@shopware/api-gen 1.4.0 → 1.5.0
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 +16 -27
- package/dist/cli.mjs +784 -394
- package/dist/index.d.mts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.mjs +4 -4
- package/dist/shared/{api-gen.BWZPGkRz.mjs → api-gen.a71ec925.mjs} +205 -791
- package/package.json +9 -8
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import yargs from 'yargs';
|
|
2
2
|
import { hideBin } from 'yargs/helpers';
|
|
3
|
-
import {
|
|
3
|
+
import { g as getAugmentedNamespace, c as commonjsGlobal, a as generate, l as loadSchema, v as validateJson } from './shared/api-gen.a71ec925.mjs';
|
|
4
4
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
5
5
|
import { resolve as resolve$4 } from 'node:path';
|
|
6
6
|
import require$$0$5 from 'fs';
|
|
@@ -18,9 +18,9 @@ import require$$0$6 from 'buffer';
|
|
|
18
18
|
import { format as format$5 } from 'prettier';
|
|
19
19
|
import 'openapi-typescript';
|
|
20
20
|
import 'typescript';
|
|
21
|
+
import 'crypto';
|
|
21
22
|
import 'ofetch';
|
|
22
23
|
import 'ts-morph';
|
|
23
|
-
import 'crypto';
|
|
24
24
|
import '@shopware/api-client';
|
|
25
25
|
|
|
26
26
|
|
|
@@ -33,7 +33,7 @@ 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
35
|
const name$1 = "@shopware/api-gen";
|
|
36
|
-
const version$2 = "1.
|
|
36
|
+
const version$2 = "1.5.0";
|
|
37
37
|
const description$2 = "Shopware CLI for API client generation.";
|
|
38
38
|
const author = "Shopware";
|
|
39
39
|
const type$b = "module";
|
|
@@ -73,7 +73,7 @@ const scripts = {
|
|
|
73
73
|
dev: "export NODE_ENV=development && unbuild --stub",
|
|
74
74
|
lint: "biome check .",
|
|
75
75
|
"lint:fix": "biome check --write . && pnpm run typecheck",
|
|
76
|
-
typecheck: "
|
|
76
|
+
typecheck: "tsgo --noEmit",
|
|
77
77
|
test: "vitest run --typecheck",
|
|
78
78
|
"test:bench": "vitest bench",
|
|
79
79
|
"test:watch": "vitest --typecheck"
|
|
@@ -81,20 +81,21 @@ const scripts = {
|
|
|
81
81
|
const devDependencies$1 = {
|
|
82
82
|
"@biomejs/biome": "1.8.3",
|
|
83
83
|
"@types/prettier": "3.0.0",
|
|
84
|
-
"@types/yargs": "17.0.
|
|
85
|
-
"@
|
|
84
|
+
"@types/yargs": "17.0.35",
|
|
85
|
+
"@typescript/native-preview": "7.0.0-dev.20260111.1",
|
|
86
|
+
"@vitest/coverage-v8": "4.0.18",
|
|
86
87
|
json5: "2.2.3",
|
|
87
88
|
picocolors: "1.1.1",
|
|
88
89
|
tsconfig: "workspace:*",
|
|
89
90
|
unbuild: "2.0.0",
|
|
90
|
-
vitest: "
|
|
91
|
+
vitest: "4.0.18"
|
|
91
92
|
};
|
|
92
93
|
const dependencies$2 = {
|
|
93
94
|
"@shopware/api-client": "workspace:*",
|
|
94
|
-
ofetch: "1.
|
|
95
|
+
ofetch: "1.5.1",
|
|
95
96
|
"openapi-typescript": "7.8.0",
|
|
96
97
|
prettier: "3.7.4",
|
|
97
|
-
"ts-morph": "
|
|
98
|
+
"ts-morph": "27.0.2",
|
|
98
99
|
typescript: "5.9.3",
|
|
99
100
|
yargs: "18.0.0"
|
|
100
101
|
};
|
|
@@ -188,199 +189,207 @@ var commonjs = {};
|
|
|
188
189
|
|
|
189
190
|
} (commonjs));
|
|
190
191
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
const
|
|
198
|
-
const
|
|
199
|
-
const
|
|
200
|
-
const
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
const
|
|
205
|
-
const
|
|
206
|
-
const
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
function
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
192
|
+
(function (exports) {
|
|
193
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
194
|
+
exports.EXPANSION_MAX = void 0;
|
|
195
|
+
exports.expand = expand;
|
|
196
|
+
const balanced_match_1 = commonjs;
|
|
197
|
+
const escSlash = '\0SLASH' + Math.random() + '\0';
|
|
198
|
+
const escOpen = '\0OPEN' + Math.random() + '\0';
|
|
199
|
+
const escClose = '\0CLOSE' + Math.random() + '\0';
|
|
200
|
+
const escComma = '\0COMMA' + Math.random() + '\0';
|
|
201
|
+
const escPeriod = '\0PERIOD' + Math.random() + '\0';
|
|
202
|
+
const escSlashPattern = new RegExp(escSlash, 'g');
|
|
203
|
+
const escOpenPattern = new RegExp(escOpen, 'g');
|
|
204
|
+
const escClosePattern = new RegExp(escClose, 'g');
|
|
205
|
+
const escCommaPattern = new RegExp(escComma, 'g');
|
|
206
|
+
const escPeriodPattern = new RegExp(escPeriod, 'g');
|
|
207
|
+
const slashPattern = /\\\\/g;
|
|
208
|
+
const openPattern = /\\{/g;
|
|
209
|
+
const closePattern = /\\}/g;
|
|
210
|
+
const commaPattern = /\\,/g;
|
|
211
|
+
const periodPattern = /\\\./g;
|
|
212
|
+
exports.EXPANSION_MAX = 100_000;
|
|
213
|
+
function numeric(str) {
|
|
214
|
+
return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
|
|
215
|
+
}
|
|
216
|
+
function escapeBraces(str) {
|
|
217
|
+
return str
|
|
218
|
+
.replace(slashPattern, escSlash)
|
|
219
|
+
.replace(openPattern, escOpen)
|
|
220
|
+
.replace(closePattern, escClose)
|
|
221
|
+
.replace(commaPattern, escComma)
|
|
222
|
+
.replace(periodPattern, escPeriod);
|
|
223
|
+
}
|
|
224
|
+
function unescapeBraces(str) {
|
|
225
|
+
return str
|
|
226
|
+
.replace(escSlashPattern, '\\')
|
|
227
|
+
.replace(escOpenPattern, '{')
|
|
228
|
+
.replace(escClosePattern, '}')
|
|
229
|
+
.replace(escCommaPattern, ',')
|
|
230
|
+
.replace(escPeriodPattern, '.');
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Basically just str.split(","), but handling cases
|
|
234
|
+
* where we have nested braced sections, which should be
|
|
235
|
+
* treated as individual members, like {a,{b,c},d}
|
|
236
|
+
*/
|
|
237
|
+
function parseCommaParts(str) {
|
|
238
|
+
if (!str) {
|
|
239
|
+
return [''];
|
|
240
|
+
}
|
|
241
|
+
const parts = [];
|
|
242
|
+
const m = (0, balanced_match_1.balanced)('{', '}', str);
|
|
243
|
+
if (!m) {
|
|
244
|
+
return str.split(',');
|
|
245
|
+
}
|
|
246
|
+
const { pre, body, post } = m;
|
|
247
|
+
const p = pre.split(',');
|
|
248
|
+
p[p.length - 1] += '{' + body + '}';
|
|
249
|
+
const postParts = parseCommaParts(post);
|
|
250
|
+
if (post.length) {
|
|
251
|
+
p[p.length - 1] += postParts.shift();
|
|
252
|
+
p.push.apply(p, postParts);
|
|
253
|
+
}
|
|
254
|
+
parts.push.apply(parts, p);
|
|
255
|
+
return parts;
|
|
256
|
+
}
|
|
257
|
+
function expand(str, options = {}) {
|
|
258
|
+
if (!str) {
|
|
259
|
+
return [];
|
|
260
|
+
}
|
|
261
|
+
const { max = exports.EXPANSION_MAX } = options;
|
|
262
|
+
// I don't know why Bash 4.3 does this, but it does.
|
|
263
|
+
// Anything starting with {} will have the first two bytes preserved
|
|
264
|
+
// but *only* at the top level, so {},a}b will not expand to anything,
|
|
265
|
+
// but a{},b}c will be expanded to [a}c,abc].
|
|
266
|
+
// One could argue that this is a bug in Bash, but since the goal of
|
|
267
|
+
// this module is to match Bash's rules, we escape a leading {}
|
|
268
|
+
if (str.slice(0, 2) === '{}') {
|
|
269
|
+
str = '\\{\\}' + str.slice(2);
|
|
270
|
+
}
|
|
271
|
+
return expand_(escapeBraces(str), max, true).map(unescapeBraces);
|
|
272
|
+
}
|
|
273
|
+
function embrace(str) {
|
|
274
|
+
return '{' + str + '}';
|
|
275
|
+
}
|
|
276
|
+
function isPadded(el) {
|
|
277
|
+
return /^-?0\d/.test(el);
|
|
278
|
+
}
|
|
279
|
+
function lte(i, y) {
|
|
280
|
+
return i <= y;
|
|
281
|
+
}
|
|
282
|
+
function gte(i, y) {
|
|
283
|
+
return i >= y;
|
|
284
|
+
}
|
|
285
|
+
function expand_(str, max, isTop) {
|
|
286
|
+
/** @type {string[]} */
|
|
287
|
+
const expansions = [];
|
|
288
|
+
const m = (0, balanced_match_1.balanced)('{', '}', str);
|
|
289
|
+
if (!m)
|
|
290
|
+
return [str];
|
|
291
|
+
// no need to expand pre, since it is guaranteed to be free of brace-sets
|
|
292
|
+
const pre = m.pre;
|
|
293
|
+
const post = m.post.length ? expand_(m.post, max, false) : [''];
|
|
294
|
+
if (/\$$/.test(m.pre)) {
|
|
295
|
+
for (let k = 0; k < post.length && k < max; k++) {
|
|
296
|
+
const expansion = pre + '{' + m.body + '}' + post[k];
|
|
297
|
+
expansions.push(expansion);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
|
|
302
|
+
const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
|
|
303
|
+
const isSequence = isNumericSequence || isAlphaSequence;
|
|
304
|
+
const isOptions = m.body.indexOf(',') >= 0;
|
|
305
|
+
if (!isSequence && !isOptions) {
|
|
306
|
+
// {a},b}
|
|
307
|
+
if (m.post.match(/,(?!,).*\}/)) {
|
|
308
|
+
str = m.pre + '{' + m.body + escClose + m.post;
|
|
309
|
+
return expand_(str, max, true);
|
|
310
|
+
}
|
|
311
|
+
return [str];
|
|
312
|
+
}
|
|
313
|
+
let n;
|
|
314
|
+
if (isSequence) {
|
|
315
|
+
n = m.body.split(/\.\./);
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
n = parseCommaParts(m.body);
|
|
319
|
+
if (n.length === 1 && n[0] !== undefined) {
|
|
320
|
+
// x{{a,b}}y ==> x{a}y x{b}y
|
|
321
|
+
n = expand_(n[0], max, false).map(embrace);
|
|
322
|
+
//XXX is this necessary? Can't seem to hit it in tests.
|
|
323
|
+
/* c8 ignore start */
|
|
324
|
+
if (n.length === 1) {
|
|
325
|
+
return post.map(p => m.pre + n[0] + p);
|
|
326
|
+
}
|
|
327
|
+
/* c8 ignore stop */
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
// at this point, n is the parts, and we know it's not a comma set
|
|
331
|
+
// with a single entry.
|
|
332
|
+
let N;
|
|
333
|
+
if (isSequence && n[0] !== undefined && n[1] !== undefined) {
|
|
334
|
+
const x = numeric(n[0]);
|
|
335
|
+
const y = numeric(n[1]);
|
|
336
|
+
const width = Math.max(n[0].length, n[1].length);
|
|
337
|
+
let incr = n.length === 3 && n[2] !== undefined ?
|
|
338
|
+
Math.max(Math.abs(numeric(n[2])), 1)
|
|
339
|
+
: 1;
|
|
340
|
+
let test = lte;
|
|
341
|
+
const reverse = y < x;
|
|
342
|
+
if (reverse) {
|
|
343
|
+
incr *= -1;
|
|
344
|
+
test = gte;
|
|
345
|
+
}
|
|
346
|
+
const pad = n.some(isPadded);
|
|
347
|
+
N = [];
|
|
348
|
+
for (let i = x; test(i, y); i += incr) {
|
|
349
|
+
let c;
|
|
350
|
+
if (isAlphaSequence) {
|
|
351
|
+
c = String.fromCharCode(i);
|
|
352
|
+
if (c === '\\') {
|
|
353
|
+
c = '';
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
c = String(i);
|
|
358
|
+
if (pad) {
|
|
359
|
+
const need = width - c.length;
|
|
360
|
+
if (need > 0) {
|
|
361
|
+
const z = new Array(need + 1).join('0');
|
|
362
|
+
if (i < 0) {
|
|
363
|
+
c = '-' + z + c.slice(1);
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
c = z + c;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
N.push(c);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
N = [];
|
|
376
|
+
for (let j = 0; j < n.length; j++) {
|
|
377
|
+
N.push.apply(N, expand_(n[j], max, false));
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
for (let j = 0; j < N.length; j++) {
|
|
381
|
+
for (let k = 0; k < post.length && expansions.length < max; k++) {
|
|
382
|
+
const expansion = pre + N[j] + post[k];
|
|
383
|
+
if (!isTop || isSequence || expansion) {
|
|
384
|
+
expansions.push(expansion);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return expansions;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
} (commonjs$1));
|
|
384
393
|
|
|
385
394
|
var assertValidPattern$1 = {};
|
|
386
395
|
|
|
@@ -543,10 +552,8 @@ const parseClass = (glob, position) => {
|
|
|
543
552
|
}
|
|
544
553
|
const sranges = '[' + (negate ? '^' : '') + rangesToString(ranges) + ']';
|
|
545
554
|
const snegs = '[' + (negate ? '' : '^') + rangesToString(negs) + ']';
|
|
546
|
-
const comb = ranges.length && negs.length
|
|
547
|
-
|
|
548
|
-
: ranges.length
|
|
549
|
-
? sranges
|
|
555
|
+
const comb = ranges.length && negs.length ? '(' + sranges + '|' + snegs + ')'
|
|
556
|
+
: ranges.length ? sranges
|
|
550
557
|
: snegs;
|
|
551
558
|
return [comb, uflag, endPos - pos, true];
|
|
552
559
|
};
|
|
@@ -559,31 +566,147 @@ _unescape.unescape = void 0;
|
|
|
559
566
|
/**
|
|
560
567
|
* Un-escape a string that has been escaped with {@link escape}.
|
|
561
568
|
*
|
|
562
|
-
* If the {@link windowsPathsNoEscape} option is used, then
|
|
563
|
-
* escapes are removed, but not backslash escapes.
|
|
564
|
-
*
|
|
565
|
-
*
|
|
569
|
+
* If the {@link MinimatchOptions.windowsPathsNoEscape} option is used, then
|
|
570
|
+
* square-bracket escapes are removed, but not backslash escapes.
|
|
571
|
+
*
|
|
572
|
+
* For example, it will turn the string `'[*]'` into `*`, but it will not
|
|
573
|
+
* turn `'\\*'` into `'*'`, because `\` is a path separator in
|
|
574
|
+
* `windowsPathsNoEscape` mode.
|
|
566
575
|
*
|
|
567
|
-
* When `windowsPathsNoEscape` is not set, then both
|
|
576
|
+
* When `windowsPathsNoEscape` is not set, then both square-bracket escapes and
|
|
568
577
|
* backslash escapes are removed.
|
|
569
578
|
*
|
|
570
579
|
* Slashes (and backslashes in `windowsPathsNoEscape` mode) cannot be escaped
|
|
571
580
|
* or unescaped.
|
|
581
|
+
*
|
|
582
|
+
* When `magicalBraces` is not set, escapes of braces (`{` and `}`) will not be
|
|
583
|
+
* unescaped.
|
|
572
584
|
*/
|
|
573
|
-
const unescape = (s, { windowsPathsNoEscape = false, } = {}) => {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
585
|
+
const unescape = (s, { windowsPathsNoEscape = false, magicalBraces = true, } = {}) => {
|
|
586
|
+
if (magicalBraces) {
|
|
587
|
+
return windowsPathsNoEscape ?
|
|
588
|
+
s.replace(/\[([^\/\\])\]/g, '$1')
|
|
589
|
+
: s
|
|
590
|
+
.replace(/((?!\\).|^)\[([^\/\\])\]/g, '$1$2')
|
|
591
|
+
.replace(/\\([^\/])/g, '$1');
|
|
592
|
+
}
|
|
593
|
+
return windowsPathsNoEscape ?
|
|
594
|
+
s.replace(/\[([^\/\\{}])\]/g, '$1')
|
|
595
|
+
: s
|
|
596
|
+
.replace(/((?!\\).|^)\[([^\/\\{}])\]/g, '$1$2')
|
|
597
|
+
.replace(/\\([^\/{}])/g, '$1');
|
|
577
598
|
};
|
|
578
599
|
_unescape.unescape = unescape;
|
|
579
600
|
|
|
580
601
|
// parse a single path portion
|
|
602
|
+
var _a;
|
|
581
603
|
Object.defineProperty(ast$3, "__esModule", { value: true });
|
|
582
604
|
ast$3.AST = void 0;
|
|
583
605
|
const brace_expressions_js_1 = braceExpressions;
|
|
584
606
|
const unescape_js_1 = _unescape;
|
|
585
607
|
const types$3 = new Set(['!', '?', '+', '*', '@']);
|
|
586
608
|
const isExtglobType = (c) => types$3.has(c);
|
|
609
|
+
const isExtglobAST = (c) => isExtglobType(c.type);
|
|
610
|
+
// Map of which extglob types can adopt the children of a nested extglob
|
|
611
|
+
//
|
|
612
|
+
// anything but ! can adopt a matching type:
|
|
613
|
+
// +(a|+(b|c)|d) => +(a|b|c|d)
|
|
614
|
+
// *(a|*(b|c)|d) => *(a|b|c|d)
|
|
615
|
+
// @(a|@(b|c)|d) => @(a|b|c|d)
|
|
616
|
+
// ?(a|?(b|c)|d) => ?(a|b|c|d)
|
|
617
|
+
//
|
|
618
|
+
// * can adopt anything, because 0 or repetition is allowed
|
|
619
|
+
// *(a|?(b|c)|d) => *(a|b|c|d)
|
|
620
|
+
// *(a|+(b|c)|d) => *(a|b|c|d)
|
|
621
|
+
// *(a|@(b|c)|d) => *(a|b|c|d)
|
|
622
|
+
//
|
|
623
|
+
// + can adopt @, because 1 or repetition is allowed
|
|
624
|
+
// +(a|@(b|c)|d) => +(a|b|c|d)
|
|
625
|
+
//
|
|
626
|
+
// + and @ CANNOT adopt *, because 0 would be allowed
|
|
627
|
+
// +(a|*(b|c)|d) => would match "", on *(b|c)
|
|
628
|
+
// @(a|*(b|c)|d) => would match "", on *(b|c)
|
|
629
|
+
//
|
|
630
|
+
// + and @ CANNOT adopt ?, because 0 would be allowed
|
|
631
|
+
// +(a|?(b|c)|d) => would match "", on ?(b|c)
|
|
632
|
+
// @(a|?(b|c)|d) => would match "", on ?(b|c)
|
|
633
|
+
//
|
|
634
|
+
// ? can adopt @, because 0 or 1 is allowed
|
|
635
|
+
// ?(a|@(b|c)|d) => ?(a|b|c|d)
|
|
636
|
+
//
|
|
637
|
+
// ? and @ CANNOT adopt * or +, because >1 would be allowed
|
|
638
|
+
// ?(a|*(b|c)|d) => would match bbb on *(b|c)
|
|
639
|
+
// @(a|*(b|c)|d) => would match bbb on *(b|c)
|
|
640
|
+
// ?(a|+(b|c)|d) => would match bbb on +(b|c)
|
|
641
|
+
// @(a|+(b|c)|d) => would match bbb on +(b|c)
|
|
642
|
+
//
|
|
643
|
+
// ! CANNOT adopt ! (nothing else can either)
|
|
644
|
+
// !(a|!(b|c)|d) => !(a|b|c|d) would fail to match on b (not not b|c)
|
|
645
|
+
//
|
|
646
|
+
// ! can adopt @
|
|
647
|
+
// !(a|@(b|c)|d) => !(a|b|c|d)
|
|
648
|
+
//
|
|
649
|
+
// ! CANNOT adopt *
|
|
650
|
+
// !(a|*(b|c)|d) => !(a|b|c|d) would match on bbb, not allowed
|
|
651
|
+
//
|
|
652
|
+
// ! CANNOT adopt +
|
|
653
|
+
// !(a|+(b|c)|d) => !(a|b|c|d) would match on bbb, not allowed
|
|
654
|
+
//
|
|
655
|
+
// ! CANNOT adopt ?
|
|
656
|
+
// x!(a|?(b|c)|d) => x!(a|b|c|d) would fail to match "x"
|
|
657
|
+
const adoptionMap = new Map([
|
|
658
|
+
['!', ['@']],
|
|
659
|
+
['?', ['?', '@']],
|
|
660
|
+
['@', ['@']],
|
|
661
|
+
['*', ['*', '+', '?', '@']],
|
|
662
|
+
['+', ['+', '@']],
|
|
663
|
+
]);
|
|
664
|
+
// nested extglobs that can be adopted in, but with the addition of
|
|
665
|
+
// a blank '' element.
|
|
666
|
+
const adoptionWithSpaceMap = new Map([
|
|
667
|
+
['!', ['?']],
|
|
668
|
+
['@', ['?']],
|
|
669
|
+
['+', ['?', '*']],
|
|
670
|
+
]);
|
|
671
|
+
// union of the previous two maps
|
|
672
|
+
const adoptionAnyMap = new Map([
|
|
673
|
+
['!', ['?', '@']],
|
|
674
|
+
['?', ['?', '@']],
|
|
675
|
+
['@', ['?', '@']],
|
|
676
|
+
['*', ['*', '+', '?', '@']],
|
|
677
|
+
['+', ['+', '@', '?', '*']],
|
|
678
|
+
]);
|
|
679
|
+
// Extglobs that can take over their parent if they are the only child
|
|
680
|
+
// the key is parent, value maps child to resulting extglob parent type
|
|
681
|
+
// '@' is omitted because it's a special case. An `@` extglob with a single
|
|
682
|
+
// member can always be usurped by that subpattern.
|
|
683
|
+
const usurpMap = new Map([
|
|
684
|
+
['!', new Map([['!', '@']])],
|
|
685
|
+
[
|
|
686
|
+
'?',
|
|
687
|
+
new Map([
|
|
688
|
+
['*', '*'],
|
|
689
|
+
['+', '*'],
|
|
690
|
+
]),
|
|
691
|
+
],
|
|
692
|
+
[
|
|
693
|
+
'@',
|
|
694
|
+
new Map([
|
|
695
|
+
['!', '!'],
|
|
696
|
+
['?', '?'],
|
|
697
|
+
['@', '@'],
|
|
698
|
+
['*', '*'],
|
|
699
|
+
['+', '+'],
|
|
700
|
+
]),
|
|
701
|
+
],
|
|
702
|
+
[
|
|
703
|
+
'+',
|
|
704
|
+
new Map([
|
|
705
|
+
['?', '*'],
|
|
706
|
+
['*', '*'],
|
|
707
|
+
]),
|
|
708
|
+
],
|
|
709
|
+
]);
|
|
587
710
|
// Patterns that get prepended to bind to the start of either the
|
|
588
711
|
// entire string, or just a single path portion, to prevent dots
|
|
589
712
|
// and/or traversal patterns, when needed.
|
|
@@ -607,6 +730,7 @@ const star = qmark + '*?';
|
|
|
607
730
|
const starNoEmpty = qmark + '+?';
|
|
608
731
|
// remove the \ chars that we added if we end up doing a nonmagic compare
|
|
609
732
|
// const deslash = (s: string) => s.replace(/\\(.)/g, '$1')
|
|
733
|
+
let ID = 0;
|
|
610
734
|
class AST {
|
|
611
735
|
type;
|
|
612
736
|
#root;
|
|
@@ -622,6 +746,22 @@ class AST {
|
|
|
622
746
|
// set to true if it's an extglob with no children
|
|
623
747
|
// (which really means one child of '')
|
|
624
748
|
#emptyExt = false;
|
|
749
|
+
id = ++ID;
|
|
750
|
+
get depth() {
|
|
751
|
+
return (this.#parent?.depth ?? -1) + 1;
|
|
752
|
+
}
|
|
753
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
754
|
+
return {
|
|
755
|
+
'@@type': 'AST',
|
|
756
|
+
id: this.id,
|
|
757
|
+
type: this.type,
|
|
758
|
+
root: this.#root.id,
|
|
759
|
+
parent: this.#parent?.id,
|
|
760
|
+
depth: this.depth,
|
|
761
|
+
partsLength: this.#parts.length,
|
|
762
|
+
parts: this.#parts,
|
|
763
|
+
};
|
|
764
|
+
}
|
|
625
765
|
constructor(type, parent, options = {}) {
|
|
626
766
|
this.type = type;
|
|
627
767
|
// extglobs are inherently magical
|
|
@@ -700,7 +840,8 @@ class AST {
|
|
|
700
840
|
if (p === '')
|
|
701
841
|
continue;
|
|
702
842
|
/* c8 ignore start */
|
|
703
|
-
if (typeof p !== 'string' &&
|
|
843
|
+
if (typeof p !== 'string' &&
|
|
844
|
+
!(p instanceof _a && p.#parent === this)) {
|
|
704
845
|
throw new Error('invalid part: ' + p);
|
|
705
846
|
}
|
|
706
847
|
/* c8 ignore stop */
|
|
@@ -708,8 +849,10 @@ class AST {
|
|
|
708
849
|
}
|
|
709
850
|
}
|
|
710
851
|
toJSON() {
|
|
711
|
-
const ret = this.type === null
|
|
712
|
-
|
|
852
|
+
const ret = this.type === null ?
|
|
853
|
+
this.#parts
|
|
854
|
+
.slice()
|
|
855
|
+
.map(p => (typeof p === 'string' ? p : p.toJSON()))
|
|
713
856
|
: [this.type, ...this.#parts.map(p => p.toJSON())];
|
|
714
857
|
if (this.isStart() && !this.type)
|
|
715
858
|
ret.unshift([]);
|
|
@@ -732,7 +875,7 @@ class AST {
|
|
|
732
875
|
const p = this.#parent;
|
|
733
876
|
for (let i = 0; i < this.#parentIndex; i++) {
|
|
734
877
|
const pp = p.#parts[i];
|
|
735
|
-
if (!(pp instanceof
|
|
878
|
+
if (!(pp instanceof _a && pp.type === '!')) {
|
|
736
879
|
return false;
|
|
737
880
|
}
|
|
738
881
|
}
|
|
@@ -760,13 +903,14 @@ class AST {
|
|
|
760
903
|
this.push(part.clone(this));
|
|
761
904
|
}
|
|
762
905
|
clone(parent) {
|
|
763
|
-
const c = new
|
|
906
|
+
const c = new _a(this.type, parent);
|
|
764
907
|
for (const p of this.#parts) {
|
|
765
908
|
c.copyIn(p);
|
|
766
909
|
}
|
|
767
910
|
return c;
|
|
768
911
|
}
|
|
769
|
-
static #parseAST(str, ast, pos, opt) {
|
|
912
|
+
static #parseAST(str, ast, pos, opt, extDepth) {
|
|
913
|
+
const maxDepth = opt.maxExtglobRecursion ?? 2;
|
|
770
914
|
let escaping = false;
|
|
771
915
|
let inBrace = false;
|
|
772
916
|
let braceStart = -1;
|
|
@@ -803,11 +947,17 @@ class AST {
|
|
|
803
947
|
acc += c;
|
|
804
948
|
continue;
|
|
805
949
|
}
|
|
806
|
-
|
|
950
|
+
// we don't have to check for adoption here, because that's
|
|
951
|
+
// done at the other recursion point.
|
|
952
|
+
const doRecurse = !opt.noext &&
|
|
953
|
+
isExtglobType(c) &&
|
|
954
|
+
str.charAt(i) === '(' &&
|
|
955
|
+
extDepth <= maxDepth;
|
|
956
|
+
if (doRecurse) {
|
|
807
957
|
ast.push(acc);
|
|
808
958
|
acc = '';
|
|
809
|
-
const ext = new
|
|
810
|
-
i =
|
|
959
|
+
const ext = new _a(c, ast);
|
|
960
|
+
i = _a.#parseAST(str, ext, i, opt, extDepth + 1);
|
|
811
961
|
ast.push(ext);
|
|
812
962
|
continue;
|
|
813
963
|
}
|
|
@@ -819,7 +969,7 @@ class AST {
|
|
|
819
969
|
// some kind of extglob, pos is at the (
|
|
820
970
|
// find the next | or )
|
|
821
971
|
let i = pos + 1;
|
|
822
|
-
let part = new
|
|
972
|
+
let part = new _a(null, ast);
|
|
823
973
|
const parts = [];
|
|
824
974
|
let acc = '';
|
|
825
975
|
while (i < str.length) {
|
|
@@ -850,19 +1000,26 @@ class AST {
|
|
|
850
1000
|
acc += c;
|
|
851
1001
|
continue;
|
|
852
1002
|
}
|
|
853
|
-
|
|
1003
|
+
const doRecurse = !opt.noext &&
|
|
1004
|
+
isExtglobType(c) &&
|
|
1005
|
+
str.charAt(i) === '(' &&
|
|
1006
|
+
/* c8 ignore start - the maxDepth is sufficient here */
|
|
1007
|
+
(extDepth <= maxDepth || (ast && ast.#canAdoptType(c)));
|
|
1008
|
+
/* c8 ignore stop */
|
|
1009
|
+
if (doRecurse) {
|
|
1010
|
+
const depthAdd = ast && ast.#canAdoptType(c) ? 0 : 1;
|
|
854
1011
|
part.push(acc);
|
|
855
1012
|
acc = '';
|
|
856
|
-
const ext = new
|
|
1013
|
+
const ext = new _a(c, part);
|
|
857
1014
|
part.push(ext);
|
|
858
|
-
i =
|
|
1015
|
+
i = _a.#parseAST(str, ext, i, opt, extDepth + depthAdd);
|
|
859
1016
|
continue;
|
|
860
1017
|
}
|
|
861
1018
|
if (c === '|') {
|
|
862
1019
|
part.push(acc);
|
|
863
1020
|
acc = '';
|
|
864
1021
|
parts.push(part);
|
|
865
|
-
part = new
|
|
1022
|
+
part = new _a(null, ast);
|
|
866
1023
|
continue;
|
|
867
1024
|
}
|
|
868
1025
|
if (c === ')') {
|
|
@@ -884,9 +1041,82 @@ class AST {
|
|
|
884
1041
|
ast.#parts = [str.substring(pos - 1)];
|
|
885
1042
|
return i;
|
|
886
1043
|
}
|
|
1044
|
+
#canAdoptWithSpace(child) {
|
|
1045
|
+
return this.#canAdopt(child, adoptionWithSpaceMap);
|
|
1046
|
+
}
|
|
1047
|
+
#canAdopt(child, map = adoptionMap) {
|
|
1048
|
+
if (!child ||
|
|
1049
|
+
typeof child !== 'object' ||
|
|
1050
|
+
child.type !== null ||
|
|
1051
|
+
child.#parts.length !== 1 ||
|
|
1052
|
+
this.type === null) {
|
|
1053
|
+
return false;
|
|
1054
|
+
}
|
|
1055
|
+
const gc = child.#parts[0];
|
|
1056
|
+
if (!gc || typeof gc !== 'object' || gc.type === null) {
|
|
1057
|
+
return false;
|
|
1058
|
+
}
|
|
1059
|
+
return this.#canAdoptType(gc.type, map);
|
|
1060
|
+
}
|
|
1061
|
+
#canAdoptType(c, map = adoptionAnyMap) {
|
|
1062
|
+
return !!map.get(this.type)?.includes(c);
|
|
1063
|
+
}
|
|
1064
|
+
#adoptWithSpace(child, index) {
|
|
1065
|
+
const gc = child.#parts[0];
|
|
1066
|
+
const blank = new _a(null, gc, this.options);
|
|
1067
|
+
blank.#parts.push('');
|
|
1068
|
+
gc.push(blank);
|
|
1069
|
+
this.#adopt(child, index);
|
|
1070
|
+
}
|
|
1071
|
+
#adopt(child, index) {
|
|
1072
|
+
const gc = child.#parts[0];
|
|
1073
|
+
this.#parts.splice(index, 1, ...gc.#parts);
|
|
1074
|
+
for (const p of gc.#parts) {
|
|
1075
|
+
if (typeof p === 'object')
|
|
1076
|
+
p.#parent = this;
|
|
1077
|
+
}
|
|
1078
|
+
this.#toString = undefined;
|
|
1079
|
+
}
|
|
1080
|
+
#canUsurpType(c) {
|
|
1081
|
+
const m = usurpMap.get(this.type);
|
|
1082
|
+
return !!(m?.has(c));
|
|
1083
|
+
}
|
|
1084
|
+
#canUsurp(child) {
|
|
1085
|
+
if (!child ||
|
|
1086
|
+
typeof child !== 'object' ||
|
|
1087
|
+
child.type !== null ||
|
|
1088
|
+
child.#parts.length !== 1 ||
|
|
1089
|
+
this.type === null ||
|
|
1090
|
+
this.#parts.length !== 1) {
|
|
1091
|
+
return false;
|
|
1092
|
+
}
|
|
1093
|
+
const gc = child.#parts[0];
|
|
1094
|
+
if (!gc || typeof gc !== 'object' || gc.type === null) {
|
|
1095
|
+
return false;
|
|
1096
|
+
}
|
|
1097
|
+
return this.#canUsurpType(gc.type);
|
|
1098
|
+
}
|
|
1099
|
+
#usurp(child) {
|
|
1100
|
+
const m = usurpMap.get(this.type);
|
|
1101
|
+
const gc = child.#parts[0];
|
|
1102
|
+
const nt = m?.get(gc.type);
|
|
1103
|
+
/* c8 ignore start - impossible */
|
|
1104
|
+
if (!nt)
|
|
1105
|
+
return false;
|
|
1106
|
+
/* c8 ignore stop */
|
|
1107
|
+
this.#parts = gc.#parts;
|
|
1108
|
+
for (const p of this.#parts) {
|
|
1109
|
+
if (typeof p === 'object') {
|
|
1110
|
+
p.#parent = this;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
this.type = nt;
|
|
1114
|
+
this.#toString = undefined;
|
|
1115
|
+
this.#emptyExt = false;
|
|
1116
|
+
}
|
|
887
1117
|
static fromGlob(pattern, options = {}) {
|
|
888
|
-
const ast = new
|
|
889
|
-
|
|
1118
|
+
const ast = new _a(null, undefined, options);
|
|
1119
|
+
_a.#parseAST(pattern, ast, 0, options, 0);
|
|
890
1120
|
return ast;
|
|
891
1121
|
}
|
|
892
1122
|
// returns the regular expression if there's magic, or the unescaped
|
|
@@ -990,14 +1220,18 @@ class AST {
|
|
|
990
1220
|
// or start or whatever) and prepend ^ or / at the Regexp construction.
|
|
991
1221
|
toRegExpSource(allowDot) {
|
|
992
1222
|
const dot = allowDot ?? !!this.#options.dot;
|
|
993
|
-
if (this.#root === this)
|
|
1223
|
+
if (this.#root === this) {
|
|
1224
|
+
this.#flatten();
|
|
994
1225
|
this.#fillNegs();
|
|
995
|
-
|
|
996
|
-
|
|
1226
|
+
}
|
|
1227
|
+
if (!isExtglobAST(this)) {
|
|
1228
|
+
const noEmpty = this.isStart() &&
|
|
1229
|
+
this.isEnd() &&
|
|
1230
|
+
!this.#parts.some(s => typeof s !== 'string');
|
|
997
1231
|
const src = this.#parts
|
|
998
1232
|
.map(p => {
|
|
999
|
-
const [re, _, hasMagic, uflag] = typeof p === 'string'
|
|
1000
|
-
|
|
1233
|
+
const [re, _, hasMagic, uflag] = typeof p === 'string' ?
|
|
1234
|
+
_a.#parseGlob(p, this.#hasMagic, noEmpty)
|
|
1001
1235
|
: p.toRegExpSource(allowDot);
|
|
1002
1236
|
this.#hasMagic = this.#hasMagic || hasMagic;
|
|
1003
1237
|
this.#uflag = this.#uflag || uflag;
|
|
@@ -1026,7 +1260,10 @@ class AST {
|
|
|
1026
1260
|
// no need to prevent dots if it can't match a dot, or if a
|
|
1027
1261
|
// sub-pattern will be preventing it anyway.
|
|
1028
1262
|
const needNoDot = !dot && !allowDot && aps.has(src.charAt(0));
|
|
1029
|
-
start =
|
|
1263
|
+
start =
|
|
1264
|
+
needNoTrav ? startNoTraversal
|
|
1265
|
+
: needNoDot ? startNoDot
|
|
1266
|
+
: '';
|
|
1030
1267
|
}
|
|
1031
1268
|
}
|
|
1032
1269
|
}
|
|
@@ -1056,14 +1293,14 @@ class AST {
|
|
|
1056
1293
|
// invalid extglob, has to at least be *something* present, if it's
|
|
1057
1294
|
// the entire path portion.
|
|
1058
1295
|
const s = this.toString();
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1296
|
+
const me = this;
|
|
1297
|
+
me.#parts = [s];
|
|
1298
|
+
me.type = null;
|
|
1299
|
+
me.#hasMagic = undefined;
|
|
1062
1300
|
return [s, (0, unescape_js_1.unescape)(this.toString()), false, false];
|
|
1063
1301
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
? ''
|
|
1302
|
+
let bodyDotAllowed = !repeated || allowDot || dot || !startNoDot ?
|
|
1303
|
+
''
|
|
1067
1304
|
: this.#partsToRegExp(true);
|
|
1068
1305
|
if (bodyDotAllowed === body) {
|
|
1069
1306
|
bodyDotAllowed = '';
|
|
@@ -1077,20 +1314,16 @@ class AST {
|
|
|
1077
1314
|
final = (this.isStart() && !dot ? startNoDot : '') + starNoEmpty;
|
|
1078
1315
|
}
|
|
1079
1316
|
else {
|
|
1080
|
-
const close = this.type === '!'
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
: this.type === '@'
|
|
1087
|
-
? ')'
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
: this.type === '+' && bodyDotAllowed
|
|
1091
|
-
? ')'
|
|
1092
|
-
: this.type === '*' && bodyDotAllowed
|
|
1093
|
-
? `)?`
|
|
1317
|
+
const close = this.type === '!' ?
|
|
1318
|
+
// !() must match something,but !(x) can match ''
|
|
1319
|
+
'))' +
|
|
1320
|
+
(this.isStart() && !dot && !allowDot ? startNoDot : '') +
|
|
1321
|
+
star +
|
|
1322
|
+
')'
|
|
1323
|
+
: this.type === '@' ? ')'
|
|
1324
|
+
: this.type === '?' ? ')?'
|
|
1325
|
+
: this.type === '+' && bodyDotAllowed ? ')'
|
|
1326
|
+
: this.type === '*' && bodyDotAllowed ? `)?`
|
|
1094
1327
|
: `)${this.type}`;
|
|
1095
1328
|
final = start + body + close;
|
|
1096
1329
|
}
|
|
@@ -1101,6 +1334,42 @@ class AST {
|
|
|
1101
1334
|
this.#uflag,
|
|
1102
1335
|
];
|
|
1103
1336
|
}
|
|
1337
|
+
#flatten() {
|
|
1338
|
+
if (!isExtglobAST(this)) {
|
|
1339
|
+
for (const p of this.#parts) {
|
|
1340
|
+
if (typeof p === 'object') {
|
|
1341
|
+
p.#flatten();
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
else {
|
|
1346
|
+
// do up to 10 passes to flatten as much as possible
|
|
1347
|
+
let iterations = 0;
|
|
1348
|
+
let done = false;
|
|
1349
|
+
do {
|
|
1350
|
+
done = true;
|
|
1351
|
+
for (let i = 0; i < this.#parts.length; i++) {
|
|
1352
|
+
const c = this.#parts[i];
|
|
1353
|
+
if (typeof c === 'object') {
|
|
1354
|
+
c.#flatten();
|
|
1355
|
+
if (this.#canAdopt(c)) {
|
|
1356
|
+
done = false;
|
|
1357
|
+
this.#adopt(c, i);
|
|
1358
|
+
}
|
|
1359
|
+
else if (this.#canAdoptWithSpace(c)) {
|
|
1360
|
+
done = false;
|
|
1361
|
+
this.#adoptWithSpace(c, i);
|
|
1362
|
+
}
|
|
1363
|
+
else if (this.#canUsurp(c)) {
|
|
1364
|
+
done = false;
|
|
1365
|
+
this.#usurp(c);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
} while (!done && ++iterations < 10);
|
|
1370
|
+
}
|
|
1371
|
+
this.#toString = undefined;
|
|
1372
|
+
}
|
|
1104
1373
|
#partsToRegExp(dot) {
|
|
1105
1374
|
return this.#parts
|
|
1106
1375
|
.map(p => {
|
|
@@ -1122,6 +1391,8 @@ class AST {
|
|
|
1122
1391
|
let escaping = false;
|
|
1123
1392
|
let re = '';
|
|
1124
1393
|
let uflag = false;
|
|
1394
|
+
// multiple stars that aren't globstars coalesce into one *
|
|
1395
|
+
let inStar = false;
|
|
1125
1396
|
for (let i = 0; i < glob.length; i++) {
|
|
1126
1397
|
const c = glob.charAt(i);
|
|
1127
1398
|
if (escaping) {
|
|
@@ -1129,6 +1400,17 @@ class AST {
|
|
|
1129
1400
|
re += (reSpecials.has(c) ? '\\' : '') + c;
|
|
1130
1401
|
continue;
|
|
1131
1402
|
}
|
|
1403
|
+
if (c === '*') {
|
|
1404
|
+
if (inStar)
|
|
1405
|
+
continue;
|
|
1406
|
+
inStar = true;
|
|
1407
|
+
re += noEmpty && /^[*]+$/.test(glob) ? starNoEmpty : star;
|
|
1408
|
+
hasMagic = true;
|
|
1409
|
+
continue;
|
|
1410
|
+
}
|
|
1411
|
+
else {
|
|
1412
|
+
inStar = false;
|
|
1413
|
+
}
|
|
1132
1414
|
if (c === '\\') {
|
|
1133
1415
|
if (i === glob.length - 1) {
|
|
1134
1416
|
re += '\\\\';
|
|
@@ -1148,14 +1430,6 @@ class AST {
|
|
|
1148
1430
|
continue;
|
|
1149
1431
|
}
|
|
1150
1432
|
}
|
|
1151
|
-
if (c === '*') {
|
|
1152
|
-
if (noEmpty && glob === '*')
|
|
1153
|
-
re += starNoEmpty;
|
|
1154
|
-
else
|
|
1155
|
-
re += star;
|
|
1156
|
-
hasMagic = true;
|
|
1157
|
-
continue;
|
|
1158
|
-
}
|
|
1159
1433
|
if (c === '?') {
|
|
1160
1434
|
re += qmark;
|
|
1161
1435
|
hasMagic = true;
|
|
@@ -1167,6 +1441,7 @@ class AST {
|
|
|
1167
1441
|
}
|
|
1168
1442
|
}
|
|
1169
1443
|
ast$3.AST = AST;
|
|
1444
|
+
_a = AST;
|
|
1170
1445
|
|
|
1171
1446
|
var _escape = {};
|
|
1172
1447
|
|
|
@@ -1175,18 +1450,26 @@ _escape.escape = void 0;
|
|
|
1175
1450
|
/**
|
|
1176
1451
|
* Escape all magic characters in a glob pattern.
|
|
1177
1452
|
*
|
|
1178
|
-
* If the {@link
|
|
1453
|
+
* If the {@link MinimatchOptions.windowsPathsNoEscape}
|
|
1179
1454
|
* option is used, then characters are escaped by wrapping in `[]`, because
|
|
1180
1455
|
* a magic character wrapped in a character class can only be satisfied by
|
|
1181
1456
|
* that exact character. In this mode, `\` is _not_ escaped, because it is
|
|
1182
1457
|
* not interpreted as a magic character, but instead as a path separator.
|
|
1458
|
+
*
|
|
1459
|
+
* If the {@link MinimatchOptions.magicalBraces} option is used,
|
|
1460
|
+
* then braces (`{` and `}`) will be escaped.
|
|
1183
1461
|
*/
|
|
1184
|
-
const escape = (s, { windowsPathsNoEscape = false, } = {}) => {
|
|
1462
|
+
const escape = (s, { windowsPathsNoEscape = false, magicalBraces = false, } = {}) => {
|
|
1185
1463
|
// don't need to escape +@! because we escape the parens
|
|
1186
1464
|
// that make those magic, and escaping ! as [!] isn't valid,
|
|
1187
1465
|
// because [!]] is a valid glob class meaning not ']'.
|
|
1188
|
-
|
|
1189
|
-
|
|
1466
|
+
if (magicalBraces) {
|
|
1467
|
+
return windowsPathsNoEscape ?
|
|
1468
|
+
s.replace(/[?*()[\]{}]/g, '[$&]')
|
|
1469
|
+
: s.replace(/[?*()[\]\\{}]/g, '\\$&');
|
|
1470
|
+
}
|
|
1471
|
+
return windowsPathsNoEscape ?
|
|
1472
|
+
s.replace(/[?*()[\]]/g, '[$&]')
|
|
1190
1473
|
: s.replace(/[?*()[\]\\]/g, '\\$&');
|
|
1191
1474
|
};
|
|
1192
1475
|
_escape.escape = escape;
|
|
@@ -1260,8 +1543,8 @@ _escape.escape = escape;
|
|
|
1260
1543
|
return (f) => f.length === len && f !== '.' && f !== '..';
|
|
1261
1544
|
};
|
|
1262
1545
|
/* c8 ignore start */
|
|
1263
|
-
const defaultPlatform = (typeof process === 'object' && process
|
|
1264
|
-
|
|
1546
|
+
const defaultPlatform = (typeof process === 'object' && process ?
|
|
1547
|
+
(typeof process.env === 'object' &&
|
|
1265
1548
|
process.env &&
|
|
1266
1549
|
process.env.__MINIMATCH_TESTING_PLATFORM__) ||
|
|
1267
1550
|
process.platform
|
|
@@ -1347,7 +1630,7 @@ _escape.escape = escape;
|
|
|
1347
1630
|
// shortcut. no need to expand.
|
|
1348
1631
|
return [pattern];
|
|
1349
1632
|
}
|
|
1350
|
-
return (0, brace_expansion_1.expand)(pattern);
|
|
1633
|
+
return (0, brace_expansion_1.expand)(pattern, { max: options.braceExpandMax });
|
|
1351
1634
|
};
|
|
1352
1635
|
exports.braceExpand = braceExpand;
|
|
1353
1636
|
exports.minimatch.braceExpand = exports.braceExpand;
|
|
@@ -1395,16 +1678,20 @@ _escape.escape = escape;
|
|
|
1395
1678
|
isWindows;
|
|
1396
1679
|
platform;
|
|
1397
1680
|
windowsNoMagicRoot;
|
|
1681
|
+
maxGlobstarRecursion;
|
|
1398
1682
|
regexp;
|
|
1399
1683
|
constructor(pattern, options = {}) {
|
|
1400
1684
|
(0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
|
|
1401
1685
|
options = options || {};
|
|
1402
1686
|
this.options = options;
|
|
1687
|
+
this.maxGlobstarRecursion = options.maxGlobstarRecursion ?? 200;
|
|
1403
1688
|
this.pattern = pattern;
|
|
1404
1689
|
this.platform = options.platform || defaultPlatform;
|
|
1405
1690
|
this.isWindows = this.platform === 'win32';
|
|
1691
|
+
// avoid the annoying deprecation flag lol
|
|
1692
|
+
const awe = ('allowWindow' + 'sEscape');
|
|
1406
1693
|
this.windowsPathsNoEscape =
|
|
1407
|
-
!!options.windowsPathsNoEscape || options
|
|
1694
|
+
!!options.windowsPathsNoEscape || options[awe] === false;
|
|
1408
1695
|
if (this.windowsPathsNoEscape) {
|
|
1409
1696
|
this.pattern = this.pattern.replace(/\\/g, '/');
|
|
1410
1697
|
}
|
|
@@ -1417,8 +1704,8 @@ _escape.escape = escape;
|
|
|
1417
1704
|
this.partial = !!options.partial;
|
|
1418
1705
|
this.nocase = !!this.options.nocase;
|
|
1419
1706
|
this.windowsNoMagicRoot =
|
|
1420
|
-
options.windowsNoMagicRoot !== undefined
|
|
1421
|
-
|
|
1707
|
+
options.windowsNoMagicRoot !== undefined ?
|
|
1708
|
+
options.windowsNoMagicRoot
|
|
1422
1709
|
: !!(this.isWindows && this.nocase);
|
|
1423
1710
|
this.globSet = [];
|
|
1424
1711
|
this.globParts = [];
|
|
@@ -1481,7 +1768,10 @@ _escape.escape = escape;
|
|
|
1481
1768
|
!globMagic.test(s[3]);
|
|
1482
1769
|
const isDrive = /^[a-z]:/i.test(s[0]);
|
|
1483
1770
|
if (isUNC) {
|
|
1484
|
-
return [
|
|
1771
|
+
return [
|
|
1772
|
+
...s.slice(0, 4),
|
|
1773
|
+
...s.slice(4).map(ss => this.parse(ss)),
|
|
1774
|
+
];
|
|
1485
1775
|
}
|
|
1486
1776
|
else if (isDrive) {
|
|
1487
1777
|
return [s[0], ...s.slice(1).map(ss => this.parse(ss))];
|
|
@@ -1513,7 +1803,7 @@ _escape.escape = escape;
|
|
|
1513
1803
|
// to the right as possible, even if it increases the number
|
|
1514
1804
|
// of patterns that we have to process.
|
|
1515
1805
|
preprocess(globParts) {
|
|
1516
|
-
// if we're not in globstar mode, then turn
|
|
1806
|
+
// if we're not in globstar mode, then turn ** into *
|
|
1517
1807
|
if (this.options.noglobstar) {
|
|
1518
1808
|
for (let i = 0; i < globParts.length; i++) {
|
|
1519
1809
|
for (let j = 0; j < globParts[i].length; j++) {
|
|
@@ -1799,7 +2089,8 @@ _escape.escape = escape;
|
|
|
1799
2089
|
// out of pattern, then that's fine, as long as all
|
|
1800
2090
|
// the parts match.
|
|
1801
2091
|
matchOne(file, pattern, partial = false) {
|
|
1802
|
-
|
|
2092
|
+
let fileStartIndex = 0;
|
|
2093
|
+
let patternStartIndex = 0;
|
|
1803
2094
|
// UNC paths like //?/X:/... can match X:/... and vice versa
|
|
1804
2095
|
// Drive letters in absolute drive or unc paths are always compared
|
|
1805
2096
|
// case-insensitively.
|
|
@@ -1817,120 +2108,210 @@ _escape.escape = escape;
|
|
|
1817
2108
|
pattern[2] === '?' &&
|
|
1818
2109
|
typeof pattern[3] === 'string' &&
|
|
1819
2110
|
/^[a-z]:$/i.test(pattern[3]);
|
|
1820
|
-
const fdi = fileUNC ? 3
|
|
1821
|
-
|
|
2111
|
+
const fdi = fileUNC ? 3
|
|
2112
|
+
: fileDrive ? 0
|
|
2113
|
+
: undefined;
|
|
2114
|
+
const pdi = patternUNC ? 3
|
|
2115
|
+
: patternDrive ? 0
|
|
2116
|
+
: undefined;
|
|
1822
2117
|
if (typeof fdi === 'number' && typeof pdi === 'number') {
|
|
1823
|
-
const [fd, pd] = [
|
|
2118
|
+
const [fd, pd] = [
|
|
2119
|
+
file[fdi],
|
|
2120
|
+
pattern[pdi],
|
|
2121
|
+
];
|
|
2122
|
+
// start matching at the drive letter index of each
|
|
1824
2123
|
if (fd.toLowerCase() === pd.toLowerCase()) {
|
|
1825
2124
|
pattern[pdi] = fd;
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
}
|
|
1829
|
-
else if (fdi > pdi) {
|
|
1830
|
-
file = file.slice(fdi);
|
|
1831
|
-
}
|
|
2125
|
+
patternStartIndex = pdi;
|
|
2126
|
+
fileStartIndex = fdi;
|
|
1832
2127
|
}
|
|
1833
2128
|
}
|
|
1834
2129
|
}
|
|
1835
2130
|
// resolve and reduce . and .. portions in the file as well.
|
|
1836
|
-
//
|
|
2131
|
+
// don't need to do the second phase, because it's only one string[]
|
|
1837
2132
|
const { optimizationLevel = 1 } = this.options;
|
|
1838
2133
|
if (optimizationLevel >= 2) {
|
|
1839
2134
|
file = this.levelTwoFileOptimize(file);
|
|
1840
2135
|
}
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
2136
|
+
if (pattern.includes(exports.GLOBSTAR)) {
|
|
2137
|
+
return this.#matchGlobstar(file, pattern, partial, fileStartIndex, patternStartIndex);
|
|
2138
|
+
}
|
|
2139
|
+
return this.#matchOne(file, pattern, partial, fileStartIndex, patternStartIndex);
|
|
2140
|
+
}
|
|
2141
|
+
#matchGlobstar(file, pattern, partial, fileIndex, patternIndex) {
|
|
2142
|
+
// split the pattern into head, tail, and middle of ** delimited parts
|
|
2143
|
+
const firstgs = pattern.indexOf(exports.GLOBSTAR, patternIndex);
|
|
2144
|
+
const lastgs = pattern.lastIndexOf(exports.GLOBSTAR);
|
|
2145
|
+
// split the pattern up into globstar-delimited sections
|
|
2146
|
+
// the tail has to be at the end, and the others just have
|
|
2147
|
+
// to be found in order from the head.
|
|
2148
|
+
const [head, body, tail] = partial ? [
|
|
2149
|
+
pattern.slice(patternIndex, firstgs),
|
|
2150
|
+
pattern.slice(firstgs + 1),
|
|
2151
|
+
[],
|
|
2152
|
+
] : [
|
|
2153
|
+
pattern.slice(patternIndex, firstgs),
|
|
2154
|
+
pattern.slice(firstgs + 1, lastgs),
|
|
2155
|
+
pattern.slice(lastgs + 1),
|
|
2156
|
+
];
|
|
2157
|
+
// check the head, from the current file/pattern index.
|
|
2158
|
+
if (head.length) {
|
|
2159
|
+
const fileHead = file.slice(fileIndex, fileIndex + head.length);
|
|
2160
|
+
if (!this.#matchOne(fileHead, head, partial, 0, 0)) {
|
|
2161
|
+
return false;
|
|
2162
|
+
}
|
|
2163
|
+
fileIndex += head.length;
|
|
2164
|
+
patternIndex += head.length;
|
|
2165
|
+
}
|
|
2166
|
+
// now we know the head matches!
|
|
2167
|
+
// if the last portion is not empty, it MUST match the end
|
|
2168
|
+
// check the tail
|
|
2169
|
+
let fileTailMatch = 0;
|
|
2170
|
+
if (tail.length) {
|
|
2171
|
+
// if head + tail > file, then we cannot possibly match
|
|
2172
|
+
if (tail.length + fileIndex > file.length)
|
|
2173
|
+
return false;
|
|
2174
|
+
// try to match the tail
|
|
2175
|
+
let tailStart = file.length - tail.length;
|
|
2176
|
+
if (this.#matchOne(file, tail, partial, tailStart, 0)) {
|
|
2177
|
+
fileTailMatch = tail.length;
|
|
2178
|
+
}
|
|
2179
|
+
else {
|
|
2180
|
+
// affordance for stuff like a/**/* matching a/b/
|
|
2181
|
+
// if the last file portion is '', and there's more to the pattern
|
|
2182
|
+
// then try without the '' bit.
|
|
2183
|
+
if (file[file.length - 1] !== '' ||
|
|
2184
|
+
fileIndex + tail.length === file.length) {
|
|
2185
|
+
return false;
|
|
2186
|
+
}
|
|
2187
|
+
tailStart--;
|
|
2188
|
+
if (!this.#matchOne(file, tail, partial, tailStart, 0)) {
|
|
2189
|
+
return false;
|
|
2190
|
+
}
|
|
2191
|
+
fileTailMatch = tail.length + 1;
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
// now we know the tail matches!
|
|
2195
|
+
// the middle is zero or more portions wrapped in **, possibly
|
|
2196
|
+
// containing more ** sections.
|
|
2197
|
+
// so a/**/b/**/c/**/d has become **/b/**/c/**
|
|
2198
|
+
// if it's empty, it means a/**/b, just verify we have no bad dots
|
|
2199
|
+
// if there's no tail, so it ends on /**, then we must have *something*
|
|
2200
|
+
// after the head, or it's not a matc
|
|
2201
|
+
if (!body.length) {
|
|
2202
|
+
let sawSome = !!fileTailMatch;
|
|
2203
|
+
for (let i = fileIndex; i < file.length - fileTailMatch; i++) {
|
|
2204
|
+
const f = String(file[i]);
|
|
2205
|
+
sawSome = true;
|
|
2206
|
+
if (f === '.' ||
|
|
2207
|
+
f === '..' ||
|
|
2208
|
+
(!this.options.dot && f.startsWith('.'))) {
|
|
2209
|
+
return false;
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
// in partial mode, we just need to get past all file parts
|
|
2213
|
+
return partial || sawSome;
|
|
2214
|
+
}
|
|
2215
|
+
// now we know that there's one or more body sections, which can
|
|
2216
|
+
// be matched anywhere from the 0 index (because the head was pruned)
|
|
2217
|
+
// through to the length-fileTailMatch index.
|
|
2218
|
+
// split the body up into sections, and note the minimum index it can
|
|
2219
|
+
// be found at (start with the length of all previous segments)
|
|
2220
|
+
// [section, before, after]
|
|
2221
|
+
const bodySegments = [[[], 0]];
|
|
2222
|
+
let currentBody = bodySegments[0];
|
|
2223
|
+
let nonGsParts = 0;
|
|
2224
|
+
const nonGsPartsSums = [0];
|
|
2225
|
+
for (const b of body) {
|
|
2226
|
+
if (b === exports.GLOBSTAR) {
|
|
2227
|
+
nonGsPartsSums.push(nonGsParts);
|
|
2228
|
+
currentBody = [[], 0];
|
|
2229
|
+
bodySegments.push(currentBody);
|
|
2230
|
+
}
|
|
2231
|
+
else {
|
|
2232
|
+
currentBody[0].push(b);
|
|
2233
|
+
nonGsParts++;
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
let i = bodySegments.length - 1;
|
|
2237
|
+
const fileLength = file.length - fileTailMatch;
|
|
2238
|
+
for (const b of bodySegments) {
|
|
2239
|
+
b[1] = fileLength - (nonGsPartsSums[i--] + b[0].length);
|
|
2240
|
+
}
|
|
2241
|
+
return !!this.#matchGlobStarBodySections(file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch);
|
|
2242
|
+
}
|
|
2243
|
+
// return false for "nope, not matching"
|
|
2244
|
+
// return null for "not matching, cannot keep trying"
|
|
2245
|
+
#matchGlobStarBodySections(file,
|
|
2246
|
+
// pattern section, last possible position for it
|
|
2247
|
+
bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail) {
|
|
2248
|
+
// take the first body segment, and walk from fileIndex to its "after"
|
|
2249
|
+
// value at the end
|
|
2250
|
+
// If it doesn't match at that position, we increment, until we hit
|
|
2251
|
+
// that final possible position, and give up.
|
|
2252
|
+
// If it does match, then advance and try to rest.
|
|
2253
|
+
// If any of them fail we keep walking forward.
|
|
2254
|
+
// this is still a bit recursively painful, but it's more constrained
|
|
2255
|
+
// than previous implementations, because we never test something that
|
|
2256
|
+
// can't possibly be a valid matching condition.
|
|
2257
|
+
const bs = bodySegments[bodyIndex];
|
|
2258
|
+
if (!bs) {
|
|
2259
|
+
// just make sure that there's no bad dots
|
|
2260
|
+
for (let i = fileIndex; i < file.length; i++) {
|
|
2261
|
+
sawTail = true;
|
|
2262
|
+
const f = file[i];
|
|
2263
|
+
if (f === '.' ||
|
|
2264
|
+
f === '..' ||
|
|
2265
|
+
(!this.options.dot && f.startsWith('.'))) {
|
|
2266
|
+
return false;
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
return sawTail;
|
|
2270
|
+
}
|
|
2271
|
+
// have a non-globstar body section to test
|
|
2272
|
+
const [body, after] = bs;
|
|
2273
|
+
while (fileIndex <= after) {
|
|
2274
|
+
const m = this.#matchOne(file.slice(0, fileIndex + body.length), body, partial, fileIndex, 0);
|
|
2275
|
+
// if limit exceeded, no match. intentional false negative,
|
|
2276
|
+
// acceptable break in correctness for security.
|
|
2277
|
+
if (m && globStarDepth < this.maxGlobstarRecursion) {
|
|
2278
|
+
// match! see if the rest match. if so, we're done!
|
|
2279
|
+
const sub = this.#matchGlobStarBodySections(file, bodySegments, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail);
|
|
2280
|
+
if (sub !== false) {
|
|
2281
|
+
return sub;
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
const f = file[fileIndex];
|
|
2285
|
+
if (f === '.' ||
|
|
2286
|
+
f === '..' ||
|
|
2287
|
+
(!this.options.dot && f.startsWith('.'))) {
|
|
2288
|
+
return false;
|
|
2289
|
+
}
|
|
2290
|
+
fileIndex++;
|
|
2291
|
+
}
|
|
2292
|
+
// walked off. no point continuing
|
|
2293
|
+
return partial || null;
|
|
2294
|
+
}
|
|
2295
|
+
#matchOne(file, pattern, partial, fileIndex, patternIndex) {
|
|
2296
|
+
let fi;
|
|
2297
|
+
let pi;
|
|
2298
|
+
let pl;
|
|
2299
|
+
let fl;
|
|
2300
|
+
for (fi = fileIndex,
|
|
2301
|
+
pi = patternIndex,
|
|
2302
|
+
fl = file.length,
|
|
2303
|
+
pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
|
|
1844
2304
|
this.debug('matchOne loop');
|
|
1845
|
-
|
|
1846
|
-
|
|
2305
|
+
let p = pattern[pi];
|
|
2306
|
+
let f = file[fi];
|
|
1847
2307
|
this.debug(pattern, p, f);
|
|
1848
2308
|
// should be impossible.
|
|
1849
2309
|
// some invalid regexp stuff in the set.
|
|
1850
2310
|
/* c8 ignore start */
|
|
1851
|
-
if (p === false) {
|
|
2311
|
+
if (p === false || p === exports.GLOBSTAR) {
|
|
1852
2312
|
return false;
|
|
1853
2313
|
}
|
|
1854
2314
|
/* c8 ignore stop */
|
|
1855
|
-
if (p === exports.GLOBSTAR) {
|
|
1856
|
-
this.debug('GLOBSTAR', [pattern, p, f]);
|
|
1857
|
-
// "**"
|
|
1858
|
-
// a/**/b/**/c would match the following:
|
|
1859
|
-
// a/b/x/y/z/c
|
|
1860
|
-
// a/x/y/z/b/c
|
|
1861
|
-
// a/b/x/b/x/c
|
|
1862
|
-
// a/b/c
|
|
1863
|
-
// To do this, take the rest of the pattern after
|
|
1864
|
-
// the **, and see if it would match the file remainder.
|
|
1865
|
-
// If so, return success.
|
|
1866
|
-
// If not, the ** "swallows" a segment, and try again.
|
|
1867
|
-
// This is recursively awful.
|
|
1868
|
-
//
|
|
1869
|
-
// a/**/b/**/c matching a/b/x/y/z/c
|
|
1870
|
-
// - a matches a
|
|
1871
|
-
// - doublestar
|
|
1872
|
-
// - matchOne(b/x/y/z/c, b/**/c)
|
|
1873
|
-
// - b matches b
|
|
1874
|
-
// - doublestar
|
|
1875
|
-
// - matchOne(x/y/z/c, c) -> no
|
|
1876
|
-
// - matchOne(y/z/c, c) -> no
|
|
1877
|
-
// - matchOne(z/c, c) -> no
|
|
1878
|
-
// - matchOne(c, c) yes, hit
|
|
1879
|
-
var fr = fi;
|
|
1880
|
-
var pr = pi + 1;
|
|
1881
|
-
if (pr === pl) {
|
|
1882
|
-
this.debug('** at the end');
|
|
1883
|
-
// a ** at the end will just swallow the rest.
|
|
1884
|
-
// We have found a match.
|
|
1885
|
-
// however, it will not swallow /.x, unless
|
|
1886
|
-
// options.dot is set.
|
|
1887
|
-
// . and .. are *never* matched by **, for explosively
|
|
1888
|
-
// exponential reasons.
|
|
1889
|
-
for (; fi < fl; fi++) {
|
|
1890
|
-
if (file[fi] === '.' ||
|
|
1891
|
-
file[fi] === '..' ||
|
|
1892
|
-
(!options.dot && file[fi].charAt(0) === '.'))
|
|
1893
|
-
return false;
|
|
1894
|
-
}
|
|
1895
|
-
return true;
|
|
1896
|
-
}
|
|
1897
|
-
// ok, let's see if we can swallow whatever we can.
|
|
1898
|
-
while (fr < fl) {
|
|
1899
|
-
var swallowee = file[fr];
|
|
1900
|
-
this.debug('\nglobstar while', file, fr, pattern, pr, swallowee);
|
|
1901
|
-
// XXX remove this slice. Just pass the start index.
|
|
1902
|
-
if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
|
|
1903
|
-
this.debug('globstar found match!', fr, fl, swallowee);
|
|
1904
|
-
// found a match.
|
|
1905
|
-
return true;
|
|
1906
|
-
}
|
|
1907
|
-
else {
|
|
1908
|
-
// can't swallow "." or ".." ever.
|
|
1909
|
-
// can only swallow ".foo" when explicitly asked.
|
|
1910
|
-
if (swallowee === '.' ||
|
|
1911
|
-
swallowee === '..' ||
|
|
1912
|
-
(!options.dot && swallowee.charAt(0) === '.')) {
|
|
1913
|
-
this.debug('dot detected!', file, fr, pattern, pr);
|
|
1914
|
-
break;
|
|
1915
|
-
}
|
|
1916
|
-
// ** swallows a segment, and continue.
|
|
1917
|
-
this.debug('globstar swallow a segment, and continue');
|
|
1918
|
-
fr++;
|
|
1919
|
-
}
|
|
1920
|
-
}
|
|
1921
|
-
// no match was found.
|
|
1922
|
-
// However, in partial mode, we can't say this is necessarily over.
|
|
1923
|
-
/* c8 ignore start */
|
|
1924
|
-
if (partial) {
|
|
1925
|
-
// ran out of file
|
|
1926
|
-
this.debug('\n>>> no match, partial?', file, fr, pattern, pr);
|
|
1927
|
-
if (fr === fl) {
|
|
1928
|
-
return true;
|
|
1929
|
-
}
|
|
1930
|
-
}
|
|
1931
|
-
/* c8 ignore stop */
|
|
1932
|
-
return false;
|
|
1933
|
-
}
|
|
1934
2315
|
// something other than **
|
|
1935
2316
|
// non-magic patterns just have to match exactly
|
|
1936
2317
|
// patterns with magic have been turned into regexps.
|
|
@@ -2001,21 +2382,19 @@ _escape.escape = escape;
|
|
|
2001
2382
|
fastTest = options.dot ? starTestDot : starTest;
|
|
2002
2383
|
}
|
|
2003
2384
|
else if ((m = pattern.match(starDotExtRE))) {
|
|
2004
|
-
fastTest = (options.nocase
|
|
2005
|
-
|
|
2006
|
-
|
|
2385
|
+
fastTest = (options.nocase ?
|
|
2386
|
+
options.dot ?
|
|
2387
|
+
starDotExtTestNocaseDot
|
|
2007
2388
|
: starDotExtTestNocase
|
|
2008
|
-
: options.dot
|
|
2009
|
-
? starDotExtTestDot
|
|
2389
|
+
: options.dot ? starDotExtTestDot
|
|
2010
2390
|
: starDotExtTest)(m[1]);
|
|
2011
2391
|
}
|
|
2012
2392
|
else if ((m = pattern.match(qmarksRE))) {
|
|
2013
|
-
fastTest = (options.nocase
|
|
2014
|
-
|
|
2015
|
-
|
|
2393
|
+
fastTest = (options.nocase ?
|
|
2394
|
+
options.dot ?
|
|
2395
|
+
qmarksTestNocaseDot
|
|
2016
2396
|
: qmarksTestNocase
|
|
2017
|
-
: options.dot
|
|
2018
|
-
? qmarksTestDot
|
|
2397
|
+
: options.dot ? qmarksTestDot
|
|
2019
2398
|
: qmarksTest)(m);
|
|
2020
2399
|
}
|
|
2021
2400
|
else if ((m = pattern.match(starDotStarRE))) {
|
|
@@ -2046,10 +2425,8 @@ _escape.escape = escape;
|
|
|
2046
2425
|
return this.regexp;
|
|
2047
2426
|
}
|
|
2048
2427
|
const options = this.options;
|
|
2049
|
-
const twoStar = options.noglobstar
|
|
2050
|
-
?
|
|
2051
|
-
: options.dot
|
|
2052
|
-
? twoStarDot
|
|
2428
|
+
const twoStar = options.noglobstar ? star
|
|
2429
|
+
: options.dot ? twoStarDot
|
|
2053
2430
|
: twoStarNoDot;
|
|
2054
2431
|
const flags = new Set(options.nocase ? ['i'] : []);
|
|
2055
2432
|
// regexpify non-globstar patterns
|
|
@@ -2065,11 +2442,9 @@ _escape.escape = escape;
|
|
|
2065
2442
|
for (const f of p.flags.split(''))
|
|
2066
2443
|
flags.add(f);
|
|
2067
2444
|
}
|
|
2068
|
-
return typeof p === 'string'
|
|
2069
|
-
?
|
|
2070
|
-
|
|
2071
|
-
? exports.GLOBSTAR
|
|
2072
|
-
: p._src;
|
|
2445
|
+
return (typeof p === 'string' ? regExpEscape(p)
|
|
2446
|
+
: p === exports.GLOBSTAR ? exports.GLOBSTAR
|
|
2447
|
+
: p._src);
|
|
2073
2448
|
});
|
|
2074
2449
|
pp.forEach((p, i) => {
|
|
2075
2450
|
const next = pp[i + 1];
|
|
@@ -2086,14 +2461,25 @@ _escape.escape = escape;
|
|
|
2086
2461
|
}
|
|
2087
2462
|
}
|
|
2088
2463
|
else if (next === undefined) {
|
|
2089
|
-
pp[i - 1] = prev + '(
|
|
2464
|
+
pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + ')?';
|
|
2090
2465
|
}
|
|
2091
2466
|
else if (next !== exports.GLOBSTAR) {
|
|
2092
2467
|
pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + '\\/)' + next;
|
|
2093
2468
|
pp[i + 1] = exports.GLOBSTAR;
|
|
2094
2469
|
}
|
|
2095
2470
|
});
|
|
2096
|
-
|
|
2471
|
+
const filtered = pp.filter(p => p !== exports.GLOBSTAR);
|
|
2472
|
+
// For partial matches, we need to make the pattern match
|
|
2473
|
+
// any prefix of the full path. We do this by generating
|
|
2474
|
+
// alternative patterns that match progressively longer prefixes.
|
|
2475
|
+
if (this.partial && filtered.length >= 1) {
|
|
2476
|
+
const prefixes = [];
|
|
2477
|
+
for (let i = 1; i <= filtered.length; i++) {
|
|
2478
|
+
prefixes.push(filtered.slice(0, i).join('/'));
|
|
2479
|
+
}
|
|
2480
|
+
return '(?:' + prefixes.join('|') + ')';
|
|
2481
|
+
}
|
|
2482
|
+
return filtered.join('/');
|
|
2097
2483
|
})
|
|
2098
2484
|
.join('|');
|
|
2099
2485
|
// need to wrap in parens if we had more than one thing with |,
|
|
@@ -2102,6 +2488,10 @@ _escape.escape = escape;
|
|
|
2102
2488
|
// must match entire pattern
|
|
2103
2489
|
// ending in a * or ** will make it less strict.
|
|
2104
2490
|
re = '^' + open + re + close + '$';
|
|
2491
|
+
// In partial mode, '/' should always match as it's a valid prefix for any pattern
|
|
2492
|
+
if (this.partial) {
|
|
2493
|
+
re = '^(?:\\/|' + open + re.slice(1, -1) + close + ')$';
|
|
2494
|
+
}
|
|
2105
2495
|
// can match anything, as long as it's not this.
|
|
2106
2496
|
if (this.negate)
|
|
2107
2497
|
re = '^(?!' + re + ').+$';
|