| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728 | // Approach://// 1. Get the minimatch set// 2. For each pattern in the set, PROCESS(pattern)// 3. Store matches per-set, then uniq them//// PROCESS(pattern)// Get the first [n] items from pattern that are all strings// Join these together.  This is PREFIX.//   If there is no more remaining, then stat(PREFIX) and//   add to matches if it succeeds.  END.// readdir(PREFIX) as ENTRIES//   If fails, END//   If pattern[n] is GLOBSTAR//     // handle the case where the globstar match is empty//     // by pruning it out, and testing the resulting pattern//     PROCESS(pattern[0..n] + pattern[n+1 .. $])//     // handle other cases.//     for ENTRY in ENTRIES (not dotfiles)//       // attach globstar + tail onto the entry//       PROCESS(pattern[0..n] + ENTRY + pattern[n .. $])////   else // not globstar//     for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot)//       Test ENTRY against pattern[n]//       If fails, continue//       If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $])//// Caveat://   Cache all stats and readdirs results to minimize syscall.  Since all//   we ever care about is existence and directory-ness, we can just keep//   `true` for files, and [children,...] for directories, or `false` for//   things that don't exist.module.exports = globvar fs = require("fs"), minimatch = require("minimatch"), Minimatch = minimatch.Minimatch, inherits = require("inherits"), EE = require("events").EventEmitter, path = require("path"), isDir = {}, assert = require("assert").okfunction glob (pattern, options, cb) {  if (typeof options === "function") cb = options, options = {}  if (!options) options = {}  if (typeof options === "number") {    deprecated()    return  }  var g = new Glob(pattern, options, cb)  return g.sync ? g.found : g}glob.fnmatch = deprecatedfunction deprecated () {  throw new Error("glob's interface has changed. Please see the docs.")}glob.sync = globSyncfunction globSync (pattern, options) {  if (typeof options === "number") {    deprecated()    return  }  options = options || {}  options.sync = true  return glob(pattern, options)}this._processingEmitQueue = falseglob.Glob = Globinherits(Glob, EE)function Glob (pattern, options, cb) {  if (!(this instanceof Glob)) {    return new Glob(pattern, options, cb)  }  if (typeof options === "function") {    cb = options    options = null  }  if (typeof cb === "function") {    this.on("error", cb)    this.on("end", function (matches) {      cb(null, matches)    })  }  options = options || {}  this._endEmitted = false  this.EOF = {}  this._emitQueue = []  this.paused = false  this._processingEmitQueue = false  this.maxDepth = options.maxDepth || 1000  this.maxLength = options.maxLength || Infinity  this.cache = options.cache || {}  this.statCache = options.statCache || {}  this.changedCwd = false  var cwd = process.cwd()  if (!options.hasOwnProperty("cwd")) this.cwd = cwd  else {    this.cwd = options.cwd    this.changedCwd = path.resolve(options.cwd) !== cwd  }  this.root = options.root || path.resolve(this.cwd, "/")  this.root = path.resolve(this.root)  if (process.platform === "win32")    this.root = this.root.replace(/\\/g, "/")  this.nomount = !!options.nomount  if (!pattern) {    throw new Error("must provide pattern")  }  // base-matching: just use globstar for that.  if (options.matchBase && -1 === pattern.indexOf("/")) {    if (options.noglobstar) {      throw new Error("base matching requires globstar")    }    pattern = "**/" + pattern  }  this.strict = options.strict !== false  this.dot = !!options.dot  this.mark = !!options.mark  this.sync = !!options.sync  this.nounique = !!options.nounique  this.nonull = !!options.nonull  this.nosort = !!options.nosort  this.nocase = !!options.nocase  this.stat = !!options.stat  this.debug = !!options.debug || !!options.globDebug  if (this.debug)    this.log = console.error  this.silent = !!options.silent  var mm = this.minimatch = new Minimatch(pattern, options)  this.options = mm.options  pattern = this.pattern = mm.pattern  this.error = null  this.aborted = false  // list of all the patterns that ** has resolved do, so  // we can avoid visiting multiple times.  this._globstars = {}  EE.call(this)  // process each pattern in the minimatch set  var n = this.minimatch.set.length  // The matches are stored as {<filename>: true,...} so that  // duplicates are automagically pruned.  // Later, we do an Object.keys() on these.  // Keep them as a list so we can fill in when nonull is set.  this.matches = new Array(n)  this.minimatch.set.forEach(iterator.bind(this))  function iterator (pattern, i, set) {    this._process(pattern, 0, i, function (er) {      if (er) this.emit("error", er)      if (-- n <= 0) this._finish()    })  }}Glob.prototype.log = function () {}Glob.prototype._finish = function () {  assert(this instanceof Glob)  var nou = this.nounique  , all = nou ? [] : {}  for (var i = 0, l = this.matches.length; i < l; i ++) {    var matches = this.matches[i]    this.log("matches[%d] =", i, matches)    // do like the shell, and spit out the literal glob    if (!matches) {      if (this.nonull) {        var literal = this.minimatch.globSet[i]        if (nou) all.push(literal)        else all[literal] = true      }    } else {      // had matches      var m = Object.keys(matches)      if (nou) all.push.apply(all, m)      else m.forEach(function (m) {        all[m] = true      })    }  }  if (!nou) all = Object.keys(all)  if (!this.nosort) {    all = all.sort(this.nocase ? alphasorti : alphasort)  }  if (this.mark) {    // at *some* point we statted all of these    all = all.map(this._mark, this)  }  this.log("emitting end", all)  this.EOF = this.found = all  this.emitMatch(this.EOF)}function alphasorti (a, b) {  a = a.toLowerCase()  b = b.toLowerCase()  return alphasort(a, b)}function alphasort (a, b) {  return a > b ? 1 : a < b ? -1 : 0}Glob.prototype._mark = function (p) {  var c = this.cache[p]  var m = p  if (c) {    var isDir = c === 2 || Array.isArray(c)    var slash = p.slice(-1) === '/'    if (isDir && !slash)      m += '/'    else if (!isDir && slash)      m = m.slice(0, -1)    if (m !== p) {      this.statCache[m] = this.statCache[p]      this.cache[m] = this.cache[p]    }  }  return m}Glob.prototype.abort = function () {  this.aborted = true  this.emit("abort")}Glob.prototype.pause = function () {  if (this.paused) return  if (this.sync)    this.emit("error", new Error("Can't pause/resume sync glob"))  this.paused = true  this.emit("pause")}Glob.prototype.resume = function () {  if (!this.paused) return  if (this.sync)    this.emit("error", new Error("Can't pause/resume sync glob"))  this.paused = false  this.emit("resume")  this._processEmitQueue()  //process.nextTick(this.emit.bind(this, "resume"))}Glob.prototype.emitMatch = function (m) {  this.log('emitMatch', m)  this._emitQueue.push(m)  this._processEmitQueue()}Glob.prototype._processEmitQueue = function (m) {  this.log("pEQ paused=%j processing=%j m=%j", this.paused,           this._processingEmitQueue, m)  var done = false  while (!this._processingEmitQueue &&         !this.paused) {    this._processingEmitQueue = true    var m = this._emitQueue.shift()    this.log(">processEmitQueue", m === this.EOF ? ":EOF:" : m)    if (!m) {      this.log(">processEmitQueue, falsey m")      this._processingEmitQueue = false      break    }    if (m === this.EOF || !(this.mark && !this.stat)) {      this.log("peq: unmarked, or eof")      next.call(this, 0, false)    } else if (this.statCache[m]) {      var sc = this.statCache[m]      var exists      if (sc)        exists = sc.isDirectory() ? 2 : 1      this.log("peq: stat cached")      next.call(this, exists, exists === 2)    } else {      this.log("peq: _stat, then next")      this._stat(m, next)    }    function next(exists, isDir) {      this.log("next", m, exists, isDir)      var ev = m === this.EOF ? "end" : "match"      // "end" can only happen once.      assert(!this._endEmitted)      if (ev === "end")        this._endEmitted = true      if (exists) {        // Doesn't mean it necessarily doesn't exist, it's possible        // we just didn't check because we don't care that much, or        // this is EOF anyway.        if (isDir && !m.match(/\/$/)) {          m = m + "/"        } else if (!isDir && m.match(/\/$/)) {          m = m.replace(/\/+$/, "")        }      }      this.log("emit", ev, m)      this.emit(ev, m)      this._processingEmitQueue = false      if (done && m !== this.EOF && !this.paused)        this._processEmitQueue()    }  }  done = true}Glob.prototype._process = function (pattern, depth, index, cb_) {  assert(this instanceof Glob)  var cb = function cb (er, res) {    assert(this instanceof Glob)    if (this.paused) {      if (!this._processQueue) {        this._processQueue = []        this.once("resume", function () {          var q = this._processQueue          this._processQueue = null          q.forEach(function (cb) { cb() })        })      }      this._processQueue.push(cb_.bind(this, er, res))    } else {      cb_.call(this, er, res)    }  }.bind(this)  if (this.aborted) return cb()  if (depth > this.maxDepth) return cb()  // Get the first [n] parts of pattern that are all strings.  var n = 0  while (typeof pattern[n] === "string") {    n ++  }  // now n is the index of the first one that is *not* a string.  // see if there's anything else  var prefix  switch (n) {    // if not, then this is rather simple    case pattern.length:      prefix = pattern.join("/")      this._stat(prefix, function (exists, isDir) {        // either it's there, or it isn't.        // nothing more to do, either way.        if (exists) {          if (prefix && isAbsolute(prefix) && !this.nomount) {            if (prefix.charAt(0) === "/") {              prefix = path.join(this.root, prefix)            } else {              prefix = path.resolve(this.root, prefix)            }          }          if (process.platform === "win32")            prefix = prefix.replace(/\\/g, "/")          this.matches[index] = this.matches[index] || {}          this.matches[index][prefix] = true          this.emitMatch(prefix)        }        return cb()      })      return    case 0:      // pattern *starts* with some non-trivial item.      // going to readdir(cwd), but not include the prefix in matches.      prefix = null      break    default:      // pattern has some string bits in the front.      // whatever it starts with, whether that's "absolute" like /foo/bar,      // or "relative" like "../baz"      prefix = pattern.slice(0, n)      prefix = prefix.join("/")      break  }  // get the list of entries.  var read  if (prefix === null) read = "."  else if (isAbsolute(prefix) || isAbsolute(pattern.join("/"))) {    if (!prefix || !isAbsolute(prefix)) {      prefix = path.join("/", prefix)    }    read = prefix = path.resolve(prefix)    // if (process.platform === "win32")    //   read = prefix = prefix.replace(/^[a-zA-Z]:|\\/g, "/")    this.log('absolute: ', prefix, this.root, pattern, read)  } else {    read = prefix  }  this.log('readdir(%j)', read, this.cwd, this.root)  return this._readdir(read, function (er, entries) {    if (er) {      // not a directory!      // this means that, whatever else comes after this, it can never match      return cb()    }    // globstar is special    if (pattern[n] === minimatch.GLOBSTAR) {      // test without the globstar, and with every child both below      // and replacing the globstar.      var s = [ pattern.slice(0, n).concat(pattern.slice(n + 1)) ]      entries.forEach(function (e) {        if (e.charAt(0) === "." && !this.dot) return        // instead of the globstar        s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1)))        // below the globstar        s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n)))      }, this)      s = s.filter(function (pattern) {        var key = gsKey(pattern)        var seen = !this._globstars[key]        this._globstars[key] = true        return seen      }, this)      if (!s.length)        return cb()      // now asyncForEach over this      var l = s.length      , errState = null      s.forEach(function (gsPattern) {        this._process(gsPattern, depth + 1, index, function (er) {          if (errState) return          if (er) return cb(errState = er)          if (--l <= 0) return cb()        })      }, this)      return    }    // not a globstar    // It will only match dot entries if it starts with a dot, or if    // dot is set.  Stuff like @(.foo|.bar) isn't allowed.    var pn = pattern[n]    var rawGlob = pattern[n]._glob    , dotOk = this.dot || rawGlob.charAt(0) === "."    entries = entries.filter(function (e) {      return (e.charAt(0) !== "." || dotOk) &&             e.match(pattern[n])    })    // If n === pattern.length - 1, then there's no need for the extra stat    // *unless* the user has specified "mark" or "stat" explicitly.    // We know that they exist, since the readdir returned them.    if (n === pattern.length - 1 &&        !this.mark &&        !this.stat) {      entries.forEach(function (e) {        if (prefix) {          if (prefix !== "/") e = prefix + "/" + e          else e = prefix + e        }        if (e.charAt(0) === "/" && !this.nomount) {          e = path.join(this.root, e)        }        if (process.platform === "win32")          e = e.replace(/\\/g, "/")        this.matches[index] = this.matches[index] || {}        this.matches[index][e] = true        this.emitMatch(e)      }, this)      return cb.call(this)    }    // now test all the remaining entries as stand-ins for that part    // of the pattern.    var l = entries.length    , errState = null    if (l === 0) return cb() // no matches possible    entries.forEach(function (e) {      var p = pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1))      this._process(p, depth + 1, index, function (er) {        if (errState) return        if (er) return cb(errState = er)        if (--l === 0) return cb.call(this)      })    }, this)  })}function gsKey (pattern) {  return '**' + pattern.map(function (p) {    return (p === minimatch.GLOBSTAR) ? '**' : (''+p)  }).join('/')}Glob.prototype._stat = function (f, cb) {  assert(this instanceof Glob)  var abs = f  if (f.charAt(0) === "/") {    abs = path.join(this.root, f)  } else if (this.changedCwd) {    abs = path.resolve(this.cwd, f)  }  if (f.length > this.maxLength) {    var er = new Error("Path name too long")    er.code = "ENAMETOOLONG"    er.path = f    return this._afterStat(f, abs, cb, er)  }  this.log('stat', [this.cwd, f, '=', abs])  if (!this.stat && this.cache.hasOwnProperty(f)) {    var exists = this.cache[f]    , isDir = exists && (Array.isArray(exists) || exists === 2)    if (this.sync) return cb.call(this, !!exists, isDir)    return process.nextTick(cb.bind(this, !!exists, isDir))  }  var stat = this.statCache[abs]  if (this.sync || stat) {    var er    try {      stat = fs.statSync(abs)    } catch (e) {      er = e    }    this._afterStat(f, abs, cb, er, stat)  } else {    fs.stat(abs, this._afterStat.bind(this, f, abs, cb))  }}Glob.prototype._afterStat = function (f, abs, cb, er, stat) {  var exists  assert(this instanceof Glob)  if (abs.slice(-1) === "/" && stat && !stat.isDirectory()) {    this.log("should be ENOTDIR, fake it")    er = new Error("ENOTDIR, not a directory '" + abs + "'")    er.path = abs    er.code = "ENOTDIR"    stat = null  }  var emit = !this.statCache[abs]  this.statCache[abs] = stat  if (er || !stat) {    exists = false  } else {    exists = stat.isDirectory() ? 2 : 1    if (emit)      this.emit('stat', f, stat)  }  this.cache[f] = this.cache[f] || exists  cb.call(this, !!exists, exists === 2)}Glob.prototype._readdir = function (f, cb) {  assert(this instanceof Glob)  var abs = f  if (f.charAt(0) === "/") {    abs = path.join(this.root, f)  } else if (isAbsolute(f)) {    abs = f  } else if (this.changedCwd) {    abs = path.resolve(this.cwd, f)  }  if (f.length > this.maxLength) {    var er = new Error("Path name too long")    er.code = "ENAMETOOLONG"    er.path = f    return this._afterReaddir(f, abs, cb, er)  }  this.log('readdir', [this.cwd, f, abs])  if (this.cache.hasOwnProperty(f)) {    var c = this.cache[f]    if (Array.isArray(c)) {      if (this.sync) return cb.call(this, null, c)      return process.nextTick(cb.bind(this, null, c))    }    if (!c || c === 1) {      // either ENOENT or ENOTDIR      var code = c ? "ENOTDIR" : "ENOENT"      , er = new Error((c ? "Not a directory" : "Not found") + ": " + f)      er.path = f      er.code = code      this.log(f, er)      if (this.sync) return cb.call(this, er)      return process.nextTick(cb.bind(this, er))    }    // at this point, c === 2, meaning it's a dir, but we haven't    // had to read it yet, or c === true, meaning it's *something*    // but we don't have any idea what.  Need to read it, either way.  }  if (this.sync) {    var er, entries    try {      entries = fs.readdirSync(abs)    } catch (e) {      er = e    }    return this._afterReaddir(f, abs, cb, er, entries)  }  fs.readdir(abs, this._afterReaddir.bind(this, f, abs, cb))}Glob.prototype._afterReaddir = function (f, abs, cb, er, entries) {  assert(this instanceof Glob)  if (entries && !er) {    this.cache[f] = entries    // if we haven't asked to stat everything for suresies, then just    // assume that everything in there exists, so we can avoid    // having to stat it a second time.  This also gets us one step    // further into ELOOP territory.    if (!this.mark && !this.stat) {      entries.forEach(function (e) {        if (f === "/") e = f + e        else e = f + "/" + e        this.cache[e] = true      }, this)    }    return cb.call(this, er, entries)  }  // now handle errors, and cache the information  if (er) switch (er.code) {    case "ENOTDIR": // totally normal. means it *does* exist.      this.cache[f] = 1      return cb.call(this, er)    case "ENOENT": // not terribly unusual    case "ELOOP":    case "ENAMETOOLONG":    case "UNKNOWN":      this.cache[f] = false      return cb.call(this, er)    default: // some unusual error.  Treat as failure.      this.cache[f] = false      if (this.strict) this.emit("error", er)      if (!this.silent) console.error("glob error", er)      return cb.call(this, er)  }}var isAbsolute = process.platform === "win32" ? absWin : absUnixfunction absWin (p) {  if (absUnix(p)) return true  // pull off the device/UNC bit from a windows path.  // from node's lib/path.js  var splitDeviceRe =      /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/    , result = splitDeviceRe.exec(p)    , device = result[1] || ''    , isUnc = device && device.charAt(1) !== ':'    , isAbsolute = !!result[2] || isUnc // UNC paths are always absolute  return isAbsolute}function absUnix (p) {  return p.charAt(0) === "/" || p === ""}
 |