minimatch.js ➔ match   F
last analyzed

Complexity

Conditions 14
Paths 63

Size

Total Lines 54
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 28
nc 63
nop 2
dl 0
loc 54
rs 3.6
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like minimatch.js ➔ match often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
module.exports = minimatch
2
minimatch.Minimatch = Minimatch
3
4
var path = { sep: '/' }
5
try {
6
  path = require('path')
7
} catch (er) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
8
9
var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
10
var expand = require('brace-expansion')
11
12
var plTypes = {
13
  '!': { open: '(?:(?!(?:', close: '))[^/]*?)'},
14
  '?': { open: '(?:', close: ')?' },
15
  '+': { open: '(?:', close: ')+' },
16
  '*': { open: '(?:', close: ')*' },
17
  '@': { open: '(?:', close: ')' }
18
}
19
20
// any single thing other than /
21
// don't need to escape / when using new RegExp()
22
var qmark = '[^/]'
23
24
// * => any number of characters
25
var star = qmark + '*?'
26
27
// ** when dots are allowed.  Anything goes, except .. and .
28
// not (^ or / followed by one or two dots followed by $ or /),
29
// followed by anything, any number of times.
30
var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?'
31
32
// not a ^ or / followed by a dot,
33
// followed by anything, any number of times.
34
var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?'
35
36
// characters that need to be escaped in RegExp.
37
var reSpecials = charSet('().*{}+?[]^$\\!')
38
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
}
46
47
// normalizes slashes.
48
var slashSplit = /\/+/
49
50
minimatch.filter = filter
51
function filter (pattern, options) {
52
  options = options || {}
53
  return function (p, i, list) {
0 ignored issues
show
Unused Code introduced by
The parameter i is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter list is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
54
    return minimatch(p, pattern, options)
55
  }
56
}
57
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
  })
68
  return t
69
}
70
71
minimatch.defaults = function (def) {
72
  if (!def || !Object.keys(def).length) return minimatch
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
73
74
  var orig = minimatch
75
76
  var m = function minimatch (p, pattern, options) {
77
    return orig.minimatch(p, pattern, ext(def, options))
78
  }
79
80
  m.Minimatch = function Minimatch (pattern, options) {
81
    return new orig.Minimatch(pattern, ext(def, options))
82
  }
83
84
  return m
85
}
86
87
Minimatch.defaults = function (def) {
88
  if (!def || !Object.keys(def).length) return Minimatch
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
89
  return minimatch.defaults(def).Minimatch
90
}
91
92
function minimatch (p, pattern, options) {
93
  if (typeof pattern !== 'string') {
94
    throw new TypeError('glob pattern string required')
95
  }
96
97
  if (!options) options = {}
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
98
99
  // shortcut: comments match nothing.
100
  if (!options.nocomment && pattern.charAt(0) === '#') {
101
    return false
102
  }
103
104
  // "" only matches ""
105
  if (pattern.trim() === '') return p === ''
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
106
107
  return new Minimatch(pattern, options).match(p)
108
}
109
110
function Minimatch (pattern, options) {
111
  if (!(this instanceof Minimatch)) {
112
    return new Minimatch(pattern, options)
113
  }
114
115
  if (typeof pattern !== 'string') {
116
    throw new TypeError('glob pattern string required')
117
  }
118
119
  if (!options) options = {}
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
120
  pattern = pattern.trim()
121
122
  // windows support: need to use /, not \
123
  if (path.sep !== '/') {
124
    pattern = pattern.split(path.sep).join('/')
125
  }
126
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
134
135
  // make the set of regexps etc.
136
  this.make()
137
}
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
138
139
Minimatch.prototype.debug = function () {}
140
141
Minimatch.prototype.make = make
142
function make () {
143
  // don't do it more than once.
144
  if (this._made) return
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
145
146
  var pattern = this.pattern
147
  var options = this.options
148
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
157
  }
158
159
  // step 1: figure out negation, etc.
160
  this.parseNegate()
161
162
  // step 2: expand braces
163
  var set = this.globSet = this.braceExpand()
164
165
  if (options.debug) this.debug = console.error
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
166
167
  this.debug(this.pattern, set)
168
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
  })
177
178
  this.debug(this.pattern, set)
179
180
  // glob --> regexps
181
  set = set.map(function (s, si, set) {
0 ignored issues
show
Unused Code introduced by
The parameter set is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter si is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
182
    return s.map(this.parse, this)
183
  }, this)
184
185
  this.debug(this.pattern, set)
186
187
  // filter out everything that didn't compile properly.
188
  set = set.filter(function (s) {
189
    return s.indexOf(false) === -1
190
  })
191
192
  this.debug(this.pattern, set)
193
194
  this.set = set
195
}
196
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
203
204
  if (options.nonegate) return
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
205
206
  for (var i = 0, l = pattern.length
207
    ; i < l && pattern.charAt(i) === '!'
208
    ; i++) {
209
    negate = !negate
210
    negateOffset++
211
  }
212
213
  if (negateOffset) this.pattern = pattern.substr(negateOffset)
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
214
  this.negate = negate
215
}
216
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
}
230
231
Minimatch.prototype.braceExpand = braceExpand
232
233
function braceExpand (pattern, options) {
234
  if (!options) {
235
    if (this instanceof Minimatch) {
236
      options = this.options
237
    } else {
238
      options = {}
239
    }
240
  }
241
242
  pattern = typeof pattern === 'undefined'
243
    ? this.pattern : pattern
244
245
  if (typeof pattern === 'undefined') {
246
    throw new TypeError('undefined pattern')
247
  }
248
249
  if (options.nobrace ||
250
    !pattern.match(/\{.*\}/)) {
251
    // shortcut. no need to expand.
252
    return [pattern]
253
  }
254
255
  return expand(pattern)
256
}
257
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
  }
275
276
  var options = this.options
277
278
  // shortcuts
279
  if (!options.noglobstar && pattern === '**') return GLOBSTAR
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
280
  if (pattern === '') return ''
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
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
316
      }
317
      self.debug('clearStateChar %j %j', stateChar, re)
318
      stateChar = false
319
    }
320
  }
321
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)
326
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
339
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 = '^'
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
359
          re += c
360
          continue
361
        }
362
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)
0 ignored issues
show
Bug introduced by
The variable stateChar seems to not be initialized for all possible execution paths. Are you sure debug handles undefined variables?
Loading history...
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()
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
373
      continue
374
375
      case '(':
376
        if (inClass) {
377
          re += '('
378
          continue
379
        }
380
381
        if (!stateChar) {
382
          re += '\\('
383
          continue
384
        }
385
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
398
399
      case ')':
400
        if (inClass || !patternListStack.length) {
401
          re += '\\)'
402
          continue
403
        }
404
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
        }
423
424
        clearStateChar()
425
        re += '|'
426
      continue
427
428
      // these are mostly the same in regexp and glob
429
      case '[':
430
        // swallow any state-tracking char before the [
431
        clearStateChar()
432
433
        if (inClass) {
434
          re += '\\' + c
435
          continue
436
        }
437
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
        }
454
455
        // handle the case where we left a class open.
456
        // "[z-a]" is valid, equivalent to "\[z-a\]"
457
        if (inClass) {
458
          // split where the last [ was, make sure we don't have
459
          // an invalid re. if so, re-walk the contents of the
460
          // would-be class to re-translate any characters that
461
          // were passed through as-is
462
          // TODO: It would probably be faster to determine this
463
          // without a try/catch and a new RegExp, but it's tricky
464
          // to do safely.  For now, this is safe and works.
465
          var cs = pattern.substring(classStart + 1, i)
466
          try {
467
            RegExp('[' + cs + ']')
468
          } catch (er) {
469
            // not a valid class!
470
            var sp = this.parse(cs, SUBPARSE)
471
            re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
472
            hasMagic = hasMagic || sp[1]
473
            inClass = false
474
            continue
475
          }
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
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
  }
513
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
      }
529
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
  }
547
548
  // handle trailing things that only matter at the very end.
549
  clearStateChar()
550
  if (escaping) {
551
    // trailing \\
552
    re += '\\\\'
553
  }
554
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
  }
563
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(/\)[+*?]?/, '')
586
    }
587
    nlAfter = cleanAfter
588
589
    var dollar = ''
590
    if (nlAfter === '' && isSub !== SUBPARSE) {
591
      dollar = '$'
592
    }
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
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
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
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
652
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 + ').*$'
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
678
679
  try {
680
    this.regexp = new RegExp(re, flags)
681
  } catch (ex) {
682
    this.regexp = false
683
  }
684
  return this.regexp
685
}
686
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
}
698
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
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
705
  if (this.empty) return f === ''
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
706
707
  if (f === '/' && partial) return true
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
708
709
  var options = this.options
710
711
  // windows: need to use /, not \
712
  if (path.sep !== '/') {
713
    f = f.split(path.sep).join('/')
714
  }
715
716
  // treat the test path as a set of pathparts.
717
  f = f.split(slashSplit)
718
  this.debug(this.pattern, 'split', f)
719
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.
724
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
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
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]
0 ignored issues
show
Bug introduced by
The variable filename seems to not be initialized for all possible execution paths.
Loading history...
741
    }
742
    var hit = this.matchOne(file, pattern, partial)
743
    if (hit) {
744
      if (options.flipNegate) return true
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
745
      return !this.negate
746
    }
747
  }
748
749
  // didn't get any hits.  this is success if it's a negative
750
  // pattern, failure otherwise.
751
  if (options.flipNegate) return false
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
752
  return this.negate
753
}
754
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
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
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
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
822
        }
823
        return true
824
      }
825
826
      // ok, let's see if we can swallow whatever we can.
827
      while (fr < fl) {
828
        var swallowee = file[fr]
829
830
        this.debug('\nglobstar while', file, fr, pattern, pr, swallowee)
831
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 {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
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
          }
845
846
          // ** swallows a segment, and continue.
847
          this.debug('globstar swallow a segment, and continue')
848
          fr++
849
        }
850
      }
851
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
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
859
      }
860
      return false
861
    }
862
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
872
      }
873
      this.debug('string match', p, f, hit)
874
    } else {
875
      hit = f.match(p)
876
      this.debug('pattern match', p, f, hit)
877
    }
878
879
    if (!hit) return false
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
880
  }
881
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
910
  }
911
912
  // should be unreachable.
913
  throw new Error('wtf?')
914
}
915
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
}
924