minimatch 5.1.6 → 5.1.8
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/changelog.md +35 -0
- package/minimatch.js +153 -101
- package/package.json +1 -1
package/changelog.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# change log
|
|
2
|
+
|
|
3
|
+
## 5.1
|
|
4
|
+
|
|
5
|
+
- use windowsPathNoEscape/allowWindowsEscape opts
|
|
6
|
+
- make character classes more faithful to bash glob behavior
|
|
7
|
+
- fix handling of escapes
|
|
8
|
+
- treat invalid character classes as non-matching pattern
|
|
9
|
+
rather than escaped literals
|
|
10
|
+
|
|
11
|
+
## 5.0
|
|
12
|
+
|
|
13
|
+
- brace-expansion: ignore only blocks that begins with $
|
|
14
|
+
- Expect exclusively forward slash as path sep, same as node-glob
|
|
15
|
+
|
|
16
|
+
## 4.2
|
|
17
|
+
|
|
18
|
+
- makeRe: globstar should match zero+ path portions
|
|
19
|
+
- Fix bug with escaped '@' in patterns
|
|
20
|
+
|
|
21
|
+
## 4.1
|
|
22
|
+
|
|
23
|
+
- treat `nocase:true` as always having magic
|
|
24
|
+
- expose GLOBSTAR marker
|
|
25
|
+
|
|
26
|
+
## 4.0
|
|
27
|
+
|
|
28
|
+
- Update to modern JS syntax
|
|
29
|
+
- Add `allowWindowsEscape` option
|
|
30
|
+
|
|
31
|
+
## 3.x
|
|
32
|
+
|
|
33
|
+
- Added basic redos protection
|
|
34
|
+
- Handle unfinished `!(` extglob patterns
|
|
35
|
+
- Add `partial: true` option
|
package/minimatch.js
CHANGED
|
@@ -168,6 +168,8 @@ class Minimatch {
|
|
|
168
168
|
if (!options) options = {}
|
|
169
169
|
|
|
170
170
|
this.options = options
|
|
171
|
+
this.maxGlobstarRecursion = options.maxGlobstarRecursion !== undefined
|
|
172
|
+
? options.maxGlobstarRecursion : 200
|
|
171
173
|
this.set = []
|
|
172
174
|
this.pattern = pattern
|
|
173
175
|
this.windowsPathsNoEscape = !!options.windowsPathsNoEscape ||
|
|
@@ -255,114 +257,172 @@ class Minimatch {
|
|
|
255
257
|
// out of pattern, then that's fine, as long as all
|
|
256
258
|
// the parts match.
|
|
257
259
|
matchOne (file, pattern, partial) {
|
|
258
|
-
|
|
260
|
+
if (pattern.indexOf(GLOBSTAR) !== -1) {
|
|
261
|
+
return this._matchGlobstar(file, pattern, partial, 0, 0)
|
|
262
|
+
}
|
|
263
|
+
return this._matchOne(file, pattern, partial, 0, 0)
|
|
264
|
+
}
|
|
259
265
|
|
|
260
|
-
|
|
261
|
-
|
|
266
|
+
_matchGlobstar (file, pattern, partial, fileIndex, patternIndex) {
|
|
267
|
+
// find first globstar from patternIndex
|
|
268
|
+
let firstgs = -1
|
|
269
|
+
for (let i = patternIndex; i < pattern.length; i++) {
|
|
270
|
+
if (pattern[i] === GLOBSTAR) { firstgs = i; break }
|
|
271
|
+
}
|
|
262
272
|
|
|
263
|
-
|
|
273
|
+
// find last globstar
|
|
274
|
+
let lastgs = -1
|
|
275
|
+
for (let i = pattern.length - 1; i >= 0; i--) {
|
|
276
|
+
if (pattern[i] === GLOBSTAR) { lastgs = i; break }
|
|
277
|
+
}
|
|
264
278
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
pl = pattern.length
|
|
269
|
-
; (fi < fl) && (pi < pl)
|
|
270
|
-
; fi++, pi++) {
|
|
271
|
-
this.debug('matchOne loop')
|
|
272
|
-
var p = pattern[pi]
|
|
273
|
-
var f = file[fi]
|
|
279
|
+
const head = pattern.slice(patternIndex, firstgs)
|
|
280
|
+
const body = pattern.slice(firstgs + 1, lastgs)
|
|
281
|
+
const tail = pattern.slice(lastgs + 1)
|
|
274
282
|
|
|
275
|
-
|
|
283
|
+
// check the head
|
|
284
|
+
if (head.length) {
|
|
285
|
+
const fileHead = file.slice(fileIndex, fileIndex + head.length)
|
|
286
|
+
if (!this._matchOne(fileHead, head, partial, 0, 0)) {
|
|
287
|
+
return false
|
|
288
|
+
}
|
|
289
|
+
fileIndex += head.length
|
|
290
|
+
}
|
|
276
291
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
if (
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
//
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
// If so, return success.
|
|
294
|
-
// If not, the ** "swallows" a segment, and try again.
|
|
295
|
-
// This is recursively awful.
|
|
296
|
-
//
|
|
297
|
-
// a/**/b/**/c matching a/b/x/y/z/c
|
|
298
|
-
// - a matches a
|
|
299
|
-
// - doublestar
|
|
300
|
-
// - matchOne(b/x/y/z/c, b/**/c)
|
|
301
|
-
// - b matches b
|
|
302
|
-
// - doublestar
|
|
303
|
-
// - matchOne(x/y/z/c, c) -> no
|
|
304
|
-
// - matchOne(y/z/c, c) -> no
|
|
305
|
-
// - matchOne(z/c, c) -> no
|
|
306
|
-
// - matchOne(c, c) yes, hit
|
|
307
|
-
var fr = fi
|
|
308
|
-
var pr = pi + 1
|
|
309
|
-
if (pr === pl) {
|
|
310
|
-
this.debug('** at the end')
|
|
311
|
-
// a ** at the end will just swallow the rest.
|
|
312
|
-
// We have found a match.
|
|
313
|
-
// however, it will not swallow /.x, unless
|
|
314
|
-
// options.dot is set.
|
|
315
|
-
// . and .. are *never* matched by **, for explosively
|
|
316
|
-
// exponential reasons.
|
|
317
|
-
for (; fi < fl; fi++) {
|
|
318
|
-
if (file[fi] === '.' || file[fi] === '..' ||
|
|
319
|
-
(!options.dot && file[fi].charAt(0) === '.')) return false
|
|
320
|
-
}
|
|
321
|
-
return true
|
|
292
|
+
// check the tail
|
|
293
|
+
let fileTailMatch = 0
|
|
294
|
+
if (tail.length) {
|
|
295
|
+
if (tail.length + fileIndex > file.length) return false
|
|
296
|
+
|
|
297
|
+
const tailStart = file.length - tail.length
|
|
298
|
+
if (this._matchOne(file, tail, partial, tailStart, 0)) {
|
|
299
|
+
fileTailMatch = tail.length
|
|
300
|
+
} else {
|
|
301
|
+
// affordance for stuff like a/**/* matching a/b/
|
|
302
|
+
if (file[file.length - 1] !== '' ||
|
|
303
|
+
fileIndex + tail.length === file.length) {
|
|
304
|
+
return false
|
|
305
|
+
}
|
|
306
|
+
if (!this._matchOne(file, tail, partial, tailStart - 1, 0)) {
|
|
307
|
+
return false
|
|
322
308
|
}
|
|
309
|
+
fileTailMatch = tail.length + 1
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// if body is empty (single ** between head and tail)
|
|
314
|
+
if (!body.length) {
|
|
315
|
+
let sawSome = !!fileTailMatch
|
|
316
|
+
for (let i = fileIndex; i < file.length - fileTailMatch; i++) {
|
|
317
|
+
const f = String(file[i])
|
|
318
|
+
sawSome = true
|
|
319
|
+
if (f === '.' || f === '..' ||
|
|
320
|
+
(!this.options.dot && f.charAt(0) === '.')) {
|
|
321
|
+
return false
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return sawSome
|
|
325
|
+
}
|
|
323
326
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
+
// split body into segments at each GLOBSTAR
|
|
328
|
+
const bodySegments = [[[], 0]]
|
|
329
|
+
let currentBody = bodySegments[0]
|
|
330
|
+
let nonGsParts = 0
|
|
331
|
+
const nonGsPartsSums = [0]
|
|
332
|
+
for (const b of body) {
|
|
333
|
+
if (b === GLOBSTAR) {
|
|
334
|
+
nonGsPartsSums.push(nonGsParts)
|
|
335
|
+
currentBody = [[], 0]
|
|
336
|
+
bodySegments.push(currentBody)
|
|
337
|
+
} else {
|
|
338
|
+
currentBody[0].push(b)
|
|
339
|
+
nonGsParts++
|
|
340
|
+
}
|
|
341
|
+
}
|
|
327
342
|
|
|
328
|
-
|
|
343
|
+
let idx = bodySegments.length - 1
|
|
344
|
+
const fileLength = file.length - fileTailMatch
|
|
345
|
+
for (const b of bodySegments) {
|
|
346
|
+
b[1] = fileLength - (nonGsPartsSums[idx--] + b[0].length)
|
|
347
|
+
}
|
|
329
348
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
349
|
+
return !!this._matchGlobStarBodySections(
|
|
350
|
+
file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch
|
|
351
|
+
)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// return false for "nope, not matching"
|
|
355
|
+
// return null for "not matching, cannot keep trying"
|
|
356
|
+
_matchGlobStarBodySections (
|
|
357
|
+
file, bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail
|
|
358
|
+
) {
|
|
359
|
+
const bs = bodySegments[bodyIndex]
|
|
360
|
+
if (!bs) {
|
|
361
|
+
// just make sure there are no bad dots
|
|
362
|
+
for (let i = fileIndex; i < file.length; i++) {
|
|
363
|
+
sawTail = true
|
|
364
|
+
const f = file[i]
|
|
365
|
+
if (f === '.' || f === '..' ||
|
|
366
|
+
(!this.options.dot && f.charAt(0) === '.')) {
|
|
367
|
+
return false
|
|
348
368
|
}
|
|
369
|
+
}
|
|
370
|
+
return sawTail
|
|
371
|
+
}
|
|
349
372
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
373
|
+
const [body, after] = bs
|
|
374
|
+
while (fileIndex <= after) {
|
|
375
|
+
const m = this._matchOne(
|
|
376
|
+
file.slice(0, fileIndex + body.length),
|
|
377
|
+
body,
|
|
378
|
+
partial,
|
|
379
|
+
fileIndex,
|
|
380
|
+
0
|
|
381
|
+
)
|
|
382
|
+
// if limit exceeded, no match. intentional false negative,
|
|
383
|
+
// acceptable break in correctness for security.
|
|
384
|
+
if (m && globStarDepth < this.maxGlobstarRecursion) {
|
|
385
|
+
const sub = this._matchGlobStarBodySections(
|
|
386
|
+
file, bodySegments,
|
|
387
|
+
fileIndex + body.length, bodyIndex + 1,
|
|
388
|
+
partial, globStarDepth + 1, sawTail
|
|
389
|
+
)
|
|
390
|
+
if (sub !== false) {
|
|
391
|
+
return sub
|
|
358
392
|
}
|
|
393
|
+
}
|
|
394
|
+
const f = file[fileIndex]
|
|
395
|
+
if (f === '.' || f === '..' ||
|
|
396
|
+
(!this.options.dot && f.charAt(0) === '.')) {
|
|
359
397
|
return false
|
|
360
398
|
}
|
|
399
|
+
fileIndex++
|
|
400
|
+
}
|
|
401
|
+
return null
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
_matchOne (file, pattern, partial, fileIndex, patternIndex) {
|
|
405
|
+
let fi, pi, fl, pl
|
|
406
|
+
for (
|
|
407
|
+
fi = fileIndex, pi = patternIndex, fl = file.length, pl = pattern.length
|
|
408
|
+
; (fi < fl) && (pi < pl)
|
|
409
|
+
; fi++, pi++
|
|
410
|
+
) {
|
|
411
|
+
this.debug('matchOne loop')
|
|
412
|
+
const p = pattern[pi]
|
|
413
|
+
const f = file[fi]
|
|
414
|
+
|
|
415
|
+
this.debug(pattern, p, f)
|
|
416
|
+
|
|
417
|
+
// should be impossible.
|
|
418
|
+
// some invalid regexp stuff in the set.
|
|
419
|
+
/* istanbul ignore if */
|
|
420
|
+
if (p === false || p === GLOBSTAR) return false
|
|
361
421
|
|
|
362
422
|
// something other than **
|
|
363
423
|
// non-magic patterns just have to match exactly
|
|
364
424
|
// patterns with magic have been turned into regexps.
|
|
365
|
-
|
|
425
|
+
let hit
|
|
366
426
|
if (typeof p === 'string') {
|
|
367
427
|
hit = f === p
|
|
368
428
|
this.debug('string match', p, f, hit)
|
|
@@ -374,17 +434,6 @@ class Minimatch {
|
|
|
374
434
|
if (!hit) return false
|
|
375
435
|
}
|
|
376
436
|
|
|
377
|
-
// Note: ending in / means that we'll get a final ""
|
|
378
|
-
// at the end of the pattern. This can only match a
|
|
379
|
-
// corresponding "" at the end of the file.
|
|
380
|
-
// If the file ends in /, then it can only match a
|
|
381
|
-
// a pattern that ends in /, unless the pattern just
|
|
382
|
-
// doesn't have any more for it. But, a/b/ should *not*
|
|
383
|
-
// match "a/b/*", even though "" matches against the
|
|
384
|
-
// [^/]*? pattern, except in partial mode, where it might
|
|
385
|
-
// simply not be reached yet.
|
|
386
|
-
// However, a/b/ should still satisfy a/*
|
|
387
|
-
|
|
388
437
|
// now either we fell off the end of the pattern, or we're done.
|
|
389
438
|
if (fi === fl && pi === pl) {
|
|
390
439
|
// ran out of pattern and filename at the same time.
|
|
@@ -533,6 +582,9 @@ class Minimatch {
|
|
|
533
582
|
continue
|
|
534
583
|
}
|
|
535
584
|
|
|
585
|
+
// coalesce consecutive non-globstar * characters
|
|
586
|
+
if (c === '*' && stateChar === '*') continue
|
|
587
|
+
|
|
536
588
|
// if we already have a stateChar, then it means
|
|
537
589
|
// that there was something like ** or +? in there.
|
|
538
590
|
// Handle the stateChar, then proceed with this one.
|