"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.unescape = exports.escape = exports.AST = exports.Minimatch = exports.match = exports.makeRe = exports.braceExpand = exports.defaults = exports.filter = exports.GLOBSTAR = exports.sep = exports.minimatch = void 0; const brace_expansion_1 = __importDefault(require("brace-expansion")); const assert_valid_pattern_js_1 = require("./assert-valid-pattern.js"); const ast_js_1 = require("./ast.js"); const escape_js_1 = require("./escape.js"); const unescape_js_1 = require("./unescape.js"); const minimatch = (p, pattern, options = {}) => { (0, assert_valid_pattern_js_1.assertValidPattern)(pattern); // shortcut: comments match nothing. if (!options.nocomment && pattern.charAt(0) === '#') { return false; } return new Minimatch(pattern, options).match(p); }; exports.minimatch = minimatch; // Optimized checking for the most common glob patterns. const starDotExtRE = /^\*+([^+@!?\*\[\(]*)$/; const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext); const starDotExtTestDot = (ext) => (f) => f.endsWith(ext); const starDotExtTestNocase = (ext) => { ext = ext.toLowerCase(); return (f) => !f.startsWith('.') && f.toLowerCase().endsWith(ext); }; const starDotExtTestNocaseDot = (ext) => { ext = ext.toLowerCase(); return (f) => f.toLowerCase().endsWith(ext); }; const starDotStarRE = /^\*+\.\*+$/; const starDotStarTest = (f) => !f.startsWith('.') && f.includes('.'); const starDotStarTestDot = (f) => f !== '.' && f !== '..' && f.includes('.'); const dotStarRE = /^\.\*+$/; const dotStarTest = (f) => f !== '.' && f !== '..' && f.startsWith('.'); const starRE = /^\*+$/; const starTest = (f) => f.length !== 0 && !f.startsWith('.'); const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..'; const qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/; const qmarksTestNocase = ([$0, ext = '']) => { const noext = qmarksTestNoExt([$0]); if (!ext) return noext; ext = ext.toLowerCase(); return (f) => noext(f) && f.toLowerCase().endsWith(ext); }; const qmarksTestNocaseDot = ([$0, ext = '']) => { const noext = qmarksTestNoExtDot([$0]); if (!ext) return noext; ext = ext.toLowerCase(); return (f) => noext(f) && f.toLowerCase().endsWith(ext); }; const qmarksTestDot = ([$0, ext = '']) => { const noext = qmarksTestNoExtDot([$0]); return !ext ? noext : (f) => noext(f) && f.endsWith(ext); }; const qmarksTest = ([$0, ext = '']) => { const noext = qmarksTestNoExt([$0]); return !ext ? noext : (f) => noext(f) && f.endsWith(ext); }; const qmarksTestNoExt = ([$0]) => { const len = $0.length; return (f) => f.length === len && !f.startsWith('.'); }; const qmarksTestNoExtDot = ([$0]) => { const len = $0.length; return (f) => f.length === len && f !== '.' && f !== '..'; }; /* c8 ignore start */ const defaultPlatform = (typeof process === 'object' && process ? (typeof process.env === 'object' && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__) || process.platform : 'posix'); const path = { win32: { sep: '\\' }, posix: { sep: '/' }, }; /* c8 ignore stop */ exports.sep = defaultPlatform === 'win32' ? path.win32.sep : path.posix.sep; exports.minimatch.sep = exports.sep; exports.GLOBSTAR = Symbol('globstar **'); exports.minimatch.GLOBSTAR = exports.GLOBSTAR; // any single thing other than / // don't need to escape / when using new RegExp() const qmark = '[^/]'; // * => any number of characters const star = qmark + '*?'; // ** when dots are allowed. Anything goes, except .. and . // not (^ or / followed by one or two dots followed by $ or /), // followed by anything, any number of times. const twoStarDot = '(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?'; // not a ^ or / followed by a dot, // followed by anything, any number of times. const twoStarNoDot = '(?:(?!(?:\\/|^)\\.).)*?'; const filter = (pattern, options = {}) => (p) => (0, exports.minimatch)(p, pattern, options); exports.filter = filter; exports.minimatch.filter = exports.filter; const ext = (a, b = {}) => Object.assign({}, a, b); const defaults = (def) => { if (!def || typeof def !== 'object' || !Object.keys(def).length) { return exports.minimatch; } const orig = exports.minimatch; const m = (p, pattern, options = {}) => orig(p, pattern, ext(def, options)); return Object.assign(m, { Minimatch: class Minimatch extends orig.Minimatch { constructor(pattern, options = {}) { super(pattern, ext(def, options)); } static defaults(options) { return orig.defaults(ext(def, options)).Minimatch; } }, AST: class AST extends orig.AST { /* c8 ignore start */ constructor(type, parent, options = {}) { super(type, parent, ext(def, options)); } /* c8 ignore stop */ static fromGlob(pattern, options = {}) { return orig.AST.fromGlob(pattern, ext(def, options)); } }, unescape: (s, options = {}) => orig.unescape(s, ext(def, options)), escape: (s, options = {}) => orig.escape(s, ext(def, options)), filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)), defaults: (options) => orig.defaults(ext(def, options)), makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)), braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)), match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)), sep: orig.sep, GLOBSTAR: exports.GLOBSTAR, }); }; exports.defaults = defaults; exports.minimatch.defaults = exports.defaults; // Brace expansion: // a{b,c}d -> abd acd // a{b,}c -> abc ac // a{0..3}d -> a0d a1d a2d a3d // a{b,c{d,e}f}g -> abg acdfg acefg // a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg // // Invalid sets are not expanded. // a{2..}b -> a{2..}b // a{b}c -> a{b}c const braceExpand = (pattern, options = {}) => { (0, assert_valid_pattern_js_1.assertValidPattern)(pattern); // Thanks to Yeting Li for // improving this regexp to avoid a ReDOS vulnerability. if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) { // shortcut. no need to expand. return [pattern]; } return (0, brace_expansion_1.default)(pattern); }; exports.braceExpand = braceExpand; exports.minimatch.braceExpand = exports.braceExpand; // parse a component of the expanded set. // At this point, no pattern may contain "/" in it // so we're going to return a 2d array, where each entry is the full // pattern, split on '/', and then turned into a regular expression. // A regexp is made at the end which joins each array with an // escaped /, and another full one which joins each regexp with |. // // Following the lead of Bash 4.1, note that "**" only has special meaning // when it is the *only* thing in a path portion. Otherwise, any series // of * is equivalent to a single *. Globstar behavior is enabled by // default, and can be disabled by setting options.noglobstar. const makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe(); exports.makeRe = makeRe; exports.minimatch.makeRe = exports.makeRe; const match = (list, pattern, options = {}) => { const mm = new Minimatch(pattern, options); list = list.filter(f => mm.match(f)); if (mm.options.nonull && !list.length) { list.push(pattern); } return list; }; exports.match = match; exports.minimatch.match = exports.match; // replace stuff like \* with * const globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/; const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); class Minimatch { options; set; pattern; windowsPathsNoEscape; nonegate; negate; comment; empty; preserveMultipleSlashes; partial; globSet; globParts; nocase; isWindows; platform; windowsNoMagicRoot; regexp; constructor(pattern, options = {}) { (0, assert_valid_pattern_js_1.assertValidPattern)(pattern); options = options || {}; this.options = options; this.pattern = pattern; this.platform = options.platform || defaultPlatform; this.isWindows = this.platform === 'win32'; this.windowsPathsNoEscape = !!options.windowsPathsNoEscape || options.allowWindowsEscape === false; if (this.windowsPathsNoEscape) { this.pattern = this.pattern.replace(/\\/g, '/'); } this.preserveMultipleSlashes = !!options.preserveMultipleSlashes; this.regexp = null; this.negate = false; this.nonegate = !!options.nonegate; this.comment = false; this.empty = false; this.partial = !!options.partial; this.nocase = !!this.options.nocase; this.windowsNoMagicRoot = options.windowsNoMagicRoot !== undefined ? options.windowsNoMagicRoot : !!(this.isWindows && this.nocase); this.globSet = []; this.globParts = []; this.set = []; // make the set of regexps etc. this.make(); } hasMagic() { if (this.options.magicalBraces && this.set.length > 1) { return true; } for (const pattern of this.set) { for (const part of pattern) { if (typeof part !== 'string') return true; } } return false; } debug(..._) { } make() { const pattern = this.pattern; const options = this.options; // empty patterns and comments match nothing. if (!options.nocomment && pattern.charAt(0) === '#') { this.comment = true; return; } if (!pattern) { this.empty = true; return; } // step 1: figure out negation, etc. this.parseNegate(); // step 2: expand braces this.globSet = [...new Set(this.braceExpand())]; if (options.debug) { this.debug = (...args) => console.error(...args); } this.debug(this.pattern, this.globSet); // step 3: now we have a set, so turn each one into a series of // path-portion matching patterns. // These will be regexps, except in the case of "**", which is // set to the GLOBSTAR object for globstar behavior, // and will not contain any / characters // // First, we preprocess to make the glob pattern sets a bit simpler // and deduped. There are some perf-killing patterns that can cause // problems with a glob walk, but we can simplify them down a bit. const rawGlobParts = this.globSet.map(s => this.slashSplit(s)); this.globParts = this.preprocess(rawGlobParts); this.debug(this.pattern, this.globParts); // glob --> regexps let set = this.globParts.map((s, _, __) => { if (this.isWindows && this.windowsNoMagicRoot) { // check if it's a drive or unc path. const isUNC = s[0] === '' && s[1] === '' && (s[2] === '?' || !globMagic.test(s[2])) && !globMagic.test(s[3]); const isDrive = /^[a-z]:/i.test(s[0]); if (isUNC) { return [...s.slice(0, 4), ...s.slice(4).map(ss => this.parse(ss))]; } else if (isDrive) { return [s[0], ...s.slice(1).map(ss => this.parse(ss))]; } } return s.map(ss => this.parse(ss)); }); this.debug(this.pattern, set); // filter out everything that didn't compile properly. this.set = set.filter(s => s.indexOf(false) === -1); // do not treat the ? in UNC paths as magic if (this.isWindows) { for (let i = 0; i < this.set.length; i++) { const p = this.set[i]; if (p[0] === '' && p[1] === '' && this.globParts[i][2] === '?' && typeof p[3] === 'string' && /^[a-z]:$/i.test(p[3])) { p[2] = '?'; } } } this.debug(this.pattern, this.set); } // various transforms to equivalent pattern sets that are // faster to process in a filesystem walk. The goal is to // eliminate what we can, and push all ** patterns as far // to the right as possible, even if it increases the number // of patterns that we have to process. preprocess(globParts) { // if we're not in globstar mode, then turn all ** into * if (this.options.noglobstar) { for (let i = 0; i < globParts.length; i++) { for (let j = 0; j < globParts[i].length; j++) { if (globParts[i][j] === '**') { globParts[i][j] = '*'; } } } } const { optimizationLevel = 1 } = this.options; if (optimizationLevel >= 2) { // aggressive optimization for the purpose of fs walking globParts = this.firstPhasePreProcess(globParts); globParts = this.secondPhasePreProcess(globParts); } else if (optimizationLevel >= 1) { // just basic optimizations to remove some .. parts globParts = this.levelOneOptimize(globParts); } else { // just collapse multiple ** portions into one globParts = this.adjascentGlobstarOptimize(globParts); } return globParts; } // just get rid of adjascent ** portions adjascentGlobstarOptimize(globParts) { return globParts.map(parts => { let gs = -1; while (-1 !== (gs = parts.indexOf('**', gs + 1))) { let i = gs; while (parts[i + 1] === '**') { i++; } if (i !== gs) { parts.splice(gs, i - gs); } } return parts; }); } // get rid of adjascent ** and resolve .. portions levelOneOptimize(globParts) { return globParts.map(parts => { parts = parts.reduce((set, part) => { const prev = set[set.length - 1]; if (part === '**' && prev === '**') { return set; } if (part === '..') { if (prev && prev !== '..' && prev !== '.' && prev !== '**') { set.pop(); return set; } } set.push(part); return set; }, []); return parts.length === 0 ? [''] : parts; }); } levelTwoFileOptimize(parts) { if (!Array.isArray(parts)) { parts = this.slashSplit(parts); } let didSomething = false; do { didSomething = false; //
// -> 
/
            if (!this.preserveMultipleSlashes) {
                for (let i = 1; i < parts.length - 1; i++) {
                    const p = parts[i];
                    // don't squeeze out UNC patterns
                    if (i === 1 && p === '' && parts[0] === '')
                        continue;
                    if (p === '.' || p === '') {
                        didSomething = true;
                        parts.splice(i, 1);
                        i--;
                    }
                }
                if (parts[0] === '.' &&
                    parts.length === 2 &&
                    (parts[1] === '.' || parts[1] === '')) {
                    didSomething = true;
                    parts.pop();
                }
            }
            // 
/

/../ ->

/
            let dd = 0;
            while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
                const p = parts[dd - 1];
                if (p && p !== '.' && p !== '..' && p !== '**') {
                    didSomething = true;
                    parts.splice(dd - 1, 2);
                    dd -= 2;
                }
            }
        } while (didSomething);
        return parts.length === 0 ? [''] : parts;
    }
    // First phase: single-pattern processing
    // 
 is 1 or more portions
    //  is 1 or more portions
    // 

is any portion other than ., .., '', or ** // is . or '' // // **/.. is *brutal* for filesystem walking performance, because // it effectively resets the recursive walk each time it occurs, // and ** cannot be reduced out by a .. pattern part like a regexp // or most strings (other than .., ., and '') can be. // //

/**/../

/

/ -> {

/../

/

/,

/**/

/

/} //

// -> 
/
    // 
/

/../ ->

/
    // **/**/ -> **/
    //
    // **/*/ -> */**/ <== not valid because ** doesn't follow
    // this WOULD be allowed if ** did follow symlinks, or * didn't
    firstPhasePreProcess(globParts) {
        let didSomething = false;
        do {
            didSomething = false;
            // 
/**/../

/

/ -> {

/../

/

/,

/**/

/

/} for (let parts of globParts) { let gs = -1; while (-1 !== (gs = parts.indexOf('**', gs + 1))) { let gss = gs; while (parts[gss + 1] === '**') { //

/**/**/ -> 
/**/
                        gss++;
                    }
                    // eg, if gs is 2 and gss is 4, that means we have 3 **
                    // parts, and can remove 2 of them.
                    if (gss > gs) {
                        parts.splice(gs + 1, gss - gs);
                    }
                    let next = parts[gs + 1];
                    const p = parts[gs + 2];
                    const p2 = parts[gs + 3];
                    if (next !== '..')
                        continue;
                    if (!p ||
                        p === '.' ||
                        p === '..' ||
                        !p2 ||
                        p2 === '.' ||
                        p2 === '..') {
                        continue;
                    }
                    didSomething = true;
                    // edit parts in place, and push the new one
                    parts.splice(gs, 1);
                    const other = parts.slice(0);
                    other[gs] = '**';
                    globParts.push(other);
                    gs--;
                }
                // 
// -> 
/
                if (!this.preserveMultipleSlashes) {
                    for (let i = 1; i < parts.length - 1; i++) {
                        const p = parts[i];
                        // don't squeeze out UNC patterns
                        if (i === 1 && p === '' && parts[0] === '')
                            continue;
                        if (p === '.' || p === '') {
                            didSomething = true;
                            parts.splice(i, 1);
                            i--;
                        }
                    }
                    if (parts[0] === '.' &&
                        parts.length === 2 &&
                        (parts[1] === '.' || parts[1] === '')) {
                        didSomething = true;
                        parts.pop();
                    }
                }
                // 
/

/../ ->

/
                let dd = 0;
                while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
                    const p = parts[dd - 1];
                    if (p && p !== '.' && p !== '..' && p !== '**') {
                        didSomething = true;
                        const needDot = dd === 1 && parts[dd + 1] === '**';
                        const splin = needDot ? ['.'] : [];
                        parts.splice(dd - 1, 2, ...splin);
                        if (parts.length === 0)
                            parts.push('');
                        dd -= 2;
                    }
                }
            }
        } while (didSomething);
        return globParts;
    }
    // second phase: multi-pattern dedupes
    // {
/*/,
/

/} ->

/*/
    // {
/,
/} -> 
/
    // {
/**/,
/} -> 
/**/
    //
    // {
/**/,
/**/

/} ->

/**/
    // ^-- not valid because ** doens't follow symlinks
    secondPhasePreProcess(globParts) {
        for (let i = 0; i < globParts.length - 1; i++) {
            for (let j = i + 1; j < globParts.length; j++) {
                const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
                if (!matched)
                    continue;
                globParts[i] = matched;
                globParts[j] = [];
            }
        }
        return globParts.filter(gs => gs.length);
    }
    partsMatch(a, b, emptyGSMatch = false) {
        let ai = 0;
        let bi = 0;
        let result = [];
        let which = '';
        while (ai < a.length && bi < b.length) {
            if (a[ai] === b[bi]) {
                result.push(which === 'b' ? b[bi] : a[ai]);
                ai++;
                bi++;
            }
            else if (emptyGSMatch && a[ai] === '**' && b[bi] === a[ai + 1]) {
                result.push(a[ai]);
                ai++;
            }
            else if (emptyGSMatch && b[bi] === '**' && a[ai] === b[bi + 1]) {
                result.push(b[bi]);
                bi++;
            }
            else if (a[ai] === '*' &&
                b[bi] &&
                (this.options.dot || !b[bi].startsWith('.')) &&
                b[bi] !== '**') {
                if (which === 'b')
                    return false;
                which = 'a';
                result.push(a[ai]);
                ai++;
                bi++;
            }
            else if (b[bi] === '*' &&
                a[ai] &&
                (this.options.dot || !a[ai].startsWith('.')) &&
                a[ai] !== '**') {
                if (which === 'a')
                    return false;
                which = 'b';
                result.push(b[bi]);
                ai++;
                bi++;
            }
            else {
                return false;
            }
        }
        // if we fall out of the loop, it means they two are identical
        // as long as their lengths match
        return a.length === b.length && result;
    }
    parseNegate() {
        if (this.nonegate)
            return;
        const pattern = this.pattern;
        let negate = false;
        let negateOffset = 0;
        for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
            negate = !negate;
            negateOffset++;
        }
        if (negateOffset)
            this.pattern = pattern.slice(negateOffset);
        this.negate = negate;
    }
    // set partial to true to test if, for example,
    // "/a/b" matches the start of "/*/b/*/d"
    // Partial means, if you run out of file before you run
    // out of pattern, then that's fine, as long as all
    // the parts match.
    matchOne(file, pattern, partial = false) {
        const options = this.options;
        // UNC paths like //?/X:/... can match X:/... and vice versa
        // Drive letters in absolute drive or unc paths are always compared
        // case-insensitively.
        if (this.isWindows) {
            const fileDrive = typeof file[0] === 'string' && /^[a-z]:$/i.test(file[0]);
            const fileUNC = !fileDrive &&
                file[0] === '' &&
                file[1] === '' &&
                file[2] === '?' &&
                /^[a-z]:$/i.test(file[3]);
            const patternDrive = typeof pattern[0] === 'string' && /^[a-z]:$/i.test(pattern[0]);
            const patternUNC = !patternDrive &&
                pattern[0] === '' &&
                pattern[1] === '' &&
                pattern[2] === '?' &&
                typeof pattern[3] === 'string' &&
                /^[a-z]:$/i.test(pattern[3]);
            const fdi = fileUNC ? 3 : fileDrive ? 0 : undefined;
            const pdi = patternUNC ? 3 : patternDrive ? 0 : undefined;
            if (typeof fdi === 'number' && typeof pdi === 'number') {
                const [fd, pd] = [file[fdi], pattern[pdi]];
                if (fd.toLowerCase() === pd.toLowerCase()) {
                    pattern[pdi] = fd;
                    if (pdi > fdi) {
                        pattern = pattern.slice(pdi);
                    }
                    else if (fdi > pdi) {
                        file = file.slice(fdi);
                    }
                }
            }
        }
        // resolve and reduce . and .. portions in the file as well.
        // dont' need to do the second phase, because it's only one string[]
        const { optimizationLevel = 1 } = this.options;
        if (optimizationLevel >= 2) {
            file = this.levelTwoFileOptimize(file);
        }
        this.debug('matchOne', this, { file, pattern });
        this.debug('matchOne', file.length, pattern.length);
        for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
            this.debug('matchOne loop');
            var p = pattern[pi];
            var f = file[fi];
            this.debug(pattern, p, f);
            // should be impossible.
            // some invalid regexp stuff in the set.
            /* c8 ignore start */
            if (p === false) {
                return false;
            }
            /* c8 ignore stop */
            if (p === exports.GLOBSTAR) {
                this.debug('GLOBSTAR', [pattern, p, f]);
                // "**"
                // a/**/b/**/c would match the following:
                // a/b/x/y/z/c
                // a/x/y/z/b/c
                // a/b/x/b/x/c
                // a/b/c
                // To do this, take the rest of the pattern after
                // the **, and see if it would match the file remainder.
                // If so, return success.
                // If not, the ** "swallows" a segment, and try again.
                // This is recursively awful.
                //
                // a/**/b/**/c matching a/b/x/y/z/c
                // - a matches a
                // - doublestar
                //   - matchOne(b/x/y/z/c, b/**/c)
                //     - b matches b
                //     - doublestar
                //       - matchOne(x/y/z/c, c) -> no
                //       - matchOne(y/z/c, c) -> no
                //       - matchOne(z/c, c) -> no
                //       - matchOne(c, c) yes, hit
                var fr = fi;
                var pr = pi + 1;
                if (pr === pl) {
                    this.debug('** at the end');
                    // a ** at the end will just swallow the rest.
                    // We have found a match.
                    // however, it will not swallow /.x, unless
                    // options.dot is set.
                    // . and .. are *never* matched by **, for explosively
                    // exponential reasons.
                    for (; fi < fl; fi++) {
                        if (file[fi] === '.' ||
                            file[fi] === '..' ||
                            (!options.dot && file[fi].charAt(0) === '.'))
                            return false;
                    }
                    return true;
                }
                // ok, let's see if we can swallow whatever we can.
                while (fr < fl) {
                    var swallowee = file[fr];
                    this.debug('\nglobstar while', file, fr, pattern, pr, swallowee);
                    // XXX remove this slice.  Just pass the start index.
                    if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
                        this.debug('globstar found match!', fr, fl, swallowee);
                        // found a match.
                        return true;
                    }
                    else {
                        // can't swallow "." or ".." ever.
                        // can only swallow ".foo" when explicitly asked.
                        if (swallowee === '.' ||
                            swallowee === '..' ||
                            (!options.dot && swallowee.charAt(0) === '.')) {
                            this.debug('dot detected!', file, fr, pattern, pr);
                            break;
                        }
                        // ** swallows a segment, and continue.
                        this.debug('globstar swallow a segment, and continue');
                        fr++;
                    }
                }
                // no match was found.
                // However, in partial mode, we can't say this is necessarily over.
                /* c8 ignore start */
                if (partial) {
                    // ran out of file
                    this.debug('\n>>> no match, partial?', file, fr, pattern, pr);
                    if (fr === fl) {
                        return true;
                    }
                }
                /* c8 ignore stop */
                return false;
            }
            // something other than **
            // non-magic patterns just have to match exactly
            // patterns with magic have been turned into regexps.
            let hit;
            if (typeof p === 'string') {
                hit = f === p;
                this.debug('string match', p, f, hit);
            }
            else {
                hit = p.test(f);
                this.debug('pattern match', p, f, hit);
            }
            if (!hit)
                return false;
        }
        // Note: ending in / means that we'll get a final ""
        // at the end of the pattern.  This can only match a
        // corresponding "" at the end of the file.
        // If the file ends in /, then it can only match a
        // a pattern that ends in /, unless the pattern just
        // doesn't have any more for it. But, a/b/ should *not*
        // match "a/b/*", even though "" matches against the
        // [^/]*? pattern, except in partial mode, where it might
        // simply not be reached yet.
        // However, a/b/ should still satisfy a/*
        // now either we fell off the end of the pattern, or we're done.
        if (fi === fl && pi === pl) {
            // ran out of pattern and filename at the same time.
            // an exact hit!
            return true;
        }
        else if (fi === fl) {
            // ran out of file, but still had pattern left.
            // this is ok if we're doing the match as part of
            // a glob fs traversal.
            return partial;
        }
        else if (pi === pl) {
            // ran out of pattern, still have file left.
            // this is only acceptable if we're on the very last
            // empty segment of a file with a trailing slash.
            // a/* should match a/b/
            return fi === fl - 1 && file[fi] === '';
            /* c8 ignore start */
        }
        else {
            // should be unreachable.
            throw new Error('wtf?');
        }
        /* c8 ignore stop */
    }
    braceExpand() {
        return (0, exports.braceExpand)(this.pattern, this.options);
    }
    parse(pattern) {
        (0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
        const options = this.options;
        // shortcuts
        if (pattern === '**')
            return exports.GLOBSTAR;
        if (pattern === '')
            return '';
        // far and away, the most common glob pattern parts are
        // *, *.*, and *.  Add a fast check method for those.
        let m;
        let fastTest = null;
        if ((m = pattern.match(starRE))) {
            fastTest = options.dot ? starTestDot : starTest;
        }
        else if ((m = pattern.match(starDotExtRE))) {
            fastTest = (options.nocase
                ? options.dot
                    ? starDotExtTestNocaseDot
                    : starDotExtTestNocase
                : options.dot
                    ? starDotExtTestDot
                    : starDotExtTest)(m[1]);
        }
        else if ((m = pattern.match(qmarksRE))) {
            fastTest = (options.nocase
                ? options.dot
                    ? qmarksTestNocaseDot
                    : qmarksTestNocase
                : options.dot
                    ? qmarksTestDot
                    : qmarksTest)(m);
        }
        else if ((m = pattern.match(starDotStarRE))) {
            fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
        }
        else if ((m = pattern.match(dotStarRE))) {
            fastTest = dotStarTest;
        }
        const re = ast_js_1.AST.fromGlob(pattern, this.options).toMMPattern();
        if (fastTest && typeof re === 'object') {
            // Avoids overriding in frozen environments
            Reflect.defineProperty(re, 'test', { value: fastTest });
        }
        return re;
    }
    makeRe() {
        if (this.regexp || this.regexp === false)
            return this.regexp;
        // at this point, this.set is a 2d array of partial
        // pattern strings, or "**".
        //
        // It's better to use .match().  This function shouldn't
        // be used, really, but it's pretty convenient sometimes,
        // when you just want to work with a regex.
        const set = this.set;
        if (!set.length) {
            this.regexp = false;
            return this.regexp;
        }
        const options = this.options;
        const twoStar = options.noglobstar
            ? star
            : options.dot
                ? twoStarDot
                : twoStarNoDot;
        const flags = new Set(options.nocase ? ['i'] : []);
        // regexpify non-globstar patterns
        // if ** is only item, then we just do one twoStar
        // if ** is first, and there are more, prepend (\/|twoStar\/)? to next
        // if ** is last, append (\/twoStar|) to previous
        // if ** is in the middle, append (\/|\/twoStar\/) to previous
        // then filter out GLOBSTAR symbols
        let re = set
            .map(pattern => {
            const pp = pattern.map(p => {
                if (p instanceof RegExp) {
                    for (const f of p.flags.split(''))
                        flags.add(f);
                }
                return typeof p === 'string'
                    ? regExpEscape(p)
                    : p === exports.GLOBSTAR
                        ? exports.GLOBSTAR
                        : p._src;
            });
            pp.forEach((p, i) => {
                const next = pp[i + 1];
                const prev = pp[i - 1];
                if (p !== exports.GLOBSTAR || prev === exports.GLOBSTAR) {
                    return;
                }
                if (prev === undefined) {
                    if (next !== undefined && next !== exports.GLOBSTAR) {
                        pp[i + 1] = '(?:\\/|' + twoStar + '\\/)?' + next;
                    }
                    else {
                        pp[i] = twoStar;
                    }
                }
                else if (next === undefined) {
                    pp[i - 1] = prev + '(?:\\/|' + twoStar + ')?';
                }
                else if (next !== exports.GLOBSTAR) {
                    pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + '\\/)' + next;
                    pp[i + 1] = exports.GLOBSTAR;
                }
            });
            return pp.filter(p => p !== exports.GLOBSTAR).join('/');
        })
            .join('|');
        // need to wrap in parens if we had more than one thing with |,
        // otherwise only the first will be anchored to ^ and the last to $
        const [open, close] = set.length > 1 ? ['(?:', ')'] : ['', ''];
        // must match entire pattern
        // ending in a * or ** will make it less strict.
        re = '^' + open + re + close + '$';
        // can match anything, as long as it's not this.
        if (this.negate)
            re = '^(?!' + re + ').+$';
        try {
            this.regexp = new RegExp(re, [...flags].join(''));
            /* c8 ignore start */
        }
        catch (ex) {
            // should be impossible
            this.regexp = false;
        }
        /* c8 ignore stop */
        return this.regexp;
    }
    slashSplit(p) {
        // if p starts with // on windows, we preserve that
        // so that UNC paths aren't broken.  Otherwise, any number of
        // / characters are coalesced into one, unless
        // preserveMultipleSlashes is set to true.
        if (this.preserveMultipleSlashes) {
            return p.split('/');
        }
        else if (this.isWindows && /^\/\/[^\/]+/.test(p)) {
            // add an extra '' for the one we lose
            return ['', ...p.split(/\/+/)];
        }
        else {
            return p.split(/\/+/);
        }
    }
    match(f, partial = this.partial) {
        this.debug('match', f, this.pattern);
        // short-circuit in the case of busted things.
        // comments, etc.
        if (this.comment) {
            return false;
        }
        if (this.empty) {
            return f === '';
        }
        if (f === '/' && partial) {
            return true;
        }
        const options = this.options;
        // windows: need to use /, not \
        if (this.isWindows) {
            f = f.split('\\').join('/');
        }
        // treat the test path as a set of pathparts.
        const ff = this.slashSplit(f);
        this.debug(this.pattern, 'split', ff);
        // just ONE of the pattern sets in this.set needs to match
        // in order for it to be valid.  If negating, then just one
        // match means that we have failed.
        // Either way, return on the first hit.
        const set = this.set;
        this.debug(this.pattern, 'set', set);
        // Find the basename of the path by looking for the last non-empty segment
        let filename = ff[ff.length - 1];
        if (!filename) {
            for (let i = ff.length - 2; !filename && i >= 0; i--) {
                filename = ff[i];
            }
        }
        for (let i = 0; i < set.length; i++) {
            const pattern = set[i];
            let file = ff;
            if (options.matchBase && pattern.length === 1) {
                file = [filename];
            }
            const hit = this.matchOne(file, pattern, partial);
            if (hit) {
                if (options.flipNegate) {
                    return true;
                }
                return !this.negate;
            }
        }
        // didn't get any hits.  this is success if it's a negative
        // pattern, failure otherwise.
        if (options.flipNegate) {
            return false;
        }
        return this.negate;
    }
    static defaults(def) {
        return exports.minimatch.defaults(def).Minimatch;
    }
}
exports.Minimatch = Minimatch;
/* c8 ignore start */
var ast_js_2 = require("./ast.js");
Object.defineProperty(exports, "AST", { enumerable: true, get: function () { return ast_js_2.AST; } });
var escape_js_2 = require("./escape.js");
Object.defineProperty(exports, "escape", { enumerable: true, get: function () { return escape_js_2.escape; } });
var unescape_js_2 = require("./unescape.js");
Object.defineProperty(exports, "unescape", { enumerable: true, get: function () { return unescape_js_2.unescape; } });
/* c8 ignore stop */
exports.minimatch.AST = ast_js_1.AST;
exports.minimatch.Minimatch = Minimatch;
exports.minimatch.escape = escape_js_1.escape;
exports.minimatch.unescape = unescape_js_1.unescape;
//# sourceMappingURL=index.js.map