@shopware/api-gen 1.5.1 → 1.5.2

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 (3) hide show
  1. package/README.md +9 -15
  2. package/dist/cli.mjs +1404 -2574
  3. package/package.json +4 -4
package/dist/cli.mjs CHANGED
@@ -32,7 +32,7 @@ import __cjs_mod__ from 'module';
32
32
  const __filename = __cjs_url__.fileURLToPath(import.meta.url);
33
33
  const __dirname = __cjs_path__.dirname(__filename);
34
34
  const require = __cjs_mod__.createRequire(import.meta.url);
35
- const version$1 = "1.5.1";
35
+ const version$1 = "1.5.2";
36
36
  const packageJson = {
37
37
  version: version$1};
38
38
 
@@ -40,2607 +40,1439 @@ var lib = {};
40
40
 
41
41
  var utils$3 = {};
42
42
 
43
- var commonjs$2 = {};
43
+ var path;
44
+ var hasRequiredPath;
45
+
46
+ function requirePath () {
47
+ if (hasRequiredPath) return path;
48
+ hasRequiredPath = 1;
49
+ const isWindows = typeof process === 'object' &&
50
+ process &&
51
+ process.platform === 'win32';
52
+ path = isWindows ? { sep: '\\' } : { sep: '/' };
53
+ return path;
54
+ }
55
+
56
+ var balancedMatch;
57
+ var hasRequiredBalancedMatch;
58
+
59
+ function requireBalancedMatch () {
60
+ if (hasRequiredBalancedMatch) return balancedMatch;
61
+ hasRequiredBalancedMatch = 1;
62
+ balancedMatch = balanced;
63
+ function balanced(a, b, str) {
64
+ if (a instanceof RegExp) a = maybeMatch(a, str);
65
+ if (b instanceof RegExp) b = maybeMatch(b, str);
66
+
67
+ var r = range(a, b, str);
68
+
69
+ return r && {
70
+ start: r[0],
71
+ end: r[1],
72
+ pre: str.slice(0, r[0]),
73
+ body: str.slice(r[0] + a.length, r[1]),
74
+ post: str.slice(r[1] + b.length)
75
+ };
76
+ }
44
77
 
45
- var commonjs$1 = {};
78
+ function maybeMatch(reg, str) {
79
+ var m = str.match(reg);
80
+ return m ? m[0] : null;
81
+ }
46
82
 
47
- var commonjs = {};
83
+ balanced.range = range;
84
+ function range(a, b, str) {
85
+ var begs, beg, left, right, result;
86
+ var ai = str.indexOf(a);
87
+ var bi = str.indexOf(b, ai + 1);
88
+ var i = ai;
48
89
 
49
- var hasRequiredCommonjs$2;
90
+ if (ai >= 0 && bi > 0) {
91
+ if(a===b) {
92
+ return [ai, bi];
93
+ }
94
+ begs = [];
95
+ left = str.length;
50
96
 
51
- function requireCommonjs$2 () {
52
- if (hasRequiredCommonjs$2) return commonjs;
53
- hasRequiredCommonjs$2 = 1;
54
- (function (exports) {
55
- Object.defineProperty(exports, "__esModule", { value: true });
56
- exports.range = exports.balanced = void 0;
57
- const balanced = (a, b, str) => {
58
- const ma = a instanceof RegExp ? maybeMatch(a, str) : a;
59
- const mb = b instanceof RegExp ? maybeMatch(b, str) : b;
60
- const r = ma !== null && mb != null && (0, exports.range)(ma, mb, str);
61
- return (r && {
62
- start: r[0],
63
- end: r[1],
64
- pre: str.slice(0, r[0]),
65
- body: str.slice(r[0] + ma.length, r[1]),
66
- post: str.slice(r[1] + mb.length),
67
- });
68
- };
69
- exports.balanced = balanced;
70
- const maybeMatch = (reg, str) => {
71
- const m = str.match(reg);
72
- return m ? m[0] : null;
73
- };
74
- const range = (a, b, str) => {
75
- let begs, beg, left, right = undefined, result;
76
- let ai = str.indexOf(a);
77
- let bi = str.indexOf(b, ai + 1);
78
- let i = ai;
79
- if (ai >= 0 && bi > 0) {
80
- if (a === b) {
81
- return [ai, bi];
82
- }
83
- begs = [];
84
- left = str.length;
85
- while (i >= 0 && !result) {
86
- if (i === ai) {
87
- begs.push(i);
88
- ai = str.indexOf(a, i + 1);
89
- }
90
- else if (begs.length === 1) {
91
- const r = begs.pop();
92
- if (r !== undefined)
93
- result = [r, bi];
94
- }
95
- else {
96
- beg = begs.pop();
97
- if (beg !== undefined && beg < left) {
98
- left = beg;
99
- right = bi;
100
- }
101
- bi = str.indexOf(b, i + 1);
102
- }
103
- i = ai < bi && ai >= 0 ? ai : bi;
104
- }
105
- if (begs.length && right !== undefined) {
106
- result = [left, right];
107
- }
108
- }
109
- return result;
110
- };
111
- exports.range = range;
112
-
113
- } (commonjs));
114
- return commonjs;
115
- }
97
+ while (i >= 0 && !result) {
98
+ if (i == ai) {
99
+ begs.push(i);
100
+ ai = str.indexOf(a, i + 1);
101
+ } else if (begs.length == 1) {
102
+ result = [ begs.pop(), bi ];
103
+ } else {
104
+ beg = begs.pop();
105
+ if (beg < left) {
106
+ left = beg;
107
+ right = bi;
108
+ }
116
109
 
117
- var hasRequiredCommonjs$1;
110
+ bi = str.indexOf(b, i + 1);
111
+ }
118
112
 
119
- function requireCommonjs$1 () {
120
- if (hasRequiredCommonjs$1) return commonjs$1;
121
- hasRequiredCommonjs$1 = 1;
122
- (function (exports) {
123
- Object.defineProperty(exports, "__esModule", { value: true });
124
- exports.EXPANSION_MAX_LENGTH = exports.EXPANSION_MAX = void 0;
125
- exports.expand = expand;
126
- const balanced_match_1 = requireCommonjs$2();
127
- const escSlash = '\0SLASH' + Math.random() + '\0';
128
- const escOpen = '\0OPEN' + Math.random() + '\0';
129
- const escClose = '\0CLOSE' + Math.random() + '\0';
130
- const escComma = '\0COMMA' + Math.random() + '\0';
131
- const escPeriod = '\0PERIOD' + Math.random() + '\0';
132
- const escSlashPattern = new RegExp(escSlash, 'g');
133
- const escOpenPattern = new RegExp(escOpen, 'g');
134
- const escClosePattern = new RegExp(escClose, 'g');
135
- const escCommaPattern = new RegExp(escComma, 'g');
136
- const escPeriodPattern = new RegExp(escPeriod, 'g');
137
- const slashPattern = /\\\\/g;
138
- const openPattern = /\\{/g;
139
- const closePattern = /\\}/g;
140
- const commaPattern = /\\,/g;
141
- const periodPattern = /\\\./g;
142
- exports.EXPANSION_MAX = 100_000;
143
- // `EXPANSION_MAX` caps the *number* of expansions, but not their length. An
144
- // input like `'{a,b}'.repeat(1500)` stays under that count - its output is
145
- // truncated to 100k results - while making every result ~1500 characters
146
- // long. The result set, and the intermediate arrays built while combining
147
- // brace sets, then grow large enough to exhaust memory and crash the process
148
- // (CVE-2026-14257). `EXPANSION_MAX_LENGTH` bounds the total number of
149
- // characters the accumulator may hold at any point, so memory stays flat no
150
- // matter how many brace groups are chained. The limit sits well above any
151
- // realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M
152
- // characters) so legitimate input is unaffected.
153
- exports.EXPANSION_MAX_LENGTH = 4_000_000;
154
- function numeric(str) {
155
- return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
156
- }
157
- function escapeBraces(str) {
158
- return str
159
- .replace(slashPattern, escSlash)
160
- .replace(openPattern, escOpen)
161
- .replace(closePattern, escClose)
162
- .replace(commaPattern, escComma)
163
- .replace(periodPattern, escPeriod);
164
- }
165
- function unescapeBraces(str) {
166
- return str
167
- .replace(escSlashPattern, '\\')
168
- .replace(escOpenPattern, '{')
169
- .replace(escClosePattern, '}')
170
- .replace(escCommaPattern, ',')
171
- .replace(escPeriodPattern, '.');
172
- }
173
- /**
174
- * Basically just str.split(","), but handling cases
175
- * where we have nested braced sections, which should be
176
- * treated as individual members, like {a,{b,c},d}
177
- */
178
- function parseCommaParts(str) {
179
- if (!str) {
180
- return [''];
181
- }
182
- const parts = [];
183
- const m = (0, balanced_match_1.balanced)('{', '}', str);
184
- if (!m) {
185
- return str.split(',');
186
- }
187
- const { pre, body, post } = m;
188
- const p = pre.split(',');
189
- p[p.length - 1] += '{' + body + '}';
190
- const postParts = parseCommaParts(post);
191
- if (post.length) {
192
- p[p.length - 1] += postParts.shift();
193
- p.push.apply(p, postParts);
194
- }
195
- parts.push.apply(parts, p);
196
- return parts;
197
- }
198
- function expand(str, options = {}) {
199
- if (!str) {
200
- return [];
201
- }
202
- const { max = exports.EXPANSION_MAX, maxLength = exports.EXPANSION_MAX_LENGTH } = options;
203
- // I don't know why Bash 4.3 does this, but it does.
204
- // Anything starting with {} will have the first two bytes preserved
205
- // but *only* at the top level, so {},a}b will not expand to anything,
206
- // but a{},b}c will be expanded to [a}c,abc].
207
- // One could argue that this is a bug in Bash, but since the goal of
208
- // this module is to match Bash's rules, we escape a leading {}
209
- if (str.slice(0, 2) === '{}') {
210
- str = '\\{\\}' + str.slice(2);
211
- }
212
- return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
213
- }
214
- function embrace(str) {
215
- return '{' + str + '}';
216
- }
217
- function isPadded(el) {
218
- return /^-?0\d/.test(el);
219
- }
220
- function lte(i, y) {
221
- return i <= y;
222
- }
223
- function gte(i, y) {
224
- return i >= y;
225
- }
226
- // Build `{ acc[a] + pre + values[v] }` for every combination, capping the
227
- // number of results at `max` and the total number of characters at `maxLength`.
228
- // This is the one place output grows, so bounding it here keeps the single
229
- // accumulator - and therefore memory - flat regardless of how many brace groups
230
- // are combined (CVE-2026-14257).
231
- function combine(acc, pre, values, max, maxLength, dropEmpties) {
232
- const out = [];
233
- let length = 0;
234
- for (let a = 0; a < acc.length; a++) {
235
- for (let v = 0; v < values.length; v++) {
236
- if (out.length >= max)
237
- return out;
238
- const expansion = acc[a] + pre + values[v];
239
- // Bash drops empty results at the top level. Skip them before they count
240
- // against `max`, so `max` bounds the number of *kept* results.
241
- if (dropEmpties && !expansion)
242
- continue;
243
- if (length + expansion.length > maxLength)
244
- return out;
245
- out.push(expansion);
246
- length += expansion.length;
247
- }
248
- }
249
- return out;
250
- }
251
- // The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)
252
- // sequence body.
253
- function expandSequence(body, isAlphaSequence, max) {
254
- const n = body.split(/\.\./);
255
- const N = [];
256
- // A sequence body always splits into two or three parts, but the compiler
257
- // can't know that.
258
- /* c8 ignore start */
259
- if (n[0] === undefined || n[1] === undefined) {
260
- return N;
261
- }
262
- /* c8 ignore stop */
263
- const x = numeric(n[0]);
264
- const y = numeric(n[1]);
265
- const width = Math.max(n[0].length, n[1].length);
266
- let incr = n.length === 3 && n[2] !== undefined ?
267
- Math.max(Math.abs(numeric(n[2])), 1)
268
- : 1;
269
- let test = lte;
270
- const reverse = y < x;
271
- if (reverse) {
272
- incr *= -1;
273
- test = gte;
274
- }
275
- const pad = n.some(isPadded);
276
- for (let i = x; test(i, y) && N.length < max; i += incr) {
277
- let c;
278
- if (isAlphaSequence) {
279
- c = String.fromCharCode(i);
280
- if (c === '\\') {
281
- c = '';
282
- }
283
- }
284
- else {
285
- c = String(i);
286
- if (pad) {
287
- const need = width - c.length;
288
- if (need > 0) {
289
- const z = new Array(need + 1).join('0');
290
- if (i < 0) {
291
- c = '-' + z + c.slice(1);
292
- }
293
- else {
294
- c = z + c;
295
- }
296
- }
297
- }
298
- }
299
- N.push(c);
300
- }
301
- return N;
302
- }
303
- function expand_(str, max, maxLength, isTop) {
304
- // Consume the string's top-level brace groups left to right, threading a
305
- // running set of combined prefixes (`acc`). Expanding the tail iteratively -
306
- // rather than recursing on `m.post` once per group - keeps the native stack
307
- // depth constant, so deeply chained input (`'{a,b}'.repeat(3000)`) can no
308
- // longer overflow the stack, and leaves a single accumulator whose size
309
- // `maxLength` bounds directly (CVE-2026-14257).
310
- let acc = [''];
311
- // Bash drops empty results, but only when the *first* top-level group is a
312
- // comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
313
- // is on the final strings, so it is applied to whichever `combine` produces
314
- // them (the one with no brace set left in the tail).
315
- let dropEmpties = false;
316
- let firstGroup = true;
317
- for (;;) {
318
- const m = (0, balanced_match_1.balanced)('{', '}', str);
319
- // No brace set left: the rest of the string is literal.
320
- if (!m) {
321
- return combine(acc, str, [''], max, maxLength, dropEmpties);
322
- }
323
- // no need to expand pre, since it is guaranteed to be free of brace-sets
324
- const pre = m.pre;
325
- if (/\$$/.test(pre)) {
326
- acc = combine(acc, pre + '{' + m.body + '}', [''], max, maxLength, dropEmpties && !m.post.length);
327
- firstGroup = false;
328
- if (!m.post.length)
329
- break;
330
- str = m.post;
331
- continue;
332
- }
333
- const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
334
- const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
335
- const isSequence = isNumericSequence || isAlphaSequence;
336
- const isOptions = m.body.indexOf(',') >= 0;
337
- if (!isSequence && !isOptions) {
338
- // {a},b}
339
- if (m.post.match(/,(?!,).*\}/)) {
340
- str = m.pre + '{' + m.body + escClose + m.post;
341
- isTop = true;
342
- continue;
343
- }
344
- // Nothing here expands, so the whole remaining string is literal.
345
- return combine(acc, pre + '{' + m.body + '}' + m.post, [''], max, maxLength, dropEmpties);
346
- }
347
- if (firstGroup) {
348
- dropEmpties = isTop && !isSequence;
349
- firstGroup = false;
350
- }
351
- let values;
352
- if (isSequence) {
353
- values = expandSequence(m.body, isAlphaSequence, max);
354
- }
355
- else {
356
- let n = parseCommaParts(m.body);
357
- if (n.length === 1 && n[0] !== undefined) {
358
- // x{{a,b}}y ==> x{a}y x{b}y
359
- n = expand_(n[0], max, maxLength, false).map(embrace);
360
- //XXX is this necessary? Can't seem to hit it in tests.
361
- /* c8 ignore start */
362
- if (n.length === 1) {
363
- acc = combine(acc, pre + n[0], [''], max, maxLength, dropEmpties && !m.post.length);
364
- if (!m.post.length)
365
- break;
366
- str = m.post;
367
- continue;
368
- }
369
- /* c8 ignore stop */
370
- }
371
- values = [];
372
- for (let j = 0; j < n.length; j++) {
373
- values.push.apply(values, expand_(n[j], max, maxLength, false));
374
- }
375
- }
376
- acc = combine(acc, pre, values, max, maxLength, dropEmpties && !m.post.length);
377
- if (!m.post.length)
378
- break;
379
- str = m.post;
380
- }
381
- return acc;
382
- }
383
-
384
- } (commonjs$1));
385
- return commonjs$1;
113
+ i = ai < bi && ai >= 0 ? ai : bi;
114
+ }
115
+
116
+ if (begs.length) {
117
+ result = [ left, right ];
118
+ }
119
+ }
120
+
121
+ return result;
122
+ }
123
+ return balancedMatch;
386
124
  }
387
125
 
388
- var assertValidPattern = {};
126
+ var braceExpansion;
127
+ var hasRequiredBraceExpansion;
389
128
 
390
- var hasRequiredAssertValidPattern;
129
+ function requireBraceExpansion () {
130
+ if (hasRequiredBraceExpansion) return braceExpansion;
131
+ hasRequiredBraceExpansion = 1;
132
+ var balanced = requireBalancedMatch();
391
133
 
392
- function requireAssertValidPattern () {
393
- if (hasRequiredAssertValidPattern) return assertValidPattern;
394
- hasRequiredAssertValidPattern = 1;
395
- Object.defineProperty(assertValidPattern, "__esModule", { value: true });
396
- assertValidPattern.assertValidPattern = void 0;
397
- const MAX_PATTERN_LENGTH = 1024 * 64;
398
- const assertValidPattern$1 = (pattern) => {
399
- if (typeof pattern !== 'string') {
400
- throw new TypeError('invalid pattern');
401
- }
402
- if (pattern.length > MAX_PATTERN_LENGTH) {
403
- throw new TypeError('pattern is too long');
134
+ braceExpansion = expandTop;
135
+
136
+ var escSlash = '\0SLASH'+Math.random()+'\0';
137
+ var escOpen = '\0OPEN'+Math.random()+'\0';
138
+ var escClose = '\0CLOSE'+Math.random()+'\0';
139
+ var escComma = '\0COMMA'+Math.random()+'\0';
140
+ var escPeriod = '\0PERIOD'+Math.random()+'\0';
141
+
142
+ var EXPANSION_MAX = 100000;
143
+
144
+ // `EXPANSION_MAX` caps the *number* of expansions, but not their length. An
145
+ // input like `'{a,b}'.repeat(1500)` stays under that count - its output is
146
+ // truncated to 100k results - while making every result ~1500 characters
147
+ // long. The result set, and the intermediate arrays built while combining
148
+ // brace sets, then grow large enough to exhaust memory and crash the process
149
+ // (CVE-2026-14257). `EXPANSION_MAX_LENGTH` bounds the total number of
150
+ // characters the accumulator may hold at any point, so memory stays flat no
151
+ // matter how many brace groups are chained. The limit sits well above any
152
+ // realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M
153
+ // characters) so legitimate input is unaffected.
154
+ var EXPANSION_MAX_LENGTH = 4000000;
155
+
156
+ function numeric(str) {
157
+ return parseInt(str, 10) == str
158
+ ? parseInt(str, 10)
159
+ : str.charCodeAt(0);
160
+ }
161
+
162
+ function escapeBraces(str) {
163
+ return str.split('\\\\').join(escSlash)
164
+ .split('\\{').join(escOpen)
165
+ .split('\\}').join(escClose)
166
+ .split('\\,').join(escComma)
167
+ .split('\\.').join(escPeriod);
168
+ }
169
+
170
+ function unescapeBraces(str) {
171
+ return str.split(escSlash).join('\\')
172
+ .split(escOpen).join('{')
173
+ .split(escClose).join('}')
174
+ .split(escComma).join(',')
175
+ .split(escPeriod).join('.');
176
+ }
177
+
178
+
179
+ // Basically just str.split(","), but handling cases
180
+ // where we have nested braced sections, which should be
181
+ // treated as individual members, like {a,{b,c},d}
182
+ function parseCommaParts(str) {
183
+ if (!str)
184
+ return [''];
185
+
186
+ var parts = [];
187
+ var m = balanced('{', '}', str);
188
+
189
+ if (!m)
190
+ return str.split(',');
191
+
192
+ var pre = m.pre;
193
+ var body = m.body;
194
+ var post = m.post;
195
+ var p = pre.split(',');
196
+
197
+ p[p.length-1] += '{' + body + '}';
198
+ var postParts = parseCommaParts(post);
199
+ if (post.length) {
200
+ p[p.length-1] += postParts.shift();
201
+ p.push.apply(p, postParts);
202
+ }
203
+
204
+ parts.push.apply(parts, p);
205
+
206
+ return parts;
207
+ }
208
+
209
+ function expandTop(str, options) {
210
+ if (!str)
211
+ return [];
212
+
213
+ options = options || {};
214
+ var max = options.max == null ? EXPANSION_MAX : options.max;
215
+ var maxLength = options.maxLength == null ? EXPANSION_MAX_LENGTH : options.maxLength;
216
+
217
+ // I don't know why Bash 4.3 does this, but it does.
218
+ // Anything starting with {} will have the first two bytes preserved
219
+ // but *only* at the top level, so {},a}b will not expand to anything,
220
+ // but a{},b}c will be expanded to [a}c,abc].
221
+ // One could argue that this is a bug in Bash, but since the goal of
222
+ // this module is to match Bash's rules, we escape a leading {}
223
+ if (str.substr(0, 2) === '{}') {
224
+ str = '\\{\\}' + str.substr(2);
225
+ }
226
+
227
+ return expand(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
228
+ }
229
+
230
+ function embrace(str) {
231
+ return '{' + str + '}';
232
+ }
233
+ function isPadded(el) {
234
+ return /^-?0\d/.test(el);
235
+ }
236
+
237
+ function lte(i, y) {
238
+ return i <= y;
239
+ }
240
+ function gte(i, y) {
241
+ return i >= y;
242
+ }
243
+
244
+ // Build `{ acc[a] + pre + values[v] }` for every combination, capping the
245
+ // number of results at `max` and the total number of characters at `maxLength`.
246
+ // This is the one place output grows, so bounding it here keeps the single
247
+ // accumulator - and therefore memory - flat regardless of how many brace groups
248
+ // are combined (CVE-2026-14257).
249
+ function combine(
250
+ acc,
251
+ pre,
252
+ values,
253
+ max,
254
+ maxLength,
255
+ dropEmpties
256
+ ) {
257
+ var out = [];
258
+ var length = 0;
259
+ for (var a = 0; a < acc.length; a++) {
260
+ for (var v = 0; v < values.length; v++) {
261
+ if (out.length >= max) return out
262
+ var expansion = acc[a] + pre + values[v];
263
+ // Bash drops empty results at the top level. Skip them before they count
264
+ // against `max`, so `max` bounds the number of *kept* results.
265
+ if (dropEmpties && !expansion) continue
266
+ if (length + expansion.length > maxLength) return out
267
+ out.push(expansion);
268
+ length += expansion.length;
404
269
  }
405
- };
406
- assertValidPattern.assertValidPattern = assertValidPattern$1;
407
-
408
- return assertValidPattern;
409
- }
410
-
411
- var ast = {};
412
-
413
- var braceExpressions = {};
414
-
415
- var hasRequiredBraceExpressions;
416
-
417
- function requireBraceExpressions () {
418
- if (hasRequiredBraceExpressions) return braceExpressions;
419
- hasRequiredBraceExpressions = 1;
420
- // translate the various posix character classes into unicode properties
421
- // this works across all unicode locales
422
- Object.defineProperty(braceExpressions, "__esModule", { value: true });
423
- braceExpressions.parseClass = void 0;
424
- // { <posix class>: [<translation>, /u flag required, negated]
425
- const posixClasses = {
426
- '[:alnum:]': ['\\p{L}\\p{Nl}\\p{Nd}', true],
427
- '[:alpha:]': ['\\p{L}\\p{Nl}', true],
428
- '[:ascii:]': ['\\x' + '00-\\x' + '7f', false],
429
- '[:blank:]': ['\\p{Zs}\\t', true],
430
- '[:cntrl:]': ['\\p{Cc}', true],
431
- '[:digit:]': ['\\p{Nd}', true],
432
- '[:graph:]': ['\\p{Z}\\p{C}', true, true],
433
- '[:lower:]': ['\\p{Ll}', true],
434
- '[:print:]': ['\\p{C}', true],
435
- '[:punct:]': ['\\p{P}', true],
436
- '[:space:]': ['\\p{Z}\\t\\r\\n\\v\\f', true],
437
- '[:upper:]': ['\\p{Lu}', true],
438
- '[:word:]': ['\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}', true],
439
- '[:xdigit:]': ['A-Fa-f0-9', false],
440
- };
441
- // only need to escape a few things inside of brace expressions
442
- // escapes: [ \ ] -
443
- const braceEscape = (s) => s.replace(/[[\]\\-]/g, '\\$&');
444
- // escape all regexp magic characters
445
- const regexpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
446
- // everything has already been escaped, we just have to join
447
- const rangesToString = (ranges) => ranges.join('');
448
- // takes a glob string at a posix brace expression, and returns
449
- // an equivalent regular expression source, and boolean indicating
450
- // whether the /u flag needs to be applied, and the number of chars
451
- // consumed to parse the character class.
452
- // This also removes out of order ranges, and returns ($.) if the
453
- // entire class just no good.
454
- const parseClass = (glob, position) => {
455
- const pos = position;
456
- /* c8 ignore start */
457
- if (glob.charAt(pos) !== '[') {
458
- throw new Error('not in a brace expression');
459
- }
460
- /* c8 ignore stop */
461
- const ranges = [];
462
- const negs = [];
463
- let i = pos + 1;
464
- let sawStart = false;
465
- let uflag = false;
466
- let escaping = false;
467
- let negate = false;
468
- let endPos = pos;
469
- let rangeStart = '';
470
- WHILE: while (i < glob.length) {
471
- const c = glob.charAt(i);
472
- if ((c === '!' || c === '^') && i === pos + 1) {
473
- negate = true;
474
- i++;
475
- continue;
476
- }
477
- if (c === ']' && sawStart && !escaping) {
478
- endPos = i + 1;
479
- break;
480
- }
481
- sawStart = true;
482
- if (c === '\\') {
483
- if (!escaping) {
484
- escaping = true;
485
- i++;
486
- continue;
487
- }
488
- // escaped \ char, fall through and treat like normal char
489
- }
490
- if (c === '[' && !escaping) {
491
- // either a posix class, a collation equivalent, or just a [
492
- for (const [cls, [unip, u, neg]] of Object.entries(posixClasses)) {
493
- if (glob.startsWith(cls, i)) {
494
- // invalid, [a-[] is fine, but not [a-[:alpha]]
495
- if (rangeStart) {
496
- return ['$.', false, glob.length - pos, true];
497
- }
498
- i += cls.length;
499
- if (neg)
500
- negs.push(unip);
501
- else
502
- ranges.push(unip);
503
- uflag = uflag || u;
504
- continue WHILE;
505
- }
506
- }
270
+ }
271
+ return out
272
+ }
273
+
274
+ // The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)
275
+ // sequence body.
276
+ function expandSequence(
277
+ body,
278
+ isAlphaSequence,
279
+ max,
280
+ maxLength
281
+ ) {
282
+ var n = body.split(/\.\./);
283
+ var N = [];
284
+ // A sequence body always splits into two or three parts, but the compiler
285
+ // can't know that.
286
+ /* c8 ignore start */
287
+ if (n[0] === undefined || n[1] === undefined) {
288
+ return N
289
+ }
290
+ /* c8 ignore stop */
291
+ var x = numeric(n[0]);
292
+ var y = numeric(n[1]);
293
+ var width = Math.max(n[0].length, n[1].length);
294
+ var incr =
295
+ n.length === 3 && n[2] !== undefined ?
296
+ Math.max(Math.abs(numeric(n[2])), 1)
297
+ : 1;
298
+ var test = lte;
299
+ var reverse = y < x;
300
+ if (reverse) {
301
+ incr *= -1;
302
+ test = gte;
303
+ }
304
+ var pad = n.some(isPadded);
305
+
306
+ var length = 0;
307
+ for (var i = x; test(i, y) && N.length < max; i += incr) {
308
+ var c;
309
+ if (isAlphaSequence) {
310
+ c = String.fromCharCode(i);
311
+ if (c === '\\') {
312
+ c = '';
313
+ }
314
+ } else {
315
+ c = String(i);
316
+ if (pad) {
317
+ var need = width - c.length;
318
+ if (need > 0) {
319
+ var z = new Array(need + 1).join('0');
320
+ if (i < 0) {
321
+ c = '-' + z + c.slice(1);
322
+ } else {
323
+ c = z + c;
324
+ }
507
325
  }
508
- // now it's just a normal character, effectively
509
- escaping = false;
510
- if (rangeStart) {
511
- // throw this range away if it's not valid, but others
512
- // can still match.
513
- if (c > rangeStart) {
514
- ranges.push(braceEscape(rangeStart) + '-' + braceEscape(c));
515
- }
516
- else if (c === rangeStart) {
517
- ranges.push(braceEscape(c));
518
- }
519
- rangeStart = '';
520
- i++;
521
- continue;
326
+ }
327
+ }
328
+ if (length + c.length > maxLength) break
329
+ N.push(c);
330
+ length += c.length;
331
+ }
332
+ return N
333
+ }
334
+
335
+ function expand(
336
+ str,
337
+ max,
338
+ maxLength,
339
+ isTop
340
+ ) {
341
+ // Consume the string's top-level brace groups left to right, threading a
342
+ // running set of combined prefixes (`acc`). Expanding the tail iteratively -
343
+ // rather than recursing on `m.post` once per group - keeps the native stack
344
+ // depth constant, so deeply chained input (`'{a,b}'.repeat(3000)`) can no
345
+ // longer overflow the stack, and leaves a single accumulator whose size
346
+ // `maxLength` bounds directly (CVE-2026-14257).
347
+ var acc = [''];
348
+
349
+ // Bash drops empty results, but only when the *first* top-level group is a
350
+ // comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
351
+ // is on the final strings, so it is applied to whichever `combine` produces
352
+ // them (the one with no brace set left in the tail).
353
+ var dropEmpties = false;
354
+ var firstGroup = true;
355
+
356
+ for (;;) {
357
+ const m = balanced('{', '}', str);
358
+
359
+ // No brace set left: the rest of the string is literal.
360
+ if (!m) {
361
+ return combine(acc, str, [''], max, maxLength, dropEmpties)
362
+ }
363
+
364
+ // no need to expand pre, since it is guaranteed to be free of brace-sets
365
+ const pre = m.pre;
366
+
367
+ if (/\$$/.test(pre)) {
368
+ acc = combine(
369
+ acc,
370
+ pre + '{' + m.body + '}',
371
+ [''],
372
+ max,
373
+ maxLength,
374
+ dropEmpties && !m.post.length
375
+ );
376
+ firstGroup = false;
377
+ if (!m.post.length) break
378
+ str = m.post;
379
+ continue
380
+ }
381
+
382
+ var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
383
+ var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
384
+ var isSequence = isNumericSequence || isAlphaSequence;
385
+ var isOptions = m.body.indexOf(',') >= 0;
386
+ if (!isSequence && !isOptions) {
387
+ // {a},b}
388
+ if (m.post.match(/,(?!,).*\}/)) {
389
+ str = m.pre + '{' + m.body + escClose + m.post;
390
+ isTop = true;
391
+ continue;
392
+ }
393
+ // Nothing here expands, so the whole remaining string is literal.
394
+ return combine(
395
+ acc,
396
+ pre + '{' + m.body + '}' + m.post,
397
+ [''],
398
+ max,
399
+ maxLength,
400
+ dropEmpties
401
+ )
402
+ }
403
+
404
+ if (firstGroup) {
405
+ dropEmpties = isTop && !isSequence;
406
+ firstGroup = false;
407
+ }
408
+
409
+ var values;
410
+ if (isSequence) {
411
+ values = expandSequence(m.body, isAlphaSequence, max, maxLength);
412
+ } else {
413
+ var n = parseCommaParts(m.body);
414
+ if (n.length === 1 && n[0] !== undefined) {
415
+ // x{{a,b}}y ==> x{a}y x{b}y
416
+ n = expand(n[0], max, maxLength, false).map(embrace);
417
+ //XXX is this necessary? Can't seem to hit it in tests.
418
+ /* c8 ignore start */
419
+ if (n.length === 1) {
420
+ acc = combine(
421
+ acc,
422
+ pre + n[0],
423
+ [''],
424
+ max,
425
+ maxLength,
426
+ dropEmpties && !m.post.length
427
+ );
428
+ if (!m.post.length) break
429
+ str = m.post;
430
+ continue
522
431
  }
523
- // now might be the start of a range.
524
- // can be either c-d or c-] or c<more...>] or c] at this point
525
- if (glob.startsWith('-]', i + 1)) {
526
- ranges.push(braceEscape(c + '-'));
527
- i += 2;
528
- continue;
432
+ /* c8 ignore stop */
433
+ }
434
+
435
+ // Values that `combine` is going to drop as empty produce no result, so
436
+ // they must not count against `max` - otherwise `{a,,b}` with `max: 2`
437
+ // would stop at `['a', '']` and yield one result instead of two. Skipping
438
+ // them outright keeps `values` bounded while leaving `max` a bound on
439
+ // *kept* results.
440
+ var dropsEmpties = dropEmpties && !m.post.length && !pre;
441
+ for (var d = 0; dropsEmpties && d < acc.length; d++) {
442
+ if (acc[d]) {
443
+ dropsEmpties = false;
529
444
  }
530
- if (glob.startsWith('-', i + 1)) {
531
- rangeStart = c;
532
- i += 2;
533
- continue;
445
+ }
446
+
447
+ values = [];
448
+ var valuesLength = 0;
449
+ outer: for (var j = 0; j < n.length; j++) {
450
+ var expanded = expand(n[j], max, maxLength, false);
451
+ for (var k = 0; k < expanded.length; k++) {
452
+ var v = expanded[k];
453
+ if (dropsEmpties && !v) continue
454
+ if (values.length >= max || valuesLength + v.length > maxLength) {
455
+ break outer
456
+ }
457
+ values.push(v);
458
+ valuesLength += v.length;
534
459
  }
535
- // not the start of a range, just a single character
536
- ranges.push(braceEscape(c));
537
- i++;
538
- }
539
- if (endPos < i) {
540
- // didn't see the end of the class, not a valid class,
541
- // but might still be valid as a literal match.
542
- return ['', false, 0, false];
543
- }
544
- // if we got no ranges and no negates, then we have a range that
545
- // cannot possibly match anything, and that poisons the whole glob
546
- if (!ranges.length && !negs.length) {
547
- return ['$.', false, glob.length - pos, true];
548
- }
549
- // if we got one positive range, and it's a single character, then that's
550
- // not actually a magic pattern, it's just that one literal character.
551
- // we should not treat that as "magic", we should just return the literal
552
- // character. [_] is a perfectly valid way to escape glob magic chars.
553
- if (negs.length === 0 &&
554
- ranges.length === 1 &&
555
- /^\\?.$/.test(ranges[0]) &&
556
- !negate) {
557
- const r = ranges[0].length === 2 ? ranges[0].slice(-1) : ranges[0];
558
- return [regexpEscape(r), false, endPos - pos, false];
559
- }
560
- const sranges = '[' + (negate ? '^' : '') + rangesToString(ranges) + ']';
561
- const snegs = '[' + (negate ? '' : '^') + rangesToString(negs) + ']';
562
- const comb = ranges.length && negs.length ? '(' + sranges + '|' + snegs + ')'
563
- : ranges.length ? sranges
564
- : snegs;
565
- return [comb, uflag, endPos - pos, true];
566
- };
567
- braceExpressions.parseClass = parseClass;
568
-
569
- return braceExpressions;
460
+ }
461
+ }
462
+
463
+ acc = combine(acc, pre, values, max, maxLength, dropEmpties && !m.post.length);
464
+ if (!m.post.length) break
465
+ str = m.post;
466
+ }
467
+
468
+ return acc
469
+ }
470
+ return braceExpansion;
570
471
  }
571
472
 
572
- var _unescape = {};
473
+ var minimatch_1;
474
+ var hasRequiredMinimatch;
573
475
 
574
- var hasRequired_unescape;
476
+ function requireMinimatch () {
477
+ if (hasRequiredMinimatch) return minimatch_1;
478
+ hasRequiredMinimatch = 1;
479
+ const minimatch = minimatch_1 = (p, pattern, options = {}) => {
480
+ assertValidPattern(pattern);
481
+
482
+ // shortcut: comments match nothing.
483
+ if (!options.nocomment && pattern.charAt(0) === '#') {
484
+ return false
485
+ }
486
+
487
+ return new Minimatch(pattern, options).match(p)
488
+ };
489
+
490
+ minimatch_1 = minimatch;
491
+
492
+ const path = requirePath();
493
+ minimatch.sep = path.sep;
494
+
495
+ const GLOBSTAR = Symbol('globstar **');
496
+ minimatch.GLOBSTAR = GLOBSTAR;
497
+ const expand = requireBraceExpansion();
498
+
499
+ const plTypes = {
500
+ '!': { open: '(?:(?!(?:', close: '))[^/]*?)'},
501
+ '?': { open: '(?:', close: ')?' },
502
+ '+': { open: '(?:', close: ')+' },
503
+ '*': { open: '(?:', close: ')*' },
504
+ '@': { open: '(?:', close: ')' }
505
+ };
575
506
 
576
- function require_unescape () {
577
- if (hasRequired_unescape) return _unescape;
578
- hasRequired_unescape = 1;
579
- Object.defineProperty(_unescape, "__esModule", { value: true });
580
- _unescape.unescape = void 0;
581
- /**
582
- * Un-escape a string that has been escaped with {@link escape}.
583
- *
584
- * If the {@link MinimatchOptions.windowsPathsNoEscape} option is used, then
585
- * square-bracket escapes are removed, but not backslash escapes.
586
- *
587
- * For example, it will turn the string `'[*]'` into `*`, but it will not
588
- * turn `'\\*'` into `'*'`, because `\` is a path separator in
589
- * `windowsPathsNoEscape` mode.
590
- *
591
- * When `windowsPathsNoEscape` is not set, then both square-bracket escapes and
592
- * backslash escapes are removed.
593
- *
594
- * Slashes (and backslashes in `windowsPathsNoEscape` mode) cannot be escaped
595
- * or unescaped.
596
- *
597
- * When `magicalBraces` is not set, escapes of braces (`{` and `}`) will not be
598
- * unescaped.
599
- */
600
- const unescape = (s, { windowsPathsNoEscape = false, magicalBraces = true, } = {}) => {
601
- if (magicalBraces) {
602
- return windowsPathsNoEscape ?
603
- s.replace(/\[([^/\\])\]/g, '$1')
604
- : s
605
- .replace(/((?!\\).|^)\[([^/\\])\]/g, '$1$2')
606
- .replace(/\\([^/])/g, '$1');
607
- }
608
- return windowsPathsNoEscape ?
609
- s.replace(/\[([^/\\{}])\]/g, '$1')
610
- : s
611
- .replace(/((?!\\).|^)\[([^/\\{}])\]/g, '$1$2')
612
- .replace(/\\([^/{}])/g, '$1');
613
- };
614
- _unescape.unescape = unescape;
615
-
616
- return _unescape;
617
- }
618
-
619
- var hasRequiredAst;
620
-
621
- function requireAst () {
622
- if (hasRequiredAst) return ast;
623
- hasRequiredAst = 1;
624
- // parse a single path portion
625
- var _a;
626
- Object.defineProperty(ast, "__esModule", { value: true });
627
- ast.AST = void 0;
628
- const brace_expressions_js_1 = requireBraceExpressions();
629
- const unescape_js_1 = require_unescape();
630
- const types = new Set(['!', '?', '+', '*', '@']);
631
- const isExtglobType = (c) => types.has(c);
632
- const isExtglobAST = (c) => isExtglobType(c.type);
633
- // Map of which extglob types can adopt the children of a nested extglob
634
- //
635
- // anything but ! can adopt a matching type:
636
- // +(a|+(b|c)|d) => +(a|b|c|d)
637
- // *(a|*(b|c)|d) => *(a|b|c|d)
638
- // @(a|@(b|c)|d) => @(a|b|c|d)
639
- // ?(a|?(b|c)|d) => ?(a|b|c|d)
640
- //
641
- // * can adopt anything, because 0 or repetition is allowed
642
- // *(a|?(b|c)|d) => *(a|b|c|d)
643
- // *(a|+(b|c)|d) => *(a|b|c|d)
644
- // *(a|@(b|c)|d) => *(a|b|c|d)
645
- //
646
- // + can adopt @, because 1 or repetition is allowed
647
- // +(a|@(b|c)|d) => +(a|b|c|d)
648
- //
649
- // + and @ CANNOT adopt *, because 0 would be allowed
650
- // +(a|*(b|c)|d) => would match "", on *(b|c)
651
- // @(a|*(b|c)|d) => would match "", on *(b|c)
652
- //
653
- // + and @ CANNOT adopt ?, because 0 would be allowed
654
- // +(a|?(b|c)|d) => would match "", on ?(b|c)
655
- // @(a|?(b|c)|d) => would match "", on ?(b|c)
656
- //
657
- // ? can adopt @, because 0 or 1 is allowed
658
- // ?(a|@(b|c)|d) => ?(a|b|c|d)
659
- //
660
- // ? and @ CANNOT adopt * or +, because >1 would be allowed
661
- // ?(a|*(b|c)|d) => would match bbb on *(b|c)
662
- // @(a|*(b|c)|d) => would match bbb on *(b|c)
663
- // ?(a|+(b|c)|d) => would match bbb on +(b|c)
664
- // @(a|+(b|c)|d) => would match bbb on +(b|c)
665
- //
666
- // ! CANNOT adopt ! (nothing else can either)
667
- // !(a|!(b|c)|d) => !(a|b|c|d) would fail to match on b (not not b|c)
668
- //
669
- // ! can adopt @
670
- // !(a|@(b|c)|d) => !(a|b|c|d)
671
- //
672
- // ! CANNOT adopt *
673
- // !(a|*(b|c)|d) => !(a|b|c|d) would match on bbb, not allowed
674
- //
675
- // ! CANNOT adopt +
676
- // !(a|+(b|c)|d) => !(a|b|c|d) would match on bbb, not allowed
677
- //
678
- // ! CANNOT adopt ?
679
- // x!(a|?(b|c)|d) => x!(a|b|c|d) would fail to match "x"
680
- const adoptionMap = new Map([
681
- ['!', ['@']],
682
- ['?', ['?', '@']],
683
- ['@', ['@']],
684
- ['*', ['*', '+', '?', '@']],
685
- ['+', ['+', '@']],
686
- ]);
687
- // nested extglobs that can be adopted in, but with the addition of
688
- // a blank '' element.
689
- const adoptionWithSpaceMap = new Map([
690
- ['!', ['?']],
691
- ['@', ['?']],
692
- ['+', ['?', '*']],
693
- ]);
694
- // union of the previous two maps
695
- const adoptionAnyMap = new Map([
696
- ['!', ['?', '@']],
697
- ['?', ['?', '@']],
698
- ['@', ['?', '@']],
699
- ['*', ['*', '+', '?', '@']],
700
- ['+', ['+', '@', '?', '*']],
701
- ]);
702
- // Extglobs that can take over their parent if they are the only child
703
- // the key is parent, value maps child to resulting extglob parent type
704
- // '@' is omitted because it's a special case. An `@` extglob with a single
705
- // member can always be usurped by that subpattern.
706
- const usurpMap = new Map([
707
- ['!', new Map([['!', '@']])],
708
- [
709
- '?',
710
- new Map([
711
- ['*', '*'],
712
- ['+', '*'],
713
- ]),
714
- ],
715
- [
716
- '@',
717
- new Map([
718
- ['!', '!'],
719
- ['?', '?'],
720
- ['@', '@'],
721
- ['*', '*'],
722
- ['+', '+'],
723
- ]),
724
- ],
725
- [
726
- '+',
727
- new Map([
728
- ['?', '*'],
729
- ['*', '*'],
730
- ]),
731
- ],
732
- ]);
733
- // Patterns that get prepended to bind to the start of either the
734
- // entire string, or just a single path portion, to prevent dots
735
- // and/or traversal patterns, when needed.
736
- // Exts don't need the ^ or / bit, because the root binds that already.
737
- const startNoTraversal = '(?!(?:^|/)\\.\\.?(?:$|/))';
738
- const startNoDot = '(?!\\.)';
739
- // characters that indicate a start of pattern needs the "no dots" bit,
740
- // because a dot *might* be matched. ( is not in the list, because in
741
- // the case of a child extglob, it will handle the prevention itself.
742
- const addPatternStart = new Set(['[', '.']);
743
- // cases where traversal is A-OK, no dot prevention needed
744
- const justDots = new Set(['..', '.']);
745
- const reSpecials = new Set('().*{}+?[]^$\\!');
746
- const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
747
507
  // any single thing other than /
508
+ // don't need to escape / when using new RegExp()
748
509
  const qmark = '[^/]';
510
+
749
511
  // * => any number of characters
750
512
  const star = qmark + '*?';
751
- // use + when we need to ensure that *something* matches, because the * is
752
- // the only thing in the path portion.
753
- const starNoEmpty = qmark + '+?';
754
- // remove the \ chars that we added if we end up doing a nonmagic compare
755
- // const deslash = (s: string) => s.replace(/\\(.)/g, '$1')
756
- let ID = 0;
757
- class AST {
758
- type;
759
- #root;
760
- #hasMagic;
761
- #uflag = false;
762
- #parts = [];
763
- #parent;
764
- #parentIndex;
765
- #negs;
766
- #filledNegs = false;
767
- #options;
768
- #toString;
769
- // set to true if it's an extglob with no children
770
- // (which really means one child of '')
771
- #emptyExt = false;
772
- id = ++ID;
773
- get depth() {
774
- return (this.#parent?.depth ?? -1) + 1;
775
- }
776
- [Symbol.for('nodejs.util.inspect.custom')]() {
777
- return {
778
- '@@type': 'AST',
779
- id: this.id,
780
- type: this.type,
781
- root: this.#root.id,
782
- parent: this.#parent?.id,
783
- depth: this.depth,
784
- partsLength: this.#parts.length,
785
- parts: this.#parts,
786
- };
513
+
514
+ // ** when dots are allowed. Anything goes, except .. and .
515
+ // not (^ or / followed by one or two dots followed by $ or /),
516
+ // followed by anything, any number of times.
517
+ const twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?';
518
+
519
+ // not a ^ or / followed by a dot,
520
+ // followed by anything, any number of times.
521
+ const twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?';
522
+
523
+ // "abc" -> { a:true, b:true, c:true }
524
+ const charSet = s => s.split('').reduce((set, c) => {
525
+ set[c] = true;
526
+ return set
527
+ }, {});
528
+
529
+ // characters that need to be escaped in RegExp.
530
+ const reSpecials = charSet('().*{}+?[]^$\\!');
531
+
532
+ // characters that indicate we have to add the pattern start
533
+ const addPatternStartSet = charSet('[.(');
534
+
535
+ // normalizes slashes.
536
+ const slashSplit = /\/+/;
537
+
538
+ minimatch.filter = (pattern, options = {}) =>
539
+ (p, i, list) => minimatch(p, pattern, options);
540
+
541
+ const ext = (a, b = {}) => {
542
+ const t = {};
543
+ Object.keys(a).forEach(k => t[k] = a[k]);
544
+ Object.keys(b).forEach(k => t[k] = b[k]);
545
+ return t
546
+ };
547
+
548
+ minimatch.defaults = def => {
549
+ if (!def || typeof def !== 'object' || !Object.keys(def).length) {
550
+ return minimatch
551
+ }
552
+
553
+ const orig = minimatch;
554
+
555
+ const m = (p, pattern, options) => orig(p, pattern, ext(def, options));
556
+ m.Minimatch = class Minimatch extends orig.Minimatch {
557
+ constructor (pattern, options) {
558
+ super(pattern, ext(def, options));
787
559
  }
788
- constructor(type, parent, options = {}) {
789
- this.type = type;
790
- // extglobs are inherently magical
791
- if (type)
792
- this.#hasMagic = true;
793
- this.#parent = parent;
794
- this.#root = this.#parent ? this.#parent.#root : this;
795
- this.#options = this.#root === this ? options : this.#root.#options;
796
- this.#negs = this.#root === this ? [] : this.#root.#negs;
797
- if (type === '!' && !this.#root.#filledNegs)
798
- this.#negs.push(this);
799
- this.#parentIndex = this.#parent ? this.#parent.#parts.length : 0;
800
- }
801
- get hasMagic() {
802
- /* c8 ignore start */
803
- if (this.#hasMagic !== undefined)
804
- return this.#hasMagic;
805
- /* c8 ignore stop */
806
- for (const p of this.#parts) {
807
- if (typeof p === 'string')
808
- continue;
809
- if (p.type || p.hasMagic)
810
- return (this.#hasMagic = true);
811
- }
812
- // note: will be undefined until we generate the regexp src and find out
813
- return this.#hasMagic;
814
- }
815
- // reconstructs the pattern
816
- toString() {
817
- return (this.#toString !== undefined ? this.#toString
818
- : !this.type ?
819
- (this.#toString = this.#parts.map(p => String(p)).join(''))
820
- : (this.#toString =
821
- this.type +
822
- '(' +
823
- this.#parts.map(p => String(p)).join('|') +
824
- ')'));
825
- }
826
- #fillNegs() {
827
- /* c8 ignore start */
828
- if (this !== this.#root)
829
- throw new Error('should only call on root');
830
- if (this.#filledNegs)
831
- return this;
832
- /* c8 ignore stop */
833
- // call toString() once to fill this out
834
- this.toString();
835
- this.#filledNegs = true;
836
- let n;
837
- while ((n = this.#negs.pop())) {
838
- if (n.type !== '!')
839
- continue;
840
- // walk up the tree, appending everthing that comes AFTER parentIndex
841
- let p = n;
842
- let pp = p.#parent;
843
- while (pp) {
844
- for (let i = p.#parentIndex + 1; !pp.type && i < pp.#parts.length; i++) {
845
- for (const part of n.#parts) {
846
- /* c8 ignore start */
847
- if (typeof part === 'string') {
848
- throw new Error('string part in extglob AST??');
849
- }
850
- /* c8 ignore stop */
851
- part.copyIn(pp.#parts[i]);
852
- }
853
- }
854
- p = pp;
855
- pp = p.#parent;
856
- }
857
- }
858
- return this;
560
+ };
561
+ m.Minimatch.defaults = options => orig.defaults(ext(def, options)).Minimatch;
562
+ m.filter = (pattern, options) => orig.filter(pattern, ext(def, options));
563
+ m.defaults = options => orig.defaults(ext(def, options));
564
+ m.makeRe = (pattern, options) => orig.makeRe(pattern, ext(def, options));
565
+ m.braceExpand = (pattern, options) => orig.braceExpand(pattern, ext(def, options));
566
+ m.match = (list, pattern, options) => orig.match(list, pattern, ext(def, options));
567
+
568
+ return m
569
+ };
570
+
571
+
572
+
573
+
574
+
575
+ // Brace expansion:
576
+ // a{b,c}d -> abd acd
577
+ // a{b,}c -> abc ac
578
+ // a{0..3}d -> a0d a1d a2d a3d
579
+ // a{b,c{d,e}f}g -> abg acdfg acefg
580
+ // a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg
581
+ //
582
+ // Invalid sets are not expanded.
583
+ // a{2..}b -> a{2..}b
584
+ // a{b}c -> a{b}c
585
+ minimatch.braceExpand = (pattern, options) => braceExpand(pattern, options);
586
+
587
+ const braceExpand = (pattern, options = {}) => {
588
+ assertValidPattern(pattern);
589
+
590
+ // Thanks to Yeting Li <https://github.com/yetingli> for
591
+ // improving this regexp to avoid a ReDOS vulnerability.
592
+ if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
593
+ // shortcut. no need to expand.
594
+ return [pattern]
595
+ }
596
+
597
+ return expand(pattern)
598
+ };
599
+
600
+ const MAX_PATTERN_LENGTH = 1024 * 64;
601
+ const assertValidPattern = pattern => {
602
+ if (typeof pattern !== 'string') {
603
+ throw new TypeError('invalid pattern')
604
+ }
605
+
606
+ if (pattern.length > MAX_PATTERN_LENGTH) {
607
+ throw new TypeError('pattern is too long')
608
+ }
609
+ };
610
+
611
+ // parse a component of the expanded set.
612
+ // At this point, no pattern may contain "/" in it
613
+ // so we're going to return a 2d array, where each entry is the full
614
+ // pattern, split on '/', and then turned into a regular expression.
615
+ // A regexp is made at the end which joins each array with an
616
+ // escaped /, and another full one which joins each regexp with |.
617
+ //
618
+ // Following the lead of Bash 4.1, note that "**" only has special meaning
619
+ // when it is the *only* thing in a path portion. Otherwise, any series
620
+ // of * is equivalent to a single *. Globstar behavior is enabled by
621
+ // default, and can be disabled by setting options.noglobstar.
622
+ const SUBPARSE = Symbol('subparse');
623
+
624
+ minimatch.makeRe = (pattern, options) =>
625
+ new Minimatch(pattern, options || {}).makeRe();
626
+
627
+ minimatch.match = (list, pattern, options = {}) => {
628
+ const mm = new Minimatch(pattern, options);
629
+ list = list.filter(f => mm.match(f));
630
+ if (mm.options.nonull && !list.length) {
631
+ list.push(pattern);
632
+ }
633
+ return list
634
+ };
635
+
636
+ // replace stuff like \* with *
637
+ const globUnescape = s => s.replace(/\\(.)/g, '$1');
638
+ const charUnescape = s => s.replace(/\\([^-\]])/g, '$1');
639
+ const regExpEscape = s => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
640
+ const braExpEscape = s => s.replace(/[[\]\\]/g, '\\$&');
641
+
642
+ class Minimatch {
643
+ constructor (pattern, options) {
644
+ assertValidPattern(pattern);
645
+
646
+ if (!options) options = {};
647
+
648
+ this.options = options;
649
+ this.maxGlobstarRecursion = options.maxGlobstarRecursion !== undefined
650
+ ? options.maxGlobstarRecursion : 200;
651
+ this.set = [];
652
+ this.pattern = pattern;
653
+ this.windowsPathsNoEscape = !!options.windowsPathsNoEscape ||
654
+ options.allowWindowsEscape === false;
655
+ if (this.windowsPathsNoEscape) {
656
+ this.pattern = this.pattern.replace(/\\/g, '/');
657
+ }
658
+ this.regexp = null;
659
+ this.negate = false;
660
+ this.comment = false;
661
+ this.empty = false;
662
+ this.partial = !!options.partial;
663
+
664
+ // make the set of regexps etc.
665
+ this.make();
666
+ }
667
+
668
+ debug () {}
669
+
670
+ make () {
671
+ const pattern = this.pattern;
672
+ const options = this.options;
673
+
674
+ // empty patterns and comments match nothing.
675
+ if (!options.nocomment && pattern.charAt(0) === '#') {
676
+ this.comment = true;
677
+ return
859
678
  }
860
- push(...parts) {
861
- for (const p of parts) {
862
- if (p === '')
863
- continue;
864
- /* c8 ignore start */
865
- if (typeof p !== 'string' &&
866
- !(p instanceof _a && p.#parent === this)) {
867
- throw new Error('invalid part: ' + p);
868
- }
869
- /* c8 ignore stop */
870
- this.#parts.push(p);
871
- }
872
- }
873
- toJSON() {
874
- const ret = this.type === null ?
875
- this.#parts
876
- .slice()
877
- .map(p => (typeof p === 'string' ? p : p.toJSON()))
878
- : [this.type, ...this.#parts.map(p => p.toJSON())];
879
- if (this.isStart() && !this.type)
880
- ret.unshift([]);
881
- if (this.isEnd() &&
882
- (this === this.#root ||
883
- (this.#root.#filledNegs && this.#parent?.type === '!'))) {
884
- ret.push({});
885
- }
886
- return ret;
887
- }
888
- isStart() {
889
- if (this.#root === this)
890
- return true;
891
- // if (this.type) return !!this.#parent?.isStart()
892
- if (!this.#parent?.isStart())
893
- return false;
894
- if (this.#parentIndex === 0)
895
- return true;
896
- // if everything AHEAD of this is a negation, then it's still the "start"
897
- const p = this.#parent;
898
- for (let i = 0; i < this.#parentIndex; i++) {
899
- const pp = p.#parts[i];
900
- if (!(pp instanceof _a && pp.type === '!')) {
901
- return false;
902
- }
903
- }
904
- return true;
679
+ if (!pattern) {
680
+ this.empty = true;
681
+ return
905
682
  }
906
- isEnd() {
907
- if (this.#root === this)
908
- return true;
909
- if (this.#parent?.type === '!')
910
- return true;
911
- if (!this.#parent?.isEnd())
912
- return false;
913
- if (!this.type)
914
- return this.#parent?.isEnd();
915
- // if not root, it'll always have a parent
916
- /* c8 ignore start */
917
- const pl = this.#parent ? this.#parent.#parts.length : 0;
918
- /* c8 ignore stop */
919
- return this.#parentIndex === pl - 1;
683
+
684
+ // step 1: figure out negation, etc.
685
+ this.parseNegate();
686
+
687
+ // step 2: expand braces
688
+ let set = this.globSet = this.braceExpand();
689
+
690
+ if (options.debug) this.debug = (...args) => console.error(...args);
691
+
692
+ this.debug(this.pattern, set);
693
+
694
+ // step 3: now we have a set, so turn each one into a series of path-portion
695
+ // matching patterns.
696
+ // These will be regexps, except in the case of "**", which is
697
+ // set to the GLOBSTAR object for globstar behavior,
698
+ // and will not contain any / characters
699
+ set = this.globParts = set.map(s => s.split(slashSplit));
700
+
701
+ this.debug(this.pattern, set);
702
+
703
+ // glob --> regexps
704
+ set = set.map((s, si, set) => s.map(this.parse, this));
705
+
706
+ this.debug(this.pattern, set);
707
+
708
+ // filter out everything that didn't compile properly.
709
+ set = set.filter(s => s.indexOf(false) === -1);
710
+
711
+ this.debug(this.pattern, set);
712
+
713
+ this.set = set;
714
+ }
715
+
716
+ parseNegate () {
717
+ if (this.options.nonegate) return
718
+
719
+ const pattern = this.pattern;
720
+ let negate = false;
721
+ let negateOffset = 0;
722
+
723
+ for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
724
+ negate = !negate;
725
+ negateOffset++;
920
726
  }
921
- copyIn(part) {
922
- if (typeof part === 'string')
923
- this.push(part);
924
- else
925
- this.push(part.clone(this));
926
- }
927
- clone(parent) {
928
- const c = new _a(this.type, parent);
929
- for (const p of this.#parts) {
930
- c.copyIn(p);
931
- }
932
- return c;
933
- }
934
- static #parseAST(str, ast, pos, opt, extDepth) {
935
- const maxDepth = opt.maxExtglobRecursion ?? 2;
936
- let escaping = false;
937
- let inBrace = false;
938
- let braceStart = -1;
939
- let braceNeg = false;
940
- if (ast.type === null) {
941
- // outside of a extglob, append until we find a start
942
- let i = pos;
943
- let acc = '';
944
- while (i < str.length) {
945
- const c = str.charAt(i++);
946
- // still accumulate escapes at this point, but we do ignore
947
- // starts that are escaped
948
- if (escaping || c === '\\') {
949
- escaping = !escaping;
950
- acc += c;
951
- continue;
952
- }
953
- if (inBrace) {
954
- if (i === braceStart + 1) {
955
- if (c === '^' || c === '!') {
956
- braceNeg = true;
957
- }
958
- }
959
- else if (c === ']' && !(i === braceStart + 2 && braceNeg)) {
960
- inBrace = false;
961
- }
962
- acc += c;
963
- continue;
964
- }
965
- else if (c === '[') {
966
- inBrace = true;
967
- braceStart = i;
968
- braceNeg = false;
969
- acc += c;
970
- continue;
971
- }
972
- // we don't have to check for adoption here, because that's
973
- // done at the other recursion point.
974
- const doRecurse = !opt.noext &&
975
- isExtglobType(c) &&
976
- str.charAt(i) === '(' &&
977
- extDepth <= maxDepth;
978
- if (doRecurse) {
979
- ast.push(acc);
980
- acc = '';
981
- const ext = new _a(c, ast);
982
- i = _a.#parseAST(str, ext, i, opt, extDepth + 1);
983
- ast.push(ext);
984
- continue;
985
- }
986
- acc += c;
987
- }
988
- ast.push(acc);
989
- return i;
990
- }
991
- // some kind of extglob, pos is at the (
992
- // find the next | or )
993
- let i = pos + 1;
994
- let part = new _a(null, ast);
995
- const parts = [];
996
- let acc = '';
997
- while (i < str.length) {
998
- const c = str.charAt(i++);
999
- // still accumulate escapes at this point, but we do ignore
1000
- // starts that are escaped
1001
- if (escaping || c === '\\') {
1002
- escaping = !escaping;
1003
- acc += c;
1004
- continue;
1005
- }
1006
- if (inBrace) {
1007
- if (i === braceStart + 1) {
1008
- if (c === '^' || c === '!') {
1009
- braceNeg = true;
1010
- }
1011
- }
1012
- else if (c === ']' && !(i === braceStart + 2 && braceNeg)) {
1013
- inBrace = false;
1014
- }
1015
- acc += c;
1016
- continue;
1017
- }
1018
- else if (c === '[') {
1019
- inBrace = true;
1020
- braceStart = i;
1021
- braceNeg = false;
1022
- acc += c;
1023
- continue;
1024
- }
1025
- const doRecurse = !opt.noext &&
1026
- isExtglobType(c) &&
1027
- str.charAt(i) === '(' &&
1028
- /* c8 ignore start - the maxDepth is sufficient here */
1029
- (extDepth <= maxDepth || (ast && ast.#canAdoptType(c)));
1030
- /* c8 ignore stop */
1031
- if (doRecurse) {
1032
- const depthAdd = ast && ast.#canAdoptType(c) ? 0 : 1;
1033
- part.push(acc);
1034
- acc = '';
1035
- const ext = new _a(c, part);
1036
- part.push(ext);
1037
- i = _a.#parseAST(str, ext, i, opt, extDepth + depthAdd);
1038
- continue;
1039
- }
1040
- if (c === '|') {
1041
- part.push(acc);
1042
- acc = '';
1043
- parts.push(part);
1044
- part = new _a(null, ast);
1045
- continue;
1046
- }
1047
- if (c === ')') {
1048
- if (acc === '' && ast.#parts.length === 0) {
1049
- ast.#emptyExt = true;
1050
- }
1051
- part.push(acc);
1052
- acc = '';
1053
- ast.push(...parts, part);
1054
- return i;
1055
- }
1056
- acc += c;
1057
- }
1058
- // unfinished extglob
1059
- // if we got here, it was a malformed extglob! not an extglob, but
1060
- // maybe something else in there.
1061
- ast.type = null;
1062
- ast.#hasMagic = undefined;
1063
- ast.#parts = [str.substring(pos - 1)];
1064
- return i;
1065
- }
1066
- #canAdoptWithSpace(child) {
1067
- return this.#canAdopt(child, adoptionWithSpaceMap);
1068
- }
1069
- #canAdopt(child, map = adoptionMap) {
1070
- if (!child ||
1071
- typeof child !== 'object' ||
1072
- child.type !== null ||
1073
- child.#parts.length !== 1 ||
1074
- this.type === null) {
1075
- return false;
1076
- }
1077
- const gc = child.#parts[0];
1078
- if (!gc || typeof gc !== 'object' || gc.type === null) {
1079
- return false;
727
+
728
+ if (negateOffset) this.pattern = pattern.slice(negateOffset);
729
+ this.negate = negate;
730
+ }
731
+
732
+ // set partial to true to test if, for example,
733
+ // "/a/b" matches the start of "/*/b/*/d"
734
+ // Partial means, if you run out of file before you run
735
+ // out of pattern, then that's fine, as long as all
736
+ // the parts match.
737
+ matchOne (file, pattern, partial) {
738
+ if (pattern.indexOf(GLOBSTAR) !== -1) {
739
+ return this._matchGlobstar(file, pattern, partial, 0, 0)
740
+ }
741
+ return this._matchOne(file, pattern, partial, 0, 0)
742
+ }
743
+
744
+ _matchGlobstar (file, pattern, partial, fileIndex, patternIndex) {
745
+ // find first globstar from patternIndex
746
+ let firstgs = -1;
747
+ for (let i = patternIndex; i < pattern.length; i++) {
748
+ if (pattern[i] === GLOBSTAR) { firstgs = i; break }
749
+ }
750
+
751
+ // find last globstar
752
+ let lastgs = -1;
753
+ for (let i = pattern.length - 1; i >= 0; i--) {
754
+ if (pattern[i] === GLOBSTAR) { lastgs = i; break }
755
+ }
756
+
757
+ const head = pattern.slice(patternIndex, firstgs);
758
+ const body = partial ? pattern.slice(firstgs + 1) : pattern.slice(firstgs + 1, lastgs);
759
+ const tail = partial ? [] : pattern.slice(lastgs + 1);
760
+
761
+ // check the head
762
+ if (head.length) {
763
+ const fileHead = file.slice(fileIndex, fileIndex + head.length);
764
+ if (!this._matchOne(fileHead, head, partial, 0, 0)) {
765
+ return false
766
+ }
767
+ fileIndex += head.length;
768
+ }
769
+
770
+ // check the tail
771
+ let fileTailMatch = 0;
772
+ if (tail.length) {
773
+ if (tail.length + fileIndex > file.length) return false
774
+
775
+ const tailStart = file.length - tail.length;
776
+ if (this._matchOne(file, tail, partial, tailStart, 0)) {
777
+ fileTailMatch = tail.length;
778
+ } else {
779
+ // affordance for stuff like a/**/* matching a/b/
780
+ if (file[file.length - 1] !== '' ||
781
+ fileIndex + tail.length === file.length) {
782
+ return false
1080
783
  }
1081
- return this.#canAdoptType(gc.type, map);
1082
- }
1083
- #canAdoptType(c, map = adoptionAnyMap) {
1084
- return !!map.get(this.type)?.includes(c);
1085
- }
1086
- #adoptWithSpace(child, index) {
1087
- const gc = child.#parts[0];
1088
- const blank = new _a(null, gc, this.options);
1089
- blank.#parts.push('');
1090
- gc.push(blank);
1091
- this.#adopt(child, index);
1092
- }
1093
- #adopt(child, index) {
1094
- const gc = child.#parts[0];
1095
- this.#parts.splice(index, 1, ...gc.#parts);
1096
- for (const p of gc.#parts) {
1097
- if (typeof p === 'object')
1098
- p.#parent = this;
1099
- }
1100
- this.#toString = undefined;
1101
- }
1102
- #canUsurpType(c) {
1103
- const m = usurpMap.get(this.type);
1104
- return !!m?.has(c);
1105
- }
1106
- #canUsurp(child) {
1107
- if (!child ||
1108
- typeof child !== 'object' ||
1109
- child.type !== null ||
1110
- child.#parts.length !== 1 ||
1111
- this.type === null ||
1112
- this.#parts.length !== 1) {
1113
- return false;
784
+ if (!this._matchOne(file, tail, partial, tailStart - 1, 0)) {
785
+ return false
1114
786
  }
1115
- const gc = child.#parts[0];
1116
- if (!gc || typeof gc !== 'object' || gc.type === null) {
1117
- return false;
787
+ fileTailMatch = tail.length + 1;
788
+ }
789
+ }
790
+
791
+ // if body is empty (single ** between head and tail)
792
+ if (!body.length) {
793
+ let sawSome = !!fileTailMatch;
794
+ for (let i = fileIndex; i < file.length - fileTailMatch; i++) {
795
+ const f = String(file[i]);
796
+ sawSome = true;
797
+ if (f === '.' || f === '..' ||
798
+ (!this.options.dot && f.charAt(0) === '.')) {
799
+ return false
1118
800
  }
1119
- return this.#canUsurpType(gc.type);
801
+ }
802
+ return partial || sawSome
803
+ }
804
+
805
+ // split body into segments at each GLOBSTAR
806
+ const bodySegments = [[[], 0]];
807
+ let currentBody = bodySegments[0];
808
+ let nonGsParts = 0;
809
+ const nonGsPartsSums = [0];
810
+ for (const b of body) {
811
+ if (b === GLOBSTAR) {
812
+ nonGsPartsSums.push(nonGsParts);
813
+ currentBody = [[], 0];
814
+ bodySegments.push(currentBody);
815
+ } else {
816
+ currentBody[0].push(b);
817
+ nonGsParts++;
818
+ }
1120
819
  }
1121
- #usurp(child) {
1122
- const m = usurpMap.get(this.type);
1123
- const gc = child.#parts[0];
1124
- const nt = m?.get(gc.type);
1125
- /* c8 ignore start - impossible */
1126
- if (!nt)
1127
- return false;
1128
- /* c8 ignore stop */
1129
- this.#parts = gc.#parts;
1130
- for (const p of this.#parts) {
1131
- if (typeof p === 'object') {
1132
- p.#parent = this;
1133
- }
820
+
821
+ let idx = bodySegments.length - 1;
822
+ const fileLength = file.length - fileTailMatch;
823
+ for (const b of bodySegments) {
824
+ b[1] = fileLength - (nonGsPartsSums[idx--] + b[0].length);
825
+ }
826
+
827
+ return !!this._matchGlobStarBodySections(
828
+ file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch
829
+ )
830
+ }
831
+
832
+ // return false for "nope, not matching"
833
+ // return null for "not matching, cannot keep trying"
834
+ _matchGlobStarBodySections (
835
+ file, bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail
836
+ ) {
837
+ const bs = bodySegments[bodyIndex];
838
+ if (!bs) {
839
+ // just make sure there are no bad dots
840
+ for (let i = fileIndex; i < file.length; i++) {
841
+ sawTail = true;
842
+ const f = file[i];
843
+ if (f === '.' || f === '..' ||
844
+ (!this.options.dot && f.charAt(0) === '.')) {
845
+ return false
846
+ }
847
+ }
848
+ return sawTail
849
+ }
850
+
851
+ const [body, after] = bs;
852
+ while (fileIndex <= after) {
853
+ const m = this._matchOne(
854
+ file.slice(0, fileIndex + body.length),
855
+ body,
856
+ partial,
857
+ fileIndex,
858
+ 0
859
+ );
860
+ // if limit exceeded, no match. intentional false negative,
861
+ // acceptable break in correctness for security.
862
+ if (m && globStarDepth < this.maxGlobstarRecursion) {
863
+ const sub = this._matchGlobStarBodySections(
864
+ file, bodySegments,
865
+ fileIndex + body.length, bodyIndex + 1,
866
+ partial, globStarDepth + 1, sawTail
867
+ );
868
+ if (sub !== false) {
869
+ return sub
1134
870
  }
1135
- this.type = nt;
1136
- this.#toString = undefined;
1137
- this.#emptyExt = false;
871
+ }
872
+ const f = file[fileIndex];
873
+ if (f === '.' || f === '..' ||
874
+ (!this.options.dot && f.charAt(0) === '.')) {
875
+ return false
876
+ }
877
+ fileIndex++;
1138
878
  }
1139
- static fromGlob(pattern, options = {}) {
1140
- const ast = new _a(null, undefined, options);
1141
- _a.#parseAST(pattern, ast, 0, options, 0);
1142
- return ast;
879
+ return partial || null
880
+ }
881
+
882
+ _matchOne (file, pattern, partial, fileIndex, patternIndex) {
883
+ let fi, pi, fl, pl;
884
+ for (
885
+ fi = fileIndex, pi = patternIndex, fl = file.length, pl = pattern.length
886
+ ; (fi < fl) && (pi < pl)
887
+ ; fi++, pi++
888
+ ) {
889
+ this.debug('matchOne loop');
890
+ const p = pattern[pi];
891
+ const f = file[fi];
892
+
893
+ this.debug(pattern, p, f);
894
+
895
+ // should be impossible.
896
+ // some invalid regexp stuff in the set.
897
+ /* istanbul ignore if */
898
+ if (p === false || p === GLOBSTAR) return false
899
+
900
+ // something other than **
901
+ // non-magic patterns just have to match exactly
902
+ // patterns with magic have been turned into regexps.
903
+ let hit;
904
+ if (typeof p === 'string') {
905
+ hit = f === p;
906
+ this.debug('string match', p, f, hit);
907
+ } else {
908
+ hit = f.match(p);
909
+ this.debug('pattern match', p, f, hit);
910
+ }
911
+
912
+ if (!hit) return false
1143
913
  }
1144
- // returns the regular expression if there's magic, or the unescaped
1145
- // string if not.
1146
- toMMPattern() {
1147
- // should only be called on root
1148
- /* c8 ignore start */
1149
- if (this !== this.#root)
1150
- return this.#root.toMMPattern();
1151
- /* c8 ignore stop */
1152
- const glob = this.toString();
1153
- const [re, body, hasMagic, uflag] = this.toRegExpSource();
1154
- // if we're in nocase mode, and not nocaseMagicOnly, then we do
1155
- // still need a regular expression if we have to case-insensitively
1156
- // match capital/lowercase characters.
1157
- const anyMagic = hasMagic ||
1158
- this.#hasMagic ||
1159
- (this.#options.nocase &&
1160
- !this.#options.nocaseMagicOnly &&
1161
- glob.toUpperCase() !== glob.toLowerCase());
1162
- if (!anyMagic) {
1163
- return body;
1164
- }
1165
- const flags = (this.#options.nocase ? 'i' : '') + (uflag ? 'u' : '');
1166
- return Object.assign(new RegExp(`^${re}$`, flags), {
1167
- _src: re,
1168
- _glob: glob,
1169
- });
914
+
915
+ // now either we fell off the end of the pattern, or we're done.
916
+ if (fi === fl && pi === pl) {
917
+ // ran out of pattern and filename at the same time.
918
+ // an exact hit!
919
+ return true
920
+ } else if (fi === fl) {
921
+ // ran out of file, but still had pattern left.
922
+ // this is ok if we're doing the match as part of
923
+ // a glob fs traversal.
924
+ return partial
925
+ } else /* istanbul ignore else */ if (pi === pl) {
926
+ // ran out of pattern, still have file left.
927
+ // this is only acceptable if we're on the very last
928
+ // empty segment of a file with a trailing slash.
929
+ // a/* should match a/b/
930
+ return (fi === fl - 1) && (file[fi] === '')
931
+ }
932
+
933
+ // should be unreachable.
934
+ /* istanbul ignore next */
935
+ throw new Error('wtf?')
936
+ }
937
+
938
+ braceExpand () {
939
+ return braceExpand(this.pattern, this.options)
940
+ }
941
+
942
+ parse (pattern, isSub) {
943
+ assertValidPattern(pattern);
944
+
945
+ const options = this.options;
946
+
947
+ // shortcuts
948
+ if (pattern === '**') {
949
+ if (!options.noglobstar)
950
+ return GLOBSTAR
951
+ else
952
+ pattern = '*';
1170
953
  }
1171
- get options() {
1172
- return this.#options;
1173
- }
1174
- // returns the string match, the regexp source, whether there's magic
1175
- // in the regexp (so a regular expression is required) and whether or
1176
- // not the uflag is needed for the regular expression (for posix classes)
1177
- // TODO: instead of injecting the start/end at this point, just return
1178
- // the BODY of the regexp, along with the start/end portions suitable
1179
- // for binding the start/end in either a joined full-path makeRe context
1180
- // (where we bind to (^|/), or a standalone matchPart context (where
1181
- // we bind to ^, and not /). Otherwise slashes get duped!
1182
- //
1183
- // In part-matching mode, the start is:
1184
- // - if not isStart: nothing
1185
- // - if traversal possible, but not allowed: ^(?!\.\.?$)
1186
- // - if dots allowed or not possible: ^
1187
- // - if dots possible and not allowed: ^(?!\.)
1188
- // end is:
1189
- // - if not isEnd(): nothing
1190
- // - else: $
1191
- //
1192
- // In full-path matching mode, we put the slash at the START of the
1193
- // pattern, so start is:
1194
- // - if first pattern: same as part-matching mode
1195
- // - if not isStart(): nothing
1196
- // - if traversal possible, but not allowed: /(?!\.\.?(?:$|/))
1197
- // - if dots allowed or not possible: /
1198
- // - if dots possible and not allowed: /(?!\.)
1199
- // end is:
1200
- // - if last pattern, same as part-matching mode
1201
- // - else nothing
1202
- //
1203
- // Always put the (?:$|/) on negated tails, though, because that has to be
1204
- // there to bind the end of the negated pattern portion, and it's easier to
1205
- // just stick it in now rather than try to inject it later in the middle of
1206
- // the pattern.
1207
- //
1208
- // We can just always return the same end, and leave it up to the caller
1209
- // to know whether it's going to be used joined or in parts.
1210
- // And, if the start is adjusted slightly, can do the same there:
1211
- // - if not isStart: nothing
1212
- // - if traversal possible, but not allowed: (?:/|^)(?!\.\.?$)
1213
- // - if dots allowed or not possible: (?:/|^)
1214
- // - if dots possible and not allowed: (?:/|^)(?!\.)
1215
- //
1216
- // But it's better to have a simpler binding without a conditional, for
1217
- // performance, so probably better to return both start options.
1218
- //
1219
- // Then the caller just ignores the end if it's not the first pattern,
1220
- // and the start always gets applied.
1221
- //
1222
- // But that's always going to be $ if it's the ending pattern, or nothing,
1223
- // so the caller can just attach $ at the end of the pattern when building.
1224
- //
1225
- // So the todo is:
1226
- // - better detect what kind of start is needed
1227
- // - return both flavors of starting pattern
1228
- // - attach $ at the end of the pattern when creating the actual RegExp
1229
- //
1230
- // Ah, but wait, no, that all only applies to the root when the first pattern
1231
- // is not an extglob. If the first pattern IS an extglob, then we need all
1232
- // that dot prevention biz to live in the extglob portions, because eg
1233
- // +(*|.x*) can match .xy but not .yx.
1234
- //
1235
- // So, return the two flavors if it's #root and the first child is not an
1236
- // AST, otherwise leave it to the child AST to handle it, and there,
1237
- // use the (?:^|/) style of start binding.
1238
- //
1239
- // Even simplified further:
1240
- // - Since the start for a join is eg /(?!\.) and the start for a part
1241
- // is ^(?!\.), we can just prepend (?!\.) to the pattern (either root
1242
- // or start or whatever) and prepend ^ or / at the Regexp construction.
1243
- toRegExpSource(allowDot) {
1244
- const dot = allowDot ?? !!this.#options.dot;
1245
- if (this.#root === this) {
1246
- this.#flatten();
1247
- this.#fillNegs();
1248
- }
1249
- if (!isExtglobAST(this)) {
1250
- const noEmpty = this.isStart() &&
1251
- this.isEnd() &&
1252
- !this.#parts.some(s => typeof s !== 'string');
1253
- const src = this.#parts
1254
- .map(p => {
1255
- const [re, _, hasMagic, uflag] = typeof p === 'string' ?
1256
- _a.#parseGlob(p, this.#hasMagic, noEmpty)
1257
- : p.toRegExpSource(allowDot);
1258
- this.#hasMagic = this.#hasMagic || hasMagic;
1259
- this.#uflag = this.#uflag || uflag;
1260
- return re;
1261
- })
1262
- .join('');
1263
- let start = '';
1264
- if (this.isStart()) {
1265
- if (typeof this.#parts[0] === 'string') {
1266
- // this is the string that will match the start of the pattern,
1267
- // so we need to protect against dots and such.
1268
- // '.' and '..' cannot match unless the pattern is that exactly,
1269
- // even if it starts with . or dot:true is set.
1270
- const dotTravAllowed = this.#parts.length === 1 && justDots.has(this.#parts[0]);
1271
- if (!dotTravAllowed) {
1272
- const aps = addPatternStart;
1273
- // check if we have a possibility of matching . or ..,
1274
- // and prevent that.
1275
- const needNoTrav =
1276
- // dots are allowed, and the pattern starts with [ or .
1277
- (dot && aps.has(src.charAt(0))) ||
1278
- // the pattern starts with \., and then [ or .
1279
- (src.startsWith('\\.') && aps.has(src.charAt(2))) ||
1280
- // the pattern starts with \.\., and then [ or .
1281
- (src.startsWith('\\.\\.') && aps.has(src.charAt(4)));
1282
- // no need to prevent dots if it can't match a dot, or if a
1283
- // sub-pattern will be preventing it anyway.
1284
- const needNoDot = !dot && !allowDot && aps.has(src.charAt(0));
1285
- start =
1286
- needNoTrav ? startNoTraversal
1287
- : needNoDot ? startNoDot
1288
- : '';
1289
- }
1290
- }
1291
- }
1292
- // append the "end of path portion" pattern to negation tails
1293
- let end = '';
1294
- if (this.isEnd() &&
1295
- this.#root.#filledNegs &&
1296
- this.#parent?.type === '!') {
1297
- end = '(?:$|\\/)';
1298
- }
1299
- const final = start + src + end;
1300
- return [
1301
- final,
1302
- (0, unescape_js_1.unescape)(src),
1303
- (this.#hasMagic = !!this.#hasMagic),
1304
- this.#uflag,
1305
- ];
954
+ if (pattern === '') return ''
955
+
956
+ let re = '';
957
+ let hasMagic = false;
958
+ let escaping = false;
959
+ // ? => one single character
960
+ const patternListStack = [];
961
+ const negativeLists = [];
962
+ let stateChar;
963
+ let inClass = false;
964
+ let reClassStart = -1;
965
+ let classStart = -1;
966
+ let cs;
967
+ let pl;
968
+ let sp;
969
+ // . and .. never match anything that doesn't start with .,
970
+ // even when options.dot is set. However, if the pattern
971
+ // starts with ., then traversal patterns can match.
972
+ let dotTravAllowed = pattern.charAt(0) === '.';
973
+ let dotFileAllowed = options.dot || dotTravAllowed;
974
+ const patternStart = () =>
975
+ dotTravAllowed
976
+ ? ''
977
+ : dotFileAllowed
978
+ ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))'
979
+ : '(?!\\.)';
980
+ const subPatternStart = (p) =>
981
+ p.charAt(0) === '.'
982
+ ? ''
983
+ : options.dot
984
+ ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))'
985
+ : '(?!\\.)';
986
+
987
+
988
+ const clearStateChar = () => {
989
+ if (stateChar) {
990
+ // we had some state-tracking character
991
+ // that wasn't consumed by this pass.
992
+ switch (stateChar) {
993
+ case '*':
994
+ re += star;
995
+ hasMagic = true;
996
+ break
997
+ case '?':
998
+ re += qmark;
999
+ hasMagic = true;
1000
+ break
1001
+ default:
1002
+ re += '\\' + stateChar;
1003
+ break
1004
+ }
1005
+ this.debug('clearStateChar %j %j', stateChar, re);
1006
+ stateChar = false;
1007
+ }
1008
+ };
1009
+
1010
+ for (let i = 0, c; (i < pattern.length) && (c = pattern.charAt(i)); i++) {
1011
+ this.debug('%s\t%s %s %j', pattern, i, re, c);
1012
+
1013
+ // skip over any that are escaped.
1014
+ if (escaping) {
1015
+ /* istanbul ignore next - completely not allowed, even escaped. */
1016
+ if (c === '/') {
1017
+ return false
1306
1018
  }
1307
- // We need to calculate the body *twice* if it's a repeat pattern
1308
- // at the start, once in nodot mode, then again in dot mode, so a
1309
- // pattern like *(?) can match 'x.y'
1310
- const repeated = this.type === '*' || this.type === '+';
1311
- // some kind of extglob
1312
- const start = this.type === '!' ? '(?:(?!(?:' : '(?:';
1313
- let body = this.#partsToRegExp(dot);
1314
- if (this.isStart() && this.isEnd() && !body && this.type !== '!') {
1315
- // invalid extglob, has to at least be *something* present, if it's
1316
- // the entire path portion.
1317
- const s = this.toString();
1318
- const me = this;
1319
- me.#parts = [s];
1320
- me.type = null;
1321
- me.#hasMagic = undefined;
1322
- return [s, (0, unescape_js_1.unescape)(this.toString()), false, false];
1323
- }
1324
- let bodyDotAllowed = !repeated || allowDot || dot || !startNoDot ?
1325
- ''
1326
- : this.#partsToRegExp(true);
1327
- if (bodyDotAllowed === body) {
1328
- bodyDotAllowed = '';
1329
- }
1330
- if (bodyDotAllowed) {
1331
- body = `(?:${body})(?:${bodyDotAllowed})*?`;
1332
- }
1333
- // an empty !() is exactly equivalent to a starNoEmpty
1334
- let final = '';
1335
- if (this.type === '!' && this.#emptyExt) {
1336
- final = (this.isStart() && !dot ? startNoDot : '') + starNoEmpty;
1019
+
1020
+ if (reSpecials[c]) {
1021
+ re += '\\';
1337
1022
  }
1338
- else {
1339
- const close = this.type === '!' ?
1340
- // !() must match something,but !(x) can match ''
1341
- '))' +
1342
- (this.isStart() && !dot && !allowDot ? startNoDot : '') +
1343
- star +
1344
- ')'
1345
- : this.type === '@' ? ')'
1346
- : this.type === '?' ? ')?'
1347
- : this.type === '+' && bodyDotAllowed ? ')'
1348
- : this.type === '*' && bodyDotAllowed ? `)?`
1349
- : `)${this.type}`;
1350
- final = start + body + close;
1023
+ re += c;
1024
+ escaping = false;
1025
+ continue
1026
+ }
1027
+
1028
+ switch (c) {
1029
+ /* istanbul ignore next */
1030
+ case '/': {
1031
+ // Should already be path-split by now.
1032
+ return false
1351
1033
  }
1352
- return [
1353
- final,
1354
- (0, unescape_js_1.unescape)(body),
1355
- (this.#hasMagic = !!this.#hasMagic),
1356
- this.#uflag,
1357
- ];
1034
+
1035
+ case '\\':
1036
+ if (inClass && pattern.charAt(i + 1) === '-') {
1037
+ re += c;
1038
+ continue
1039
+ }
1040
+
1041
+ clearStateChar();
1042
+ escaping = true;
1043
+ continue
1044
+
1045
+ // the various stateChar values
1046
+ // for the "extglob" stuff.
1047
+ case '?':
1048
+ case '*':
1049
+ case '+':
1050
+ case '@':
1051
+ case '!':
1052
+ this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c);
1053
+
1054
+ // all of those are literals inside a class, except that
1055
+ // the glob [!a] means [^a] in regexp
1056
+ if (inClass) {
1057
+ this.debug(' in class');
1058
+ if (c === '!' && i === classStart + 1) c = '^';
1059
+ re += c;
1060
+ continue
1061
+ }
1062
+
1063
+ // coalesce consecutive non-globstar * characters
1064
+ if (c === '*' && stateChar === '*') continue
1065
+
1066
+ // if we already have a stateChar, then it means
1067
+ // that there was something like ** or +? in there.
1068
+ // Handle the stateChar, then proceed with this one.
1069
+ this.debug('call clearStateChar %j', stateChar);
1070
+ clearStateChar();
1071
+ stateChar = c;
1072
+ // if extglob is disabled, then +(asdf|foo) isn't a thing.
1073
+ // just clear the statechar *now*, rather than even diving into
1074
+ // the patternList stuff.
1075
+ if (options.noext) clearStateChar();
1076
+ continue
1077
+
1078
+ case '(': {
1079
+ if (inClass) {
1080
+ re += '(';
1081
+ continue
1082
+ }
1083
+
1084
+ if (!stateChar) {
1085
+ re += '\\(';
1086
+ continue
1087
+ }
1088
+
1089
+ const plEntry = {
1090
+ type: stateChar,
1091
+ start: i - 1,
1092
+ reStart: re.length,
1093
+ open: plTypes[stateChar].open,
1094
+ close: plTypes[stateChar].close,
1095
+ };
1096
+ this.debug(this.pattern, '\t', plEntry);
1097
+ patternListStack.push(plEntry);
1098
+ // negation is (?:(?!(?:js)(?:<rest>))[^/]*)
1099
+ re += plEntry.open;
1100
+ // next entry starts with a dot maybe?
1101
+ if (plEntry.start === 0 && plEntry.type !== '!') {
1102
+ dotTravAllowed = true;
1103
+ re += subPatternStart(pattern.slice(i + 1));
1104
+ }
1105
+ this.debug('plType %j %j', stateChar, re);
1106
+ stateChar = false;
1107
+ continue
1108
+ }
1109
+
1110
+ case ')': {
1111
+ const plEntry = patternListStack[patternListStack.length - 1];
1112
+ if (inClass || !plEntry) {
1113
+ re += '\\)';
1114
+ continue
1115
+ }
1116
+ patternListStack.pop();
1117
+
1118
+ // closing an extglob
1119
+ clearStateChar();
1120
+ hasMagic = true;
1121
+ pl = plEntry;
1122
+ // negation is (?:(?!js)[^/]*)
1123
+ // The others are (?:<pattern>)<type>
1124
+ re += pl.close;
1125
+ if (pl.type === '!') {
1126
+ negativeLists.push(Object.assign(pl, { reEnd: re.length }));
1127
+ }
1128
+ continue
1129
+ }
1130
+
1131
+ case '|': {
1132
+ const plEntry = patternListStack[patternListStack.length - 1];
1133
+ if (inClass || !plEntry) {
1134
+ re += '\\|';
1135
+ continue
1136
+ }
1137
+
1138
+ clearStateChar();
1139
+ re += '|';
1140
+ // next subpattern can start with a dot?
1141
+ if (plEntry.start === 0 && plEntry.type !== '!') {
1142
+ dotTravAllowed = true;
1143
+ re += subPatternStart(pattern.slice(i + 1));
1144
+ }
1145
+ continue
1146
+ }
1147
+
1148
+ // these are mostly the same in regexp and glob
1149
+ case '[':
1150
+ // swallow any state-tracking char before the [
1151
+ clearStateChar();
1152
+
1153
+ if (inClass) {
1154
+ re += '\\' + c;
1155
+ continue
1156
+ }
1157
+
1158
+ inClass = true;
1159
+ classStart = i;
1160
+ reClassStart = re.length;
1161
+ re += c;
1162
+ continue
1163
+
1164
+ case ']':
1165
+ // a right bracket shall lose its special
1166
+ // meaning and represent itself in
1167
+ // a bracket expression if it occurs
1168
+ // first in the list. -- POSIX.2 2.8.3.2
1169
+ if (i === classStart + 1 || !inClass) {
1170
+ re += '\\' + c;
1171
+ continue
1172
+ }
1173
+
1174
+ // split where the last [ was, make sure we don't have
1175
+ // an invalid re. if so, re-walk the contents of the
1176
+ // would-be class to re-translate any characters that
1177
+ // were passed through as-is
1178
+ // TODO: It would probably be faster to determine this
1179
+ // without a try/catch and a new RegExp, but it's tricky
1180
+ // to do safely. For now, this is safe and works.
1181
+ cs = pattern.substring(classStart + 1, i);
1182
+ try {
1183
+ RegExp('[' + braExpEscape(charUnescape(cs)) + ']');
1184
+ // looks good, finish up the class.
1185
+ re += c;
1186
+ } catch (er) {
1187
+ // out of order ranges in JS are errors, but in glob syntax,
1188
+ // they're just a range that matches nothing.
1189
+ re = re.substring(0, reClassStart) + '(?:$.)'; // match nothing ever
1190
+ }
1191
+ hasMagic = true;
1192
+ inClass = false;
1193
+ continue
1194
+
1195
+ default:
1196
+ // swallow any state char that wasn't consumed
1197
+ clearStateChar();
1198
+
1199
+ if (reSpecials[c] && !(c === '^' && inClass)) {
1200
+ re += '\\';
1201
+ }
1202
+
1203
+ re += c;
1204
+ break
1205
+
1206
+ } // switch
1207
+ } // for
1208
+
1209
+ // handle the case where we left a class open.
1210
+ // "[abc" is valid, equivalent to "\[abc"
1211
+ if (inClass) {
1212
+ // split where the last [ was, and escape it
1213
+ // this is a huge pita. We now have to re-walk
1214
+ // the contents of the would-be class to re-translate
1215
+ // any characters that were passed through as-is
1216
+ cs = pattern.slice(classStart + 1);
1217
+ sp = this.parse(cs, SUBPARSE);
1218
+ re = re.substring(0, reClassStart) + '\\[' + sp[0];
1219
+ hasMagic = hasMagic || sp[1];
1220
+ }
1221
+
1222
+ // handle the case where we had a +( thing at the *end*
1223
+ // of the pattern.
1224
+ // each pattern list stack adds 3 chars, and we need to go through
1225
+ // and escape any | chars that were passed through as-is for the regexp.
1226
+ // Go through and escape them, taking care not to double-escape any
1227
+ // | chars that were already escaped.
1228
+ for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
1229
+ let tail;
1230
+ tail = re.slice(pl.reStart + pl.open.length);
1231
+ this.debug('setting tail', re, pl);
1232
+ // maybe some even number of \, then maybe 1 \, followed by a |
1233
+ tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, (_, $1, $2) => {
1234
+ /* istanbul ignore else - should already be done */
1235
+ if (!$2) {
1236
+ // the | isn't already escaped, so escape it.
1237
+ $2 = '\\';
1238
+ }
1239
+
1240
+ // need to escape all those slashes *again*, without escaping the
1241
+ // one that we need for escaping the | character. As it works out,
1242
+ // escaping an even number of slashes can be done by simply repeating
1243
+ // it exactly after itself. That's why this trick works.
1244
+ //
1245
+ // I am sorry that you have to see this.
1246
+ return $1 + $1 + $2 + '|'
1247
+ });
1248
+
1249
+ this.debug('tail=%j\n %s', tail, tail, pl, re);
1250
+ const t = pl.type === '*' ? star
1251
+ : pl.type === '?' ? qmark
1252
+ : '\\' + pl.type;
1253
+
1254
+ hasMagic = true;
1255
+ re = re.slice(0, pl.reStart) + t + '\\(' + tail;
1256
+ }
1257
+
1258
+ // handle trailing things that only matter at the very end.
1259
+ clearStateChar();
1260
+ if (escaping) {
1261
+ // trailing \\
1262
+ re += '\\\\';
1263
+ }
1264
+
1265
+ // only need to apply the nodot start if the re starts with
1266
+ // something that could conceivably capture a dot
1267
+ const addPatternStart = addPatternStartSet[re.charAt(0)];
1268
+
1269
+ // Hack to work around lack of negative lookbehind in JS
1270
+ // A pattern like: *.!(x).!(y|z) needs to ensure that a name
1271
+ // like 'a.xyz.yz' doesn't match. So, the first negative
1272
+ // lookahead, has to look ALL the way ahead, to the end of
1273
+ // the pattern.
1274
+ for (let n = negativeLists.length - 1; n > -1; n--) {
1275
+ const nl = negativeLists[n];
1276
+
1277
+ const nlBefore = re.slice(0, nl.reStart);
1278
+ const nlFirst = re.slice(nl.reStart, nl.reEnd - 8);
1279
+ let nlAfter = re.slice(nl.reEnd);
1280
+ const nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + nlAfter;
1281
+
1282
+ // Handle nested stuff like *(*.js|!(*.json)), where open parens
1283
+ // mean that we should *not* include the ) in the bit that is considered
1284
+ // "after" the negated section.
1285
+ const closeParensBefore = nlBefore.split(')').length;
1286
+ const openParensBefore = nlBefore.split('(').length - closeParensBefore;
1287
+ let cleanAfter = nlAfter;
1288
+ for (let i = 0; i < openParensBefore; i++) {
1289
+ cleanAfter = cleanAfter.replace(/\)[+*?]?/, '');
1290
+ }
1291
+ nlAfter = cleanAfter;
1292
+
1293
+ const dollar = nlAfter === '' && isSub !== SUBPARSE ? '(?:$|\\/)' : '';
1294
+
1295
+ re = nlBefore + nlFirst + nlAfter + dollar + nlLast;
1296
+ }
1297
+
1298
+ // if the re is not "" at this point, then we need to make sure
1299
+ // it doesn't match against an empty path part.
1300
+ // Otherwise a/* will match a/, which it should not.
1301
+ if (re !== '' && hasMagic) {
1302
+ re = '(?=.)' + re;
1303
+ }
1304
+
1305
+ if (addPatternStart) {
1306
+ re = patternStart() + re;
1307
+ }
1308
+
1309
+ // parsing just a piece of a larger pattern.
1310
+ if (isSub === SUBPARSE) {
1311
+ return [re, hasMagic]
1312
+ }
1313
+
1314
+ // if it's nocase, and the lcase/uppercase don't match, it's magic
1315
+ if (options.nocase && !hasMagic) {
1316
+ hasMagic = pattern.toUpperCase() !== pattern.toLowerCase();
1317
+ }
1318
+
1319
+ // skip the regexp for non-magical patterns
1320
+ // unescape anything in it, though, so that it'll be
1321
+ // an exact match against a file etc.
1322
+ if (!hasMagic) {
1323
+ return globUnescape(pattern)
1358
1324
  }
1359
- #flatten() {
1360
- if (!isExtglobAST(this)) {
1361
- for (const p of this.#parts) {
1362
- if (typeof p === 'object') {
1363
- p.#flatten();
1364
- }
1365
- }
1366
- }
1367
- else {
1368
- // do up to 10 passes to flatten as much as possible
1369
- let iterations = 0;
1370
- let done = false;
1371
- do {
1372
- done = true;
1373
- for (let i = 0; i < this.#parts.length; i++) {
1374
- const c = this.#parts[i];
1375
- if (typeof c === 'object') {
1376
- c.#flatten();
1377
- if (this.#canAdopt(c)) {
1378
- done = false;
1379
- this.#adopt(c, i);
1380
- }
1381
- else if (this.#canAdoptWithSpace(c)) {
1382
- done = false;
1383
- this.#adoptWithSpace(c, i);
1384
- }
1385
- else if (this.#canUsurp(c)) {
1386
- done = false;
1387
- this.#usurp(c);
1388
- }
1389
- }
1390
- }
1391
- } while (!done && ++iterations < 10);
1392
- }
1393
- this.#toString = undefined;
1394
- }
1395
- #partsToRegExp(dot) {
1396
- return this.#parts
1397
- .map(p => {
1398
- // extglob ASTs should only contain parent ASTs
1399
- /* c8 ignore start */
1400
- if (typeof p === 'string') {
1401
- throw new Error('string type in extglob ast??');
1402
- }
1403
- /* c8 ignore stop */
1404
- // can ignore hasMagic, because extglobs are already always magic
1405
- const [re, _, _hasMagic, uflag] = p.toRegExpSource(dot);
1406
- this.#uflag = this.#uflag || uflag;
1407
- return re;
1408
- })
1409
- .filter(p => !(this.isStart() && this.isEnd()) || !!p)
1410
- .join('|');
1411
- }
1412
- static #parseGlob(glob, hasMagic, noEmpty = false) {
1413
- let escaping = false;
1414
- let re = '';
1415
- let uflag = false;
1416
- // multiple stars that aren't globstars coalesce into one *
1417
- let inStar = false;
1418
- for (let i = 0; i < glob.length; i++) {
1419
- const c = glob.charAt(i);
1420
- if (escaping) {
1421
- escaping = false;
1422
- re += (reSpecials.has(c) ? '\\' : '') + c;
1423
- continue;
1424
- }
1425
- if (c === '*') {
1426
- if (inStar)
1427
- continue;
1428
- inStar = true;
1429
- re += noEmpty && /^[*]+$/.test(glob) ? starNoEmpty : star;
1430
- hasMagic = true;
1431
- continue;
1432
- }
1433
- else {
1434
- inStar = false;
1435
- }
1436
- if (c === '\\') {
1437
- if (i === glob.length - 1) {
1438
- re += '\\\\';
1439
- }
1440
- else {
1441
- escaping = true;
1442
- }
1443
- continue;
1444
- }
1445
- if (c === '[') {
1446
- const [src, needUflag, consumed, magic] = (0, brace_expressions_js_1.parseClass)(glob, i);
1447
- if (consumed) {
1448
- re += src;
1449
- uflag = uflag || needUflag;
1450
- i += consumed - 1;
1451
- hasMagic = hasMagic || magic;
1452
- continue;
1453
- }
1454
- }
1455
- if (c === '?') {
1456
- re += qmark;
1457
- hasMagic = true;
1458
- continue;
1459
- }
1460
- re += regExpEscape(c);
1325
+
1326
+ const flags = options.nocase ? 'i' : '';
1327
+ try {
1328
+ return Object.assign(new RegExp('^' + re + '$', flags), {
1329
+ _glob: pattern,
1330
+ _src: re,
1331
+ })
1332
+ } catch (er) /* istanbul ignore next - should be impossible */ {
1333
+ // If it was an invalid regular expression, then it can't match
1334
+ // anything. This trick looks for a character after the end of
1335
+ // the string, which is of course impossible, except in multi-line
1336
+ // mode, but it's not a /m regex.
1337
+ return new RegExp('$.')
1338
+ }
1339
+ }
1340
+
1341
+ makeRe () {
1342
+ if (this.regexp || this.regexp === false) return this.regexp
1343
+
1344
+ // at this point, this.set is a 2d array of partial
1345
+ // pattern strings, or "**".
1346
+ //
1347
+ // It's better to use .match(). This function shouldn't
1348
+ // be used, really, but it's pretty convenient sometimes,
1349
+ // when you just want to work with a regex.
1350
+ const set = this.set;
1351
+
1352
+ if (!set.length) {
1353
+ this.regexp = false;
1354
+ return this.regexp
1355
+ }
1356
+ const options = this.options;
1357
+
1358
+ const twoStar = options.noglobstar ? star
1359
+ : options.dot ? twoStarDot
1360
+ : twoStarNoDot;
1361
+ const flags = options.nocase ? 'i' : '';
1362
+
1363
+ // coalesce globstars and regexpify non-globstar patterns
1364
+ // if it's the only item, then we just do one twoStar
1365
+ // if it's the first, and there are more, prepend (\/|twoStar\/)? to next
1366
+ // if it's the last, append (\/twoStar|) to previous
1367
+ // if it's in the middle, append (\/|\/twoStar\/) to previous
1368
+ // then filter out GLOBSTAR symbols
1369
+ let re = set.map(pattern => {
1370
+ pattern = pattern.map(p =>
1371
+ typeof p === 'string' ? regExpEscape(p)
1372
+ : p === GLOBSTAR ? GLOBSTAR
1373
+ : p._src
1374
+ ).reduce((set, p) => {
1375
+ if (!(set[set.length - 1] === GLOBSTAR && p === GLOBSTAR)) {
1376
+ set.push(p);
1377
+ }
1378
+ return set
1379
+ }, []);
1380
+ pattern.forEach((p, i) => {
1381
+ if (p !== GLOBSTAR || pattern[i-1] === GLOBSTAR) {
1382
+ return
1383
+ }
1384
+ if (i === 0) {
1385
+ if (pattern.length > 1) {
1386
+ pattern[i+1] = '(?:\\\/|' + twoStar + '\\\/)?' + pattern[i+1];
1387
+ } else {
1388
+ pattern[i] = twoStar;
1389
+ }
1390
+ } else if (i === pattern.length - 1) {
1391
+ pattern[i-1] += '(?:\\\/|' + twoStar + ')?';
1392
+ } else {
1393
+ pattern[i-1] += '(?:\\\/|\\\/' + twoStar + '\\\/)' + pattern[i+1];
1394
+ pattern[i+1] = GLOBSTAR;
1461
1395
  }
1462
- return [re, (0, unescape_js_1.unescape)(glob), !!hasMagic, uflag];
1396
+ });
1397
+ return pattern.filter(p => p !== GLOBSTAR).join('/')
1398
+ }).join('|');
1399
+
1400
+ // must match entire pattern
1401
+ // ending in a * or ** will make it less strict.
1402
+ re = '^(?:' + re + ')$';
1403
+
1404
+ // can match anything, as long as it's not this.
1405
+ if (this.negate) re = '^(?!' + re + ').*$';
1406
+
1407
+ try {
1408
+ this.regexp = new RegExp(re, flags);
1409
+ } catch (ex) /* istanbul ignore next - should be impossible */ {
1410
+ this.regexp = false;
1463
1411
  }
1464
- }
1465
- ast.AST = AST;
1466
- _a = AST;
1467
-
1468
- return ast;
1469
- }
1412
+ return this.regexp
1413
+ }
1470
1414
 
1471
- var _escape = {};
1415
+ match (f, partial = this.partial) {
1416
+ this.debug('match', f, this.pattern);
1417
+ // short-circuit in the case of busted things.
1418
+ // comments, etc.
1419
+ if (this.comment) return false
1420
+ if (this.empty) return f === ''
1472
1421
 
1473
- var hasRequired_escape;
1422
+ if (f === '/' && partial) return true
1474
1423
 
1475
- function require_escape () {
1476
- if (hasRequired_escape) return _escape;
1477
- hasRequired_escape = 1;
1478
- Object.defineProperty(_escape, "__esModule", { value: true });
1479
- _escape.escape = void 0;
1480
- /**
1481
- * Escape all magic characters in a glob pattern.
1482
- *
1483
- * If the {@link MinimatchOptions.windowsPathsNoEscape}
1484
- * option is used, then characters are escaped by wrapping in `[]`, because
1485
- * a magic character wrapped in a character class can only be satisfied by
1486
- * that exact character. In this mode, `\` is _not_ escaped, because it is
1487
- * not interpreted as a magic character, but instead as a path separator.
1488
- *
1489
- * If the {@link MinimatchOptions.magicalBraces} option is used,
1490
- * then braces (`{` and `}`) will be escaped.
1491
- */
1492
- const escape = (s, { windowsPathsNoEscape = false, magicalBraces = false, } = {}) => {
1493
- // don't need to escape +@! because we escape the parens
1494
- // that make those magic, and escaping ! as [!] isn't valid,
1495
- // because [!]] is a valid glob class meaning not ']'.
1496
- if (magicalBraces) {
1497
- return windowsPathsNoEscape ?
1498
- s.replace(/[?*()[\]{}]/g, '[$&]')
1499
- : s.replace(/[?*()[\]\\{}]/g, '\\$&');
1500
- }
1501
- return windowsPathsNoEscape ?
1502
- s.replace(/[?*()[\]]/g, '[$&]')
1503
- : s.replace(/[?*()[\]\\]/g, '\\$&');
1504
- };
1505
- _escape.escape = escape;
1506
-
1507
- return _escape;
1508
- }
1424
+ const options = this.options;
1509
1425
 
1510
- var hasRequiredCommonjs;
1426
+ // windows: need to use /, not \
1427
+ if (path.sep !== '/') {
1428
+ f = f.split(path.sep).join('/');
1429
+ }
1511
1430
 
1512
- function requireCommonjs () {
1513
- if (hasRequiredCommonjs) return commonjs$2;
1514
- hasRequiredCommonjs = 1;
1515
- (function (exports) {
1516
- Object.defineProperty(exports, "__esModule", { value: true });
1517
- exports.unescape = exports.escape = exports.AST = exports.Minimatch = exports.match = exports.makeRe = exports.braceExpand = exports.defaults = exports.filter = exports.GLOBSTAR = exports.sep = exports.minimatch = void 0;
1518
- const brace_expansion_1 = requireCommonjs$1();
1519
- const assert_valid_pattern_js_1 = requireAssertValidPattern();
1520
- const ast_js_1 = requireAst();
1521
- const escape_js_1 = require_escape();
1522
- const unescape_js_1 = require_unescape();
1523
- const minimatch = (p, pattern, options = {}) => {
1524
- (0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
1525
- // shortcut: comments match nothing.
1526
- if (!options.nocomment && pattern.charAt(0) === '#') {
1527
- return false;
1528
- }
1529
- return new Minimatch(pattern, options).match(p);
1530
- };
1531
- exports.minimatch = minimatch;
1532
- // Optimized checking for the most common glob patterns.
1533
- const starDotExtRE = /^\*+([^+@!?*[(]*)$/;
1534
- const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext);
1535
- const starDotExtTestDot = (ext) => (f) => f.endsWith(ext);
1536
- const starDotExtTestNocase = (ext) => {
1537
- ext = ext.toLowerCase();
1538
- return (f) => !f.startsWith('.') && f.toLowerCase().endsWith(ext);
1539
- };
1540
- const starDotExtTestNocaseDot = (ext) => {
1541
- ext = ext.toLowerCase();
1542
- return (f) => f.toLowerCase().endsWith(ext);
1543
- };
1544
- const starDotStarRE = /^\*+\.\*+$/;
1545
- const starDotStarTest = (f) => !f.startsWith('.') && f.includes('.');
1546
- const starDotStarTestDot = (f) => f !== '.' && f !== '..' && f.includes('.');
1547
- const dotStarRE = /^\.\*+$/;
1548
- const dotStarTest = (f) => f !== '.' && f !== '..' && f.startsWith('.');
1549
- const starRE = /^\*+$/;
1550
- const starTest = (f) => f.length !== 0 && !f.startsWith('.');
1551
- const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..';
1552
- const qmarksRE = /^\?+([^+@!?*[(]*)?$/;
1553
- const qmarksTestNocase = ([$0, ext = '']) => {
1554
- const noext = qmarksTestNoExt([$0]);
1555
- if (!ext)
1556
- return noext;
1557
- ext = ext.toLowerCase();
1558
- return (f) => noext(f) && f.toLowerCase().endsWith(ext);
1559
- };
1560
- const qmarksTestNocaseDot = ([$0, ext = '']) => {
1561
- const noext = qmarksTestNoExtDot([$0]);
1562
- if (!ext)
1563
- return noext;
1564
- ext = ext.toLowerCase();
1565
- return (f) => noext(f) && f.toLowerCase().endsWith(ext);
1566
- };
1567
- const qmarksTestDot = ([$0, ext = '']) => {
1568
- const noext = qmarksTestNoExtDot([$0]);
1569
- return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
1570
- };
1571
- const qmarksTest = ([$0, ext = '']) => {
1572
- const noext = qmarksTestNoExt([$0]);
1573
- return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
1574
- };
1575
- const qmarksTestNoExt = ([$0]) => {
1576
- const len = $0.length;
1577
- return (f) => f.length === len && !f.startsWith('.');
1578
- };
1579
- const qmarksTestNoExtDot = ([$0]) => {
1580
- const len = $0.length;
1581
- return (f) => f.length === len && f !== '.' && f !== '..';
1582
- };
1583
- /* c8 ignore start */
1584
- const defaultPlatform = (typeof process === 'object' && process ?
1585
- (typeof process.env === 'object' &&
1586
- process.env &&
1587
- process.env.__MINIMATCH_TESTING_PLATFORM__) ||
1588
- process.platform
1589
- : 'posix');
1590
- const path = {
1591
- win32: { sep: '\\' },
1592
- posix: { sep: '/' },
1593
- };
1594
- /* c8 ignore stop */
1595
- exports.sep = defaultPlatform === 'win32' ? path.win32.sep : path.posix.sep;
1596
- exports.minimatch.sep = exports.sep;
1597
- exports.GLOBSTAR = Symbol('globstar **');
1598
- exports.minimatch.GLOBSTAR = exports.GLOBSTAR;
1599
- // any single thing other than /
1600
- // don't need to escape / when using new RegExp()
1601
- const qmark = '[^/]';
1602
- // * => any number of characters
1603
- const star = qmark + '*?';
1604
- // ** when dots are allowed. Anything goes, except .. and .
1605
- // not (^ or / followed by one or two dots followed by $ or /),
1606
- // followed by anything, any number of times.
1607
- const twoStarDot = '(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?';
1608
- // not a ^ or / followed by a dot,
1609
- // followed by anything, any number of times.
1610
- const twoStarNoDot = '(?:(?!(?:\\/|^)\\.).)*?';
1611
- const filter = (pattern, options = {}) => (p) => (0, exports.minimatch)(p, pattern, options);
1612
- exports.filter = filter;
1613
- exports.minimatch.filter = exports.filter;
1614
- const ext = (a, b = {}) => Object.assign({}, a, b);
1615
- const defaults = (def) => {
1616
- if (!def || typeof def !== 'object' || !Object.keys(def).length) {
1617
- return exports.minimatch;
1618
- }
1619
- const orig = exports.minimatch;
1620
- const m = (p, pattern, options = {}) => orig(p, pattern, ext(def, options));
1621
- return Object.assign(m, {
1622
- Minimatch: class Minimatch extends orig.Minimatch {
1623
- constructor(pattern, options = {}) {
1624
- super(pattern, ext(def, options));
1625
- }
1626
- static defaults(options) {
1627
- return orig.defaults(ext(def, options)).Minimatch;
1628
- }
1629
- },
1630
- AST: class AST extends orig.AST {
1631
- /* c8 ignore start */
1632
- constructor(type, parent, options = {}) {
1633
- super(type, parent, ext(def, options));
1634
- }
1635
- /* c8 ignore stop */
1636
- static fromGlob(pattern, options = {}) {
1637
- return orig.AST.fromGlob(pattern, ext(def, options));
1638
- }
1639
- },
1640
- unescape: (s, options = {}) => orig.unescape(s, ext(def, options)),
1641
- escape: (s, options = {}) => orig.escape(s, ext(def, options)),
1642
- filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)),
1643
- defaults: (options) => orig.defaults(ext(def, options)),
1644
- makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)),
1645
- braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)),
1646
- match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)),
1647
- sep: orig.sep,
1648
- GLOBSTAR: exports.GLOBSTAR,
1649
- });
1650
- };
1651
- exports.defaults = defaults;
1652
- exports.minimatch.defaults = exports.defaults;
1653
- // Brace expansion:
1654
- // a{b,c}d -> abd acd
1655
- // a{b,}c -> abc ac
1656
- // a{0..3}d -> a0d a1d a2d a3d
1657
- // a{b,c{d,e}f}g -> abg acdfg acefg
1658
- // a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg
1659
- //
1660
- // Invalid sets are not expanded.
1661
- // a{2..}b -> a{2..}b
1662
- // a{b}c -> a{b}c
1663
- const braceExpand = (pattern, options = {}) => {
1664
- (0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
1665
- // Thanks to Yeting Li <https://github.com/yetingli> for
1666
- // improving this regexp to avoid a ReDOS vulnerability.
1667
- if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
1668
- // shortcut. no need to expand.
1669
- return [pattern];
1670
- }
1671
- return (0, brace_expansion_1.expand)(pattern, { max: options.braceExpandMax });
1672
- };
1673
- exports.braceExpand = braceExpand;
1674
- exports.minimatch.braceExpand = exports.braceExpand;
1675
- // parse a component of the expanded set.
1676
- // At this point, no pattern may contain "/" in it
1677
- // so we're going to return a 2d array, where each entry is the full
1678
- // pattern, split on '/', and then turned into a regular expression.
1679
- // A regexp is made at the end which joins each array with an
1680
- // escaped /, and another full one which joins each regexp with |.
1681
- //
1682
- // Following the lead of Bash 4.1, note that "**" only has special meaning
1683
- // when it is the *only* thing in a path portion. Otherwise, any series
1684
- // of * is equivalent to a single *. Globstar behavior is enabled by
1685
- // default, and can be disabled by setting options.noglobstar.
1686
- const makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
1687
- exports.makeRe = makeRe;
1688
- exports.minimatch.makeRe = exports.makeRe;
1689
- const match = (list, pattern, options = {}) => {
1690
- const mm = new Minimatch(pattern, options);
1691
- list = list.filter(f => mm.match(f));
1692
- if (mm.options.nonull && !list.length) {
1693
- list.push(pattern);
1694
- }
1695
- return list;
1696
- };
1697
- exports.match = match;
1698
- exports.minimatch.match = exports.match;
1699
- // replace stuff like \* with *
1700
- const globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/;
1701
- const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
1702
- class Minimatch {
1703
- options;
1704
- set;
1705
- pattern;
1706
- windowsPathsNoEscape;
1707
- nonegate;
1708
- negate;
1709
- comment;
1710
- empty;
1711
- preserveMultipleSlashes;
1712
- partial;
1713
- globSet;
1714
- globParts;
1715
- nocase;
1716
- isWindows;
1717
- platform;
1718
- windowsNoMagicRoot;
1719
- maxGlobstarRecursion;
1720
- regexp;
1721
- constructor(pattern, options = {}) {
1722
- (0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
1723
- options = options || {};
1724
- this.options = options;
1725
- this.maxGlobstarRecursion = options.maxGlobstarRecursion ?? 200;
1726
- this.pattern = pattern;
1727
- this.platform = options.platform || defaultPlatform;
1728
- this.isWindows = this.platform === 'win32';
1729
- // avoid the annoying deprecation flag lol
1730
- const awe = ('allowWindow' + 'sEscape');
1731
- this.windowsPathsNoEscape =
1732
- !!options.windowsPathsNoEscape || options[awe] === false;
1733
- if (this.windowsPathsNoEscape) {
1734
- this.pattern = this.pattern.replace(/\\/g, '/');
1735
- }
1736
- this.preserveMultipleSlashes = !!options.preserveMultipleSlashes;
1737
- this.regexp = null;
1738
- this.negate = false;
1739
- this.nonegate = !!options.nonegate;
1740
- this.comment = false;
1741
- this.empty = false;
1742
- this.partial = !!options.partial;
1743
- this.nocase = !!this.options.nocase;
1744
- this.windowsNoMagicRoot =
1745
- options.windowsNoMagicRoot !== undefined ?
1746
- options.windowsNoMagicRoot
1747
- : !!(this.isWindows && this.nocase);
1748
- this.globSet = [];
1749
- this.globParts = [];
1750
- this.set = [];
1751
- // make the set of regexps etc.
1752
- this.make();
1753
- }
1754
- hasMagic() {
1755
- if (this.options.magicalBraces && this.set.length > 1) {
1756
- return true;
1757
- }
1758
- for (const pattern of this.set) {
1759
- for (const part of pattern) {
1760
- if (typeof part !== 'string')
1761
- return true;
1762
- }
1763
- }
1764
- return false;
1765
- }
1766
- debug(..._) { }
1767
- make() {
1768
- const pattern = this.pattern;
1769
- const options = this.options;
1770
- // empty patterns and comments match nothing.
1771
- if (!options.nocomment && pattern.charAt(0) === '#') {
1772
- this.comment = true;
1773
- return;
1774
- }
1775
- if (!pattern) {
1776
- this.empty = true;
1777
- return;
1778
- }
1779
- // step 1: figure out negation, etc.
1780
- this.parseNegate();
1781
- // step 2: expand braces
1782
- this.globSet = [...new Set(this.braceExpand())];
1783
- if (options.debug) {
1784
- //oxlint-disable-next-line no-console
1785
- this.debug = (...args) => console.error(...args);
1786
- }
1787
- this.debug(this.pattern, this.globSet);
1788
- // step 3: now we have a set, so turn each one into a series of
1789
- // path-portion matching patterns.
1790
- // These will be regexps, except in the case of "**", which is
1791
- // set to the GLOBSTAR object for globstar behavior,
1792
- // and will not contain any / characters
1793
- //
1794
- // First, we preprocess to make the glob pattern sets a bit simpler
1795
- // and deduped. There are some perf-killing patterns that can cause
1796
- // problems with a glob walk, but we can simplify them down a bit.
1797
- const rawGlobParts = this.globSet.map(s => this.slashSplit(s));
1798
- this.globParts = this.preprocess(rawGlobParts);
1799
- this.debug(this.pattern, this.globParts);
1800
- // glob --> regexps
1801
- let set = this.globParts.map((s, _, __) => {
1802
- if (this.isWindows && this.windowsNoMagicRoot) {
1803
- // check if it's a drive or unc path.
1804
- const isUNC = s[0] === '' &&
1805
- s[1] === '' &&
1806
- (s[2] === '?' || !globMagic.test(s[2])) &&
1807
- !globMagic.test(s[3]);
1808
- const isDrive = /^[a-z]:/i.test(s[0]);
1809
- if (isUNC) {
1810
- return [
1811
- ...s.slice(0, 4),
1812
- ...s.slice(4).map(ss => this.parse(ss)),
1813
- ];
1814
- }
1815
- else if (isDrive) {
1816
- return [s[0], ...s.slice(1).map(ss => this.parse(ss))];
1817
- }
1818
- }
1819
- return s.map(ss => this.parse(ss));
1820
- });
1821
- this.debug(this.pattern, set);
1822
- // filter out everything that didn't compile properly.
1823
- this.set = set.filter(s => s.indexOf(false) === -1);
1824
- // do not treat the ? in UNC paths as magic
1825
- if (this.isWindows) {
1826
- for (let i = 0; i < this.set.length; i++) {
1827
- const p = this.set[i];
1828
- if (p[0] === '' &&
1829
- p[1] === '' &&
1830
- this.globParts[i][2] === '?' &&
1831
- typeof p[3] === 'string' &&
1832
- /^[a-z]:$/i.test(p[3])) {
1833
- p[2] = '?';
1834
- }
1835
- }
1836
- }
1837
- this.debug(this.pattern, this.set);
1838
- }
1839
- // various transforms to equivalent pattern sets that are
1840
- // faster to process in a filesystem walk. The goal is to
1841
- // eliminate what we can, and push all ** patterns as far
1842
- // to the right as possible, even if it increases the number
1843
- // of patterns that we have to process.
1844
- preprocess(globParts) {
1845
- // if we're not in globstar mode, then turn ** into *
1846
- if (this.options.noglobstar) {
1847
- for (const partset of globParts) {
1848
- for (let j = 0; j < partset.length; j++) {
1849
- if (partset[j] === '**') {
1850
- partset[j] = '*';
1851
- }
1852
- }
1853
- }
1854
- }
1855
- const { optimizationLevel = 1 } = this.options;
1856
- if (optimizationLevel >= 2) {
1857
- // aggressive optimization for the purpose of fs walking
1858
- globParts = this.firstPhasePreProcess(globParts);
1859
- globParts = this.secondPhasePreProcess(globParts);
1860
- }
1861
- else if (optimizationLevel >= 1) {
1862
- // just basic optimizations to remove some .. parts
1863
- globParts = this.levelOneOptimize(globParts);
1864
- }
1865
- else {
1866
- // just collapse multiple ** portions into one
1867
- globParts = this.adjascentGlobstarOptimize(globParts);
1868
- }
1869
- return globParts;
1870
- }
1871
- // just get rid of adjascent ** portions
1872
- adjascentGlobstarOptimize(globParts) {
1873
- return globParts.map(parts => {
1874
- let gs = -1;
1875
- while (-1 !== (gs = parts.indexOf('**', gs + 1))) {
1876
- let i = gs;
1877
- while (parts[i + 1] === '**') {
1878
- i++;
1879
- }
1880
- if (i !== gs) {
1881
- parts.splice(gs, i - gs);
1882
- }
1883
- }
1884
- return parts;
1885
- });
1886
- }
1887
- // get rid of adjascent ** and resolve .. portions
1888
- levelOneOptimize(globParts) {
1889
- return globParts.map(parts => {
1890
- parts = parts.reduce((set, part) => {
1891
- const prev = set[set.length - 1];
1892
- if (part === '**' && prev === '**') {
1893
- return set;
1894
- }
1895
- if (part === '..') {
1896
- if (prev && prev !== '..' && prev !== '.' && prev !== '**') {
1897
- set.pop();
1898
- return set;
1899
- }
1900
- }
1901
- set.push(part);
1902
- return set;
1903
- }, []);
1904
- return parts.length === 0 ? [''] : parts;
1905
- });
1906
- }
1907
- levelTwoFileOptimize(parts) {
1908
- if (!Array.isArray(parts)) {
1909
- parts = this.slashSplit(parts);
1910
- }
1911
- let didSomething = false;
1912
- do {
1913
- didSomething = false;
1914
- // <pre>/<e>/<rest> -> <pre>/<rest>
1915
- if (!this.preserveMultipleSlashes) {
1916
- for (let i = 1; i < parts.length - 1; i++) {
1917
- const p = parts[i];
1918
- // don't squeeze out UNC patterns
1919
- if (i === 1 && p === '' && parts[0] === '')
1920
- continue;
1921
- if (p === '.' || p === '') {
1922
- didSomething = true;
1923
- parts.splice(i, 1);
1924
- i--;
1925
- }
1926
- }
1927
- if (parts[0] === '.' &&
1928
- parts.length === 2 &&
1929
- (parts[1] === '.' || parts[1] === '')) {
1930
- didSomething = true;
1931
- parts.pop();
1932
- }
1933
- }
1934
- // <pre>/<p>/../<rest> -> <pre>/<rest>
1935
- let dd = 0;
1936
- while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
1937
- const p = parts[dd - 1];
1938
- if (p &&
1939
- p !== '.' &&
1940
- p !== '..' &&
1941
- p !== '**' &&
1942
- !(this.isWindows && /^[a-z]:$/i.test(p))) {
1943
- didSomething = true;
1944
- parts.splice(dd - 1, 2);
1945
- dd -= 2;
1946
- }
1947
- }
1948
- } while (didSomething);
1949
- return parts.length === 0 ? [''] : parts;
1950
- }
1951
- // First phase: single-pattern processing
1952
- // <pre> is 1 or more portions
1953
- // <rest> is 1 or more portions
1954
- // <p> is any portion other than ., .., '', or **
1955
- // <e> is . or ''
1956
- //
1957
- // **/.. is *brutal* for filesystem walking performance, because
1958
- // it effectively resets the recursive walk each time it occurs,
1959
- // and ** cannot be reduced out by a .. pattern part like a regexp
1960
- // or most strings (other than .., ., and '') can be.
1961
- //
1962
- // <pre>/**/../<p>/<p>/<rest> -> {<pre>/../<p>/<p>/<rest>,<pre>/**/<p>/<p>/<rest>}
1963
- // <pre>/<e>/<rest> -> <pre>/<rest>
1964
- // <pre>/<p>/../<rest> -> <pre>/<rest>
1965
- // **/**/<rest> -> **/<rest>
1966
- //
1967
- // **/*/<rest> -> */**/<rest> <== not valid because ** doesn't follow
1968
- // this WOULD be allowed if ** did follow symlinks, or * didn't
1969
- firstPhasePreProcess(globParts) {
1970
- let didSomething = false;
1971
- do {
1972
- didSomething = false;
1973
- // <pre>/**/../<p>/<p>/<rest> -> {<pre>/../<p>/<p>/<rest>,<pre>/**/<p>/<p>/<rest>}
1974
- for (let parts of globParts) {
1975
- let gs = -1;
1976
- while (-1 !== (gs = parts.indexOf('**', gs + 1))) {
1977
- let gss = gs;
1978
- while (parts[gss + 1] === '**') {
1979
- // <pre>/**/**/<rest> -> <pre>/**/<rest>
1980
- gss++;
1981
- }
1982
- // eg, if gs is 2 and gss is 4, that means we have 3 **
1983
- // parts, and can remove 2 of them.
1984
- if (gss > gs) {
1985
- parts.splice(gs + 1, gss - gs);
1986
- }
1987
- let next = parts[gs + 1];
1988
- const p = parts[gs + 2];
1989
- const p2 = parts[gs + 3];
1990
- if (next !== '..')
1991
- continue;
1992
- if (!p ||
1993
- p === '.' ||
1994
- p === '..' ||
1995
- !p2 ||
1996
- p2 === '.' ||
1997
- p2 === '..') {
1998
- continue;
1999
- }
2000
- didSomething = true;
2001
- // edit parts in place, and push the new one
2002
- parts.splice(gs, 1);
2003
- const other = parts.slice(0);
2004
- other[gs] = '**';
2005
- globParts.push(other);
2006
- gs--;
2007
- }
2008
- // <pre>/<e>/<rest> -> <pre>/<rest>
2009
- if (!this.preserveMultipleSlashes) {
2010
- for (let i = 1; i < parts.length - 1; i++) {
2011
- const p = parts[i];
2012
- // don't squeeze out UNC patterns
2013
- if (i === 1 && p === '' && parts[0] === '')
2014
- continue;
2015
- if (p === '.' || p === '') {
2016
- didSomething = true;
2017
- parts.splice(i, 1);
2018
- i--;
2019
- }
2020
- }
2021
- if (parts[0] === '.' &&
2022
- parts.length === 2 &&
2023
- (parts[1] === '.' || parts[1] === '')) {
2024
- didSomething = true;
2025
- parts.pop();
2026
- }
2027
- }
2028
- // <pre>/<p>/../<rest> -> <pre>/<rest>
2029
- let dd = 0;
2030
- while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
2031
- const p = parts[dd - 1];
2032
- if (p && p !== '.' && p !== '..' && p !== '**') {
2033
- didSomething = true;
2034
- const needDot = dd === 1 && parts[dd + 1] === '**';
2035
- const splin = needDot ? ['.'] : [];
2036
- parts.splice(dd - 1, 2, ...splin);
2037
- if (parts.length === 0)
2038
- parts.push('');
2039
- dd -= 2;
2040
- }
2041
- }
2042
- }
2043
- } while (didSomething);
2044
- return globParts;
2045
- }
2046
- // second phase: multi-pattern dedupes
2047
- // {<pre>/*/<rest>,<pre>/<p>/<rest>} -> <pre>/*/<rest>
2048
- // {<pre>/<rest>,<pre>/<rest>} -> <pre>/<rest>
2049
- // {<pre>/**/<rest>,<pre>/<rest>} -> <pre>/**/<rest>
2050
- //
2051
- // {<pre>/**/<rest>,<pre>/**/<p>/<rest>} -> <pre>/**/<rest>
2052
- // ^-- not valid because ** doens't follow symlinks
2053
- secondPhasePreProcess(globParts) {
2054
- for (let i = 0; i < globParts.length - 1; i++) {
2055
- for (let j = i + 1; j < globParts.length; j++) {
2056
- const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
2057
- if (matched) {
2058
- globParts[i] = [];
2059
- globParts[j] = matched;
2060
- break;
2061
- }
2062
- }
2063
- }
2064
- return globParts.filter(gs => gs.length);
2065
- }
2066
- partsMatch(a, b, emptyGSMatch = false) {
2067
- let ai = 0;
2068
- let bi = 0;
2069
- let result = [];
2070
- let which = '';
2071
- while (ai < a.length && bi < b.length) {
2072
- if (a[ai] === b[bi]) {
2073
- result.push(which === 'b' ? b[bi] : a[ai]);
2074
- ai++;
2075
- bi++;
2076
- }
2077
- else if (emptyGSMatch && a[ai] === '**' && b[bi] === a[ai + 1]) {
2078
- result.push(a[ai]);
2079
- ai++;
2080
- }
2081
- else if (emptyGSMatch && b[bi] === '**' && a[ai] === b[bi + 1]) {
2082
- result.push(b[bi]);
2083
- bi++;
2084
- }
2085
- else if (a[ai] === '*' &&
2086
- b[bi] &&
2087
- (this.options.dot || !b[bi].startsWith('.')) &&
2088
- b[bi] !== '**') {
2089
- if (which === 'b')
2090
- return false;
2091
- which = 'a';
2092
- result.push(a[ai]);
2093
- ai++;
2094
- bi++;
2095
- }
2096
- else if (b[bi] === '*' &&
2097
- a[ai] &&
2098
- (this.options.dot || !a[ai].startsWith('.')) &&
2099
- a[ai] !== '**') {
2100
- if (which === 'a')
2101
- return false;
2102
- which = 'b';
2103
- result.push(b[bi]);
2104
- ai++;
2105
- bi++;
2106
- }
2107
- else {
2108
- return false;
2109
- }
2110
- }
2111
- // if we fall out of the loop, it means they two are identical
2112
- // as long as their lengths match
2113
- return a.length === b.length && result;
2114
- }
2115
- parseNegate() {
2116
- if (this.nonegate)
2117
- return;
2118
- const pattern = this.pattern;
2119
- let negate = false;
2120
- let negateOffset = 0;
2121
- for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
2122
- negate = !negate;
2123
- negateOffset++;
2124
- }
2125
- if (negateOffset)
2126
- this.pattern = pattern.slice(negateOffset);
2127
- this.negate = negate;
2128
- }
2129
- // set partial to true to test if, for example,
2130
- // "/a/b" matches the start of "/*/b/*/d"
2131
- // Partial means, if you run out of file before you run
2132
- // out of pattern, then that's fine, as long as all
2133
- // the parts match.
2134
- matchOne(file, pattern, partial = false) {
2135
- let fileStartIndex = 0;
2136
- let patternStartIndex = 0;
2137
- // UNC paths like //?/X:/... can match X:/... and vice versa
2138
- // Drive letters in absolute drive or unc paths are always compared
2139
- // case-insensitively.
2140
- if (this.isWindows) {
2141
- const fileDrive = typeof file[0] === 'string' && /^[a-z]:$/i.test(file[0]);
2142
- const fileUNC = !fileDrive &&
2143
- file[0] === '' &&
2144
- file[1] === '' &&
2145
- file[2] === '?' &&
2146
- /^[a-z]:$/i.test(file[3]);
2147
- const patternDrive = typeof pattern[0] === 'string' && /^[a-z]:$/i.test(pattern[0]);
2148
- const patternUNC = !patternDrive &&
2149
- pattern[0] === '' &&
2150
- pattern[1] === '' &&
2151
- pattern[2] === '?' &&
2152
- typeof pattern[3] === 'string' &&
2153
- /^[a-z]:$/i.test(pattern[3]);
2154
- const fdi = fileUNC ? 3
2155
- : fileDrive ? 0
2156
- : undefined;
2157
- const pdi = patternUNC ? 3
2158
- : patternDrive ? 0
2159
- : undefined;
2160
- if (typeof fdi === 'number' && typeof pdi === 'number') {
2161
- const [fd, pd] = [
2162
- file[fdi],
2163
- pattern[pdi],
2164
- ];
2165
- // start matching at the drive letter index of each
2166
- if (fd.toLowerCase() === pd.toLowerCase()) {
2167
- pattern[pdi] = fd;
2168
- patternStartIndex = pdi;
2169
- fileStartIndex = fdi;
2170
- }
2171
- }
2172
- }
2173
- // resolve and reduce . and .. portions in the file as well.
2174
- // don't need to do the second phase, because it's only one string[]
2175
- const { optimizationLevel = 1 } = this.options;
2176
- if (optimizationLevel >= 2) {
2177
- file = this.levelTwoFileOptimize(file);
2178
- }
2179
- if (pattern.includes(exports.GLOBSTAR)) {
2180
- return this.#matchGlobstar(file, pattern, partial, fileStartIndex, patternStartIndex);
2181
- }
2182
- return this.#matchOne(file, pattern, partial, fileStartIndex, patternStartIndex);
2183
- }
2184
- #matchGlobstar(file, pattern, partial, fileIndex, patternIndex) {
2185
- // split the pattern into head, tail, and middle of ** delimited parts
2186
- const firstgs = pattern.indexOf(exports.GLOBSTAR, patternIndex);
2187
- const lastgs = pattern.lastIndexOf(exports.GLOBSTAR);
2188
- // split the pattern up into globstar-delimited sections
2189
- // the tail has to be at the end, and the others just have
2190
- // to be found in order from the head.
2191
- const [head, body, tail] = partial ?
2192
- [
2193
- pattern.slice(patternIndex, firstgs),
2194
- pattern.slice(firstgs + 1),
2195
- [],
2196
- ]
2197
- : [
2198
- pattern.slice(patternIndex, firstgs),
2199
- pattern.slice(firstgs + 1, lastgs),
2200
- pattern.slice(lastgs + 1),
2201
- ];
2202
- // check the head, from the current file/pattern index.
2203
- if (head.length) {
2204
- const fileHead = file.slice(fileIndex, fileIndex + head.length);
2205
- if (!this.#matchOne(fileHead, head, partial, 0, 0)) {
2206
- return false;
2207
- }
2208
- fileIndex += head.length;
2209
- patternIndex += head.length;
2210
- }
2211
- // now we know the head matches!
2212
- // if the last portion is not empty, it MUST match the end
2213
- // check the tail
2214
- let fileTailMatch = 0;
2215
- if (tail.length) {
2216
- // if head + tail > file, then we cannot possibly match
2217
- if (tail.length + fileIndex > file.length)
2218
- return false;
2219
- // try to match the tail
2220
- let tailStart = file.length - tail.length;
2221
- if (this.#matchOne(file, tail, partial, tailStart, 0)) {
2222
- fileTailMatch = tail.length;
2223
- }
2224
- else {
2225
- // affordance for stuff like a/**/* matching a/b/
2226
- // if the last file portion is '', and there's more to the pattern
2227
- // then try without the '' bit.
2228
- if (file[file.length - 1] !== '' ||
2229
- fileIndex + tail.length === file.length) {
2230
- return false;
2231
- }
2232
- tailStart--;
2233
- if (!this.#matchOne(file, tail, partial, tailStart, 0)) {
2234
- return false;
2235
- }
2236
- fileTailMatch = tail.length + 1;
2237
- }
2238
- }
2239
- // now we know the tail matches!
2240
- // the middle is zero or more portions wrapped in **, possibly
2241
- // containing more ** sections.
2242
- // so a/**/b/**/c/**/d has become **/b/**/c/**
2243
- // if it's empty, it means a/**/b, just verify we have no bad dots
2244
- // if there's no tail, so it ends on /**, then we must have *something*
2245
- // after the head, or it's not a matc
2246
- if (!body.length) {
2247
- let sawSome = !!fileTailMatch;
2248
- for (let i = fileIndex; i < file.length - fileTailMatch; i++) {
2249
- const f = String(file[i]);
2250
- sawSome = true;
2251
- if (f === '.' ||
2252
- f === '..' ||
2253
- (!this.options.dot && f.startsWith('.'))) {
2254
- return false;
2255
- }
2256
- }
2257
- // in partial mode, we just need to get past all file parts
2258
- return partial || sawSome;
2259
- }
2260
- // now we know that there's one or more body sections, which can
2261
- // be matched anywhere from the 0 index (because the head was pruned)
2262
- // through to the length-fileTailMatch index.
2263
- // split the body up into sections, and note the minimum index it can
2264
- // be found at (start with the length of all previous segments)
2265
- // [section, before, after]
2266
- const bodySegments = [[[], 0]];
2267
- let currentBody = bodySegments[0];
2268
- let nonGsParts = 0;
2269
- const nonGsPartsSums = [0];
2270
- for (const b of body) {
2271
- if (b === exports.GLOBSTAR) {
2272
- nonGsPartsSums.push(nonGsParts);
2273
- currentBody = [[], 0];
2274
- bodySegments.push(currentBody);
2275
- }
2276
- else {
2277
- currentBody[0].push(b);
2278
- nonGsParts++;
2279
- }
2280
- }
2281
- let i = bodySegments.length - 1;
2282
- const fileLength = file.length - fileTailMatch;
2283
- for (const b of bodySegments) {
2284
- b[1] = fileLength - (nonGsPartsSums[i--] + b[0].length);
2285
- }
2286
- return !!this.#matchGlobStarBodySections(file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch);
2287
- }
2288
- // return false for "nope, not matching"
2289
- // return null for "not matching, cannot keep trying"
2290
- #matchGlobStarBodySections(file,
2291
- // pattern section, last possible position for it
2292
- bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail) {
2293
- // take the first body segment, and walk from fileIndex to its "after"
2294
- // value at the end
2295
- // If it doesn't match at that position, we increment, until we hit
2296
- // that final possible position, and give up.
2297
- // If it does match, then advance and try to rest.
2298
- // If any of them fail we keep walking forward.
2299
- // this is still a bit recursively painful, but it's more constrained
2300
- // than previous implementations, because we never test something that
2301
- // can't possibly be a valid matching condition.
2302
- const bs = bodySegments[bodyIndex];
2303
- if (!bs) {
2304
- // just make sure that there's no bad dots
2305
- for (let i = fileIndex; i < file.length; i++) {
2306
- sawTail = true;
2307
- const f = file[i];
2308
- if (f === '.' ||
2309
- f === '..' ||
2310
- (!this.options.dot && f.startsWith('.'))) {
2311
- return false;
2312
- }
2313
- }
2314
- return sawTail;
2315
- }
2316
- // have a non-globstar body section to test
2317
- const [body, after] = bs;
2318
- while (fileIndex <= after) {
2319
- const m = this.#matchOne(file.slice(0, fileIndex + body.length), body, partial, fileIndex, 0);
2320
- // if limit exceeded, no match. intentional false negative,
2321
- // acceptable break in correctness for security.
2322
- if (m && globStarDepth < this.maxGlobstarRecursion) {
2323
- // match! see if the rest match. if so, we're done!
2324
- const sub = this.#matchGlobStarBodySections(file, bodySegments, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail);
2325
- if (sub !== false) {
2326
- return sub;
2327
- }
2328
- }
2329
- const f = file[fileIndex];
2330
- if (f === '.' ||
2331
- f === '..' ||
2332
- (!this.options.dot && f.startsWith('.'))) {
2333
- return false;
2334
- }
2335
- fileIndex++;
2336
- }
2337
- // walked off. no point continuing
2338
- return partial || null;
2339
- }
2340
- #matchOne(file, pattern, partial, fileIndex, patternIndex) {
2341
- let fi;
2342
- let pi;
2343
- let pl;
2344
- let fl;
2345
- for (fi = fileIndex,
2346
- pi = patternIndex,
2347
- fl = file.length,
2348
- pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
2349
- this.debug('matchOne loop');
2350
- let p = pattern[pi];
2351
- let f = file[fi];
2352
- this.debug(pattern, p, f);
2353
- // should be impossible.
2354
- // some invalid regexp stuff in the set.
2355
- /* c8 ignore start */
2356
- if (p === false || p === exports.GLOBSTAR) {
2357
- return false;
2358
- }
2359
- /* c8 ignore stop */
2360
- // something other than **
2361
- // non-magic patterns just have to match exactly
2362
- // patterns with magic have been turned into regexps.
2363
- let hit;
2364
- if (typeof p === 'string') {
2365
- hit = f === p;
2366
- this.debug('string match', p, f, hit);
2367
- }
2368
- else {
2369
- hit = p.test(f);
2370
- this.debug('pattern match', p, f, hit);
2371
- }
2372
- if (!hit)
2373
- return false;
2374
- }
2375
- // Note: ending in / means that we'll get a final ""
2376
- // at the end of the pattern. This can only match a
2377
- // corresponding "" at the end of the file.
2378
- // If the file ends in /, then it can only match a
2379
- // a pattern that ends in /, unless the pattern just
2380
- // doesn't have any more for it. But, a/b/ should *not*
2381
- // match "a/b/*", even though "" matches against the
2382
- // [^/]*? pattern, except in partial mode, where it might
2383
- // simply not be reached yet.
2384
- // However, a/b/ should still satisfy a/*
2385
- // now either we fell off the end of the pattern, or we're done.
2386
- if (fi === fl && pi === pl) {
2387
- // ran out of pattern and filename at the same time.
2388
- // an exact hit!
2389
- return true;
2390
- }
2391
- else if (fi === fl) {
2392
- // ran out of file, but still had pattern left.
2393
- // this is ok if we're doing the match as part of
2394
- // a glob fs traversal.
2395
- return partial;
2396
- }
2397
- else if (pi === pl) {
2398
- // ran out of pattern, still have file left.
2399
- // this is only acceptable if we're on the very last
2400
- // empty segment of a file with a trailing slash.
2401
- // a/* should match a/b/
2402
- return fi === fl - 1 && file[fi] === '';
2403
- /* c8 ignore start */
2404
- }
2405
- else {
2406
- // should be unreachable.
2407
- throw new Error('wtf?');
2408
- }
2409
- /* c8 ignore stop */
2410
- }
2411
- braceExpand() {
2412
- return (0, exports.braceExpand)(this.pattern, this.options);
2413
- }
2414
- parse(pattern) {
2415
- (0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
2416
- const options = this.options;
2417
- // shortcuts
2418
- if (pattern === '**')
2419
- return exports.GLOBSTAR;
2420
- if (pattern === '')
2421
- return '';
2422
- // far and away, the most common glob pattern parts are
2423
- // *, *.*, and *.<ext> Add a fast check method for those.
2424
- let m;
2425
- let fastTest = null;
2426
- if ((m = pattern.match(starRE))) {
2427
- fastTest = options.dot ? starTestDot : starTest;
2428
- }
2429
- else if ((m = pattern.match(starDotExtRE))) {
2430
- fastTest = (options.nocase ?
2431
- options.dot ?
2432
- starDotExtTestNocaseDot
2433
- : starDotExtTestNocase
2434
- : options.dot ? starDotExtTestDot
2435
- : starDotExtTest)(m[1]);
2436
- }
2437
- else if ((m = pattern.match(qmarksRE))) {
2438
- fastTest = (options.nocase ?
2439
- options.dot ?
2440
- qmarksTestNocaseDot
2441
- : qmarksTestNocase
2442
- : options.dot ? qmarksTestDot
2443
- : qmarksTest)(m);
2444
- }
2445
- else if ((m = pattern.match(starDotStarRE))) {
2446
- fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
2447
- }
2448
- else if ((m = pattern.match(dotStarRE))) {
2449
- fastTest = dotStarTest;
2450
- }
2451
- const re = ast_js_1.AST.fromGlob(pattern, this.options).toMMPattern();
2452
- if (fastTest && typeof re === 'object') {
2453
- // Avoids overriding in frozen environments
2454
- Reflect.defineProperty(re, 'test', { value: fastTest });
2455
- }
2456
- return re;
2457
- }
2458
- makeRe() {
2459
- if (this.regexp || this.regexp === false)
2460
- return this.regexp;
2461
- // at this point, this.set is a 2d array of partial
2462
- // pattern strings, or "**".
2463
- //
2464
- // It's better to use .match(). This function shouldn't
2465
- // be used, really, but it's pretty convenient sometimes,
2466
- // when you just want to work with a regex.
2467
- const set = this.set;
2468
- if (!set.length) {
2469
- this.regexp = false;
2470
- return this.regexp;
2471
- }
2472
- const options = this.options;
2473
- const twoStar = options.noglobstar ? star
2474
- : options.dot ? twoStarDot
2475
- : twoStarNoDot;
2476
- const flags = new Set(options.nocase ? ['i'] : []);
2477
- // regexpify non-globstar patterns
2478
- // if ** is only item, then we just do one twoStar
2479
- // if ** is first, and there are more, prepend (\/|twoStar\/)? to next
2480
- // if ** is last, append (\/twoStar|) to previous
2481
- // if ** is in the middle, append (\/|\/twoStar\/) to previous
2482
- // then filter out GLOBSTAR symbols
2483
- let re = set
2484
- .map(pattern => {
2485
- const pp = pattern.map(p => {
2486
- if (p instanceof RegExp) {
2487
- for (const f of p.flags.split(''))
2488
- flags.add(f);
2489
- }
2490
- return (typeof p === 'string' ? regExpEscape(p)
2491
- : p === exports.GLOBSTAR ? exports.GLOBSTAR
2492
- : p._src);
2493
- });
2494
- pp.forEach((p, i) => {
2495
- const next = pp[i + 1];
2496
- const prev = pp[i - 1];
2497
- if (p !== exports.GLOBSTAR || prev === exports.GLOBSTAR) {
2498
- return;
2499
- }
2500
- if (prev === undefined) {
2501
- if (next !== undefined && next !== exports.GLOBSTAR) {
2502
- pp[i + 1] = '(?:\\/|' + twoStar + '\\/)?' + next;
2503
- }
2504
- else {
2505
- pp[i] = twoStar;
2506
- }
2507
- }
2508
- else if (next === undefined) {
2509
- pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + ')?';
2510
- }
2511
- else if (next !== exports.GLOBSTAR) {
2512
- pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + '\\/)' + next;
2513
- pp[i + 1] = exports.GLOBSTAR;
2514
- }
2515
- });
2516
- const filtered = pp.filter(p => p !== exports.GLOBSTAR);
2517
- // For partial matches, we need to make the pattern match
2518
- // any prefix of the full path. We do this by generating
2519
- // alternative patterns that match progressively longer prefixes.
2520
- if (this.partial && filtered.length >= 1) {
2521
- const prefixes = [];
2522
- for (let i = 1; i <= filtered.length; i++) {
2523
- prefixes.push(filtered.slice(0, i).join('/'));
2524
- }
2525
- return '(?:' + prefixes.join('|') + ')';
2526
- }
2527
- return filtered.join('/');
2528
- })
2529
- .join('|');
2530
- // need to wrap in parens if we had more than one thing with |,
2531
- // otherwise only the first will be anchored to ^ and the last to $
2532
- const [open, close] = set.length > 1 ? ['(?:', ')'] : ['', ''];
2533
- // must match entire pattern
2534
- // ending in a * or ** will make it less strict.
2535
- re = '^' + open + re + close + '$';
2536
- // In partial mode, '/' should always match as it's a valid prefix for any pattern
2537
- if (this.partial) {
2538
- re = '^(?:\\/|' + open + re.slice(1, -1) + close + ')$';
2539
- }
2540
- // can match anything, as long as it's not this.
2541
- if (this.negate)
2542
- re = '^(?!' + re + ').+$';
2543
- try {
2544
- this.regexp = new RegExp(re, [...flags].join(''));
2545
- /* c8 ignore start */
2546
- }
2547
- catch {
2548
- // should be impossible
2549
- this.regexp = false;
2550
- }
2551
- /* c8 ignore stop */
2552
- return this.regexp;
2553
- }
2554
- slashSplit(p) {
2555
- // if p starts with // on windows, we preserve that
2556
- // so that UNC paths aren't broken. Otherwise, any number of
2557
- // / characters are coalesced into one, unless
2558
- // preserveMultipleSlashes is set to true.
2559
- if (this.preserveMultipleSlashes) {
2560
- return p.split('/');
2561
- }
2562
- else if (this.isWindows && /^\/\/[^/]+/.test(p)) {
2563
- // add an extra '' for the one we lose
2564
- return ['', ...p.split(/\/+/)];
2565
- }
2566
- else {
2567
- return p.split(/\/+/);
2568
- }
2569
- }
2570
- match(f, partial = this.partial) {
2571
- this.debug('match', f, this.pattern);
2572
- // short-circuit in the case of busted things.
2573
- // comments, etc.
2574
- if (this.comment) {
2575
- return false;
2576
- }
2577
- if (this.empty) {
2578
- return f === '';
2579
- }
2580
- if (f === '/' && partial) {
2581
- return true;
2582
- }
2583
- const options = this.options;
2584
- // windows: need to use /, not \
2585
- if (this.isWindows) {
2586
- f = f.split('\\').join('/');
2587
- }
2588
- // treat the test path as a set of pathparts.
2589
- const ff = this.slashSplit(f);
2590
- this.debug(this.pattern, 'split', ff);
2591
- // just ONE of the pattern sets in this.set needs to match
2592
- // in order for it to be valid. If negating, then just one
2593
- // match means that we have failed.
2594
- // Either way, return on the first hit.
2595
- const set = this.set;
2596
- this.debug(this.pattern, 'set', set);
2597
- // Find the basename of the path by looking for the last non-empty segment
2598
- let filename = ff[ff.length - 1];
2599
- if (!filename) {
2600
- for (let i = ff.length - 2; !filename && i >= 0; i--) {
2601
- filename = ff[i];
2602
- }
2603
- }
2604
- for (const pattern of set) {
2605
- let file = ff;
2606
- if (options.matchBase && pattern.length === 1) {
2607
- file = [filename];
2608
- }
2609
- const hit = this.matchOne(file, pattern, partial);
2610
- if (hit) {
2611
- if (options.flipNegate) {
2612
- return true;
2613
- }
2614
- return !this.negate;
2615
- }
2616
- }
2617
- // didn't get any hits. this is success if it's a negative
2618
- // pattern, failure otherwise.
2619
- if (options.flipNegate) {
2620
- return false;
2621
- }
2622
- return this.negate;
2623
- }
2624
- static defaults(def) {
2625
- return exports.minimatch.defaults(def).Minimatch;
2626
- }
2627
- }
2628
- exports.Minimatch = Minimatch;
2629
- /* c8 ignore start */
2630
- var ast_js_2 = requireAst();
2631
- Object.defineProperty(exports, "AST", { enumerable: true, get: function () { return ast_js_2.AST; } });
2632
- var escape_js_2 = require_escape();
2633
- Object.defineProperty(exports, "escape", { enumerable: true, get: function () { return escape_js_2.escape; } });
2634
- var unescape_js_2 = require_unescape();
2635
- Object.defineProperty(exports, "unescape", { enumerable: true, get: function () { return unescape_js_2.unescape; } });
2636
- /* c8 ignore stop */
2637
- exports.minimatch.AST = ast_js_1.AST;
2638
- exports.minimatch.Minimatch = Minimatch;
2639
- exports.minimatch.escape = escape_js_1.escape;
2640
- exports.minimatch.unescape = unescape_js_1.unescape;
2641
-
2642
- } (commonjs$2));
2643
- return commonjs$2;
1431
+ // treat the test path as a set of pathparts.
1432
+ f = f.split(slashSplit);
1433
+ this.debug(this.pattern, 'split', f);
1434
+
1435
+ // just ONE of the pattern sets in this.set needs to match
1436
+ // in order for it to be valid. If negating, then just one
1437
+ // match means that we have failed.
1438
+ // Either way, return on the first hit.
1439
+
1440
+ const set = this.set;
1441
+ this.debug(this.pattern, 'set', set);
1442
+
1443
+ // Find the basename of the path by looking for the last non-empty segment
1444
+ let filename;
1445
+ for (let i = f.length - 1; i >= 0; i--) {
1446
+ filename = f[i];
1447
+ if (filename) break
1448
+ }
1449
+
1450
+ for (let i = 0; i < set.length; i++) {
1451
+ const pattern = set[i];
1452
+ let file = f;
1453
+ if (options.matchBase && pattern.length === 1) {
1454
+ file = [filename];
1455
+ }
1456
+ const hit = this.matchOne(file, pattern, partial);
1457
+ if (hit) {
1458
+ if (options.flipNegate) return true
1459
+ return !this.negate
1460
+ }
1461
+ }
1462
+
1463
+ // didn't get any hits. this is success if it's a negative
1464
+ // pattern, failure otherwise.
1465
+ if (options.flipNegate) return false
1466
+ return this.negate
1467
+ }
1468
+
1469
+ static defaults (def) {
1470
+ return minimatch.defaults(def).Minimatch
1471
+ }
1472
+ }
1473
+
1474
+ minimatch.Minimatch = Minimatch;
1475
+ return minimatch_1;
2644
1476
  }
2645
1477
 
2646
1478
  var jsYaml$1 = {};
@@ -3760,7 +2592,7 @@ function requireOmap$1 () {
3760
2592
  function resolveYamlOmap (data) {
3761
2593
  if (data === null) return true
3762
2594
 
3763
- const objectKeys = [];
2595
+ const objectKeys = {};
3764
2596
  const object = data;
3765
2597
 
3766
2598
  for (let index = 0, length = object.length; index < length; index += 1) {
@@ -3779,8 +2611,8 @@ function requireOmap$1 () {
3779
2611
 
3780
2612
  if (!pairHasKey) return false
3781
2613
 
3782
- if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey);
3783
- else return false
2614
+ if (_hasOwnProperty.call(objectKeys, pairKey)) return false
2615
+ Object.defineProperty(objectKeys, pairKey, { value: true });
3784
2616
  }
3785
2617
 
3786
2618
  return true
@@ -9099,7 +7931,7 @@ function requireUtils$3 () {
9099
7931
  exports.dequal = dequal;
9100
7932
  const fs = require$$0$5;
9101
7933
  const path_1 = require$$1$4;
9102
- const minimatch = requireCommonjs();
7934
+ const minimatch = requireMinimatch();
9103
7935
  const js_yaml_1 = requireJsYaml();
9104
7936
  const env_1 = requireEnv();
9105
7937
  const logger_1 = requireLogger();
@@ -13464,10 +12296,6 @@ const navItemSchema = {
13464
12296
  },
13465
12297
  // Allow users to eject the navbar and implement additional levels of nesting
13466
12298
  items: { type: 'array', items: { type: 'object', additionalProperties: true } },
13467
- rbac: {
13468
- type: 'object',
13469
- additionalProperties: { type: 'string' },
13470
- },
13471
12299
  },
13472
12300
  };
13473
12301
  const navItemsSchema = {
@@ -14745,7 +13573,9 @@ function requireOasTypes () {
14745
13573
  if (typeof root.openapi === 'string' && root.openapi.startsWith('3.0')) {
14746
13574
  return SpecVersion.OAS3_0;
14747
13575
  }
14748
- if (typeof root.openapi === 'string' && root.openapi.startsWith('3.1')) {
13576
+ if (typeof root.openapi === 'string' &&
13577
+ (root.openapi.startsWith('3.1') || root.openapi.startsWith('3.2')) // temporary support for 3.2
13578
+ ) {
14749
13579
  return SpecVersion.OAS3_1;
14750
13580
  }
14751
13581
  if (root.swagger && root.swagger === '2.0') {
@@ -30807,7 +29637,7 @@ var redocly = {};
30807
29637
  var registryApi = {};
30808
29638
 
30809
29639
  const name = "@redocly/openapi-core";
30810
- const version = "1.34.5";
29640
+ const version = "1.34.19";
30811
29641
  const description = "";
30812
29642
  const main = "lib/index.js";
30813
29643
  const engines = {
@@ -30842,14 +29672,14 @@ const contributors = [
30842
29672
  "Roman Hotsiy <roman@redocly.com> (https://redocly.com/)"
30843
29673
  ];
30844
29674
  const dependencies = {
30845
- "@redocly/ajv": "^8.11.2",
30846
- "@redocly/config": "^0.22.0",
30847
- colorette: "^1.2.0",
30848
- "https-proxy-agent": "^7.0.5",
30849
- "js-levenshtein": "^1.1.6",
30850
- "js-yaml": "^4.1.0",
30851
- minimatch: "^5.0.1",
30852
- pluralize: "^8.0.0",
29675
+ "@redocly/ajv": "8.11.2",
29676
+ "@redocly/config": "0.22.0",
29677
+ colorette: "1.4.0",
29678
+ "https-proxy-agent": "7.0.6",
29679
+ "js-levenshtein": "1.1.6",
29680
+ "js-yaml": "4.3.1",
29681
+ minimatch: "5.1.9",
29682
+ pluralize: "8.0.0",
30853
29683
  "yaml-ast-parser": "0.0.43"
30854
29684
  };
30855
29685
  const devDependencies = {