Name: js-handler/node_modules/nodeunit/node_modules/tap/node_modules/glob/glob.js
| 1: | // Approach: |
| 2: | // |
| 3: | // 1. Get the minimatch set |
| 4: | // 2. For each pattern in the set, PROCESS(pattern) |
| 5: | // 3. Store matches per-set, then uniq them |
| 6: | // |
| 7: | // PROCESS(pattern) |
| 8: | // Get the first [n] items from pattern that are all strings |
| 9: | // Join these together. This is PREFIX. |
| 10: | // If there is no more remaining, then stat(PREFIX) and |
| 11: | // add to matches if it succeeds. END. |
| 12: | // readdir(PREFIX) as ENTRIES |
| 13: | // If fails, END |
| 14: | // If pattern[n] is GLOBSTAR |
| 15: | // // handle the case where the globstar match is empty |
| 16: | // // by pruning it out, and testing the resulting pattern |
| 17: | // PROCESS(pattern[0..n] + pattern[n+1 .. $]) |
| 18: | // // handle other cases. |
| 19: | // for ENTRY in ENTRIES (not dotfiles) |
| 20: | // // attach globstar + tail onto the entry |
| 21: | // PROCESS(pattern[0..n] + ENTRY + pattern[n .. $]) |
| 22: | // |
| 23: | // else // not globstar |
| 24: | // for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot) |
| 25: | // Test ENTRY against pattern[n] |
| 26: | // If fails, continue |
| 27: | // If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $]) |
| 28: | // |
| 29: | // Caveat: |
| 30: | // Cache all stats and readdirs results to minimize syscall. Since all |
| 31: | // we ever care about is existence and directory-ness, we can just keep |
| 32: | // `true` for files, and [children,...] for directories, or `false` for |
| 33: | // things that don't exist. |
| 34: | |
| 35: | |
| 36: | |
| 37: | module.exports = glob |
| 38: | |
| 39: | var fs = require("fs") |
| 40: | , minimatch = require("minimatch") |
| 41: | , Minimatch = minimatch.Minimatch |
| 42: | , inherits = require("inherits") |
| 43: | , EE = require("events").EventEmitter |
| 44: | , path = require("path") |
| 45: | , isDir = {} |
| 46: | , assert = require("assert").ok |
| 47: | |
| 48: | function glob (pattern, options, cb) { |
| 49: | if (typeof options === "function") cb = options, options = {} |
| 50: | if (!options) options = {} |
| 51: | |
| 52: | if (typeof options === "number") { |
| 53: | deprecated() |
| 54: | return |
| 55: | } |
| 56: | |
| 57: | var g = new Glob(pattern, options, cb) |
| 58: | return g.sync ? g.found : g |
| 59: | } |
| 60: | |
| 61: | glob.fnmatch = deprecated |
| 62: | |
| 63: | function deprecated () { |
| 64: | throw new Error("glob's interface has changed. Please see the docs.") |
| 65: | } |
| 66: | |
| 67: | glob.sync = globSync |
| 68: | function globSync (pattern, options) { |
| 69: | if (typeof options === "number") { |
| 70: | deprecated() |
| 71: | return |
| 72: | } |
| 73: | |
| 74: | options = options || {} |
| 75: | options.sync = true |
| 76: | return glob(pattern, options) |
| 77: | } |
| 78: | |
| 79: | |
| 80: | glob.Glob = Glob |
| 81: | inherits(Glob, EE) |
| 82: | function Glob (pattern, options, cb) { |
| 83: | if (!(this instanceof Glob)) { |
| 84: | return new Glob(pattern, options, cb) |
| 85: | } |
| 86: | |
| 87: | if (typeof cb === "function") { |
| 88: | this.on("error", cb) |
| 89: | this.on("end", function (matches) { |
| 90: | cb(null, matches) |
| 91: | }) |
| 92: | } |
| 93: | |
| 94: | options = options || {} |
| 95: | |
| 96: | this.EOF = {} |
| 97: | this._emitQueue = [] |
| 98: | |
| 99: | this.maxDepth = options.maxDepth || 1000 |
| 100: | this.maxLength = options.maxLength || Infinity |
| 101: | this.cache = options.cache || {} |
| 102: | this.statCache = options.statCache || {} |
| 103: | |
| 104: | this.changedCwd = false |
| 105: | var cwd = process.cwd() |
| 106: | if (!options.hasOwnProperty("cwd")) this.cwd = cwd |
| 107: | else { |
| 108: | this.cwd = options.cwd |
| 109: | this.changedCwd = path.resolve(options.cwd) !== cwd |
| 110: | } |
| 111: | |
| 112: | this.root = options.root || path.resolve(this.cwd, "/") |
| 113: | this.root = path.resolve(this.root) |
| 114: | if (process.platform === "win32") |
| 115: | this.root = this.root.replace(/\\/g, "/") |
| 116: | |
| 117: | this.nomount = !!options.nomount |
| 118: | |
| 119: | if (!pattern) { |
| 120: | throw new Error("must provide pattern") |
| 121: | } |
| 122: | |
| 123: | // base-matching: just use globstar for that. |
| 124: | if (options.matchBase && -1 === pattern.indexOf("/")) { |
| 125: | if (options.noglobstar) { |
| 126: | throw new Error("base matching requires globstar") |
| 127: | } |
| 128: | pattern = "**/" + pattern |
| 129: | } |
| 130: | |
| 131: | this.strict = options.strict !== false |
| 132: | this.dot = !!options.dot |
| 133: | this.mark = !!options.mark |
| 134: | this.sync = !!options.sync |
| 135: | this.nounique = !!options.nounique |
| 136: | this.nonull = !!options.nonull |
| 137: | this.nosort = !!options.nosort |
| 138: | this.nocase = !!options.nocase |
| 139: | this.stat = !!options.stat |
| 140: | |
| 141: | this.debug = !!options.debug || !!options.globDebug |
| 142: | if (this.debug) |
| 143: | this.log = console.error |
| 144: | |
| 145: | this.silent = !!options.silent |
| 146: | |
| 147: | var mm = this.minimatch = new Minimatch(pattern, options) |
| 148: | this.options = mm.options |
| 149: | pattern = this.pattern = mm.pattern |
| 150: | |
| 151: | this.error = null |
| 152: | this.aborted = false |
| 153: | |
| 154: | // list of all the patterns that ** has resolved do, so |
| 155: | // we can avoid visiting multiple times. |
| 156: | this._globstars = {} |
| 157: | |
| 158: | EE.call(this) |
| 159: | |
| 160: | // process each pattern in the minimatch set |
| 161: | var n = this.minimatch.set.length |
| 162: | |
| 163: | // The matches are stored as {<filename>: true,...} so that |
| 164: | // duplicates are automagically pruned. |
| 165: | // Later, we do an Object.keys() on these. |
| 166: | // Keep them as a list so we can fill in when nonull is set. |
| 167: | this.matches = new Array(n) |
| 168: | |
| 169: | this.minimatch.set.forEach(iterator.bind(this)) |
| 170: | function iterator (pattern, i, set) { |
| 171: | this._process(pattern, 0, i, function (er) { |
| 172: | if (er) this.emit("error", er) |
| 173: | if (-- n <= 0) this._finish() |
| 174: | }) |
| 175: | } |
| 176: | } |
| 177: | |
| 178: | Glob.prototype.log = function () {} |
| 179: | |
| 180: | Glob.prototype._finish = function () { |
| 181: | assert(this instanceof Glob) |
| 182: | |
| 183: | var nou = this.nounique |
| 184: | , all = nou ? [] : {} |
| 185: | |
| 186: | for (var i = 0, l = this.matches.length; i < l; i ++) { |
| 187: | var matches = this.matches[i] |
| 188: | this.log("matches[%d] =", i, matches) |
| 189: | // do like the shell, and spit out the literal glob |
| 190: | if (!matches) { |
| 191: | if (this.nonull) { |
| 192: | var literal = this.minimatch.globSet[i] |
| 193: | if (nou) all.push(literal) |
| 194: | else all[literal] = true |
| 195: | } |
| 196: | } else { |
| 197: | // had matches |
| 198: | var m = Object.keys(matches) |
| 199: | if (nou) all.push.apply(all, m) |
| 200: | else m.forEach(function (m) { |
| 201: | all[m] = true |
| 202: | }) |
| 203: | } |
| 204: | } |
| 205: | |
| 206: | if (!nou) all = Object.keys(all) |
| 207: | |
| 208: | if (!this.nosort) { |
| 209: | all = all.sort(this.nocase ? alphasorti : alphasort) |
| 210: | } |
| 211: | |
| 212: | if (this.mark) { |
| 213: | // at *some* point we statted all of these |
| 214: | all = all.map(function (m) { |
| 215: | var sc = this.cache[m] |
| 216: | if (!sc) |
| 217: | return m |
| 218: | var isDir = (Array.isArray(sc) || sc === 2) |
| 219: | if (isDir && m.slice(-1) !== "/") { |
| 220: | return m + "/" |
| 221: | } |
| 222: | if (!isDir && m.slice(-1) === "/") { |
| 223: | return m.replace(/\/+$/, "") |
| 224: | } |
| 225: | return m |
| 226: | }, this) |
| 227: | } |
| 228: | |
| 229: | this.log("emitting end", all) |
| 230: | |
| 231: | this.EOF = this.found = all |
| 232: | this.emitMatch(this.EOF) |
| 233: | } |
| 234: | |
| 235: | function alphasorti (a, b) { |
| 236: | a = a.toLowerCase() |
| 237: | b = b.toLowerCase() |
| 238: | return alphasort(a, b) |
| 239: | } |
| 240: | |
| 241: | function alphasort (a, b) { |
| 242: | return a > b ? 1 : a < b ? -1 : 0 |
| 243: | } |
| 244: | |
| 245: | Glob.prototype.abort = function () { |
| 246: | this.aborted = true |
| 247: | this.emit("abort") |
| 248: | } |
| 249: | |
| 250: | Glob.prototype.pause = function () { |
| 251: | if (this.paused) return |
| 252: | if (this.sync) |
| 253: | this.emit("error", new Error("Can't pause/resume sync glob")) |
| 254: | this.paused = true |
| 255: | this.emit("pause") |
| 256: | } |
| 257: | |
| 258: | Glob.prototype.resume = function () { |
| 259: | if (!this.paused) return |
| 260: | if (this.sync) |
| 261: | this.emit("error", new Error("Can't pause/resume sync glob")) |
| 262: | this.paused = false |
| 263: | this.emit("resume") |
| 264: | this._processEmitQueue() |
| 265: | //process.nextTick(this.emit.bind(this, "resume")) |
| 266: | } |
| 267: | |
| 268: | Glob.prototype.emitMatch = function (m) { |
| 269: | if (!this.stat || this.statCache[m] || m === this.EOF) { |
| 270: | this._emitQueue.push(m) |
| 271: | this._processEmitQueue() |
| 272: | } else { |
| 273: | this._stat(m, function(exists, isDir) { |
| 274: | if (exists) { |
| 275: | this._emitQueue.push(m) |
| 276: | this._processEmitQueue() |
| 277: | } |
| 278: | }) |
| 279: | } |
| 280: | } |
| 281: | |
| 282: | Glob.prototype._processEmitQueue = function (m) { |
| 283: | while (!this._processingEmitQueue && |
| 284: | !this.paused) { |
| 285: | this._processingEmitQueue = true |
| 286: | var m = this._emitQueue.shift() |
| 287: | if (!m) { |
| 288: | this._processingEmitQueue = false |
| 289: | break |
| 290: | } |
| 291: | |
| 292: | this.log('emit!', m === this.EOF ? "end" : "match") |
| 293: | |
| 294: | this.emit(m === this.EOF ? "end" : "match", m) |
| 295: | this._processingEmitQueue = false |
| 296: | } |
| 297: | } |
| 298: | |
| 299: | Glob.prototype._process = function (pattern, depth, index, cb_) { |
| 300: | assert(this instanceof Glob) |
| 301: | |
| 302: | var cb = function cb (er, res) { |
| 303: | assert(this instanceof Glob) |
| 304: | if (this.paused) { |
| 305: | if (!this._processQueue) { |
| 306: | this._processQueue = [] |
| 307: | this.once("resume", function () { |
| 308: | var q = this._processQueue |
| 309: | this._processQueue = null |
| 310: | q.forEach(function (cb) { cb() }) |
| 311: | }) |
| 312: | } |
| 313: | this._processQueue.push(cb_.bind(this, er, res)) |
| 314: | } else { |
| 315: | cb_.call(this, er, res) |
| 316: | } |
| 317: | }.bind(this) |
| 318: | |
| 319: | if (this.aborted) return cb() |
| 320: | |
| 321: | if (depth > this.maxDepth) return cb() |
| 322: | |
| 323: | // Get the first [n] parts of pattern that are all strings. |
| 324: | var n = 0 |
| 325: | while (typeof pattern[n] === "string") { |
| 326: | n ++ |
| 327: | } |
| 328: | // now n is the index of the first one that is *not* a string. |
| 329: | |
| 330: | // see if there's anything else |
| 331: | var prefix |
| 332: | switch (n) { |
| 333: | // if not, then this is rather simple |
| 334: | case pattern.length: |
| 335: | prefix = pattern.join("/") |
| 336: | this._stat(prefix, function (exists, isDir) { |
| 337: | // either it's there, or it isn't. |
| 338: | // nothing more to do, either way. |
| 339: | if (exists) { |
| 340: | if (prefix && isAbsolute(prefix) && !this.nomount) { |
| 341: | if (prefix.charAt(0) === "/") { |
| 342: | prefix = path.join(this.root, prefix) |
| 343: | } else { |
| 344: | prefix = path.resolve(this.root, prefix) |
| 345: | } |
| 346: | } |
| 347: | |
| 348: | if (process.platform === "win32") |
| 349: | prefix = prefix.replace(/\\/g, "/") |
| 350: | |
| 351: | this.matches[index] = this.matches[index] || {} |
| 352: | this.matches[index][prefix] = true |
| 353: | this.emitMatch(prefix) |
| 354: | } |
| 355: | return cb() |
| 356: | }) |
| 357: | return |
| 358: | |
| 359: | case 0: |
| 360: | // pattern *starts* with some non-trivial item. |
| 361: | // going to readdir(cwd), but not include the prefix in matches. |
| 362: | prefix = null |
| 363: | break |
| 364: | |
| 365: | default: |
| 366: | // pattern has some string bits in the front. |
| 367: | // whatever it starts with, whether that's "absolute" like /foo/bar, |
| 368: | // or "relative" like "../baz" |
| 369: | prefix = pattern.slice(0, n) |
| 370: | prefix = prefix.join("/") |
| 371: | break |
| 372: | } |
| 373: | |
| 374: | // get the list of entries. |
| 375: | var read |
| 376: | if (prefix === null) read = "." |
| 377: | else if (isAbsolute(prefix) || isAbsolute(pattern.join("/"))) { |
| 378: | if (!prefix || !isAbsolute(prefix)) { |
| 379: | prefix = path.join("/", prefix) |
| 380: | } |
| 381: | read = prefix = path.resolve(prefix) |
| 382: | |
| 383: | // if (process.platform === "win32") |
| 384: | // read = prefix = prefix.replace(/^[a-zA-Z]:|\\/g, "/") |
| 385: | |
| 386: | this.log('absolute: ', prefix, this.root, pattern, read) |
| 387: | } else { |
| 388: | read = prefix |
| 389: | } |
| 390: | |
| 391: | this.log('readdir(%j)', read, this.cwd, this.root) |
| 392: | |
| 393: | return this._readdir(read, function (er, entries) { |
| 394: | if (er) { |
| 395: | // not a directory! |
| 396: | // this means that, whatever else comes after this, it can never match |
| 397: | return cb() |
| 398: | } |
| 399: | |
| 400: | // globstar is special |
| 401: | if (pattern[n] === minimatch.GLOBSTAR) { |
| 402: | // test without the globstar, and with every child both below |
| 403: | // and replacing the globstar. |
| 404: | var s = [ pattern.slice(0, n).concat(pattern.slice(n + 1)) ] |
| 405: | entries.forEach(function (e) { |
| 406: | if (e.charAt(0) === "." && !this.dot) return |
| 407: | // instead of the globstar |
| 408: | s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1))) |
| 409: | // below the globstar |
| 410: | s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n))) |
| 411: | }, this) |
| 412: | |
| 413: | s = s.filter(function (pattern) { |
| 414: | var key = gsKey(pattern) |
| 415: | var seen = !this._globstars[key] |
| 416: | this._globstars[key] = true |
| 417: | return seen |
| 418: | }, this) |
| 419: | |
| 420: | if (!s.length) |
| 421: | return cb() |
| 422: | |
| 423: | // now asyncForEach over this |
| 424: | var l = s.length |
| 425: | , errState = null |
| 426: | s.forEach(function (gsPattern) { |
| 427: | this._process(gsPattern, depth + 1, index, function (er) { |
| 428: | if (errState) return |
| 429: | if (er) return cb(errState = er) |
| 430: | if (--l <= 0) return cb() |
| 431: | }) |
| 432: | }, this) |
| 433: | |
| 434: | return |
| 435: | } |
| 436: | |
| 437: | // not a globstar |
| 438: | // It will only match dot entries if it starts with a dot, or if |
| 439: | // dot is set. Stuff like @(.foo|.bar) isn't allowed. |
| 440: | var pn = pattern[n] |
| 441: | var rawGlob = pattern[n]._glob |
| 442: | , dotOk = this.dot || rawGlob.charAt(0) === "." |
| 443: | |
| 444: | entries = entries.filter(function (e) { |
| 445: | return (e.charAt(0) !== "." || dotOk) && |
| 446: | e.match(pattern[n]) |
| 447: | }) |
| 448: | |
| 449: | // If n === pattern.length - 1, then there's no need for the extra stat |
| 450: | // *unless* the user has specified "mark" or "stat" explicitly. |
| 451: | // We know that they exist, since the readdir returned them. |
| 452: | if (n === pattern.length - 1 && |
| 453: | !this.mark && |
| 454: | !this.stat) { |
| 455: | entries.forEach(function (e) { |
| 456: | if (prefix) { |
| 457: | if (prefix !== "/") e = prefix + "/" + e |
| 458: | else e = prefix + e |
| 459: | } |
| 460: | if (e.charAt(0) === "/" && !this.nomount) { |
| 461: | e = path.join(this.root, e) |
| 462: | } |
| 463: | |
| 464: | if (process.platform === "win32") |
| 465: | e = e.replace(/\\/g, "/") |
| 466: | |
| 467: | this.matches[index] = this.matches[index] || {} |
| 468: | this.matches[index][e] = true |
| 469: | this.emitMatch(e) |
| 470: | }, this) |
| 471: | return cb.call(this) |
| 472: | } |
| 473: | |
| 474: | |
| 475: | // now test all the remaining entries as stand-ins for that part |
| 476: | // of the pattern. |
| 477: | var l = entries.length |
| 478: | , errState = null |
| 479: | if (l === 0) return cb() // no matches possible |
| 480: | entries.forEach(function (e) { |
| 481: | var p = pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1)) |
| 482: | this._process(p, depth + 1, index, function (er) { |
| 483: | if (errState) return |
| 484: | if (er) return cb(errState = er) |
| 485: | if (--l === 0) return cb.call(this) |
| 486: | }) |
| 487: | }, this) |
| 488: | }) |
| 489: | |
| 490: | } |
| 491: | |
| 492: | function gsKey (pattern) { |
| 493: | return '**' + pattern.map(function (p) { |
| 494: | return (p === minimatch.GLOBSTAR) ? '**' : (''+p) |
| 495: | }).join('/') |
| 496: | } |
| 497: | |
| 498: | Glob.prototype._stat = function (f, cb) { |
| 499: | assert(this instanceof Glob) |
| 500: | var abs = f |
| 501: | if (f.charAt(0) === "/") { |
| 502: | abs = path.join(this.root, f) |
| 503: | } else if (this.changedCwd) { |
| 504: | abs = path.resolve(this.cwd, f) |
| 505: | } |
| 506: | |
| 507: | if (f.length > this.maxLength) { |
| 508: | var er = new Error("Path name too long") |
| 509: | er.code = "ENAMETOOLONG" |
| 510: | er.path = f |
| 511: | return this._afterStat(f, abs, cb, er) |
| 512: | } |
| 513: | |
| 514: | this.log('stat', [this.cwd, f, '=', abs]) |
| 515: | |
| 516: | if (!this.stat && this.cache.hasOwnProperty(f)) { |
| 517: | var exists = this.cache[f] |
| 518: | , isDir = exists && (Array.isArray(exists) || exists === 2) |
| 519: | if (this.sync) return cb.call(this, !!exists, isDir) |
| 520: | return process.nextTick(cb.bind(this, !!exists, isDir)) |
| 521: | } |
| 522: | |
| 523: | var stat = this.statCache[abs] |
| 524: | if (this.sync || stat) { |
| 525: | var er |
| 526: | try { |
| 527: | stat = fs.statSync(abs) |
| 528: | } catch (e) { |
| 529: | er = e |
| 530: | } |
| 531: | this._afterStat(f, abs, cb, er, stat) |
| 532: | } else { |
| 533: | fs.stat(abs, this._afterStat.bind(this, f, abs, cb)) |
| 534: | } |
| 535: | } |
| 536: | |
| 537: | Glob.prototype._afterStat = function (f, abs, cb, er, stat) { |
| 538: | var exists |
| 539: | assert(this instanceof Glob) |
| 540: | |
| 541: | if (abs.slice(-1) === "/" && stat && !stat.isDirectory()) { |
| 542: | this.log("should be ENOTDIR, fake it") |
| 543: | |
| 544: | er = new Error("ENOTDIR, not a directory '" + abs + "'") |
| 545: | er.path = abs |
| 546: | er.code = "ENOTDIR" |
| 547: | stat = null |
| 548: | } |
| 549: | |
| 550: | var emit = !this.statCache[abs] |
| 551: | this.statCache[abs] = stat |
| 552: | |
| 553: | if (er || !stat) { |
| 554: | exists = false |
| 555: | } else { |
| 556: | exists = stat.isDirectory() ? 2 : 1 |
| 557: | if (emit) |
| 558: | this.emit('stat', f, stat) |
| 559: | } |
| 560: | this.cache[f] = this.cache[f] || exists |
| 561: | cb.call(this, !!exists, exists === 2) |
| 562: | } |
| 563: | |
| 564: | Glob.prototype._readdir = function (f, cb) { |
| 565: | assert(this instanceof Glob) |
| 566: | var abs = f |
| 567: | if (f.charAt(0) === "/") { |
| 568: | abs = path.join(this.root, f) |
| 569: | } else if (isAbsolute(f)) { |
| 570: | abs = f |
| 571: | } else if (this.changedCwd) { |
| 572: | abs = path.resolve(this.cwd, f) |
| 573: | } |
| 574: | |
| 575: | if (f.length > this.maxLength) { |
| 576: | var er = new Error("Path name too long") |
| 577: | er.code = "ENAMETOOLONG" |
| 578: | er.path = f |
| 579: | return this._afterReaddir(f, abs, cb, er) |
| 580: | } |
| 581: | |
| 582: | this.log('readdir', [this.cwd, f, abs]) |
| 583: | if (this.cache.hasOwnProperty(f)) { |
| 584: | var c = this.cache[f] |
| 585: | if (Array.isArray(c)) { |
| 586: | if (this.sync) return cb.call(this, null, c) |
| 587: | return process.nextTick(cb.bind(this, null, c)) |
| 588: | } |
| 589: | |
| 590: | if (!c || c === 1) { |
| 591: | // either ENOENT or ENOTDIR |
| 592: | var code = c ? "ENOTDIR" : "ENOENT" |
| 593: | , er = new Error((c ? "Not a directory" : "Not found") + ": " + f) |
| 594: | er.path = f |
| 595: | er.code = code |
| 596: | this.log(f, er) |
| 597: | if (this.sync) return cb.call(this, er) |
| 598: | return process.nextTick(cb.bind(this, er)) |
| 599: | } |
| 600: | |
| 601: | // at this point, c === 2, meaning it's a dir, but we haven't |
| 602: | // had to read it yet, or c === true, meaning it's *something* |
| 603: | // but we don't have any idea what. Need to read it, either way. |
| 604: | } |
| 605: | |
| 606: | if (this.sync) { |
| 607: | var er, entries |
| 608: | try { |
| 609: | entries = fs.readdirSync(abs) |
| 610: | } catch (e) { |
| 611: | er = e |
| 612: | } |
| 613: | return this._afterReaddir(f, abs, cb, er, entries) |
| 614: | } |
| 615: | |
| 616: | fs.readdir(abs, this._afterReaddir.bind(this, f, abs, cb)) |
| 617: | } |
| 618: | |
| 619: | Glob.prototype._afterReaddir = function (f, abs, cb, er, entries) { |
| 620: | assert(this instanceof Glob) |
| 621: | if (entries && !er) { |
| 622: | this.cache[f] = entries |
| 623: | // if we haven't asked to stat everything for suresies, then just |
| 624: | // assume that everything in there exists, so we can avoid |
| 625: | // having to stat it a second time. This also gets us one step |
| 626: | // further into ELOOP territory. |
| 627: | if (!this.mark && !this.stat) { |
| 628: | entries.forEach(function (e) { |
| 629: | if (f === "/") e = f + e |
| 630: | else e = f + "/" + e |
| 631: | this.cache[e] = true |
| 632: | }, this) |
| 633: | } |
| 634: | |
| 635: | return cb.call(this, er, entries) |
| 636: | } |
| 637: | |
| 638: | // now handle errors, and cache the information |
| 639: | if (er) switch (er.code) { |
| 640: | case "ENOTDIR": // totally normal. means it *does* exist. |
| 641: | this.cache[f] = 1 |
| 642: | return cb.call(this, er) |
| 643: | case "ENOENT": // not terribly unusual |
| 644: | case "ELOOP": |
| 645: | case "ENAMETOOLONG": |
| 646: | case "UNKNOWN": |
| 647: | this.cache[f] = false |
| 648: | return cb.call(this, er) |
| 649: | default: // some unusual error. Treat as failure. |
| 650: | this.cache[f] = false |
| 651: | if (this.strict) this.emit("error", er) |
| 652: | if (!this.silent) console.error("glob error", er) |
| 653: | return cb.call(this, er) |
| 654: | } |
| 655: | } |
| 656: | |
| 657: | var isAbsolute = process.platform === "win32" ? absWin : absUnix |
| 658: | |
| 659: | function absWin (p) { |
| 660: | if (absUnix(p)) return true |
| 661: | // pull off the device/UNC bit from a windows path. |
| 662: | // from node's lib/path.js |
| 663: | var splitDeviceRe = |
| 664: | /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/ |
| 665: | , result = splitDeviceRe.exec(p) |
| 666: | , device = result[1] || '' |
| 667: | , isUnc = device && device.charAt(1) !== ':' |
| 668: | , isAbsolute = !!result[2] || isUnc // UNC paths are always absolute |
| 669: | |
| 670: | return isAbsolute |
| 671: | } |
| 672: | |
| 673: | function absUnix (p) { |
| 674: | return p.charAt(0) === "/" || p === "" |
| 675: | } |
