Changeset 33517cc for node_modules/minimatch/dist/esm/index.js
- Timestamp:
- 09/19/26 10:30:30 (10 days ago)
- Branches:
- finki-main, main
- Children:
- 06ebe74
- Parents:
- 62b2964
- File:
-
- 1 edited
-
node_modules/minimatch/dist/esm/index.js (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
-
node_modules/minimatch/dist/esm/index.js
r62b2964 r33517cc 13 13 }; 14 14 // Optimized checking for the most common glob patterns. 15 const starDotExtRE = /^\*+([^+@!? \*\[\(]*)$/;15 const starDotExtRE = /^\*+([^+@!?*[(]*)$/; 16 16 const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext); 17 17 const starDotExtTestDot = (ext) => (f) => f.endsWith(ext); … … 32 32 const starTest = (f) => f.length !== 0 && !f.startsWith('.'); 33 33 const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..'; 34 const qmarksRE = /^\?+([^+@!? \*\[\(]*)?$/;34 const qmarksRE = /^\?+([^+@!?*[(]*)?$/; 35 35 const qmarksTestNocase = ([$0, ext = '']) => { 36 36 const noext = qmarksTestNoExt([$0]); … … 194 194 platform; 195 195 windowsNoMagicRoot; 196 maxGlobstarRecursion; 196 197 regexp; 197 198 constructor(pattern, options = {}) { … … 199 200 options = options || {}; 200 201 this.options = options; 202 this.maxGlobstarRecursion = options.maxGlobstarRecursion ?? 200; 201 203 this.pattern = pattern; 202 204 this.platform = options.platform || defaultPlatform; … … 257 259 this.globSet = [...new Set(this.braceExpand())]; 258 260 if (options.debug) { 261 //oxlint-disable-next-line no-console 259 262 this.debug = (...args) => console.error(...args); 260 263 } … … 319 322 // if we're not in globstar mode, then turn ** into * 320 323 if (this.options.noglobstar) { 321 for ( let i = 0; i < globParts.length; i++) {322 for (let j = 0; j < globParts[i].length; j++) {323 if ( globParts[i][j] === '**') {324 globParts[i][j] = '*';324 for (const partset of globParts) { 325 for (let j = 0; j < partset.length; j++) { 326 if (partset[j] === '**') { 327 partset[j] = '*'; 325 328 } 326 329 } … … 410 413 while (-1 !== (dd = parts.indexOf('..', dd + 1))) { 411 414 const p = parts[dd - 1]; 412 if (p && p !== '.' && p !== '..' && p !== '**') { 415 if (p && 416 p !== '.' && 417 p !== '..' && 418 p !== '**' && 419 !(this.isWindows && /^[a-z]:$/i.test(p))) { 413 420 didSomething = true; 414 421 parts.splice(dd - 1, 2); … … 603 610 // the parts match. 604 611 matchOne(file, pattern, partial = false) { 605 const options = this.options; 612 let fileStartIndex = 0; 613 let patternStartIndex = 0; 606 614 // UNC paths like //?/X:/... can match X:/... and vice versa 607 615 // Drive letters in absolute drive or unc paths are always compared … … 632 640 pattern[pdi], 633 641 ]; 642 // start matching at the drive letter index of each 634 643 if (fd.toLowerCase() === pd.toLowerCase()) { 635 644 pattern[pdi] = fd; 636 if (pdi > fdi) { 637 pattern = pattern.slice(pdi); 638 } 639 else if (fdi > pdi) { 640 file = file.slice(fdi); 641 } 645 patternStartIndex = pdi; 646 fileStartIndex = fdi; 642 647 } 643 648 } … … 649 654 file = this.levelTwoFileOptimize(file); 650 655 } 651 this.debug('matchOne', this, { file, pattern }); 652 this.debug('matchOne', file.length, pattern.length); 653 for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) { 656 if (pattern.includes(GLOBSTAR)) { 657 return this.#matchGlobstar(file, pattern, partial, fileStartIndex, patternStartIndex); 658 } 659 return this.#matchOne(file, pattern, partial, fileStartIndex, patternStartIndex); 660 } 661 #matchGlobstar(file, pattern, partial, fileIndex, patternIndex) { 662 // split the pattern into head, tail, and middle of ** delimited parts 663 const firstgs = pattern.indexOf(GLOBSTAR, patternIndex); 664 const lastgs = pattern.lastIndexOf(GLOBSTAR); 665 // split the pattern up into globstar-delimited sections 666 // the tail has to be at the end, and the others just have 667 // to be found in order from the head. 668 const [head, body, tail] = partial ? 669 [ 670 pattern.slice(patternIndex, firstgs), 671 pattern.slice(firstgs + 1), 672 [], 673 ] 674 : [ 675 pattern.slice(patternIndex, firstgs), 676 pattern.slice(firstgs + 1, lastgs), 677 pattern.slice(lastgs + 1), 678 ]; 679 // check the head, from the current file/pattern index. 680 if (head.length) { 681 const fileHead = file.slice(fileIndex, fileIndex + head.length); 682 if (!this.#matchOne(fileHead, head, partial, 0, 0)) { 683 return false; 684 } 685 fileIndex += head.length; 686 patternIndex += head.length; 687 } 688 // now we know the head matches! 689 // if the last portion is not empty, it MUST match the end 690 // check the tail 691 let fileTailMatch = 0; 692 if (tail.length) { 693 // if head + tail > file, then we cannot possibly match 694 if (tail.length + fileIndex > file.length) 695 return false; 696 // try to match the tail 697 let tailStart = file.length - tail.length; 698 if (this.#matchOne(file, tail, partial, tailStart, 0)) { 699 fileTailMatch = tail.length; 700 } 701 else { 702 // affordance for stuff like a/**/* matching a/b/ 703 // if the last file portion is '', and there's more to the pattern 704 // then try without the '' bit. 705 if (file[file.length - 1] !== '' || 706 fileIndex + tail.length === file.length) { 707 return false; 708 } 709 tailStart--; 710 if (!this.#matchOne(file, tail, partial, tailStart, 0)) { 711 return false; 712 } 713 fileTailMatch = tail.length + 1; 714 } 715 } 716 // now we know the tail matches! 717 // the middle is zero or more portions wrapped in **, possibly 718 // containing more ** sections. 719 // so a/**/b/**/c/**/d has become **/b/**/c/** 720 // if it's empty, it means a/**/b, just verify we have no bad dots 721 // if there's no tail, so it ends on /**, then we must have *something* 722 // after the head, or it's not a matc 723 if (!body.length) { 724 let sawSome = !!fileTailMatch; 725 for (let i = fileIndex; i < file.length - fileTailMatch; i++) { 726 const f = String(file[i]); 727 sawSome = true; 728 if (f === '.' || 729 f === '..' || 730 (!this.options.dot && f.startsWith('.'))) { 731 return false; 732 } 733 } 734 // in partial mode, we just need to get past all file parts 735 return partial || sawSome; 736 } 737 // now we know that there's one or more body sections, which can 738 // be matched anywhere from the 0 index (because the head was pruned) 739 // through to the length-fileTailMatch index. 740 // split the body up into sections, and note the minimum index it can 741 // be found at (start with the length of all previous segments) 742 // [section, before, after] 743 const bodySegments = [[[], 0]]; 744 let currentBody = bodySegments[0]; 745 let nonGsParts = 0; 746 const nonGsPartsSums = [0]; 747 for (const b of body) { 748 if (b === GLOBSTAR) { 749 nonGsPartsSums.push(nonGsParts); 750 currentBody = [[], 0]; 751 bodySegments.push(currentBody); 752 } 753 else { 754 currentBody[0].push(b); 755 nonGsParts++; 756 } 757 } 758 let i = bodySegments.length - 1; 759 const fileLength = file.length - fileTailMatch; 760 for (const b of bodySegments) { 761 b[1] = fileLength - (nonGsPartsSums[i--] + b[0].length); 762 } 763 return !!this.#matchGlobStarBodySections(file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch); 764 } 765 // return false for "nope, not matching" 766 // return null for "not matching, cannot keep trying" 767 #matchGlobStarBodySections(file, 768 // pattern section, last possible position for it 769 bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail) { 770 // take the first body segment, and walk from fileIndex to its "after" 771 // value at the end 772 // If it doesn't match at that position, we increment, until we hit 773 // that final possible position, and give up. 774 // If it does match, then advance and try to rest. 775 // If any of them fail we keep walking forward. 776 // this is still a bit recursively painful, but it's more constrained 777 // than previous implementations, because we never test something that 778 // can't possibly be a valid matching condition. 779 const bs = bodySegments[bodyIndex]; 780 if (!bs) { 781 // just make sure that there's no bad dots 782 for (let i = fileIndex; i < file.length; i++) { 783 sawTail = true; 784 const f = file[i]; 785 if (f === '.' || 786 f === '..' || 787 (!this.options.dot && f.startsWith('.'))) { 788 return false; 789 } 790 } 791 return sawTail; 792 } 793 // have a non-globstar body section to test 794 const [body, after] = bs; 795 while (fileIndex <= after) { 796 const m = this.#matchOne(file.slice(0, fileIndex + body.length), body, partial, fileIndex, 0); 797 // if limit exceeded, no match. intentional false negative, 798 // acceptable break in correctness for security. 799 if (m && globStarDepth < this.maxGlobstarRecursion) { 800 // match! see if the rest match. if so, we're done! 801 const sub = this.#matchGlobStarBodySections(file, bodySegments, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail); 802 if (sub !== false) { 803 return sub; 804 } 805 } 806 const f = file[fileIndex]; 807 if (f === '.' || 808 f === '..' || 809 (!this.options.dot && f.startsWith('.'))) { 810 return false; 811 } 812 fileIndex++; 813 } 814 // walked off. no point continuing 815 return partial || null; 816 } 817 #matchOne(file, pattern, partial, fileIndex, patternIndex) { 818 let fi; 819 let pi; 820 let pl; 821 let fl; 822 for (fi = fileIndex, 823 pi = patternIndex, 824 fl = file.length, 825 pl = pattern.length; fi < fl && pi < pl; fi++, pi++) { 654 826 this.debug('matchOne loop'); 655 varp = pattern[pi];656 varf = file[fi];827 let p = pattern[pi]; 828 let f = file[fi]; 657 829 this.debug(pattern, p, f); 658 830 // should be impossible. 659 831 // some invalid regexp stuff in the set. 660 832 /* c8 ignore start */ 661 if (p === false ) {833 if (p === false || p === GLOBSTAR) { 662 834 return false; 663 835 } 664 836 /* c8 ignore stop */ 665 if (p === GLOBSTAR) {666 this.debug('GLOBSTAR', [pattern, p, f]);667 // "**"668 // a/**/b/**/c would match the following:669 // a/b/x/y/z/c670 // a/x/y/z/b/c671 // a/b/x/b/x/c672 // a/b/c673 // To do this, take the rest of the pattern after674 // the **, and see if it would match the file remainder.675 // If so, return success.676 // If not, the ** "swallows" a segment, and try again.677 // This is recursively awful.678 //679 // a/**/b/**/c matching a/b/x/y/z/c680 // - a matches a681 // - doublestar682 // - matchOne(b/x/y/z/c, b/**/c)683 // - b matches b684 // - doublestar685 // - matchOne(x/y/z/c, c) -> no686 // - matchOne(y/z/c, c) -> no687 // - matchOne(z/c, c) -> no688 // - matchOne(c, c) yes, hit689 var fr = fi;690 var pr = pi + 1;691 if (pr === pl) {692 this.debug('** at the end');693 // a ** at the end will just swallow the rest.694 // We have found a match.695 // however, it will not swallow /.x, unless696 // options.dot is set.697 // . and .. are *never* matched by **, for explosively698 // exponential reasons.699 for (; fi < fl; fi++) {700 if (file[fi] === '.' ||701 file[fi] === '..' ||702 (!options.dot && file[fi].charAt(0) === '.'))703 return false;704 }705 return true;706 }707 // ok, let's see if we can swallow whatever we can.708 while (fr < fl) {709 var swallowee = file[fr];710 this.debug('\nglobstar while', file, fr, pattern, pr, swallowee);711 // XXX remove this slice. Just pass the start index.712 if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {713 this.debug('globstar found match!', fr, fl, swallowee);714 // found a match.715 return true;716 }717 else {718 // can't swallow "." or ".." ever.719 // can only swallow ".foo" when explicitly asked.720 if (swallowee === '.' ||721 swallowee === '..' ||722 (!options.dot && swallowee.charAt(0) === '.')) {723 this.debug('dot detected!', file, fr, pattern, pr);724 break;725 }726 // ** swallows a segment, and continue.727 this.debug('globstar swallow a segment, and continue');728 fr++;729 }730 }731 // no match was found.732 // However, in partial mode, we can't say this is necessarily over.733 /* c8 ignore start */734 if (partial) {735 // ran out of file736 this.debug('\n>>> no match, partial?', file, fr, pattern, pr);737 if (fr === fl) {738 return true;739 }740 }741 /* c8 ignore stop */742 return false;743 }744 837 // something other than ** 745 838 // non-magic patterns just have to match exactly … … 929 1022 /* c8 ignore start */ 930 1023 } 931 catch (ex){1024 catch { 932 1025 // should be impossible 933 1026 this.regexp = false; … … 944 1037 return p.split('/'); 945 1038 } 946 else if (this.isWindows && /^\/\/[^ \/]+/.test(p)) {1039 else if (this.isWindows && /^\/\/[^/]+/.test(p)) { 947 1040 // add an extra '' for the one we lose 948 1041 return ['', ...p.split(/\/+/)]; … … 986 1079 } 987 1080 } 988 for (let i = 0; i < set.length; i++) { 989 const pattern = set[i]; 1081 for (const pattern of set) { 990 1082 let file = ff; 991 1083 if (options.matchBase && pattern.length === 1) {
Note:
See TracChangeset
for help on using the changeset viewer.
