"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/fstream-ignore/node_modules/minimatch/minimatch.js" (8 Mar 2017, 24864 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

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