aboutsummaryrefslogtreecommitdiff
path: root/node_modules/readdirp/readdirp.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/readdirp/readdirp.js')
-rw-r--r--node_modules/readdirp/readdirp.js294
1 files changed, 294 insertions, 0 deletions
diff --git a/node_modules/readdirp/readdirp.js b/node_modules/readdirp/readdirp.js
new file mode 100644
index 0000000..863bd17
--- /dev/null
+++ b/node_modules/readdirp/readdirp.js
@@ -0,0 +1,294 @@
+'use strict';
+
+var fs = require('graceful-fs')
+ , path = require('path')
+ , micromatch = require('micromatch').isMatch
+ , toString = Object.prototype.toString
+ ;
+
+
+// Standard helpers
+function isFunction (obj) {
+ return toString.call(obj) === '[object Function]';
+}
+
+function isString (obj) {
+ return toString.call(obj) === '[object String]';
+}
+
+function isUndefined (obj) {
+ return obj === void 0;
+}
+
+/**
+ * Main function which ends up calling readdirRec and reads all files and directories in given root recursively.
+ * @param { Object } opts Options to specify root (start directory), filters and recursion depth
+ * @param { function } callback1 When callback2 is given calls back for each processed file - function (fileInfo) { ... },
+ * when callback2 is not given, it behaves like explained in callback2
+ * @param { function } callback2 Calls back once all files have been processed with an array of errors and file infos
+ * function (err, fileInfos) { ... }
+ */
+function readdir(opts, callback1, callback2) {
+ var stream
+ , handleError
+ , handleFatalError
+ , errors = []
+ , readdirResult = {
+ directories: []
+ , files: []
+ }
+ , fileProcessed
+ , allProcessed
+ , realRoot
+ , aborted = false
+ , paused = false
+ ;
+
+ // If no callbacks were given we will use a streaming interface
+ if (isUndefined(callback1)) {
+ var api = require('./stream-api')();
+ stream = api.stream;
+ callback1 = api.processEntry;
+ callback2 = api.done;
+ handleError = api.handleError;
+ handleFatalError = api.handleFatalError;
+
+ stream.on('close', function () { aborted = true; });
+ stream.on('pause', function () { paused = true; });
+ stream.on('resume', function () { paused = false; });
+ } else {
+ handleError = function (err) { errors.push(err); };
+ handleFatalError = function (err) {
+ handleError(err);
+ allProcessed(errors, null);
+ };
+ }
+
+ if (isUndefined(opts)){
+ handleFatalError(new Error (
+ 'Need to pass at least one argument: opts! \n' +
+ 'https://github.com/paulmillr/readdirp#options'
+ )
+ );
+ return stream;
+ }
+
+ opts.root = opts.root || '.';
+ opts.fileFilter = opts.fileFilter || function() { return true; };
+ opts.directoryFilter = opts.directoryFilter || function() { return true; };
+ opts.depth = typeof opts.depth === 'undefined' ? 999999999 : opts.depth;
+ opts.entryType = opts.entryType || 'files';
+
+ var statfn = opts.lstat === true ? fs.lstat.bind(fs) : fs.stat.bind(fs);
+
+ if (isUndefined(callback2)) {
+ fileProcessed = function() { };
+ allProcessed = callback1;
+ } else {
+ fileProcessed = callback1;
+ allProcessed = callback2;
+ }
+
+ function normalizeFilter (filter) {
+
+ if (isUndefined(filter)) return undefined;
+
+ function isNegated (filters) {
+
+ function negated(f) {
+ return f.indexOf('!') === 0;
+ }
+
+ var some = filters.some(negated);
+ if (!some) {
+ return false;
+ } else {
+ if (filters.every(negated)) {
+ return true;
+ } else {
+ // if we detect illegal filters, bail out immediately
+ throw new Error(
+ 'Cannot mix negated with non negated glob filters: ' + filters + '\n' +
+ 'https://github.com/paulmillr/readdirp#filters'
+ );
+ }
+ }
+ }
+
+ // Turn all filters into a function
+ if (isFunction(filter)) {
+
+ return filter;
+
+ } else if (isString(filter)) {
+
+ return function (entryInfo) {
+ return micromatch(entryInfo.name, filter.trim());
+ };
+
+ } else if (filter && Array.isArray(filter)) {
+
+ if (filter) filter = filter.map(function (f) {
+ return f.trim();
+ });
+
+ return isNegated(filter) ?
+ // use AND to concat multiple negated filters
+ function (entryInfo) {
+ return filter.every(function (f) {
+ return micromatch(entryInfo.name, f);
+ });
+ }
+ :
+ // use OR to concat multiple inclusive filters
+ function (entryInfo) {
+ return filter.some(function (f) {
+ return micromatch(entryInfo.name, f);
+ });
+ };
+ }
+ }
+
+ function processDir(currentDir, entries, callProcessed) {
+ if (aborted) return;
+ var total = entries.length
+ , processed = 0
+ , entryInfos = []
+ ;
+
+ fs.realpath(currentDir, function(err, realCurrentDir) {
+ if (aborted) return;
+ if (err) {
+ handleError(err);
+ callProcessed(entryInfos);
+ return;
+ }
+
+ var relDir = path.relative(realRoot, realCurrentDir);
+
+ if (entries.length === 0) {
+ callProcessed([]);
+ } else {
+ entries.forEach(function (entry) {
+
+ var fullPath = path.join(realCurrentDir, entry)
+ , relPath = path.join(relDir, entry);
+
+ statfn(fullPath, function (err, stat) {
+ if (err) {
+ handleError(err);
+ } else {
+ entryInfos.push({
+ name : entry
+ , path : relPath // relative to root
+ , fullPath : fullPath
+
+ , parentDir : relDir // relative to root
+ , fullParentDir : realCurrentDir
+
+ , stat : stat
+ });
+ }
+ processed++;
+ if (processed === total) callProcessed(entryInfos);
+ });
+ });
+ }
+ });
+ }
+
+ function readdirRec(currentDir, depth, callCurrentDirProcessed) {
+ var args = arguments;
+ if (aborted) return;
+ if (paused) {
+ setImmediate(function () {
+ readdirRec.apply(null, args);
+ })
+ return;
+ }
+
+ fs.readdir(currentDir, function (err, entries) {
+ if (err) {
+ handleError(err);
+ callCurrentDirProcessed();
+ return;
+ }
+
+ processDir(currentDir, entries, function(entryInfos) {
+
+ var subdirs = entryInfos
+ .filter(function (ei) { return ei.stat.isDirectory() && opts.directoryFilter(ei); });
+
+ subdirs.forEach(function (di) {
+ if(opts.entryType === 'directories' || opts.entryType === 'both' || opts.entryType === 'all') {
+ fileProcessed(di);
+ }
+ readdirResult.directories.push(di);
+ });
+
+ entryInfos
+ .filter(function(ei) {
+ var isCorrectType = opts.entryType === 'all' ?
+ !ei.stat.isDirectory() : ei.stat.isFile() || ei.stat.isSymbolicLink();
+ return isCorrectType && opts.fileFilter(ei);
+ })
+ .forEach(function (fi) {
+ if(opts.entryType === 'files' || opts.entryType === 'both' || opts.entryType === 'all') {
+ fileProcessed(fi);
+ }
+ readdirResult.files.push(fi);
+ });
+
+ var pendingSubdirs = subdirs.length;
+
+ // Be done if no more subfolders exist or we reached the maximum desired depth
+ if(pendingSubdirs === 0 || depth === opts.depth) {
+ callCurrentDirProcessed();
+ } else {
+ // recurse into subdirs, keeping track of which ones are done
+ // and call back once all are processed
+ subdirs.forEach(function (subdir) {
+ readdirRec(subdir.fullPath, depth + 1, function () {
+ pendingSubdirs = pendingSubdirs - 1;
+ if(pendingSubdirs === 0) {
+ callCurrentDirProcessed();
+ }
+ });
+ });
+ }
+ });
+ });
+ }
+
+ // Validate and normalize filters
+ try {
+ opts.fileFilter = normalizeFilter(opts.fileFilter);
+ opts.directoryFilter = normalizeFilter(opts.directoryFilter);
+ } catch (err) {
+ // if we detect illegal filters, bail out immediately
+ handleFatalError(err);
+ return stream;
+ }
+
+ // If filters were valid get on with the show
+ fs.realpath(opts.root, function(err, res) {
+ if (err) {
+ handleFatalError(err);
+ return stream;
+ }
+
+ realRoot = res;
+ readdirRec(opts.root, 0, function () {
+ // All errors are collected into the errors array
+ if (errors.length > 0) {
+ allProcessed(errors, readdirResult);
+ } else {
+ allProcessed(null, readdirResult);
+ }
+ });
+ });
+
+ return stream;
+}
+
+module.exports = readdir;