"Fossies" - the Fresh Open Source Software Archive

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