JAVASCRIPT 27
Glob.js Guest on 25th April 2021 07:52:55 AM
  1. // Approach:
  2. //
  3. // 1. Get the minimatch set
  4. // 2. For each pattern in the set, PROCESS(pattern, false)
  5. // 3. Store matches per-set, then uniq them
  6. //
  7. // PROCESS(pattern, inGlobStar)
  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. //
  13. // If inGlobStar and PREFIX is symlink and points to dir
  14. //   set ENTRIES = []
  15. // else readdir(PREFIX) as ENTRIES
  16. //   If fail, END
  17. //
  18. // with ENTRIES
  19. //   If pattern[n] is GLOBSTAR
  20. //     // handle the case where the globstar match is empty
  21. //     // by pruning it out, and testing the resulting pattern
  22. //     PROCESS(pattern[0..n] + pattern[n+1 .. $], false)
  23. //     // handle other cases.
  24. //     for ENTRY in ENTRIES (not dotfiles)
  25. //       // attach globstar + tail onto the entry
  26. //       // Mark that this entry is a globstar match
  27. //       PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true)
  28. //
  29. //   else // not globstar
  30. //     for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot)
  31. //       Test ENTRY against pattern[n]
  32. //       If fails, continue
  33. //       If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $])
  34. //
  35. // Caveat:
  36. //   Cache all stats and readdirs results to minimize syscall.  Since all
  37. //   we ever care about is existence and directory-ness, we can just keep
  38. //   `true` for files, and [children,...] for directories, or `false` for
  39. //   things that don't exist.
  40.  
  41. module.exports = glob
  42.  
  43. var fs = require('fs')
  44. var rp = require('fs.realpath')
  45. var minimatch = require('minimatch')
  46. var Minimatch = minimatch.Minimatch
  47. var inherits = require('inherits')
  48. var EE = require('events').EventEmitter
  49. var path = require('path')
  50. var assert = require('assert')
  51. var isAbsolute = require('path-is-absolute')
  52. var globSync = require('./sync.js')
  53. var common = require('./common.js')
  54. var alphasort = common.alphasort
  55. var alphasorti = common.alphasorti
  56. var setopts = common.setopts
  57. var ownProp = common.ownProp
  58. var inflight = require('inflight')
  59. var util = require('util')
  60. var childrenIgnored = common.childrenIgnored
  61. var isIgnored = common.isIgnored
  62.  
  63. var once = require('once')
  64.  
  65. function glob (pattern, options, cb) {
  66.   if (typeof options === 'function') cb = options, options = {}
  67.   if (!options) options = {}
  68.  
  69.   if (options.sync) {
  70.     if (cb)
  71.       throw new TypeError('callback provided to sync glob')
  72.     return globSync(pattern, options)
  73.   }
  74.  
  75.   return new Glob(pattern, options, cb)
  76. }
  77.  
  78. glob.sync = globSync
  79. var GlobSync = glob.GlobSync = globSync.GlobSync
  80.  
  81. // old api surface
  82. glob.glob = glob
  83.  
  84. function extend (origin, add) {
  85.   if (add === null || typeof add !== 'object') {
  86.     return origin
  87.   }
  88.  
  89.   var keys = Object.keys(add)
  90.   var i = keys.length
  91.   while (i--) {
  92.     origin[keys[i]] = add[keys[i]]
  93.   }
  94.   return origin
  95. }
  96.  
  97. glob.hasMagic = function (pattern, options_) {
  98.   var options = extend({}, options_)
  99.   options.noprocess = true
  100.  
  101.   var g = new Glob(pattern, options)
  102.   var set = g.minimatch.set
  103.  
  104.   if (!pattern)
  105.     return false
  106.  
  107.   if (set.length > 1)
  108.     return true
  109.  
  110.   for (var j = 0; j < set[0].length; j++) {
  111.     if (typeof set[0][j] !== 'string')
  112.       return true
  113.   }
  114.  
  115.   return false
  116. }
  117.  
  118. glob.Glob = Glob
  119. inherits(Glob, EE)
  120. function Glob (pattern, options, cb) {
  121.   if (typeof options === 'function') {
  122.     cb = options
  123.     options = null
  124.   }
  125.  
  126.   if (options && options.sync) {
  127.     if (cb)
  128.       throw new TypeError('callback provided to sync glob')
  129.     return new GlobSync(pattern, options)
  130.   }
  131.  
  132.   if (!(this instanceof Glob))
  133.     return new Glob(pattern, options, cb)
  134.  
  135.   setopts(this, pattern, options)
  136.   this._didRealPath = false
  137.  
  138.   // process each pattern in the minimatch set
  139.   var n = this.minimatch.set.length
  140.  
  141.   // The matches are stored as {<filename>: true,...} so that
  142.   // duplicates are automagically pruned.
  143.   // Later, we do an Object.keys() on these.
  144.   // Keep them as a list so we can fill in when nonull is set.
  145.   this.matches = new Array(n)
  146.  
  147.   if (typeof cb === 'function') {
  148.     cb = once(cb)
  149.     this.on('error', cb)
  150.     this.on('end', function (matches) {
  151.       cb(null, matches)
  152.     })
  153.   }
  154.  
  155.   var self = this
  156.   this._processing = 0
  157.  
  158.   this._emitQueue = []
  159.   this._processQueue = []
  160.   this.paused = false
  161.  
  162.   if (this.noprocess)
  163.     return this
  164.  
  165.   if (n === 0)
  166.     return done()
  167.  
  168.   var sync = true
  169.   for (var i = 0; i < n; i ++) {
  170.     this._process(this.minimatch.set[i], i, false, done)
  171.   }
  172.   sync = false
  173.  
  174.   function done () {
  175.     --self._processing
  176.     if (self._processing <= 0) {
  177.       if (sync) {
  178.         process.nextTick(function () {
  179.           self._finish()
  180.         })
  181.       } else {
  182.         self._finish()
  183.       }
  184.     }
  185.   }
  186. }
  187.  
  188. Glob.prototype._finish = function () {
  189.   assert(this instanceof Glob)
  190.   if (this.aborted)
  191.     return
  192.  
  193.   if (this.realpath && !this._didRealpath)
  194.     return this._realpath()
  195.  
  196.   common.finish(this)
  197.   this.emit('end', this.found)
  198. }
  199.  
  200. Glob.prototype._realpath = function () {
  201.   if (this._didRealpath)
  202.     return
  203.  
  204.   this._didRealpath = true
  205.  
  206.   var n = this.matches.length
  207.   if (n === 0)
  208.     return this._finish()
  209.  
  210.   var self = this
  211.   for (var i = 0; i < this.matches.length; i++)
  212.     this._realpathSet(i, next)
  213.  
  214.   function next () {
  215.     if (--n === 0)
  216.       self._finish()
  217.   }
  218. }
  219.  
  220. Glob.prototype._realpathSet = function (index, cb) {
  221.   var matchset = this.matches[index]
  222.   if (!matchset)
  223.     return cb()
  224.  
  225.   var found = Object.keys(matchset)
  226.   var self = this
  227.   var n = found.length
  228.  
  229.   if (n === 0)
  230.     return cb()
  231.  
  232.   var set = this.matches[index] = Object.create(null)
  233.   found.forEach(function (p, i) {
  234.     // If there's a problem with the stat, then it means that
  235.     // one or more of the links in the realpath couldn't be
  236.     // resolved.  just return the abs value in that case.
  237.     p = self._makeAbs(p)
  238.     rp.realpath(p, self.realpathCache, function (er, real) {
  239.       if (!er)
  240.         set[real] = true
  241.       else if (er.syscall === 'stat')
  242.         set[p] = true
  243.       else
  244.         self.emit('error', er) // srsly wtf right here
  245.  
  246.       if (--n === 0) {
  247.         self.matches[index] = set
  248.         cb()
  249.       }
  250.     })
  251.   })
  252. }
  253.  
  254. Glob.prototype._mark = function (p) {
  255.   return common.mark(this, p)
  256. }
  257.  
  258. Glob.prototype._makeAbs = function (f) {
  259.   return common.makeAbs(this, f)
  260. }
  261.  
  262. Glob.prototype.abort = function () {
  263.   this.aborted = true
  264.   this.emit('abort')
  265. }
  266.  
  267. Glob.prototype.pause = function () {
  268.   if (!this.paused) {
  269.     this.paused = true
  270.     this.emit('pause')
  271.   }
  272. }
  273.  
  274. Glob.prototype.resume = function () {
  275.   if (this.paused) {
  276.     this.emit('resume')
  277.     this.paused = false
  278.     if (this._emitQueue.length) {
  279.       var eq = this._emitQueue.slice(0)
  280.       this._emitQueue.length = 0
  281.       for (var i = 0; i < eq.length; i ++) {
  282.         var e = eq[i]
  283.         this._emitMatch(e[0], e[1])
  284.       }
  285.     }
  286.     if (this._processQueue.length) {
  287.       var pq = this._processQueue.slice(0)
  288.       this._processQueue.length = 0
  289.       for (var i = 0; i < pq.length; i ++) {
  290.         var p = pq[i]
  291.         this._processing--
  292.         this._process(p[0], p[1], p[2], p[3])
  293.       }
  294.     }
  295.   }
  296. }
  297.  
  298. Glob.prototype._process = function (pattern, index, inGlobStar, cb) {
  299.   assert(this instanceof Glob)
  300.   assert(typeof cb === 'function')
  301.  
  302.   if (this.aborted)
  303.     return
  304.  
  305.   this._processing++
  306.   if (this.paused) {
  307.     this._processQueue.push([pattern, index, inGlobStar, cb])
  308.     return
  309.   }
  310.  
  311.   //console.error('PROCESS %d', this._processing, pattern)
  312.  
  313.   // Get the first [n] parts of pattern that are all strings.
  314.   var n = 0
  315.   while (typeof pattern[n] === 'string') {
  316.     n ++
  317.   }
  318.   // now n is the index of the first one that is *not* a string.
  319.  
  320.   // see if there's anything else
  321.   var prefix
  322.   switch (n) {
  323.     // if not, then this is rather simple
  324.     case pattern.length:
  325.       this._processSimple(pattern.join('/'), index, cb)
  326.       return
  327.  
  328.     case 0:
  329.       // pattern *starts* with some non-trivial item.
  330.       // going to readdir(cwd), but not include the prefix in matches.
  331.       prefix = null
  332.       break
  333.  
  334.     default:
  335.       // pattern has some string bits in the front.
  336.       // whatever it starts with, whether that's 'absolute' like /foo/bar,
  337.       // or 'relative' like '../baz'
  338.       prefix = pattern.slice(0, n).join('/')
  339.       break
  340.   }
  341.  
  342.   var remain = pattern.slice(n)
  343.  
  344.   // get the list of entries.
  345.   var read
  346.   if (prefix === null)
  347.     read = '.'
  348.   else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) {
  349.     if (!prefix || !isAbsolute(prefix))
  350.       prefix = '/' + prefix
  351.     read = prefix
  352.   } else
  353.     read = prefix
  354.  
  355.   var abs = this._makeAbs(read)
  356.  
  357.   //if ignored, skip _processing
  358.   if (childrenIgnored(this, read))
  359.     return cb()
  360.  
  361.   var isGlobStar = remain[0] === minimatch.GLOBSTAR
  362.   if (isGlobStar)
  363.     this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb)
  364.   else
  365.     this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb)
  366. }
  367.  
  368. Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) {
  369.   var self = this
  370.   this._readdir(abs, inGlobStar, function (er, entries) {
  371.     return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb)
  372.   })
  373. }
  374.  
  375. Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) {
  376.  
  377.   // if the abs isn't a dir, then nothing can match!
  378.   if (!entries)
  379.     return cb()
  380.  
  381.   // It will only match dot entries if it starts with a dot, or if
  382.   // dot is set.  Stuff like @(.foo|.bar) isn't allowed.
  383.   var pn = remain[0]
  384.   var negate = !!this.minimatch.negate
  385.   var rawGlob = pn._glob
  386.   var dotOk = this.dot || rawGlob.charAt(0) === '.'
  387.  
  388.   var matchedEntries = []
  389.   for (var i = 0; i < entries.length; i++) {
  390.     var e = entries[i]
  391.     if (e.charAt(0) !== '.' || dotOk) {
  392.       var m
  393.       if (negate && !prefix) {
  394.         m = !e.match(pn)
  395.       } else {
  396.         m = e.match(pn)
  397.       }
  398.       if (m)
  399.         matchedEntries.push(e)
  400.     }
  401.   }
  402.  
  403.   //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries)
  404.  
  405.   var len = matchedEntries.length
  406.   // If there are no matched entries, then nothing matches.
  407.   if (len === 0)
  408.     return cb()
  409.  
  410.   // if this is the last remaining pattern bit, then no need for
  411.   // an additional stat *unless* the user has specified mark or
  412.   // stat explicitly.  We know they exist, since readdir returned
  413.   // them.
  414.  
  415.   if (remain.length === 1 && !this.mark && !this.stat) {
  416.     if (!this.matches[index])
  417.       this.matches[index] = Object.create(null)
  418.  
  419.     for (var i = 0; i < len; i ++) {
  420.       var e = matchedEntries[i]
  421.       if (prefix) {
  422.         if (prefix !== '/')
  423.           e = prefix + '/' + e
  424.         else
  425.           e = prefix + e
  426.       }
  427.  
  428.       if (e.charAt(0) === '/' && !this.nomount) {
  429.         e = path.join(this.root, e)
  430.       }
  431.       this._emitMatch(index, e)
  432.     }
  433.     // This was the last one, and no stats were needed
  434.     return cb()
  435.   }
  436.  
  437.   // now test all matched entries as stand-ins for that part
  438.   // of the pattern.
  439.   remain.shift()
  440.   for (var i = 0; i < len; i ++) {
  441.     var e = matchedEntries[i]
  442.     var newPattern
  443.     if (prefix) {
  444.       if (prefix !== '/')
  445.         e = prefix + '/' + e
  446.       else
  447.         e = prefix + e
  448.     }
  449.     this._process([e].concat(remain), index, inGlobStar, cb)
  450.   }
  451.   cb()
  452. }
  453.  
  454. Glob.prototype._emitMatch = function (index, e) {
  455.   if (this.aborted)
  456.     return
  457.  
  458.   if (isIgnored(this, e))
  459.     return
  460.  
  461.   if (this.paused) {
  462.     this._emitQueue.push([index, e])
  463.     return
  464.   }
  465.  
  466.   var abs = isAbsolute(e) ? e : this._makeAbs(e)
  467.  
  468.   if (this.mark)
  469.     e = this._mark(e)
  470.  
  471.   if (this.absolute)
  472.     e = abs
  473.  
  474.   if (this.matches[index][e])
  475.     return
  476.  
  477.   if (this.nodir) {
  478.     var c = this.cache[abs]
  479.     if (c === 'DIR' || Array.isArray(c))
  480.       return
  481.   }
  482.  
  483.   this.matches[index][e] = true
  484.  
  485.   var st = this.statCache[abs]
  486.   if (st)
  487.     this.emit('stat', e, st)
  488.  
  489.   this.emit('match', e)
  490. }
  491.  
  492. Glob.prototype._readdirInGlobStar = function (abs, cb) {
  493.   if (this.aborted)
  494.     return
  495.  
  496.   // follow all symlinked directories forever
  497.   // just proceed as if this is a non-globstar situation
  498.   if (this.follow)
  499.     return this._readdir(abs, false, cb)
  500.  
  501.   var lstatkey = 'lstat\0' + abs
  502.   var self = this
  503.   var lstatcb = inflight(lstatkey, lstatcb_)
  504.  
  505.   if (lstatcb)
  506.     fs.lstat(abs, lstatcb)
  507.  
  508.   function lstatcb_ (er, lstat) {
  509.     if (er && er.code === 'ENOENT')
  510.       return cb()
  511.  
  512.     var isSym = lstat && lstat.isSymbolicLink()
  513.     self.symlinks[abs] = isSym
  514.  
  515.     // If it's not a symlink or a dir, then it's definitely a regular file.
  516.     // don't bother doing a readdir in that case.
  517.     if (!isSym && lstat && !lstat.isDirectory()) {
  518.       self.cache[abs] = 'FILE'
  519.       cb()
  520.     } else
  521.       self._readdir(abs, false, cb)
  522.   }
  523. }
  524.  
  525. Glob.prototype._readdir = function (abs, inGlobStar, cb) {
  526.   if (this.aborted)
  527.     return
  528.  
  529.   cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb)
  530.   if (!cb)
  531.     return
  532.  
  533.   //console.error('RD %j %j', +inGlobStar, abs)
  534.   if (inGlobStar && !ownProp(this.symlinks, abs))
  535.     return this._readdirInGlobStar(abs, cb)
  536.  
  537.   if (ownProp(this.cache, abs)) {
  538.     var c = this.cache[abs]
  539.     if (!c || c === 'FILE')
  540.       return cb()
  541.  
  542.     if (Array.isArray(c))
  543.       return cb(null, c)
  544.   }
  545.  
  546.   var self = this
  547.   fs.readdir(abs, readdirCb(this, abs, cb))
  548. }
  549.  
  550. function readdirCb (self, abs, cb) {
  551.   return function (er, entries) {
  552.     if (er)
  553.       self._readdirError(abs, er, cb)
  554.     else
  555.       self._readdirEntries(abs, entries, cb)
  556.   }
  557. }
  558.  
  559. Glob.prototype._readdirEntries = function (abs, entries, cb) {
  560.   if (this.aborted)
  561.     return
  562.  
  563.   // if we haven't asked to stat everything, then just
  564.   // assume that everything in there exists, so we can avoid
  565.   // having to stat it a second time.
  566.   if (!this.mark && !this.stat) {
  567.     for (var i = 0; i < entries.length; i ++) {
  568.       var e = entries[i]
  569.       if (abs === '/')
  570.         e = abs + e
  571.       else
  572.         e = abs + '/' + e
  573.       this.cache[e] = true
  574.     }
  575.   }
  576.  
  577.   this.cache[abs] = entries
  578.   return cb(null, entries)
  579. }
  580.  
  581. Glob.prototype._readdirError = function (f, er, cb) {
  582.   if (this.aborted)
  583.     return
  584.  
  585.   // handle errors, and cache the information
  586.   switch (er.code) {
  587.     case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205
  588.     case 'ENOTDIR': // totally normal. means it *does* exist.
  589.       var abs = this._makeAbs(f)
  590.       this.cache[abs] = 'FILE'
  591.       if (abs === this.cwdAbs) {
  592.         var error = new Error(er.code + ' invalid cwd ' + this.cwd)
  593.         error.path = this.cwd
  594.         error.code = er.code
  595.         this.emit('error', error)
  596.         this.abort()
  597.       }
  598.       break
  599.  
  600.     case 'ENOENT': // not terribly unusual
  601.     case 'ELOOP':
  602.     case 'ENAMETOOLONG':
  603.     case 'UNKNOWN':
  604.       this.cache[this._makeAbs(f)] = false
  605.       break
  606.  
  607.     default: // some unusual error.  Treat as failure.
  608.       this.cache[this._makeAbs(f)] = false
  609.       if (this.strict) {
  610.         this.emit('error', er)
  611.         // If the error is handled, then we abort
  612.         // if not, we threw out of here
  613.         this.abort()
  614.       }
  615.       if (!this.silent)
  616.         console.error('glob error', er)
  617.       break
  618.   }
  619.  
  620.   return cb()
  621. }
  622.  
  623. Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) {
  624.   var self = this
  625.   this._readdir(abs, inGlobStar, function (er, entries) {
  626.     self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb)
  627.   })
  628. }
  629.  
  630.  
  631. Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) {
  632.   //console.error('pgs2', prefix, remain[0], entries)
  633.  
  634.   // no entries means not a dir, so it can never have matches
  635.   // foo.txt/** doesn't match foo.txt
  636.   if (!entries)
  637.     return cb()
  638.  
  639.   // test without the globstar, and with every child both below
  640.   // and replacing the globstar.
  641.   var remainWithoutGlobStar = remain.slice(1)
  642.   var gspref = prefix ? [ prefix ] : []
  643.   var noGlobStar = gspref.concat(remainWithoutGlobStar)
  644.  
  645.   // the noGlobStar pattern exits the inGlobStar state
  646.   this._process(noGlobStar, index, false, cb)
  647.  
  648.   var isSym = this.symlinks[abs]
  649.   var len = entries.length
  650.  
  651.   // If it's a symlink, and we're in a globstar, then stop
  652.   if (isSym && inGlobStar)
  653.     return cb()
  654.  
  655.   for (var i = 0; i < len; i++) {
  656.     var e = entries[i]
  657.     if (e.charAt(0) === '.' && !this.dot)
  658.       continue
  659.  
  660.     // these two cases enter the inGlobStar state
  661.     var instead = gspref.concat(entries[i], remainWithoutGlobStar)
  662.     this._process(instead, index, true, cb)
  663.  
  664.     var below = gspref.concat(entries[i], remain)
  665.     this._process(below, index, true, cb)
  666.   }
  667.  
  668.   cb()
  669. }
  670.  
  671. Glob.prototype._processSimple = function (prefix, index, cb) {
  672.   // XXX review this.  Shouldn't it be doing the mounting etc
  673.   // before doing stat?  kinda weird?
  674.   var self = this
  675.   this._stat(prefix, function (er, exists) {
  676.     self._processSimple2(prefix, index, er, exists, cb)
  677.   })
  678. }
  679. Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) {
  680.  
  681.   //console.error('ps2', prefix, exists)
  682.  
  683.   if (!this.matches[index])
  684.     this.matches[index] = Object.create(null)
  685.  
  686.   // If it doesn't exist, then just mark the lack of results
  687.   if (!exists)
  688.     return cb()
  689.  
  690.   if (prefix && isAbsolute(prefix) && !this.nomount) {
  691.     var trail = /[\/\\]$/.test(prefix)
  692.     if (prefix.charAt(0) === '/') {
  693.       prefix = path.join(this.root, prefix)
  694.     } else {
  695.       prefix = path.resolve(this.root, prefix)
  696.       if (trail)
  697.         prefix += '/'
  698.     }
  699.   }
  700.  
  701.   if (process.platform === 'win32')
  702.     prefix = prefix.replace(/\\/g, '/')
  703.  
  704.   // Mark this as a match
  705.   this._emitMatch(index, prefix)
  706.   cb()
  707. }
  708.  
  709. // Returns either 'DIR', 'FILE', or false
  710. Glob.prototype._stat = function (f, cb) {
  711.   var abs = this._makeAbs(f)
  712.   var needDir = f.slice(-1) === '/'
  713.  
  714.   if (f.length > this.maxLength)
  715.     return cb()
  716.  
  717.   if (!this.stat && ownProp(this.cache, abs)) {
  718.     var c = this.cache[abs]
  719.  
  720.     if (Array.isArray(c))
  721.       c = 'DIR'
  722.  
  723.     // It exists, but maybe not how we need it
  724.     if (!needDir || c === 'DIR')
  725.       return cb(null, c)
  726.  
  727.     if (needDir && c === 'FILE')
  728.       return cb()
  729.  
  730.     // otherwise we have to stat, because maybe c=true
  731.     // if we know it exists, but not what it is.
  732.   }
  733.  
  734.   var exists
  735.   var stat = this.statCache[abs]
  736.   if (stat !== undefined) {
  737.     if (stat === false)
  738.       return cb(null, stat)
  739.     else {
  740.       var type = stat.isDirectory() ? 'DIR' : 'FILE'
  741.       if (needDir && type === 'FILE')
  742.         return cb()
  743.       else
  744.         return cb(null, type, stat)
  745.     }
  746.   }
  747.  
  748.   var self = this
  749.   var statcb = inflight('stat\0' + abs, lstatcb_)
  750.   if (statcb)
  751.     fs.lstat(abs, statcb)
  752.  
  753.   function lstatcb_ (er, lstat) {
  754.     if (lstat && lstat.isSymbolicLink()) {
  755.       // If it's a symlink, then treat it as the target, unless
  756.       // the target does not exist, then treat it as a file.
  757.       return fs.stat(abs, function (er, stat) {
  758.         if (er)
  759.           self._stat2(f, abs, null, lstat, cb)
  760.         else
  761.           self._stat2(f, abs, er, stat, cb)
  762.       })
  763.     } else {
  764.       self._stat2(f, abs, er, lstat, cb)
  765.     }
  766.   }
  767. }
  768.  
  769. Glob.prototype._stat2 = function (f, abs, er, stat, cb) {
  770.   if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) {
  771.     this.statCache[abs] = false
  772.     return cb()
  773.   }
  774.  
  775.   var needDir = f.slice(-1) === '/'
  776.   this.statCache[abs] = stat
  777.  
  778.   if (abs.slice(-1) === '/' && stat && !stat.isDirectory())
  779.     return cb(null, false, stat)
  780.  
  781.   var c = true
  782.   if (stat)
  783.     c = stat.isDirectory() ? 'DIR' : 'FILE'
  784.   this.cache[abs] = this.cache[abs] || c
  785.  
  786.   if (needDir && c === 'FILE')
  787.     return cb()
  788.  
  789.   return cb(null, c, stat)
  790. }

Paste-bin is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Raw Paste

Login or Register to edit or fork this paste. It's free.