| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 | 'use strict';var fs        =  require('graceful-fs')  , path      =  require('path')  , micromatch =  require('micromatch').isMatch  , toString  =  Object.prototype.toString  ;// Standard helpersfunction 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;
 |