Spaces:
Sleeping
Sleeping
| ; | |
| Object.defineProperty(exports, "__esModule", { value: true }); | |
| exports.GlobStream = exports.GlobWalker = exports.GlobUtil = void 0; | |
| /** | |
| * Single-use utility classes to provide functionality to the {@link Glob} | |
| * methods. | |
| * | |
| * @module | |
| */ | |
| const minipass_1 = require("minipass"); | |
| const ignore_js_1 = require("./ignore.js"); | |
| const processor_js_1 = require("./processor.js"); | |
| const makeIgnore = (ignore, opts) => typeof ignore === 'string' ? new ignore_js_1.Ignore([ignore], opts) | |
| : Array.isArray(ignore) ? new ignore_js_1.Ignore(ignore, opts) | |
| : ignore; | |
| /** | |
| * basic walking utilities that all the glob walker types use | |
| */ | |
| class GlobUtil { | |
| path; | |
| patterns; | |
| opts; | |
| seen = new Set(); | |
| paused = false; | |
| aborted = false; | |
| #onResume = []; | |
| #ignore; | |
| #sep; | |
| signal; | |
| maxDepth; | |
| includeChildMatches; | |
| constructor(patterns, path, opts) { | |
| this.patterns = patterns; | |
| this.path = path; | |
| this.opts = opts; | |
| this.#sep = !opts.posix && opts.platform === 'win32' ? '\\' : '/'; | |
| this.includeChildMatches = opts.includeChildMatches !== false; | |
| if (opts.ignore || !this.includeChildMatches) { | |
| this.#ignore = makeIgnore(opts.ignore ?? [], opts); | |
| if (!this.includeChildMatches && | |
| typeof this.#ignore.add !== 'function') { | |
| const m = 'cannot ignore child matches, ignore lacks add() method.'; | |
| throw new Error(m); | |
| } | |
| } | |
| // ignore, always set with maxDepth, but it's optional on the | |
| // GlobOptions type | |
| /* c8 ignore start */ | |
| this.maxDepth = opts.maxDepth || Infinity; | |
| /* c8 ignore stop */ | |
| if (opts.signal) { | |
| this.signal = opts.signal; | |
| this.signal.addEventListener('abort', () => { | |
| this.#onResume.length = 0; | |
| }); | |
| } | |
| } | |
| #ignored(path) { | |
| return this.seen.has(path) || !!this.#ignore?.ignored?.(path); | |
| } | |
| #childrenIgnored(path) { | |
| return !!this.#ignore?.childrenIgnored?.(path); | |
| } | |
| // backpressure mechanism | |
| pause() { | |
| this.paused = true; | |
| } | |
| resume() { | |
| /* c8 ignore start */ | |
| if (this.signal?.aborted) | |
| return; | |
| /* c8 ignore stop */ | |
| this.paused = false; | |
| let fn = undefined; | |
| while (!this.paused && (fn = this.#onResume.shift())) { | |
| fn(); | |
| } | |
| } | |
| onResume(fn) { | |
| if (this.signal?.aborted) | |
| return; | |
| /* c8 ignore start */ | |
| if (!this.paused) { | |
| fn(); | |
| } | |
| else { | |
| /* c8 ignore stop */ | |
| this.#onResume.push(fn); | |
| } | |
| } | |
| // do the requisite realpath/stat checking, and return the path | |
| // to add or undefined to filter it out. | |
| async matchCheck(e, ifDir) { | |
| if (ifDir && this.opts.nodir) | |
| return undefined; | |
| let rpc; | |
| if (this.opts.realpath) { | |
| rpc = e.realpathCached() || (await e.realpath()); | |
| if (!rpc) | |
| return undefined; | |
| e = rpc; | |
| } | |
| const needStat = e.isUnknown() || this.opts.stat; | |
| const s = needStat ? await e.lstat() : e; | |
| if (this.opts.follow && this.opts.nodir && s?.isSymbolicLink()) { | |
| const target = await s.realpath(); | |
| /* c8 ignore start */ | |
| if (target && (target.isUnknown() || this.opts.stat)) { | |
| await target.lstat(); | |
| } | |
| /* c8 ignore stop */ | |
| } | |
| return this.matchCheckTest(s, ifDir); | |
| } | |
| matchCheckTest(e, ifDir) { | |
| return (e && | |
| (this.maxDepth === Infinity || e.depth() <= this.maxDepth) && | |
| (!ifDir || e.canReaddir()) && | |
| (!this.opts.nodir || !e.isDirectory()) && | |
| (!this.opts.nodir || | |
| !this.opts.follow || | |
| !e.isSymbolicLink() || | |
| !e.realpathCached()?.isDirectory()) && | |
| !this.#ignored(e)) ? | |
| e | |
| : undefined; | |
| } | |
| matchCheckSync(e, ifDir) { | |
| if (ifDir && this.opts.nodir) | |
| return undefined; | |
| let rpc; | |
| if (this.opts.realpath) { | |
| rpc = e.realpathCached() || e.realpathSync(); | |
| if (!rpc) | |
| return undefined; | |
| e = rpc; | |
| } | |
| const needStat = e.isUnknown() || this.opts.stat; | |
| const s = needStat ? e.lstatSync() : e; | |
| if (this.opts.follow && this.opts.nodir && s?.isSymbolicLink()) { | |
| const target = s.realpathSync(); | |
| if (target && (target?.isUnknown() || this.opts.stat)) { | |
| target.lstatSync(); | |
| } | |
| } | |
| return this.matchCheckTest(s, ifDir); | |
| } | |
| matchFinish(e, absolute) { | |
| if (this.#ignored(e)) | |
| return; | |
| // we know we have an ignore if this is false, but TS doesn't | |
| if (!this.includeChildMatches && this.#ignore?.add) { | |
| const ign = `${e.relativePosix()}/**`; | |
| this.#ignore.add(ign); | |
| } | |
| const abs = this.opts.absolute === undefined ? absolute : this.opts.absolute; | |
| this.seen.add(e); | |
| const mark = this.opts.mark && e.isDirectory() ? this.#sep : ''; | |
| // ok, we have what we need! | |
| if (this.opts.withFileTypes) { | |
| this.matchEmit(e); | |
| } | |
| else if (abs) { | |
| const abs = this.opts.posix ? e.fullpathPosix() : e.fullpath(); | |
| this.matchEmit(abs + mark); | |
| } | |
| else { | |
| const rel = this.opts.posix ? e.relativePosix() : e.relative(); | |
| const pre = this.opts.dotRelative && !rel.startsWith('..' + this.#sep) ? | |
| '.' + this.#sep | |
| : ''; | |
| this.matchEmit(!rel ? '.' + mark : pre + rel + mark); | |
| } | |
| } | |
| async match(e, absolute, ifDir) { | |
| const p = await this.matchCheck(e, ifDir); | |
| if (p) | |
| this.matchFinish(p, absolute); | |
| } | |
| matchSync(e, absolute, ifDir) { | |
| const p = this.matchCheckSync(e, ifDir); | |
| if (p) | |
| this.matchFinish(p, absolute); | |
| } | |
| walkCB(target, patterns, cb) { | |
| /* c8 ignore start */ | |
| if (this.signal?.aborted) | |
| cb(); | |
| /* c8 ignore stop */ | |
| this.walkCB2(target, patterns, new processor_js_1.Processor(this.opts), cb); | |
| } | |
| walkCB2(target, patterns, processor, cb) { | |
| if (this.#childrenIgnored(target)) | |
| return cb(); | |
| if (this.signal?.aborted) | |
| cb(); | |
| if (this.paused) { | |
| this.onResume(() => this.walkCB2(target, patterns, processor, cb)); | |
| return; | |
| } | |
| processor.processPatterns(target, patterns); | |
| // done processing. all of the above is sync, can be abstracted out. | |
| // subwalks is a map of paths to the entry filters they need | |
| // matches is a map of paths to [absolute, ifDir] tuples. | |
| let tasks = 1; | |
| const next = () => { | |
| if (--tasks === 0) | |
| cb(); | |
| }; | |
| for (const [m, absolute, ifDir] of processor.matches.entries()) { | |
| if (this.#ignored(m)) | |
| continue; | |
| tasks++; | |
| this.match(m, absolute, ifDir).then(() => next()); | |
| } | |
| for (const t of processor.subwalkTargets()) { | |
| if (this.maxDepth !== Infinity && t.depth() >= this.maxDepth) { | |
| continue; | |
| } | |
| tasks++; | |
| const childrenCached = t.readdirCached(); | |
| if (t.calledReaddir()) | |
| this.walkCB3(t, childrenCached, processor, next); | |
| else { | |
| t.readdirCB((_, entries) => this.walkCB3(t, entries, processor, next), true); | |
| } | |
| } | |
| next(); | |
| } | |
| walkCB3(target, entries, processor, cb) { | |
| processor = processor.filterEntries(target, entries); | |
| let tasks = 1; | |
| const next = () => { | |
| if (--tasks === 0) | |
| cb(); | |
| }; | |
| for (const [m, absolute, ifDir] of processor.matches.entries()) { | |
| if (this.#ignored(m)) | |
| continue; | |
| tasks++; | |
| this.match(m, absolute, ifDir).then(() => next()); | |
| } | |
| for (const [target, patterns] of processor.subwalks.entries()) { | |
| tasks++; | |
| this.walkCB2(target, patterns, processor.child(), next); | |
| } | |
| next(); | |
| } | |
| walkCBSync(target, patterns, cb) { | |
| /* c8 ignore start */ | |
| if (this.signal?.aborted) | |
| cb(); | |
| /* c8 ignore stop */ | |
| this.walkCB2Sync(target, patterns, new processor_js_1.Processor(this.opts), cb); | |
| } | |
| walkCB2Sync(target, patterns, processor, cb) { | |
| if (this.#childrenIgnored(target)) | |
| return cb(); | |
| if (this.signal?.aborted) | |
| cb(); | |
| if (this.paused) { | |
| this.onResume(() => this.walkCB2Sync(target, patterns, processor, cb)); | |
| return; | |
| } | |
| processor.processPatterns(target, patterns); | |
| // done processing. all of the above is sync, can be abstracted out. | |
| // subwalks is a map of paths to the entry filters they need | |
| // matches is a map of paths to [absolute, ifDir] tuples. | |
| let tasks = 1; | |
| const next = () => { | |
| if (--tasks === 0) | |
| cb(); | |
| }; | |
| for (const [m, absolute, ifDir] of processor.matches.entries()) { | |
| if (this.#ignored(m)) | |
| continue; | |
| this.matchSync(m, absolute, ifDir); | |
| } | |
| for (const t of processor.subwalkTargets()) { | |
| if (this.maxDepth !== Infinity && t.depth() >= this.maxDepth) { | |
| continue; | |
| } | |
| tasks++; | |
| const children = t.readdirSync(); | |
| this.walkCB3Sync(t, children, processor, next); | |
| } | |
| next(); | |
| } | |
| walkCB3Sync(target, entries, processor, cb) { | |
| processor = processor.filterEntries(target, entries); | |
| let tasks = 1; | |
| const next = () => { | |
| if (--tasks === 0) | |
| cb(); | |
| }; | |
| for (const [m, absolute, ifDir] of processor.matches.entries()) { | |
| if (this.#ignored(m)) | |
| continue; | |
| this.matchSync(m, absolute, ifDir); | |
| } | |
| for (const [target, patterns] of processor.subwalks.entries()) { | |
| tasks++; | |
| this.walkCB2Sync(target, patterns, processor.child(), next); | |
| } | |
| next(); | |
| } | |
| } | |
| exports.GlobUtil = GlobUtil; | |
| class GlobWalker extends GlobUtil { | |
| matches = new Set(); | |
| constructor(patterns, path, opts) { | |
| super(patterns, path, opts); | |
| } | |
| matchEmit(e) { | |
| this.matches.add(e); | |
| } | |
| async walk() { | |
| if (this.signal?.aborted) | |
| throw this.signal.reason; | |
| if (this.path.isUnknown()) { | |
| await this.path.lstat(); | |
| } | |
| await new Promise((res, rej) => { | |
| this.walkCB(this.path, this.patterns, () => { | |
| if (this.signal?.aborted) { | |
| rej(this.signal.reason); | |
| } | |
| else { | |
| res(this.matches); | |
| } | |
| }); | |
| }); | |
| return this.matches; | |
| } | |
| walkSync() { | |
| if (this.signal?.aborted) | |
| throw this.signal.reason; | |
| if (this.path.isUnknown()) { | |
| this.path.lstatSync(); | |
| } | |
| // nothing for the callback to do, because this never pauses | |
| this.walkCBSync(this.path, this.patterns, () => { | |
| if (this.signal?.aborted) | |
| throw this.signal.reason; | |
| }); | |
| return this.matches; | |
| } | |
| } | |
| exports.GlobWalker = GlobWalker; | |
| class GlobStream extends GlobUtil { | |
| results; | |
| constructor(patterns, path, opts) { | |
| super(patterns, path, opts); | |
| this.results = new minipass_1.Minipass({ | |
| signal: this.signal, | |
| objectMode: true, | |
| }); | |
| this.results.on('drain', () => this.resume()); | |
| this.results.on('resume', () => this.resume()); | |
| } | |
| matchEmit(e) { | |
| this.results.write(e); | |
| if (!this.results.flowing) | |
| this.pause(); | |
| } | |
| stream() { | |
| const target = this.path; | |
| if (target.isUnknown()) { | |
| target.lstat().then(() => { | |
| this.walkCB(target, this.patterns, () => this.results.end()); | |
| }); | |
| } | |
| else { | |
| this.walkCB(target, this.patterns, () => this.results.end()); | |
| } | |
| return this.results; | |
| } | |
| streamSync() { | |
| if (this.path.isUnknown()) { | |
| this.path.lstatSync(); | |
| } | |
| this.walkCBSync(this.path, this.patterns, () => this.results.end()); | |
| return this.results; | |
| } | |
| } | |
| exports.GlobStream = GlobStream; | |
| //# sourceMappingURL=walker.js.map |