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        /* c8 ignore start */
63        if (!opts)
64            throw new TypeError('glob options required');
65        /* c8 ignore stop */
66        this.withFileTypes = !!opts.withFileTypes;
67        this.signal = opts.signal;
68        this.follow = !!opts.follow;
69        this.dot = !!opts.dot;
70        this.dotRelative = !!opts.dotRelative;
71        this.nodir = !!opts.nodir;
72        this.mark = !!opts.mark;
73        if (!opts.cwd) {
74            this.cwd = '';
75        }
76        else if (opts.cwd instanceof URL || opts.cwd.startsWith('file://')) {
77            opts.cwd = fileURLToPath(opts.cwd);
78        }
79        this.cwd = opts.cwd || '';
80        this.root = opts.root;
81        this.magicalBraces = !!opts.magicalBraces;
82        this.nobrace = !!opts.nobrace;
83        this.noext = !!opts.noext;
84        this.realpath = !!opts.realpath;
85        this.absolute = opts.absolute;
86        this.noglobstar = !!opts.noglobstar;
87        this.matchBase = !!opts.matchBase;
88        this.maxDepth =
89            typeof opts.maxDepth === 'number' ? opts.maxDepth : Infinity;
90        this.stat = !!opts.stat;
91        this.ignore = opts.ignore;
92        if (this.withFileTypes && this.absolute !== undefined) {
93            throw new Error('cannot set absolute and withFileTypes:true');
94        }
95        if (typeof pattern === 'string') {
96            pattern = [pattern];
97        }
98        this.windowsPathsNoEscape =
99            !!opts.windowsPathsNoEscape ||
100                opts.allowWindowsEscape === false;
101        if (this.windowsPathsNoEscape) {
102            pattern = pattern.map(p => p.replace(/\\/g, '/'));
103        }
104        if (this.matchBase) {
105            if (opts.noglobstar) {
106                throw new TypeError('base matching requires globstar');
107            }
108            pattern = pattern.map(p => (p.includes('/') ? p : `./**/${p}`));
109        }
110        this.pattern = pattern;
111        this.platform = opts.platform || defaultPlatform;
112        this.opts = { ...opts, platform: this.platform };
113        if (opts.scurry) {
114            this.scurry = opts.scurry;
115            if (opts.nocase !== undefined &&
116                opts.nocase !== opts.scurry.nocase) {
117                throw new Error('nocase option contradicts provided scurry option');
118            }
119        }
120        else {
121            const Scurry = opts.platform === 'win32'
122                ? PathScurryWin32
123                : opts.platform === 'darwin'
124                    ? PathScurryDarwin
125                    : opts.platform
126                        ? PathScurryPosix
127                        : PathScurry;
128            this.scurry = new Scurry(this.cwd, {
129                nocase: opts.nocase,
130                fs: opts.fs,
131            });
132        }
133        this.nocase = this.scurry.nocase;
134        // If you do nocase:true on a case-sensitive file system, then
135        // we need to use regexps instead of strings for non-magic
136        // path portions, because statting `aBc` won't return results
137        // for the file `AbC` for example.
138        const nocaseMagicOnly = this.platform === 'darwin' || this.platform === 'win32';
139        const mmo = {
140            // default nocase based on platform
141            ...opts,
142            dot: this.dot,
143            matchBase: this.matchBase,
144            nobrace: this.nobrace,
145            nocase: this.nocase,
146            nocaseMagicOnly,
147            nocomment: true,
148            noext: this.noext,
149            nonegate: true,
150            optimizationLevel: 2,
151            platform: this.platform,
152            windowsPathsNoEscape: this.windowsPathsNoEscape,
153            debug: !!this.opts.debug,
154        };
155        const mms = this.pattern.map(p => new Minimatch(p, mmo));
156        const [matchSet, globParts] = mms.reduce((set, m) => {
157            set[0].push(...m.set);
158            set[1].push(...m.globParts);
159            return set;
160        }, [[], []]);
161        this.patterns = matchSet.map((set, i) => {
162            const g = globParts[i];
163            /* c8 ignore start */
164            if (!g)
165                throw new Error('invalid pattern object');
166            /* c8 ignore stop */
167            return new Pattern(set, g, 0, this.platform);
168        });
169    }
170    async walk() {
171        // Walkers always return array of Path objects, so we just have to
172        // coerce them into the right shape.  It will have already called
173        // realpath() if the option was set to do so, so we know that's cached.
174        // start out knowing the cwd, at least
175        return [
176            ...(await new GlobWalker(this.patterns, this.scurry.cwd, {
177                ...this.opts,
178                maxDepth: this.maxDepth !== Infinity
179                    ? this.maxDepth + this.scurry.cwd.depth()
180                    : Infinity,
181                platform: this.platform,
182                nocase: this.nocase,
183            }).walk()),
184        ];
185    }
186    walkSync() {
187        return [
188            ...new GlobWalker(this.patterns, this.scurry.cwd, {
189                ...this.opts,
190                maxDepth: this.maxDepth !== Infinity
191                    ? this.maxDepth + this.scurry.cwd.depth()
192                    : Infinity,
193                platform: this.platform,
194                nocase: this.nocase,
195            }).walkSync(),
196        ];
197    }
198    stream() {
199        return new GlobStream(this.patterns, this.scurry.cwd, {
200            ...this.opts,
201            maxDepth: this.maxDepth !== Infinity
202                ? this.maxDepth + this.scurry.cwd.depth()
203                : Infinity,
204            platform: this.platform,
205            nocase: this.nocase,
206        }).stream();
207    }
208    streamSync() {
209        return new GlobStream(this.patterns, this.scurry.cwd, {
210            ...this.opts,
211            maxDepth: this.maxDepth !== Infinity
212                ? this.maxDepth + this.scurry.cwd.depth()
213                : Infinity,
214            platform: this.platform,
215            nocase: this.nocase,
216        }).streamSync();
217    }
218    /**
219     * Default sync iteration function. Returns a Generator that
220     * iterates over the results.
221     */
222    iterateSync() {
223        return this.streamSync()[Symbol.iterator]();
224    }
225    [Symbol.iterator]() {
226        return this.iterateSync();
227    }
228    /**
229     * Default async iteration function. Returns an AsyncGenerator that
230     * iterates over the results.
231     */
232    iterate() {
233        return this.stream()[Symbol.asyncIterator]();
234    }
235    [Symbol.asyncIterator]() {
236        return this.iterate();
237    }
238}
239//# sourceMappingURL=glob.js.map