• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import expand from 'brace-expansion';
2import { assertValidPattern } from './assert-valid-pattern.js';
3import { AST } from './ast.js';
4import { escape } from './escape.js';
5import { unescape } from './unescape.js';
6export const minimatch = (p, pattern, options = {}) => {
7    assertValidPattern(pattern);
8    // shortcut: comments match nothing.
9    if (!options.nocomment && pattern.charAt(0) === '#') {
10        return false;
11    }
12    return new Minimatch(pattern, options).match(p);
13};
14// Optimized checking for the most common glob patterns.
15const starDotExtRE = /^\*+([^+@!?\*\[\(]*)$/;
16const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext);
17const starDotExtTestDot = (ext) => (f) => f.endsWith(ext);
18const starDotExtTestNocase = (ext) => {
19    ext = ext.toLowerCase();
20    return (f) => !f.startsWith('.') && f.toLowerCase().endsWith(ext);
21};
22const starDotExtTestNocaseDot = (ext) => {
23    ext = ext.toLowerCase();
24    return (f) => f.toLowerCase().endsWith(ext);
25};
26const starDotStarRE = /^\*+\.\*+$/;
27const starDotStarTest = (f) => !f.startsWith('.') && f.includes('.');
28const starDotStarTestDot = (f) => f !== '.' && f !== '..' && f.includes('.');
29const dotStarRE = /^\.\*+$/;
30const dotStarTest = (f) => f !== '.' && f !== '..' && f.startsWith('.');
31const starRE = /^\*+$/;
32const starTest = (f) => f.length !== 0 && !f.startsWith('.');
33const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..';
34const qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/;
35const qmarksTestNocase = ([$0, ext = '']) => {
36    const noext = qmarksTestNoExt([$0]);
37    if (!ext)
38        return noext;
39    ext = ext.toLowerCase();
40    return (f) => noext(f) && f.toLowerCase().endsWith(ext);
41};
42const qmarksTestNocaseDot = ([$0, ext = '']) => {
43    const noext = qmarksTestNoExtDot([$0]);
44    if (!ext)
45        return noext;
46    ext = ext.toLowerCase();
47    return (f) => noext(f) && f.toLowerCase().endsWith(ext);
48};
49const qmarksTestDot = ([$0, ext = '']) => {
50    const noext = qmarksTestNoExtDot([$0]);
51    return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
52};
53const qmarksTest = ([$0, ext = '']) => {
54    const noext = qmarksTestNoExt([$0]);
55    return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
56};
57const qmarksTestNoExt = ([$0]) => {
58    const len = $0.length;
59    return (f) => f.length === len && !f.startsWith('.');
60};
61const qmarksTestNoExtDot = ([$0]) => {
62    const len = $0.length;
63    return (f) => f.length === len && f !== '.' && f !== '..';
64};
65/* c8 ignore start */
66const defaultPlatform = (typeof process === 'object' && process
67    ? (typeof process.env === 'object' &&
68        process.env &&
69        process.env.__MINIMATCH_TESTING_PLATFORM__) ||
70        process.platform
71    : 'posix');
72const path = {
73    win32: { sep: '\\' },
74    posix: { sep: '/' },
75};
76/* c8 ignore stop */
77export const sep = defaultPlatform === 'win32' ? path.win32.sep : path.posix.sep;
78minimatch.sep = sep;
79export const GLOBSTAR = Symbol('globstar **');
80minimatch.GLOBSTAR = GLOBSTAR;
81// any single thing other than /
82// don't need to escape / when using new RegExp()
83const qmark = '[^/]';
84// * => any number of characters
85const star = qmark + '*?';
86// ** when dots are allowed.  Anything goes, except .. and .
87// not (^ or / followed by one or two dots followed by $ or /),
88// followed by anything, any number of times.
89const twoStarDot = '(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?';
90// not a ^ or / followed by a dot,
91// followed by anything, any number of times.
92const twoStarNoDot = '(?:(?!(?:\\/|^)\\.).)*?';
93export const filter = (pattern, options = {}) => (p) => minimatch(p, pattern, options);
94minimatch.filter = filter;
95const ext = (a, b = {}) => Object.assign({}, a, b);
96export const defaults = (def) => {
97    if (!def || typeof def !== 'object' || !Object.keys(def).length) {
98        return minimatch;
99    }
100    const orig = minimatch;
101    const m = (p, pattern, options = {}) => orig(p, pattern, ext(def, options));
102    return Object.assign(m, {
103        Minimatch: class Minimatch extends orig.Minimatch {
104            constructor(pattern, options = {}) {
105                super(pattern, ext(def, options));
106            }
107            static defaults(options) {
108                return orig.defaults(ext(def, options)).Minimatch;
109            }
110        },
111        AST: class AST extends orig.AST {
112            /* c8 ignore start */
113            constructor(type, parent, options = {}) {
114                super(type, parent, ext(def, options));
115            }
116            /* c8 ignore stop */
117            static fromGlob(pattern, options = {}) {
118                return orig.AST.fromGlob(pattern, ext(def, options));
119            }
120        },
121        unescape: (s, options = {}) => orig.unescape(s, ext(def, options)),
122        escape: (s, options = {}) => orig.escape(s, ext(def, options)),
123        filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)),
124        defaults: (options) => orig.defaults(ext(def, options)),
125        makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)),
126        braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)),
127        match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)),
128        sep: orig.sep,
129        GLOBSTAR: GLOBSTAR,
130    });
131};
132minimatch.defaults = defaults;
133// Brace expansion:
134// a{b,c}d -> abd acd
135// a{b,}c -> abc ac
136// a{0..3}d -> a0d a1d a2d a3d
137// a{b,c{d,e}f}g -> abg acdfg acefg
138// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg
139//
140// Invalid sets are not expanded.
141// a{2..}b -> a{2..}b
142// a{b}c -> a{b}c
143export const braceExpand = (pattern, options = {}) => {
144    assertValidPattern(pattern);
145    // Thanks to Yeting Li <https://github.com/yetingli> for
146    // improving this regexp to avoid a ReDOS vulnerability.
147    if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
148        // shortcut. no need to expand.
149        return [pattern];
150    }
151    return expand(pattern);
152};
153minimatch.braceExpand = braceExpand;
154// parse a component of the expanded set.
155// At this point, no pattern may contain "/" in it
156// so we're going to return a 2d array, where each entry is the full
157// pattern, split on '/', and then turned into a regular expression.
158// A regexp is made at the end which joins each array with an
159// escaped /, and another full one which joins each regexp with |.
160//
161// Following the lead of Bash 4.1, note that "**" only has special meaning
162// when it is the *only* thing in a path portion.  Otherwise, any series
163// of * is equivalent to a single *.  Globstar behavior is enabled by
164// default, and can be disabled by setting options.noglobstar.
165export const makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
166minimatch.makeRe = makeRe;
167export const match = (list, pattern, options = {}) => {
168    const mm = new Minimatch(pattern, options);
169    list = list.filter(f => mm.match(f));
170    if (mm.options.nonull && !list.length) {
171        list.push(pattern);
172    }
173    return list;
174};
175minimatch.match = match;
176// replace stuff like \* with *
177const globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/;
178const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
179export class Minimatch {
180    options;
181    set;
182    pattern;
183    windowsPathsNoEscape;
184    nonegate;
185    negate;
186    comment;
187    empty;
188    preserveMultipleSlashes;
189    partial;
190    globSet;
191    globParts;
192    nocase;
193    isWindows;
194    platform;
195    windowsNoMagicRoot;
196    regexp;
197    constructor(pattern, options = {}) {
198        assertValidPattern(pattern);
199        options = options || {};
200        this.options = options;
201        this.pattern = pattern;
202        this.platform = options.platform || defaultPlatform;
203        this.isWindows = this.platform === 'win32';
204        this.windowsPathsNoEscape =
205            !!options.windowsPathsNoEscape || options.allowWindowsEscape === false;
206        if (this.windowsPathsNoEscape) {
207            this.pattern = this.pattern.replace(/\\/g, '/');
208        }
209        this.preserveMultipleSlashes = !!options.preserveMultipleSlashes;
210        this.regexp = null;
211        this.negate = false;
212        this.nonegate = !!options.nonegate;
213        this.comment = false;
214        this.empty = false;
215        this.partial = !!options.partial;
216        this.nocase = !!this.options.nocase;
217        this.windowsNoMagicRoot =
218            options.windowsNoMagicRoot !== undefined
219                ? options.windowsNoMagicRoot
220                : !!(this.isWindows && this.nocase);
221        this.globSet = [];
222        this.globParts = [];
223        this.set = [];
224        // make the set of regexps etc.
225        this.make();
226    }
227    hasMagic() {
228        if (this.options.magicalBraces && this.set.length > 1) {
229            return true;
230        }
231        for (const pattern of this.set) {
232            for (const part of pattern) {
233                if (typeof part !== 'string')
234                    return true;
235            }
236        }
237        return false;
238    }
239    debug(..._) { }
240    make() {
241        const pattern = this.pattern;
242        const options = this.options;
243        // empty patterns and comments match nothing.
244        if (!options.nocomment && pattern.charAt(0) === '#') {
245            this.comment = true;
246            return;
247        }
248        if (!pattern) {
249            this.empty = true;
250            return;
251        }
252        // step 1: figure out negation, etc.
253        this.parseNegate();
254        // step 2: expand braces
255        this.globSet = [...new Set(this.braceExpand())];
256        if (options.debug) {
257            this.debug = (...args) => console.error(...args);
258        }
259        this.debug(this.pattern, this.globSet);
260        // step 3: now we have a set, so turn each one into a series of
261        // path-portion matching patterns.
262        // These will be regexps, except in the case of "**", which is
263        // set to the GLOBSTAR object for globstar behavior,
264        // and will not contain any / characters
265        //
266        // First, we preprocess to make the glob pattern sets a bit simpler
267        // and deduped.  There are some perf-killing patterns that can cause
268        // problems with a glob walk, but we can simplify them down a bit.
269        const rawGlobParts = this.globSet.map(s => this.slashSplit(s));
270        this.globParts = this.preprocess(rawGlobParts);
271        this.debug(this.pattern, this.globParts);
272        // glob --> regexps
273        let set = this.globParts.map((s, _, __) => {
274            if (this.isWindows && this.windowsNoMagicRoot) {
275                // check if it's a drive or unc path.
276                const isUNC = s[0] === '' &&
277                    s[1] === '' &&
278                    (s[2] === '?' || !globMagic.test(s[2])) &&
279                    !globMagic.test(s[3]);
280                const isDrive = /^[a-z]:/i.test(s[0]);
281                if (isUNC) {
282                    return [...s.slice(0, 4), ...s.slice(4).map(ss => this.parse(ss))];
283                }
284                else if (isDrive) {
285                    return [s[0], ...s.slice(1).map(ss => this.parse(ss))];
286                }
287            }
288            return s.map(ss => this.parse(ss));
289        });
290        this.debug(this.pattern, set);
291        // filter out everything that didn't compile properly.
292        this.set = set.filter(s => s.indexOf(false) === -1);
293        // do not treat the ? in UNC paths as magic
294        if (this.isWindows) {
295            for (let i = 0; i < this.set.length; i++) {
296                const p = this.set[i];
297                if (p[0] === '' &&
298                    p[1] === '' &&
299                    this.globParts[i][2] === '?' &&
300                    typeof p[3] === 'string' &&
301                    /^[a-z]:$/i.test(p[3])) {
302                    p[2] = '?';
303                }
304            }
305        }
306        this.debug(this.pattern, this.set);
307    }
308    // various transforms to equivalent pattern sets that are
309    // faster to process in a filesystem walk.  The goal is to
310    // eliminate what we can, and push all ** patterns as far
311    // to the right as possible, even if it increases the number
312    // of patterns that we have to process.
313    preprocess(globParts) {
314        // if we're not in globstar mode, then turn all ** into *
315        if (this.options.noglobstar) {
316            for (let i = 0; i < globParts.length; i++) {
317                for (let j = 0; j < globParts[i].length; j++) {
318                    if (globParts[i][j] === '**') {
319                        globParts[i][j] = '*';
320                    }
321                }
322            }
323        }
324        const { optimizationLevel = 1 } = this.options;
325        if (optimizationLevel >= 2) {
326            // aggressive optimization for the purpose of fs walking
327            globParts = this.firstPhasePreProcess(globParts);
328            globParts = this.secondPhasePreProcess(globParts);
329        }
330        else if (optimizationLevel >= 1) {
331            // just basic optimizations to remove some .. parts
332            globParts = this.levelOneOptimize(globParts);
333        }
334        else {
335            globParts = this.adjascentGlobstarOptimize(globParts);
336        }
337        return globParts;
338    }
339    // just get rid of adjascent ** portions
340    adjascentGlobstarOptimize(globParts) {
341        return globParts.map(parts => {
342            let gs = -1;
343            while (-1 !== (gs = parts.indexOf('**', gs + 1))) {
344                let i = gs;
345                while (parts[i + 1] === '**') {
346                    i++;
347                }
348                if (i !== gs) {
349                    parts.splice(gs, i - gs);
350                }
351            }
352            return parts;
353        });
354    }
355    // get rid of adjascent ** and resolve .. portions
356    levelOneOptimize(globParts) {
357        return globParts.map(parts => {
358            parts = parts.reduce((set, part) => {
359                const prev = set[set.length - 1];
360                if (part === '**' && prev === '**') {
361                    return set;
362                }
363                if (part === '..') {
364                    if (prev && prev !== '..' && prev !== '.' && prev !== '**') {
365                        set.pop();
366                        return set;
367                    }
368                }
369                set.push(part);
370                return set;
371            }, []);
372            return parts.length === 0 ? [''] : parts;
373        });
374    }
375    levelTwoFileOptimize(parts) {
376        if (!Array.isArray(parts)) {
377            parts = this.slashSplit(parts);
378        }
379        let didSomething = false;
380        do {
381            didSomething = false;
382            // <pre>/<e>/<rest> -> <pre>/<rest>
383            if (!this.preserveMultipleSlashes) {
384                for (let i = 1; i < parts.length - 1; i++) {
385                    const p = parts[i];
386                    // don't squeeze out UNC patterns
387                    if (i === 1 && p === '' && parts[0] === '')
388                        continue;
389                    if (p === '.' || p === '') {
390                        didSomething = true;
391                        parts.splice(i, 1);
392                        i--;
393                    }
394                }
395                if (parts[0] === '.' &&
396                    parts.length === 2 &&
397                    (parts[1] === '.' || parts[1] === '')) {
398                    didSomething = true;
399                    parts.pop();
400                }
401            }
402            // <pre>/<p>/../<rest> -> <pre>/<rest>
403            let dd = 0;
404            while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
405                const p = parts[dd - 1];
406                if (p && p !== '.' && p !== '..' && p !== '**') {
407                    didSomething = true;
408                    parts.splice(dd - 1, 2);
409                    dd -= 2;
410                }
411            }
412        } while (didSomething);
413        return parts.length === 0 ? [''] : parts;
414    }
415    // First phase: single-pattern processing
416    // <pre> is 1 or more portions
417    // <rest> is 1 or more portions
418    // <p> is any portion other than ., .., '', or **
419    // <e> is . or ''
420    //
421    // **/.. is *brutal* for filesystem walking performance, because
422    // it effectively resets the recursive walk each time it occurs,
423    // and ** cannot be reduced out by a .. pattern part like a regexp
424    // or most strings (other than .., ., and '') can be.
425    //
426    // <pre>/**/../<p>/<p>/<rest> -> {<pre>/../<p>/<p>/<rest>,<pre>/**/<p>/<p>/<rest>}
427    // <pre>/<e>/<rest> -> <pre>/<rest>
428    // <pre>/<p>/../<rest> -> <pre>/<rest>
429    // **/**/<rest> -> **/<rest>
430    //
431    // **/*/<rest> -> */**/<rest> <== not valid because ** doesn't follow
432    // this WOULD be allowed if ** did follow symlinks, or * didn't
433    firstPhasePreProcess(globParts) {
434        let didSomething = false;
435        do {
436            didSomething = false;
437            // <pre>/**/../<p>/<p>/<rest> -> {<pre>/../<p>/<p>/<rest>,<pre>/**/<p>/<p>/<rest>}
438            for (let parts of globParts) {
439                let gs = -1;
440                while (-1 !== (gs = parts.indexOf('**', gs + 1))) {
441                    let gss = gs;
442                    while (parts[gss + 1] === '**') {
443                        // <pre>/**/**/<rest> -> <pre>/**/<rest>
444                        gss++;
445                    }
446                    // eg, if gs is 2 and gss is 4, that means we have 3 **
447                    // parts, and can remove 2 of them.
448                    if (gss > gs) {
449                        parts.splice(gs + 1, gss - gs);
450                    }
451                    let next = parts[gs + 1];
452                    const p = parts[gs + 2];
453                    const p2 = parts[gs + 3];
454                    if (next !== '..')
455                        continue;
456                    if (!p ||
457                        p === '.' ||
458                        p === '..' ||
459                        !p2 ||
460                        p2 === '.' ||
461                        p2 === '..') {
462                        continue;
463                    }
464                    didSomething = true;
465                    // edit parts in place, and push the new one
466                    parts.splice(gs, 1);
467                    const other = parts.slice(0);
468                    other[gs] = '**';
469                    globParts.push(other);
470                    gs--;
471                }
472                // <pre>/<e>/<rest> -> <pre>/<rest>
473                if (!this.preserveMultipleSlashes) {
474                    for (let i = 1; i < parts.length - 1; i++) {
475                        const p = parts[i];
476                        // don't squeeze out UNC patterns
477                        if (i === 1 && p === '' && parts[0] === '')
478                            continue;
479                        if (p === '.' || p === '') {
480                            didSomething = true;
481                            parts.splice(i, 1);
482                            i--;
483                        }
484                    }
485                    if (parts[0] === '.' &&
486                        parts.length === 2 &&
487                        (parts[1] === '.' || parts[1] === '')) {
488                        didSomething = true;
489                        parts.pop();
490                    }
491                }
492                // <pre>/<p>/../<rest> -> <pre>/<rest>
493                let dd = 0;
494                while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
495                    const p = parts[dd - 1];
496                    if (p && p !== '.' && p !== '..' && p !== '**') {
497                        didSomething = true;
498                        const needDot = dd === 1 && parts[dd + 1] === '**';
499                        const splin = needDot ? ['.'] : [];
500                        parts.splice(dd - 1, 2, ...splin);
501                        if (parts.length === 0)
502                            parts.push('');
503                        dd -= 2;
504                    }
505                }
506            }
507        } while (didSomething);
508        return globParts;
509    }
510    // second phase: multi-pattern dedupes
511    // {<pre>/*/<rest>,<pre>/<p>/<rest>} -> <pre>/*/<rest>
512    // {<pre>/<rest>,<pre>/<rest>} -> <pre>/<rest>
513    // {<pre>/**/<rest>,<pre>/<rest>} -> <pre>/**/<rest>
514    //
515    // {<pre>/**/<rest>,<pre>/**/<p>/<rest>} -> <pre>/**/<rest>
516    // ^-- not valid because ** doens't follow symlinks
517    secondPhasePreProcess(globParts) {
518        for (let i = 0; i < globParts.length - 1; i++) {
519            for (let j = i + 1; j < globParts.length; j++) {
520                const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
521                if (!matched)
522                    continue;
523                globParts[i] = matched;
524                globParts[j] = [];
525            }
526        }
527        return globParts.filter(gs => gs.length);
528    }
529    partsMatch(a, b, emptyGSMatch = false) {
530        let ai = 0;
531        let bi = 0;
532        let result = [];
533        let which = '';
534        while (ai < a.length && bi < b.length) {
535            if (a[ai] === b[bi]) {
536                result.push(which === 'b' ? b[bi] : a[ai]);
537                ai++;
538                bi++;
539            }
540            else if (emptyGSMatch && a[ai] === '**' && b[bi] === a[ai + 1]) {
541                result.push(a[ai]);
542                ai++;
543            }
544            else if (emptyGSMatch && b[bi] === '**' && a[ai] === b[bi + 1]) {
545                result.push(b[bi]);
546                bi++;
547            }
548            else if (a[ai] === '*' &&
549                b[bi] &&
550                (this.options.dot || !b[bi].startsWith('.')) &&
551                b[bi] !== '**') {
552                if (which === 'b')
553                    return false;
554                which = 'a';
555                result.push(a[ai]);
556                ai++;
557                bi++;
558            }
559            else if (b[bi] === '*' &&
560                a[ai] &&
561                (this.options.dot || !a[ai].startsWith('.')) &&
562                a[ai] !== '**') {
563                if (which === 'a')
564                    return false;
565                which = 'b';
566                result.push(b[bi]);
567                ai++;
568                bi++;
569            }
570            else {
571                return false;
572            }
573        }
574        // if we fall out of the loop, it means they two are identical
575        // as long as their lengths match
576        return a.length === b.length && result;
577    }
578    parseNegate() {
579        if (this.nonegate)
580            return;
581        const pattern = this.pattern;
582        let negate = false;
583        let negateOffset = 0;
584        for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
585            negate = !negate;
586            negateOffset++;
587        }
588        if (negateOffset)
589            this.pattern = pattern.slice(negateOffset);
590        this.negate = negate;
591    }
592    // set partial to true to test if, for example,
593    // "/a/b" matches the start of "/*/b/*/d"
594    // Partial means, if you run out of file before you run
595    // out of pattern, then that's fine, as long as all
596    // the parts match.
597    matchOne(file, pattern, partial = false) {
598        const options = this.options;
599        // UNC paths like //?/X:/... can match X:/... and vice versa
600        // Drive letters in absolute drive or unc paths are always compared
601        // case-insensitively.
602        if (this.isWindows) {
603            const fileDrive = typeof file[0] === 'string' && /^[a-z]:$/i.test(file[0]);
604            const fileUNC = !fileDrive &&
605                file[0] === '' &&
606                file[1] === '' &&
607                file[2] === '?' &&
608                /^[a-z]:$/i.test(file[3]);
609            const patternDrive = typeof pattern[0] === 'string' && /^[a-z]:$/i.test(pattern[0]);
610            const patternUNC = !patternDrive &&
611                pattern[0] === '' &&
612                pattern[1] === '' &&
613                pattern[2] === '?' &&
614                typeof pattern[3] === 'string' &&
615                /^[a-z]:$/i.test(pattern[3]);
616            const fdi = fileUNC ? 3 : fileDrive ? 0 : undefined;
617            const pdi = patternUNC ? 3 : patternDrive ? 0 : undefined;
618            if (typeof fdi === 'number' && typeof pdi === 'number') {
619                const [fd, pd] = [file[fdi], pattern[pdi]];
620                if (fd.toLowerCase() === pd.toLowerCase()) {
621                    pattern[pdi] = fd;
622                    if (pdi > fdi) {
623                        pattern = pattern.slice(pdi);
624                    }
625                    else if (fdi > pdi) {
626                        file = file.slice(fdi);
627                    }
628                }
629            }
630        }
631        // resolve and reduce . and .. portions in the file as well.
632        // dont' need to do the second phase, because it's only one string[]
633        const { optimizationLevel = 1 } = this.options;
634        if (optimizationLevel >= 2) {
635            file = this.levelTwoFileOptimize(file);
636        }
637        this.debug('matchOne', this, { file, pattern });
638        this.debug('matchOne', file.length, pattern.length);
639        for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
640            this.debug('matchOne loop');
641            var p = pattern[pi];
642            var f = file[fi];
643            this.debug(pattern, p, f);
644            // should be impossible.
645            // some invalid regexp stuff in the set.
646            /* c8 ignore start */
647            if (p === false) {
648                return false;
649            }
650            /* c8 ignore stop */
651            if (p === GLOBSTAR) {
652                this.debug('GLOBSTAR', [pattern, p, f]);
653                // "**"
654                // a/**/b/**/c would match the following:
655                // a/b/x/y/z/c
656                // a/x/y/z/b/c
657                // a/b/x/b/x/c
658                // a/b/c
659                // To do this, take the rest of the pattern after
660                // the **, and see if it would match the file remainder.
661                // If so, return success.
662                // If not, the ** "swallows" a segment, and try again.
663                // This is recursively awful.
664                //
665                // a/**/b/**/c matching a/b/x/y/z/c
666                // - a matches a
667                // - doublestar
668                //   - matchOne(b/x/y/z/c, b/**/c)
669                //     - b matches b
670                //     - doublestar
671                //       - matchOne(x/y/z/c, c) -> no
672                //       - matchOne(y/z/c, c) -> no
673                //       - matchOne(z/c, c) -> no
674                //       - matchOne(c, c) yes, hit
675                var fr = fi;
676                var pr = pi + 1;
677                if (pr === pl) {
678                    this.debug('** at the end');
679                    // a ** at the end will just swallow the rest.
680                    // We have found a match.
681                    // however, it will not swallow /.x, unless
682                    // options.dot is set.
683                    // . and .. are *never* matched by **, for explosively
684                    // exponential reasons.
685                    for (; fi < fl; fi++) {
686                        if (file[fi] === '.' ||
687                            file[fi] === '..' ||
688                            (!options.dot && file[fi].charAt(0) === '.'))
689                            return false;
690                    }
691                    return true;
692                }
693                // ok, let's see if we can swallow whatever we can.
694                while (fr < fl) {
695                    var swallowee = file[fr];
696                    this.debug('\nglobstar while', file, fr, pattern, pr, swallowee);
697                    // XXX remove this slice.  Just pass the start index.
698                    if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
699                        this.debug('globstar found match!', fr, fl, swallowee);
700                        // found a match.
701                        return true;
702                    }
703                    else {
704                        // can't swallow "." or ".." ever.
705                        // can only swallow ".foo" when explicitly asked.
706                        if (swallowee === '.' ||
707                            swallowee === '..' ||
708                            (!options.dot && swallowee.charAt(0) === '.')) {
709                            this.debug('dot detected!', file, fr, pattern, pr);
710                            break;
711                        }
712                        // ** swallows a segment, and continue.
713                        this.debug('globstar swallow a segment, and continue');
714                        fr++;
715                    }
716                }
717                // no match was found.
718                // However, in partial mode, we can't say this is necessarily over.
719                /* c8 ignore start */
720                if (partial) {
721                    // ran out of file
722                    this.debug('\n>>> no match, partial?', file, fr, pattern, pr);
723                    if (fr === fl) {
724                        return true;
725                    }
726                }
727                /* c8 ignore stop */
728                return false;
729            }
730            // something other than **
731            // non-magic patterns just have to match exactly
732            // patterns with magic have been turned into regexps.
733            let hit;
734            if (typeof p === 'string') {
735                hit = f === p;
736                this.debug('string match', p, f, hit);
737            }
738            else {
739                hit = p.test(f);
740                this.debug('pattern match', p, f, hit);
741            }
742            if (!hit)
743                return false;
744        }
745        // Note: ending in / means that we'll get a final ""
746        // at the end of the pattern.  This can only match a
747        // corresponding "" at the end of the file.
748        // If the file ends in /, then it can only match a
749        // a pattern that ends in /, unless the pattern just
750        // doesn't have any more for it. But, a/b/ should *not*
751        // match "a/b/*", even though "" matches against the
752        // [^/]*? pattern, except in partial mode, where it might
753        // simply not be reached yet.
754        // However, a/b/ should still satisfy a/*
755        // now either we fell off the end of the pattern, or we're done.
756        if (fi === fl && pi === pl) {
757            // ran out of pattern and filename at the same time.
758            // an exact hit!
759            return true;
760        }
761        else if (fi === fl) {
762            // ran out of file, but still had pattern left.
763            // this is ok if we're doing the match as part of
764            // a glob fs traversal.
765            return partial;
766        }
767        else if (pi === pl) {
768            // ran out of pattern, still have file left.
769            // this is only acceptable if we're on the very last
770            // empty segment of a file with a trailing slash.
771            // a/* should match a/b/
772            return fi === fl - 1 && file[fi] === '';
773            /* c8 ignore start */
774        }
775        else {
776            // should be unreachable.
777            throw new Error('wtf?');
778        }
779        /* c8 ignore stop */
780    }
781    braceExpand() {
782        return braceExpand(this.pattern, this.options);
783    }
784    parse(pattern) {
785        assertValidPattern(pattern);
786        const options = this.options;
787        // shortcuts
788        if (pattern === '**')
789            return GLOBSTAR;
790        if (pattern === '')
791            return '';
792        // far and away, the most common glob pattern parts are
793        // *, *.*, and *.<ext>  Add a fast check method for those.
794        let m;
795        let fastTest = null;
796        if ((m = pattern.match(starRE))) {
797            fastTest = options.dot ? starTestDot : starTest;
798        }
799        else if ((m = pattern.match(starDotExtRE))) {
800            fastTest = (options.nocase
801                ? options.dot
802                    ? starDotExtTestNocaseDot
803                    : starDotExtTestNocase
804                : options.dot
805                    ? starDotExtTestDot
806                    : starDotExtTest)(m[1]);
807        }
808        else if ((m = pattern.match(qmarksRE))) {
809            fastTest = (options.nocase
810                ? options.dot
811                    ? qmarksTestNocaseDot
812                    : qmarksTestNocase
813                : options.dot
814                    ? qmarksTestDot
815                    : qmarksTest)(m);
816        }
817        else if ((m = pattern.match(starDotStarRE))) {
818            fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
819        }
820        else if ((m = pattern.match(dotStarRE))) {
821            fastTest = dotStarTest;
822        }
823        const re = AST.fromGlob(pattern, this.options).toMMPattern();
824        return fastTest ? Object.assign(re, { test: fastTest }) : re;
825    }
826    makeRe() {
827        if (this.regexp || this.regexp === false)
828            return this.regexp;
829        // at this point, this.set is a 2d array of partial
830        // pattern strings, or "**".
831        //
832        // It's better to use .match().  This function shouldn't
833        // be used, really, but it's pretty convenient sometimes,
834        // when you just want to work with a regex.
835        const set = this.set;
836        if (!set.length) {
837            this.regexp = false;
838            return this.regexp;
839        }
840        const options = this.options;
841        const twoStar = options.noglobstar
842            ? star
843            : options.dot
844                ? twoStarDot
845                : twoStarNoDot;
846        const flags = new Set(options.nocase ? ['i'] : []);
847        // regexpify non-globstar patterns
848        // if ** is only item, then we just do one twoStar
849        // if ** is first, and there are more, prepend (\/|twoStar\/)? to next
850        // if ** is last, append (\/twoStar|) to previous
851        // if ** is in the middle, append (\/|\/twoStar\/) to previous
852        // then filter out GLOBSTAR symbols
853        let re = set
854            .map(pattern => {
855            const pp = pattern.map(p => {
856                if (p instanceof RegExp) {
857                    for (const f of p.flags.split(''))
858                        flags.add(f);
859                }
860                return typeof p === 'string'
861                    ? regExpEscape(p)
862                    : p === GLOBSTAR
863                        ? GLOBSTAR
864                        : p._src;
865            });
866            pp.forEach((p, i) => {
867                const next = pp[i + 1];
868                const prev = pp[i - 1];
869                if (p !== GLOBSTAR || prev === GLOBSTAR) {
870                    return;
871                }
872                if (prev === undefined) {
873                    if (next !== undefined && next !== GLOBSTAR) {
874                        pp[i + 1] = '(?:\\/|' + twoStar + '\\/)?' + next;
875                    }
876                    else {
877                        pp[i] = twoStar;
878                    }
879                }
880                else if (next === undefined) {
881                    pp[i - 1] = prev + '(?:\\/|' + twoStar + ')?';
882                }
883                else if (next !== GLOBSTAR) {
884                    pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + '\\/)' + next;
885                    pp[i + 1] = GLOBSTAR;
886                }
887            });
888            return pp.filter(p => p !== GLOBSTAR).join('/');
889        })
890            .join('|');
891        // need to wrap in parens if we had more than one thing with |,
892        // otherwise only the first will be anchored to ^ and the last to $
893        const [open, close] = set.length > 1 ? ['(?:', ')'] : ['', ''];
894        // must match entire pattern
895        // ending in a * or ** will make it less strict.
896        re = '^' + open + re + close + '$';
897        // can match anything, as long as it's not this.
898        if (this.negate)
899            re = '^(?!' + re + ').+$';
900        try {
901            this.regexp = new RegExp(re, [...flags].join(''));
902            /* c8 ignore start */
903        }
904        catch (ex) {
905            // should be impossible
906            this.regexp = false;
907        }
908        /* c8 ignore stop */
909        return this.regexp;
910    }
911    slashSplit(p) {
912        // if p starts with // on windows, we preserve that
913        // so that UNC paths aren't broken.  Otherwise, any number of
914        // / characters are coalesced into one, unless
915        // preserveMultipleSlashes is set to true.
916        if (this.preserveMultipleSlashes) {
917            return p.split('/');
918        }
919        else if (this.isWindows && /^\/\/[^\/]+/.test(p)) {
920            // add an extra '' for the one we lose
921            return ['', ...p.split(/\/+/)];
922        }
923        else {
924            return p.split(/\/+/);
925        }
926    }
927    match(f, partial = this.partial) {
928        this.debug('match', f, this.pattern);
929        // short-circuit in the case of busted things.
930        // comments, etc.
931        if (this.comment) {
932            return false;
933        }
934        if (this.empty) {
935            return f === '';
936        }
937        if (f === '/' && partial) {
938            return true;
939        }
940        const options = this.options;
941        // windows: need to use /, not \
942        if (this.isWindows) {
943            f = f.split('\\').join('/');
944        }
945        // treat the test path as a set of pathparts.
946        const ff = this.slashSplit(f);
947        this.debug(this.pattern, 'split', ff);
948        // just ONE of the pattern sets in this.set needs to match
949        // in order for it to be valid.  If negating, then just one
950        // match means that we have failed.
951        // Either way, return on the first hit.
952        const set = this.set;
953        this.debug(this.pattern, 'set', set);
954        // Find the basename of the path by looking for the last non-empty segment
955        let filename = ff[ff.length - 1];
956        if (!filename) {
957            for (let i = ff.length - 2; !filename && i >= 0; i--) {
958                filename = ff[i];
959            }
960        }
961        for (let i = 0; i < set.length; i++) {
962            const pattern = set[i];
963            let file = ff;
964            if (options.matchBase && pattern.length === 1) {
965                file = [filename];
966            }
967            const hit = this.matchOne(file, pattern, partial);
968            if (hit) {
969                if (options.flipNegate) {
970                    return true;
971                }
972                return !this.negate;
973            }
974        }
975        // didn't get any hits.  this is success if it's a negative
976        // pattern, failure otherwise.
977        if (options.flipNegate) {
978            return false;
979        }
980        return this.negate;
981    }
982    static defaults(def) {
983        return minimatch.defaults(def).Minimatch;
984    }
985}
986/* c8 ignore start */
987export { AST } from './ast.js';
988export { escape } from './escape.js';
989export { unescape } from './unescape.js';
990/* c8 ignore stop */
991minimatch.AST = AST;
992minimatch.Minimatch = Minimatch;
993minimatch.escape = escape;
994minimatch.unescape = unescape;
995//# sourceMappingURL=index.js.map