|  |  |  |  | module.exports = readdirGlob; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const fs = require('fs'); | 
					
						
							|  |  |  |  | const { EventEmitter } = require('events'); | 
					
						
							|  |  |  |  | const { Minimatch } = require('minimatch'); | 
					
						
							|  |  |  |  | const { resolve } = require('path'); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function readdir(dir, strict) { | 
					
						
							|  |  |  |  |   return new Promise((resolve, reject) => { | 
					
						
							|  |  |  |  |     fs.readdir(dir, {withFileTypes: true} ,(err, files) => { | 
					
						
							|  |  |  |  |       if(err) { | 
					
						
							|  |  |  |  |         switch (err.code) { | 
					
						
							|  |  |  |  |           case 'ENOTDIR':      // Not a directory
 | 
					
						
							|  |  |  |  |             if(strict) { | 
					
						
							|  |  |  |  |               reject(err); | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |               resolve([]); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case 'ENOTSUP':      // Operation not supported
 | 
					
						
							|  |  |  |  |           case 'ENOENT':       // No such file or directory
 | 
					
						
							|  |  |  |  |           case 'ENAMETOOLONG': // Filename too long
 | 
					
						
							|  |  |  |  |           case 'UNKNOWN': | 
					
						
							|  |  |  |  |             resolve([]); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case 'ELOOP':        // Too many levels of symbolic links
 | 
					
						
							|  |  |  |  |           default: | 
					
						
							|  |  |  |  |             reject(err); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |       } else { | 
					
						
							|  |  |  |  |         resolve(files); | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |   }); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | function stat(file, followSymlinks) { | 
					
						
							|  |  |  |  |   return new Promise((resolve, reject) => { | 
					
						
							|  |  |  |  |     const statFunc = followSymlinks ? fs.stat : fs.lstat; | 
					
						
							|  |  |  |  |     statFunc(file, (err, stats) => { | 
					
						
							|  |  |  |  |       if(err) { | 
					
						
							|  |  |  |  |         switch (err.code) { | 
					
						
							|  |  |  |  |           case 'ENOENT': | 
					
						
							|  |  |  |  |             if(followSymlinks) { | 
					
						
							|  |  |  |  |               // Fallback to lstat to handle broken links as files
 | 
					
						
							|  |  |  |  |               resolve(stat(file, false));  | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |               resolve(null); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           default: | 
					
						
							|  |  |  |  |             resolve(null); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |       } else { | 
					
						
							|  |  |  |  |         resolve(stats); | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |   }); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | async function* exploreWalkAsync(dir, path, followSymlinks, useStat, shouldSkip, strict) { | 
					
						
							|  |  |  |  |   let files = await readdir(path + dir, strict); | 
					
						
							|  |  |  |  |   for(const file of files) { | 
					
						
							|  |  |  |  |     let name = file.name; | 
					
						
							|  |  |  |  |     if(name === undefined) { | 
					
						
							|  |  |  |  |       // undefined file.name means the `withFileTypes` options is not supported by node
 | 
					
						
							|  |  |  |  |       // we have to call the stat function to know if file is directory or not.
 | 
					
						
							|  |  |  |  |       name = file; | 
					
						
							|  |  |  |  |       useStat = true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     const filename = dir + '/' + name; | 
					
						
							|  |  |  |  |     const relative = filename.slice(1); // Remove the leading /
 | 
					
						
							|  |  |  |  |     const absolute = path + '/' + relative; | 
					
						
							|  |  |  |  |     let stats = null; | 
					
						
							|  |  |  |  |     if(useStat || followSymlinks) { | 
					
						
							|  |  |  |  |       stats = await stat(absolute, followSymlinks); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if(!stats && file.name !== undefined) { | 
					
						
							|  |  |  |  |       stats = file; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if(stats === null) { | 
					
						
							|  |  |  |  |       stats = { isDirectory: () => false }; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if(stats.isDirectory()) { | 
					
						
							|  |  |  |  |       if(!shouldSkip(relative)) { | 
					
						
							|  |  |  |  |         yield {relative, absolute, stats}; | 
					
						
							|  |  |  |  |         yield* exploreWalkAsync(filename, path, followSymlinks, useStat, shouldSkip, false); | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       yield {relative, absolute, stats}; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | async function* explore(path, followSymlinks, useStat, shouldSkip) { | 
					
						
							|  |  |  |  |   yield* exploreWalkAsync('', path, followSymlinks, useStat, shouldSkip, true); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function readOptions(options) { | 
					
						
							|  |  |  |  |   return { | 
					
						
							|  |  |  |  |     pattern: options.pattern, | 
					
						
							|  |  |  |  |     dot: !!options.dot, | 
					
						
							|  |  |  |  |     noglobstar: !!options.noglobstar, | 
					
						
							|  |  |  |  |     matchBase: !!options.matchBase, | 
					
						
							|  |  |  |  |     nocase: !!options.nocase, | 
					
						
							|  |  |  |  |     ignore: options.ignore, | 
					
						
							|  |  |  |  |     skip: options.skip, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     follow: !!options.follow, | 
					
						
							|  |  |  |  |     stat: !!options.stat, | 
					
						
							|  |  |  |  |     nodir: !!options.nodir, | 
					
						
							|  |  |  |  |     mark: !!options.mark, | 
					
						
							|  |  |  |  |     silent: !!options.silent, | 
					
						
							|  |  |  |  |     absolute: !!options.absolute | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | class ReaddirGlob extends EventEmitter { | 
					
						
							|  |  |  |  |   constructor(cwd, options, cb) { | 
					
						
							|  |  |  |  |     super(); | 
					
						
							|  |  |  |  |     if(typeof options === 'function') { | 
					
						
							|  |  |  |  |       cb = options; | 
					
						
							|  |  |  |  |       options = null; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     this.options = readOptions(options || {}); | 
					
						
							|  |  |  |  |    | 
					
						
							|  |  |  |  |     this.matchers = []; | 
					
						
							|  |  |  |  |     if(this.options.pattern) { | 
					
						
							|  |  |  |  |       const matchers = Array.isArray(this.options.pattern) ? this.options.pattern : [this.options.pattern]; | 
					
						
							|  |  |  |  |       this.matchers = matchers.map( m => | 
					
						
							|  |  |  |  |         new Minimatch(m, { | 
					
						
							|  |  |  |  |           dot: this.options.dot, | 
					
						
							|  |  |  |  |           noglobstar:this.options.noglobstar, | 
					
						
							|  |  |  |  |           matchBase:this.options.matchBase, | 
					
						
							|  |  |  |  |           nocase:this.options.nocase | 
					
						
							|  |  |  |  |         }) | 
					
						
							|  |  |  |  |       ); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |    | 
					
						
							|  |  |  |  |     this.ignoreMatchers = []; | 
					
						
							|  |  |  |  |     if(this.options.ignore) { | 
					
						
							|  |  |  |  |       const ignorePatterns = Array.isArray(this.options.ignore) ? this.options.ignore : [this.options.ignore]; | 
					
						
							|  |  |  |  |       this.ignoreMatchers = ignorePatterns.map( ignore => | 
					
						
							|  |  |  |  |         new Minimatch(ignore, {dot: true}) | 
					
						
							|  |  |  |  |       ); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |    | 
					
						
							|  |  |  |  |     this.skipMatchers = []; | 
					
						
							|  |  |  |  |     if(this.options.skip) { | 
					
						
							|  |  |  |  |       const skipPatterns = Array.isArray(this.options.skip) ? this.options.skip : [this.options.skip]; | 
					
						
							|  |  |  |  |       this.skipMatchers = skipPatterns.map( skip => | 
					
						
							|  |  |  |  |         new Minimatch(skip, {dot: true}) | 
					
						
							|  |  |  |  |       ); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     this.iterator = explore(resolve(cwd || '.'), this.options.follow, this.options.stat, this._shouldSkipDirectory.bind(this)); | 
					
						
							|  |  |  |  |     this.paused = false; | 
					
						
							|  |  |  |  |     this.inactive = false; | 
					
						
							|  |  |  |  |     this.aborted = false; | 
					
						
							|  |  |  |  |    | 
					
						
							|  |  |  |  |     if(cb) { | 
					
						
							|  |  |  |  |       this._matches = [];  | 
					
						
							|  |  |  |  |       this.on('match', match => this._matches.push(this.options.absolute ? match.absolute : match.relative)); | 
					
						
							|  |  |  |  |       this.on('error', err => cb(err)); | 
					
						
							|  |  |  |  |       this.on('end', () => cb(null, this._matches)); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     setTimeout( () => this._next(), 0); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   _shouldSkipDirectory(relative) { | 
					
						
							|  |  |  |  |     //console.log(relative, this.skipMatchers.some(m => m.match(relative)));
 | 
					
						
							|  |  |  |  |     return this.skipMatchers.some(m => m.match(relative)); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   _fileMatches(relative, isDirectory) { | 
					
						
							|  |  |  |  |     const file = relative + (isDirectory ? '/' : ''); | 
					
						
							|  |  |  |  |     return (this.matchers.length === 0 || this.matchers.some(m => m.match(file))) | 
					
						
							|  |  |  |  |       && !this.ignoreMatchers.some(m => m.match(file)) | 
					
						
							|  |  |  |  |       && (!this.options.nodir || !isDirectory); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   _next() { | 
					
						
							|  |  |  |  |     if(!this.paused && !this.aborted) { | 
					
						
							|  |  |  |  |       this.iterator.next() | 
					
						
							|  |  |  |  |       .then((obj)=> { | 
					
						
							|  |  |  |  |         if(!obj.done) { | 
					
						
							|  |  |  |  |           const isDirectory = obj.value.stats.isDirectory(); | 
					
						
							|  |  |  |  |           if(this._fileMatches(obj.value.relative, isDirectory )) { | 
					
						
							|  |  |  |  |             let relative = obj.value.relative; | 
					
						
							|  |  |  |  |             let absolute = obj.value.absolute; | 
					
						
							|  |  |  |  |             if(this.options.mark && isDirectory) { | 
					
						
							|  |  |  |  |               relative += '/'; | 
					
						
							|  |  |  |  |               absolute += '/'; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             if(this.options.stat) { | 
					
						
							|  |  |  |  |               this.emit('match', {relative, absolute, stat:obj.value.stats}); | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |               this.emit('match', {relative, absolute}); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |           } | 
					
						
							|  |  |  |  |           this._next(this.iterator); | 
					
						
							|  |  |  |  |         } else { | 
					
						
							|  |  |  |  |           this.emit('end'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |       }) | 
					
						
							|  |  |  |  |       .catch((err) => { | 
					
						
							|  |  |  |  |         this.abort(); | 
					
						
							|  |  |  |  |         this.emit('error', err); | 
					
						
							|  |  |  |  |         if(!err.code && !this.options.silent) { | 
					
						
							|  |  |  |  |           console.error(err); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |       }); | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       this.inactive = true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   abort() { | 
					
						
							|  |  |  |  |     this.aborted = true; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   pause() { | 
					
						
							|  |  |  |  |     this.paused = true; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   resume() { | 
					
						
							|  |  |  |  |     this.paused = false; | 
					
						
							|  |  |  |  |     if(this.inactive) { | 
					
						
							|  |  |  |  |       this.inactive = false; | 
					
						
							|  |  |  |  |       this._next(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function readdirGlob(pattern, options, cb) { | 
					
						
							|  |  |  |  |   return new ReaddirGlob(pattern, options, cb); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | readdirGlob.ReaddirGlob = ReaddirGlob; |