• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.GlobStream = exports.GlobWalker = exports.GlobUtil = void 0;
4/**
5 * Single-use utility classes to provide functionality to the {@link Glob}
6 * methods.
7 *
8 * @module
9 */
10const minipass_1 = require("minipass");
11const ignore_js_1 = require("./ignore.js");
12const processor_js_1 = require("./processor.js");
13const makeIgnore = (ignore, opts) => typeof ignore === 'string'
14    ? new ignore_js_1.Ignore([ignore], opts)
15    : Array.isArray(ignore)
16        ? new ignore_js_1.Ignore(ignore, opts)
17        : ignore;
18/**
19 * basic walking utilities that all the glob walker types use
20 */
21class GlobUtil {
22    path;
23    patterns;
24    opts;
25    seen = new Set();
26    paused = false;
27    aborted = false;
28    #onResume = [];
29    #ignore;
30    #sep;
31    signal;
32    maxDepth;
33    constructor(patterns, path, opts) {
34        this.patterns = patterns;
35        this.path = path;
36        this.opts = opts;
37        this.#sep = !opts.posix && opts.platform === 'win32' ? '\\' : '/';
38        if (opts.ignore) {
39            this.#ignore = makeIgnore(opts.ignore, opts);
40        }
41        // ignore, always set with maxDepth, but it's optional on the
42        // GlobOptions type
43        /* c8 ignore start */
44        this.maxDepth = opts.maxDepth || Infinity;
45        /* c8 ignore stop */
46        if (opts.signal) {
47            this.signal = opts.signal;
48            this.signal.addEventListener('abort', () => {
49                this.#onResume.length = 0;
50            });
51        }
52    }
53    #ignored(path) {
54        return this.seen.has(path) || !!this.#ignore?.ignored?.(path);
55    }
56    #childrenIgnored(path) {
57        return !!this.#ignore?.childrenIgnored?.(path);
58    }
59    // backpressure mechanism
60    pause() {
61        this.paused = true;
62    }
63    resume() {
64        /* c8 ignore start */
65        if (this.signal?.aborted)
66            return;
67        /* c8 ignore stop */
68        this.paused = false;
69        let fn = undefined;
70        while (!this.paused && (fn = this.#onResume.shift())) {
71            fn();
72        }
73    }
74    onResume(fn) {
75        if (this.signal?.aborted)
76            return;
77        /* c8 ignore start */
78        if (!this.paused) {
79            fn();
80        }
81        else {
82            /* c8 ignore stop */
83            this.#onResume.push(fn);
84        }
85    }
86    // do the requisite realpath/stat checking, and return the path
87    // to add or undefined to filter it out.
88    async matchCheck(e, ifDir) {
89        if (ifDir && this.opts.nodir)
90            return undefined;
91        let rpc;
92        if (this.opts.realpath) {
93            rpc = e.realpathCached() || (await e.realpath());
94            if (!rpc)
95                return undefined;
96            e = rpc;
97        }
98        const needStat = e.isUnknown() || this.opts.stat;
99        return this.matchCheckTest(needStat ? await e.lstat() : e, ifDir);
100    }
101    matchCheckTest(e, ifDir) {
102        return e &&
103            (this.maxDepth === Infinity || e.depth() <= this.maxDepth) &&
104            (!ifDir || e.canReaddir()) &&
105            (!this.opts.nodir || !e.isDirectory()) &&
106            !this.#ignored(e)
107            ? e
108            : undefined;
109    }
110    matchCheckSync(e, ifDir) {
111        if (ifDir && this.opts.nodir)
112            return undefined;
113        let rpc;
114        if (this.opts.realpath) {
115            rpc = e.realpathCached() || e.realpathSync();
116            if (!rpc)
117                return undefined;
118            e = rpc;
119        }
120        const needStat = e.isUnknown() || this.opts.stat;
121        return this.matchCheckTest(needStat ? e.lstatSync() : e, ifDir);
122    }
123    matchFinish(e, absolute) {
124        if (this.#ignored(e))
125            return;
126        const abs = this.opts.absolute === undefined ? absolute : this.opts.absolute;
127        this.seen.add(e);
128        const mark = this.opts.mark && e.isDirectory() ? this.#sep : '';
129        // ok, we have what we need!
130        if (this.opts.withFileTypes) {
131            this.matchEmit(e);
132        }
133        else if (abs) {
134            const abs = this.opts.posix ? e.fullpathPosix() : e.fullpath();
135            this.matchEmit(abs + mark);
136        }
137        else {
138            const rel = this.opts.posix ? e.relativePosix() : e.relative();
139            const pre = this.opts.dotRelative && !rel.startsWith('..' + this.#sep)
140                ? '.' + this.#sep
141                : '';
142            this.matchEmit(!rel ? '.' + mark : pre + rel + mark);
143        }
144    }
145    async match(e, absolute, ifDir) {
146        const p = await this.matchCheck(e, ifDir);
147        if (p)
148            this.matchFinish(p, absolute);
149    }
150    matchSync(e, absolute, ifDir) {
151        const p = this.matchCheckSync(e, ifDir);
152        if (p)
153            this.matchFinish(p, absolute);
154    }
155    walkCB(target, patterns, cb) {
156        /* c8 ignore start */
157        if (this.signal?.aborted)
158            cb();
159        /* c8 ignore stop */
160        this.walkCB2(target, patterns, new processor_js_1.Processor(this.opts), cb);
161    }
162    walkCB2(target, patterns, processor, cb) {
163        if (this.#childrenIgnored(target))
164            return cb();
165        if (this.signal?.aborted)
166            cb();
167        if (this.paused) {
168            this.onResume(() => this.walkCB2(target, patterns, processor, cb));
169            return;
170        }
171        processor.processPatterns(target, patterns);
172        // done processing.  all of the above is sync, can be abstracted out.
173        // subwalks is a map of paths to the entry filters they need
174        // matches is a map of paths to [absolute, ifDir] tuples.
175        let tasks = 1;
176        const next = () => {
177            if (--tasks === 0)
178                cb();
179        };
180        for (const [m, absolute, ifDir] of processor.matches.entries()) {
181            if (this.#ignored(m))
182                continue;
183            tasks++;
184            this.match(m, absolute, ifDir).then(() => next());
185        }
186        for (const t of processor.subwalkTargets()) {
187            if (this.maxDepth !== Infinity && t.depth() >= this.maxDepth) {
188                continue;
189            }
190            tasks++;
191            const childrenCached = t.readdirCached();
192            if (t.calledReaddir())
193                this.walkCB3(t, childrenCached, processor, next);
194            else {
195                t.readdirCB((_, entries) => this.walkCB3(t, entries, processor, next), true);
196            }
197        }
198        next();
199    }
200    walkCB3(target, entries, processor, cb) {
201        processor = processor.filterEntries(target, entries);
202        let tasks = 1;
203        const next = () => {
204            if (--tasks === 0)
205                cb();
206        };
207        for (const [m, absolute, ifDir] of processor.matches.entries()) {
208            if (this.#ignored(m))
209                continue;
210            tasks++;
211            this.match(m, absolute, ifDir).then(() => next());
212        }
213        for (const [target, patterns] of processor.subwalks.entries()) {
214            tasks++;
215            this.walkCB2(target, patterns, processor.child(), next);
216        }
217        next();
218    }
219    walkCBSync(target, patterns, cb) {
220        /* c8 ignore start */
221        if (this.signal?.aborted)
222            cb();
223        /* c8 ignore stop */
224        this.walkCB2Sync(target, patterns, new processor_js_1.Processor(this.opts), cb);
225    }
226    walkCB2Sync(target, patterns, processor, cb) {
227        if (this.#childrenIgnored(target))
228            return cb();
229        if (this.signal?.aborted)
230            cb();
231        if (this.paused) {
232            this.onResume(() => this.walkCB2Sync(target, patterns, processor, cb));
233            return;
234        }
235        processor.processPatterns(target, patterns);
236        // done processing.  all of the above is sync, can be abstracted out.
237        // subwalks is a map of paths to the entry filters they need
238        // matches is a map of paths to [absolute, ifDir] tuples.
239        let tasks = 1;
240        const next = () => {
241            if (--tasks === 0)
242                cb();
243        };
244        for (const [m, absolute, ifDir] of processor.matches.entries()) {
245            if (this.#ignored(m))
246                continue;
247            this.matchSync(m, absolute, ifDir);
248        }
249        for (const t of processor.subwalkTargets()) {
250            if (this.maxDepth !== Infinity && t.depth() >= this.maxDepth) {
251                continue;
252            }
253            tasks++;
254            const children = t.readdirSync();
255            this.walkCB3Sync(t, children, processor, next);
256        }
257        next();
258    }
259    walkCB3Sync(target, entries, processor, cb) {
260        processor = processor.filterEntries(target, entries);
261        let tasks = 1;
262        const next = () => {
263            if (--tasks === 0)
264                cb();
265        };
266        for (const [m, absolute, ifDir] of processor.matches.entries()) {
267            if (this.#ignored(m))
268                continue;
269            this.matchSync(m, absolute, ifDir);
270        }
271        for (const [target, patterns] of processor.subwalks.entries()) {
272            tasks++;
273            this.walkCB2Sync(target, patterns, processor.child(), next);
274        }
275        next();
276    }
277}
278exports.GlobUtil = GlobUtil;
279class GlobWalker extends GlobUtil {
280    matches;
281    constructor(patterns, path, opts) {
282        super(patterns, path, opts);
283        this.matches = new Set();
284    }
285    matchEmit(e) {
286        this.matches.add(e);
287    }
288    async walk() {
289        if (this.signal?.aborted)
290            throw this.signal.reason;
291        if (this.path.isUnknown()) {
292            await this.path.lstat();
293        }
294        await new Promise((res, rej) => {
295            this.walkCB(this.path, this.patterns, () => {
296                if (this.signal?.aborted) {
297                    rej(this.signal.reason);
298                }
299                else {
300                    res(this.matches);
301                }
302            });
303        });
304        return this.matches;
305    }
306    walkSync() {
307        if (this.signal?.aborted)
308            throw this.signal.reason;
309        if (this.path.isUnknown()) {
310            this.path.lstatSync();
311        }
312        // nothing for the callback to do, because this never pauses
313        this.walkCBSync(this.path, this.patterns, () => {
314            if (this.signal?.aborted)
315                throw this.signal.reason;
316        });
317        return this.matches;
318    }
319}
320exports.GlobWalker = GlobWalker;
321class GlobStream extends GlobUtil {
322    results;
323    constructor(patterns, path, opts) {
324        super(patterns, path, opts);
325        this.results = new minipass_1.Minipass({
326            signal: this.signal,
327            objectMode: true,
328        });
329        this.results.on('drain', () => this.resume());
330        this.results.on('resume', () => this.resume());
331    }
332    matchEmit(e) {
333        this.results.write(e);
334        if (!this.results.flowing)
335            this.pause();
336    }
337    stream() {
338        const target = this.path;
339        if (target.isUnknown()) {
340            target.lstat().then(() => {
341                this.walkCB(target, this.patterns, () => this.results.end());
342            });
343        }
344        else {
345            this.walkCB(target, this.patterns, () => this.results.end());
346        }
347        return this.results;
348    }
349    streamSync() {
350        if (this.path.isUnknown()) {
351            this.path.lstatSync();
352        }
353        this.walkCBSync(this.path, this.patterns, () => this.results.end());
354        return this.results;
355    }
356}
357exports.GlobStream = GlobStream;
358//# sourceMappingURL=walker.js.map