Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
processor.js301 linesDownload Raw Back to commonjs
1"use strict";
2// synchronous utility for filtering entries and calculating subwalks
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.Processor = exports.SubWalks = exports.MatchRecord = exports.HasWalkedCache = void 0;
5const minimatch_1 = require("minimatch");
6/**
7 * A cache of which patterns have been processed for a given Path
8 */
9class HasWalkedCache {
10    store;
11    constructor(store = new Map()) {
12        this.store = store;
13    }
14    copy() {
15        return new HasWalkedCache(new Map(this.store));
16    }
17    hasWalked(target, pattern) {
18        return this.store.get(target.fullpath())?.has(pattern.globString());
19    }
20    storeWalked(target, pattern) {
21        const fullpath = target.fullpath();
22        const cached = this.store.get(fullpath);
23        if (cached)
24            cached.add(pattern.globString());
25        else
26            this.store.set(fullpath, new Set([pattern.globString()]));
27    }
28}
29exports.HasWalkedCache = HasWalkedCache;
30/**
31 * A record of which paths have been matched in a given walk step,
32 * and whether they only are considered a match if they are a directory,
33 * and whether their absolute or relative path should be returned.
34 */
35class MatchRecord {
36    store = new Map();
37    add(target, absolute, ifDir) {
38        const n = (absolute ? 2 : 0) | (ifDir ? 1 : 0);
39        const current = this.store.get(target);
40        this.store.set(target, current === undefined ? n : n & current);
41    }
42    // match, absolute, ifdir
43    entries() {
44        return [...this.store.entries()].map(([path, n]) => [
45            path,
46            !!(n & 2),
47            !!(n & 1),
48        ]);
49    }
50}
51exports.MatchRecord = MatchRecord;
52/**
53 * A collection of patterns that must be processed in a subsequent step
54 * for a given path.
55 */
56class SubWalks {
57    store = new Map();
58    add(target, pattern) {
59        if (!target.canReaddir()) {
60            return;
61        }
62        const subs = this.store.get(target);
63        if (subs) {
64            if (!subs.find(p => p.globString() === pattern.globString())) {
65                subs.push(pattern);
66            }
67        }
68        else
69            this.store.set(target, [pattern]);
70    }
71    get(target) {
72        const subs = this.store.get(target);
73        /* c8 ignore start */
74        if (!subs) {
75            throw new Error('attempting to walk unknown path');
76        }
77        /* c8 ignore stop */
78        return subs;
79    }
80    entries() {
81        return this.keys().map(k => [k, this.store.get(k)]);
82    }
83    keys() {
84        return [...this.store.keys()].filter(t => t.canReaddir());
85    }
86}
87exports.SubWalks = SubWalks;
88/**
89 * The class that processes patterns for a given path.
90 *
91 * Handles child entry filtering, and determining whether a path's
92 * directory contents must be read.
93 */
94class Processor {
95    hasWalkedCache;
96    matches = new MatchRecord();
97    subwalks = new SubWalks();
98    patterns;
99    follow;
100    dot;
101    opts;
102    constructor(opts, hasWalkedCache) {
103        this.opts = opts;
104        this.follow = !!opts.follow;
105        this.dot = !!opts.dot;
106        this.hasWalkedCache =
107            hasWalkedCache ? hasWalkedCache.copy() : new HasWalkedCache();
108    }
109    processPatterns(target, patterns) {
110        this.patterns = patterns;
111        const processingSet = patterns.map(p => [target, p]);
112        // map of paths to the magic-starting subwalks they need to walk
113        // first item in patterns is the filter
114        for (let [t, pattern] of processingSet) {
115            this.hasWalkedCache.storeWalked(t, pattern);
116            const root = pattern.root();
117            const absolute = pattern.isAbsolute() && this.opts.absolute !== false;
118            // start absolute patterns at root
119            if (root) {
120                t = t.resolve(root === '/' && this.opts.root !== undefined ?
121                    this.opts.root
122                    : root);
123                const rest = pattern.rest();
124                if (!rest) {
125                    this.matches.add(t, true, false);
126                    continue;
127                }
128                else {
129                    pattern = rest;
130                }
131            }
132            if (t.isENOENT())
133                continue;
134            let p;
135            let rest;
136            let changed = false;
137            while (typeof (p = pattern.pattern()) === 'string' &&
138                (rest = pattern.rest())) {
139                const c = t.resolve(p);
140                t = c;
141                pattern = rest;
142                changed = true;
143            }
144            p = pattern.pattern();
145            rest = pattern.rest();
146            if (changed) {
147                if (this.hasWalkedCache.hasWalked(t, pattern))
148                    continue;
149                this.hasWalkedCache.storeWalked(t, pattern);
150            }
151            // now we have either a final string for a known entry,
152            // more strings for an unknown entry,
153            // or a pattern starting with magic, mounted on t.
154            if (typeof p === 'string') {
155                // must not be final entry, otherwise we would have
156                // concatenated it earlier.
157                const ifDir = p === '..' || p === '' || p === '.';
158                this.matches.add(t.resolve(p), absolute, ifDir);
159                continue;
160            }
161            else if (p === minimatch_1.GLOBSTAR) {
162                // if no rest, match and subwalk pattern
163                // if rest, process rest and subwalk pattern
164                // if it's a symlink, but we didn't get here by way of a
165                // globstar match (meaning it's the first time THIS globstar
166                // has traversed a symlink), then we follow it. Otherwise, stop.
167                if (!t.isSymbolicLink() ||
168                    this.follow ||
169                    pattern.checkFollowGlobstar()) {
170                    this.subwalks.add(t, pattern);
171                }
172                const rp = rest?.pattern();
173                const rrest = rest?.rest();
174                if (!rest || ((rp === '' || rp === '.') && !rrest)) {
175                    // only HAS to be a dir if it ends in **/ or **/.
176                    // but ending in ** will match files as well.
177                    this.matches.add(t, absolute, rp === '' || rp === '.');
178                }
179                else {
180                    if (rp === '..') {
181                        // this would mean you're matching **/.. at the fs root,
182                        // and no thanks, I'm not gonna test that specific case.
183                        /* c8 ignore start */
184                        const tp = t.parent || t;
185                        /* c8 ignore stop */
186                        if (!rrest)
187                            this.matches.add(tp, absolute, true);
188                        else if (!this.hasWalkedCache.hasWalked(tp, rrest)) {
189                            this.subwalks.add(tp, rrest);
190                        }
191                    }
192                }
193            }
194            else if (p instanceof RegExp) {
195                this.subwalks.add(t, pattern);
196            }
197        }
198        return this;
199    }
200    subwalkTargets() {
201        return this.subwalks.keys();
202    }
203    child() {
204        return new Processor(this.opts, this.hasWalkedCache);
205    }
206    // return a new Processor containing the subwalks for each
207    // child entry, and a set of matches, and
208    // a hasWalkedCache that's a copy of this one
209    // then we're going to call
210    filterEntries(parent, entries) {
211        const patterns = this.subwalks.get(parent);
212        // put matches and entry walks into the results processor
213        const results = this.child();
214        for (const e of entries) {
215            for (const pattern of patterns) {
216                const absolute = pattern.isAbsolute();
217                const p = pattern.pattern();
218                const rest = pattern.rest();
219                if (p === minimatch_1.GLOBSTAR) {
220                    results.testGlobstar(e, pattern, rest, absolute);
221                }
222                else if (p instanceof RegExp) {
223                    results.testRegExp(e, p, rest, absolute);
224                }
225                else {
226                    results.testString(e, p, rest, absolute);
227                }
228            }
229        }
230        return results;
231    }
232    testGlobstar(e, pattern, rest, absolute) {
233        if (this.dot || !e.name.startsWith('.')) {
234            if (!pattern.hasMore()) {
235                this.matches.add(e, absolute, false);
236            }
237            if (e.canReaddir()) {
238                // if we're in follow mode or it's not a symlink, just keep
239                // testing the same pattern. If there's more after the globstar,
240                // then this symlink consumes the globstar. If not, then we can
241                // follow at most ONE symlink along the way, so we mark it, which
242                // also checks to ensure that it wasn't already marked.
243                if (this.follow || !e.isSymbolicLink()) {
244                    this.subwalks.add(e, pattern);
245                }
246                else if (e.isSymbolicLink()) {
247                    if (rest && pattern.checkFollowGlobstar()) {
248                        this.subwalks.add(e, rest);
249                    }
250                    else if (pattern.markFollowGlobstar()) {
251                        this.subwalks.add(e, pattern);
252                    }
253                }
254            }
255        }
256        // if the NEXT thing matches this entry, then also add
257        // the rest.
258        if (rest) {
259            const rp = rest.pattern();
260            if (typeof rp === 'string' &&
261                // dots and empty were handled already
262                rp !== '..' &&
263                rp !== '' &&
264                rp !== '.') {
265                this.testString(e, rp, rest.rest(), absolute);
266            }
267            else if (rp === '..') {
268                /* c8 ignore start */
269                const ep = e.parent || e;
270                /* c8 ignore stop */
271                this.subwalks.add(ep, rest);
272            }
273            else if (rp instanceof RegExp) {
274                this.testRegExp(e, rp, rest.rest(), absolute);
275            }
276        }
277    }
278    testRegExp(e, p, rest, absolute) {
279        if (!p.test(e.name))
280            return;
281        if (!rest) {
282            this.matches.add(e, absolute, false);
283        }
284        else {
285            this.subwalks.add(e, rest);
286        }
287    }
288    testString(e, p, rest, absolute) {
289        // should never happen?
290        if (!e.isNamed(p))
291            return;
292        if (!rest) {
293            this.matches.add(e, absolute, false);
294        }
295        else {
296            this.subwalks.add(e, rest);
297        }
298    }
299}
300exports.Processor = Processor;
301//# sourceMappingURL=processor.js.map
codekingpro/portable-devtools · Team Ai