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