123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- "use strict";
- 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
|