@shopware/api-gen 1.5.1 → 1.5.3

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.
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import yargs from 'yargs';
2
2
  import { hideBin } from 'yargs/helpers';
3
- import { a as getAugmentedNamespace, f as formatSource, g as generate, l as loadSchema, v as validateJson } from './shared/api-gen.DDkIkZIo.mjs';
3
+ import { a as getAugmentedNamespace, f as formatSource, g as generate, l as loadSchema, v as validateJson } from './shared/api-gen.DwUlbL4g.mjs';
4
4
  import { mkdirSync, writeFileSync } from 'node:fs';
5
5
  import { resolve as resolve$2 } from 'node:path';
6
6
  import require$$0$5 from 'fs';
@@ -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.3";
36
36
  const packageJson = {
37
37
  version: version$1};
38
38
 
@@ -40,2607 +40,1495 @@ 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;
386
- }
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;
124
+ }
125
+
126
+ var braceExpansion;
127
+ var hasRequiredBraceExpansion;
128
+
129
+ function requireBraceExpansion () {
130
+ if (hasRequiredBraceExpansion) return braceExpansion;
131
+ hasRequiredBraceExpansion = 1;
132
+ var balanced = requireBalancedMatch();
133
+
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
+ // `expand` recurses once per level of brace *nesting* - both when expanding a
157
+ // set's comma members and when re-wrapping a set whose body is a single part.
158
+ // The CVE-2026-14257 fix made the *tail* iterative (recursion on `m.post`, one
159
+ // level per chained group), which left nesting depth unbounded: about 3,100
160
+ // levels of `{{{...a,b...}}}` - only ~6KB of input - exhausted the native stack
161
+ // and crashed the process. `EXPANSION_MAX_DEPTH` bounds how deep the parser
162
+ // will follow nesting. It sits far above any realistic pattern and well below
163
+ // the depth at which the stack runs out.
164
+ var EXPANSION_MAX_DEPTH = 1000;
165
+
166
+ // Bash keeps a quirk where a brace group followed by a comma set still expands
167
+ // (`{a},b}`). The parser implements it by rewriting the string and restarting
168
+ // the scan, absorbing one `}` per pass. `n` trailing braces therefore cost `n`
169
+ // full passes over a string that itself grows by one `escClose` sentinel each
170
+ // time - quadratic in `n`, with a ~26x constant from the sentinel's length.
171
+ // 128KB of `'{a}' + '}'.repeat(n) + ',z}'` blocked the event loop for 27
172
+ // seconds to produce two results. `EXPANSION_MAX_REWRITES` bounds how many
173
+ // times the scan may restart. Real `{a},b}` input needs a handful.
174
+ var EXPANSION_MAX_REWRITES = 1000;
175
+
176
+ function numeric(str) {
177
+ return parseInt(str, 10) == str
178
+ ? parseInt(str, 10)
179
+ : str.charCodeAt(0);
180
+ }
181
+
182
+ function escapeBraces(str) {
183
+ return str.split('\\\\').join(escSlash)
184
+ .split('\\{').join(escOpen)
185
+ .split('\\}').join(escClose)
186
+ .split('\\,').join(escComma)
187
+ .split('\\.').join(escPeriod);
188
+ }
189
+
190
+ function unescapeBraces(str) {
191
+ return str.split(escSlash).join('\\')
192
+ .split(escOpen).join('{')
193
+ .split(escClose).join('}')
194
+ .split(escComma).join(',')
195
+ .split(escPeriod).join('.');
196
+ }
197
+
198
+
199
+ // Like `target.push(...items)` but doesn't overflow the stack
200
+ function pushAll(target, items) {
201
+ for (var i = 0; i < items.length; i++) {
202
+ target.push(items[i]);
203
+ }
204
+ }
205
+
206
+ // Basically just str.split(","), but handling cases
207
+ // where we have nested braced sections, which should be
208
+ // treated as individual members, like {a,{b,c},d}
209
+ function parseCommaParts(str) {
210
+ var parts = [];
387
211
 
388
- var assertValidPattern = {};
212
+ // Walk the brace groups iteratively. Recursing on `post` once per group let a
213
+ // chain of them exhaust the stack - the parsing-side counterpart to
214
+ // the `expand` overflow fixed for CVE-2026-14257, and not something `max` or
215
+ // `maxLength` can bound, since it happens before expansion.
216
+ //
217
+ // The part the next chunk continues
218
+ var carry = '';
389
219
 
390
- var hasRequiredAssertValidPattern;
220
+ for (;;) {
221
+ var m = balanced('{', '}', str);
391
222
 
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');
223
+ if (!m) {
224
+ var tail = str.split(',');
225
+ tail[0] = carry + tail[0];
226
+ pushAll(parts, tail);
227
+ return parts;
401
228
  }
402
- if (pattern.length > MAX_PATTERN_LENGTH) {
403
- throw new TypeError('pattern is too long');
229
+
230
+ var pre = m.pre;
231
+ var body = m.body;
232
+ var post = m.post;
233
+ var p = pre.split(',');
234
+
235
+ p[0] = carry + p[0];
236
+ p[p.length-1] += '{' + body + '}';
237
+
238
+ if (!post.length) {
239
+ pushAll(parts, p);
240
+ return parts;
404
241
  }
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
- }
242
+
243
+ carry = p.pop();
244
+ pushAll(parts, p);
245
+ str = post;
246
+ }
247
+ }
248
+
249
+ function expandTop(str, options) {
250
+ if (!str)
251
+ return [];
252
+
253
+ options = options || {};
254
+ var max = options.max == null ? EXPANSION_MAX : options.max;
255
+ var maxLength = options.maxLength == null ? EXPANSION_MAX_LENGTH : options.maxLength;
256
+ var maxDepth = options.maxDepth == null ? EXPANSION_MAX_DEPTH : options.maxDepth;
257
+ var maxRewrites = options.maxRewrites == null ? EXPANSION_MAX_REWRITES : options.maxRewrites;
258
+
259
+ // I don't know why Bash 4.3 does this, but it does.
260
+ // Anything starting with {} will have the first two bytes preserved
261
+ // but *only* at the top level, so {},a}b will not expand to anything,
262
+ // but a{},b}c will be expanded to [a}c,abc].
263
+ // One could argue that this is a bug in Bash, but since the goal of
264
+ // this module is to match Bash's rules, we escape a leading {}
265
+ if (str.substr(0, 2) === '{}') {
266
+ str = '\\{\\}' + str.substr(2);
267
+ }
268
+
269
+ return expand(escapeBraces(str), max, maxLength, maxDepth, 0, maxRewrites, true).map(unescapeBraces);
270
+ }
271
+
272
+ function embrace(str) {
273
+ return '{' + str + '}';
274
+ }
275
+ function isPadded(el) {
276
+ return /^-?0\d/.test(el);
277
+ }
278
+
279
+ function lte(i, y) {
280
+ return i <= y;
281
+ }
282
+ function gte(i, y) {
283
+ return i >= y;
284
+ }
285
+
286
+ // Build `{ acc[a] + pre + values[v] }` for every combination, capping the
287
+ // number of results at `max` and the total number of characters at `maxLength`.
288
+ // This is the one place output grows, so bounding it here keeps the single
289
+ // accumulator - and therefore memory - flat regardless of how many brace groups
290
+ // are combined (CVE-2026-14257).
291
+ function combine(
292
+ acc,
293
+ pre,
294
+ values,
295
+ max,
296
+ maxLength,
297
+ dropEmpties
298
+ ) {
299
+ var out = [];
300
+ var length = 0;
301
+ for (var a = 0; a < acc.length; a++) {
302
+ for (var v = 0; v < values.length; v++) {
303
+ if (out.length >= max) return out
304
+ var expansion = acc[a] + pre + values[v];
305
+ // Bash drops empty results at the top level. Skip them before they count
306
+ // against `max`, so `max` bounds the number of *kept* results.
307
+ if (dropEmpties && !expansion) continue
308
+ if (length + expansion.length > maxLength) return out
309
+ out.push(expansion);
310
+ length += expansion.length;
311
+ }
312
+ }
313
+ return out
314
+ }
315
+
316
+ // The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)
317
+ // sequence body.
318
+ function expandSequence(
319
+ body,
320
+ isAlphaSequence,
321
+ max,
322
+ maxLength
323
+ ) {
324
+ var n = body.split(/\.\./);
325
+ var N = [];
326
+ // A sequence body always splits into two or three parts, but the compiler
327
+ // can't know that.
328
+ /* c8 ignore start */
329
+ if (n[0] === undefined || n[1] === undefined) {
330
+ return N
331
+ }
332
+ /* c8 ignore stop */
333
+ var x = numeric(n[0]);
334
+ var y = numeric(n[1]);
335
+ var width = Math.max(n[0].length, n[1].length);
336
+ var incr =
337
+ n.length === 3 && n[2] !== undefined ?
338
+ Math.max(Math.abs(numeric(n[2])), 1)
339
+ : 1;
340
+ var test = lte;
341
+ var reverse = y < x;
342
+ if (reverse) {
343
+ incr *= -1;
344
+ test = gte;
345
+ }
346
+ var pad = n.some(isPadded);
347
+
348
+ var length = 0;
349
+ for (var i = x; test(i, y) && N.length < max; i += incr) {
350
+ var c;
351
+ if (isAlphaSequence) {
352
+ c = String.fromCharCode(i);
353
+ if (c === '\\') {
354
+ c = '';
355
+ }
356
+ } else {
357
+ c = String(i);
358
+ if (pad) {
359
+ var need = width - c.length;
360
+ if (need > 0) {
361
+ var z = new Array(need + 1).join('0');
362
+ if (i < 0) {
363
+ c = '-' + z + c.slice(1);
364
+ } else {
365
+ c = z + c;
366
+ }
507
367
  }
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;
368
+ }
369
+ }
370
+ if (length + c.length > maxLength) break
371
+ N.push(c);
372
+ length += c.length;
373
+ }
374
+ return N
375
+ }
376
+
377
+ function expand(
378
+ str,
379
+ max,
380
+ maxLength,
381
+ maxDepth,
382
+ depth,
383
+ maxRewrites,
384
+ isTop
385
+ ) {
386
+ // Too deeply nested to keep following: treat the rest as literal, the same
387
+ // way a group that cannot expand is already handled. Truncating rather than
388
+ // throwing keeps expansion total, matching `max` and `maxLength`.
389
+ if (depth > maxDepth) {
390
+ return [str];
391
+ }
392
+
393
+ // Consume the string's top-level brace groups left to right, threading a
394
+ // running set of combined prefixes (`acc`). Expanding the tail iteratively -
395
+ // rather than recursing on `m.post` once per group - keeps the native stack
396
+ // depth constant, so deeply chained input (`'{a,b}'.repeat(3000)`) can no
397
+ // longer overflow the stack, and leaves a single accumulator whose size
398
+ // `maxLength` bounds directly (CVE-2026-14257).
399
+ var acc = [''];
400
+
401
+ // Bash drops empty results, but only when the *first* top-level group is a
402
+ // comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
403
+ // is on the final strings, so it is applied to whichever `combine` produces
404
+ // them (the one with no brace set left in the tail).
405
+ // How many times the `{a},b}` rewrite below has restarted the scan. Each pass
406
+ // re-reads the whole string, so leaving this unbounded is quadratic.
407
+ var rewrites = 0;
408
+ var dropEmpties = false;
409
+ var firstGroup = true;
410
+
411
+ for (;;) {
412
+ const m = balanced('{', '}', str);
413
+
414
+ // No brace set left: the rest of the string is literal.
415
+ if (!m) {
416
+ return combine(acc, str, [''], max, maxLength, dropEmpties)
417
+ }
418
+
419
+ // no need to expand pre, since it is guaranteed to be free of brace-sets
420
+ const pre = m.pre;
421
+
422
+ if (/\$$/.test(pre)) {
423
+ acc = combine(
424
+ acc,
425
+ pre + '{' + m.body + '}',
426
+ [''],
427
+ max,
428
+ maxLength,
429
+ dropEmpties && !m.post.length
430
+ );
431
+ firstGroup = false;
432
+ if (!m.post.length) break
433
+ str = m.post;
434
+ continue
435
+ }
436
+
437
+ var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
438
+ var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
439
+ var isSequence = isNumericSequence || isAlphaSequence;
440
+ var isOptions = m.body.indexOf(',') >= 0;
441
+ if (!isSequence && !isOptions) {
442
+ // {a},b}
443
+ if (rewrites < maxRewrites && m.post.match(/,(?!,).*\}/)) {
444
+ rewrites++;
445
+ str = m.pre + '{' + m.body + escClose + m.post;
446
+ isTop = true;
447
+ continue;
448
+ }
449
+ // Nothing here expands, so the whole remaining string is literal.
450
+ return combine(
451
+ acc,
452
+ pre + '{' + m.body + '}' + m.post,
453
+ [''],
454
+ max,
455
+ maxLength,
456
+ dropEmpties
457
+ )
458
+ }
459
+
460
+ if (firstGroup) {
461
+ dropEmpties = isTop && !isSequence;
462
+ firstGroup = false;
463
+ }
464
+
465
+ var values;
466
+ if (isSequence) {
467
+ values = expandSequence(m.body, isAlphaSequence, max, maxLength);
468
+ } else {
469
+ var n = parseCommaParts(m.body);
470
+ if (n.length === 1 && n[0] !== undefined) {
471
+ // x{{a,b}}y ==> x{a}y x{b}y
472
+ n = expand(n[0], max, maxLength, maxDepth, depth + 1, maxRewrites, false).map(embrace);
473
+ //XXX is this necessary? Can't seem to hit it in tests.
474
+ /* c8 ignore start */
475
+ if (n.length === 1) {
476
+ acc = combine(
477
+ acc,
478
+ pre + n[0],
479
+ [''],
480
+ max,
481
+ maxLength,
482
+ dropEmpties && !m.post.length
483
+ );
484
+ if (!m.post.length) break
485
+ str = m.post;
486
+ continue
522
487
  }
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;
488
+ /* c8 ignore stop */
489
+ }
490
+
491
+ // Values that `combine` is going to drop as empty produce no result, so
492
+ // they must not count against `max` - otherwise `{a,,b}` with `max: 2`
493
+ // would stop at `['a', '']` and yield one result instead of two. Skipping
494
+ // them outright keeps `values` bounded while leaving `max` a bound on
495
+ // *kept* results.
496
+ var dropsEmpties = dropEmpties && !m.post.length && !pre;
497
+ for (var d = 0; dropsEmpties && d < acc.length; d++) {
498
+ if (acc[d]) {
499
+ dropsEmpties = false;
529
500
  }
530
- if (glob.startsWith('-', i + 1)) {
531
- rangeStart = c;
532
- i += 2;
533
- continue;
501
+ }
502
+
503
+ values = [];
504
+ var valuesLength = 0;
505
+ outer: for (var j = 0; j < n.length; j++) {
506
+ var expanded = expand(n[j], max, maxLength, maxDepth, depth + 1, maxRewrites, false);
507
+ for (var k = 0; k < expanded.length; k++) {
508
+ var v = expanded[k];
509
+ if (dropsEmpties && !v) continue
510
+ if (values.length >= max || valuesLength + v.length > maxLength) {
511
+ break outer
512
+ }
513
+ values.push(v);
514
+ valuesLength += v.length;
534
515
  }
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;
516
+ }
517
+ }
518
+
519
+ acc = combine(acc, pre, values, max, maxLength, dropEmpties && !m.post.length);
520
+ if (!m.post.length) break
521
+ str = m.post;
522
+ }
523
+
524
+ return acc
525
+ }
526
+ return braceExpansion;
570
527
  }
571
528
 
572
- var _unescape = {};
529
+ var minimatch_1;
530
+ var hasRequiredMinimatch;
573
531
 
574
- var hasRequired_unescape;
532
+ function requireMinimatch () {
533
+ if (hasRequiredMinimatch) return minimatch_1;
534
+ hasRequiredMinimatch = 1;
535
+ const minimatch = minimatch_1 = (p, pattern, options = {}) => {
536
+ assertValidPattern(pattern);
537
+
538
+ // shortcut: comments match nothing.
539
+ if (!options.nocomment && pattern.charAt(0) === '#') {
540
+ return false
541
+ }
542
+
543
+ return new Minimatch(pattern, options).match(p)
544
+ };
545
+
546
+ minimatch_1 = minimatch;
547
+
548
+ const path = requirePath();
549
+ minimatch.sep = path.sep;
550
+
551
+ const GLOBSTAR = Symbol('globstar **');
552
+ minimatch.GLOBSTAR = GLOBSTAR;
553
+ const expand = requireBraceExpansion();
554
+
555
+ const plTypes = {
556
+ '!': { open: '(?:(?!(?:', close: '))[^/]*?)'},
557
+ '?': { open: '(?:', close: ')?' },
558
+ '+': { open: '(?:', close: ')+' },
559
+ '*': { open: '(?:', close: ')*' },
560
+ '@': { open: '(?:', close: ')' }
561
+ };
575
562
 
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
563
  // any single thing other than /
564
+ // don't need to escape / when using new RegExp()
748
565
  const qmark = '[^/]';
566
+
749
567
  // * => any number of characters
750
568
  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
- };
569
+
570
+ // ** when dots are allowed. Anything goes, except .. and .
571
+ // not (^ or / followed by one or two dots followed by $ or /),
572
+ // followed by anything, any number of times.
573
+ const twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?';
574
+
575
+ // not a ^ or / followed by a dot,
576
+ // followed by anything, any number of times.
577
+ const twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?';
578
+
579
+ // "abc" -> { a:true, b:true, c:true }
580
+ const charSet = s => s.split('').reduce((set, c) => {
581
+ set[c] = true;
582
+ return set
583
+ }, {});
584
+
585
+ // characters that need to be escaped in RegExp.
586
+ const reSpecials = charSet('().*{}+?[]^$\\!');
587
+
588
+ // characters that indicate we have to add the pattern start
589
+ const addPatternStartSet = charSet('[.(');
590
+
591
+ // normalizes slashes.
592
+ const slashSplit = /\/+/;
593
+
594
+ minimatch.filter = (pattern, options = {}) =>
595
+ (p, i, list) => minimatch(p, pattern, options);
596
+
597
+ const ext = (a, b = {}) => {
598
+ const t = {};
599
+ Object.keys(a).forEach(k => t[k] = a[k]);
600
+ Object.keys(b).forEach(k => t[k] = b[k]);
601
+ return t
602
+ };
603
+
604
+ minimatch.defaults = def => {
605
+ if (!def || typeof def !== 'object' || !Object.keys(def).length) {
606
+ return minimatch
607
+ }
608
+
609
+ const orig = minimatch;
610
+
611
+ const m = (p, pattern, options) => orig(p, pattern, ext(def, options));
612
+ m.Minimatch = class Minimatch extends orig.Minimatch {
613
+ constructor (pattern, options) {
614
+ super(pattern, ext(def, options));
787
615
  }
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
- }
616
+ };
617
+ m.Minimatch.defaults = options => orig.defaults(ext(def, options)).Minimatch;
618
+ m.filter = (pattern, options) => orig.filter(pattern, ext(def, options));
619
+ m.defaults = options => orig.defaults(ext(def, options));
620
+ m.makeRe = (pattern, options) => orig.makeRe(pattern, ext(def, options));
621
+ m.braceExpand = (pattern, options) => orig.braceExpand(pattern, ext(def, options));
622
+ m.match = (list, pattern, options) => orig.match(list, pattern, ext(def, options));
623
+
624
+ return m
625
+ };
626
+
627
+
628
+
629
+
630
+
631
+ // Brace expansion:
632
+ // a{b,c}d -> abd acd
633
+ // a{b,}c -> abc ac
634
+ // a{0..3}d -> a0d a1d a2d a3d
635
+ // a{b,c{d,e}f}g -> abg acdfg acefg
636
+ // a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg
637
+ //
638
+ // Invalid sets are not expanded.
639
+ // a{2..}b -> a{2..}b
640
+ // a{b}c -> a{b}c
641
+ minimatch.braceExpand = (pattern, options) => braceExpand(pattern, options);
642
+
643
+ const braceExpand = (pattern, options = {}) => {
644
+ assertValidPattern(pattern);
645
+
646
+ // Thanks to Yeting Li <https://github.com/yetingli> for
647
+ // improving this regexp to avoid a ReDOS vulnerability.
648
+ if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
649
+ // shortcut. no need to expand.
650
+ return [pattern]
651
+ }
652
+
653
+ return expand(pattern)
654
+ };
655
+
656
+ const MAX_PATTERN_LENGTH = 1024 * 64;
657
+ const assertValidPattern = pattern => {
658
+ if (typeof pattern !== 'string') {
659
+ throw new TypeError('invalid pattern')
660
+ }
661
+
662
+ if (pattern.length > MAX_PATTERN_LENGTH) {
663
+ throw new TypeError('pattern is too long')
664
+ }
665
+ };
666
+
667
+ // parse a component of the expanded set.
668
+ // At this point, no pattern may contain "/" in it
669
+ // so we're going to return a 2d array, where each entry is the full
670
+ // pattern, split on '/', and then turned into a regular expression.
671
+ // A regexp is made at the end which joins each array with an
672
+ // escaped /, and another full one which joins each regexp with |.
673
+ //
674
+ // Following the lead of Bash 4.1, note that "**" only has special meaning
675
+ // when it is the *only* thing in a path portion. Otherwise, any series
676
+ // of * is equivalent to a single *. Globstar behavior is enabled by
677
+ // default, and can be disabled by setting options.noglobstar.
678
+ const SUBPARSE = Symbol('subparse');
679
+
680
+ minimatch.makeRe = (pattern, options) =>
681
+ new Minimatch(pattern, options || {}).makeRe();
682
+
683
+ minimatch.match = (list, pattern, options = {}) => {
684
+ const mm = new Minimatch(pattern, options);
685
+ list = list.filter(f => mm.match(f));
686
+ if (mm.options.nonull && !list.length) {
687
+ list.push(pattern);
688
+ }
689
+ return list
690
+ };
691
+
692
+ // replace stuff like \* with *
693
+ const globUnescape = s => s.replace(/\\(.)/g, '$1');
694
+ const charUnescape = s => s.replace(/\\([^-\]])/g, '$1');
695
+ const regExpEscape = s => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
696
+ const braExpEscape = s => s.replace(/[[\]\\]/g, '\\$&');
697
+
698
+ class Minimatch {
699
+ constructor (pattern, options) {
700
+ assertValidPattern(pattern);
701
+
702
+ if (!options) options = {};
703
+
704
+ this.options = options;
705
+ this.maxGlobstarRecursion = options.maxGlobstarRecursion !== undefined
706
+ ? options.maxGlobstarRecursion : 200;
707
+ this.set = [];
708
+ this.pattern = pattern;
709
+ this.windowsPathsNoEscape = !!options.windowsPathsNoEscape ||
710
+ options.allowWindowsEscape === false;
711
+ if (this.windowsPathsNoEscape) {
712
+ this.pattern = this.pattern.replace(/\\/g, '/');
713
+ }
714
+ this.regexp = null;
715
+ this.negate = false;
716
+ this.comment = false;
717
+ this.empty = false;
718
+ this.partial = !!options.partial;
719
+
720
+ // make the set of regexps etc.
721
+ this.make();
722
+ }
723
+
724
+ debug () {}
725
+
726
+ make () {
727
+ const pattern = this.pattern;
728
+ const options = this.options;
729
+
730
+ // empty patterns and comments match nothing.
731
+ if (!options.nocomment && pattern.charAt(0) === '#') {
732
+ this.comment = true;
733
+ return
734
+ }
735
+ if (!pattern) {
736
+ this.empty = true;
737
+ return
738
+ }
739
+
740
+ // step 1: figure out negation, etc.
741
+ this.parseNegate();
742
+
743
+ // step 2: expand braces
744
+ let set = this.globSet = this.braceExpand();
745
+
746
+ if (options.debug) this.debug = (...args) => console.error(...args);
747
+
748
+ this.debug(this.pattern, set);
749
+
750
+ // step 3: now we have a set, so turn each one into a series of path-portion
751
+ // matching patterns.
752
+ // These will be regexps, except in the case of "**", which is
753
+ // set to the GLOBSTAR object for globstar behavior,
754
+ // and will not contain any / characters
755
+ set = this.globParts = set.map(s => s.split(slashSplit));
756
+
757
+ this.debug(this.pattern, set);
758
+
759
+ // glob --> regexps
760
+ set = set.map((s, si, set) => s.map(this.parse, this));
761
+
762
+ this.debug(this.pattern, set);
763
+
764
+ // filter out everything that didn't compile properly.
765
+ set = set.filter(s => s.indexOf(false) === -1);
766
+
767
+ this.debug(this.pattern, set);
768
+
769
+ this.set = set;
770
+ }
771
+
772
+ parseNegate () {
773
+ if (this.options.nonegate) return
774
+
775
+ const pattern = this.pattern;
776
+ let negate = false;
777
+ let negateOffset = 0;
778
+
779
+ for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
780
+ negate = !negate;
781
+ negateOffset++;
782
+ }
783
+
784
+ if (negateOffset) this.pattern = pattern.slice(negateOffset);
785
+ this.negate = negate;
786
+ }
787
+
788
+ // set partial to true to test if, for example,
789
+ // "/a/b" matches the start of "/*/b/*/d"
790
+ // Partial means, if you run out of file before you run
791
+ // out of pattern, then that's fine, as long as all
792
+ // the parts match.
793
+ matchOne (file, pattern, partial) {
794
+ if (pattern.indexOf(GLOBSTAR) !== -1) {
795
+ return this._matchGlobstar(file, pattern, partial, 0, 0)
796
+ }
797
+ return this._matchOne(file, pattern, partial, 0, 0)
798
+ }
799
+
800
+ _matchGlobstar (file, pattern, partial, fileIndex, patternIndex) {
801
+ // find first globstar from patternIndex
802
+ let firstgs = -1;
803
+ for (let i = patternIndex; i < pattern.length; i++) {
804
+ if (pattern[i] === GLOBSTAR) { firstgs = i; break }
805
+ }
806
+
807
+ // find last globstar
808
+ let lastgs = -1;
809
+ for (let i = pattern.length - 1; i >= 0; i--) {
810
+ if (pattern[i] === GLOBSTAR) { lastgs = i; break }
811
+ }
812
+
813
+ const head = pattern.slice(patternIndex, firstgs);
814
+ const body = partial ? pattern.slice(firstgs + 1) : pattern.slice(firstgs + 1, lastgs);
815
+ const tail = partial ? [] : pattern.slice(lastgs + 1);
816
+
817
+ // check the head
818
+ if (head.length) {
819
+ const fileHead = file.slice(fileIndex, fileIndex + head.length);
820
+ if (!this._matchOne(fileHead, head, partial, 0, 0)) {
821
+ return false
822
+ }
823
+ fileIndex += head.length;
824
+ }
825
+
826
+ // check the tail
827
+ let fileTailMatch = 0;
828
+ if (tail.length) {
829
+ if (tail.length + fileIndex > file.length) return false
830
+
831
+ const tailStart = file.length - tail.length;
832
+ if (this._matchOne(file, tail, partial, tailStart, 0)) {
833
+ fileTailMatch = tail.length;
834
+ } else {
835
+ // affordance for stuff like a/**/* matching a/b/
836
+ if (file[file.length - 1] !== '' ||
837
+ fileIndex + tail.length === file.length) {
838
+ return false
857
839
  }
858
- return this;
840
+ if (!this._matchOne(file, tail, partial, tailStart - 1, 0)) {
841
+ return false
842
+ }
843
+ fileTailMatch = tail.length + 1;
844
+ }
859
845
  }
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
- }
846
+
847
+ // if body is empty (single ** between head and tail)
848
+ if (!body.length) {
849
+ let sawSome = !!fileTailMatch;
850
+ for (let i = fileIndex; i < file.length - fileTailMatch; i++) {
851
+ const f = String(file[i]);
852
+ sawSome = true;
853
+ if (f === '.' || f === '..' ||
854
+ (!this.options.dot && f.charAt(0) === '.')) {
855
+ return false
903
856
  }
904
- return true;
857
+ }
858
+ return partial || sawSome
859
+ }
860
+
861
+ // split body into segments at each GLOBSTAR
862
+ const bodySegments = [[[], 0]];
863
+ let currentBody = bodySegments[0];
864
+ let nonGsParts = 0;
865
+ const nonGsPartsSums = [0];
866
+ for (const b of body) {
867
+ if (b === GLOBSTAR) {
868
+ nonGsPartsSums.push(nonGsParts);
869
+ currentBody = [[], 0];
870
+ bodySegments.push(currentBody);
871
+ } else {
872
+ currentBody[0].push(b);
873
+ nonGsParts++;
874
+ }
905
875
  }
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;
876
+
877
+ let idx = bodySegments.length - 1;
878
+ const fileLength = file.length - fileTailMatch;
879
+ for (const b of bodySegments) {
880
+ b[1] = fileLength - (nonGsPartsSums[idx--] + b[0].length);
920
881
  }
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;
882
+
883
+ return !!this._matchGlobStarBodySections(
884
+ file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch
885
+ )
886
+ }
887
+
888
+ // return false for "nope, not matching"
889
+ // return null for "not matching, cannot keep trying"
890
+ _matchGlobStarBodySections (
891
+ file, bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail
892
+ ) {
893
+ const bs = bodySegments[bodyIndex];
894
+ if (!bs) {
895
+ // just make sure there are no bad dots
896
+ for (let i = fileIndex; i < file.length; i++) {
897
+ sawTail = true;
898
+ const f = file[i];
899
+ if (f === '.' || f === '..' ||
900
+ (!this.options.dot && f.charAt(0) === '.')) {
901
+ return false
990
902
  }
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;
903
+ }
904
+ return sawTail
905
+ }
906
+
907
+ const [body, after] = bs;
908
+ while (fileIndex <= after) {
909
+ const m = this._matchOne(
910
+ file.slice(0, fileIndex + body.length),
911
+ body,
912
+ partial,
913
+ fileIndex,
914
+ 0
915
+ );
916
+ // if limit exceeded, no match. intentional false negative,
917
+ // acceptable break in correctness for security.
918
+ if (m && globStarDepth < this.maxGlobstarRecursion) {
919
+ const sub = this._matchGlobStarBodySections(
920
+ file, bodySegments,
921
+ fileIndex + body.length, bodyIndex + 1,
922
+ partial, globStarDepth + 1, sawTail
923
+ );
924
+ if (sub !== false) {
925
+ return sub
1076
926
  }
1077
- const gc = child.#parts[0];
1078
- if (!gc || typeof gc !== 'object' || gc.type === null) {
1079
- return false;
927
+ }
928
+ const f = file[fileIndex];
929
+ if (f === '.' || f === '..' ||
930
+ (!this.options.dot && f.charAt(0) === '.')) {
931
+ return false
932
+ }
933
+ fileIndex++;
934
+ }
935
+ return partial || null
936
+ }
937
+
938
+ _matchOne (file, pattern, partial, fileIndex, patternIndex) {
939
+ let fi, pi, fl, pl;
940
+ for (
941
+ fi = fileIndex, pi = patternIndex, fl = file.length, pl = pattern.length
942
+ ; (fi < fl) && (pi < pl)
943
+ ; fi++, pi++
944
+ ) {
945
+ this.debug('matchOne loop');
946
+ const p = pattern[pi];
947
+ const f = file[fi];
948
+
949
+ this.debug(pattern, p, f);
950
+
951
+ // should be impossible.
952
+ // some invalid regexp stuff in the set.
953
+ /* istanbul ignore if */
954
+ if (p === false || p === GLOBSTAR) return false
955
+
956
+ // something other than **
957
+ // non-magic patterns just have to match exactly
958
+ // patterns with magic have been turned into regexps.
959
+ let hit;
960
+ if (typeof p === 'string') {
961
+ hit = f === p;
962
+ this.debug('string match', p, f, hit);
963
+ } else {
964
+ hit = f.match(p);
965
+ this.debug('pattern match', p, f, hit);
966
+ }
967
+
968
+ if (!hit) return false
969
+ }
970
+
971
+ // now either we fell off the end of the pattern, or we're done.
972
+ if (fi === fl && pi === pl) {
973
+ // ran out of pattern and filename at the same time.
974
+ // an exact hit!
975
+ return true
976
+ } else if (fi === fl) {
977
+ // ran out of file, but still had pattern left.
978
+ // this is ok if we're doing the match as part of
979
+ // a glob fs traversal.
980
+ return partial
981
+ } else /* istanbul ignore else */ if (pi === pl) {
982
+ // ran out of pattern, still have file left.
983
+ // this is only acceptable if we're on the very last
984
+ // empty segment of a file with a trailing slash.
985
+ // a/* should match a/b/
986
+ return (fi === fl - 1) && (file[fi] === '')
987
+ }
988
+
989
+ // should be unreachable.
990
+ /* istanbul ignore next */
991
+ throw new Error('wtf?')
992
+ }
993
+
994
+ braceExpand () {
995
+ return braceExpand(this.pattern, this.options)
996
+ }
997
+
998
+ parse (pattern, isSub) {
999
+ assertValidPattern(pattern);
1000
+
1001
+ const options = this.options;
1002
+
1003
+ // shortcuts
1004
+ if (pattern === '**') {
1005
+ if (!options.noglobstar)
1006
+ return GLOBSTAR
1007
+ else
1008
+ pattern = '*';
1009
+ }
1010
+ if (pattern === '') return ''
1011
+
1012
+ let re = '';
1013
+ let hasMagic = false;
1014
+ let escaping = false;
1015
+ // ? => one single character
1016
+ const patternListStack = [];
1017
+ const negativeLists = [];
1018
+ let stateChar;
1019
+ let inClass = false;
1020
+ let reClassStart = -1;
1021
+ let classStart = -1;
1022
+ let cs;
1023
+ let pl;
1024
+ let sp;
1025
+ // . and .. never match anything that doesn't start with .,
1026
+ // even when options.dot is set. However, if the pattern
1027
+ // starts with ., then traversal patterns can match.
1028
+ let dotTravAllowed = pattern.charAt(0) === '.';
1029
+ let dotFileAllowed = options.dot || dotTravAllowed;
1030
+ const patternStart = () =>
1031
+ dotTravAllowed
1032
+ ? ''
1033
+ : dotFileAllowed
1034
+ ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))'
1035
+ : '(?!\\.)';
1036
+ const subPatternStart = (p) =>
1037
+ p.charAt(0) === '.'
1038
+ ? ''
1039
+ : options.dot
1040
+ ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))'
1041
+ : '(?!\\.)';
1042
+
1043
+
1044
+ const clearStateChar = () => {
1045
+ if (stateChar) {
1046
+ // we had some state-tracking character
1047
+ // that wasn't consumed by this pass.
1048
+ switch (stateChar) {
1049
+ case '*':
1050
+ re += star;
1051
+ hasMagic = true;
1052
+ break
1053
+ case '?':
1054
+ re += qmark;
1055
+ hasMagic = true;
1056
+ break
1057
+ default:
1058
+ re += '\\' + stateChar;
1059
+ break
1080
1060
  }
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;
1061
+ this.debug('clearStateChar %j %j', stateChar, re);
1062
+ stateChar = false;
1063
+ }
1064
+ };
1065
+
1066
+ for (let i = 0, c; (i < pattern.length) && (c = pattern.charAt(i)); i++) {
1067
+ this.debug('%s\t%s %s %j', pattern, i, re, c);
1068
+
1069
+ // skip over any that are escaped.
1070
+ if (escaping) {
1071
+ /* istanbul ignore next - completely not allowed, even escaped. */
1072
+ if (c === '/') {
1073
+ return false
1114
1074
  }
1115
- const gc = child.#parts[0];
1116
- if (!gc || typeof gc !== 'object' || gc.type === null) {
1117
- return false;
1075
+
1076
+ if (reSpecials[c]) {
1077
+ re += '\\';
1118
1078
  }
1119
- return this.#canUsurpType(gc.type);
1120
- }
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
- }
1079
+ re += c;
1080
+ escaping = false;
1081
+ continue
1082
+ }
1083
+
1084
+ switch (c) {
1085
+ /* istanbul ignore next */
1086
+ case '/': {
1087
+ // Should already be path-split by now.
1088
+ return false
1134
1089
  }
1135
- this.type = nt;
1136
- this.#toString = undefined;
1137
- this.#emptyExt = false;
1138
- }
1139
- static fromGlob(pattern, options = {}) {
1140
- const ast = new _a(null, undefined, options);
1141
- _a.#parseAST(pattern, ast, 0, options, 0);
1142
- return ast;
1090
+
1091
+ case '\\':
1092
+ if (inClass && pattern.charAt(i + 1) === '-') {
1093
+ re += c;
1094
+ continue
1095
+ }
1096
+
1097
+ clearStateChar();
1098
+ escaping = true;
1099
+ continue
1100
+
1101
+ // the various stateChar values
1102
+ // for the "extglob" stuff.
1103
+ case '?':
1104
+ case '*':
1105
+ case '+':
1106
+ case '@':
1107
+ case '!':
1108
+ this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c);
1109
+
1110
+ // all of those are literals inside a class, except that
1111
+ // the glob [!a] means [^a] in regexp
1112
+ if (inClass) {
1113
+ this.debug(' in class');
1114
+ if (c === '!' && i === classStart + 1) c = '^';
1115
+ re += c;
1116
+ continue
1117
+ }
1118
+
1119
+ // coalesce consecutive non-globstar * characters
1120
+ if (c === '*' && stateChar === '*') continue
1121
+
1122
+ // if we already have a stateChar, then it means
1123
+ // that there was something like ** or +? in there.
1124
+ // Handle the stateChar, then proceed with this one.
1125
+ this.debug('call clearStateChar %j', stateChar);
1126
+ clearStateChar();
1127
+ stateChar = c;
1128
+ // if extglob is disabled, then +(asdf|foo) isn't a thing.
1129
+ // just clear the statechar *now*, rather than even diving into
1130
+ // the patternList stuff.
1131
+ if (options.noext) clearStateChar();
1132
+ continue
1133
+
1134
+ case '(': {
1135
+ if (inClass) {
1136
+ re += '(';
1137
+ continue
1138
+ }
1139
+
1140
+ if (!stateChar) {
1141
+ re += '\\(';
1142
+ continue
1143
+ }
1144
+
1145
+ const plEntry = {
1146
+ type: stateChar,
1147
+ start: i - 1,
1148
+ reStart: re.length,
1149
+ open: plTypes[stateChar].open,
1150
+ close: plTypes[stateChar].close,
1151
+ };
1152
+ this.debug(this.pattern, '\t', plEntry);
1153
+ patternListStack.push(plEntry);
1154
+ // negation is (?:(?!(?:js)(?:<rest>))[^/]*)
1155
+ re += plEntry.open;
1156
+ // next entry starts with a dot maybe?
1157
+ if (plEntry.start === 0 && plEntry.type !== '!') {
1158
+ dotTravAllowed = true;
1159
+ re += subPatternStart(pattern.slice(i + 1));
1160
+ }
1161
+ this.debug('plType %j %j', stateChar, re);
1162
+ stateChar = false;
1163
+ continue
1164
+ }
1165
+
1166
+ case ')': {
1167
+ const plEntry = patternListStack[patternListStack.length - 1];
1168
+ if (inClass || !plEntry) {
1169
+ re += '\\)';
1170
+ continue
1171
+ }
1172
+ patternListStack.pop();
1173
+
1174
+ // closing an extglob
1175
+ clearStateChar();
1176
+ hasMagic = true;
1177
+ pl = plEntry;
1178
+ // negation is (?:(?!js)[^/]*)
1179
+ // The others are (?:<pattern>)<type>
1180
+ re += pl.close;
1181
+ if (pl.type === '!') {
1182
+ negativeLists.push(Object.assign(pl, { reEnd: re.length }));
1183
+ }
1184
+ continue
1185
+ }
1186
+
1187
+ case '|': {
1188
+ const plEntry = patternListStack[patternListStack.length - 1];
1189
+ if (inClass || !plEntry) {
1190
+ re += '\\|';
1191
+ continue
1192
+ }
1193
+
1194
+ clearStateChar();
1195
+ re += '|';
1196
+ // next subpattern can start with a dot?
1197
+ if (plEntry.start === 0 && plEntry.type !== '!') {
1198
+ dotTravAllowed = true;
1199
+ re += subPatternStart(pattern.slice(i + 1));
1200
+ }
1201
+ continue
1202
+ }
1203
+
1204
+ // these are mostly the same in regexp and glob
1205
+ case '[':
1206
+ // swallow any state-tracking char before the [
1207
+ clearStateChar();
1208
+
1209
+ if (inClass) {
1210
+ re += '\\' + c;
1211
+ continue
1212
+ }
1213
+
1214
+ inClass = true;
1215
+ classStart = i;
1216
+ reClassStart = re.length;
1217
+ re += c;
1218
+ continue
1219
+
1220
+ case ']':
1221
+ // a right bracket shall lose its special
1222
+ // meaning and represent itself in
1223
+ // a bracket expression if it occurs
1224
+ // first in the list. -- POSIX.2 2.8.3.2
1225
+ if (i === classStart + 1 || !inClass) {
1226
+ re += '\\' + c;
1227
+ continue
1228
+ }
1229
+
1230
+ // split where the last [ was, make sure we don't have
1231
+ // an invalid re. if so, re-walk the contents of the
1232
+ // would-be class to re-translate any characters that
1233
+ // were passed through as-is
1234
+ // TODO: It would probably be faster to determine this
1235
+ // without a try/catch and a new RegExp, but it's tricky
1236
+ // to do safely. For now, this is safe and works.
1237
+ cs = pattern.substring(classStart + 1, i);
1238
+ try {
1239
+ RegExp('[' + braExpEscape(charUnescape(cs)) + ']');
1240
+ // looks good, finish up the class.
1241
+ re += c;
1242
+ } catch (er) {
1243
+ // out of order ranges in JS are errors, but in glob syntax,
1244
+ // they're just a range that matches nothing.
1245
+ re = re.substring(0, reClassStart) + '(?:$.)'; // match nothing ever
1246
+ }
1247
+ hasMagic = true;
1248
+ inClass = false;
1249
+ continue
1250
+
1251
+ default:
1252
+ // swallow any state char that wasn't consumed
1253
+ clearStateChar();
1254
+
1255
+ if (reSpecials[c] && !(c === '^' && inClass)) {
1256
+ re += '\\';
1257
+ }
1258
+
1259
+ re += c;
1260
+ break
1261
+
1262
+ } // switch
1263
+ } // for
1264
+
1265
+ // handle the case where we left a class open.
1266
+ // "[abc" is valid, equivalent to "\[abc"
1267
+ if (inClass) {
1268
+ // split where the last [ was, and escape it
1269
+ // this is a huge pita. We now have to re-walk
1270
+ // the contents of the would-be class to re-translate
1271
+ // any characters that were passed through as-is
1272
+ cs = pattern.slice(classStart + 1);
1273
+ sp = this.parse(cs, SUBPARSE);
1274
+ re = re.substring(0, reClassStart) + '\\[' + sp[0];
1275
+ hasMagic = hasMagic || sp[1];
1276
+ }
1277
+
1278
+ // handle the case where we had a +( thing at the *end*
1279
+ // of the pattern.
1280
+ // each pattern list stack adds 3 chars, and we need to go through
1281
+ // and escape any | chars that were passed through as-is for the regexp.
1282
+ // Go through and escape them, taking care not to double-escape any
1283
+ // | chars that were already escaped.
1284
+ for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
1285
+ let tail;
1286
+ tail = re.slice(pl.reStart + pl.open.length);
1287
+ this.debug('setting tail', re, pl);
1288
+ // maybe some even number of \, then maybe 1 \, followed by a |
1289
+ tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, (_, $1, $2) => {
1290
+ /* istanbul ignore else - should already be done */
1291
+ if (!$2) {
1292
+ // the | isn't already escaped, so escape it.
1293
+ $2 = '\\';
1294
+ }
1295
+
1296
+ // need to escape all those slashes *again*, without escaping the
1297
+ // one that we need for escaping the | character. As it works out,
1298
+ // escaping an even number of slashes can be done by simply repeating
1299
+ // it exactly after itself. That's why this trick works.
1300
+ //
1301
+ // I am sorry that you have to see this.
1302
+ return $1 + $1 + $2 + '|'
1303
+ });
1304
+
1305
+ this.debug('tail=%j\n %s', tail, tail, pl, re);
1306
+ const t = pl.type === '*' ? star
1307
+ : pl.type === '?' ? qmark
1308
+ : '\\' + pl.type;
1309
+
1310
+ hasMagic = true;
1311
+ re = re.slice(0, pl.reStart) + t + '\\(' + tail;
1143
1312
  }
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
- });
1313
+
1314
+ // handle trailing things that only matter at the very end.
1315
+ clearStateChar();
1316
+ if (escaping) {
1317
+ // trailing \\
1318
+ re += '\\\\';
1170
1319
  }
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
1320
+
1321
+ // only need to apply the nodot start if the re starts with
1322
+ // something that could conceivably capture a dot
1323
+ const addPatternStart = addPatternStartSet[re.charAt(0)];
1324
+
1325
+ // Hack to work around lack of negative lookbehind in JS
1326
+ // A pattern like: *.!(x).!(y|z) needs to ensure that a name
1327
+ // like 'a.xyz.yz' doesn't match. So, the first negative
1328
+ // lookahead, has to look ALL the way ahead, to the end of
1206
1329
  // the pattern.
1330
+ for (let n = negativeLists.length - 1; n > -1; n--) {
1331
+ const nl = negativeLists[n];
1332
+
1333
+ const nlBefore = re.slice(0, nl.reStart);
1334
+ const nlFirst = re.slice(nl.reStart, nl.reEnd - 8);
1335
+ let nlAfter = re.slice(nl.reEnd);
1336
+ const nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + nlAfter;
1337
+
1338
+ // Handle nested stuff like *(*.js|!(*.json)), where open parens
1339
+ // mean that we should *not* include the ) in the bit that is considered
1340
+ // "after" the negated section.
1341
+ const closeParensBefore = nlBefore.split(')').length;
1342
+ const openParensBefore = nlBefore.split('(').length - closeParensBefore;
1343
+ let cleanAfter = nlAfter;
1344
+ for (let i = 0; i < openParensBefore; i++) {
1345
+ cleanAfter = cleanAfter.replace(/\)[+*?]?/, '');
1346
+ }
1347
+ nlAfter = cleanAfter;
1348
+
1349
+ const dollar = nlAfter === '' && isSub !== SUBPARSE ? '(?:$|\\/)' : '';
1350
+
1351
+ re = nlBefore + nlFirst + nlAfter + dollar + nlLast;
1352
+ }
1353
+
1354
+ // if the re is not "" at this point, then we need to make sure
1355
+ // it doesn't match against an empty path part.
1356
+ // Otherwise a/* will match a/, which it should not.
1357
+ if (re !== '' && hasMagic) {
1358
+ re = '(?=.)' + re;
1359
+ }
1360
+
1361
+ if (addPatternStart) {
1362
+ re = patternStart() + re;
1363
+ }
1364
+
1365
+ // parsing just a piece of a larger pattern.
1366
+ if (isSub === SUBPARSE) {
1367
+ return [re, hasMagic]
1368
+ }
1369
+
1370
+ // if it's nocase, and the lcase/uppercase don't match, it's magic
1371
+ if (options.nocase && !hasMagic) {
1372
+ hasMagic = pattern.toUpperCase() !== pattern.toLowerCase();
1373
+ }
1374
+
1375
+ // skip the regexp for non-magical patterns
1376
+ // unescape anything in it, though, so that it'll be
1377
+ // an exact match against a file etc.
1378
+ if (!hasMagic) {
1379
+ return globUnescape(pattern)
1380
+ }
1381
+
1382
+ const flags = options.nocase ? 'i' : '';
1383
+ try {
1384
+ return Object.assign(new RegExp('^' + re + '$', flags), {
1385
+ _glob: pattern,
1386
+ _src: re,
1387
+ })
1388
+ } catch (er) /* istanbul ignore next - should be impossible */ {
1389
+ // If it was an invalid regular expression, then it can't match
1390
+ // anything. This trick looks for a character after the end of
1391
+ // the string, which is of course impossible, except in multi-line
1392
+ // mode, but it's not a /m regex.
1393
+ return new RegExp('$.')
1394
+ }
1395
+ }
1396
+
1397
+ makeRe () {
1398
+ if (this.regexp || this.regexp === false) return this.regexp
1399
+
1400
+ // at this point, this.set is a 2d array of partial
1401
+ // pattern strings, or "**".
1207
1402
  //
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
- ];
1306
- }
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;
1337
- }
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;
1403
+ // It's better to use .match(). This function shouldn't
1404
+ // be used, really, but it's pretty convenient sometimes,
1405
+ // when you just want to work with a regex.
1406
+ const set = this.set;
1407
+
1408
+ if (!set.length) {
1409
+ this.regexp = false;
1410
+ return this.regexp
1411
+ }
1412
+ const options = this.options;
1413
+
1414
+ const twoStar = options.noglobstar ? star
1415
+ : options.dot ? twoStarDot
1416
+ : twoStarNoDot;
1417
+ const flags = options.nocase ? 'i' : '';
1418
+
1419
+ // coalesce globstars and regexpify non-globstar patterns
1420
+ // if it's the only item, then we just do one twoStar
1421
+ // if it's the first, and there are more, prepend (\/|twoStar\/)? to next
1422
+ // if it's the last, append (\/twoStar|) to previous
1423
+ // if it's in the middle, append (\/|\/twoStar\/) to previous
1424
+ // then filter out GLOBSTAR symbols
1425
+ let re = set.map(pattern => {
1426
+ pattern = pattern.map(p =>
1427
+ typeof p === 'string' ? regExpEscape(p)
1428
+ : p === GLOBSTAR ? GLOBSTAR
1429
+ : p._src
1430
+ ).reduce((set, p) => {
1431
+ if (!(set[set.length - 1] === GLOBSTAR && p === GLOBSTAR)) {
1432
+ set.push(p);
1433
+ }
1434
+ return set
1435
+ }, []);
1436
+ pattern.forEach((p, i) => {
1437
+ if (p !== GLOBSTAR || pattern[i-1] === GLOBSTAR) {
1438
+ return
1439
+ }
1440
+ if (i === 0) {
1441
+ if (pattern.length > 1) {
1442
+ pattern[i+1] = '(?:\\\/|' + twoStar + '\\\/)?' + pattern[i+1];
1443
+ } else {
1444
+ pattern[i] = twoStar;
1445
+ }
1446
+ } else if (i === pattern.length - 1) {
1447
+ pattern[i-1] += '(?:\\\/|' + twoStar + ')?';
1448
+ } else {
1449
+ pattern[i-1] += '(?:\\\/|\\\/' + twoStar + '\\\/)' + pattern[i+1];
1450
+ pattern[i+1] = GLOBSTAR;
1351
1451
  }
1352
- return [
1353
- final,
1354
- (0, unescape_js_1.unescape)(body),
1355
- (this.#hasMagic = !!this.#hasMagic),
1356
- this.#uflag,
1357
- ];
1452
+ });
1453
+ return pattern.filter(p => p !== GLOBSTAR).join('/')
1454
+ }).join('|');
1455
+
1456
+ // must match entire pattern
1457
+ // ending in a * or ** will make it less strict.
1458
+ re = '^(?:' + re + ')$';
1459
+
1460
+ // can match anything, as long as it's not this.
1461
+ if (this.negate) re = '^(?!' + re + ').*$';
1462
+
1463
+ try {
1464
+ this.regexp = new RegExp(re, flags);
1465
+ } catch (ex) /* istanbul ignore next - should be impossible */ {
1466
+ this.regexp = false;
1358
1467
  }
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);
1461
- }
1462
- return [re, (0, unescape_js_1.unescape)(glob), !!hasMagic, uflag];
1468
+ return this.regexp
1469
+ }
1470
+
1471
+ match (f, partial = this.partial) {
1472
+ this.debug('match', f, this.pattern);
1473
+ // short-circuit in the case of busted things.
1474
+ // comments, etc.
1475
+ if (this.comment) return false
1476
+ if (this.empty) return f === ''
1477
+
1478
+ if (f === '/' && partial) return true
1479
+
1480
+ const options = this.options;
1481
+
1482
+ // windows: need to use /, not \
1483
+ if (path.sep !== '/') {
1484
+ f = f.split(path.sep).join('/');
1463
1485
  }
1464
- }
1465
- ast.AST = AST;
1466
- _a = AST;
1467
-
1468
- return ast;
1469
- }
1470
1486
 
1471
- var _escape = {};
1487
+ // treat the test path as a set of pathparts.
1488
+ f = f.split(slashSplit);
1489
+ this.debug(this.pattern, 'split', f);
1472
1490
 
1473
- var hasRequired_escape;
1491
+ // just ONE of the pattern sets in this.set needs to match
1492
+ // in order for it to be valid. If negating, then just one
1493
+ // match means that we have failed.
1494
+ // Either way, return on the first hit.
1474
1495
 
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
- }
1496
+ const set = this.set;
1497
+ this.debug(this.pattern, 'set', set);
1509
1498
 
1510
- var hasRequiredCommonjs;
1499
+ // Find the basename of the path by looking for the last non-empty segment
1500
+ let filename;
1501
+ for (let i = f.length - 1; i >= 0; i--) {
1502
+ filename = f[i];
1503
+ if (filename) break
1504
+ }
1511
1505
 
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;
1506
+ for (let i = 0; i < set.length; i++) {
1507
+ const pattern = set[i];
1508
+ let file = f;
1509
+ if (options.matchBase && pattern.length === 1) {
1510
+ file = [filename];
1511
+ }
1512
+ const hit = this.matchOne(file, pattern, partial);
1513
+ if (hit) {
1514
+ if (options.flipNegate) return true
1515
+ return !this.negate
1516
+ }
1517
+ }
1518
+
1519
+ // didn't get any hits. this is success if it's a negative
1520
+ // pattern, failure otherwise.
1521
+ if (options.flipNegate) return false
1522
+ return this.negate
1523
+ }
1524
+
1525
+ static defaults (def) {
1526
+ return minimatch.defaults(def).Minimatch
1527
+ }
1528
+ }
1529
+
1530
+ minimatch.Minimatch = Minimatch;
1531
+ return minimatch_1;
2644
1532
  }
2645
1533
 
2646
1534
  var jsYaml$1 = {};
@@ -3760,7 +2648,7 @@ function requireOmap$1 () {
3760
2648
  function resolveYamlOmap (data) {
3761
2649
  if (data === null) return true
3762
2650
 
3763
- const objectKeys = [];
2651
+ const objectKeys = {};
3764
2652
  const object = data;
3765
2653
 
3766
2654
  for (let index = 0, length = object.length; index < length; index += 1) {
@@ -3779,8 +2667,8 @@ function requireOmap$1 () {
3779
2667
 
3780
2668
  if (!pairHasKey) return false
3781
2669
 
3782
- if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey);
3783
- else return false
2670
+ if (_hasOwnProperty.call(objectKeys, pairKey)) return false
2671
+ Object.defineProperty(objectKeys, pairKey, { value: true });
3784
2672
  }
3785
2673
 
3786
2674
  return true
@@ -4292,19 +3180,28 @@ function requireLoader$1 () {
4292
3180
  }
4293
3181
  }
4294
3182
 
3183
+ function chargeMergeWork (state) {
3184
+ state.totalMergeKeys++;
3185
+
3186
+ if (state.maxTotalMergeKeys !== -1 && state.totalMergeKeys > state.maxTotalMergeKeys) {
3187
+ throwError(state, 'merge keys exceeded maxTotalMergeKeys (' + state.maxTotalMergeKeys + ')');
3188
+ }
3189
+ }
3190
+
4295
3191
  function mergeMappings (state, destination, source, overridableKeys) {
4296
3192
  if (!common.isObject(source)) {
4297
3193
  throwError(state, 'cannot merge mappings; the provided source object is unacceptable');
4298
3194
  }
4299
3195
 
3196
+ // Count the source mapping itself to bound sequences of empty mappings.
3197
+ chargeMergeWork(state);
3198
+
4300
3199
  const sourceKeys = Object.keys(source);
4301
3200
 
4302
3201
  for (let index = 0, quantity = sourceKeys.length; index < quantity; index += 1) {
4303
3202
  const key = sourceKeys[index];
4304
3203
 
4305
- if (state.maxTotalMergeKeys !== -1 && ++state.totalMergeKeys > state.maxTotalMergeKeys) {
4306
- throwError(state, 'merge keys exceeded maxTotalMergeKeys (' + state.maxTotalMergeKeys + ')');
4307
- }
3204
+ chargeMergeWork(state);
4308
3205
 
4309
3206
  if (!_hasOwnProperty.call(destination, key)) {
4310
3207
  setProperty(destination, key, source[key]);
@@ -4347,6 +3244,10 @@ function requireLoader$1 () {
4347
3244
 
4348
3245
  if (keyTag === 'tag:yaml.org,2002:merge') {
4349
3246
  if (Array.isArray(valueNode)) {
3247
+ if (valueNode.length > 100) {
3248
+ throwError(state, 'abnormal merge sequence size');
3249
+ }
3250
+
4350
3251
  for (let index = 0, quantity = valueNode.length; index < quantity; index += 1) {
4351
3252
  mergeMappings(state, _result, valueNode[index], overridableKeys);
4352
3253
  }
@@ -9099,7 +8000,7 @@ function requireUtils$3 () {
9099
8000
  exports.dequal = dequal;
9100
8001
  const fs = require$$0$5;
9101
8002
  const path_1 = require$$1$4;
9102
- const minimatch = requireCommonjs();
8003
+ const minimatch = requireMinimatch();
9103
8004
  const js_yaml_1 = requireJsYaml();
9104
8005
  const env_1 = requireEnv();
9105
8006
  const logger_1 = requireLogger();
@@ -13464,10 +12365,6 @@ const navItemSchema = {
13464
12365
  },
13465
12366
  // Allow users to eject the navbar and implement additional levels of nesting
13466
12367
  items: { type: 'array', items: { type: 'object', additionalProperties: true } },
13467
- rbac: {
13468
- type: 'object',
13469
- additionalProperties: { type: 'string' },
13470
- },
13471
12368
  },
13472
12369
  };
13473
12370
  const navItemsSchema = {
@@ -14745,7 +13642,9 @@ function requireOasTypes () {
14745
13642
  if (typeof root.openapi === 'string' && root.openapi.startsWith('3.0')) {
14746
13643
  return SpecVersion.OAS3_0;
14747
13644
  }
14748
- if (typeof root.openapi === 'string' && root.openapi.startsWith('3.1')) {
13645
+ if (typeof root.openapi === 'string' &&
13646
+ (root.openapi.startsWith('3.1') || root.openapi.startsWith('3.2')) // temporary support for 3.2
13647
+ ) {
14749
13648
  return SpecVersion.OAS3_1;
14750
13649
  }
14751
13650
  if (root.swagger && root.swagger === '2.0') {
@@ -30807,7 +29706,7 @@ var redocly = {};
30807
29706
  var registryApi = {};
30808
29707
 
30809
29708
  const name = "@redocly/openapi-core";
30810
- const version = "1.34.5";
29709
+ const version = "1.34.19";
30811
29710
  const description = "";
30812
29711
  const main = "lib/index.js";
30813
29712
  const engines = {
@@ -30842,14 +29741,14 @@ const contributors = [
30842
29741
  "Roman Hotsiy <roman@redocly.com> (https://redocly.com/)"
30843
29742
  ];
30844
29743
  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",
29744
+ "@redocly/ajv": "8.11.2",
29745
+ "@redocly/config": "0.22.0",
29746
+ colorette: "1.4.0",
29747
+ "https-proxy-agent": "7.0.6",
29748
+ "js-levenshtein": "1.1.6",
29749
+ "js-yaml": "4.3.1",
29750
+ minimatch: "5.1.9",
29751
+ pluralize: "8.0.0",
30853
29752
  "yaml-ast-parser": "0.0.43"
30854
29753
  };
30855
29754
  const devDependencies = {