minimatch 3.1.2 → 5.1.0

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