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