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