Changeset 33517cc for node_modules/minimatch/dist/commonjs/index.js
- Timestamp:
- 09/19/26 10:30:30 (11 days ago)
- Branches:
- finki-main, main
- Children:
- 06ebe74
- Parents:
- 62b2964
- File:
-
- 1 edited
-
node_modules/minimatch/dist/commonjs/index.js (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
-
node_modules/minimatch/dist/commonjs/index.js
r62b2964 r33517cc 17 17 exports.minimatch = minimatch; 18 18 // Optimized checking for the most common glob patterns. 19 const starDotExtRE = /^\*+([^+@!? \*\[\(]*)$/;19 const starDotExtRE = /^\*+([^+@!?*[(]*)$/; 20 20 const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext); 21 21 const starDotExtTestDot = (ext) => (f) => f.endsWith(ext); … … 36 36 const starTest = (f) => f.length !== 0 && !f.startsWith('.'); 37 37 const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..'; 38 const qmarksRE = /^\?+([^+@!? \*\[\(]*)?$/;38 const qmarksRE = /^\?+([^+@!?*[(]*)?$/; 39 39 const qmarksTestNocase = ([$0, ext = '']) => { 40 40 const noext = qmarksTestNoExt([$0]); … … 203 203 platform; 204 204 windowsNoMagicRoot; 205 maxGlobstarRecursion; 205 206 regexp; 206 207 constructor(pattern, options = {}) { … … 208 209 options = options || {}; 209 210 this.options = options; 211 this.maxGlobstarRecursion = options.maxGlobstarRecursion ?? 200; 210 212 this.pattern = pattern; 211 213 this.platform = options.platform || defaultPlatform; … … 266 268 this.globSet = [...new Set(this.braceExpand())]; 267 269 if (options.debug) { 270 //oxlint-disable-next-line no-console 268 271 this.debug = (...args) => console.error(...args); 269 272 } … … 328 331 // if we're not in globstar mode, then turn ** into * 329 332 if (this.options.noglobstar) { 330 for ( let i = 0; i < globParts.length; i++) {331 for (let j = 0; j < globParts[i].length; j++) {332 if ( globParts[i][j] === '**') {333 globParts[i][j] = '*';333 for (const partset of globParts) { 334 for (let j = 0; j < partset.length; j++) { 335 if (partset[j] === '**') { 336 partset[j] = '*'; 334 337 } 335 338 } … … 419 422 while (-1 !== (dd = parts.indexOf('..', dd + 1))) { 420 423 const p = parts[dd - 1]; 421 if (p && p !== '.' && p !== '..' && p !== '**') { 424 if (p && 425 p !== '.' && 426 p !== '..' && 427 p !== '**' && 428 !(this.isWindows && /^[a-z]:$/i.test(p))) { 422 429 didSomething = true; 423 430 parts.splice(dd - 1, 2); … … 612 619 // the parts match. 613 620 matchOne(file, pattern, partial = false) { 614 const options = this.options; 621 let fileStartIndex = 0; 622 let patternStartIndex = 0; 615 623 // UNC paths like //?/X:/... can match X:/... and vice versa 616 624 // Drive letters in absolute drive or unc paths are always compared … … 641 649 pattern[pdi], 642 650 ]; 651 // start matching at the drive letter index of each 643 652 if (fd.toLowerCase() === pd.toLowerCase()) { 644 653 pattern[pdi] = fd; 645 if (pdi > fdi) { 646 pattern = pattern.slice(pdi); 647 } 648 else if (fdi > pdi) { 649 file = file.slice(fdi); 650 } 654 patternStartIndex = pdi; 655 fileStartIndex = fdi; 651 656 } 652 657 } … … 658 663 file = this.levelTwoFileOptimize(file); 659 664 } 660 this.debug('matchOne', this, { file, pattern }); 661 this.debug('matchOne', file.length, pattern.length); 662 for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) { 665 if (pattern.includes(exports.GLOBSTAR)) { 666 return this.#matchGlobstar(file, pattern, partial, fileStartIndex, patternStartIndex); 667 } 668 return this.#matchOne(file, pattern, partial, fileStartIndex, patternStartIndex); 669 } 670 #matchGlobstar(file, pattern, partial, fileIndex, patternIndex) { 671 // split the pattern into head, tail, and middle of ** delimited parts 672 const firstgs = pattern.indexOf(exports.GLOBSTAR, patternIndex); 673 const lastgs = pattern.lastIndexOf(exports.GLOBSTAR); 674 // split the pattern up into globstar-delimited sections 675 // the tail has to be at the end, and the others just have 676 // to be found in order from the head. 677 const [head, body, tail] = partial ? 678 [ 679 pattern.slice(patternIndex, firstgs), 680 pattern.slice(firstgs + 1), 681 [], 682 ] 683 : [ 684 pattern.slice(patternIndex, firstgs), 685 pattern.slice(firstgs + 1, lastgs), 686 pattern.slice(lastgs + 1), 687 ]; 688 // check the head, from the current file/pattern index. 689 if (head.length) { 690 const fileHead = file.slice(fileIndex, fileIndex + head.length); 691 if (!this.#matchOne(fileHead, head, partial, 0, 0)) { 692 return false; 693 } 694 fileIndex += head.length; 695 patternIndex += head.length; 696 } 697 // now we know the head matches! 698 // if the last portion is not empty, it MUST match the end 699 // check the tail 700 let fileTailMatch = 0; 701 if (tail.length) { 702 // if head + tail > file, then we cannot possibly match 703 if (tail.length + fileIndex > file.length) 704 return false; 705 // try to match the tail 706 let tailStart = file.length - tail.length; 707 if (this.#matchOne(file, tail, partial, tailStart, 0)) { 708 fileTailMatch = tail.length; 709 } 710 else { 711 // affordance for stuff like a/**/* matching a/b/ 712 // if the last file portion is '', and there's more to the pattern 713 // then try without the '' bit. 714 if (file[file.length - 1] !== '' || 715 fileIndex + tail.length === file.length) { 716 return false; 717 } 718 tailStart--; 719 if (!this.#matchOne(file, tail, partial, tailStart, 0)) { 720 return false; 721 } 722 fileTailMatch = tail.length + 1; 723 } 724 } 725 // now we know the tail matches! 726 // the middle is zero or more portions wrapped in **, possibly 727 // containing more ** sections. 728 // so a/**/b/**/c/**/d has become **/b/**/c/** 729 // if it's empty, it means a/**/b, just verify we have no bad dots 730 // if there's no tail, so it ends on /**, then we must have *something* 731 // after the head, or it's not a matc 732 if (!body.length) { 733 let sawSome = !!fileTailMatch; 734 for (let i = fileIndex; i < file.length - fileTailMatch; i++) { 735 const f = String(file[i]); 736 sawSome = true; 737 if (f === '.' || 738 f === '..' || 739 (!this.options.dot && f.startsWith('.'))) { 740 return false; 741 } 742 } 743 // in partial mode, we just need to get past all file parts 744 return partial || sawSome; 745 } 746 // now we know that there's one or more body sections, which can 747 // be matched anywhere from the 0 index (because the head was pruned) 748 // through to the length-fileTailMatch index. 749 // split the body up into sections, and note the minimum index it can 750 // be found at (start with the length of all previous segments) 751 // [section, before, after] 752 const bodySegments = [[[], 0]]; 753 let currentBody = bodySegments[0]; 754 let nonGsParts = 0; 755 const nonGsPartsSums = [0]; 756 for (const b of body) { 757 if (b === exports.GLOBSTAR) { 758 nonGsPartsSums.push(nonGsParts); 759 currentBody = [[], 0]; 760 bodySegments.push(currentBody); 761 } 762 else { 763 currentBody[0].push(b); 764 nonGsParts++; 765 } 766 } 767 let i = bodySegments.length - 1; 768 const fileLength = file.length - fileTailMatch; 769 for (const b of bodySegments) { 770 b[1] = fileLength - (nonGsPartsSums[i--] + b[0].length); 771 } 772 return !!this.#matchGlobStarBodySections(file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch); 773 } 774 // return false for "nope, not matching" 775 // return null for "not matching, cannot keep trying" 776 #matchGlobStarBodySections(file, 777 // pattern section, last possible position for it 778 bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail) { 779 // take the first body segment, and walk from fileIndex to its "after" 780 // value at the end 781 // If it doesn't match at that position, we increment, until we hit 782 // that final possible position, and give up. 783 // If it does match, then advance and try to rest. 784 // If any of them fail we keep walking forward. 785 // this is still a bit recursively painful, but it's more constrained 786 // than previous implementations, because we never test something that 787 // can't possibly be a valid matching condition. 788 const bs = bodySegments[bodyIndex]; 789 if (!bs) { 790 // just make sure that there's no bad dots 791 for (let i = fileIndex; i < file.length; i++) { 792 sawTail = true; 793 const f = file[i]; 794 if (f === '.' || 795 f === '..' || 796 (!this.options.dot && f.startsWith('.'))) { 797 return false; 798 } 799 } 800 return sawTail; 801 } 802 // have a non-globstar body section to test 803 const [body, after] = bs; 804 while (fileIndex <= after) { 805 const m = this.#matchOne(file.slice(0, fileIndex + body.length), body, partial, fileIndex, 0); 806 // if limit exceeded, no match. intentional false negative, 807 // acceptable break in correctness for security. 808 if (m && globStarDepth < this.maxGlobstarRecursion) { 809 // match! see if the rest match. if so, we're done! 810 const sub = this.#matchGlobStarBodySections(file, bodySegments, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail); 811 if (sub !== false) { 812 return sub; 813 } 814 } 815 const f = file[fileIndex]; 816 if (f === '.' || 817 f === '..' || 818 (!this.options.dot && f.startsWith('.'))) { 819 return false; 820 } 821 fileIndex++; 822 } 823 // walked off. no point continuing 824 return partial || null; 825 } 826 #matchOne(file, pattern, partial, fileIndex, patternIndex) { 827 let fi; 828 let pi; 829 let pl; 830 let fl; 831 for (fi = fileIndex, 832 pi = patternIndex, 833 fl = file.length, 834 pl = pattern.length; fi < fl && pi < pl; fi++, pi++) { 663 835 this.debug('matchOne loop'); 664 varp = pattern[pi];665 varf = file[fi];836 let p = pattern[pi]; 837 let f = file[fi]; 666 838 this.debug(pattern, p, f); 667 839 // should be impossible. 668 840 // some invalid regexp stuff in the set. 669 841 /* c8 ignore start */ 670 if (p === false ) {842 if (p === false || p === exports.GLOBSTAR) { 671 843 return false; 672 844 } 673 845 /* c8 ignore stop */ 674 if (p === exports.GLOBSTAR) {675 this.debug('GLOBSTAR', [pattern, p, f]);676 // "**"677 // a/**/b/**/c would match the following:678 // a/b/x/y/z/c679 // a/x/y/z/b/c680 // a/b/x/b/x/c681 // a/b/c682 // To do this, take the rest of the pattern after683 // the **, and see if it would match the file remainder.684 // If so, return success.685 // If not, the ** "swallows" a segment, and try again.686 // This is recursively awful.687 //688 // a/**/b/**/c matching a/b/x/y/z/c689 // - a matches a690 // - doublestar691 // - matchOne(b/x/y/z/c, b/**/c)692 // - b matches b693 // - doublestar694 // - matchOne(x/y/z/c, c) -> no695 // - matchOne(y/z/c, c) -> no696 // - matchOne(z/c, c) -> no697 // - matchOne(c, c) yes, hit698 var fr = fi;699 var pr = pi + 1;700 if (pr === pl) {701 this.debug('** at the end');702 // a ** at the end will just swallow the rest.703 // We have found a match.704 // however, it will not swallow /.x, unless705 // options.dot is set.706 // . and .. are *never* matched by **, for explosively707 // exponential reasons.708 for (; fi < fl; fi++) {709 if (file[fi] === '.' ||710 file[fi] === '..' ||711 (!options.dot && file[fi].charAt(0) === '.'))712 return false;713 }714 return true;715 }716 // ok, let's see if we can swallow whatever we can.717 while (fr < fl) {718 var swallowee = file[fr];719 this.debug('\nglobstar while', file, fr, pattern, pr, swallowee);720 // XXX remove this slice. Just pass the start index.721 if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {722 this.debug('globstar found match!', fr, fl, swallowee);723 // found a match.724 return true;725 }726 else {727 // can't swallow "." or ".." ever.728 // can only swallow ".foo" when explicitly asked.729 if (swallowee === '.' ||730 swallowee === '..' ||731 (!options.dot && swallowee.charAt(0) === '.')) {732 this.debug('dot detected!', file, fr, pattern, pr);733 break;734 }735 // ** swallows a segment, and continue.736 this.debug('globstar swallow a segment, and continue');737 fr++;738 }739 }740 // no match was found.741 // However, in partial mode, we can't say this is necessarily over.742 /* c8 ignore start */743 if (partial) {744 // ran out of file745 this.debug('\n>>> no match, partial?', file, fr, pattern, pr);746 if (fr === fl) {747 return true;748 }749 }750 /* c8 ignore stop */751 return false;752 }753 846 // something other than ** 754 847 // non-magic patterns just have to match exactly … … 938 1031 /* c8 ignore start */ 939 1032 } 940 catch (ex){1033 catch { 941 1034 // should be impossible 942 1035 this.regexp = false; … … 953 1046 return p.split('/'); 954 1047 } 955 else if (this.isWindows && /^\/\/[^ \/]+/.test(p)) {1048 else if (this.isWindows && /^\/\/[^/]+/.test(p)) { 956 1049 // add an extra '' for the one we lose 957 1050 return ['', ...p.split(/\/+/)]; … … 995 1088 } 996 1089 } 997 for (let i = 0; i < set.length; i++) { 998 const pattern = set[i]; 1090 for (const pattern of set) { 999 1091 let file = ff; 1000 1092 if (options.matchBase && pattern.length === 1) {
Note:
See TracChangeset
for help on using the changeset viewer.
