Passed
Push — main ( 10dbfc...61a674 )
by LCS
05:39 queued 03:09
created

node_modules/minimatch/minimatch.js   F

Complexity

Total Complexity 140
Complexity/F 3.26

Size

Lines of Code 947
Function Count 43

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 471
dl 0
loc 947
rs 2
c 0
b 0
f 0
wmc 140
mnd 97
bc 97
fnc 43
bpm 2.2557
cpm 3.2557
noi 32

How to fix   Complexity   

Complexity

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