minimatch 3.1.0 → 4.1.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.
Files changed (3) hide show
  1. package/LICENSE +1 -1
  2. package/minimatch.js +708 -781
  3. package/package.json +3 -6
package/minimatch.js CHANGED
@@ -1,15 +1,26 @@
1
+ const minimatch = module.exports = (p, pattern, options = {}) => {
2
+ assertValidPattern(pattern)
3
+
4
+ // shortcut: comments match nothing.
5
+ if (!options.nocomment && pattern.charAt(0) === '#') {
6
+ return false
7
+ }
8
+
9
+ return new Minimatch(pattern, options).match(p)
10
+ }
11
+
1
12
  module.exports = minimatch
2
- minimatch.Minimatch = Minimatch
3
13
 
4
- var path = (function () { try { return require('path') } catch (e) {}}()) || {
14
+ const path = (() => { try { return require('path') } catch (e) {}})() || {
5
15
  sep: '/'
6
16
  }
7
17
  minimatch.sep = path.sep
8
18
 
9
- var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
10
- var expand = require('brace-expansion')
19
+ const GLOBSTAR = Symbol('globstar **')
20
+ minimatch.GLOBSTAR = GLOBSTAR
21
+ const expand = require('brace-expansion')
11
22
 
12
- var plTypes = {
23
+ const plTypes = {
13
24
  '!': { open: '(?:(?!(?:', close: '))[^/]*?)'},
14
25
  '?': { open: '(?:', close: ')?' },
15
26
  '+': { open: '(?:', close: ')+' },
@@ -19,213 +30,71 @@ var plTypes = {
19
30
 
20
31
  // any single thing other than /
21
32
  // don't need to escape / when using new RegExp()
22
- var qmark = '[^/]'
33
+ const qmark = '[^/]'
23
34
 
24
35
  // * => any number of characters
25
- var star = qmark + '*?'
36
+ const star = qmark + '*?'
26
37
 
27
38
  // ** when dots are allowed. Anything goes, except .. and .
28
39
  // not (^ or / followed by one or two dots followed by $ or /),
29
40
  // followed by anything, any number of times.
30
- var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?'
41
+ const twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?'
31
42
 
32
43
  // not a ^ or / followed by a dot,
33
44
  // followed by anything, any number of times.
34
- var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?'
45
+ const twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?'
46
+
47
+ // "abc" -> { a:true, b:true, c:true }
48
+ const charSet = s => s.split('').reduce((set, c) => {
49
+ set[c] = true
50
+ return set
51
+ }, {})
35
52
 
36
53
  // characters that need to be escaped in RegExp.
37
- var reSpecials = charSet('().*{}+?[]^$\\!')
54
+ const reSpecials = charSet('().*{}+?[]^$\\!')
38
55
 
39
- // "abc" -> { a:true, b:true, c:true }
40
- function charSet (s) {
41
- return s.split('').reduce(function (set, c) {
42
- set[c] = true
43
- return set
44
- }, {})
45
- }
56
+ // characters that indicate we have to add the pattern start
57
+ const addPatternStartSet = charSet('[.(')
46
58
 
47
59
  // normalizes slashes.
48
- var slashSplit = /\/+/
60
+ const slashSplit = /\/+/
49
61
 
50
- minimatch.filter = filter
51
- function filter (pattern, options) {
52
- options = options || {}
53
- return function (p, i, list) {
54
- return minimatch(p, pattern, options)
55
- }
56
- }
62
+ minimatch.filter = (pattern, options = {}) =>
63
+ (p, i, list) => minimatch(p, pattern, options)
57
64
 
58
- function ext (a, b) {
59
- b = b || {}
60
- var t = {}
61
- Object.keys(a).forEach(function (k) {
62
- t[k] = a[k]
63
- })
64
- Object.keys(b).forEach(function (k) {
65
- t[k] = b[k]
66
- })
65
+ const ext = (a, b = {}) => {
66
+ const t = {}
67
+ Object.keys(a).forEach(k => t[k] = a[k])
68
+ Object.keys(b).forEach(k => t[k] = b[k])
67
69
  return t
68
70
  }
69
71
 
70
- minimatch.defaults = function (def) {
72
+ minimatch.defaults = def => {
71
73
  if (!def || typeof def !== 'object' || !Object.keys(def).length) {
72
74
  return minimatch
73
75
  }
74
76
 
75
- var orig = minimatch
76
-
77
- var m = function minimatch (p, pattern, options) {
78
- return orig(p, pattern, ext(def, options))
79
- }
80
-
81
- m.Minimatch = function Minimatch (pattern, options) {
82
- return new orig.Minimatch(pattern, ext(def, options))
83
- }
84
- m.Minimatch.defaults = function defaults (options) {
85
- return orig.defaults(ext(def, options)).Minimatch
86
- }
87
-
88
- m.filter = function filter (pattern, options) {
89
- return orig.filter(pattern, ext(def, options))
90
- }
91
-
92
- m.defaults = function defaults (options) {
93
- return orig.defaults(ext(def, options))
94
- }
77
+ const orig = minimatch
95
78
 
96
- m.makeRe = function makeRe (pattern, options) {
97
- return orig.makeRe(pattern, ext(def, options))
98
- }
99
-
100
- m.braceExpand = function braceExpand (pattern, options) {
101
- return orig.braceExpand(pattern, ext(def, options))
102
- }
103
-
104
- m.match = function (list, pattern, options) {
105
- return orig.match(list, pattern, ext(def, options))
79
+ const m = (p, pattern, options) => orig(p, pattern, ext(def, options))
80
+ m.Minimatch = class Minimatch extends orig.Minimatch {
81
+ constructor (pattern, options) {
82
+ super(pattern, ext(def, options))
83
+ }
106
84
  }
85
+ m.Minimatch.defaults = options => orig.defaults(ext(def, options)).Minimatch
86
+ m.filter = (pattern, options) => orig.filter(pattern, ext(def, options))
87
+ m.defaults = options => orig.defaults(ext(def, options))
88
+ m.makeRe = (pattern, options) => orig.makeRe(pattern, ext(def, options))
89
+ m.braceExpand = (pattern, options) => orig.braceExpand(pattern, ext(def, options))
90
+ m.match = (list, pattern, options) => orig.match(list, pattern, ext(def, options))
107
91
 
108
92
  return m
109
93
  }
110
94
 
111
- Minimatch.defaults = function (def) {
112
- return minimatch.defaults(def).Minimatch
113
- }
114
-
115
- function minimatch (p, pattern, options) {
116
- assertValidPattern(pattern)
117
-
118
- if (!options) options = {}
119
-
120
- // shortcut: comments match nothing.
121
- if (!options.nocomment && pattern.charAt(0) === '#') {
122
- return false
123
- }
124
-
125
- return new Minimatch(pattern, options).match(p)
126
- }
127
-
128
- function Minimatch (pattern, options) {
129
- if (!(this instanceof Minimatch)) {
130
- return new Minimatch(pattern, options)
131
- }
132
-
133
- assertValidPattern(pattern)
134
-
135
- if (!options) options = {}
136
-
137
- // windows support: need to use /, not \
138
- if (!options.allowWindowsEscape && path.sep !== '/') {
139
- pattern = pattern.split(path.sep).join('/')
140
- }
141
-
142
- this.options = options
143
- this.set = []
144
- this.pattern = pattern
145
- this.regexp = null
146
- this.negate = false
147
- this.comment = false
148
- this.empty = false
149
- this.partial = !!options.partial
150
-
151
- // make the set of regexps etc.
152
- this.make()
153
- }
154
-
155
- Minimatch.prototype.debug = function () {}
156
-
157
- Minimatch.prototype.make = make
158
- function make () {
159
- var pattern = this.pattern
160
- var options = this.options
161
95
 
162
- // empty patterns and comments match nothing.
163
- if (!options.nocomment && pattern.charAt(0) === '#') {
164
- this.comment = true
165
- return
166
- }
167
- if (!pattern) {
168
- this.empty = true
169
- return
170
- }
171
96
 
172
- // step 1: figure out negation, etc.
173
- this.parseNegate()
174
97
 
175
- // step 2: expand braces
176
- var set = this.globSet = this.braceExpand()
177
-
178
- if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) }
179
-
180
- this.debug(this.pattern, set)
181
-
182
- // step 3: now we have a set, so turn each one into a series of path-portion
183
- // matching patterns.
184
- // These will be regexps, except in the case of "**", which is
185
- // set to the GLOBSTAR object for globstar behavior,
186
- // and will not contain any / characters
187
- set = this.globParts = set.map(function (s) {
188
- return s.split(slashSplit)
189
- })
190
-
191
- this.debug(this.pattern, set)
192
-
193
- // glob --> regexps
194
- set = set.map(function (s, si, set) {
195
- return s.map(this.parse, this)
196
- }, this)
197
-
198
- this.debug(this.pattern, set)
199
-
200
- // filter out everything that didn't compile properly.
201
- set = set.filter(function (s) {
202
- return s.indexOf(false) === -1
203
- })
204
-
205
- this.debug(this.pattern, set)
206
-
207
- this.set = set
208
- }
209
-
210
- Minimatch.prototype.parseNegate = parseNegate
211
- function parseNegate () {
212
- var pattern = this.pattern
213
- var negate = false
214
- var options = this.options
215
- var negateOffset = 0
216
-
217
- if (options.nonegate) return
218
-
219
- for (var i = 0, l = pattern.length
220
- ; i < l && pattern.charAt(i) === '!'
221
- ; i++) {
222
- negate = !negate
223
- negateOffset++
224
- }
225
-
226
- if (negateOffset) this.pattern = pattern.substr(negateOffset)
227
- this.negate = negate
228
- }
229
98
 
230
99
  // Brace expansion:
231
100
  // a{b,c}d -> abd acd
@@ -237,24 +106,9 @@ function parseNegate () {
237
106
  // Invalid sets are not expanded.
238
107
  // a{2..}b -> a{2..}b
239
108
  // a{b}c -> a{b}c
240
- minimatch.braceExpand = function (pattern, options) {
241
- return braceExpand(pattern, options)
242
- }
243
-
244
- Minimatch.prototype.braceExpand = braceExpand
245
-
246
- function braceExpand (pattern, options) {
247
- if (!options) {
248
- if (this instanceof Minimatch) {
249
- options = this.options
250
- } else {
251
- options = {}
252
- }
253
- }
254
-
255
- pattern = typeof pattern === 'undefined'
256
- ? this.pattern : pattern
109
+ minimatch.braceExpand = (pattern, options) => braceExpand(pattern, options)
257
110
 
111
+ const braceExpand = (pattern, options = {}) => {
258
112
  assertValidPattern(pattern)
259
113
 
260
114
  // Thanks to Yeting Li <https://github.com/yetingli> for
@@ -267,8 +121,8 @@ function braceExpand (pattern, options) {
267
121
  return expand(pattern)
268
122
  }
269
123
 
270
- var MAX_PATTERN_LENGTH = 1024 * 64
271
- var assertValidPattern = function (pattern) {
124
+ const MAX_PATTERN_LENGTH = 1024 * 64
125
+ const assertValidPattern = pattern => {
272
126
  if (typeof pattern !== 'string') {
273
127
  throw new TypeError('invalid pattern')
274
128
  }
@@ -289,661 +143,734 @@ var assertValidPattern = function (pattern) {
289
143
  // when it is the *only* thing in a path portion. Otherwise, any series
290
144
  // of * is equivalent to a single *. Globstar behavior is enabled by
291
145
  // default, and can be disabled by setting options.noglobstar.
292
- Minimatch.prototype.parse = parse
293
- var SUBPARSE = {}
294
- function parse (pattern, isSub) {
295
- assertValidPattern(pattern)
146
+ const SUBPARSE = Symbol('subparse')
296
147
 
297
- var options = this.options
148
+ minimatch.makeRe = (pattern, options) =>
149
+ new Minimatch(pattern, options || {}).makeRe()
298
150
 
299
- // shortcuts
300
- if (pattern === '**') {
301
- if (!options.noglobstar)
302
- return GLOBSTAR
303
- else
304
- pattern = '*'
151
+ minimatch.match = (list, pattern, options = {}) => {
152
+ const mm = new Minimatch(pattern, options)
153
+ list = list.filter(f => mm.match(f))
154
+ if (mm.options.nonull && !list.length) {
155
+ list.push(pattern)
305
156
  }
306
- if (pattern === '') return ''
307
-
308
- var re = ''
309
- var hasMagic = false
310
- var escaping = false
311
- // ? => one single character
312
- var patternListStack = []
313
- var negativeLists = []
314
- var stateChar
315
- var inClass = false
316
- var reClassStart = -1
317
- var classStart = -1
318
- // . and .. never match anything that doesn't start with .,
319
- // even when options.dot is set.
320
- var patternStart = pattern.charAt(0) === '.' ? '' // anything
321
- // not (start or / followed by . or .. followed by / or end)
322
- : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))'
323
- : '(?!\\.)'
324
- var self = this
325
-
326
- function clearStateChar () {
327
- if (stateChar) {
328
- // we had some state-tracking character
329
- // that wasn't consumed by this pass.
330
- switch (stateChar) {
331
- case '*':
332
- re += star
333
- hasMagic = true
334
- break
335
- case '?':
336
- re += qmark
337
- hasMagic = true
338
- break
339
- default:
340
- re += '\\' + stateChar
341
- break
342
- }
343
- self.debug('clearStateChar %j %j', stateChar, re)
344
- stateChar = false
157
+ return list
158
+ }
159
+
160
+ // replace stuff like \* with *
161
+ const globUnescape = s => s.replace(/\\(.)/g, '$1')
162
+ const regExpEscape = s => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
163
+
164
+ class Minimatch {
165
+ constructor (pattern, options) {
166
+ assertValidPattern(pattern)
167
+
168
+ if (!options) options = {}
169
+
170
+ // windows support: need to use /, not \
171
+ if (!options.allowWindowsEscape && path.sep !== '/') {
172
+ pattern = pattern.split(path.sep).join('/')
345
173
  }
174
+
175
+ this.options = options
176
+ this.set = []
177
+ this.pattern = pattern
178
+ this.regexp = null
179
+ this.negate = false
180
+ this.comment = false
181
+ this.empty = false
182
+ this.partial = !!options.partial
183
+
184
+ // make the set of regexps etc.
185
+ this.make()
346
186
  }
347
187
 
348
- for (var i = 0, len = pattern.length, c
349
- ; (i < len) && (c = pattern.charAt(i))
350
- ; i++) {
351
- this.debug('%s\t%s %s %j', pattern, i, re, c)
188
+ debug () {}
189
+
190
+ make () {
191
+ const pattern = this.pattern
192
+ const options = this.options
352
193
 
353
- // skip over any that are escaped.
354
- if (escaping && reSpecials[c]) {
355
- re += '\\' + c
356
- escaping = false
357
- continue
194
+ // empty patterns and comments match nothing.
195
+ if (!options.nocomment && pattern.charAt(0) === '#') {
196
+ this.comment = true
197
+ return
198
+ }
199
+ if (!pattern) {
200
+ this.empty = true
201
+ return
358
202
  }
359
203
 
360
- switch (c) {
361
- /* istanbul ignore next */
362
- case '/': {
363
- // completely not allowed, even escaped.
364
- // Should already be path-split by now.
365
- return false
366
- }
204
+ // step 1: figure out negation, etc.
205
+ this.parseNegate()
367
206
 
368
- case '\\':
369
- clearStateChar()
370
- escaping = true
371
- continue
372
-
373
- // the various stateChar values
374
- // for the "extglob" stuff.
375
- case '?':
376
- case '*':
377
- case '+':
378
- case '@':
379
- case '!':
380
- this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c)
381
-
382
- // all of those are literals inside a class, except that
383
- // the glob [!a] means [^a] in regexp
384
- if (inClass) {
385
- this.debug(' in class')
386
- if (c === '!' && i === classStart + 1) c = '^'
387
- re += c
388
- continue
389
- }
207
+ // step 2: expand braces
208
+ let set = this.globSet = this.braceExpand()
390
209
 
391
- // if we already have a stateChar, then it means
392
- // that there was something like ** or +? in there.
393
- // Handle the stateChar, then proceed with this one.
394
- self.debug('call clearStateChar %j', stateChar)
395
- clearStateChar()
396
- stateChar = c
397
- // if extglob is disabled, then +(asdf|foo) isn't a thing.
398
- // just clear the statechar *now*, rather than even diving into
399
- // the patternList stuff.
400
- if (options.noext) clearStateChar()
401
- continue
402
-
403
- case '(':
404
- if (inClass) {
405
- re += '('
406
- continue
407
- }
210
+ if (options.debug) this.debug = (...args) => console.error(...args)
408
211
 
409
- if (!stateChar) {
410
- re += '\\('
411
- continue
412
- }
212
+ this.debug(this.pattern, set)
413
213
 
414
- patternListStack.push({
415
- type: stateChar,
416
- start: i - 1,
417
- reStart: re.length,
418
- open: plTypes[stateChar].open,
419
- close: plTypes[stateChar].close
420
- })
421
- // negation is (?:(?!js)[^/]*)
422
- re += stateChar === '!' ? '(?:(?!(?:' : '(?:'
423
- this.debug('plType %j %j', stateChar, re)
424
- stateChar = false
425
- continue
214
+ // step 3: now we have a set, so turn each one into a series of path-portion
215
+ // matching patterns.
216
+ // These will be regexps, except in the case of "**", which is
217
+ // set to the GLOBSTAR object for globstar behavior,
218
+ // and will not contain any / characters
219
+ set = this.globParts = set.map(s => s.split(slashSplit))
426
220
 
427
- case ')':
428
- if (inClass || !patternListStack.length) {
429
- re += '\\)'
430
- continue
431
- }
221
+ this.debug(this.pattern, set)
432
222
 
433
- clearStateChar()
434
- hasMagic = true
435
- var pl = patternListStack.pop()
436
- // negation is (?:(?!js)[^/]*)
437
- // The others are (?:<pattern>)<type>
438
- re += pl.close
439
- if (pl.type === '!') {
440
- negativeLists.push(pl)
441
- }
442
- pl.reEnd = re.length
443
- continue
444
-
445
- case '|':
446
- if (inClass || !patternListStack.length || escaping) {
447
- re += '\\|'
448
- escaping = false
449
- continue
450
- }
223
+ // glob --> regexps
224
+ set = set.map((s, si, set) => s.map(this.parse, this))
451
225
 
452
- clearStateChar()
453
- re += '|'
454
- continue
226
+ this.debug(this.pattern, set)
455
227
 
456
- // these are mostly the same in regexp and glob
457
- case '[':
458
- // swallow any state-tracking char before the [
459
- clearStateChar()
228
+ // filter out everything that didn't compile properly.
229
+ set = set.filter(s => s.indexOf(false) === -1)
460
230
 
461
- if (inClass) {
462
- re += '\\' + c
463
- continue
464
- }
231
+ this.debug(this.pattern, set)
465
232
 
466
- inClass = true
467
- classStart = i
468
- reClassStart = re.length
469
- re += c
470
- continue
471
-
472
- case ']':
473
- // a right bracket shall lose its special
474
- // meaning and represent itself in
475
- // a bracket expression if it occurs
476
- // first in the list. -- POSIX.2 2.8.3.2
477
- if (i === classStart + 1 || !inClass) {
478
- re += '\\' + c
479
- escaping = false
480
- continue
481
- }
233
+ this.set = set
234
+ }
482
235
 
483
- // handle the case where we left a class open.
484
- // "[z-a]" is valid, equivalent to "\[z-a\]"
485
- // split where the last [ was, make sure we don't have
486
- // an invalid re. if so, re-walk the contents of the
487
- // would-be class to re-translate any characters that
488
- // were passed through as-is
489
- // TODO: It would probably be faster to determine this
490
- // without a try/catch and a new RegExp, but it's tricky
491
- // to do safely. For now, this is safe and works.
492
- var cs = pattern.substring(classStart + 1, i)
493
- try {
494
- RegExp('[' + cs + ']')
495
- } catch (er) {
496
- // not a valid class!
497
- var sp = this.parse(cs, SUBPARSE)
498
- re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
499
- hasMagic = hasMagic || sp[1]
500
- inClass = false
501
- continue
236
+ parseNegate () {
237
+ if (this.options.nonegate) return
238
+
239
+ const pattern = this.pattern
240
+ let negate = false
241
+ let negateOffset = 0
242
+
243
+ for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
244
+ negate = !negate
245
+ negateOffset++
246
+ }
247
+
248
+ if (negateOffset) this.pattern = pattern.substr(negateOffset)
249
+ this.negate = negate
250
+ }
251
+
252
+ // set partial to true to test if, for example,
253
+ // "/a/b" matches the start of "/*/b/*/d"
254
+ // Partial means, if you run out of file before you run
255
+ // out of pattern, then that's fine, as long as all
256
+ // the parts match.
257
+ matchOne (file, pattern, partial) {
258
+ var options = this.options
259
+
260
+ this.debug('matchOne',
261
+ { 'this': this, file: file, pattern: pattern })
262
+
263
+ this.debug('matchOne', file.length, pattern.length)
264
+
265
+ for (var fi = 0,
266
+ pi = 0,
267
+ fl = file.length,
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]
274
+
275
+ this.debug(pattern, p, f)
276
+
277
+ // should be impossible.
278
+ // some invalid regexp stuff in the set.
279
+ /* istanbul ignore if */
280
+ if (p === false) return false
281
+
282
+ if (p === GLOBSTAR) {
283
+ this.debug('GLOBSTAR', [pattern, p, f])
284
+
285
+ // "**"
286
+ // a/**/b/**/c would match the following:
287
+ // a/b/x/y/z/c
288
+ // a/x/y/z/b/c
289
+ // a/b/x/b/x/c
290
+ // a/b/c
291
+ // To do this, take the rest of the pattern after
292
+ // the **, and see if it would match the file remainder.
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
502
322
  }
503
323
 
504
- // finish up the class.
505
- hasMagic = true
506
- inClass = false
507
- re += c
508
- continue
509
-
510
- default:
511
- // swallow any state char that wasn't consumed
512
- clearStateChar()
513
-
514
- if (escaping) {
515
- // no need
516
- escaping = false
517
- } else if (reSpecials[c]
518
- && !(c === '^' && inClass)) {
519
- re += '\\'
324
+ // ok, let's see if we can swallow whatever we can.
325
+ while (fr < fl) {
326
+ var swallowee = file[fr]
327
+
328
+ this.debug('\nglobstar while', file, fr, pattern, pr, swallowee)
329
+
330
+ // XXX remove this slice. Just pass the start index.
331
+ if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
332
+ this.debug('globstar found match!', fr, fl, swallowee)
333
+ // found a match.
334
+ return true
335
+ } else {
336
+ // can't swallow "." or ".." ever.
337
+ // can only swallow ".foo" when explicitly asked.
338
+ if (swallowee === '.' || swallowee === '..' ||
339
+ (!options.dot && swallowee.charAt(0) === '.')) {
340
+ this.debug('dot detected!', file, fr, pattern, pr)
341
+ break
342
+ }
343
+
344
+ // ** swallows a segment, and continue.
345
+ this.debug('globstar swallow a segment, and continue')
346
+ fr++
347
+ }
520
348
  }
521
349
 
522
- re += c
523
-
524
- } // switch
525
- } // for
526
-
527
- // handle the case where we left a class open.
528
- // "[abc" is valid, equivalent to "\[abc"
529
- if (inClass) {
530
- // split where the last [ was, and escape it
531
- // this is a huge pita. We now have to re-walk
532
- // the contents of the would-be class to re-translate
533
- // any characters that were passed through as-is
534
- cs = pattern.substr(classStart + 1)
535
- sp = this.parse(cs, SUBPARSE)
536
- re = re.substr(0, reClassStart) + '\\[' + sp[0]
537
- hasMagic = hasMagic || sp[1]
538
- }
350
+ // no match was found.
351
+ // However, in partial mode, we can't say this is necessarily over.
352
+ // If there's more *pattern* left, then
353
+ /* istanbul ignore if */
354
+ if (partial) {
355
+ // ran out of file
356
+ this.debug('\n>>> no match, partial?', file, fr, pattern, pr)
357
+ if (fr === fl) return true
358
+ }
359
+ return false
360
+ }
539
361
 
540
- // handle the case where we had a +( thing at the *end*
541
- // of the pattern.
542
- // each pattern list stack adds 3 chars, and we need to go through
543
- // and escape any | chars that were passed through as-is for the regexp.
544
- // Go through and escape them, taking care not to double-escape any
545
- // | chars that were already escaped.
546
- for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
547
- var tail = re.slice(pl.reStart + pl.open.length)
548
- this.debug('setting tail', re, pl)
549
- // maybe some even number of \, then maybe 1 \, followed by a |
550
- tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) {
551
- if (!$2) {
552
- // the | isn't already escaped, so escape it.
553
- $2 = '\\'
362
+ // something other than **
363
+ // non-magic patterns just have to match exactly
364
+ // patterns with magic have been turned into regexps.
365
+ var hit
366
+ if (typeof p === 'string') {
367
+ hit = f === p
368
+ this.debug('string match', p, f, hit)
369
+ } else {
370
+ hit = f.match(p)
371
+ this.debug('pattern match', p, f, hit)
554
372
  }
555
373
 
556
- // need to escape all those slashes *again*, without escaping the
557
- // one that we need for escaping the | character. As it works out,
558
- // escaping an even number of slashes can be done by simply repeating
559
- // it exactly after itself. That's why this trick works.
560
- //
561
- // I am sorry that you have to see this.
562
- return $1 + $1 + $2 + '|'
563
- })
564
-
565
- this.debug('tail=%j\n %s', tail, tail, pl, re)
566
- var t = pl.type === '*' ? star
567
- : pl.type === '?' ? qmark
568
- : '\\' + pl.type
569
-
570
- hasMagic = true
571
- re = re.slice(0, pl.reStart) + t + '\\(' + tail
572
- }
374
+ if (!hit) return false
375
+ }
376
+
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
+ // now either we fell off the end of the pattern, or we're done.
389
+ if (fi === fl && pi === pl) {
390
+ // ran out of pattern and filename at the same time.
391
+ // an exact hit!
392
+ return true
393
+ } else if (fi === fl) {
394
+ // ran out of file, but still had pattern left.
395
+ // this is ok if we're doing the match as part of
396
+ // a glob fs traversal.
397
+ return partial
398
+ } else /* istanbul ignore else */ if (pi === pl) {
399
+ // ran out of pattern, still have file left.
400
+ // this is only acceptable if we're on the very last
401
+ // empty segment of a file with a trailing slash.
402
+ // a/* should match a/b/
403
+ return (fi === fl - 1) && (file[fi] === '')
404
+ }
573
405
 
574
- // handle trailing things that only matter at the very end.
575
- clearStateChar()
576
- if (escaping) {
577
- // trailing \\
578
- re += '\\\\'
406
+ // should be unreachable.
407
+ /* istanbul ignore next */
408
+ throw new Error('wtf?')
579
409
  }
580
410
 
581
- // only need to apply the nodot start if the re starts with
582
- // something that could conceivably capture a dot
583
- var addPatternStart = false
584
- switch (re.charAt(0)) {
585
- case '[': case '.': case '(': addPatternStart = true
411
+ braceExpand () {
412
+ return braceExpand(this.pattern, this.options)
586
413
  }
587
414
 
588
- // Hack to work around lack of negative lookbehind in JS
589
- // A pattern like: *.!(x).!(y|z) needs to ensure that a name
590
- // like 'a.xyz.yz' doesn't match. So, the first negative
591
- // lookahead, has to look ALL the way ahead, to the end of
592
- // the pattern.
593
- for (var n = negativeLists.length - 1; n > -1; n--) {
594
- var nl = negativeLists[n]
595
-
596
- var nlBefore = re.slice(0, nl.reStart)
597
- var nlFirst = re.slice(nl.reStart, nl.reEnd - 8)
598
- var nlLast = re.slice(nl.reEnd - 8, nl.reEnd)
599
- var nlAfter = re.slice(nl.reEnd)
600
-
601
- nlLast += nlAfter
602
-
603
- // Handle nested stuff like *(*.js|!(*.json)), where open parens
604
- // mean that we should *not* include the ) in the bit that is considered
605
- // "after" the negated section.
606
- var openParensBefore = nlBefore.split('(').length - 1
607
- var cleanAfter = nlAfter
608
- for (i = 0; i < openParensBefore; i++) {
609
- cleanAfter = cleanAfter.replace(/\)[+*?]?/, '')
610
- }
611
- nlAfter = cleanAfter
415
+ parse (pattern, isSub) {
416
+ assertValidPattern(pattern)
417
+
418
+ const options = this.options
612
419
 
613
- var dollar = ''
614
- if (nlAfter === '' && isSub !== SUBPARSE) {
615
- dollar = '$'
420
+ // shortcuts
421
+ if (pattern === '**') {
422
+ if (!options.noglobstar)
423
+ return GLOBSTAR
424
+ else
425
+ pattern = '*'
426
+ }
427
+ if (pattern === '') return ''
428
+
429
+ let re = ''
430
+ let hasMagic = !!options.nocase
431
+ let escaping = false
432
+ // ? => one single character
433
+ const patternListStack = []
434
+ const negativeLists = []
435
+ let stateChar
436
+ let inClass = false
437
+ let reClassStart = -1
438
+ let classStart = -1
439
+ let cs
440
+ let pl
441
+ let sp
442
+ // . and .. never match anything that doesn't start with .,
443
+ // even when options.dot is set.
444
+ const patternStart = pattern.charAt(0) === '.' ? '' // anything
445
+ // not (start or / followed by . or .. followed by / or end)
446
+ : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))'
447
+ : '(?!\\.)'
448
+
449
+ const clearStateChar = () => {
450
+ if (stateChar) {
451
+ // we had some state-tracking character
452
+ // that wasn't consumed by this pass.
453
+ switch (stateChar) {
454
+ case '*':
455
+ re += star
456
+ hasMagic = true
457
+ break
458
+ case '?':
459
+ re += qmark
460
+ hasMagic = true
461
+ break
462
+ default:
463
+ re += '\\' + stateChar
464
+ break
465
+ }
466
+ this.debug('clearStateChar %j %j', stateChar, re)
467
+ stateChar = false
468
+ }
616
469
  }
617
- var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast
618
- re = newRe
619
- }
620
470
 
621
- // if the re is not "" at this point, then we need to make sure
622
- // it doesn't match against an empty path part.
623
- // Otherwise a/* will match a/, which it should not.
624
- if (re !== '' && hasMagic) {
625
- re = '(?=.)' + re
626
- }
471
+ for (let i = 0, c; (i < pattern.length) && (c = pattern.charAt(i)); i++) {
472
+ this.debug('%s\t%s %s %j', pattern, i, re, c)
627
473
 
628
- if (addPatternStart) {
629
- re = patternStart + re
630
- }
474
+ // skip over any that are escaped.
475
+ if (escaping && reSpecials[c]) {
476
+ re += '\\' + c
477
+ escaping = false
478
+ continue
479
+ }
631
480
 
632
- // parsing just a piece of a larger pattern.
633
- if (isSub === SUBPARSE) {
634
- return [re, hasMagic]
635
- }
481
+ switch (c) {
482
+ /* istanbul ignore next */
483
+ case '/': {
484
+ // completely not allowed, even escaped.
485
+ // Should already be path-split by now.
486
+ return false
487
+ }
636
488
 
637
- // skip the regexp for non-magical patterns
638
- // unescape anything in it, though, so that it'll be
639
- // an exact match against a file etc.
640
- if (!hasMagic) {
641
- return globUnescape(pattern)
642
- }
489
+ case '\\':
490
+ clearStateChar()
491
+ escaping = true
492
+ continue
643
493
 
644
- var flags = options.nocase ? 'i' : ''
645
- try {
646
- var regExp = new RegExp('^' + re + '$', flags)
647
- } catch (er) /* istanbul ignore next - should be impossible */ {
648
- // If it was an invalid regular expression, then it can't match
649
- // anything. This trick looks for a character after the end of
650
- // the string, which is of course impossible, except in multi-line
651
- // mode, but it's not a /m regex.
652
- return new RegExp('$.')
653
- }
494
+ // the various stateChar values
495
+ // for the "extglob" stuff.
496
+ case '?':
497
+ case '*':
498
+ case '+':
499
+ case '@':
500
+ case '!':
501
+ this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c)
502
+
503
+ // all of those are literals inside a class, except that
504
+ // the glob [!a] means [^a] in regexp
505
+ if (inClass) {
506
+ this.debug(' in class')
507
+ if (c === '!' && i === classStart + 1) c = '^'
508
+ re += c
509
+ continue
510
+ }
654
511
 
655
- regExp._glob = pattern
656
- regExp._src = re
512
+ // if we already have a stateChar, then it means
513
+ // that there was something like ** or +? in there.
514
+ // Handle the stateChar, then proceed with this one.
515
+ this.debug('call clearStateChar %j', stateChar)
516
+ clearStateChar()
517
+ stateChar = c
518
+ // if extglob is disabled, then +(asdf|foo) isn't a thing.
519
+ // just clear the statechar *now*, rather than even diving into
520
+ // the patternList stuff.
521
+ if (options.noext) clearStateChar()
522
+ continue
523
+
524
+ case '(':
525
+ if (inClass) {
526
+ re += '('
527
+ continue
528
+ }
657
529
 
658
- return regExp
659
- }
530
+ if (!stateChar) {
531
+ re += '\\('
532
+ continue
533
+ }
660
534
 
661
- minimatch.makeRe = function (pattern, options) {
662
- return new Minimatch(pattern, options || {}).makeRe()
663
- }
535
+ patternListStack.push({
536
+ type: stateChar,
537
+ start: i - 1,
538
+ reStart: re.length,
539
+ open: plTypes[stateChar].open,
540
+ close: plTypes[stateChar].close
541
+ })
542
+ // negation is (?:(?!js)[^/]*)
543
+ re += stateChar === '!' ? '(?:(?!(?:' : '(?:'
544
+ this.debug('plType %j %j', stateChar, re)
545
+ stateChar = false
546
+ continue
547
+
548
+ case ')':
549
+ if (inClass || !patternListStack.length) {
550
+ re += '\\)'
551
+ continue
552
+ }
664
553
 
665
- Minimatch.prototype.makeRe = makeRe
666
- function makeRe () {
667
- if (this.regexp || this.regexp === false) return this.regexp
554
+ clearStateChar()
555
+ hasMagic = true
556
+ pl = patternListStack.pop()
557
+ // negation is (?:(?!js)[^/]*)
558
+ // The others are (?:<pattern>)<type>
559
+ re += pl.close
560
+ if (pl.type === '!') {
561
+ negativeLists.push(pl)
562
+ }
563
+ pl.reEnd = re.length
564
+ continue
565
+
566
+ case '|':
567
+ if (inClass || !patternListStack.length || escaping) {
568
+ re += '\\|'
569
+ escaping = false
570
+ continue
571
+ }
668
572
 
669
- // at this point, this.set is a 2d array of partial
670
- // pattern strings, or "**".
671
- //
672
- // It's better to use .match(). This function shouldn't
673
- // be used, really, but it's pretty convenient sometimes,
674
- // when you just want to work with a regex.
675
- var set = this.set
573
+ clearStateChar()
574
+ re += '|'
575
+ continue
676
576
 
677
- if (!set.length) {
678
- this.regexp = false
679
- return this.regexp
680
- }
681
- var options = this.options
682
-
683
- var twoStar = options.noglobstar ? star
684
- : options.dot ? twoStarDot
685
- : twoStarNoDot
686
- var flags = options.nocase ? 'i' : ''
687
-
688
- var re = set.map(function (pattern) {
689
- return pattern.map(function (p) {
690
- return (p === GLOBSTAR) ? twoStar
691
- : (typeof p === 'string') ? regExpEscape(p)
692
- : p._src
693
- }).join('\\\/')
694
- }).join('|')
695
-
696
- // must match entire pattern
697
- // ending in a * or ** will make it less strict.
698
- re = '^(?:' + re + ')$'
699
-
700
- // can match anything, as long as it's not this.
701
- if (this.negate) re = '^(?!' + re + ').*$'
702
-
703
- try {
704
- this.regexp = new RegExp(re, flags)
705
- } catch (ex) /* istanbul ignore next - should be impossible */ {
706
- this.regexp = false
707
- }
708
- return this.regexp
709
- }
577
+ // these are mostly the same in regexp and glob
578
+ case '[':
579
+ // swallow any state-tracking char before the [
580
+ clearStateChar()
710
581
 
711
- minimatch.match = function (list, pattern, options) {
712
- options = options || {}
713
- var mm = new Minimatch(pattern, options)
714
- list = list.filter(function (f) {
715
- return mm.match(f)
716
- })
717
- if (mm.options.nonull && !list.length) {
718
- list.push(pattern)
719
- }
720
- return list
721
- }
582
+ if (inClass) {
583
+ re += '\\' + c
584
+ continue
585
+ }
586
+
587
+ inClass = true
588
+ classStart = i
589
+ reClassStart = re.length
590
+ re += c
591
+ continue
592
+
593
+ case ']':
594
+ // a right bracket shall lose its special
595
+ // meaning and represent itself in
596
+ // a bracket expression if it occurs
597
+ // first in the list. -- POSIX.2 2.8.3.2
598
+ if (i === classStart + 1 || !inClass) {
599
+ re += '\\' + c
600
+ escaping = false
601
+ continue
602
+ }
722
603
 
723
- Minimatch.prototype.match = function match (f, partial) {
724
- if (typeof partial === 'undefined') partial = this.partial
725
- this.debug('match', f, this.pattern)
726
- // short-circuit in the case of busted things.
727
- // comments, etc.
728
- if (this.comment) return false
729
- if (this.empty) return f === ''
604
+ // handle the case where we left a class open.
605
+ // "[z-a]" is valid, equivalent to "\[z-a\]"
606
+ // split where the last [ was, make sure we don't have
607
+ // an invalid re. if so, re-walk the contents of the
608
+ // would-be class to re-translate any characters that
609
+ // were passed through as-is
610
+ // TODO: It would probably be faster to determine this
611
+ // without a try/catch and a new RegExp, but it's tricky
612
+ // to do safely. For now, this is safe and works.
613
+ cs = pattern.substring(classStart + 1, i)
614
+ try {
615
+ RegExp('[' + cs + ']')
616
+ } catch (er) {
617
+ // not a valid class!
618
+ sp = this.parse(cs, SUBPARSE)
619
+ re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
620
+ hasMagic = hasMagic || sp[1]
621
+ inClass = false
622
+ continue
623
+ }
730
624
 
731
- if (f === '/' && partial) return true
625
+ // finish up the class.
626
+ hasMagic = true
627
+ inClass = false
628
+ re += c
629
+ continue
732
630
 
733
- var options = this.options
631
+ default:
632
+ // swallow any state char that wasn't consumed
633
+ clearStateChar()
634
+
635
+ if (escaping) {
636
+ // no need
637
+ escaping = false
638
+ } else if (reSpecials[c]
639
+ && !(c === '^' && inClass)) {
640
+ re += '\\'
641
+ }
734
642
 
735
- // windows: need to use /, not \
736
- if (path.sep !== '/') {
737
- f = f.split(path.sep).join('/')
738
- }
643
+ re += c
644
+
645
+ } // switch
646
+ } // for
647
+
648
+ // handle the case where we left a class open.
649
+ // "[abc" is valid, equivalent to "\[abc"
650
+ if (inClass) {
651
+ // split where the last [ was, and escape it
652
+ // this is a huge pita. We now have to re-walk
653
+ // the contents of the would-be class to re-translate
654
+ // any characters that were passed through as-is
655
+ cs = pattern.substr(classStart + 1)
656
+ sp = this.parse(cs, SUBPARSE)
657
+ re = re.substr(0, reClassStart) + '\\[' + sp[0]
658
+ hasMagic = hasMagic || sp[1]
659
+ }
660
+
661
+ // handle the case where we had a +( thing at the *end*
662
+ // of the pattern.
663
+ // each pattern list stack adds 3 chars, and we need to go through
664
+ // and escape any | chars that were passed through as-is for the regexp.
665
+ // Go through and escape them, taking care not to double-escape any
666
+ // | chars that were already escaped.
667
+ for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
668
+ let tail
669
+ tail = re.slice(pl.reStart + pl.open.length)
670
+ this.debug('setting tail', re, pl)
671
+ // maybe some even number of \, then maybe 1 \, followed by a |
672
+ tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, (_, $1, $2) => {
673
+ if (!$2) {
674
+ // the | isn't already escaped, so escape it.
675
+ $2 = '\\'
676
+ }
677
+
678
+ // need to escape all those slashes *again*, without escaping the
679
+ // one that we need for escaping the | character. As it works out,
680
+ // escaping an even number of slashes can be done by simply repeating
681
+ // it exactly after itself. That's why this trick works.
682
+ //
683
+ // I am sorry that you have to see this.
684
+ return $1 + $1 + $2 + '|'
685
+ })
686
+
687
+ this.debug('tail=%j\n %s', tail, tail, pl, re)
688
+ const t = pl.type === '*' ? star
689
+ : pl.type === '?' ? qmark
690
+ : '\\' + pl.type
691
+
692
+ hasMagic = true
693
+ re = re.slice(0, pl.reStart) + t + '\\(' + tail
694
+ }
695
+
696
+ // handle trailing things that only matter at the very end.
697
+ clearStateChar()
698
+ if (escaping) {
699
+ // trailing \\
700
+ re += '\\\\'
701
+ }
702
+
703
+ // only need to apply the nodot start if the re starts with
704
+ // something that could conceivably capture a dot
705
+ const addPatternStart = addPatternStartSet[re.charAt(0)]
706
+
707
+ // Hack to work around lack of negative lookbehind in JS
708
+ // A pattern like: *.!(x).!(y|z) needs to ensure that a name
709
+ // like 'a.xyz.yz' doesn't match. So, the first negative
710
+ // lookahead, has to look ALL the way ahead, to the end of
711
+ // the pattern.
712
+ for (let n = negativeLists.length - 1; n > -1; n--) {
713
+ const nl = negativeLists[n]
714
+
715
+ const nlBefore = re.slice(0, nl.reStart)
716
+ const nlFirst = re.slice(nl.reStart, nl.reEnd - 8)
717
+ let nlAfter = re.slice(nl.reEnd)
718
+ const nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + nlAfter
719
+
720
+ // Handle nested stuff like *(*.js|!(*.json)), where open parens
721
+ // mean that we should *not* include the ) in the bit that is considered
722
+ // "after" the negated section.
723
+ const openParensBefore = nlBefore.split('(').length - 1
724
+ let cleanAfter = nlAfter
725
+ for (let i = 0; i < openParensBefore; i++) {
726
+ cleanAfter = cleanAfter.replace(/\)[+*?]?/, '')
727
+ }
728
+ nlAfter = cleanAfter
729
+
730
+ const dollar = nlAfter === '' && isSub !== SUBPARSE ? '$' : ''
731
+ re = nlBefore + nlFirst + nlAfter + dollar + nlLast
732
+ }
733
+
734
+ // if the re is not "" at this point, then we need to make sure
735
+ // it doesn't match against an empty path part.
736
+ // Otherwise a/* will match a/, which it should not.
737
+ if (re !== '' && hasMagic) {
738
+ re = '(?=.)' + re
739
+ }
739
740
 
740
- // treat the test path as a set of pathparts.
741
- f = f.split(slashSplit)
742
- this.debug(this.pattern, 'split', f)
741
+ if (addPatternStart) {
742
+ re = patternStart + re
743
+ }
743
744
 
744
- // just ONE of the pattern sets in this.set needs to match
745
- // in order for it to be valid. If negating, then just one
746
- // match means that we have failed.
747
- // Either way, return on the first hit.
745
+ // parsing just a piece of a larger pattern.
746
+ if (isSub === SUBPARSE) {
747
+ return [re, hasMagic]
748
+ }
748
749
 
749
- var set = this.set
750
- this.debug(this.pattern, 'set', set)
750
+ // skip the regexp for non-magical patterns
751
+ // unescape anything in it, though, so that it'll be
752
+ // an exact match against a file etc.
753
+ if (!hasMagic) {
754
+ return globUnescape(pattern)
755
+ }
751
756
 
752
- // Find the basename of the path by looking for the last non-empty segment
753
- var filename
754
- var i
755
- for (i = f.length - 1; i >= 0; i--) {
756
- filename = f[i]
757
- if (filename) break
757
+ const flags = options.nocase ? 'i' : ''
758
+ try {
759
+ return Object.assign(new RegExp('^' + re + '$', flags), {
760
+ _glob: pattern,
761
+ _src: re,
762
+ })
763
+ } catch (er) /* istanbul ignore next - should be impossible */ {
764
+ // If it was an invalid regular expression, then it can't match
765
+ // anything. This trick looks for a character after the end of
766
+ // the string, which is of course impossible, except in multi-line
767
+ // mode, but it's not a /m regex.
768
+ return new RegExp('$.')
769
+ }
758
770
  }
759
771
 
760
- for (i = 0; i < set.length; i++) {
761
- var pattern = set[i]
762
- var file = f
763
- if (options.matchBase && pattern.length === 1) {
764
- file = [filename]
772
+ makeRe () {
773
+ if (this.regexp || this.regexp === false) return this.regexp
774
+
775
+ // at this point, this.set is a 2d array of partial
776
+ // pattern strings, or "**".
777
+ //
778
+ // It's better to use .match(). This function shouldn't
779
+ // be used, really, but it's pretty convenient sometimes,
780
+ // when you just want to work with a regex.
781
+ const set = this.set
782
+
783
+ if (!set.length) {
784
+ this.regexp = false
785
+ return this.regexp
765
786
  }
766
- var hit = this.matchOne(file, pattern, partial)
767
- if (hit) {
768
- if (options.flipNegate) return true
769
- return !this.negate
787
+ const options = this.options
788
+
789
+ const twoStar = options.noglobstar ? star
790
+ : options.dot ? twoStarDot
791
+ : twoStarNoDot
792
+ const flags = options.nocase ? 'i' : ''
793
+
794
+ let re = set.map(pattern =>
795
+ pattern.map(p =>
796
+ (p === GLOBSTAR) ? twoStar
797
+ : (typeof p === 'string') ? regExpEscape(p)
798
+ : p._src
799
+ ).join('\\\/')
800
+ ).join('|')
801
+
802
+ // must match entire pattern
803
+ // ending in a * or ** will make it less strict.
804
+ re = '^(?:' + re + ')$'
805
+
806
+ // can match anything, as long as it's not this.
807
+ if (this.negate) re = '^(?!' + re + ').*$'
808
+
809
+ try {
810
+ this.regexp = new RegExp(re, flags)
811
+ } catch (ex) /* istanbul ignore next - should be impossible */ {
812
+ this.regexp = false
770
813
  }
814
+ return this.regexp
771
815
  }
772
816
 
773
- // didn't get any hits. this is success if it's a negative
774
- // pattern, failure otherwise.
775
- if (options.flipNegate) return false
776
- return this.negate
777
- }
817
+ match (f, partial = this.partial) {
818
+ this.debug('match', f, this.pattern)
819
+ // short-circuit in the case of busted things.
820
+ // comments, etc.
821
+ if (this.comment) return false
822
+ if (this.empty) return f === ''
778
823
 
779
- // set partial to true to test if, for example,
780
- // "/a/b" matches the start of "/*/b/*/d"
781
- // Partial means, if you run out of file before you run
782
- // out of pattern, then that's fine, as long as all
783
- // the parts match.
784
- Minimatch.prototype.matchOne = function (file, pattern, partial) {
785
- var options = this.options
786
-
787
- this.debug('matchOne',
788
- { 'this': this, file: file, pattern: pattern })
789
-
790
- this.debug('matchOne', file.length, pattern.length)
791
-
792
- for (var fi = 0,
793
- pi = 0,
794
- fl = file.length,
795
- pl = pattern.length
796
- ; (fi < fl) && (pi < pl)
797
- ; fi++, pi++) {
798
- this.debug('matchOne loop')
799
- var p = pattern[pi]
800
- var f = file[fi]
801
-
802
- this.debug(pattern, p, f)
803
-
804
- // should be impossible.
805
- // some invalid regexp stuff in the set.
806
- /* istanbul ignore if */
807
- if (p === false) return false
808
-
809
- if (p === GLOBSTAR) {
810
- this.debug('GLOBSTAR', [pattern, p, f])
811
-
812
- // "**"
813
- // a/**/b/**/c would match the following:
814
- // a/b/x/y/z/c
815
- // a/x/y/z/b/c
816
- // a/b/x/b/x/c
817
- // a/b/c
818
- // To do this, take the rest of the pattern after
819
- // the **, and see if it would match the file remainder.
820
- // If so, return success.
821
- // If not, the ** "swallows" a segment, and try again.
822
- // This is recursively awful.
823
- //
824
- // a/**/b/**/c matching a/b/x/y/z/c
825
- // - a matches a
826
- // - doublestar
827
- // - matchOne(b/x/y/z/c, b/**/c)
828
- // - b matches b
829
- // - doublestar
830
- // - matchOne(x/y/z/c, c) -> no
831
- // - matchOne(y/z/c, c) -> no
832
- // - matchOne(z/c, c) -> no
833
- // - matchOne(c, c) yes, hit
834
- var fr = fi
835
- var pr = pi + 1
836
- if (pr === pl) {
837
- this.debug('** at the end')
838
- // a ** at the end will just swallow the rest.
839
- // We have found a match.
840
- // however, it will not swallow /.x, unless
841
- // options.dot is set.
842
- // . and .. are *never* matched by **, for explosively
843
- // exponential reasons.
844
- for (; fi < fl; fi++) {
845
- if (file[fi] === '.' || file[fi] === '..' ||
846
- (!options.dot && file[fi].charAt(0) === '.')) return false
847
- }
848
- return true
849
- }
824
+ if (f === '/' && partial) return true
850
825
 
851
- // ok, let's see if we can swallow whatever we can.
852
- while (fr < fl) {
853
- var swallowee = file[fr]
826
+ const options = this.options
854
827
 
855
- this.debug('\nglobstar while', file, fr, pattern, pr, swallowee)
828
+ // windows: need to use /, not \
829
+ if (path.sep !== '/') {
830
+ f = f.split(path.sep).join('/')
831
+ }
856
832
 
857
- // XXX remove this slice. Just pass the start index.
858
- if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
859
- this.debug('globstar found match!', fr, fl, swallowee)
860
- // found a match.
861
- return true
862
- } else {
863
- // can't swallow "." or ".." ever.
864
- // can only swallow ".foo" when explicitly asked.
865
- if (swallowee === '.' || swallowee === '..' ||
866
- (!options.dot && swallowee.charAt(0) === '.')) {
867
- this.debug('dot detected!', file, fr, pattern, pr)
868
- break
869
- }
833
+ // treat the test path as a set of pathparts.
834
+ f = f.split(slashSplit)
835
+ this.debug(this.pattern, 'split', f)
870
836
 
871
- // ** swallows a segment, and continue.
872
- this.debug('globstar swallow a segment, and continue')
873
- fr++
874
- }
875
- }
837
+ // just ONE of the pattern sets in this.set needs to match
838
+ // in order for it to be valid. If negating, then just one
839
+ // match means that we have failed.
840
+ // Either way, return on the first hit.
876
841
 
877
- // no match was found.
878
- // However, in partial mode, we can't say this is necessarily over.
879
- // If there's more *pattern* left, then
880
- /* istanbul ignore if */
881
- if (partial) {
882
- // ran out of file
883
- this.debug('\n>>> no match, partial?', file, fr, pattern, pr)
884
- if (fr === fl) return true
885
- }
886
- return false
842
+ const set = this.set
843
+ this.debug(this.pattern, 'set', set)
844
+
845
+ // Find the basename of the path by looking for the last non-empty segment
846
+ let filename
847
+ for (let i = f.length - 1; i >= 0; i--) {
848
+ filename = f[i]
849
+ if (filename) break
887
850
  }
888
851
 
889
- // something other than **
890
- // non-magic patterns just have to match exactly
891
- // patterns with magic have been turned into regexps.
892
- var hit
893
- if (typeof p === 'string') {
894
- if (options.nocase) {
895
- hit = f.toLowerCase() === p.toLowerCase()
896
- } else {
897
- hit = f === p
852
+ for (let i = 0; i < set.length; i++) {
853
+ const pattern = set[i]
854
+ let file = f
855
+ if (options.matchBase && pattern.length === 1) {
856
+ file = [filename]
857
+ }
858
+ const hit = this.matchOne(file, pattern, partial)
859
+ if (hit) {
860
+ if (options.flipNegate) return true
861
+ return !this.negate
898
862
  }
899
- this.debug('string match', p, f, hit)
900
- } else {
901
- hit = f.match(p)
902
- this.debug('pattern match', p, f, hit)
903
863
  }
904
864
 
905
- if (!hit) return false
865
+ // didn't get any hits. this is success if it's a negative
866
+ // pattern, failure otherwise.
867
+ if (options.flipNegate) return false
868
+ return this.negate
906
869
  }
907
870
 
908
- // Note: ending in / means that we'll get a final ""
909
- // at the end of the pattern. This can only match a
910
- // corresponding "" at the end of the file.
911
- // If the file ends in /, then it can only match a
912
- // a pattern that ends in /, unless the pattern just
913
- // doesn't have any more for it. But, a/b/ should *not*
914
- // match "a/b/*", even though "" matches against the
915
- // [^/]*? pattern, except in partial mode, where it might
916
- // simply not be reached yet.
917
- // However, a/b/ should still satisfy a/*
918
-
919
- // now either we fell off the end of the pattern, or we're done.
920
- if (fi === fl && pi === pl) {
921
- // ran out of pattern and filename at the same time.
922
- // an exact hit!
923
- return true
924
- } else if (fi === fl) {
925
- // ran out of file, but still had pattern left.
926
- // this is ok if we're doing the match as part of
927
- // a glob fs traversal.
928
- return partial
929
- } else /* istanbul ignore else */ if (pi === pl) {
930
- // ran out of pattern, still have file left.
931
- // this is only acceptable if we're on the very last
932
- // empty segment of a file with a trailing slash.
933
- // a/* should match a/b/
934
- return (fi === fl - 1) && (file[fi] === '')
871
+ static defaults (def) {
872
+ return minimatch.defaults(def).Minimatch
935
873
  }
936
-
937
- // should be unreachable.
938
- /* istanbul ignore next */
939
- throw new Error('wtf?')
940
874
  }
941
875
 
942
- // replace stuff like \* with *
943
- function globUnescape (s) {
944
- return s.replace(/\\(.)/g, '$1')
945
- }
946
-
947
- function regExpEscape (s) {
948
- return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
949
- }
876
+ minimatch.Minimatch = Minimatch