@teammy/server 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +2 -2
  2. package/dist/main.js +10936 -6840
  3. package/dist/native-pi-entry.js +14 -1
  4. package/dist/project-pi-entry.js +51 -11
  5. package/dist/runtime/workflows/task-bootstrap/prompt.md +2 -0
  6. package/dist/web/assets/Assistant-BeYamS0w.js +1 -0
  7. package/dist/web/assets/Assistant-C7QfFYLo.css +1 -0
  8. package/dist/web/assets/Dashboard-BzmrE4Xv.js +1 -0
  9. package/dist/web/assets/Files-BvCYgjVV.js +1 -0
  10. package/dist/web/assets/{Markdown-oZagG-wy.js → Markdown-BRPMsc7D.js} +4 -4
  11. package/dist/web/assets/Materials-CK-mbNmo.css +1 -0
  12. package/dist/web/assets/Materials-DK3CkLr0.js +6 -0
  13. package/dist/web/assets/Sessions-D_579m-e.js +1 -0
  14. package/dist/web/assets/WorkspaceTree-fMDtGIFa.js +1 -0
  15. package/dist/web/assets/{file-links-CD346_jf.js → file-links-I1K8CwVK.js} +1 -1
  16. package/dist/web/assets/{index-Be5hGscJ.css → index-CTIAGUGG.css} +1 -1
  17. package/dist/web/assets/index-DQsx-e5d.js +66 -0
  18. package/dist/web/downloads/teammy-skill.zip +0 -0
  19. package/dist/web/index.html +2 -2
  20. package/node_modules/@isaacs/nonrecursive-glob-match/LICENSE.md +55 -0
  21. package/node_modules/@isaacs/nonrecursive-glob-match/README.md +333 -0
  22. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/index.d.ts +114 -0
  23. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/index.d.ts.map +1 -0
  24. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/index.js +762 -0
  25. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/index.js.map +1 -0
  26. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/index.min.js +3 -0
  27. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/index.min.js.map +7 -0
  28. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/package.json +3 -0
  29. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/parse-class.d.ts +4 -0
  30. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/parse-class.d.ts.map +1 -0
  31. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/parse-class.js +142 -0
  32. package/node_modules/@isaacs/nonrecursive-glob-match/dist/commonjs/parse-class.js.map +1 -0
  33. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/index.d.ts +114 -0
  34. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/index.d.ts.map +1 -0
  35. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/index.js +758 -0
  36. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/index.js.map +1 -0
  37. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/index.min.js +3 -0
  38. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/index.min.js.map +7 -0
  39. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/package.json +3 -0
  40. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/parse-class.d.ts +4 -0
  41. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/parse-class.d.ts.map +1 -0
  42. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/parse-class.js +138 -0
  43. package/node_modules/@isaacs/nonrecursive-glob-match/dist/esm/parse-class.js.map +1 -0
  44. package/node_modules/@isaacs/nonrecursive-glob-match/package.json +56 -0
  45. package/node_modules/@isaacs/nonrecursive-glob-match/src/index.ts +900 -0
  46. package/node_modules/@isaacs/nonrecursive-glob-match/src/parse-class.ts +158 -0
  47. package/node_modules/glob/README.md +388 -214
  48. package/node_modules/glob/dist/commonjs/glob.d.ts +20 -11
  49. package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -1
  50. package/node_modules/glob/dist/commonjs/glob.js +22 -29
  51. package/node_modules/glob/dist/commonjs/glob.js.map +1 -1
  52. package/node_modules/glob/dist/commonjs/has-magic.d.ts +1 -1
  53. package/node_modules/glob/dist/commonjs/has-magic.d.ts.map +1 -1
  54. package/node_modules/glob/dist/commonjs/has-magic.js +1 -4
  55. package/node_modules/glob/dist/commonjs/has-magic.js.map +1 -1
  56. package/node_modules/glob/dist/commonjs/ignore.d.ts +16 -4
  57. package/node_modules/glob/dist/commonjs/ignore.d.ts.map +1 -1
  58. package/node_modules/glob/dist/commonjs/ignore.js +24 -4
  59. package/node_modules/glob/dist/commonjs/ignore.js.map +1 -1
  60. package/node_modules/glob/dist/commonjs/index.d.ts +3 -2
  61. package/node_modules/glob/dist/commonjs/index.d.ts.map +1 -1
  62. package/node_modules/glob/dist/commonjs/index.js.map +1 -1
  63. package/node_modules/glob/dist/commonjs/index.min.js +2 -3
  64. package/node_modules/glob/dist/commonjs/index.min.js.map +4 -4
  65. package/node_modules/glob/dist/commonjs/pattern.d.ts +10 -3
  66. package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -1
  67. package/node_modules/glob/dist/commonjs/pattern.js +27 -15
  68. package/node_modules/glob/dist/commonjs/pattern.js.map +1 -1
  69. package/node_modules/glob/dist/commonjs/processor.d.ts +23 -10
  70. package/node_modules/glob/dist/commonjs/processor.d.ts.map +1 -1
  71. package/node_modules/glob/dist/commonjs/processor.js +36 -23
  72. package/node_modules/glob/dist/commonjs/processor.js.map +1 -1
  73. package/node_modules/glob/dist/commonjs/walker.d.ts +19 -17
  74. package/node_modules/glob/dist/commonjs/walker.d.ts.map +1 -1
  75. package/node_modules/glob/dist/commonjs/walker.js +50 -35
  76. package/node_modules/glob/dist/commonjs/walker.js.map +1 -1
  77. package/node_modules/glob/dist/esm/glob.d.ts +20 -11
  78. package/node_modules/glob/dist/esm/glob.d.ts.map +1 -1
  79. package/node_modules/glob/dist/esm/glob.js +22 -29
  80. package/node_modules/glob/dist/esm/glob.js.map +1 -1
  81. package/node_modules/glob/dist/esm/has-magic.d.ts +1 -1
  82. package/node_modules/glob/dist/esm/has-magic.d.ts.map +1 -1
  83. package/node_modules/glob/dist/esm/has-magic.js +1 -4
  84. package/node_modules/glob/dist/esm/has-magic.js.map +1 -1
  85. package/node_modules/glob/dist/esm/ignore.d.ts +16 -4
  86. package/node_modules/glob/dist/esm/ignore.d.ts.map +1 -1
  87. package/node_modules/glob/dist/esm/ignore.js +25 -5
  88. package/node_modules/glob/dist/esm/ignore.js.map +1 -1
  89. package/node_modules/glob/dist/esm/index.d.ts +3 -2
  90. package/node_modules/glob/dist/esm/index.d.ts.map +1 -1
  91. package/node_modules/glob/dist/esm/index.js.map +1 -1
  92. package/node_modules/glob/dist/esm/index.min.js +2 -3
  93. package/node_modules/glob/dist/esm/index.min.js.map +4 -4
  94. package/node_modules/glob/dist/esm/pattern.d.ts +10 -3
  95. package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -1
  96. package/node_modules/glob/dist/esm/pattern.js +27 -15
  97. package/node_modules/glob/dist/esm/pattern.js.map +1 -1
  98. package/node_modules/glob/dist/esm/processor.d.ts +23 -10
  99. package/node_modules/glob/dist/esm/processor.d.ts.map +1 -1
  100. package/node_modules/glob/dist/esm/processor.js +36 -23
  101. package/node_modules/glob/dist/esm/processor.js.map +1 -1
  102. package/node_modules/glob/dist/esm/walker.d.ts +19 -17
  103. package/node_modules/glob/dist/esm/walker.d.ts.map +1 -1
  104. package/node_modules/glob/dist/esm/walker.js +51 -36
  105. package/node_modules/glob/dist/esm/walker.js.map +1 -1
  106. package/node_modules/glob/package.json +28 -12
  107. package/node_modules/glob/src/glob.ts +655 -0
  108. package/node_modules/glob/src/has-magic.ts +23 -0
  109. package/node_modules/glob/src/ignore.ts +162 -0
  110. package/node_modules/glob/src/index.ts +225 -0
  111. package/node_modules/glob/src/pattern.ts +286 -0
  112. package/node_modules/glob/src/processor.ts +333 -0
  113. package/node_modules/glob/src/walker.ts +523 -0
  114. package/node_modules/minimatch/README.md +125 -107
  115. package/node_modules/minimatch/dist/commonjs/index.d.ts +49 -38
  116. package/node_modules/minimatch/dist/commonjs/index.d.ts.map +1 -1
  117. package/node_modules/minimatch/dist/commonjs/index.js +782 -359
  118. package/node_modules/minimatch/dist/commonjs/index.js.map +1 -1
  119. package/node_modules/minimatch/dist/esm/index.d.ts +49 -38
  120. package/node_modules/minimatch/dist/esm/index.d.ts.map +1 -1
  121. package/node_modules/minimatch/dist/esm/index.js +781 -356
  122. package/node_modules/minimatch/dist/esm/index.js.map +1 -1
  123. package/node_modules/minimatch/package.json +5 -4
  124. package/node_modules/path-scurry/README.md +0 -1
  125. package/node_modules/path-scurry/dist/commonjs/index.d.ts +7 -0
  126. package/node_modules/path-scurry/dist/commonjs/index.d.ts.map +1 -1
  127. package/node_modules/path-scurry/dist/commonjs/index.js +59 -21
  128. package/node_modules/path-scurry/dist/commonjs/index.js.map +1 -1
  129. package/node_modules/path-scurry/dist/esm/index.d.ts +7 -0
  130. package/node_modules/path-scurry/dist/esm/index.d.ts.map +1 -1
  131. package/node_modules/path-scurry/dist/esm/index.js +42 -14
  132. package/node_modules/path-scurry/dist/esm/index.js.map +1 -1
  133. package/node_modules/path-scurry/package.json +4 -4
  134. package/package.json +2 -1
  135. package/dist/web/assets/Assistant-B3h2yQF3.css +0 -1
  136. package/dist/web/assets/Assistant-Dm_p8EZl.js +0 -1
  137. package/dist/web/assets/Dashboard-fwW9NxcC.js +0 -1
  138. package/dist/web/assets/Files-D-KCDWmO.js +0 -1
  139. package/dist/web/assets/Sessions-BQhGiLvz.js +0 -1
  140. package/dist/web/assets/WorkspaceTree-B9733pV3.js +0 -1
  141. package/dist/web/assets/index-BiiPuwDi.js +0 -66
  142. package/node_modules/minimatch/dist/commonjs/ast.d.ts +0 -22
  143. package/node_modules/minimatch/dist/commonjs/ast.d.ts.map +0 -1
  144. package/node_modules/minimatch/dist/commonjs/ast.js +0 -845
  145. package/node_modules/minimatch/dist/commonjs/ast.js.map +0 -1
  146. package/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts +0 -8
  147. package/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts.map +0 -1
  148. package/node_modules/minimatch/dist/commonjs/brace-expressions.js +0 -150
  149. package/node_modules/minimatch/dist/commonjs/brace-expressions.js.map +0 -1
  150. package/node_modules/minimatch/dist/esm/ast.d.ts +0 -22
  151. package/node_modules/minimatch/dist/esm/ast.d.ts.map +0 -1
  152. package/node_modules/minimatch/dist/esm/ast.js +0 -841
  153. package/node_modules/minimatch/dist/esm/ast.js.map +0 -1
  154. package/node_modules/minimatch/dist/esm/brace-expressions.d.ts +0 -8
  155. package/node_modules/minimatch/dist/esm/brace-expressions.d.ts.map +0 -1
  156. package/node_modules/minimatch/dist/esm/brace-expressions.js +0 -146
  157. package/node_modules/minimatch/dist/esm/brace-expressions.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { expand } from 'brace-expansion';
2
+ import { Matcher } from '@isaacs/nonrecursive-glob-match';
2
3
  import { assertValidPattern } from './assert-valid-pattern.js';
3
- import { AST } from './ast.js';
4
4
  import { escape } from './escape.js';
5
5
  import { unescape } from './unescape.js';
6
6
  export const minimatch = (p, pattern, options = {}) => {
@@ -9,65 +9,32 @@ export const minimatch = (p, pattern, options = {}) => {
9
9
  if (!options.nocomment && pattern.charAt(0) === '#') {
10
10
  return false;
11
11
  }
12
- return new Minimatch(pattern, options).match(p);
12
+ return cachedMinimatch(pattern, options).match(p);
13
13
  };
14
- // Optimized checking for the most common glob patterns.
15
- const starDotExtRE = /^\*+([^+@!?*[(]*)$/;
16
- const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext);
17
- const starDotExtTestDot = (ext) => (f) => f.endsWith(ext);
18
- const starDotExtTestNocase = (ext) => {
19
- ext = ext.toLowerCase();
20
- return (f) => !f.startsWith('.') && f.toLowerCase().endsWith(ext);
21
- };
22
- const starDotExtTestNocaseDot = (ext) => {
23
- ext = ext.toLowerCase();
24
- return (f) => f.toLowerCase().endsWith(ext);
25
- };
26
- const starDotStarRE = /^\*+\.\*+$/;
27
- const starDotStarTest = (f) => !f.startsWith('.') && f.includes('.');
28
- const starDotStarTestDot = (f) => f !== '.' && f !== '..' && f.includes('.');
29
- const dotStarRE = /^\.\*+$/;
30
- const dotStarTest = (f) => f !== '.' && f !== '..' && f.startsWith('.');
31
- const starRE = /^\*+$/;
32
- const starTest = (f) => f.length !== 0 && !f.startsWith('.');
33
- const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..';
34
- const qmarksRE = /^\?+([^+@!?*[(]*)?$/;
35
- const qmarksTestNocase = ([$0, ext = '']) => {
36
- const noext = qmarksTestNoExt([$0]);
37
- if (!ext)
38
- return noext;
39
- ext = ext.toLowerCase();
40
- return (f) => noext(f) && f.toLowerCase().endsWith(ext);
41
- };
42
- const qmarksTestNocaseDot = ([$0, ext = '']) => {
43
- const noext = qmarksTestNoExtDot([$0]);
44
- if (!ext)
45
- return noext;
46
- ext = ext.toLowerCase();
47
- return (f) => noext(f) && f.toLowerCase().endsWith(ext);
48
- };
49
- const qmarksTestDot = ([$0, ext = '']) => {
50
- const noext = qmarksTestNoExtDot([$0]);
51
- return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
52
- };
53
- const qmarksTest = ([$0, ext = '']) => {
54
- const noext = qmarksTestNoExt([$0]);
55
- return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
56
- };
57
- const qmarksTestNoExt = ([$0]) => {
58
- const len = $0.length;
59
- return (f) => f.length === len && !f.startsWith('.');
60
- };
61
- const qmarksTestNoExtDot = ([$0]) => {
62
- const len = $0.length;
63
- return (f) => f.length === len && f !== '.' && f !== '..';
14
+ // The Minimatch objects that minimatch() used most recently. A Map
15
+ // keeps its keys in the order they were set, so the first key is the
16
+ // one used least recently.
17
+ const cache = new Map();
18
+ const cacheMax = 256;
19
+ const cachedMinimatch = (pattern, options) => {
20
+ const key = pattern + '\0' + JSON.stringify(options);
21
+ let mm = cache.get(key);
22
+ if (mm) {
23
+ cache.delete(key);
24
+ }
25
+ else {
26
+ // a copy, so a later change to the options can not change it
27
+ mm = new Minimatch(pattern, { ...options });
28
+ if (cache.size >= cacheMax) {
29
+ cache.delete(cache.keys().next().value);
30
+ }
31
+ }
32
+ cache.set(key, mm);
33
+ return mm;
64
34
  };
65
35
  /* c8 ignore start */
66
36
  const defaultPlatform = (typeof process === 'object' && process ?
67
- (typeof process.env === 'object' &&
68
- process.env &&
69
- process.env.__MINIMATCH_TESTING_PLATFORM__) ||
70
- process.platform
37
+ process.env?.__MINIMATCH_TESTING_PLATFORM__ || process.platform
71
38
  : 'posix');
72
39
  const path = {
73
40
  win32: { sep: '\\' },
@@ -78,18 +45,6 @@ export const sep = defaultPlatform === 'win32' ? path.win32.sep : path.posix.sep
78
45
  minimatch.sep = sep;
79
46
  export const GLOBSTAR = Symbol('globstar **');
80
47
  minimatch.GLOBSTAR = GLOBSTAR;
81
- // any single thing other than /
82
- // don't need to escape / when using new RegExp()
83
- const qmark = '[^/]';
84
- // * => any number of characters
85
- const star = qmark + '*?';
86
- // ** when dots are allowed. Anything goes, except .. and .
87
- // not (^ or / followed by one or two dots followed by $ or /),
88
- // followed by anything, any number of times.
89
- const twoStarDot = '(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?';
90
- // not a ^ or / followed by a dot,
91
- // followed by anything, any number of times.
92
- const twoStarNoDot = '(?:(?!(?:\\/|^)\\.).)*?';
93
48
  export const filter = (pattern, options = {}) => (p) => minimatch(p, pattern, options);
94
49
  minimatch.filter = filter;
95
50
  const ext = (a, b = {}) => Object.assign({}, a, b);
@@ -108,21 +63,10 @@ export const defaults = (def) => {
108
63
  return orig.defaults(ext(def, options)).Minimatch;
109
64
  }
110
65
  },
111
- AST: class AST extends orig.AST {
112
- /* c8 ignore start */
113
- constructor(type, parent, options = {}) {
114
- super(type, parent, ext(def, options));
115
- }
116
- /* c8 ignore stop */
117
- static fromGlob(pattern, options = {}) {
118
- return orig.AST.fromGlob(pattern, ext(def, options));
119
- }
120
- },
121
66
  unescape: (s, options = {}) => orig.unescape(s, ext(def, options)),
122
67
  escape: (s, options = {}) => orig.escape(s, ext(def, options)),
123
68
  filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)),
124
69
  defaults: (options) => orig.defaults(ext(def, options)),
125
- makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)),
126
70
  braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)),
127
71
  match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)),
128
72
  sep: orig.sep,
@@ -151,19 +95,6 @@ export const braceExpand = (pattern, options = {}) => {
151
95
  return expand(pattern, { max: options.braceExpandMax });
152
96
  };
153
97
  minimatch.braceExpand = braceExpand;
154
- // parse a component of the expanded set.
155
- // At this point, no pattern may contain "/" in it
156
- // so we're going to return a 2d array, where each entry is the full
157
- // pattern, split on '/', and then turned into a regular expression.
158
- // A regexp is made at the end which joins each array with an
159
- // escaped /, and another full one which joins each regexp with |.
160
- //
161
- // Following the lead of Bash 4.1, note that "**" only has special meaning
162
- // when it is the *only* thing in a path portion. Otherwise, any series
163
- // of * is equivalent to a single *. Globstar behavior is enabled by
164
- // default, and can be disabled by setting options.noglobstar.
165
- export const makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
166
- minimatch.makeRe = makeRe;
167
98
  export const match = (list, pattern, options = {}) => {
168
99
  const mm = new Minimatch(pattern, options);
169
100
  list = list.filter(f => mm.match(f));
@@ -173,9 +104,201 @@ export const match = (list, pattern, options = {}) => {
173
104
  return list;
174
105
  };
175
106
  minimatch.match = match;
176
- // replace stuff like \* with *
177
107
  const globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/;
178
- const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
108
+ // Index of the `]` that closes the class that starts at `start`,
109
+ // or -1 if it is not closed. Posix classes such as `[:alpha:]` are
110
+ // not skipped, so this can find a `]` before the real end. That
111
+ // only makes a class look less like a literal.
112
+ const classEnd = (pattern, start) => {
113
+ let i = start + 1;
114
+ if (pattern.charAt(i) === '!' || pattern.charAt(i) === '^')
115
+ i++;
116
+ let sawStart = false;
117
+ for (; i < pattern.length; i++) {
118
+ const c = pattern.charAt(i);
119
+ if (c === ']' && sawStart)
120
+ return i;
121
+ sawStart = true;
122
+ if (c === '\\')
123
+ i++;
124
+ }
125
+ return -1;
126
+ };
127
+ // If a path portion pattern has no magic, return the string it
128
+ // matches. Otherwise, return undefined. This can report magic for
129
+ // a pattern that is in fact literal (eg, `[]`), but never the
130
+ // reverse, so a string result is always safe to compare directly.
131
+ const literal = (pattern, noext) => {
132
+ if (!noext && (pattern === '+()' || pattern === '@()'))
133
+ return pattern;
134
+ let lit = '';
135
+ for (let i = 0; i < pattern.length; i++) {
136
+ const c = pattern.charAt(i);
137
+ if (c === '\\') {
138
+ // a trailing \ is a literal \
139
+ lit += pattern.charAt(++i) || c;
140
+ }
141
+ else if (c === '*' || c === '?') {
142
+ return undefined;
143
+ }
144
+ else if (c === '[') {
145
+ const close = classEnd(pattern, i);
146
+ if (close === -1) {
147
+ // not closed, so the [ is a literal
148
+ lit += c;
149
+ continue;
150
+ }
151
+ // a class of one char, such as `[*]` or `[\b]`, is a literal
152
+ let body = pattern.slice(i + 1, close);
153
+ if (body.startsWith('\\'))
154
+ body = body.slice(1);
155
+ if ([...body].length !== 1 || '!^'.includes(pattern.charAt(i + 1))) {
156
+ return undefined;
157
+ }
158
+ lit += body;
159
+ i = close;
160
+ }
161
+ else if (!noext &&
162
+ '+@!'.includes(c) &&
163
+ pattern.charAt(i + 1) === '(' &&
164
+ pattern.includes(')', i + 2)) {
165
+ return undefined;
166
+ }
167
+ else {
168
+ lit += c;
169
+ }
170
+ }
171
+ return lit;
172
+ };
173
+ // True if the portion pattern has the same meaning as an alternative
174
+ // inside `@(...)`. It must not have a `|` or `)` that is not in a
175
+ // closed extglob (those are literal at the top level), an extglob
176
+ // that is not closed (the `)` of the `@(...)` would close it), or a
177
+ // trailing `\` (it would escape the next `|`). A pattern that is
178
+ // only an empty extglob, such as `?()`, is literal on its own, but
179
+ // not in `@(...)`. Posix classes such as `[:alpha:]` can hide a `]`
180
+ // from classEnd, so patterns with them are not merged.
181
+ const extSafe = (pattern) => {
182
+ if (/^[?*+@]\(\)$/.test(pattern) || pattern.includes('[:'))
183
+ return false;
184
+ let depth = 0;
185
+ for (let i = 0; i < pattern.length; i++) {
186
+ const c = pattern.charAt(i);
187
+ if (c === '\\') {
188
+ if (++i === pattern.length)
189
+ return false;
190
+ }
191
+ else if (c === '[') {
192
+ const close = classEnd(pattern, i);
193
+ if (close !== -1)
194
+ i = close;
195
+ }
196
+ else if ('+@!?*'.includes(c) && pattern.charAt(i + 1) === '(') {
197
+ depth++;
198
+ i++;
199
+ }
200
+ else if (c === ')') {
201
+ if (!depth--)
202
+ return false;
203
+ }
204
+ else if (c === '|' && !depth) {
205
+ return false;
206
+ }
207
+ }
208
+ return !depth;
209
+ };
210
+ // The last path that Minimatch#match split, and its parts. A path is
211
+ // often tested against many patterns in a row (such as a list of
212
+ // ignore patterns), so this saves splitting it again. The parts are
213
+ // never changed, so they can be shared.
214
+ let lastSplit;
215
+ // The last path that Minimatch#match checked before splitting it. If
216
+ // the same path is checked again, it is being tested against many
217
+ // patterns, so it is split and the parts are kept for the others.
218
+ let lastChecked;
219
+ // true if a pattern portion that is not ** matches a path portion.
220
+ // An empty path portion only matches an empty pattern portion. A path
221
+ // portion never has a `/`, so the Matcher does not need to check it.
222
+ const portionMatch = (p, f) => typeof p === 'string' ? f === p : f !== '' && p.testUnchecked(f);
223
+ // Where the last portion of a row matches in a path: the start of the
224
+ // last portion of the path, or of the one before a trailing `/`. -1 if
225
+ // it matches neither.
226
+ const endIndex = (p, last, lastStart, prev, prevStart) => portionMatch(p, last) ? lastStart
227
+ : prev !== undefined && portionMatch(p, prev) ? prevStart
228
+ : -1;
229
+ const isDots = (p) => p === '.' || p === '..';
230
+ // a Windows drive letter portion, like `c:`
231
+ const isDrive = (p) => typeof p === 'string' && /^[a-z]:$/i.test(p);
232
+ // true for the `UNC` portion of a long UNC root, //?/UNC/host/share
233
+ const isLongUNC = (p) => typeof p === 'string' && /^unc$/i.test(p);
234
+ // The index of the host in a row or split path that starts with a
235
+ // Windows UNC root: 2 for `//host/share`, and 4 for
236
+ // `//?/UNC/host/share`. Otherwise -1. `//?/c:` is not one.
237
+ const uncHost = (p) => {
238
+ if (p[0] !== '' || p[1] !== '')
239
+ return -1;
240
+ const h = p[2] !== '?' ? 2
241
+ : isLongUNC(p[3]) ? 4
242
+ : -1;
243
+ const host = p[h];
244
+ const share = p[h + 1];
245
+ return (h !== -1 &&
246
+ host !== undefined &&
247
+ host !== '' &&
248
+ host !== GLOBSTAR &&
249
+ share !== undefined &&
250
+ share !== '' &&
251
+ share !== GLOBSTAR) ?
252
+ h
253
+ : -1;
254
+ };
255
+ // true if ** can walk the path portion: not `.` or `..`, and not a
256
+ // dotfile unless `dot` is set
257
+ const walkable = (p, dot) => !isDots(p) && (dot || !p.startsWith('.'));
258
+ // True if a portion of the path from `start` to `end` can not be
259
+ // walked by **: one that starts with `.`, or with `dot`, one that is
260
+ // `.` or `..`. `start` is the start of a portion, and `end` is the end
261
+ // of the path, or just after a separator.
262
+ const dotPortion = (f, start, end, dot, sep) => {
263
+ for (let k = start; k < end;) {
264
+ if (f.charCodeAt(k) === 46) {
265
+ if (!dot)
266
+ return true;
267
+ const n = f.charCodeAt(k + 1) === 46 ? k + 2 : k + 1;
268
+ if (n >= end || isSep(f.charCodeAt(n), sep))
269
+ return true;
270
+ }
271
+ // the start of the next portion, after any run of separators
272
+ const s = nextSep(f, k, sep);
273
+ if (s === -1)
274
+ return false;
275
+ k = s + 1;
276
+ while (k < end && isSep(f.charCodeAt(k), sep))
277
+ k++;
278
+ }
279
+ return false;
280
+ };
281
+ const isSep = (c, sep) => sep === '/' ? c === 47
282
+ : sep === '\\' ? c === 92
283
+ : c === 47 || c === 92;
284
+ // the index of the first separator at or after `from`, or -1
285
+ const nextSep = (f, from, sep) => {
286
+ if (sep !== 'both')
287
+ return f.indexOf(sep, from);
288
+ const s = f.indexOf('/', from);
289
+ const b = f.indexOf('\\', from);
290
+ return (s === -1 ? b
291
+ : b === -1 ? s
292
+ : Math.min(s, b));
293
+ };
294
+ // the index of the last separator at or before `from`, or -1
295
+ const lastSep = (f, from, sep) => sep !== 'both' ?
296
+ f.lastIndexOf(sep, from)
297
+ : Math.max(f.lastIndexOf('/', from), f.lastIndexOf('\\', from));
298
+ // What parse() returns in place of a Matcher while make() builds and
299
+ // merges the rows. Most of the Matchers in rows that are merged would
300
+ // never be used, so they are only made for the rows that are left.
301
+ const PENDING = {};
179
302
  export class Minimatch {
180
303
  options;
181
304
  set;
@@ -194,7 +317,27 @@ export class Minimatch {
194
317
  platform;
195
318
  windowsNoMagicRoot;
196
319
  maxGlobstarRecursion;
197
- regexp;
320
+ // the path can be checked against the last portion, and the string
321
+ // portions, of each row before it is split. See #canMatch.
322
+ #endCheck;
323
+ #literalCheck;
324
+ // level 2 resolves `.` and `..` portions in the path
325
+ #level2;
326
+ // the unicode normalization form, if any
327
+ #form;
328
+ // the string portions of each row in the set
329
+ #literals = [];
330
+ // the rows that #canMatch can match without splitting the path
331
+ #shapes = [];
332
+ // the rows whose last portion can be checked against the path's
333
+ #endRows = [];
334
+ // brace expansion can make the same portion in many rows, so they
335
+ // share one Matcher, and the states that it caches
336
+ #matchers = new Map();
337
+ // parse() returns PENDING in place of a Matcher
338
+ #pending = false;
339
+ // the GlobstarParts of each pattern row, by start index and partial
340
+ #globstarParts = new WeakMap();
198
341
  constructor(pattern, options = {}) {
199
342
  assertValidPattern(pattern);
200
343
  options = options || {};
@@ -211,7 +354,6 @@ export class Minimatch {
211
354
  this.pattern = this.pattern.replace(/\\/g, '/');
212
355
  }
213
356
  this.preserveMultipleSlashes = !!options.preserveMultipleSlashes;
214
- this.regexp = null;
215
357
  this.negate = false;
216
358
  this.nonegate = !!options.nonegate;
217
359
  this.comment = false;
@@ -225,8 +367,81 @@ export class Minimatch {
225
367
  this.globSet = [];
226
368
  this.globParts = [];
227
369
  this.set = [];
228
- // make the set of regexps etc.
370
+ this.#endCheck = !this.preserveMultipleSlashes;
371
+ this.#level2 = (options.optimizationLevel ?? 1) >= 2;
372
+ const n = options.normalize;
373
+ this.#form = n === true ? 'NFC' : n || undefined;
374
+ // make the set of Matchers etc.
229
375
  this.make();
376
+ // On Windows, the portions of a row up to its drive letter or UNC
377
+ // share are skipped or compared without case, if the path has one
378
+ // too. So the checks only use the portions after it.
379
+ const drives = this.set.map(row => this.#rootIndex(row));
380
+ this.#endRows = this.set.map((row, r) => this.#endCheck && row.length - 1 > drives[r]);
381
+ // with the end check, the last portion is already checked
382
+ this.#literals = this.set.map((row, r) => {
383
+ const end = this.#endRows[r] ? row.length - 1 : row.length;
384
+ const lits = row
385
+ .slice(drives[r] + 1, end)
386
+ .filter((p) => typeof p === 'string' && !!p);
387
+ return [...new Set(lits)];
388
+ });
389
+ this.#literalCheck = this.#literals.some(l => l.length);
390
+ this.#shapes = this.set.map((row, r) => {
391
+ const [p0, p1, p2] = row;
392
+ if (this.#endRows[r] && row.length === 2) {
393
+ if (p0 === GLOBSTAR && p1 !== GLOBSTAR)
394
+ return 'tail';
395
+ }
396
+ // the basename of a path that is split on / is its last portion,
397
+ // or the one before a trailing /, the same as the end check
398
+ if (this.#endRows[r] &&
399
+ options.matchBase &&
400
+ row.length === 1 &&
401
+ p0 !== GLOBSTAR &&
402
+ p0 !== '') {
403
+ return 'base';
404
+ }
405
+ // the portion must not be a root, or '', which can be a
406
+ // different portion on Windows (where //x paths get an extra '')
407
+ if (!this.#endCheck || drives[r] !== -1)
408
+ return undefined;
409
+ if (row.length === 3 &&
410
+ p0 === GLOBSTAR &&
411
+ p2 === GLOBSTAR &&
412
+ p1 !== GLOBSTAR &&
413
+ p1 !== '' &&
414
+ // the portion between is only matched below this limit
415
+ this.maxGlobstarRecursion > 0) {
416
+ return 'mid';
417
+ }
418
+ if (row.length === 2 &&
419
+ p1 === GLOBSTAR &&
420
+ p0 !== GLOBSTAR &&
421
+ p0 !== '') {
422
+ return 'head';
423
+ }
424
+ return undefined;
425
+ });
426
+ }
427
+ // a string portion of a pattern, normalized if the option is set
428
+ #norm(p) {
429
+ return this.#form ? p.normalize(this.#form) : p;
430
+ }
431
+ // On Windows, the index of the last root portion of a row, as
432
+ // #matchRow finds it: 0 for `c:/...`, 3 for `//?/c:/...` and
433
+ // `//host/share/...`, and 5 for `//?/UNC/host/share/...`. Otherwise
434
+ // -1.
435
+ #rootIndex(row) {
436
+ if (!this.isWindows)
437
+ return -1;
438
+ if (isDrive(row[0]))
439
+ return 0;
440
+ const uncDrive = row[0] === '' && row[1] === '' && row[2] === '?' && isDrive(row[3]);
441
+ if (uncDrive)
442
+ return 3;
443
+ const h = uncHost(row);
444
+ return h === -1 ? -1 : h + 1;
230
445
  }
231
446
  hasMagic() {
232
447
  if (this.options.magicalBraces && this.set.length > 1) {
@@ -240,7 +455,6 @@ export class Minimatch {
240
455
  }
241
456
  return false;
242
457
  }
243
- debug(..._) { }
244
458
  make() {
245
459
  const pattern = this.pattern;
246
460
  const options = this.options;
@@ -257,45 +471,44 @@ export class Minimatch {
257
471
  this.parseNegate();
258
472
  // step 2: expand braces
259
473
  this.globSet = [...new Set(this.braceExpand())];
260
- if (options.debug) {
261
- //oxlint-disable-next-line no-console
262
- this.debug = (...args) => console.error(...args);
263
- }
264
- this.debug(this.pattern, this.globSet);
265
474
  // step 3: now we have a set, so turn each one into a series of
266
475
  // path-portion matching patterns.
267
- // These will be regexps, except in the case of "**", which is
476
+ // These will be Matchers, except in the case of "**", which is
268
477
  // set to the GLOBSTAR object for globstar behavior,
269
478
  // and will not contain any / characters
270
479
  //
271
480
  // First, we preprocess to make the glob pattern sets a bit simpler
272
481
  // and deduped. There are some perf-killing patterns that can cause
273
482
  // problems with a glob walk, but we can simplify them down a bit.
274
- const rawGlobParts = this.globSet.map(s => this.slashSplit(s));
483
+ const rawGlobParts = this.globSet.map(s => this.#slashSplit(s));
275
484
  this.globParts = this.preprocess(rawGlobParts);
276
- this.debug(this.pattern, this.globParts);
277
- // glob --> regexps
485
+ // glob --> Matchers
486
+ this.#pending = true;
278
487
  let set = this.globParts.map((s, _, __) => {
279
488
  if (this.isWindows && this.windowsNoMagicRoot) {
280
- // check if it's a drive or unc path.
489
+ // check if it's a drive or unc path. The root of a long UNC
490
+ // path, //?/UNC/host/share, is 6 portions.
491
+ const n = s[2] === '?' && isLongUNC(s[3]) ? 6 : 4;
281
492
  const isUNC = s[0] === '' &&
282
493
  s[1] === '' &&
283
494
  (s[2] === '?' || !globMagic.test(s[2])) &&
284
- !globMagic.test(s[3]);
495
+ s.slice(3, n).every(p => !globMagic.test(p));
285
496
  const isDrive = /^[a-z]:/i.test(s[0]);
286
497
  if (isUNC) {
287
498
  return [
288
- ...s.slice(0, 4),
289
- ...s.slice(4).map(ss => this.parse(ss)),
499
+ ...s.slice(0, n).map(p => this.#norm(p)),
500
+ ...s.slice(n).map(ss => this.parse(ss)),
290
501
  ];
291
502
  }
292
503
  else if (isDrive) {
293
- return [s[0], ...s.slice(1).map(ss => this.parse(ss))];
504
+ return [
505
+ this.#norm(s[0]),
506
+ ...s.slice(1).map(ss => this.parse(ss)),
507
+ ];
294
508
  }
295
509
  }
296
510
  return s.map(ss => this.parse(ss));
297
511
  });
298
- this.debug(this.pattern, set);
299
512
  // filter out everything that didn't compile properly.
300
513
  this.set = set.filter(s => s.indexOf(false) === -1);
301
514
  // do not treat the ? in UNC paths as magic
@@ -305,13 +518,70 @@ export class Minimatch {
305
518
  if (p[0] === '' &&
306
519
  p[1] === '' &&
307
520
  this.globParts[i][2] === '?' &&
308
- typeof p[3] === 'string' &&
309
- /^[a-z]:$/i.test(p[3])) {
521
+ (isDrive(p[3]) || isLongUNC(this.globParts[i][3]))) {
522
+ if (isLongUNC(this.globParts[i][3]))
523
+ p[3] = 'UNC';
310
524
  p[2] = '?';
311
525
  }
312
526
  }
313
527
  }
314
- this.debug(this.pattern, this.set);
528
+ // with noext, `@(...)` would be literal
529
+ if (!options.noext)
530
+ this.mergeRows();
531
+ this.#pending = false;
532
+ this.set.forEach((row, i) => {
533
+ for (let k = 0; k < row.length; k++) {
534
+ if (row[k] === PENDING) {
535
+ row[k] = this.parse(this.globParts[i][k]);
536
+ }
537
+ }
538
+ });
539
+ }
540
+ // Merge rows that only differ in one portion, where each of them
541
+ // is a Matcher, into one row that matches any of them with
542
+ // `@(a|b|...)`. Then a path is only walked once for all of them,
543
+ // for example with `**/*.{js,ts}`.
544
+ mergeRows() {
545
+ let merged = true;
546
+ while (merged) {
547
+ merged = false;
548
+ const len = Math.max(0, ...this.set.map(r => r.length));
549
+ for (let k = 0; k < len; k++) {
550
+ // the rows that are the same other than at portion k
551
+ const groups = new Map();
552
+ this.set.forEach((row, i) => {
553
+ if (!(row[k] instanceof Matcher || row[k] === PENDING) ||
554
+ !extSafe(this.globParts[i][k])) {
555
+ return;
556
+ }
557
+ const parts = [...this.globParts[i]];
558
+ parts[k] = '';
559
+ const key = `${row.length}/${parts.join('/')}`;
560
+ const g = groups.get(key);
561
+ if (g)
562
+ g.push(i);
563
+ else
564
+ groups.set(key, [i]);
565
+ });
566
+ const drop = new Set();
567
+ for (const g of groups.values()) {
568
+ if (g.length < 2)
569
+ continue;
570
+ const [first, ...rest] = g;
571
+ const alts = g.map(i => this.globParts[i][k]);
572
+ const glob = `@(${alts.join('|')})`;
573
+ this.globParts[first][k] = glob;
574
+ this.set[first][k] = this.parse(glob);
575
+ for (const i of rest)
576
+ drop.add(i);
577
+ }
578
+ if (drop.size) {
579
+ merged = true;
580
+ this.set = this.set.filter((_, i) => !drop.has(i));
581
+ this.globParts = this.globParts.filter((_, i) => !drop.has(i));
582
+ }
583
+ }
584
+ }
315
585
  }
316
586
  // various transforms to equivalent pattern sets that are
317
587
  // faster to process in a filesystem walk. The goal is to
@@ -364,13 +634,19 @@ export class Minimatch {
364
634
  // get rid of adjascent ** and resolve .. portions
365
635
  levelOneOptimize(globParts) {
366
636
  return globParts.map(parts => {
637
+ // .. can not remove the root of a Windows path
638
+ const root = this.#rootIndex(parts) + 1;
367
639
  parts = parts.reduce((set, part) => {
368
640
  const prev = set[set.length - 1];
369
641
  if (part === '**' && prev === '**') {
370
642
  return set;
371
643
  }
372
644
  if (part === '..') {
373
- if (prev && prev !== '..' && prev !== '.' && prev !== '**') {
645
+ if (set.length > root &&
646
+ prev &&
647
+ prev !== '..' &&
648
+ prev !== '.' &&
649
+ prev !== '**') {
374
650
  set.pop();
375
651
  return set;
376
652
  }
@@ -381,10 +657,214 @@ export class Minimatch {
381
657
  return parts.length === 0 ? [''] : parts;
382
658
  });
383
659
  }
384
- levelTwoFileOptimize(parts) {
385
- if (!Array.isArray(parts)) {
386
- parts = this.slashSplit(parts);
660
+ // Check the path against each row before it is split. 'no' if no
661
+ // row can match, so it does not need to be split. 'yes' if a row of
662
+ // `**` and one more portion matches. 'maybe' if it must be split to
663
+ // know. None of this applies with partial, where the path can end
664
+ // before the row does.
665
+ //
666
+ // On Windows, `\` is a separator in the path too, and the portions of
667
+ // a row up to its drive letter or UNC share are not checked (see
668
+ // #rootIndex).
669
+ //
670
+ // Each string portion of a row must be a portion of the path, so the
671
+ // path must contain it. Level 2 can only take portions out of the
672
+ // path, so this is still true then.
673
+ //
674
+ // The last portion of a row must match the last portion of the path,
675
+ // or the one before a trailing `/` (as a/* and a/**/* match a/b/).
676
+ // This does not apply to rows that end in **, rows that end in a
677
+ // root, or preserveMultipleSlashes (which can leave more
678
+ // than one '' at the end). At level 2, it does not apply if that
679
+ // portion is `.` or `..`, which can be
680
+ // resolved away. Level 2 only takes other portions out of the
681
+ // middle of the path.
682
+ //
683
+ // A row of `**/x` then matches if the ** can walk the portions
684
+ // before the one that x matches, the same as #matchGlobstar. At
685
+ // level 2, this is only known if none of them are `.` or `..`, so
686
+ // that the path does not change when it is resolved.
687
+ #canMatch(f) {
688
+ const sep = !this.isWindows || !f.includes('\\') ? '/'
689
+ : f.includes('/') ? 'both'
690
+ : '\\';
691
+ // the portions that f.split(/\/+/) would end with, and where they
692
+ // start in f, found when a row needs them. `ends` is 0 until they
693
+ // are found, then 1, or -1 if they can not be used.
694
+ let ends = this.#endCheck ? 0 : -1;
695
+ let last = '';
696
+ let lastStart = 0;
697
+ let prev;
698
+ let prevStart = 0;
699
+ const dot = !!this.options.dot;
700
+ // A string compare is cheaper than includes(), and a Matcher test
701
+ // costs more, so the cheaper check goes first.
702
+ ROWS: for (let r = 0; r < this.set.length; r++) {
703
+ const row = this.set[r];
704
+ const p = row[row.length - 1];
705
+ let end = ends !== -1 && this.#endRows[r] && p !== GLOBSTAR;
706
+ if (end && ends === 0) {
707
+ const i = lastSep(f, f.length, sep);
708
+ lastStart = i + 1;
709
+ last = f.slice(lastStart);
710
+ if (last === '' && i >= 0) {
711
+ let j = i;
712
+ while (j > 0 && isSep(f.charCodeAt(j - 1), sep))
713
+ j--;
714
+ prevStart = j === 0 ? 0 : lastSep(f, j - 1, sep) + 1;
715
+ prev = f.slice(prevStart, j);
716
+ }
717
+ const resolves = this.#level2 &&
718
+ (isDots(last) ||
719
+ (last === '' && prev !== undefined && isDots(prev)));
720
+ ends = resolves ? -1 : 1;
721
+ end = !resolves;
722
+ }
723
+ let tailStart = -1;
724
+ if (end && typeof p === 'string') {
725
+ tailStart = endIndex(p, last, lastStart, prev, prevStart);
726
+ if (tailStart === -1)
727
+ continue;
728
+ }
729
+ if (this.#literalCheck) {
730
+ for (const l of this.#literals[r]) {
731
+ if (!f.includes(l))
732
+ continue ROWS;
733
+ }
734
+ }
735
+ if (end && typeof p === 'object') {
736
+ tailStart = endIndex(p, last, lastStart, prev, prevStart);
737
+ if (tailStart === -1)
738
+ continue;
739
+ }
740
+ const shape = this.#shapes[r];
741
+ if (shape === 'base' && end)
742
+ return 'yes';
743
+ if (shape === 'tail' && end) {
744
+ if (this.#level2 && dotPortion(f, 0, tailStart, true, sep)) {
745
+ return 'maybe';
746
+ }
747
+ if (!dotPortion(f, 0, tailStart, dot, sep))
748
+ return 'yes';
749
+ continue;
750
+ }
751
+ if (shape === 'mid' || shape === 'head') {
752
+ const m = this.#walk(f, row, shape === 'head', dot, sep);
753
+ if (m !== 'no')
754
+ return m;
755
+ continue;
756
+ }
757
+ return 'maybe';
758
+ }
759
+ return 'no';
760
+ }
761
+ // Match a row of a known shape against the split path, the same as
762
+ // #matchGlobstar and #matchGlobStarBodySections do. None of these
763
+ // rows have a drive letter, so they start at the first portion.
764
+ #matchShape(file, row, shape) {
765
+ const dot = !!this.options.dot;
766
+ const n = file.length;
767
+ if (shape === 'head') {
768
+ // x, then at least one portion that ** can walk
769
+ if (n < 2 || !portionMatch(row[0], file[0])) {
770
+ return false;
771
+ }
772
+ for (let i = 1; i < n; i++)
773
+ if (!walkable(file[i], dot))
774
+ return false;
775
+ return true;
776
+ }
777
+ const x = row[1];
778
+ if (shape === 'tail') {
779
+ // x is the last portion, or the one before a trailing ''
780
+ let t = n - 1;
781
+ if (!portionMatch(x, file[t])) {
782
+ if (file[t] !== '' || n === 1 || !portionMatch(x, file[--t])) {
783
+ return false;
784
+ }
785
+ }
786
+ for (let i = 0; i < t; i++)
787
+ if (!walkable(file[i], dot))
788
+ return false;
789
+ return true;
790
+ }
791
+ // mid: the first x that ** can walk to, with a portion after it,
792
+ // and ** can walk all of those
793
+ for (let k = 0; k < n; k++) {
794
+ if (portionMatch(x, file[k]) && k + 1 < n) {
795
+ let i = k + 1;
796
+ while (i < n && walkable(file[i], dot))
797
+ i++;
798
+ if (i === n)
799
+ return true;
800
+ }
801
+ if (!walkable(file[k], dot))
802
+ return false;
803
+ }
804
+ return false;
805
+ }
806
+ // Match a row of `**/x/**` or `x/**` against the path, the same as
807
+ // #matchGlobstar and #matchGlobStarBodySections do once it is split.
808
+ // x must match a portion (the first one, for `x/**`), the ** before
809
+ // it must be able to walk the portions before that one, and there
810
+ // must be a portion after it, which the ** after it can walk. At
811
+ // level 2, this is only known if no portion is `.` or `..`.
812
+ #walk(f, row, head, dot, sep) {
813
+ if (this.#level2 && dotPortion(f, 0, f.length, true, sep))
814
+ return 'maybe';
815
+ const x = row[head ? 0 : 1];
816
+ // the last portion has none after it, so it can not be x
817
+ let s = 0;
818
+ for (let e = nextSep(f, s, sep); e !== -1; e = nextSep(f, s, sep)) {
819
+ // the start of the next portion
820
+ let next = e + 1;
821
+ while (next < f.length && isSep(f.charCodeAt(next), sep))
822
+ next++;
823
+ const hit = typeof x === 'string' ?
824
+ e - s === x.length && f.startsWith(x, s)
825
+ : e > s && x.testUnchecked(f.slice(s, e));
826
+ if (hit && !dotPortion(f, next, f.length, dot, sep))
827
+ return 'yes';
828
+ if (head || dotPortion(f, s, next, dot, sep))
829
+ return 'no';
830
+ s = next;
387
831
  }
832
+ return 'no';
833
+ }
834
+ // the last split, if it was the same path with the same split
835
+ // settings
836
+ #cachedSplit(f) {
837
+ const last = lastSplit;
838
+ return (last?.f === f &&
839
+ last.isWindows === this.isWindows &&
840
+ last.preserveMultipleSlashes === this.preserveMultipleSlashes &&
841
+ last.normalize === this.#form) ?
842
+ last
843
+ : undefined;
844
+ }
845
+ // split a path for match(), and keep the parts for the next call
846
+ #split(f) {
847
+ const { isWindows, preserveMultipleSlashes } = this;
848
+ // windows: need to use /, not \
849
+ let parts = this.#slashSplit(isWindows ? f.split('\\').join('/') : f);
850
+ // normalize each portion, so that a char that normalizes to `/`
851
+ // does not make a new portion
852
+ const normalize = this.#form;
853
+ if (normalize)
854
+ parts = parts.map(p => p.normalize(normalize));
855
+ lastSplit = {
856
+ f,
857
+ isWindows,
858
+ preserveMultipleSlashes,
859
+ normalize,
860
+ parts,
861
+ };
862
+ return lastSplit;
863
+ }
864
+ // resolve `.` and `..` portions of a path, for level 2
865
+ #levelTwoFileOptimize(file) {
866
+ // work on a copy, so that the cached parts do not change
867
+ const parts = [...file];
388
868
  let didSomething = false;
389
869
  do {
390
870
  didSomething = false;
@@ -409,17 +889,15 @@ export class Minimatch {
409
889
  }
410
890
  }
411
891
  // <pre>/<p>/../<rest> -> <pre>/<rest>
412
- let dd = 0;
892
+ // .. can not remove the root of a Windows path
893
+ const root = this.#rootIndex(parts) + 1;
894
+ let dd = root;
413
895
  while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
414
896
  const p = parts[dd - 1];
415
- if (p &&
416
- p !== '.' &&
417
- p !== '..' &&
418
- p !== '**' &&
419
- !(this.isWindows && /^[a-z]:$/i.test(p))) {
897
+ if (p && p !== '.' && p !== '..' && p !== '**') {
420
898
  didSomething = true;
421
899
  parts.splice(dd - 1, 2);
422
- dd -= 2;
900
+ dd = Math.max(dd - 2, root);
423
901
  }
424
902
  }
425
903
  } while (didSomething);
@@ -444,6 +922,8 @@ export class Minimatch {
444
922
  // **/*/<rest> -> */**/<rest> <== not valid because ** doesn't follow
445
923
  // this WOULD be allowed if ** did follow symlinks, or * didn't
446
924
  firstPhasePreProcess(globParts) {
925
+ // each **/.. split doubles the patterns, so stop at the brace max
926
+ const { braceExpandMax = 100_000 } = this.options;
447
927
  let didSomething = false;
448
928
  do {
449
929
  didSomething = false;
@@ -471,7 +951,8 @@ export class Minimatch {
471
951
  p === '..' ||
472
952
  !p2 ||
473
953
  p2 === '.' ||
474
- p2 === '..') {
954
+ p2 === '..' ||
955
+ globParts.length >= braceExpandMax) {
475
956
  continue;
476
957
  }
477
958
  didSomething = true;
@@ -503,7 +984,9 @@ export class Minimatch {
503
984
  }
504
985
  }
505
986
  // <pre>/<p>/../<rest> -> <pre>/<rest>
506
- let dd = 0;
987
+ // .. can not remove the root of a Windows path
988
+ const root = this.#rootIndex(parts) + 1;
989
+ let dd = root;
507
990
  while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
508
991
  const p = parts[dd - 1];
509
992
  if (p && p !== '.' && p !== '..' && p !== '**') {
@@ -513,7 +996,7 @@ export class Minimatch {
513
996
  parts.splice(dd - 1, 2, ...splin);
514
997
  if (parts.length === 0)
515
998
  parts.push('');
516
- dd -= 2;
999
+ dd = Math.max(dd - 2, root);
517
1000
  }
518
1001
  }
519
1002
  }
@@ -528,6 +1011,10 @@ export class Minimatch {
528
1011
  // {<pre>/**/<rest>,<pre>/**/<p>/<rest>} -> <pre>/**/<rest>
529
1012
  // ^-- not valid because ** doens't follow symlinks
530
1013
  secondPhasePreProcess(globParts) {
1014
+ // each pattern is compared to each other one, so skip this for
1015
+ // large sets. The patterns match the same paths either way.
1016
+ if (globParts.length > 1000)
1017
+ return globParts;
531
1018
  for (let i = 0; i < globParts.length - 1; i++) {
532
1019
  for (let j = i + 1; j < globParts.length; j++) {
533
1020
  const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
@@ -603,18 +1090,36 @@ export class Minimatch {
603
1090
  this.pattern = pattern.slice(negateOffset);
604
1091
  this.negate = negate;
605
1092
  }
606
- // set partial to true to test if, for example,
607
- // "/a/b" matches the start of "/*/b/*/d"
608
- // Partial means, if you run out of file before you run
609
- // out of pattern, then that's fine, as long as all
610
- // the parts match.
611
- matchOne(file, pattern, partial = false) {
1093
+ // Match the parts of a path against one row of the set. `resolved`
1094
+ // is the parts after level 2 resolves `.` and `..` in them, or the
1095
+ // same parts below level 2. Set partial to true to test if, for
1096
+ // example, "/a/b" matches the start of "/*/b/*/d". Partial means, if
1097
+ // you run out of file before you run out of pattern, then that's
1098
+ // fine, as long as all the parts match.
1099
+ #matchRow(file, resolved, pattern, partial) {
612
1100
  let fileStartIndex = 0;
613
1101
  let patternStartIndex = 0;
614
- // UNC paths like //?/X:/... can match X:/... and vice versa
615
- // Drive letters in absolute drive or unc paths are always compared
616
- // case-insensitively.
617
- if (this.isWindows) {
1102
+ // UNC paths like //?/X:/... can match X:/... and vice versa, and
1103
+ // //?/UNC/host/share/... can match //host/share/... and vice versa.
1104
+ // Drive letters in absolute drive or unc paths, and the host and
1105
+ // share of UNC paths, are always compared case-insensitively.
1106
+ const fh = this.isWindows ? uncHost(resolved) : -1;
1107
+ const ph = fh === -1 ? -1 : uncHost(pattern);
1108
+ if (ph !== -1) {
1109
+ const host = pattern[ph];
1110
+ const share = pattern[ph + 1];
1111
+ if (typeof host !== 'string' || typeof share !== 'string') {
1112
+ // a host or share with magic is matched as usual
1113
+ fileStartIndex = fh;
1114
+ patternStartIndex = ph;
1115
+ }
1116
+ else if (resolved[fh].toLowerCase() === host.toLowerCase() &&
1117
+ resolved[fh + 1].toLowerCase() === share.toLowerCase()) {
1118
+ fileStartIndex = fh + 2;
1119
+ patternStartIndex = ph + 2;
1120
+ }
1121
+ }
1122
+ else if (this.isWindows) {
618
1123
  const fileDrive = typeof file[0] === 'string' && /^[a-z]:$/i.test(file[0]);
619
1124
  const fileUNC = !fileDrive &&
620
1125
  file[0] === '' &&
@@ -639,47 +1144,27 @@ export class Minimatch {
639
1144
  file[fdi],
640
1145
  pattern[pdi],
641
1146
  ];
642
- // start matching at the drive letter index of each
1147
+ // the drives match, so start matching after them
643
1148
  if (fd.toLowerCase() === pd.toLowerCase()) {
644
- pattern[pdi] = fd;
645
- patternStartIndex = pdi;
646
- fileStartIndex = fdi;
1149
+ patternStartIndex = pdi + 1;
1150
+ fileStartIndex = fdi + 1;
647
1151
  }
648
1152
  }
649
1153
  }
650
- // resolve and reduce . and .. portions in the file as well.
651
- // don't need to do the second phase, because it's only one string[]
652
- const { optimizationLevel = 1 } = this.options;
653
- if (optimizationLevel >= 2) {
654
- file = this.levelTwoFileOptimize(file);
655
- }
1154
+ // the drive letters are found in the parts before level 2 resolves
1155
+ // them, and the match uses the resolved parts
1156
+ file = resolved;
656
1157
  if (pattern.includes(GLOBSTAR)) {
657
1158
  return this.#matchGlobstar(file, pattern, partial, fileStartIndex, patternStartIndex);
658
1159
  }
659
1160
  return this.#matchOne(file, pattern, partial, fileStartIndex, patternStartIndex);
660
1161
  }
661
1162
  #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
- ];
1163
+ const { head, body, tail, segments } = this.#getGlobstarParts(pattern, partial, patternIndex);
679
1164
  // check the head, from the current file/pattern index.
680
1165
  if (head.length) {
681
- const fileHead = file.slice(fileIndex, fileIndex + head.length);
682
- if (!this.#matchOne(fileHead, head, partial, 0, 0)) {
1166
+ const headEnd = fileIndex + head.length;
1167
+ if (!this.#matchOne(file, head, partial, fileIndex, 0, headEnd)) {
683
1168
  return false;
684
1169
  }
685
1170
  fileIndex += head.length;
@@ -737,36 +1222,64 @@ export class Minimatch {
737
1222
  // now we know that there's one or more body sections, which can
738
1223
  // be matched anywhere from the 0 index (because the head was pruned)
739
1224
  // 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];
1225
+ return !!this.#matchGlobStarBodySections(file, segments, file.length - fileTailMatch, fileIndex, 0, partial, 0, !!fileTailMatch, new Set());
1226
+ }
1227
+ // Split the pattern into head, tail, and middle of ** delimited
1228
+ // parts. The tail has to be at the end, and the others just have to
1229
+ // be found in order from the head. These only depend on the pattern
1230
+ // row, so they are kept for the next path.
1231
+ #getGlobstarParts(pattern, partial, patternIndex) {
1232
+ let byStart = this.#globstarParts.get(pattern);
1233
+ if (!byStart) {
1234
+ byStart = [];
1235
+ this.#globstarParts.set(pattern, byStart);
1236
+ }
1237
+ const key = patternIndex * 2 + (partial ? 1 : 0);
1238
+ const found = byStart[key];
1239
+ if (found)
1240
+ return found;
1241
+ const firstgs = pattern.indexOf(GLOBSTAR, patternIndex);
1242
+ const lastgs = pattern.lastIndexOf(GLOBSTAR);
1243
+ const head = pattern.slice(patternIndex, firstgs);
1244
+ const body = pattern.slice(firstgs + 1, partial ? undefined : lastgs);
1245
+ const tail = partial ? [] : pattern.slice(lastgs + 1);
1246
+ // split the body up into sections, and note the number of
1247
+ // portions that must come after the start of each one
1248
+ const segments = [[[], 0]];
1249
+ let current = segments[0];
745
1250
  let nonGsParts = 0;
746
1251
  const nonGsPartsSums = [0];
747
1252
  for (const b of body) {
748
1253
  if (b === GLOBSTAR) {
749
1254
  nonGsPartsSums.push(nonGsParts);
750
- currentBody = [[], 0];
751
- bodySegments.push(currentBody);
1255
+ current = [[], 0];
1256
+ segments.push(current);
752
1257
  }
753
1258
  else {
754
- currentBody[0].push(b);
1259
+ current[0].push(b);
755
1260
  nonGsParts++;
756
1261
  }
757
1262
  }
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);
1263
+ // the portions in this section and the ones after it
1264
+ segments.forEach((b, i) => {
1265
+ b[1] = nonGsParts - nonGsPartsSums[i];
1266
+ });
1267
+ const parts = { head, body, tail, segments };
1268
+ byStart[key] = parts;
1269
+ return parts;
764
1270
  }
765
1271
  // return false for "nope, not matching"
766
1272
  // return null for "not matching, cannot keep trying"
767
1273
  #matchGlobStarBodySections(file,
768
- // pattern section, last possible position for it
769
- bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail) {
1274
+ // pattern section, and the portions that it and the rest need
1275
+ bodySegments,
1276
+ // the end of the file portions that the body can match
1277
+ fileLength, fileIndex, bodyIndex, partial, globStarDepth, sawTail,
1278
+ // the places that a walk has already tried, as
1279
+ // bodyIndex * (file.length + 1) + fileIndex. A walk from a place
1280
+ // does the same no matter how it got there, and it only comes back
1281
+ // if it found no match, so a walk that gets to one stops.
1282
+ tried) {
770
1283
  // take the first body segment, and walk from fileIndex to its "after"
771
1284
  // value at the end
772
1285
  // If it doesn't match at that position, we increment, until we hit
@@ -778,8 +1291,16 @@ export class Minimatch {
778
1291
  // can't possibly be a valid matching condition.
779
1292
  const bs = bodySegments[bodyIndex];
780
1293
  if (!bs) {
781
- // just make sure that there's no bad dots
782
- for (let i = fileIndex; i < file.length; i++) {
1294
+ // with partial, the body is the rest of the pattern, so it
1295
+ // matches if no portions are left, or only the '' of a trailing
1296
+ // / (as a/* matches a/b/). A ** at the end walks them as its own
1297
+ // empty section.
1298
+ if (partial) {
1299
+ return (fileIndex >= fileLength ||
1300
+ (fileIndex === fileLength - 1 && file[fileIndex] === ''));
1301
+ }
1302
+ // just make sure that there's no bad dots before the tail
1303
+ for (let i = fileIndex; i < fileLength; i++) {
783
1304
  sawTail = true;
784
1305
  const f = file[i];
785
1306
  if (f === '.' ||
@@ -790,19 +1311,29 @@ export class Minimatch {
790
1311
  }
791
1312
  return sawTail;
792
1313
  }
793
- // have a non-globstar body section to test
794
- const [body, after] = bs;
1314
+ // have a non-globstar body section to test, up to the last index
1315
+ // where it can start
1316
+ const [body, need] = bs;
1317
+ // with partial, the path can end before the body does
1318
+ const after = partial ? fileLength : fileLength - need;
795
1319
  while (fileIndex <= after) {
796
- const m = this.#matchOne(file.slice(0, fileIndex + body.length), body, partial, fileIndex, 0);
1320
+ const key = bodyIndex * (file.length + 1) + fileIndex;
1321
+ if (tried.has(key))
1322
+ return false;
1323
+ tried.add(key);
1324
+ const m = this.#matchOne(file, body, partial, fileIndex, 0, fileIndex + body.length);
797
1325
  // if limit exceeded, no match. intentional false negative,
798
1326
  // acceptable break in correctness for security.
799
1327
  if (m && globStarDepth < this.maxGlobstarRecursion) {
800
1328
  // 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);
1329
+ const sub = this.#matchGlobStarBodySections(file, bodySegments, fileLength, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail, tried);
802
1330
  if (sub !== false) {
803
1331
  return sub;
804
1332
  }
805
1333
  }
1334
+ // the ** does not walk past the last place the body can start
1335
+ if (fileIndex === after)
1336
+ break;
806
1337
  const f = file[fileIndex];
807
1338
  if (f === '.' ||
808
1339
  f === '..' ||
@@ -814,21 +1345,20 @@ export class Minimatch {
814
1345
  // walked off. no point continuing
815
1346
  return partial || null;
816
1347
  }
817
- #matchOne(file, pattern, partial, fileIndex, patternIndex) {
1348
+ #matchOne(file, pattern, partial, fileIndex, patternIndex,
1349
+ // only match the file portions before this index
1350
+ fileEnd = file.length) {
818
1351
  let fi;
819
1352
  let pi;
820
1353
  let pl;
821
1354
  let fl;
822
1355
  for (fi = fileIndex,
823
1356
  pi = patternIndex,
824
- fl = file.length,
1357
+ fl = Math.min(fileEnd, file.length),
825
1358
  pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
826
- this.debug('matchOne loop');
827
1359
  let p = pattern[pi];
828
1360
  let f = file[fi];
829
- this.debug(pattern, p, f);
830
1361
  // should be impossible.
831
- // some invalid regexp stuff in the set.
832
1362
  /* c8 ignore start */
833
1363
  if (p === false || p === GLOBSTAR) {
834
1364
  return false;
@@ -836,17 +1366,8 @@ export class Minimatch {
836
1366
  /* c8 ignore stop */
837
1367
  // something other than **
838
1368
  // non-magic patterns just have to match exactly
839
- // patterns with magic have been turned into regexps.
840
- let hit;
841
- if (typeof p === 'string') {
842
- hit = f === p;
843
- this.debug('string match', p, f, hit);
844
- }
845
- else {
846
- hit = p.test(f);
847
- this.debug('pattern match', p, f, hit);
848
- }
849
- if (!hit)
1369
+ // patterns with magic have been turned into Matchers.
1370
+ if (!portionMatch(p, f))
850
1371
  return false;
851
1372
  }
852
1373
  // Note: ending in / means that we'll get a final ""
@@ -855,9 +1376,8 @@ export class Minimatch {
855
1376
  // If the file ends in /, then it can only match a
856
1377
  // a pattern that ends in /, unless the pattern just
857
1378
  // doesn't have any more for it. But, a/b/ should *not*
858
- // match "a/b/*", even though "" matches against the
859
- // [^/]*? pattern, except in partial mode, where it might
860
- // simply not be reached yet.
1379
+ // match "a/b/*", even though * can match "", except in
1380
+ // partial mode, where it might simply not be reached yet.
861
1381
  // However, a/b/ should still satisfy a/*
862
1382
  // now either we fell off the end of the pattern, or we're done.
863
1383
  if (fi === fl && pi === pl) {
@@ -896,139 +1416,26 @@ export class Minimatch {
896
1416
  return GLOBSTAR;
897
1417
  if (pattern === '')
898
1418
  return '';
899
- // far and away, the most common glob pattern parts are
900
- // *, *.*, and *.<ext> Add a fast check method for those.
901
- let m;
902
- let fastTest = null;
903
- if ((m = pattern.match(starRE))) {
904
- fastTest = options.dot ? starTestDot : starTest;
1419
+ const { nocase, nocaseMagicOnly, noext = false, dot, normalize, } = options;
1420
+ const lit = literal(pattern, noext);
1421
+ // in nocase mode, a literal with cased chars still needs a
1422
+ // Matcher, unless nocaseMagicOnly is set.
1423
+ if (lit !== undefined &&
1424
+ !(nocase &&
1425
+ !nocaseMagicOnly &&
1426
+ pattern.toUpperCase() !== pattern.toLowerCase())) {
1427
+ return this.#norm(lit);
905
1428
  }
906
- else if ((m = pattern.match(starDotExtRE))) {
907
- fastTest = (options.nocase ?
908
- options.dot ?
909
- starDotExtTestNocaseDot
910
- : starDotExtTestNocase
911
- : options.dot ? starDotExtTestDot
912
- : starDotExtTest)(m[1]);
1429
+ if (this.#pending)
1430
+ return PENDING;
1431
+ let m = this.#matchers.get(pattern);
1432
+ if (!m) {
1433
+ m = new Matcher(pattern, { nocase, noext, dot, normalize });
1434
+ this.#matchers.set(pattern, m);
913
1435
  }
914
- else if ((m = pattern.match(qmarksRE))) {
915
- fastTest = (options.nocase ?
916
- options.dot ?
917
- qmarksTestNocaseDot
918
- : qmarksTestNocase
919
- : options.dot ? qmarksTestDot
920
- : qmarksTest)(m);
921
- }
922
- else if ((m = pattern.match(starDotStarRE))) {
923
- fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
924
- }
925
- else if ((m = pattern.match(dotStarRE))) {
926
- fastTest = dotStarTest;
927
- }
928
- const re = AST.fromGlob(pattern, this.options).toMMPattern();
929
- if (fastTest && typeof re === 'object') {
930
- // Avoids overriding in frozen environments
931
- Reflect.defineProperty(re, 'test', { value: fastTest });
932
- }
933
- return re;
1436
+ return m;
934
1437
  }
935
- makeRe() {
936
- if (this.regexp || this.regexp === false)
937
- return this.regexp;
938
- // at this point, this.set is a 2d array of partial
939
- // pattern strings, or "**".
940
- //
941
- // It's better to use .match(). This function shouldn't
942
- // be used, really, but it's pretty convenient sometimes,
943
- // when you just want to work with a regex.
944
- const set = this.set;
945
- if (!set.length) {
946
- this.regexp = false;
947
- return this.regexp;
948
- }
949
- const options = this.options;
950
- const twoStar = options.noglobstar ? star
951
- : options.dot ? twoStarDot
952
- : twoStarNoDot;
953
- const flags = new Set(options.nocase ? ['i'] : []);
954
- // regexpify non-globstar patterns
955
- // if ** is only item, then we just do one twoStar
956
- // if ** is first, and there are more, prepend (\/|twoStar\/)? to next
957
- // if ** is last, append (\/twoStar|) to previous
958
- // if ** is in the middle, append (\/|\/twoStar\/) to previous
959
- // then filter out GLOBSTAR symbols
960
- let re = set
961
- .map(pattern => {
962
- const pp = pattern.map(p => {
963
- if (p instanceof RegExp) {
964
- for (const f of p.flags.split(''))
965
- flags.add(f);
966
- }
967
- return (typeof p === 'string' ? regExpEscape(p)
968
- : p === GLOBSTAR ? GLOBSTAR
969
- : p._src);
970
- });
971
- pp.forEach((p, i) => {
972
- const next = pp[i + 1];
973
- const prev = pp[i - 1];
974
- if (p !== GLOBSTAR || prev === GLOBSTAR) {
975
- return;
976
- }
977
- if (prev === undefined) {
978
- if (next !== undefined && next !== GLOBSTAR) {
979
- pp[i + 1] = '(?:\\/|' + twoStar + '\\/)?' + next;
980
- }
981
- else {
982
- pp[i] = twoStar;
983
- }
984
- }
985
- else if (next === undefined) {
986
- pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + ')?';
987
- }
988
- else if (next !== GLOBSTAR) {
989
- pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + '\\/)' + next;
990
- pp[i + 1] = GLOBSTAR;
991
- }
992
- });
993
- const filtered = pp.filter(p => p !== GLOBSTAR);
994
- // For partial matches, we need to make the pattern match
995
- // any prefix of the full path. We do this by generating
996
- // alternative patterns that match progressively longer prefixes.
997
- if (this.partial && filtered.length >= 1) {
998
- const prefixes = [];
999
- for (let i = 1; i <= filtered.length; i++) {
1000
- prefixes.push(filtered.slice(0, i).join('/'));
1001
- }
1002
- return '(?:' + prefixes.join('|') + ')';
1003
- }
1004
- return filtered.join('/');
1005
- })
1006
- .join('|');
1007
- // need to wrap in parens if we had more than one thing with |,
1008
- // otherwise only the first will be anchored to ^ and the last to $
1009
- const [open, close] = set.length > 1 ? ['(?:', ')'] : ['', ''];
1010
- // must match entire pattern
1011
- // ending in a * or ** will make it less strict.
1012
- re = '^' + open + re + close + '$';
1013
- // In partial mode, '/' should always match as it's a valid prefix for any pattern
1014
- if (this.partial) {
1015
- re = '^(?:\\/|' + open + re.slice(1, -1) + close + ')$';
1016
- }
1017
- // can match anything, as long as it's not this.
1018
- if (this.negate)
1019
- re = '^(?!' + re + ').+$';
1020
- try {
1021
- this.regexp = new RegExp(re, [...flags].join(''));
1022
- /* c8 ignore start */
1023
- }
1024
- catch {
1025
- // should be impossible
1026
- this.regexp = false;
1027
- }
1028
- /* c8 ignore stop */
1029
- return this.regexp;
1030
- }
1031
- slashSplit(p) {
1438
+ #slashSplit(p) {
1032
1439
  // if p starts with // on windows, we preserve that
1033
1440
  // so that UNC paths aren't broken. Otherwise, any number of
1034
1441
  // / characters are coalesced into one, unless
@@ -1045,7 +1452,6 @@ export class Minimatch {
1045
1452
  }
1046
1453
  }
1047
1454
  match(f, partial = this.partial) {
1048
- this.debug('match', f, this.pattern);
1049
1455
  // short-circuit in the case of busted things.
1050
1456
  // comments, etc.
1051
1457
  if (this.comment) {
@@ -1058,19 +1464,36 @@ export class Minimatch {
1058
1464
  return true;
1059
1465
  }
1060
1466
  const options = this.options;
1061
- // windows: need to use /, not \
1062
- if (this.isWindows) {
1063
- f = f.split('\\').join('/');
1467
+ // treat the test path as a set of pathparts. If it was not just
1468
+ // split or checked, check that it can match before splitting it.
1469
+ let split = this.#cachedSplit(f);
1470
+ if (!split) {
1471
+ // the checks look at the path as given, so not if it is
1472
+ // normalized
1473
+ if (!partial &&
1474
+ !this.#form &&
1475
+ (this.#endCheck || this.#literalCheck) &&
1476
+ lastChecked !== f) {
1477
+ lastChecked = f;
1478
+ const can = this.#canMatch(f);
1479
+ if (can === 'no')
1480
+ return options.flipNegate ? false : this.negate;
1481
+ if (can === 'yes')
1482
+ return options.flipNegate ? true : !this.negate;
1483
+ }
1484
+ split = this.#split(f);
1064
1485
  }
1065
- // treat the test path as a set of pathparts.
1066
- const ff = this.slashSplit(f);
1067
- this.debug(this.pattern, 'split', ff);
1486
+ const ff = split.parts;
1487
+ // the parts after level 2 resolves them, kept for the next pattern
1488
+ // that tests the same path
1489
+ const resolved = this.#level2 ?
1490
+ (split.resolved ??= this.#levelTwoFileOptimize(ff))
1491
+ : ff;
1068
1492
  // just ONE of the pattern sets in this.set needs to match
1069
1493
  // in order for it to be valid. If negating, then just one
1070
1494
  // match means that we have failed.
1071
1495
  // Either way, return on the first hit.
1072
1496
  const set = this.set;
1073
- this.debug(this.pattern, 'set', set);
1074
1497
  // Find the basename of the path by looking for the last non-empty segment
1075
1498
  let filename = ff[ff.length - 1];
1076
1499
  if (!filename) {
@@ -1078,12 +1501,16 @@ export class Minimatch {
1078
1501
  filename = ff[i];
1079
1502
  }
1080
1503
  }
1081
- for (const pattern of set) {
1082
- let file = ff;
1083
- if (options.matchBase && pattern.length === 1) {
1084
- file = [filename];
1085
- }
1086
- const hit = this.matchOne(file, pattern, partial);
1504
+ for (let r = 0; r < set.length; r++) {
1505
+ const pattern = set[r];
1506
+ const shape = partial ? undefined : this.#shapes[r];
1507
+ // level 2 does not change a path of one portion
1508
+ const hit = shape === 'base' ?
1509
+ portionMatch(pattern[0], filename)
1510
+ : shape ? this.#matchShape(resolved, pattern, shape)
1511
+ : options.matchBase && pattern.length === 1 ?
1512
+ this.#matchRow([filename], [filename], pattern, partial)
1513
+ : this.#matchRow(ff, resolved, pattern, partial);
1087
1514
  if (hit) {
1088
1515
  if (options.flipNegate) {
1089
1516
  return true;
@@ -1103,11 +1530,9 @@ export class Minimatch {
1103
1530
  }
1104
1531
  }
1105
1532
  /* c8 ignore start */
1106
- export { AST } from './ast.js';
1107
1533
  export { escape } from './escape.js';
1108
1534
  export { unescape } from './unescape.js';
1109
1535
  /* c8 ignore stop */
1110
- minimatch.AST = AST;
1111
1536
  minimatch.Minimatch = Minimatch;
1112
1537
  minimatch.escape = escape;
1113
1538
  minimatch.unescape = unescape;