CoolFace
Apppublic

opusdev/vector-similarity-api

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes
minimatch.js948 linesDownload Raw Back to minimatch
1module.exports = minimatch2minimatch.Minimatch = Minimatch3 4var path = (function () { try { return require('path') } catch (e) {}}()) || {5  sep: '/'6}7minimatch.sep = path.sep8 9var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}10var expand = require('brace-expansion')11 12var 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()22var qmark = '[^/]'23 24// * => any number of characters25var 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.30var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?'31 32// not a ^ or / followed by a dot,33// followed by anything, any number of times.34var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?'35 36// characters that need to be escaped in RegExp.37var reSpecials = charSet('().*{}+?[]^$\\!')38 39// "abc" -> { a:true, b:true, c:true }40function charSet (s) {41  return s.split('').reduce(function (set, c) {42    set[c] = true43    return set44  }, {})45}46 47// normalizes slashes.48var slashSplit = /\/+/49 50minimatch.filter = filter51function filter (pattern, options) {52  options = options || {}53  return function (p, i, list) {54    return minimatch(p, pattern, options)55  }56}57 58function ext (a, b) {59  b = b || {}60  var t = {}61  Object.keys(a).forEach(function (k) {62    t[k] = a[k]63  })64  Object.keys(b).forEach(function (k) {65    t[k] = b[k]66  })67  return t68}69 70minimatch.defaults = function (def) {71  if (!def || typeof def !== 'object' || !Object.keys(def).length) {72    return minimatch73  }74 75  var orig = minimatch76 77  var m = function minimatch (p, pattern, options) {78    return orig(p, pattern, ext(def, options))79  }80 81  m.Minimatch = function Minimatch (pattern, options) {82    return new orig.Minimatch(pattern, ext(def, options))83  }84  m.Minimatch.defaults = function defaults (options) {85    return orig.defaults(ext(def, options)).Minimatch86  }87 88  m.filter = function filter (pattern, options) {89    return orig.filter(pattern, ext(def, options))90  }91 92  m.defaults = function defaults (options) {93    return orig.defaults(ext(def, options))94  }95 96  m.makeRe = function makeRe (pattern, options) {97    return orig.makeRe(pattern, ext(def, options))98  }99 100  m.braceExpand = function braceExpand (pattern, options) {101    return orig.braceExpand(pattern, ext(def, options))102  }103 104  m.match = function (list, pattern, options) {105    return orig.match(list, pattern, ext(def, options))106  }107 108  return m109}110 111Minimatch.defaults = function (def) {112  return minimatch.defaults(def).Minimatch113}114 115function minimatch (p, pattern, options) {116  assertValidPattern(pattern)117 118  if (!options) options = {}119 120  // shortcut: comments match nothing.121  if (!options.nocomment && pattern.charAt(0) === '#') {122    return false123  }124 125  return new Minimatch(pattern, options).match(p)126}127 128function Minimatch (pattern, options) {129  if (!(this instanceof Minimatch)) {130    return new Minimatch(pattern, options)131  }132 133  assertValidPattern(pattern)134 135  if (!options) options = {}136 137  pattern = pattern.trim()138 139  // windows support: need to use /, not \140  if (!options.allowWindowsEscape && path.sep !== '/') {141    pattern = pattern.split(path.sep).join('/')142  }143 144  this.options = options145  this.set = []146  this.pattern = pattern147  this.regexp = null148  this.negate = false149  this.comment = false150  this.empty = false151  this.partial = !!options.partial152 153  // make the set of regexps etc.154  this.make()155}156 157Minimatch.prototype.debug = function () {}158 159Minimatch.prototype.make = make160function make () {161  var pattern = this.pattern162  var options = this.options163 164  // empty patterns and comments match nothing.165  if (!options.nocomment && pattern.charAt(0) === '#') {166    this.comment = true167    return168  }169  if (!pattern) {170    this.empty = true171    return172  }173 174  // step 1: figure out negation, etc.175  this.parseNegate()176 177  // step 2: expand braces178  var set = this.globSet = this.braceExpand()179 180  if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) }181 182  this.debug(this.pattern, set)183 184  // step 3: now we have a set, so turn each one into a series of path-portion185  // matching patterns.186  // These will be regexps, except in the case of "**", which is187  // set to the GLOBSTAR object for globstar behavior,188  // and will not contain any / characters189  set = this.globParts = set.map(function (s) {190    return s.split(slashSplit)191  })192 193  this.debug(this.pattern, set)194 195  // glob --> regexps196  set = set.map(function (s, si, set) {197    return s.map(this.parse, this)198  }, this)199 200  this.debug(this.pattern, set)201 202  // filter out everything that didn't compile properly.203  set = set.filter(function (s) {204    return s.indexOf(false) === -1205  })206 207  this.debug(this.pattern, set)208 209  this.set = set210}211 212Minimatch.prototype.parseNegate = parseNegate213function parseNegate () {214  var pattern = this.pattern215  var negate = false216  var options = this.options217  var negateOffset = 0218 219  if (options.nonegate) return220 221  for (var i = 0, l = pattern.length222    ; i < l && pattern.charAt(i) === '!'223    ; i++) {224    negate = !negate225    negateOffset++226  }227 228  if (negateOffset) this.pattern = pattern.substr(negateOffset)229  this.negate = negate230}231 232// Brace expansion:233// a{b,c}d -> abd acd234// a{b,}c -> abc ac235// a{0..3}d -> a0d a1d a2d a3d236// a{b,c{d,e}f}g -> abg acdfg acefg237// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg238//239// Invalid sets are not expanded.240// a{2..}b -> a{2..}b241// a{b}c -> a{b}c242minimatch.braceExpand = function (pattern, options) {243  return braceExpand(pattern, options)244}245 246Minimatch.prototype.braceExpand = braceExpand247 248function braceExpand (pattern, options) {249  if (!options) {250    if (this instanceof Minimatch) {251      options = this.options252    } else {253      options = {}254    }255  }256 257  pattern = typeof pattern === 'undefined'258    ? this.pattern : pattern259 260  assertValidPattern(pattern)261 262  // Thanks to Yeting Li <https://github.com/yetingli> for263  // improving this regexp to avoid a ReDOS vulnerability.264  if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {265    // shortcut. no need to expand.266    return [pattern]267  }268 269  return expand(pattern)270}271 272var MAX_PATTERN_LENGTH = 1024 * 64273var assertValidPattern = function (pattern) {274  if (typeof pattern !== 'string') {275    throw new TypeError('invalid pattern')276  }277 278  if (pattern.length > MAX_PATTERN_LENGTH) {279    throw new TypeError('pattern is too long')280  }281}282 283// parse a component of the expanded set.284// At this point, no pattern may contain "/" in it285// so we're going to return a 2d array, where each entry is the full286// pattern, split on '/', and then turned into a regular expression.287// A regexp is made at the end which joins each array with an288// escaped /, and another full one which joins each regexp with |.289//290// Following the lead of Bash 4.1, note that "**" only has special meaning291// when it is the *only* thing in a path portion.  Otherwise, any series292// of * is equivalent to a single *.  Globstar behavior is enabled by293// default, and can be disabled by setting options.noglobstar.294Minimatch.prototype.parse = parse295var SUBPARSE = {}296function parse (pattern, isSub) {297  assertValidPattern(pattern)298 299  var options = this.options300 301  // shortcuts302  if (pattern === '**') {303    if (!options.noglobstar)304      return GLOBSTAR305    else306      pattern = '*'307  }308  if (pattern === '') return ''309 310  var re = ''311  var hasMagic = !!options.nocase312  var escaping = false313  // ? => one single character314  var patternListStack = []315  var negativeLists = []316  var stateChar317  var inClass = false318  var reClassStart = -1319  var classStart = -1320  // . and .. never match anything that doesn't start with .,321  // even when options.dot is set.322  var patternStart = pattern.charAt(0) === '.' ? '' // anything323  // not (start or / followed by . or .. followed by / or end)324  : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))'325  : '(?!\\.)'326  var self = this327 328  function clearStateChar () {329    if (stateChar) {330      // we had some state-tracking character331      // that wasn't consumed by this pass.332      switch (stateChar) {333        case '*':334          re += star335          hasMagic = true336        break337        case '?':338          re += qmark339          hasMagic = true340        break341        default:342          re += '\\' + stateChar343        break344      }345      self.debug('clearStateChar %j %j', stateChar, re)346      stateChar = false347    }348  }349 350  for (var i = 0, len = pattern.length, c351    ; (i < len) && (c = pattern.charAt(i))352    ; i++) {353    this.debug('%s\t%s %s %j', pattern, i, re, c)354 355    // skip over any that are escaped.356    if (escaping && reSpecials[c]) {357      re += '\\' + c358      escaping = false359      continue360    }361 362    switch (c) {363      /* istanbul ignore next */364      case '/': {365        // completely not allowed, even escaped.366        // Should already be path-split by now.367        return false368      }369 370      case '\\':371        clearStateChar()372        escaping = true373      continue374 375      // the various stateChar values376      // for the "extglob" stuff.377      case '?':378      case '*':379      case '+':380      case '@':381      case '!':382        this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c)383 384        // all of those are literals inside a class, except that385        // the glob [!a] means [^a] in regexp386        if (inClass) {387          this.debug('  in class')388          if (c === '!' && i === classStart + 1) c = '^'389          re += c390          continue391        }392 393        // if we already have a stateChar, then it means394        // that there was something like ** or +? in there.395        // Handle the stateChar, then proceed with this one.396        self.debug('call clearStateChar %j', stateChar)397        clearStateChar()398        stateChar = c399        // if extglob is disabled, then +(asdf|foo) isn't a thing.400        // just clear the statechar *now*, rather than even diving into401        // the patternList stuff.402        if (options.noext) clearStateChar()403      continue404 405      case '(':406        if (inClass) {407          re += '('408          continue409        }410 411        if (!stateChar) {412          re += '\\('413          continue414        }415 416        patternListStack.push({417          type: stateChar,418          start: i - 1,419          reStart: re.length,420          open: plTypes[stateChar].open,421          close: plTypes[stateChar].close422        })423        // negation is (?:(?!js)[^/]*)424        re += stateChar === '!' ? '(?:(?!(?:' : '(?:'425        this.debug('plType %j %j', stateChar, re)426        stateChar = false427      continue428 429      case ')':430        if (inClass || !patternListStack.length) {431          re += '\\)'432          continue433        }434 435        clearStateChar()436        hasMagic = true437        var pl = patternListStack.pop()438        // negation is (?:(?!js)[^/]*)439        // The others are (?:<pattern>)<type>440        re += pl.close441        if (pl.type === '!') {442          negativeLists.push(pl)443        }444        pl.reEnd = re.length445      continue446 447      case '|':448        if (inClass || !patternListStack.length || escaping) {449          re += '\\|'450          escaping = false451          continue452        }453 454        clearStateChar()455        re += '|'456      continue457 458      // these are mostly the same in regexp and glob459      case '[':460        // swallow any state-tracking char before the [461        clearStateChar()462 463        if (inClass) {464          re += '\\' + c465          continue466        }467 468        inClass = true469        classStart = i470        reClassStart = re.length471        re += c472      continue473 474      case ']':475        //  a right bracket shall lose its special476        //  meaning and represent itself in477        //  a bracket expression if it occurs478        //  first in the list.  -- POSIX.2 2.8.3.2479        if (i === classStart + 1 || !inClass) {480          re += '\\' + c481          escaping = false482          continue483        }484 485        // handle the case where we left a class open.486        // "[z-a]" is valid, equivalent to "\[z-a\]"487        // split where the last [ was, make sure we don't have488        // an invalid re. if so, re-walk the contents of the489        // would-be class to re-translate any characters that490        // were passed through as-is491        // TODO: It would probably be faster to determine this492        // without a try/catch and a new RegExp, but it's tricky493        // to do safely.  For now, this is safe and works.494        var cs = pattern.substring(classStart + 1, i)495        try {496          RegExp('[' + cs + ']')497        } catch (er) {498          // not a valid class!499          var sp = this.parse(cs, SUBPARSE)500          re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'501          hasMagic = hasMagic || sp[1]502          inClass = false503          continue504        }505 506        // finish up the class.507        hasMagic = true508        inClass = false509        re += c510      continue511 512      default:513        // swallow any state char that wasn't consumed514        clearStateChar()515 516        if (escaping) {517          // no need518          escaping = false519        } else if (reSpecials[c]520          && !(c === '^' && inClass)) {521          re += '\\'522        }523 524        re += c525 526    } // switch527  } // for528 529  // handle the case where we left a class open.530  // "[abc" is valid, equivalent to "\[abc"531  if (inClass) {532    // split where the last [ was, and escape it533    // this is a huge pita.  We now have to re-walk534    // the contents of the would-be class to re-translate535    // any characters that were passed through as-is536    cs = pattern.substr(classStart + 1)537    sp = this.parse(cs, SUBPARSE)538    re = re.substr(0, reClassStart) + '\\[' + sp[0]539    hasMagic = hasMagic || sp[1]540  }541 542  // handle the case where we had a +( thing at the *end*543  // of the pattern.544  // each pattern list stack adds 3 chars, and we need to go through545  // and escape any | chars that were passed through as-is for the regexp.546  // Go through and escape them, taking care not to double-escape any547  // | chars that were already escaped.548  for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {549    var tail = re.slice(pl.reStart + pl.open.length)550    this.debug('setting tail', re, pl)551    // maybe some even number of \, then maybe 1 \, followed by a |552    tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) {553      if (!$2) {554        // the | isn't already escaped, so escape it.555        $2 = '\\'556      }557 558      // need to escape all those slashes *again*, without escaping the559      // one that we need for escaping the | character.  As it works out,560      // escaping an even number of slashes can be done by simply repeating561      // it exactly after itself.  That's why this trick works.562      //563      // I am sorry that you have to see this.564      return $1 + $1 + $2 + '|'565    })566 567    this.debug('tail=%j\n   %s', tail, tail, pl, re)568    var t = pl.type === '*' ? star569      : pl.type === '?' ? qmark570      : '\\' + pl.type571 572    hasMagic = true573    re = re.slice(0, pl.reStart) + t + '\\(' + tail574  }575 576  // handle trailing things that only matter at the very end.577  clearStateChar()578  if (escaping) {579    // trailing \\580    re += '\\\\'581  }582 583  // only need to apply the nodot start if the re starts with584  // something that could conceivably capture a dot585  var addPatternStart = false586  switch (re.charAt(0)) {587    case '[': case '.': case '(': addPatternStart = true588  }589 590  // Hack to work around lack of negative lookbehind in JS591  // A pattern like: *.!(x).!(y|z) needs to ensure that a name592  // like 'a.xyz.yz' doesn't match.  So, the first negative593  // lookahead, has to look ALL the way ahead, to the end of594  // the pattern.595  for (var n = negativeLists.length - 1; n > -1; n--) {596    var nl = negativeLists[n]597 598    var nlBefore = re.slice(0, nl.reStart)599    var nlFirst = re.slice(nl.reStart, nl.reEnd - 8)600    var nlLast = re.slice(nl.reEnd - 8, nl.reEnd)601    var nlAfter = re.slice(nl.reEnd)602 603    nlLast += nlAfter604 605    // Handle nested stuff like *(*.js|!(*.json)), where open parens606    // mean that we should *not* include the ) in the bit that is considered607    // "after" the negated section.608    var openParensBefore = nlBefore.split('(').length - 1609    var cleanAfter = nlAfter610    for (i = 0; i < openParensBefore; i++) {611      cleanAfter = cleanAfter.replace(/\)[+*?]?/, '')612    }613    nlAfter = cleanAfter614 615    var dollar = ''616    if (nlAfter === '' && isSub !== SUBPARSE) {617      dollar = '$'618    }619    var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast620    re = newRe621  }622 623  // if the re is not "" at this point, then we need to make sure624  // it doesn't match against an empty path part.625  // Otherwise a/* will match a/, which it should not.626  if (re !== '' && hasMagic) {627    re = '(?=.)' + re628  }629 630  if (addPatternStart) {631    re = patternStart + re632  }633 634  // parsing just a piece of a larger pattern.635  if (isSub === SUBPARSE) {636    return [re, hasMagic]637  }638 639  // skip the regexp for non-magical patterns640  // unescape anything in it, though, so that it'll be641  // an exact match against a file etc.642  if (!hasMagic) {643    return globUnescape(pattern)644  }645 646  var flags = options.nocase ? 'i' : ''647  try {648    var regExp = new RegExp('^' + re + '$', flags)649  } catch (er) /* istanbul ignore next - should be impossible */ {650    // If it was an invalid regular expression, then it can't match651    // anything.  This trick looks for a character after the end of652    // the string, which is of course impossible, except in multi-line653    // mode, but it's not a /m regex.654    return new RegExp('$.')655  }656 657  regExp._glob = pattern658  regExp._src = re659 660  return regExp661}662 663minimatch.makeRe = function (pattern, options) {664  return new Minimatch(pattern, options || {}).makeRe()665}666 667Minimatch.prototype.makeRe = makeRe668function makeRe () {669  if (this.regexp || this.regexp === false) return this.regexp670 671  // at this point, this.set is a 2d array of partial672  // pattern strings, or "**".673  //674  // It's better to use .match().  This function shouldn't675  // be used, really, but it's pretty convenient sometimes,676  // when you just want to work with a regex.677  var set = this.set678 679  if (!set.length) {680    this.regexp = false681    return this.regexp682  }683  var options = this.options684 685  var twoStar = options.noglobstar ? star686    : options.dot ? twoStarDot687    : twoStarNoDot688  var flags = options.nocase ? 'i' : ''689 690  var re = set.map(function (pattern) {691    return pattern.map(function (p) {692      return (p === GLOBSTAR) ? twoStar693      : (typeof p === 'string') ? regExpEscape(p)694      : p._src695    }).join('\\\/')696  }).join('|')697 698  // must match entire pattern699  // ending in a * or ** will make it less strict.700  re = '^(?:' + re + ')$'701 702  // can match anything, as long as it's not this.703  if (this.negate) re = '^(?!' + re + ').*$'704 705  try {706    this.regexp = new RegExp(re, flags)707  } catch (ex) /* istanbul ignore next - should be impossible */ {708    this.regexp = false709  }710  return this.regexp711}712 713minimatch.match = function (list, pattern, options) {714  options = options || {}715  var mm = new Minimatch(pattern, options)716  list = list.filter(function (f) {717    return mm.match(f)718  })719  if (mm.options.nonull && !list.length) {720    list.push(pattern)721  }722  return list723}724 725Minimatch.prototype.match = function match (f, partial) {726  if (typeof partial === 'undefined') partial = this.partial727  this.debug('match', f, this.pattern)728  // short-circuit in the case of busted things.729  // comments, etc.730  if (this.comment) return false731  if (this.empty) return f === ''732 733  if (f === '/' && partial) return true734 735  var options = this.options736 737  // windows: need to use /, not \738  if (path.sep !== '/') {739    f = f.split(path.sep).join('/')740  }741 742  // treat the test path as a set of pathparts.743  f = f.split(slashSplit)744  this.debug(this.pattern, 'split', f)745 746  // just ONE of the pattern sets in this.set needs to match747  // in order for it to be valid.  If negating, then just one748  // match means that we have failed.749  // Either way, return on the first hit.750 751  var set = this.set752  this.debug(this.pattern, 'set', set)753 754  // Find the basename of the path by looking for the last non-empty segment755  var filename756  var i757  for (i = f.length - 1; i >= 0; i--) {758    filename = f[i]759    if (filename) break760  }761 762  for (i = 0; i < set.length; i++) {763    var pattern = set[i]764    var file = f765    if (options.matchBase && pattern.length === 1) {766      file = [filename]767    }768    var hit = this.matchOne(file, pattern, partial)769    if (hit) {770      if (options.flipNegate) return true771      return !this.negate772    }773  }774 775  // didn't get any hits.  this is success if it's a negative776  // pattern, failure otherwise.777  if (options.flipNegate) return false778  return this.negate779}780 781// set partial to true to test if, for example,782// "/a/b" matches the start of "/*/b/*/d"783// Partial means, if you run out of file before you run784// out of pattern, then that's fine, as long as all785// the parts match.786Minimatch.prototype.matchOne = function (file, pattern, partial) {787  var options = this.options788 789  this.debug('matchOne',790    { 'this': this, file: file, pattern: pattern })791 792  this.debug('matchOne', file.length, pattern.length)793 794  for (var fi = 0,795      pi = 0,796      fl = file.length,797      pl = pattern.length798      ; (fi < fl) && (pi < pl)799      ; fi++, pi++) {800    this.debug('matchOne loop')801    var p = pattern[pi]802    var f = file[fi]803 804    this.debug(pattern, p, f)805 806    // should be impossible.807    // some invalid regexp stuff in the set.808    /* istanbul ignore if */809    if (p === false) return false810 811    if (p === GLOBSTAR) {812      this.debug('GLOBSTAR', [pattern, p, f])813 814      // "**"815      // a/**/b/**/c would match the following:816      // a/b/x/y/z/c817      // a/x/y/z/b/c818      // a/b/x/b/x/c819      // a/b/c820      // To do this, take the rest of the pattern after821      // the **, and see if it would match the file remainder.822      // If so, return success.823      // If not, the ** "swallows" a segment, and try again.824      // This is recursively awful.825      //826      // a/**/b/**/c matching a/b/x/y/z/c827      // - a matches a828      // - doublestar829      //   - matchOne(b/x/y/z/c, b/**/c)830      //     - b matches b831      //     - doublestar832      //       - matchOne(x/y/z/c, c) -> no833      //       - matchOne(y/z/c, c) -> no834      //       - matchOne(z/c, c) -> no835      //       - matchOne(c, c) yes, hit836      var fr = fi837      var pr = pi + 1838      if (pr === pl) {839        this.debug('** at the end')840        // a ** at the end will just swallow the rest.841        // We have found a match.842        // however, it will not swallow /.x, unless843        // options.dot is set.844        // . and .. are *never* matched by **, for explosively845        // exponential reasons.846        for (; fi < fl; fi++) {847          if (file[fi] === '.' || file[fi] === '..' ||848            (!options.dot && file[fi].charAt(0) === '.')) return false849        }850        return true851      }852 853      // ok, let's see if we can swallow whatever we can.854      while (fr < fl) {855        var swallowee = file[fr]856 857        this.debug('\nglobstar while', file, fr, pattern, pr, swallowee)858 859        // XXX remove this slice.  Just pass the start index.860        if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {861          this.debug('globstar found match!', fr, fl, swallowee)862          // found a match.863          return true864        } else {865          // can't swallow "." or ".." ever.866          // can only swallow ".foo" when explicitly asked.867          if (swallowee === '.' || swallowee === '..' ||868            (!options.dot && swallowee.charAt(0) === '.')) {869            this.debug('dot detected!', file, fr, pattern, pr)870            break871          }872 873          // ** swallows a segment, and continue.874          this.debug('globstar swallow a segment, and continue')875          fr++876        }877      }878 879      // no match was found.880      // However, in partial mode, we can't say this is necessarily over.881      // If there's more *pattern* left, then882      /* istanbul ignore if */883      if (partial) {884        // ran out of file885        this.debug('\n>>> no match, partial?', file, fr, pattern, pr)886        if (fr === fl) return true887      }888      return false889    }890 891    // something other than **892    // non-magic patterns just have to match exactly893    // patterns with magic have been turned into regexps.894    var hit895    if (typeof p === 'string') {896      hit = f === p897      this.debug('string match', p, f, hit)898    } else {899      hit = f.match(p)900      this.debug('pattern match', p, f, hit)901    }902 903    if (!hit) return false904  }905 906  // Note: ending in / means that we'll get a final ""907  // at the end of the pattern.  This can only match a908  // corresponding "" at the end of the file.909  // If the file ends in /, then it can only match a910  // a pattern that ends in /, unless the pattern just911  // doesn't have any more for it. But, a/b/ should *not*912  // match "a/b/*", even though "" matches against the913  // [^/]*? pattern, except in partial mode, where it might914  // simply not be reached yet.915  // However, a/b/ should still satisfy a/*916 917  // now either we fell off the end of the pattern, or we're done.918  if (fi === fl && pi === pl) {919    // ran out of pattern and filename at the same time.920    // an exact hit!921    return true922  } else if (fi === fl) {923    // ran out of file, but still had pattern left.924    // this is ok if we're doing the match as part of925    // a glob fs traversal.926    return partial927  } else /* istanbul ignore else */ if (pi === pl) {928    // ran out of pattern, still have file left.929    // this is only acceptable if we're on the very last930    // empty segment of a file with a trailing slash.931    // a/* should match a/b/932    return (fi === fl - 1) && (file[fi] === '')933  }934 935  // should be unreachable.936  /* istanbul ignore next */937  throw new Error('wtf?')938}939 940// replace stuff like \* with *941function globUnescape (s) {942  return s.replace(/\\(.)/g, '$1')943}944 945function regExpEscape (s) {946  return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')947}948