minimatch 6.2.0 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.js +185 -57
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/mini.d.ts +68 -0
- package/dist/cjs/mini.js +799 -0
- package/dist/cjs/mini.js.map +1 -0
- package/dist/mjs/index.d.ts +4 -0
- package/dist/mjs/index.js +185 -57
- package/dist/mjs/index.js.map +1 -1
- package/dist/mjs/mini.d.ts +68 -0
- package/dist/mjs/mini.js +787 -0
- package/dist/mjs/mini.js.map +1 -0
- package/package.json +1 -1
package/dist/cjs/mini.js
ADDED
|
@@ -0,0 +1,799 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// this is a much more "mini" minimatch, optimized for use in a recursive
|
|
3
|
+
// glob walk.
|
|
4
|
+
//
|
|
5
|
+
// String parts of the pattern set are only parsed and used on demand,
|
|
6
|
+
// so that we don't have to bother parsing parts of the pattern that
|
|
7
|
+
// don't ever end up being used.
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.tokenize = exports.compile = exports.parsePattern = exports.Pattern = exports.braceExpand = exports.Mini = void 0;
|
|
13
|
+
const brace_expansion_1 = __importDefault(require("brace-expansion"));
|
|
14
|
+
const index_js_1 = require("./index.js");
|
|
15
|
+
/* c8 ignore start */
|
|
16
|
+
const defaultPlatform = typeof process === 'object' &&
|
|
17
|
+
!!process &&
|
|
18
|
+
typeof process.platform === 'string'
|
|
19
|
+
? process.platform
|
|
20
|
+
: 'linux';
|
|
21
|
+
/* c8 ignore stop */
|
|
22
|
+
class Mini {
|
|
23
|
+
options;
|
|
24
|
+
globLists;
|
|
25
|
+
patterns;
|
|
26
|
+
dot;
|
|
27
|
+
nocase;
|
|
28
|
+
noext;
|
|
29
|
+
noglobstar;
|
|
30
|
+
nobrace;
|
|
31
|
+
windowsPathsNoEscape;
|
|
32
|
+
platform;
|
|
33
|
+
isWindows;
|
|
34
|
+
constructor(patterns, opts = {}) {
|
|
35
|
+
const { dot = false, nocase, noext = false, noglobstar = false, nobrace = false, windowsPathsNoEscape = false, platform = defaultPlatform, } = opts;
|
|
36
|
+
this.dot = dot;
|
|
37
|
+
this.noext = noext;
|
|
38
|
+
this.noglobstar = noglobstar;
|
|
39
|
+
this.nobrace = nobrace;
|
|
40
|
+
this.windowsPathsNoEscape = windowsPathsNoEscape;
|
|
41
|
+
this.platform = platform;
|
|
42
|
+
this.nocase =
|
|
43
|
+
nocase !== undefined
|
|
44
|
+
? nocase
|
|
45
|
+
: this.platform === 'win32' || this.platform === 'darwin';
|
|
46
|
+
this.isWindows = this.platform === 'win32';
|
|
47
|
+
opts = {
|
|
48
|
+
dot: this.dot,
|
|
49
|
+
nocase: this.nocase,
|
|
50
|
+
noext: this.noext,
|
|
51
|
+
noglobstar: this.noglobstar,
|
|
52
|
+
nobrace: this.nobrace,
|
|
53
|
+
windowsPathsNoEscape: this.windowsPathsNoEscape,
|
|
54
|
+
platform: this.platform,
|
|
55
|
+
};
|
|
56
|
+
this.options = opts;
|
|
57
|
+
if (!patterns)
|
|
58
|
+
throw new TypeError('pattern required');
|
|
59
|
+
if (!Array.isArray(patterns))
|
|
60
|
+
patterns = [patterns];
|
|
61
|
+
if (opts.windowsPathsNoEscape) {
|
|
62
|
+
patterns = patterns.map(p => p.replace(/\\/g, '/'));
|
|
63
|
+
}
|
|
64
|
+
this.globLists = this.preprocess(patterns
|
|
65
|
+
.map(p => (0, exports.braceExpand)(p, this.options))
|
|
66
|
+
.reduce((ps, p) => ps.concat(p), [])
|
|
67
|
+
.map(p => this.splitGlobString(p))
|
|
68
|
+
.filter(gl => !!gl.length));
|
|
69
|
+
const parsed = new Map();
|
|
70
|
+
this.patterns = this.globLists.map(gl => new Pattern(gl, 0, parsed, opts));
|
|
71
|
+
}
|
|
72
|
+
splitGlobString(globString) {
|
|
73
|
+
const parts = globString.split('/');
|
|
74
|
+
// canonincalize UNC paths and drives, make the first
|
|
75
|
+
// pattern the whole root ending in / for absolute patterns.
|
|
76
|
+
if (this.isUNC(parts)) {
|
|
77
|
+
const [p0, p1, p2] = parts;
|
|
78
|
+
parts.shift();
|
|
79
|
+
parts.shift();
|
|
80
|
+
parts.shift();
|
|
81
|
+
parts.unshift([p0, p1, p2, ''].join('/').toUpperCase());
|
|
82
|
+
}
|
|
83
|
+
else if (this.isDrive(parts)) {
|
|
84
|
+
const drive = parts[0].toUpperCase() + '/';
|
|
85
|
+
parts.shift();
|
|
86
|
+
parts.unshift(drive);
|
|
87
|
+
}
|
|
88
|
+
else if (parts[0] === '') {
|
|
89
|
+
parts[0] = '/';
|
|
90
|
+
}
|
|
91
|
+
// now strip any empty parts
|
|
92
|
+
return parts.filter(p => !!p);
|
|
93
|
+
}
|
|
94
|
+
isDrive(pl) {
|
|
95
|
+
return (this.isWindows && typeof pl[0] === 'string' && /^[a-z]:$/i.test(pl[0]));
|
|
96
|
+
}
|
|
97
|
+
isUNC(pl) {
|
|
98
|
+
return (this.isWindows &&
|
|
99
|
+
pl[0] === '' &&
|
|
100
|
+
pl[1] === '' &&
|
|
101
|
+
typeof pl[2] === 'string' &&
|
|
102
|
+
!!pl[2] &&
|
|
103
|
+
typeof pl[3] === 'string' &&
|
|
104
|
+
!!pl[3]);
|
|
105
|
+
}
|
|
106
|
+
preprocess(globParts) {
|
|
107
|
+
// if we're not in globstar mode, then turn all ** into *
|
|
108
|
+
if (this.noglobstar) {
|
|
109
|
+
for (let i = 0; i < globParts.length; i++) {
|
|
110
|
+
for (let j = 0; j < globParts[i].length; j++) {
|
|
111
|
+
if (globParts[i][j] === '**') {
|
|
112
|
+
globParts[i][j] = '*';
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
globParts = this.firstPhasePreProcess(globParts);
|
|
118
|
+
globParts = this.secondPhasePreProcess(globParts);
|
|
119
|
+
return globParts;
|
|
120
|
+
}
|
|
121
|
+
// First phase: single-pattern processing
|
|
122
|
+
// <pre> is 1 or more portions
|
|
123
|
+
// <rest> is 1 or more portions
|
|
124
|
+
// <p> is any portion other than ., .., '', or **
|
|
125
|
+
// <e> is . or ''
|
|
126
|
+
//
|
|
127
|
+
// **/.. is *brutal* for filesystem walking performance, because
|
|
128
|
+
// it effectively resets the recursive walk each time it occurs,
|
|
129
|
+
// and ** cannot be reduced out by a .. pattern part like a regexp
|
|
130
|
+
// or most strings (other than .., ., and '') can be.
|
|
131
|
+
//
|
|
132
|
+
// <pre>/**/../<p>/<rest> -> {<pre>/../<p>/<rest>,<pre>/**/<p>/<rest>}
|
|
133
|
+
// <pre>/<e>/<rest> -> <pre>/<rest>
|
|
134
|
+
// <pre>/<p>/../<rest> -> <pre>/<rest>
|
|
135
|
+
// **/**/<rest> -> **/<rest>
|
|
136
|
+
//
|
|
137
|
+
// **/*/<rest> -> */**/<rest> <== not valid because ** doesn't follow
|
|
138
|
+
// this WOULD be allowed if ** did follow symlinks, or * didn't
|
|
139
|
+
firstPhasePreProcess(globParts) {
|
|
140
|
+
let didSomething = false;
|
|
141
|
+
do {
|
|
142
|
+
didSomething = false;
|
|
143
|
+
// <pre>/**/../<p>/<rest> -> {<pre>/../<p>/<rest>,<pre>/**/<p>/<rest>}
|
|
144
|
+
for (let parts of globParts) {
|
|
145
|
+
let gs = -1;
|
|
146
|
+
while (-1 !== (gs = parts.indexOf('**', gs + 1))) {
|
|
147
|
+
let gss = gs;
|
|
148
|
+
while (parts[gss + 1] === '**') {
|
|
149
|
+
// <pre>/**/**/<rest> -> <pre>/**/<rest>
|
|
150
|
+
gss++;
|
|
151
|
+
}
|
|
152
|
+
// eg, if gs is 2 and gss is 4, that means we have 3 **
|
|
153
|
+
// parts, and can remove 2 of them.
|
|
154
|
+
if (gss > gs) {
|
|
155
|
+
parts.splice(gs + 1, gss - gs);
|
|
156
|
+
}
|
|
157
|
+
let next = parts[gs + 1];
|
|
158
|
+
const p = parts[gs + 2];
|
|
159
|
+
if (next !== '..')
|
|
160
|
+
continue;
|
|
161
|
+
if (!p || p === '.' || p === '..')
|
|
162
|
+
continue;
|
|
163
|
+
didSomething = true;
|
|
164
|
+
// edit parts in place, and push the new one
|
|
165
|
+
parts.splice(gs, 1);
|
|
166
|
+
const other = parts.slice(0);
|
|
167
|
+
other[gs] = '**';
|
|
168
|
+
globParts.push(other);
|
|
169
|
+
gs--;
|
|
170
|
+
}
|
|
171
|
+
// <pre>/<e>/<rest> -> <pre>/<rest>
|
|
172
|
+
for (let i = 1; i < parts.length - 1; i++) {
|
|
173
|
+
const p = parts[i];
|
|
174
|
+
// don't squeeze out UNC patterns
|
|
175
|
+
if (i === 1 && p === '' && parts[0] === '')
|
|
176
|
+
continue;
|
|
177
|
+
if (p === '.' || p === '') {
|
|
178
|
+
didSomething = true;
|
|
179
|
+
parts.splice(i, 1);
|
|
180
|
+
i--;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (parts[0] === '.') {
|
|
184
|
+
didSomething = true;
|
|
185
|
+
parts.shift();
|
|
186
|
+
}
|
|
187
|
+
// <pre>/<p>/../<rest> -> <pre>/<rest>
|
|
188
|
+
let dd = 0;
|
|
189
|
+
while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
|
|
190
|
+
const p = parts[dd - 1];
|
|
191
|
+
if (p && p !== '.' && p !== '..' && p !== '**') {
|
|
192
|
+
didSomething = true;
|
|
193
|
+
parts.splice(dd - 1, 2);
|
|
194
|
+
if (parts.length === 0)
|
|
195
|
+
parts.push('');
|
|
196
|
+
dd -= 2;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
} while (didSomething);
|
|
201
|
+
return globParts;
|
|
202
|
+
}
|
|
203
|
+
// second phase: multi-pattern dedupes
|
|
204
|
+
// {<pre>/*/<rest>,<pre>/<p>/<rest>} -> <pre>/*/<rest>
|
|
205
|
+
// {<pre>/<rest>,<pre>/<rest>} -> <pre>/<rest>
|
|
206
|
+
// {<pre>/**/<rest>,<pre>/<rest>} -> <pre>/**/<rest>
|
|
207
|
+
//
|
|
208
|
+
// {<pre>/**/<rest>,<pre>/**/<p>/<rest>} -> <pre>/**/<rest>
|
|
209
|
+
// ^-- not valid because ** doens't follow symlinks
|
|
210
|
+
secondPhasePreProcess(globParts) {
|
|
211
|
+
for (let i = 0; i < globParts.length - 1; i++) {
|
|
212
|
+
for (let j = i + 1; j < globParts.length; j++) {
|
|
213
|
+
const matched = this.partsMatch(globParts[i], globParts[j]);
|
|
214
|
+
if (!matched)
|
|
215
|
+
continue;
|
|
216
|
+
globParts[i] = matched;
|
|
217
|
+
globParts[j] = [];
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return globParts.filter(gs => gs.length);
|
|
221
|
+
}
|
|
222
|
+
partsMatch(a, b) {
|
|
223
|
+
let ai = 0;
|
|
224
|
+
let bi = 0;
|
|
225
|
+
let result = [];
|
|
226
|
+
let which = '';
|
|
227
|
+
while (ai < a.length && bi < b.length) {
|
|
228
|
+
if (a[ai] === b[bi]) {
|
|
229
|
+
result.push(which === 'b' ? b[bi] : a[ai]);
|
|
230
|
+
ai++;
|
|
231
|
+
bi++;
|
|
232
|
+
}
|
|
233
|
+
else if (a[ai] === '**' && b[bi] === a[ai + 1]) {
|
|
234
|
+
result.push(a[ai]);
|
|
235
|
+
ai++;
|
|
236
|
+
}
|
|
237
|
+
else if (b[bi] === '**' && a[ai] === b[bi + 1]) {
|
|
238
|
+
result.push(b[bi]);
|
|
239
|
+
bi++;
|
|
240
|
+
}
|
|
241
|
+
else if (a[ai] === '*' &&
|
|
242
|
+
b[bi] &&
|
|
243
|
+
!b[bi].startsWith('.') &&
|
|
244
|
+
b[bi] !== '**') {
|
|
245
|
+
if (which === 'b')
|
|
246
|
+
return false;
|
|
247
|
+
which = 'a';
|
|
248
|
+
result.push(a[ai]);
|
|
249
|
+
ai++;
|
|
250
|
+
bi++;
|
|
251
|
+
}
|
|
252
|
+
else if (b[bi] === '*' &&
|
|
253
|
+
a[ai] &&
|
|
254
|
+
(this.dot || !a[ai].startsWith('.')) &&
|
|
255
|
+
a[ai] !== '**') {
|
|
256
|
+
if (which === 'a')
|
|
257
|
+
return false;
|
|
258
|
+
which = 'b';
|
|
259
|
+
result.push(b[bi]);
|
|
260
|
+
ai++;
|
|
261
|
+
bi++;
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// if we fall out of the loop, it means they two are identical
|
|
268
|
+
// as long as their lengths match
|
|
269
|
+
return a.length === b.length && result;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
exports.Mini = Mini;
|
|
273
|
+
const braceExpand = (pattern, options = {}) => {
|
|
274
|
+
assertValidPattern(pattern);
|
|
275
|
+
// Thanks to Yeting Li <https://github.com/yetingli> for
|
|
276
|
+
// improving this regexp to avoid a ReDOS vulnerability.
|
|
277
|
+
if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
|
|
278
|
+
// shortcut. no need to expand.
|
|
279
|
+
return [pattern];
|
|
280
|
+
}
|
|
281
|
+
return (0, brace_expansion_1.default)(pattern);
|
|
282
|
+
};
|
|
283
|
+
exports.braceExpand = braceExpand;
|
|
284
|
+
const MAX_PATTERN_LENGTH = 1024 * 64;
|
|
285
|
+
const assertValidPattern = (pattern) => {
|
|
286
|
+
if (typeof pattern !== 'string') {
|
|
287
|
+
throw new TypeError('invalid pattern');
|
|
288
|
+
}
|
|
289
|
+
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
290
|
+
throw new TypeError('pattern is too long');
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
const isGlobList = (gl) => gl.length >= 1;
|
|
294
|
+
class Pattern {
|
|
295
|
+
#options;
|
|
296
|
+
#globList;
|
|
297
|
+
length;
|
|
298
|
+
#index;
|
|
299
|
+
#parsed;
|
|
300
|
+
// memoizing
|
|
301
|
+
#pattern;
|
|
302
|
+
#rest;
|
|
303
|
+
constructor(globList, index, parsed, options) {
|
|
304
|
+
if (!isGlobList(globList)) {
|
|
305
|
+
throw new TypeError('empty glob list');
|
|
306
|
+
}
|
|
307
|
+
this.#globList = globList;
|
|
308
|
+
if (index >= globList.length) {
|
|
309
|
+
throw new TypeError('index out of range');
|
|
310
|
+
}
|
|
311
|
+
this.length = globList.length;
|
|
312
|
+
this.#options = options;
|
|
313
|
+
this.#index = index;
|
|
314
|
+
this.#parsed = parsed;
|
|
315
|
+
}
|
|
316
|
+
glob() {
|
|
317
|
+
return this.#globList[this.#index];
|
|
318
|
+
}
|
|
319
|
+
pattern() {
|
|
320
|
+
if (this.#pattern !== undefined) {
|
|
321
|
+
return this.#pattern;
|
|
322
|
+
}
|
|
323
|
+
const glob = this.glob();
|
|
324
|
+
if (glob.endsWith('/')) {
|
|
325
|
+
return (this.#pattern = glob);
|
|
326
|
+
}
|
|
327
|
+
const cached = this.#parsed.get(glob);
|
|
328
|
+
if (cached !== undefined) {
|
|
329
|
+
return (this.#pattern = cached);
|
|
330
|
+
}
|
|
331
|
+
const pattern = parse(glob, this.#options);
|
|
332
|
+
this.#parsed.set(glob, pattern);
|
|
333
|
+
return (this.#pattern = pattern);
|
|
334
|
+
}
|
|
335
|
+
isAbsolute() {
|
|
336
|
+
return this.#globList[0].endsWith('/');
|
|
337
|
+
}
|
|
338
|
+
root() {
|
|
339
|
+
return this.#index === 0 && this.isAbsolute() ? this.#globList[0] : '';
|
|
340
|
+
}
|
|
341
|
+
rest() {
|
|
342
|
+
if (this.#rest !== undefined)
|
|
343
|
+
return this.#rest;
|
|
344
|
+
if (this.#index >= this.length - 1)
|
|
345
|
+
return (this.#rest = null);
|
|
346
|
+
const rest = new Pattern(this.#globList, this.#index + 1, this.#parsed, this.#options);
|
|
347
|
+
this.#rest = rest;
|
|
348
|
+
return rest;
|
|
349
|
+
}
|
|
350
|
+
hasMore() {
|
|
351
|
+
return this.#index < this.length - 1;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
exports.Pattern = Pattern;
|
|
355
|
+
const parsePattern = (pattern, options) => {
|
|
356
|
+
const ast = (0, exports.tokenize)(pattern, options);
|
|
357
|
+
if (ast.length === 1 && ast[0][TokenField.TYPE] === TokenType.STRING) {
|
|
358
|
+
return ast[0][TokenField.VALUE];
|
|
359
|
+
}
|
|
360
|
+
const re = (0, exports.compile)(ast, options, true);
|
|
361
|
+
try {
|
|
362
|
+
return new RegExp(re, options.nocase ? 'i' : '');
|
|
363
|
+
}
|
|
364
|
+
catch (er) {
|
|
365
|
+
return /$./;
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
exports.parsePattern = parsePattern;
|
|
369
|
+
const compile = (ast, options, isTop = false, isStart = true) => {
|
|
370
|
+
const negativeExts = [];
|
|
371
|
+
const re = [];
|
|
372
|
+
let stillStart = isStart;
|
|
373
|
+
let maybeEmpty = true;
|
|
374
|
+
for (let i = 0; i < ast.length; i++) {
|
|
375
|
+
const token = ast[i];
|
|
376
|
+
if (isStringToken(token)) {
|
|
377
|
+
if (token[TokenField.VALUE] !== '') {
|
|
378
|
+
maybeEmpty = false;
|
|
379
|
+
}
|
|
380
|
+
re.push(compileNonMagic(token, options));
|
|
381
|
+
}
|
|
382
|
+
else if (isClassToken(token)) {
|
|
383
|
+
maybeEmpty = false;
|
|
384
|
+
re.push(compileClass(token, options));
|
|
385
|
+
}
|
|
386
|
+
else if (isExtToken(token)) {
|
|
387
|
+
if (token[TokenField.VALUE] === '!') {
|
|
388
|
+
negativeExts.push(i);
|
|
389
|
+
}
|
|
390
|
+
re.push(compileExt(token, options, stillStart));
|
|
391
|
+
}
|
|
392
|
+
else if (isQmarkToken(token)) {
|
|
393
|
+
maybeEmpty = false;
|
|
394
|
+
re.push(compileQmark(token, options));
|
|
395
|
+
}
|
|
396
|
+
else if (isStarToken(token)) {
|
|
397
|
+
re.push(compileStar(token, options));
|
|
398
|
+
/* c8 ignore start */
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
throw new TypeError('unknown token type: ' + token);
|
|
402
|
+
}
|
|
403
|
+
/* c8 ignore stop */
|
|
404
|
+
stillStart = false;
|
|
405
|
+
}
|
|
406
|
+
if (isTop) {
|
|
407
|
+
re.push('$');
|
|
408
|
+
}
|
|
409
|
+
// a negative extglob is:
|
|
410
|
+
// ((?!(sub|patterns)<rest of the pattern>).*?)
|
|
411
|
+
// so we need to do it in two passes.
|
|
412
|
+
for (let i = negativeExts.length - 1; i >= 0; i--) {
|
|
413
|
+
const n = negativeExts[i];
|
|
414
|
+
re[n] += compileNegativeExtClose(re, n);
|
|
415
|
+
}
|
|
416
|
+
if (isTop) {
|
|
417
|
+
if (!options.dot && needDotProtection(ast)) {
|
|
418
|
+
re.unshift('(?!^\\.)');
|
|
419
|
+
}
|
|
420
|
+
if (maybeEmpty) {
|
|
421
|
+
re.unshift('(?=.)');
|
|
422
|
+
}
|
|
423
|
+
re.unshift('^');
|
|
424
|
+
}
|
|
425
|
+
else if (isStart) {
|
|
426
|
+
if (!options.dot && needDotProtection(ast)) {
|
|
427
|
+
re.unshift('(?!^\\.)');
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return re.join('');
|
|
431
|
+
};
|
|
432
|
+
exports.compile = compile;
|
|
433
|
+
const needDotProtection = (ast) => {
|
|
434
|
+
const first = ast[0];
|
|
435
|
+
return isClassToken(first) || isStarToken(first) || isQmarkToken(first);
|
|
436
|
+
};
|
|
437
|
+
const compileQmark = (_, __) => '.';
|
|
438
|
+
const compileStar = (_, __) => '.*?';
|
|
439
|
+
const compileNonMagic = (token, _) => regExpEscape(token[TokenField.VALUE]);
|
|
440
|
+
const compileClass = (token, _) => {
|
|
441
|
+
// TODO: posix classes
|
|
442
|
+
const cls = braceEscape(charUnescape(token[TokenField.VALUE]));
|
|
443
|
+
const re = `[${cls}]`;
|
|
444
|
+
// handle out of order classes, like `[z-a]`, which throw
|
|
445
|
+
// in javascript, but just match nothing in glob syntax.
|
|
446
|
+
try {
|
|
447
|
+
RegExp(re);
|
|
448
|
+
return re;
|
|
449
|
+
}
|
|
450
|
+
catch (_) {
|
|
451
|
+
return '$.';
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
const charUnescape = (s) => s.replace(/\\([^-\]])/g, '$1');
|
|
455
|
+
const braceEscape = (s) => s.replace(/[[\]\\]/g, '\\$&');
|
|
456
|
+
const globSpecialChars = new Set(['?', '*', '+', '@', '!', '[', '(']);
|
|
457
|
+
const escapeInClass = new Set(['-', ']']);
|
|
458
|
+
const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
|
459
|
+
const isExtToken = (t) => t[TokenField.TYPE] === TokenType.EXT;
|
|
460
|
+
const isStringToken = (t) => t[TokenField.TYPE] === TokenType.STRING;
|
|
461
|
+
const isStarToken = (t) => t[TokenField.TYPE] === TokenType.STAR;
|
|
462
|
+
const isQmarkToken = (t) => t[TokenField.TYPE] === TokenType.QMARK;
|
|
463
|
+
const isClassToken = (t) => t[TokenField.TYPE] === TokenType.CLASS;
|
|
464
|
+
var TokenField;
|
|
465
|
+
(function (TokenField) {
|
|
466
|
+
TokenField[TokenField["TYPE"] = 0] = "TYPE";
|
|
467
|
+
TokenField[TokenField["VALUE"] = 1] = "VALUE";
|
|
468
|
+
TokenField[TokenField["CHILDREN"] = 2] = "CHILDREN";
|
|
469
|
+
})(TokenField || (TokenField = {}));
|
|
470
|
+
var TokenType;
|
|
471
|
+
(function (TokenType) {
|
|
472
|
+
TokenType["STRING"] = "string";
|
|
473
|
+
TokenType["STAR"] = "star";
|
|
474
|
+
TokenType["EXT"] = "ext";
|
|
475
|
+
TokenType["QMARK"] = "qmark";
|
|
476
|
+
TokenType["CLASS"] = "class";
|
|
477
|
+
})(TokenType || (TokenType = {}));
|
|
478
|
+
const extGlobTypes = new Set(['?', '*', '+', '@', '!']);
|
|
479
|
+
const isExtGlobType = (s) => extGlobTypes.has(s);
|
|
480
|
+
const extTypes = {
|
|
481
|
+
'!': { open: '(?:(?!(?:', close: ').*?))' },
|
|
482
|
+
'?': { open: '(?:', close: ')?' },
|
|
483
|
+
'+': { open: '(?:', close: ')+' },
|
|
484
|
+
'*': { open: '(?:', close: ')*' },
|
|
485
|
+
'@': { open: '(?:', close: ')' },
|
|
486
|
+
};
|
|
487
|
+
const compileExt = (token, options, isStart) => {
|
|
488
|
+
const t = token[TokenField.VALUE];
|
|
489
|
+
const open = extTypes[t].open;
|
|
490
|
+
const close = t === '!' ? '' : extTypes[t].close;
|
|
491
|
+
const subs = token[TokenField.CHILDREN];
|
|
492
|
+
const body = subs.map(ast => (0, exports.compile)(ast, options, false, isStart)).join('|');
|
|
493
|
+
return open + body + close;
|
|
494
|
+
};
|
|
495
|
+
const compileNegativeExtClose = (re, n) => {
|
|
496
|
+
// walk the AST from i onwards, collecting the regexp
|
|
497
|
+
// then add the end bit:
|
|
498
|
+
// ((?!(sub|patterns)<rest of the pattern>).*?)
|
|
499
|
+
// ^-- from here on
|
|
500
|
+
let s = ')';
|
|
501
|
+
for (let i = n + 1; i < re.length; i++) {
|
|
502
|
+
s += re[i];
|
|
503
|
+
}
|
|
504
|
+
s += ').*?)';
|
|
505
|
+
return s;
|
|
506
|
+
};
|
|
507
|
+
const tokenize = (pattern, options, ast = []) => {
|
|
508
|
+
// tokenize the string up into chunks first
|
|
509
|
+
// sort of like an AST of the pattern
|
|
510
|
+
// each node is [type, value, [...children]]
|
|
511
|
+
// root, or children of extglobs, are an array of nodes
|
|
512
|
+
// so 'i\?jk?*.@(xy[a-c]|!(foo|ba*r))baz*bo' becomes:
|
|
513
|
+
// [
|
|
514
|
+
// [STRING, 'i?jk'],
|
|
515
|
+
// [QMARK, '?'],
|
|
516
|
+
// [STAR, '*'],
|
|
517
|
+
// [STRING, '.'],
|
|
518
|
+
// [EXT, '@', [
|
|
519
|
+
// [[STRING, 'xy'], [CLASS, 'a-c']],
|
|
520
|
+
// [[EXT, '!', [
|
|
521
|
+
// [[STRING, 'foo']],
|
|
522
|
+
// [[STRING, 'ba'], [STAR, '*'], [STRING, 'r']]
|
|
523
|
+
// ]]],
|
|
524
|
+
// ]],
|
|
525
|
+
// [STRING, 'baz'],
|
|
526
|
+
// [STAR, '*'],
|
|
527
|
+
// [STRING, 'bo'],
|
|
528
|
+
// ]
|
|
529
|
+
//
|
|
530
|
+
// which turns into the regexp:
|
|
531
|
+
// ^i\?jk..*?\.(?:xy[a-c]|(?:(?!(?:foo|ba.*?r).*$)))baz.*?bo$
|
|
532
|
+
// Place the "no dot allowed" if the AST starts at position 0,
|
|
533
|
+
// and is a *, ?, or class at the start
|
|
534
|
+
let i = 0;
|
|
535
|
+
const length = pattern.length;
|
|
536
|
+
while (i < length) {
|
|
537
|
+
let c = pattern.charAt(i);
|
|
538
|
+
// take our best guess as to what it is
|
|
539
|
+
// the other tokenizers will append to the AST and return
|
|
540
|
+
// the amount of string that was consumed.
|
|
541
|
+
if (!options.noext && isExtGlobType(c) && pattern.charAt(i + 1) === '(') {
|
|
542
|
+
const consumed = tokenizeExt(pattern, options, i, ast);
|
|
543
|
+
if (consumed) {
|
|
544
|
+
i += consumed;
|
|
545
|
+
c = pattern.charAt(i);
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (c === '[') {
|
|
550
|
+
const consumed = tokenizeClass(pattern, options, i, ast);
|
|
551
|
+
if (consumed) {
|
|
552
|
+
i += consumed;
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
if (c === '*') {
|
|
557
|
+
ast.push([TokenType.STAR, '*']);
|
|
558
|
+
}
|
|
559
|
+
else if (c === '?') {
|
|
560
|
+
ast.push([TokenType.QMARK, '?']);
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
const consumed = tokenizeNonMagic(pattern, options, i, ast);
|
|
564
|
+
if (consumed) {
|
|
565
|
+
i += consumed;
|
|
566
|
+
c = pattern.charAt(i);
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
i++;
|
|
571
|
+
}
|
|
572
|
+
return ast;
|
|
573
|
+
};
|
|
574
|
+
exports.tokenize = tokenize;
|
|
575
|
+
const tokenizeExt = (pattern, options, i, ast) => {
|
|
576
|
+
const extType = pattern.charAt(i);
|
|
577
|
+
if (!isExtGlobType(extType)) {
|
|
578
|
+
throw new Error('invalid extglob type: ' + extType);
|
|
579
|
+
}
|
|
580
|
+
const matchStack = [];
|
|
581
|
+
const pipes = [];
|
|
582
|
+
let p;
|
|
583
|
+
const length = pattern.length;
|
|
584
|
+
let end = -1;
|
|
585
|
+
let escaping = false;
|
|
586
|
+
// first split out the top-level set of strings
|
|
587
|
+
// if we can't do that, it's not a valid extglob
|
|
588
|
+
for (p = i + 2; p < length; p++) {
|
|
589
|
+
const c = pattern.charAt(p);
|
|
590
|
+
if (escaping) {
|
|
591
|
+
escaping = false;
|
|
592
|
+
continue;
|
|
593
|
+
}
|
|
594
|
+
if (c === '\\') {
|
|
595
|
+
escaping = true;
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
if (c === ']') {
|
|
599
|
+
if (matchStack[0] === '[' && pattern.charAt(p - 1) !== '[') {
|
|
600
|
+
matchStack.shift();
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
else if (c === ')') {
|
|
604
|
+
if (!matchStack.length) {
|
|
605
|
+
// finished!
|
|
606
|
+
end = p;
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
else if (matchStack[0] === '(') {
|
|
610
|
+
matchStack.shift();
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
else if (c === '(') {
|
|
614
|
+
if (matchStack[0] !== '[' && isExtGlobType(pattern.charAt(p - 1))) {
|
|
615
|
+
matchStack.unshift(c);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
else if (c === '|' && matchStack.length === 0) {
|
|
619
|
+
pipes.push(p);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
if (!end || matchStack.length) {
|
|
623
|
+
return 0;
|
|
624
|
+
}
|
|
625
|
+
// i + 1, pipes, and end define the outside boundaries of the subs
|
|
626
|
+
const subPatterns = [];
|
|
627
|
+
let start = i + 2;
|
|
628
|
+
for (const pipe of pipes) {
|
|
629
|
+
subPatterns.push(pattern.substring(start, pipe));
|
|
630
|
+
start = pipe + 1;
|
|
631
|
+
}
|
|
632
|
+
subPatterns.push(pattern.substring(start, end));
|
|
633
|
+
const subTokenized = subPatterns.map(p => (0, exports.tokenize)(p, options));
|
|
634
|
+
ast.push([TokenType.EXT, extType, subTokenized]);
|
|
635
|
+
return end - i + 1;
|
|
636
|
+
};
|
|
637
|
+
const tokenizeClass = (pattern, _, i, ast) => {
|
|
638
|
+
// walk until we find the closing ] that is not escaped or the first char
|
|
639
|
+
// return 0 if it's not a valid class (basically, just if it's left open)
|
|
640
|
+
let p;
|
|
641
|
+
let escaping = false;
|
|
642
|
+
const length = pattern.length;
|
|
643
|
+
let s = '';
|
|
644
|
+
for (p = i + 1; p < length; p++) {
|
|
645
|
+
const c = pattern.charAt(p);
|
|
646
|
+
if (c === '\\' && !escaping) {
|
|
647
|
+
escaping = true;
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
if (p === i + 1 && c === ']') {
|
|
651
|
+
s += c;
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
if (escaping) {
|
|
655
|
+
escaping = false;
|
|
656
|
+
if (escapeInClass.has(c)) {
|
|
657
|
+
s += '\\';
|
|
658
|
+
}
|
|
659
|
+
s += c;
|
|
660
|
+
continue;
|
|
661
|
+
}
|
|
662
|
+
if (c === ']') {
|
|
663
|
+
ast.push([TokenType.CLASS, s]);
|
|
664
|
+
return p - i + 1;
|
|
665
|
+
}
|
|
666
|
+
s += c;
|
|
667
|
+
}
|
|
668
|
+
return 0;
|
|
669
|
+
};
|
|
670
|
+
const tokenizeNonMagic = (pattern, _, i, ast) => {
|
|
671
|
+
let escaping = false;
|
|
672
|
+
let p = i;
|
|
673
|
+
let sawFirst = false;
|
|
674
|
+
const length = pattern.length;
|
|
675
|
+
let s = '';
|
|
676
|
+
for (p = i; p < length; p++) {
|
|
677
|
+
let c = pattern.charAt(p);
|
|
678
|
+
if (c === '\\' && !escaping) {
|
|
679
|
+
escaping = true;
|
|
680
|
+
continue;
|
|
681
|
+
}
|
|
682
|
+
if (escaping) {
|
|
683
|
+
escaping = false;
|
|
684
|
+
s += c;
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
// this is only called when we KNOW the first char is not magic,
|
|
688
|
+
// so no need to stop for that at the outset.
|
|
689
|
+
if (!sawFirst) {
|
|
690
|
+
sawFirst = true;
|
|
691
|
+
s += c;
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
if (globSpecialChars.has(c)) {
|
|
695
|
+
break;
|
|
696
|
+
}
|
|
697
|
+
s += c;
|
|
698
|
+
}
|
|
699
|
+
ast.push([TokenType.STRING, s]);
|
|
700
|
+
return p - i;
|
|
701
|
+
};
|
|
702
|
+
const parse = (pattern, options) => {
|
|
703
|
+
if (pattern === '**')
|
|
704
|
+
return index_js_1.GLOBSTAR;
|
|
705
|
+
let m;
|
|
706
|
+
let fastTest = null;
|
|
707
|
+
if ((m = pattern.match(starRE))) {
|
|
708
|
+
fastTest = options.dot ? starTestDot : starTest;
|
|
709
|
+
}
|
|
710
|
+
else if ((m = pattern.match(starDotExtRE))) {
|
|
711
|
+
fastTest = (options.nocase
|
|
712
|
+
? options.dot
|
|
713
|
+
? starDotExtTestNocaseDot
|
|
714
|
+
: starDotExtTestNocase
|
|
715
|
+
: options.dot
|
|
716
|
+
? starDotExtTestDot
|
|
717
|
+
: starDotExtTest)(m[1]);
|
|
718
|
+
}
|
|
719
|
+
else if ((m = pattern.match(qmarksRE))) {
|
|
720
|
+
fastTest = (options.nocase
|
|
721
|
+
? options.dot
|
|
722
|
+
? qmarksTestNocaseDot
|
|
723
|
+
: qmarksTestNocase
|
|
724
|
+
: options.dot
|
|
725
|
+
? qmarksTestDot
|
|
726
|
+
: qmarksTest)(m);
|
|
727
|
+
}
|
|
728
|
+
else if ((m = pattern.match(starDotStarRE))) {
|
|
729
|
+
fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
|
|
730
|
+
}
|
|
731
|
+
else if ((m = pattern.match(dotStarRE))) {
|
|
732
|
+
fastTest = dotStarTest;
|
|
733
|
+
}
|
|
734
|
+
if (fastTest) {
|
|
735
|
+
return Object.assign(/$./, {
|
|
736
|
+
_glob: pattern,
|
|
737
|
+
test: fastTest,
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
// ok we have to actually parse it
|
|
742
|
+
const re = (0, exports.parsePattern)(pattern, options);
|
|
743
|
+
return typeof re === 'string' ? re : Object.assign(re, {
|
|
744
|
+
_glob: pattern,
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
// Optimized checking for the most common glob patterns.
|
|
749
|
+
const starDotExtRE = /^\*+([^+@!?\*\[\(]*)$/;
|
|
750
|
+
const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext);
|
|
751
|
+
const starDotExtTestDot = (ext) => (f) => f.endsWith(ext);
|
|
752
|
+
const starDotExtTestNocase = (ext) => {
|
|
753
|
+
ext = ext.toLowerCase();
|
|
754
|
+
return (f) => !f.startsWith('.') && f.toLowerCase().endsWith(ext);
|
|
755
|
+
};
|
|
756
|
+
const starDotExtTestNocaseDot = (ext) => {
|
|
757
|
+
ext = ext.toLowerCase();
|
|
758
|
+
return (f) => f.toLowerCase().endsWith(ext);
|
|
759
|
+
};
|
|
760
|
+
const starDotStarRE = /^\*+\.\*+$/;
|
|
761
|
+
const starDotStarTest = (f) => !f.startsWith('.') && f.includes('.');
|
|
762
|
+
const starDotStarTestDot = (f) => f !== '.' && f !== '..' && f.includes('.');
|
|
763
|
+
const dotStarRE = /^\.\*+$/;
|
|
764
|
+
const dotStarTest = (f) => f !== '.' && f !== '..' && f.startsWith('.');
|
|
765
|
+
const starRE = /^\*+$/;
|
|
766
|
+
const starTest = (f) => f.length !== 0 && !f.startsWith('.');
|
|
767
|
+
const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..';
|
|
768
|
+
const qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/;
|
|
769
|
+
const qmarksTestNocase = ([$0, ext = '']) => {
|
|
770
|
+
const noext = qmarksTestNoExt([$0]);
|
|
771
|
+
if (!ext)
|
|
772
|
+
return noext;
|
|
773
|
+
ext = ext.toLowerCase();
|
|
774
|
+
return (f) => noext(f) && f.toLowerCase().endsWith(ext);
|
|
775
|
+
};
|
|
776
|
+
const qmarksTestNocaseDot = ([$0, ext = '']) => {
|
|
777
|
+
const noext = qmarksTestNoExtDot([$0]);
|
|
778
|
+
if (!ext)
|
|
779
|
+
return noext;
|
|
780
|
+
ext = ext.toLowerCase();
|
|
781
|
+
return (f) => noext(f) && f.toLowerCase().endsWith(ext);
|
|
782
|
+
};
|
|
783
|
+
const qmarksTestDot = ([$0, ext = '']) => {
|
|
784
|
+
const noext = qmarksTestNoExtDot([$0]);
|
|
785
|
+
return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
|
|
786
|
+
};
|
|
787
|
+
const qmarksTest = ([$0, ext = '']) => {
|
|
788
|
+
const noext = qmarksTestNoExt([$0]);
|
|
789
|
+
return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
|
|
790
|
+
};
|
|
791
|
+
const qmarksTestNoExt = ([$0]) => {
|
|
792
|
+
const len = $0.length;
|
|
793
|
+
return (f) => f.length === len && !f.startsWith('.');
|
|
794
|
+
};
|
|
795
|
+
const qmarksTestNoExtDot = ([$0]) => {
|
|
796
|
+
const len = $0.length;
|
|
797
|
+
return (f) => f.length === len && f !== '.' && f !== '..';
|
|
798
|
+
};
|
|
799
|
+
//# sourceMappingURL=mini.js.map
|