--- /dev/null
+// 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 = glob
+
+var fs = require("graceful-fs")
+, minimatch = require("minimatch")
+, Minimatch = minimatch.Minimatch
+, inherits = require("inherits")
+, EE = require("events").EventEmitter
+, path = require("path")
+, isDir = {}
+, assert = require("assert").ok
+
+function 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 = deprecated
+
+function deprecated () {
+ throw new Error("glob's interface has changed. Please see the docs.")
+}
+
+glob.sync = globSync
+function globSync (pattern, options) {
+ if (typeof options === "number") {
+ deprecated()
+ return
+ }
+
+ options = options || {}
+ options.sync = true
+ return glob(pattern, options)
+}
+
+
+glob.Glob = Glob
+inherits(Glob, EE)
+function Glob (pattern, options, cb) {
+ if (!(this instanceof Glob)) {
+ return new Glob(pattern, options, cb)
+ }
+
+ if (typeof cb === "function") {
+ this.on("error", cb)
+ this.on("end", function (matches) {
+ cb(null, matches)
+ })
+ }
+
+ options = options || {}
+
+ this.EOF = {}
+ this._emitQueue = []
+
+ this.maxDepth = options.maxDepth || 1000
+ this.maxLength = options.maxLength || Infinity
+ 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
+
+ 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(function (m) {
+ var sc = this.statCache[m]
+ if (!sc)
+ return m
+ var isDir = (Array.isArray(sc) || sc === 2)
+ if (isDir && m.slice(-1) !== "/") {
+ return m + "/"
+ }
+ if (!isDir && m.slice(-1) === "/") {
+ return m.replace(/\/+$/, "")
+ }
+ return m
+ }, 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.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._emitQueue.push(m)
+ this._processEmitQueue()
+}
+
+Glob.prototype._processEmitQueue = function (m) {
+ while (!this._processingEmitQueue &&
+ !this.paused) {
+ this._processingEmitQueue = true
+ var m = this._emitQueue.shift()
+ if (!m) {
+ this._processingEmitQueue = false
+ break
+ }
+
+ this.log('emit!', m === this.EOF ? "end" : "match")
+
+ this.emit(m === this.EOF ? "end" : "match", m)
+ this._processingEmitQueue = false
+ }
+}
+
+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)
+
+ // 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]
+ if (typeof pn === "string") {
+ var found = entries.indexOf(pn) !== -1
+ entries = found ? entries[pn] : []
+ } else {
+ var rawGlob = pattern[n]._glob
+ , dotOk = this.dot || rawGlob.charAt(0) === "."
+
+ entries = entries.filter(function (e) {
+ return (e.charAt(0) !== "." || dotOk) &&
+ (typeof pattern[n] === "string" && e === pattern[n] ||
+ 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)
+ })
+
+}
+
+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)
+ }
+ this.log('stat', [this.cwd, f, '=', abs])
+ 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)
+ }
+
+ if (this.statCache.hasOwnProperty(f)) {
+ var exists = this.statCache[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))
+ }
+
+ if (this.sync) {
+ var er, stat
+ 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
+ }
+
+ if (er || !stat) {
+ exists = false
+ } else {
+ exists = stat.isDirectory() ? 2 : 1
+ }
+ this.statCache[f] = this.statCache[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)
+ }
+
+ this.log('readdir', [this.cwd, f, abs])
+ 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)
+ }
+
+ if (this.statCache.hasOwnProperty(f)) {
+ var c = this.statCache[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.statCache[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.statCache[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.statCache[f] = 1
+ return cb.call(this, er)
+ case "ENOENT": // not terribly unusual
+ case "ELOOP":
+ case "ENAMETOOLONG":
+ case "UNKNOWN":
+ this.statCache[f] = false
+ return cb.call(this, er)
+ default: // some unusual error. Treat as failure.
+ this.statCache[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 : absUnix
+
+function 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 === ""
+}