| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 | 
							- 'use strict';
 
- const fs = require('fs');
 
- const { Readable } = require('stream');
 
- const sysPath = require('path');
 
- const { promisify } = require('util');
 
- const picomatch = require('picomatch');
 
- const readdir = promisify(fs.readdir);
 
- const stat = promisify(fs.stat);
 
- const lstat = promisify(fs.lstat);
 
- const realpath = promisify(fs.realpath);
 
- /**
 
-  * @typedef {Object} EntryInfo
 
-  * @property {String} path
 
-  * @property {String} fullPath
 
-  * @property {fs.Stats=} stats
 
-  * @property {fs.Dirent=} dirent
 
-  * @property {String} basename
 
-  */
 
- const BANG = '!';
 
- const RECURSIVE_ERROR_CODE = 'READDIRP_RECURSIVE_ERROR';
 
- const NORMAL_FLOW_ERRORS = new Set(['ENOENT', 'EPERM', 'EACCES', 'ELOOP', RECURSIVE_ERROR_CODE]);
 
- const FILE_TYPE = 'files';
 
- const DIR_TYPE = 'directories';
 
- const FILE_DIR_TYPE = 'files_directories';
 
- const EVERYTHING_TYPE = 'all';
 
- const ALL_TYPES = [FILE_TYPE, DIR_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE];
 
- const isNormalFlowError = error => NORMAL_FLOW_ERRORS.has(error.code);
 
- const [maj, min] = process.versions.node.split('.').slice(0, 2).map(n => Number.parseInt(n, 10));
 
- const wantBigintFsStats = process.platform === 'win32' && (maj > 10 || (maj === 10 && min >= 5));
 
- const normalizeFilter = filter => {
 
-   if (filter === undefined) return;
 
-   if (typeof filter === 'function') return filter;
 
-   if (typeof filter === 'string') {
 
-     const glob = picomatch(filter.trim());
 
-     return entry => glob(entry.basename);
 
-   }
 
-   if (Array.isArray(filter)) {
 
-     const positive = [];
 
-     const negative = [];
 
-     for (const item of filter) {
 
-       const trimmed = item.trim();
 
-       if (trimmed.charAt(0) === BANG) {
 
-         negative.push(picomatch(trimmed.slice(1)));
 
-       } else {
 
-         positive.push(picomatch(trimmed));
 
-       }
 
-     }
 
-     if (negative.length > 0) {
 
-       if (positive.length > 0) {
 
-         return entry =>
 
-           positive.some(f => f(entry.basename)) && !negative.some(f => f(entry.basename));
 
-       }
 
-       return entry => !negative.some(f => f(entry.basename));
 
-     }
 
-     return entry => positive.some(f => f(entry.basename));
 
-   }
 
- };
 
- class ReaddirpStream extends Readable {
 
-   static get defaultOptions() {
 
-     return {
 
-       root: '.',
 
-       /* eslint-disable no-unused-vars */
 
-       fileFilter: (path) => true,
 
-       directoryFilter: (path) => true,
 
-       /* eslint-enable no-unused-vars */
 
-       type: FILE_TYPE,
 
-       lstat: false,
 
-       depth: 2147483648,
 
-       alwaysStat: false
 
-     };
 
-   }
 
-   constructor(options = {}) {
 
-     super({
 
-       objectMode: true,
 
-       autoDestroy: true,
 
-       highWaterMark: options.highWaterMark || 4096
 
-     });
 
-     const opts = { ...ReaddirpStream.defaultOptions, ...options };
 
-     const { root, type } = opts;
 
-     this._fileFilter = normalizeFilter(opts.fileFilter);
 
-     this._directoryFilter = normalizeFilter(opts.directoryFilter);
 
-     const statMethod = opts.lstat ? lstat : stat;
 
-     // Use bigint stats if it's windows and stat() supports options (node 10+).
 
-     if (wantBigintFsStats) {
 
-       this._stat = path => statMethod(path, { bigint: true });
 
-     } else {
 
-       this._stat = statMethod;
 
-     }
 
-     this._maxDepth = opts.depth;
 
-     this._wantsDir = [DIR_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE].includes(type);
 
-     this._wantsFile = [FILE_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE].includes(type);
 
-     this._wantsEverything = type === EVERYTHING_TYPE;
 
-     this._root = sysPath.resolve(root);
 
-     this._isDirent = ('Dirent' in fs) && !opts.alwaysStat;
 
-     this._statsProp = this._isDirent ? 'dirent' : 'stats';
 
-     this._rdOptions = { encoding: 'utf8', withFileTypes: this._isDirent };
 
-     // Launch stream with one parent, the root dir.
 
-     this.parents = [this._exploreDir(root, 1)];
 
-     this.reading = false;
 
-     this.parent = undefined;
 
-   }
 
-   async _read(batch) {
 
-     if (this.reading) return;
 
-     this.reading = true;
 
-     try {
 
-       while (!this.destroyed && batch > 0) {
 
-         const { path, depth, files = [] } = this.parent || {};
 
-         if (files.length > 0) {
 
-           const slice = files.splice(0, batch).map(dirent => this._formatEntry(dirent, path));
 
-           for (const entry of await Promise.all(slice)) {
 
-             if (this.destroyed) return;
 
-             const entryType = await this._getEntryType(entry);
 
-             if (entryType === 'directory' && this._directoryFilter(entry)) {
 
-               if (depth <= this._maxDepth) {
 
-                 this.parents.push(this._exploreDir(entry.fullPath, depth + 1));
 
-               }
 
-               if (this._wantsDir) {
 
-                 this.push(entry);
 
-                 batch--;
 
-               }
 
-             } else if ((entryType === 'file' || this._includeAsFile(entry)) && this._fileFilter(entry)) {
 
-               if (this._wantsFile) {
 
-                 this.push(entry);
 
-                 batch--;
 
-               }
 
-             }
 
-           }
 
-         } else {
 
-           const parent = this.parents.pop();
 
-           if (!parent) {
 
-             this.push(null);
 
-             break;
 
-           }
 
-           this.parent = await parent;
 
-           if (this.destroyed) return;
 
-         }
 
-       }
 
-     } catch (error) {
 
-       this.destroy(error);
 
-     } finally {
 
-       this.reading = false;
 
-     }
 
-   }
 
-   async _exploreDir(path, depth) {
 
-     let files;
 
-     try {
 
-       files = await readdir(path, this._rdOptions);
 
-     } catch (error) {
 
-       this._onError(error);
 
-     }
 
-     return { files, depth, path };
 
-   }
 
-   async _formatEntry(dirent, path) {
 
-     let entry;
 
-     try {
 
-       const basename = this._isDirent ? dirent.name : dirent;
 
-       const fullPath = sysPath.resolve(sysPath.join(path, basename));
 
-       entry = { path: sysPath.relative(this._root, fullPath), fullPath, basename };
 
-       entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
 
-     } catch (err) {
 
-       this._onError(err);
 
-     }
 
-     return entry;
 
-   }
 
-   _onError(err) {
 
-     if (isNormalFlowError(err) && !this.destroyed) {
 
-       this.emit('warn', err);
 
-     } else {
 
-       this.destroy(err);
 
-     }
 
-   }
 
-   async _getEntryType(entry) {
 
-     // entry may be undefined, because a warning or an error were emitted
 
-     // and the statsProp is undefined
 
-     const stats = entry && entry[this._statsProp];
 
-     if (!stats) {
 
-       return;
 
-     }
 
-     if (stats.isFile()) {
 
-       return 'file';
 
-     }
 
-     if (stats.isDirectory()) {
 
-       return 'directory';
 
-     }
 
-     if (stats && stats.isSymbolicLink()) {
 
-       const full = entry.fullPath;
 
-       try {
 
-         const entryRealPath = await realpath(full);
 
-         const entryRealPathStats = await lstat(entryRealPath);
 
-         if (entryRealPathStats.isFile()) {
 
-           return 'file';
 
-         }
 
-         if (entryRealPathStats.isDirectory()) {
 
-           const len = entryRealPath.length;
 
-           if (full.startsWith(entryRealPath) && full.substr(len, 1) === sysPath.sep) {
 
-             const recursiveError = new Error(
 
-               `Circular symlink detected: "${full}" points to "${entryRealPath}"`
 
-             );
 
-             recursiveError.code = RECURSIVE_ERROR_CODE;
 
-             return this._onError(recursiveError);
 
-           }
 
-           return 'directory';
 
-         }
 
-       } catch (error) {
 
-         this._onError(error);
 
-       }
 
-     }
 
-   }
 
-   _includeAsFile(entry) {
 
-     const stats = entry && entry[this._statsProp];
 
-     return stats && this._wantsEverything && !stats.isDirectory();
 
-   }
 
- }
 
- /**
 
-  * @typedef {Object} ReaddirpArguments
 
-  * @property {Function=} fileFilter
 
-  * @property {Function=} directoryFilter
 
-  * @property {String=} type
 
-  * @property {Number=} depth
 
-  * @property {String=} root
 
-  * @property {Boolean=} lstat
 
-  * @property {Boolean=} bigint
 
-  */
 
- /**
 
-  * Main function which ends up calling readdirRec and reads all files and directories in given root recursively.
 
-  * @param {String} root Root directory
 
-  * @param {ReaddirpArguments=} options Options to specify root (start directory), filters and recursion depth
 
-  */
 
- const readdirp = (root, options = {}) => {
 
-   let type = options.entryType || options.type;
 
-   if (type === 'both') type = FILE_DIR_TYPE; // backwards-compatibility
 
-   if (type) options.type = type;
 
-   if (!root) {
 
-     throw new Error('readdirp: root argument is required. Usage: readdirp(root, options)');
 
-   } else if (typeof root !== 'string') {
 
-     throw new TypeError('readdirp: root argument must be a string. Usage: readdirp(root, options)');
 
-   } else if (type && !ALL_TYPES.includes(type)) {
 
-     throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(', ')}`);
 
-   }
 
-   options.root = root;
 
-   return new ReaddirpStream(options);
 
- };
 
- const readdirpPromise = (root, options = {}) => {
 
-   return new Promise((resolve, reject) => {
 
-     const files = [];
 
-     readdirp(root, options)
 
-       .on('data', entry => files.push(entry))
 
-       .on('end', () => resolve(files))
 
-       .on('error', error => reject(error));
 
-   });
 
- };
 
- readdirp.promise = readdirpPromise;
 
- readdirp.ReaddirpStream = ReaddirpStream;
 
- readdirp.default = readdirp;
 
- module.exports = readdirp;
 
 
  |