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