JAVASCRIPT 27
Sync.js Guest on 25th April 2021 07:53:54 AM
  1. module.exports = globSync
  2. globSync.GlobSync = GlobSync
  3.  
  4. var fs = require('fs')
  5. var rp = require('fs.realpath')
  6. var minimatch = require('minimatch')
  7. var Minimatch = minimatch.Minimatch
  8. var Glob = require('./glob.js').Glob
  9. var util = require('util')
  10. var path = require('path')
  11. var assert = require('assert')
  12. var isAbsolute = require('path-is-absolute')
  13. var common = require('./common.js')
  14. var alphasort = common.alphasort
  15. var alphasorti = common.alphasorti
  16. var setopts = common.setopts
  17. var ownProp = common.ownProp
  18. var childrenIgnored = common.childrenIgnored
  19. var isIgnored = common.isIgnored
  20.  
  21. function globSync (pattern, options) {
  22.   if (typeof options === 'function' || arguments.length === 3)
  23.     throw new TypeError('callback provided to sync glob\n'+
  24.                         'See: https://github.com/isaacs/node-glob/issues/167')
  25.  
  26.   return new GlobSync(pattern, options).found
  27. }
  28.  
  29. function GlobSync (pattern, options) {
  30.   if (!pattern)
  31.     throw new Error('must provide pattern')
  32.  
  33.   if (typeof options === 'function' || arguments.length === 3)
  34.     throw new TypeError('callback provided to sync glob\n'+
  35.                         'See: https://github.com/isaacs/node-glob/issues/167')
  36.  
  37.   if (!(this instanceof GlobSync))
  38.     return new GlobSync(pattern, options)
  39.  
  40.   setopts(this, pattern, options)
  41.  
  42.   if (this.noprocess)
  43.     return this
  44.  
  45.   var n = this.minimatch.set.length
  46.   this.matches = new Array(n)
  47.   for (var i = 0; i < n; i ++) {
  48.     this._process(this.minimatch.set[i], i, false)
  49.   }
  50.   this._finish()
  51. }
  52.  
  53. GlobSync.prototype._finish = function () {
  54.   assert(this instanceof GlobSync)
  55.   if (this.realpath) {
  56.     var self = this
  57.     this.matches.forEach(function (matchset, index) {
  58.       var set = self.matches[index] = Object.create(null)
  59.       for (var p in matchset) {
  60.         try {
  61.           p = self._makeAbs(p)
  62.           var real = rp.realpathSync(p, self.realpathCache)
  63.           set[real] = true
  64.         } catch (er) {
  65.           if (er.syscall === 'stat')
  66.             set[self._makeAbs(p)] = true
  67.           else
  68.             throw er
  69.         }
  70.       }
  71.     })
  72.   }
  73.   common.finish(this)
  74. }
  75.  
  76.  
  77. GlobSync.prototype._process = function (pattern, index, inGlobStar) {
  78.   assert(this instanceof GlobSync)
  79.  
  80.   // Get the first [n] parts of pattern that are all strings.
  81.   var n = 0
  82.   while (typeof pattern[n] === 'string') {
  83.     n ++
  84.   }
  85.   // now n is the index of the first one that is *not* a string.
  86.  
  87.   // See if there's anything else
  88.   var prefix
  89.   switch (n) {
  90.     // if not, then this is rather simple
  91.     case pattern.length:
  92.       this._processSimple(pattern.join('/'), index)
  93.       return
  94.  
  95.     case 0:
  96.       // pattern *starts* with some non-trivial item.
  97.       // going to readdir(cwd), but not include the prefix in matches.
  98.       prefix = null
  99.       break
  100.  
  101.     default:
  102.       // pattern has some string bits in the front.
  103.       // whatever it starts with, whether that's 'absolute' like /foo/bar,
  104.       // or 'relative' like '../baz'
  105.       prefix = pattern.slice(0, n).join('/')
  106.       break
  107.   }
  108.  
  109.   var remain = pattern.slice(n)
  110.  
  111.   // get the list of entries.
  112.   var read
  113.   if (prefix === null)
  114.     read = '.'
  115.   else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) {
  116.     if (!prefix || !isAbsolute(prefix))
  117.       prefix = '/' + prefix
  118.     read = prefix
  119.   } else
  120.     read = prefix
  121.  
  122.   var abs = this._makeAbs(read)
  123.  
  124.   //if ignored, skip processing
  125.   if (childrenIgnored(this, read))
  126.     return
  127.  
  128.   var isGlobStar = remain[0] === minimatch.GLOBSTAR
  129.   if (isGlobStar)
  130.     this._processGlobStar(prefix, read, abs, remain, index, inGlobStar)
  131.   else
  132.     this._processReaddir(prefix, read, abs, remain, index, inGlobStar)
  133. }
  134.  
  135.  
  136. GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) {
  137.   var entries = this._readdir(abs, inGlobStar)
  138.  
  139.   // if the abs isn't a dir, then nothing can match!
  140.   if (!entries)
  141.     return
  142.  
  143.   // It will only match dot entries if it starts with a dot, or if
  144.   // dot is set.  Stuff like @(.foo|.bar) isn't allowed.
  145.   var pn = remain[0]
  146.   var negate = !!this.minimatch.negate
  147.   var rawGlob = pn._glob
  148.   var dotOk = this.dot || rawGlob.charAt(0) === '.'
  149.  
  150.   var matchedEntries = []
  151.   for (var i = 0; i < entries.length; i++) {
  152.     var e = entries[i]
  153.     if (e.charAt(0) !== '.' || dotOk) {
  154.       var m
  155.       if (negate && !prefix) {
  156.         m = !e.match(pn)
  157.       } else {
  158.         m = e.match(pn)
  159.       }
  160.       if (m)
  161.         matchedEntries.push(e)
  162.     }
  163.   }
  164.  
  165.   var len = matchedEntries.length
  166.   // If there are no matched entries, then nothing matches.
  167.   if (len === 0)
  168.     return
  169.  
  170.   // if this is the last remaining pattern bit, then no need for
  171.   // an additional stat *unless* the user has specified mark or
  172.   // stat explicitly.  We know they exist, since readdir returned
  173.   // them.
  174.  
  175.   if (remain.length === 1 && !this.mark && !this.stat) {
  176.     if (!this.matches[index])
  177.       this.matches[index] = Object.create(null)
  178.  
  179.     for (var i = 0; i < len; i ++) {
  180.       var e = matchedEntries[i]
  181.       if (prefix) {
  182.         if (prefix.slice(-1) !== '/')
  183.           e = prefix + '/' + e
  184.         else
  185.           e = prefix + e
  186.       }
  187.  
  188.       if (e.charAt(0) === '/' && !this.nomount) {
  189.         e = path.join(this.root, e)
  190.       }
  191.       this._emitMatch(index, e)
  192.     }
  193.     // This was the last one, and no stats were needed
  194.     return
  195.   }
  196.  
  197.   // now test all matched entries as stand-ins for that part
  198.   // of the pattern.
  199.   remain.shift()
  200.   for (var i = 0; i < len; i ++) {
  201.     var e = matchedEntries[i]
  202.     var newPattern
  203.     if (prefix)
  204.       newPattern = [prefix, e]
  205.     else
  206.       newPattern = [e]
  207.     this._process(newPattern.concat(remain), index, inGlobStar)
  208.   }
  209. }
  210.  
  211.  
  212. GlobSync.prototype._emitMatch = function (index, e) {
  213.   if (isIgnored(this, e))
  214.     return
  215.  
  216.   var abs = this._makeAbs(e)
  217.  
  218.   if (this.mark)
  219.     e = this._mark(e)
  220.  
  221.   if (this.absolute) {
  222.     e = abs
  223.   }
  224.  
  225.   if (this.matches[index][e])
  226.     return
  227.  
  228.   if (this.nodir) {
  229.     var c = this.cache[abs]
  230.     if (c === 'DIR' || Array.isArray(c))
  231.       return
  232.   }
  233.  
  234.   this.matches[index][e] = true
  235.  
  236.   if (this.stat)
  237.     this._stat(e)
  238. }
  239.  
  240.  
  241. GlobSync.prototype._readdirInGlobStar = function (abs) {
  242.   // follow all symlinked directories forever
  243.   // just proceed as if this is a non-globstar situation
  244.   if (this.follow)
  245.     return this._readdir(abs, false)
  246.  
  247.   var entries
  248.   var lstat
  249.   var stat
  250.   try {
  251.     lstat = fs.lstatSync(abs)
  252.   } catch (er) {
  253.     if (er.code === 'ENOENT') {
  254.       // lstat failed, doesn't exist
  255.       return null
  256.     }
  257.   }
  258.  
  259.   var isSym = lstat && lstat.isSymbolicLink()
  260.   this.symlinks[abs] = isSym
  261.  
  262.   // If it's not a symlink or a dir, then it's definitely a regular file.
  263.   // don't bother doing a readdir in that case.
  264.   if (!isSym && lstat && !lstat.isDirectory())
  265.     this.cache[abs] = 'FILE'
  266.   else
  267.     entries = this._readdir(abs, false)
  268.  
  269.   return entries
  270. }
  271.  
  272. GlobSync.prototype._readdir = function (abs, inGlobStar) {
  273.   var entries
  274.  
  275.   if (inGlobStar && !ownProp(this.symlinks, abs))
  276.     return this._readdirInGlobStar(abs)
  277.  
  278.   if (ownProp(this.cache, abs)) {
  279.     var c = this.cache[abs]
  280.     if (!c || c === 'FILE')
  281.       return null
  282.  
  283.     if (Array.isArray(c))
  284.       return c
  285.   }
  286.  
  287.   try {
  288.     return this._readdirEntries(abs, fs.readdirSync(abs))
  289.   } catch (er) {
  290.     this._readdirError(abs, er)
  291.     return null
  292.   }
  293. }
  294.  
  295. GlobSync.prototype._readdirEntries = function (abs, entries) {
  296.   // if we haven't asked to stat everything, then just
  297.   // assume that everything in there exists, so we can avoid
  298.   // having to stat it a second time.
  299.   if (!this.mark && !this.stat) {
  300.     for (var i = 0; i < entries.length; i ++) {
  301.       var e = entries[i]
  302.       if (abs === '/')
  303.         e = abs + e
  304.       else
  305.         e = abs + '/' + e
  306.       this.cache[e] = true
  307.     }
  308.   }
  309.  
  310.   this.cache[abs] = entries
  311.  
  312.   // mark and cache dir-ness
  313.   return entries
  314. }
  315.  
  316. GlobSync.prototype._readdirError = function (f, er) {
  317.   // handle errors, and cache the information
  318.   switch (er.code) {
  319.     case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205
  320.     case 'ENOTDIR': // totally normal. means it *does* exist.
  321.       var abs = this._makeAbs(f)
  322.       this.cache[abs] = 'FILE'
  323.       if (abs === this.cwdAbs) {
  324.         var error = new Error(er.code + ' invalid cwd ' + this.cwd)
  325.         error.path = this.cwd
  326.         error.code = er.code
  327.         throw error
  328.       }
  329.       break
  330.  
  331.     case 'ENOENT': // not terribly unusual
  332.     case 'ELOOP':
  333.     case 'ENAMETOOLONG':
  334.     case 'UNKNOWN':
  335.       this.cache[this._makeAbs(f)] = false
  336.       break
  337.  
  338.     default: // some unusual error.  Treat as failure.
  339.       this.cache[this._makeAbs(f)] = false
  340.       if (this.strict)
  341.         throw er
  342.       if (!this.silent)
  343.         console.error('glob error', er)
  344.       break
  345.   }
  346. }
  347.  
  348. GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) {
  349.  
  350.   var entries = this._readdir(abs, inGlobStar)
  351.  
  352.   // no entries means not a dir, so it can never have matches
  353.   // foo.txt/** doesn't match foo.txt
  354.   if (!entries)
  355.     return
  356.  
  357.   // test without the globstar, and with every child both below
  358.   // and replacing the globstar.
  359.   var remainWithoutGlobStar = remain.slice(1)
  360.   var gspref = prefix ? [ prefix ] : []
  361.   var noGlobStar = gspref.concat(remainWithoutGlobStar)
  362.  
  363.   // the noGlobStar pattern exits the inGlobStar state
  364.   this._process(noGlobStar, index, false)
  365.  
  366.   var len = entries.length
  367.   var isSym = this.symlinks[abs]
  368.  
  369.   // If it's a symlink, and we're in a globstar, then stop
  370.   if (isSym && inGlobStar)
  371.     return
  372.  
  373.   for (var i = 0; i < len; i++) {
  374.     var e = entries[i]
  375.     if (e.charAt(0) === '.' && !this.dot)
  376.       continue
  377.  
  378.     // these two cases enter the inGlobStar state
  379.     var instead = gspref.concat(entries[i], remainWithoutGlobStar)
  380.     this._process(instead, index, true)
  381.  
  382.     var below = gspref.concat(entries[i], remain)
  383.     this._process(below, index, true)
  384.   }
  385. }
  386.  
  387. GlobSync.prototype._processSimple = function (prefix, index) {
  388.   // XXX review this.  Shouldn't it be doing the mounting etc
  389.   // before doing stat?  kinda weird?
  390.   var exists = this._stat(prefix)
  391.  
  392.   if (!this.matches[index])
  393.     this.matches[index] = Object.create(null)
  394.  
  395.   // If it doesn't exist, then just mark the lack of results
  396.   if (!exists)
  397.     return
  398.  
  399.   if (prefix && isAbsolute(prefix) && !this.nomount) {
  400.     var trail = /[\/\\]$/.test(prefix)
  401.     if (prefix.charAt(0) === '/') {
  402.       prefix = path.join(this.root, prefix)
  403.     } else {
  404.       prefix = path.resolve(this.root, prefix)
  405.       if (trail)
  406.         prefix += '/'
  407.     }
  408.   }
  409.  
  410.   if (process.platform === 'win32')
  411.     prefix = prefix.replace(/\\/g, '/')
  412.  
  413.   // Mark this as a match
  414.   this._emitMatch(index, prefix)
  415. }
  416.  
  417. // Returns either 'DIR', 'FILE', or false
  418. GlobSync.prototype._stat = function (f) {
  419.   var abs = this._makeAbs(f)
  420.   var needDir = f.slice(-1) === '/'
  421.  
  422.   if (f.length > this.maxLength)
  423.     return false
  424.  
  425.   if (!this.stat && ownProp(this.cache, abs)) {
  426.     var c = this.cache[abs]
  427.  
  428.     if (Array.isArray(c))
  429.       c = 'DIR'
  430.  
  431.     // It exists, but maybe not how we need it
  432.     if (!needDir || c === 'DIR')
  433.       return c
  434.  
  435.     if (needDir && c === 'FILE')
  436.       return false
  437.  
  438.     // otherwise we have to stat, because maybe c=true
  439.     // if we know it exists, but not what it is.
  440.   }
  441.  
  442.   var exists
  443.   var stat = this.statCache[abs]
  444.   if (!stat) {
  445.     var lstat
  446.     try {
  447.       lstat = fs.lstatSync(abs)
  448.     } catch (er) {
  449.       if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) {
  450.         this.statCache[abs] = false
  451.         return false
  452.       }
  453.     }
  454.  
  455.     if (lstat && lstat.isSymbolicLink()) {
  456.       try {
  457.         stat = fs.statSync(abs)
  458.       } catch (er) {
  459.         stat = lstat
  460.       }
  461.     } else {
  462.       stat = lstat
  463.     }
  464.   }
  465.  
  466.   this.statCache[abs] = stat
  467.  
  468.   var c = true
  469.   if (stat)
  470.     c = stat.isDirectory() ? 'DIR' : 'FILE'
  471.  
  472.   this.cache[abs] = this.cache[abs] || c
  473.  
  474.   if (needDir && c === 'FILE')
  475.     return false
  476.  
  477.   return c
  478. }
  479.  
  480. GlobSync.prototype._mark = function (p) {
  481.   return common.mark(this, p)
  482. }
  483.  
  484. GlobSync.prototype._makeAbs = function (f) {
  485.   return common.makeAbs(this, f)
  486. }

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.