• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import { Minimatch } from 'minimatch';
2import { PathScurry, PathScurryDarwin, PathScurryPosix, PathScurryWin32, } from 'path-scurry';
3import { fileURLToPath } from 'url';
4import { Pattern } from './pattern.js';
5import { GlobStream, GlobWalker } from './walker.js';
6// if no process global, just call it linux.
7// so we default to case-sensitive, / separators
8const defaultPlatform = typeof process === 'object' &&
9    process &&
10    typeof process.platform === 'string'
11    ? process.platform
12    : 'linux';
13/**
14 * An object that can perform glob pattern traversals.
15 */
16export class Glob {
17    absolute;
18    cwd;
19    root;
20    dot;
21    dotRelative;
22    follow;
23    ignore;
24    magicalBraces;
25    mark;
26    matchBase;
27    maxDepth;
28    nobrace;
29    nocase;
30    nodir;
31    noext;
32    noglobstar;
33    pattern;
34    platform;
35    realpath;
36    scurry;
37    stat;
38    signal;
39    windowsPathsNoEscape;
40    withFileTypes;
41    /**
42     * The options provided to the constructor.
43     */
44    opts;
45    /**
46     * An array of parsed immutable {@link Pattern} objects.
47     */
48    patterns;
49    /**
50     * All options are stored as properties on the `Glob` object.
51     *
52     * See {@link GlobOptions} for full options descriptions.
53     *
54     * Note that a previous `Glob` object can be passed as the
55     * `GlobOptions` to another `Glob` instantiation to re-use settings
56     * and caches with a new pattern.
57     *
58     * Traversal functions can be called multiple times to run the walk
59     * again.
60     */
61    constructor(pattern, opts) {
62        this.withFileTypes = !!opts.withFileTypes;
63        this.signal = opts.signal;
64        this.follow = !!opts.follow;
65        this.dot = !!opts.dot;
66        this.dotRelative = !!opts.dotRelative;
67        this.nodir = !!opts.nodir;
68        this.mark = !!opts.mark;
69        if (!opts.cwd) {
70            this.cwd = '';
71        }
72        else if (opts.cwd instanceof URL || opts.cwd.startsWith('file://')) {
73            opts.cwd = fileURLToPath(opts.cwd);
74        }
75        this.cwd = opts.cwd || '';
76        this.root = opts.root;
77        this.magicalBraces = !!opts.magicalBraces;
78        this.nobrace = !!opts.nobrace;
79        this.noext = !!opts.noext;
80        this.realpath = !!opts.realpath;
81        this.absolute = opts.absolute;
82        this.noglobstar = !!opts.noglobstar;
83        this.matchBase = !!opts.matchBase;
84        this.maxDepth =
85            typeof opts.maxDepth === 'number' ? opts.maxDepth : Infinity;
86        this.stat = !!opts.stat;
87        this.ignore = opts.ignore;
88        if (this.withFileTypes && this.absolute !== undefined) {
89            throw new Error('cannot set absolute and withFileTypes:true');
90        }
91        if (typeof pattern === 'string') {
92            pattern = [pattern];
93        }
94        this.windowsPathsNoEscape =
95            !!opts.windowsPathsNoEscape ||
96                opts.allowWindowsEscape === false;
97        if (this.windowsPathsNoEscape) {
98            pattern = pattern.map(p => p.replace(/\\/g, '/'));
99        }
100        if (this.matchBase) {
101            if (opts.noglobstar) {
102                throw new TypeError('base matching requires globstar');
103            }
104            pattern = pattern.map(p => (p.includes('/') ? p : `./**/${p}`));
105        }
106        this.pattern = pattern;
107        this.platform = opts.platform || defaultPlatform;
108        this.opts = { ...opts, platform: this.platform };
109        if (opts.scurry) {
110            this.scurry = opts.scurry;
111            if (opts.nocase !== undefined &&
112                opts.nocase !== opts.scurry.nocase) {
113                throw new Error('nocase option contradicts provided scurry option');
114            }
115        }
116        else {
117            const Scurry = opts.platform === 'win32'
118                ? PathScurryWin32
119                : opts.platform === 'darwin'
120                    ? PathScurryDarwin
121                    : opts.platform
122                        ? PathScurryPosix
123                        : PathScurry;
124            this.scurry = new Scurry(this.cwd, {
125                nocase: opts.nocase,
126                fs: opts.fs,
127            });
128        }
129        this.nocase = this.scurry.nocase;
130        // If you do nocase:true on a case-sensitive file system, then
131        // we need to use regexps instead of strings for non-magic
132        // path portions, because statting `aBc` won't return results
133        // for the file `AbC` for example.
134        const nocaseMagicOnly = this.platform === 'darwin' || this.platform === 'win32';
135        const mmo = {
136            // default nocase based on platform
137            ...opts,
138            dot: this.dot,
139            matchBase: this.matchBase,
140            nobrace: this.nobrace,
141            nocase: this.nocase,
142            nocaseMagicOnly,
143            nocomment: true,
144            noext: this.noext,
145            nonegate: true,
146            optimizationLevel: 2,
147            platform: this.platform,
148            windowsPathsNoEscape: this.windowsPathsNoEscape,
149            debug: !!this.opts.debug,
150        };
151        const mms = this.pattern.map(p => new Minimatch(p, mmo));
152        const [matchSet, globParts] = mms.reduce((set, m) => {
153            set[0].push(...m.set);
154            set[1].push(...m.globParts);
155            return set;
156        }, [[], []]);
157        this.patterns = matchSet.map((set, i) => {
158            return new Pattern(set, globParts[i], 0, this.platform);
159        });
160    }
161    async walk() {
162        // Walkers always return array of Path objects, so we just have to
163        // coerce them into the right shape.  It will have already called
164        // realpath() if the option was set to do so, so we know that's cached.
165        // start out knowing the cwd, at least
166        return [
167            ...(await new GlobWalker(this.patterns, this.scurry.cwd, {
168                ...this.opts,
169                maxDepth: this.maxDepth !== Infinity
170                    ? this.maxDepth + this.scurry.cwd.depth()
171                    : Infinity,
172                platform: this.platform,
173                nocase: this.nocase,
174            }).walk()),
175        ];
176    }
177    walkSync() {
178        return [
179            ...new GlobWalker(this.patterns, this.scurry.cwd, {
180                ...this.opts,
181                maxDepth: this.maxDepth !== Infinity
182                    ? this.maxDepth + this.scurry.cwd.depth()
183                    : Infinity,
184                platform: this.platform,
185                nocase: this.nocase,
186            }).walkSync(),
187        ];
188    }
189    stream() {
190        return new GlobStream(this.patterns, this.scurry.cwd, {
191            ...this.opts,
192            maxDepth: this.maxDepth !== Infinity
193                ? this.maxDepth + this.scurry.cwd.depth()
194                : Infinity,
195            platform: this.platform,
196            nocase: this.nocase,
197        }).stream();
198    }
199    streamSync() {
200        return new GlobStream(this.patterns, this.scurry.cwd, {
201            ...this.opts,
202            maxDepth: this.maxDepth !== Infinity
203                ? this.maxDepth + this.scurry.cwd.depth()
204                : Infinity,
205            platform: this.platform,
206            nocase: this.nocase,
207        }).streamSync();
208    }
209    /**
210     * Default sync iteration function. Returns a Generator that
211     * iterates over the results.
212     */
213    iterateSync() {
214        return this.streamSync()[Symbol.iterator]();
215    }
216    [Symbol.iterator]() {
217        return this.iterateSync();
218    }
219    /**
220     * Default async iteration function. Returns an AsyncGenerator that
221     * iterates over the results.
222     */
223    iterate() {
224        return this.stream()[Symbol.asyncIterator]();
225    }
226    [Symbol.asyncIterator]() {
227        return this.iterate();
228    }
229}
230//# sourceMappingURL=glob.js.map