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