+3
-1
| language: node_js | ||
| node_js: | ||
| - 'iojs' | ||
| - '6' | ||
| - '5' | ||
| - '4' | ||
| - '0.12' | ||
| - '0.10' |
+8
-0
@@ -5,2 +5,10 @@ # Change Log | ||
| <a name="2.0.2"></a> | ||
| ## [2.0.2](https://github.com/mklabs/node-fileset/compare/v1.0.1...v2.0.2) (2016-06-27) | ||
| <a name="2.0.0"></a> | ||
| ## [2.0.0](https://github.com/mklabs/node-fileset/compare/v1.0.1...v2.0.0) (2016-06-26) | ||
| <a name="1.0.1"></a> | ||
@@ -7,0 +15,0 @@ ## [1.0.1](https://github.com/mklabs/node-fileset/compare/v1.0.0...v1.0.1) (2016-06-01) |
+3
-1
@@ -8,3 +8,3 @@ | ||
| test: | ||
| mocha -R spec test | ||
| cd test && ../node_modules/.bin/mocha -R spec . | ||
@@ -27,1 +27,3 @@ eslint: | ||
| npm publish | ||
| .PHONY: test |
+4
-4
| { | ||
| "name": "fileset", | ||
| "version": "1.0.1", | ||
| "version": "2.0.2", | ||
| "description": "Wrapper around miniglob / minimatch combo to allow multiple patterns matching and include-exclude ability", | ||
| "main": "./lib/fileset", | ||
| "scripts": { | ||
| "test": "bake test" | ||
| "test": "make test" | ||
| }, | ||
| "dependencies": { | ||
| "glob": "^7.0.3", | ||
| "minimatch": "^3.0.0" | ||
| "minimatch": "^3.0.2" | ||
| }, | ||
@@ -34,2 +34,2 @@ "devDependencies": { | ||
| "author": "mklabs" | ||
| } | ||
| } |
+19
-49
@@ -10,3 +10,3 @@ var assert = require('assert'); | ||
| assert.ok(results.length, 'should return at least one element'); | ||
| assert.equal(results.length, 2, 'actually, should return only two'); | ||
| assert.equal(results.length, 1, 'actually, should return only one'); | ||
| }); | ||
@@ -21,4 +21,3 @@ }); | ||
| assert.ok(results.length, 'should return at least one element'); | ||
| assert.equal(results.length, 7, 'actually, should return only 7'); | ||
| assert.equal(results.length, 3, 'actually, should return only 3'); | ||
| }); | ||
@@ -30,7 +29,7 @@ }); | ||
| it('returns the list of matching file in this repo', function(done) { | ||
| fileset('*.md', function(err, results) { | ||
| fileset('*.js', function(err, results) { | ||
| if(err) return done(err); | ||
| assert.ok(Array.isArray(results), 'should be an array'); | ||
| assert.ok(results.length, 'should return at least one element'); | ||
| assert.equal(results.length, 2, 'actually, should return only two'); | ||
| assert.equal(results.length, 1, 'actually, should return only two'); | ||
| done(); | ||
@@ -46,3 +45,3 @@ }); | ||
| assert.ok(Array.isArray(results), 'should be an array'); | ||
| assert.equal(results.length, 11); | ||
| assert.equal(results.length, 2); | ||
| done(); | ||
@@ -56,3 +55,3 @@ }); | ||
| assert.ok(Array.isArray(results), 'should be an array'); | ||
| assert.equal(results.length, 11); | ||
| assert.equal(results.length, 2); | ||
| done(); | ||
@@ -67,18 +66,7 @@ }); | ||
| assert.ok(Array.isArray(results), 'should be an array'); | ||
| assert.equal(results.length, 13); | ||
| assert.equal(results.length, 2); | ||
| assert.deepEqual(results, [ | ||
| 'CHANGELOG.md', | ||
| 'README.md', | ||
| 'lib/fileset.js', | ||
| 'test/fixtures/an (odd) filename.js', | ||
| 'test/fixtures/glob/common.js', | ||
| 'test/fixtures/glob/glob.js', | ||
| 'test/fixtures/glob/sync.js', | ||
| 'test/fixtures/minimatch/minimatch.js', | ||
| 'test/mocha.js', | ||
| 'tests/fixtures/an (odd) filename.js', | ||
| 'tests/helper.js', | ||
| 'tests/test-sync.js', | ||
| 'tests/test.js' | ||
| 'fixtures/an (odd) filename.js', | ||
| 'mocha.js' | ||
| ]); | ||
@@ -94,13 +82,7 @@ | ||
| assert.ok(Array.isArray(results), 'should be an array'); | ||
| assert.equal(results.length, 8); | ||
| assert.equal(results.length, 2); | ||
| assert.deepEqual(results, [ | ||
| 'lib/fileset.js', | ||
| 'test/fixtures/an (odd) filename.js', | ||
| 'test/fixtures/glob/common.js', | ||
| 'test/fixtures/glob/glob.js', | ||
| 'test/fixtures/glob/sync.js', | ||
| 'test/fixtures/minimatch/minimatch.js', | ||
| 'test/mocha.js', | ||
| 'tests/fixtures/an (odd) filename.js', | ||
| 'fixtures/an (odd) filename.js', | ||
| 'mocha.js' | ||
| ]); | ||
@@ -119,3 +101,3 @@ | ||
| assert.ok(Array.isArray(results), 'should be an array'); | ||
| assert.equal(results.length, 11); | ||
| assert.equal(results.length, 2); | ||
| done(); | ||
@@ -130,18 +112,7 @@ }); | ||
| assert.ok(Array.isArray(results), 'should be an array'); | ||
| assert.equal(results.length, 13); | ||
| assert.equal(results.length, 2); | ||
| assert.deepEqual(results, [ | ||
| 'CHANGELOG.md', | ||
| 'README.md', | ||
| 'lib/fileset.js', | ||
| 'test/fixtures/an (odd) filename.js', | ||
| 'test/fixtures/glob/common.js', | ||
| 'test/fixtures/glob/glob.js', | ||
| 'test/fixtures/glob/sync.js', | ||
| 'test/fixtures/minimatch/minimatch.js', | ||
| 'test/mocha.js', | ||
| 'tests/fixtures/an (odd) filename.js', | ||
| 'tests/helper.js', | ||
| 'tests/test-sync.js', | ||
| 'tests/test.js' | ||
| 'fixtures/an (odd) filename.js', | ||
| 'mocha.js' | ||
| ]); | ||
@@ -156,10 +127,9 @@ | ||
| it('match files passed as an array with odd filenames', function(done) { | ||
| fileset(['lib/*.js', 'test/fixtures/an (odd) filename.js'], ['node_modules/**']) | ||
| fileset(['fixtures/*.md', 'fixtures/an (odd) filename.js'], ['*.md']) | ||
| .on('error', done) | ||
| .on('end', function(results) { | ||
| assert.ok(Array.isArray(results), 'should be an array'); | ||
| assert.equal(results.length, 2); | ||
| assert.equal(results.length, 1); | ||
| assert.deepEqual(results, [ | ||
| 'lib/fileset.js', | ||
| 'test/fixtures/an (odd) filename.js', | ||
| 'fixtures/an (odd) filename.js', | ||
| ]); | ||
@@ -166,0 +136,0 @@ |
| exports.alphasort = alphasort | ||
| exports.alphasorti = alphasorti | ||
| exports.setopts = setopts | ||
| exports.ownProp = ownProp | ||
| exports.makeAbs = makeAbs | ||
| exports.finish = finish | ||
| exports.mark = mark | ||
| exports.isIgnored = isIgnored | ||
| exports.childrenIgnored = childrenIgnored | ||
| function ownProp (obj, field) { | ||
| return Object.prototype.hasOwnProperty.call(obj, field) | ||
| } | ||
| var path = require("path") | ||
| var minimatch = require("minimatch") | ||
| var isAbsolute = require("path-is-absolute") | ||
| var Minimatch = minimatch.Minimatch | ||
| function alphasorti (a, b) { | ||
| return a.toLowerCase().localeCompare(b.toLowerCase()) | ||
| } | ||
| function alphasort (a, b) { | ||
| return a.localeCompare(b) | ||
| } | ||
| function setupIgnores (self, options) { | ||
| self.ignore = options.ignore || [] | ||
| if (!Array.isArray(self.ignore)) | ||
| self.ignore = [self.ignore] | ||
| if (self.ignore.length) { | ||
| self.ignore = self.ignore.map(ignoreMap) | ||
| } | ||
| } | ||
| // ignore patterns are always in dot:true mode. | ||
| function ignoreMap (pattern) { | ||
| var gmatcher = null | ||
| if (pattern.slice(-3) === '/**') { | ||
| var gpattern = pattern.replace(/(\/\*\*)+$/, '') | ||
| gmatcher = new Minimatch(gpattern, { dot: true }) | ||
| } | ||
| return { | ||
| matcher: new Minimatch(pattern, { dot: true }), | ||
| gmatcher: gmatcher | ||
| } | ||
| } | ||
| function setopts (self, pattern, options) { | ||
| if (!options) | ||
| options = {} | ||
| // 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 | ||
| } | ||
| self.silent = !!options.silent | ||
| self.pattern = pattern | ||
| self.strict = options.strict !== false | ||
| self.realpath = !!options.realpath | ||
| self.realpathCache = options.realpathCache || Object.create(null) | ||
| self.follow = !!options.follow | ||
| self.dot = !!options.dot | ||
| self.mark = !!options.mark | ||
| self.nodir = !!options.nodir | ||
| if (self.nodir) | ||
| self.mark = true | ||
| self.sync = !!options.sync | ||
| self.nounique = !!options.nounique | ||
| self.nonull = !!options.nonull | ||
| self.nosort = !!options.nosort | ||
| self.nocase = !!options.nocase | ||
| self.stat = !!options.stat | ||
| self.noprocess = !!options.noprocess | ||
| self.maxLength = options.maxLength || Infinity | ||
| self.cache = options.cache || Object.create(null) | ||
| self.statCache = options.statCache || Object.create(null) | ||
| self.symlinks = options.symlinks || Object.create(null) | ||
| setupIgnores(self, options) | ||
| self.changedCwd = false | ||
| var cwd = process.cwd() | ||
| if (!ownProp(options, "cwd")) | ||
| self.cwd = cwd | ||
| else { | ||
| self.cwd = options.cwd | ||
| self.changedCwd = path.resolve(options.cwd) !== cwd | ||
| } | ||
| self.root = options.root || path.resolve(self.cwd, "/") | ||
| self.root = path.resolve(self.root) | ||
| if (process.platform === "win32") | ||
| self.root = self.root.replace(/\\/g, "/") | ||
| self.nomount = !!options.nomount | ||
| // disable comments and negation in Minimatch. | ||
| // Note that they are not supported in Glob itself anyway. | ||
| options.nonegate = true | ||
| options.nocomment = true | ||
| self.minimatch = new Minimatch(pattern, options) | ||
| self.options = self.minimatch.options | ||
| } | ||
| function finish (self) { | ||
| var nou = self.nounique | ||
| var all = nou ? [] : Object.create(null) | ||
| for (var i = 0, l = self.matches.length; i < l; i ++) { | ||
| var matches = self.matches[i] | ||
| if (!matches || Object.keys(matches).length === 0) { | ||
| if (self.nonull) { | ||
| // do like the shell, and spit out the literal glob | ||
| var literal = self.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 (!self.nosort) | ||
| all = all.sort(self.nocase ? alphasorti : alphasort) | ||
| // at *some* point we statted all of these | ||
| if (self.mark) { | ||
| for (var i = 0; i < all.length; i++) { | ||
| all[i] = self._mark(all[i]) | ||
| } | ||
| if (self.nodir) { | ||
| all = all.filter(function (e) { | ||
| return !(/\/$/.test(e)) | ||
| }) | ||
| } | ||
| } | ||
| if (self.ignore.length) | ||
| all = all.filter(function(m) { | ||
| return !isIgnored(self, m) | ||
| }) | ||
| self.found = all | ||
| } | ||
| function mark (self, p) { | ||
| var abs = makeAbs(self, p) | ||
| var c = self.cache[abs] | ||
| var m = p | ||
| if (c) { | ||
| var isDir = c === 'DIR' || Array.isArray(c) | ||
| var slash = p.slice(-1) === '/' | ||
| if (isDir && !slash) | ||
| m += '/' | ||
| else if (!isDir && slash) | ||
| m = m.slice(0, -1) | ||
| if (m !== p) { | ||
| var mabs = makeAbs(self, m) | ||
| self.statCache[mabs] = self.statCache[abs] | ||
| self.cache[mabs] = self.cache[abs] | ||
| } | ||
| } | ||
| return m | ||
| } | ||
| // lotta situps... | ||
| function makeAbs (self, f) { | ||
| var abs = f | ||
| if (f.charAt(0) === '/') { | ||
| abs = path.join(self.root, f) | ||
| } else if (isAbsolute(f) || f === '') { | ||
| abs = f | ||
| } else if (self.changedCwd) { | ||
| abs = path.resolve(self.cwd, f) | ||
| } else { | ||
| abs = path.resolve(f) | ||
| } | ||
| return abs | ||
| } | ||
| // Return true, if pattern ends with globstar '**', for the accompanying parent directory. | ||
| // Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents | ||
| function isIgnored (self, path) { | ||
| if (!self.ignore.length) | ||
| return false | ||
| return self.ignore.some(function(item) { | ||
| return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) | ||
| }) | ||
| } | ||
| function childrenIgnored (self, path) { | ||
| if (!self.ignore.length) | ||
| return false | ||
| return self.ignore.some(function(item) { | ||
| return !!(item.gmatcher && item.gmatcher.match(path)) | ||
| }) | ||
| } |
| // Approach: | ||
| // | ||
| // 1. Get the minimatch set | ||
| // 2. For each pattern in the set, PROCESS(pattern, false) | ||
| // 3. Store matches per-set, then uniq them | ||
| // | ||
| // PROCESS(pattern, inGlobStar) | ||
| // 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. | ||
| // | ||
| // If inGlobStar and PREFIX is symlink and points to dir | ||
| // set ENTRIES = [] | ||
| // else readdir(PREFIX) as ENTRIES | ||
| // If fail, END | ||
| // | ||
| // with ENTRIES | ||
| // 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 .. $], false) | ||
| // // handle other cases. | ||
| // for ENTRY in ENTRIES (not dotfiles) | ||
| // // attach globstar + tail onto the entry | ||
| // // Mark that this entry is a globstar match | ||
| // PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true) | ||
| // | ||
| // 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('fs') | ||
| var minimatch = require('minimatch') | ||
| var Minimatch = minimatch.Minimatch | ||
| var inherits = require('inherits') | ||
| var EE = require('events').EventEmitter | ||
| var path = require('path') | ||
| var assert = require('assert') | ||
| var isAbsolute = require('path-is-absolute') | ||
| var globSync = require('./sync.js') | ||
| var common = require('./common.js') | ||
| var alphasort = common.alphasort | ||
| var alphasorti = common.alphasorti | ||
| var setopts = common.setopts | ||
| var ownProp = common.ownProp | ||
| var inflight = require('inflight') | ||
| var util = require('util') | ||
| var childrenIgnored = common.childrenIgnored | ||
| var isIgnored = common.isIgnored | ||
| var once = require('once') | ||
| function glob (pattern, options, cb) { | ||
| if (typeof options === 'function') cb = options, options = {} | ||
| if (!options) options = {} | ||
| if (options.sync) { | ||
| if (cb) | ||
| throw new TypeError('callback provided to sync glob') | ||
| return globSync(pattern, options) | ||
| } | ||
| return new Glob(pattern, options, cb) | ||
| } | ||
| glob.sync = globSync | ||
| var GlobSync = glob.GlobSync = globSync.GlobSync | ||
| // old api surface | ||
| glob.glob = glob | ||
| function extend (origin, add) { | ||
| if (add === null || typeof add !== 'object') { | ||
| return origin | ||
| } | ||
| var keys = Object.keys(add) | ||
| var i = keys.length | ||
| while (i--) { | ||
| origin[keys[i]] = add[keys[i]] | ||
| } | ||
| return origin | ||
| } | ||
| glob.hasMagic = function (pattern, options_) { | ||
| var options = extend({}, options_) | ||
| options.noprocess = true | ||
| var g = new Glob(pattern, options) | ||
| var set = g.minimatch.set | ||
| if (set.length > 1) | ||
| return true | ||
| for (var j = 0; j < set[0].length; j++) { | ||
| if (typeof set[0][j] !== 'string') | ||
| return true | ||
| } | ||
| return false | ||
| } | ||
| glob.Glob = Glob | ||
| inherits(Glob, EE) | ||
| function Glob (pattern, options, cb) { | ||
| if (typeof options === 'function') { | ||
| cb = options | ||
| options = null | ||
| } | ||
| if (options && options.sync) { | ||
| if (cb) | ||
| throw new TypeError('callback provided to sync glob') | ||
| return new GlobSync(pattern, options) | ||
| } | ||
| if (!(this instanceof Glob)) | ||
| return new Glob(pattern, options, cb) | ||
| setopts(this, pattern, options) | ||
| this._didRealPath = false | ||
| // 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) | ||
| if (typeof cb === 'function') { | ||
| cb = once(cb) | ||
| this.on('error', cb) | ||
| this.on('end', function (matches) { | ||
| cb(null, matches) | ||
| }) | ||
| } | ||
| var self = this | ||
| var n = this.minimatch.set.length | ||
| this._processing = 0 | ||
| this.matches = new Array(n) | ||
| this._emitQueue = [] | ||
| this._processQueue = [] | ||
| this.paused = false | ||
| if (this.noprocess) | ||
| return this | ||
| if (n === 0) | ||
| return done() | ||
| for (var i = 0; i < n; i ++) { | ||
| this._process(this.minimatch.set[i], i, false, done) | ||
| } | ||
| function done () { | ||
| --self._processing | ||
| if (self._processing <= 0) | ||
| self._finish() | ||
| } | ||
| } | ||
| Glob.prototype._finish = function () { | ||
| assert(this instanceof Glob) | ||
| if (this.aborted) | ||
| return | ||
| if (this.realpath && !this._didRealpath) | ||
| return this._realpath() | ||
| common.finish(this) | ||
| this.emit('end', this.found) | ||
| } | ||
| Glob.prototype._realpath = function () { | ||
| if (this._didRealpath) | ||
| return | ||
| this._didRealpath = true | ||
| var n = this.matches.length | ||
| if (n === 0) | ||
| return this._finish() | ||
| var self = this | ||
| for (var i = 0; i < this.matches.length; i++) | ||
| this._realpathSet(i, next) | ||
| function next () { | ||
| if (--n === 0) | ||
| self._finish() | ||
| } | ||
| } | ||
| Glob.prototype._realpathSet = function (index, cb) { | ||
| var matchset = this.matches[index] | ||
| if (!matchset) | ||
| return cb() | ||
| var found = Object.keys(matchset) | ||
| var self = this | ||
| var n = found.length | ||
| if (n === 0) | ||
| return cb() | ||
| var set = this.matches[index] = Object.create(null) | ||
| found.forEach(function (p, i) { | ||
| // If there's a problem with the stat, then it means that | ||
| // one or more of the links in the realpath couldn't be | ||
| // resolved. just return the abs value in that case. | ||
| p = self._makeAbs(p) | ||
| fs.realpath(p, self.realpathCache, function (er, real) { | ||
| if (!er) | ||
| set[real] = true | ||
| else if (er.syscall === 'stat') | ||
| set[p] = true | ||
| else | ||
| self.emit('error', er) // srsly wtf right here | ||
| if (--n === 0) { | ||
| self.matches[index] = set | ||
| cb() | ||
| } | ||
| }) | ||
| }) | ||
| } | ||
| Glob.prototype._mark = function (p) { | ||
| return common.mark(this, p) | ||
| } | ||
| Glob.prototype._makeAbs = function (f) { | ||
| return common.makeAbs(this, f) | ||
| } | ||
| Glob.prototype.abort = function () { | ||
| this.aborted = true | ||
| this.emit('abort') | ||
| } | ||
| Glob.prototype.pause = function () { | ||
| if (!this.paused) { | ||
| this.paused = true | ||
| this.emit('pause') | ||
| } | ||
| } | ||
| Glob.prototype.resume = function () { | ||
| if (this.paused) { | ||
| this.emit('resume') | ||
| this.paused = false | ||
| if (this._emitQueue.length) { | ||
| var eq = this._emitQueue.slice(0) | ||
| this._emitQueue.length = 0 | ||
| for (var i = 0; i < eq.length; i ++) { | ||
| var e = eq[i] | ||
| this._emitMatch(e[0], e[1]) | ||
| } | ||
| } | ||
| if (this._processQueue.length) { | ||
| var pq = this._processQueue.slice(0) | ||
| this._processQueue.length = 0 | ||
| for (var i = 0; i < pq.length; i ++) { | ||
| var p = pq[i] | ||
| this._processing-- | ||
| this._process(p[0], p[1], p[2], p[3]) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Glob.prototype._process = function (pattern, index, inGlobStar, cb) { | ||
| assert(this instanceof Glob) | ||
| assert(typeof cb === 'function') | ||
| if (this.aborted) | ||
| return | ||
| this._processing++ | ||
| if (this.paused) { | ||
| this._processQueue.push([pattern, index, inGlobStar, cb]) | ||
| return | ||
| } | ||
| //console.error('PROCESS %d', this._processing, pattern) | ||
| // 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: | ||
| this._processSimple(pattern.join('/'), index, 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).join('/') | ||
| break | ||
| } | ||
| var remain = pattern.slice(n) | ||
| // get the list of entries. | ||
| var read | ||
| if (prefix === null) | ||
| read = '.' | ||
| else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { | ||
| if (!prefix || !isAbsolute(prefix)) | ||
| prefix = '/' + prefix | ||
| read = prefix | ||
| } else | ||
| read = prefix | ||
| var abs = this._makeAbs(read) | ||
| //if ignored, skip _processing | ||
| if (childrenIgnored(this, read)) | ||
| return cb() | ||
| var isGlobStar = remain[0] === minimatch.GLOBSTAR | ||
| if (isGlobStar) | ||
| this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb) | ||
| else | ||
| this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb) | ||
| } | ||
| Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) { | ||
| var self = this | ||
| this._readdir(abs, inGlobStar, function (er, entries) { | ||
| return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb) | ||
| }) | ||
| } | ||
| Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { | ||
| // if the abs isn't a dir, then nothing can match! | ||
| if (!entries) | ||
| return cb() | ||
| // 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 = remain[0] | ||
| var negate = !!this.minimatch.negate | ||
| var rawGlob = pn._glob | ||
| var dotOk = this.dot || rawGlob.charAt(0) === '.' | ||
| var matchedEntries = [] | ||
| for (var i = 0; i < entries.length; i++) { | ||
| var e = entries[i] | ||
| if (e.charAt(0) !== '.' || dotOk) { | ||
| var m | ||
| if (negate && !prefix) { | ||
| m = !e.match(pn) | ||
| } else { | ||
| m = e.match(pn) | ||
| } | ||
| if (m) | ||
| matchedEntries.push(e) | ||
| } | ||
| } | ||
| //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) | ||
| var len = matchedEntries.length | ||
| // If there are no matched entries, then nothing matches. | ||
| if (len === 0) | ||
| return cb() | ||
| // if this is the last remaining pattern bit, then no need for | ||
| // an additional stat *unless* the user has specified mark or | ||
| // stat explicitly. We know they exist, since readdir returned | ||
| // them. | ||
| if (remain.length === 1 && !this.mark && !this.stat) { | ||
| if (!this.matches[index]) | ||
| this.matches[index] = Object.create(null) | ||
| for (var i = 0; i < len; i ++) { | ||
| var e = matchedEntries[i] | ||
| if (prefix) { | ||
| if (prefix !== '/') | ||
| e = prefix + '/' + e | ||
| else | ||
| e = prefix + e | ||
| } | ||
| if (e.charAt(0) === '/' && !this.nomount) { | ||
| e = path.join(this.root, e) | ||
| } | ||
| this._emitMatch(index, e) | ||
| } | ||
| // This was the last one, and no stats were needed | ||
| return cb() | ||
| } | ||
| // now test all matched entries as stand-ins for that part | ||
| // of the pattern. | ||
| remain.shift() | ||
| for (var i = 0; i < len; i ++) { | ||
| var e = matchedEntries[i] | ||
| var newPattern | ||
| if (prefix) { | ||
| if (prefix !== '/') | ||
| e = prefix + '/' + e | ||
| else | ||
| e = prefix + e | ||
| } | ||
| this._process([e].concat(remain), index, inGlobStar, cb) | ||
| } | ||
| cb() | ||
| } | ||
| Glob.prototype._emitMatch = function (index, e) { | ||
| if (this.aborted) | ||
| return | ||
| if (this.matches[index][e]) | ||
| return | ||
| if (isIgnored(this, e)) | ||
| return | ||
| if (this.paused) { | ||
| this._emitQueue.push([index, e]) | ||
| return | ||
| } | ||
| var abs = this._makeAbs(e) | ||
| if (this.nodir) { | ||
| var c = this.cache[abs] | ||
| if (c === 'DIR' || Array.isArray(c)) | ||
| return | ||
| } | ||
| if (this.mark) | ||
| e = this._mark(e) | ||
| this.matches[index][e] = true | ||
| var st = this.statCache[abs] | ||
| if (st) | ||
| this.emit('stat', e, st) | ||
| this.emit('match', e) | ||
| } | ||
| Glob.prototype._readdirInGlobStar = function (abs, cb) { | ||
| if (this.aborted) | ||
| return | ||
| // follow all symlinked directories forever | ||
| // just proceed as if this is a non-globstar situation | ||
| if (this.follow) | ||
| return this._readdir(abs, false, cb) | ||
| var lstatkey = 'lstat\0' + abs | ||
| var self = this | ||
| var lstatcb = inflight(lstatkey, lstatcb_) | ||
| if (lstatcb) | ||
| fs.lstat(abs, lstatcb) | ||
| function lstatcb_ (er, lstat) { | ||
| if (er) | ||
| return cb() | ||
| var isSym = lstat.isSymbolicLink() | ||
| self.symlinks[abs] = isSym | ||
| // If it's not a symlink or a dir, then it's definitely a regular file. | ||
| // don't bother doing a readdir in that case. | ||
| if (!isSym && !lstat.isDirectory()) { | ||
| self.cache[abs] = 'FILE' | ||
| cb() | ||
| } else | ||
| self._readdir(abs, false, cb) | ||
| } | ||
| } | ||
| Glob.prototype._readdir = function (abs, inGlobStar, cb) { | ||
| if (this.aborted) | ||
| return | ||
| cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) | ||
| if (!cb) | ||
| return | ||
| //console.error('RD %j %j', +inGlobStar, abs) | ||
| if (inGlobStar && !ownProp(this.symlinks, abs)) | ||
| return this._readdirInGlobStar(abs, cb) | ||
| if (ownProp(this.cache, abs)) { | ||
| var c = this.cache[abs] | ||
| if (!c || c === 'FILE') | ||
| return cb() | ||
| if (Array.isArray(c)) | ||
| return cb(null, c) | ||
| } | ||
| var self = this | ||
| fs.readdir(abs, readdirCb(this, abs, cb)) | ||
| } | ||
| function readdirCb (self, abs, cb) { | ||
| return function (er, entries) { | ||
| if (er) | ||
| self._readdirError(abs, er, cb) | ||
| else | ||
| self._readdirEntries(abs, entries, cb) | ||
| } | ||
| } | ||
| Glob.prototype._readdirEntries = function (abs, entries, cb) { | ||
| if (this.aborted) | ||
| return | ||
| // if we haven't asked to stat everything, then just | ||
| // assume that everything in there exists, so we can avoid | ||
| // having to stat it a second time. | ||
| if (!this.mark && !this.stat) { | ||
| for (var i = 0; i < entries.length; i ++) { | ||
| var e = entries[i] | ||
| if (abs === '/') | ||
| e = abs + e | ||
| else | ||
| e = abs + '/' + e | ||
| this.cache[e] = true | ||
| } | ||
| } | ||
| this.cache[abs] = entries | ||
| return cb(null, entries) | ||
| } | ||
| Glob.prototype._readdirError = function (f, er, cb) { | ||
| if (this.aborted) | ||
| return | ||
| // handle errors, and cache the information | ||
| switch (er.code) { | ||
| case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 | ||
| case 'ENOTDIR': // totally normal. means it *does* exist. | ||
| this.cache[this._makeAbs(f)] = 'FILE' | ||
| break | ||
| case 'ENOENT': // not terribly unusual | ||
| case 'ELOOP': | ||
| case 'ENAMETOOLONG': | ||
| case 'UNKNOWN': | ||
| this.cache[this._makeAbs(f)] = false | ||
| break | ||
| default: // some unusual error. Treat as failure. | ||
| this.cache[this._makeAbs(f)] = false | ||
| if (this.strict) { | ||
| this.emit('error', er) | ||
| // If the error is handled, then we abort | ||
| // if not, we threw out of here | ||
| this.abort() | ||
| } | ||
| if (!this.silent) | ||
| console.error('glob error', er) | ||
| break | ||
| } | ||
| return cb() | ||
| } | ||
| Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) { | ||
| var self = this | ||
| this._readdir(abs, inGlobStar, function (er, entries) { | ||
| self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb) | ||
| }) | ||
| } | ||
| Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { | ||
| //console.error('pgs2', prefix, remain[0], entries) | ||
| // no entries means not a dir, so it can never have matches | ||
| // foo.txt/** doesn't match foo.txt | ||
| if (!entries) | ||
| return cb() | ||
| // test without the globstar, and with every child both below | ||
| // and replacing the globstar. | ||
| var remainWithoutGlobStar = remain.slice(1) | ||
| var gspref = prefix ? [ prefix ] : [] | ||
| var noGlobStar = gspref.concat(remainWithoutGlobStar) | ||
| // the noGlobStar pattern exits the inGlobStar state | ||
| this._process(noGlobStar, index, false, cb) | ||
| var isSym = this.symlinks[abs] | ||
| var len = entries.length | ||
| // If it's a symlink, and we're in a globstar, then stop | ||
| if (isSym && inGlobStar) | ||
| return cb() | ||
| for (var i = 0; i < len; i++) { | ||
| var e = entries[i] | ||
| if (e.charAt(0) === '.' && !this.dot) | ||
| continue | ||
| // these two cases enter the inGlobStar state | ||
| var instead = gspref.concat(entries[i], remainWithoutGlobStar) | ||
| this._process(instead, index, true, cb) | ||
| var below = gspref.concat(entries[i], remain) | ||
| this._process(below, index, true, cb) | ||
| } | ||
| cb() | ||
| } | ||
| Glob.prototype._processSimple = function (prefix, index, cb) { | ||
| // XXX review this. Shouldn't it be doing the mounting etc | ||
| // before doing stat? kinda weird? | ||
| var self = this | ||
| this._stat(prefix, function (er, exists) { | ||
| self._processSimple2(prefix, index, er, exists, cb) | ||
| }) | ||
| } | ||
| Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) { | ||
| //console.error('ps2', prefix, exists) | ||
| if (!this.matches[index]) | ||
| this.matches[index] = Object.create(null) | ||
| // If it doesn't exist, then just mark the lack of results | ||
| if (!exists) | ||
| return cb() | ||
| if (prefix && isAbsolute(prefix) && !this.nomount) { | ||
| var trail = /[\/\\]$/.test(prefix) | ||
| if (prefix.charAt(0) === '/') { | ||
| prefix = path.join(this.root, prefix) | ||
| } else { | ||
| prefix = path.resolve(this.root, prefix) | ||
| if (trail) | ||
| prefix += '/' | ||
| } | ||
| } | ||
| if (process.platform === 'win32') | ||
| prefix = prefix.replace(/\\/g, '/') | ||
| // Mark this as a match | ||
| this._emitMatch(index, prefix) | ||
| cb() | ||
| } | ||
| // Returns either 'DIR', 'FILE', or false | ||
| Glob.prototype._stat = function (f, cb) { | ||
| var abs = this._makeAbs(f) | ||
| var needDir = f.slice(-1) === '/' | ||
| if (f.length > this.maxLength) | ||
| return cb() | ||
| if (!this.stat && ownProp(this.cache, abs)) { | ||
| var c = this.cache[abs] | ||
| if (Array.isArray(c)) | ||
| c = 'DIR' | ||
| // It exists, but maybe not how we need it | ||
| if (!needDir || c === 'DIR') | ||
| return cb(null, c) | ||
| if (needDir && c === 'FILE') | ||
| return cb() | ||
| // otherwise we have to stat, because maybe c=true | ||
| // if we know it exists, but not what it is. | ||
| } | ||
| var exists | ||
| var stat = this.statCache[abs] | ||
| if (stat !== undefined) { | ||
| if (stat === false) | ||
| return cb(null, stat) | ||
| else { | ||
| var type = stat.isDirectory() ? 'DIR' : 'FILE' | ||
| if (needDir && type === 'FILE') | ||
| return cb() | ||
| else | ||
| return cb(null, type, stat) | ||
| } | ||
| } | ||
| var self = this | ||
| var statcb = inflight('stat\0' + abs, lstatcb_) | ||
| if (statcb) | ||
| fs.lstat(abs, statcb) | ||
| function lstatcb_ (er, lstat) { | ||
| if (lstat && lstat.isSymbolicLink()) { | ||
| // If it's a symlink, then treat it as the target, unless | ||
| // the target does not exist, then treat it as a file. | ||
| return fs.stat(abs, function (er, stat) { | ||
| if (er) | ||
| self._stat2(f, abs, null, lstat, cb) | ||
| else | ||
| self._stat2(f, abs, er, stat, cb) | ||
| }) | ||
| } else { | ||
| self._stat2(f, abs, er, lstat, cb) | ||
| } | ||
| } | ||
| } | ||
| Glob.prototype._stat2 = function (f, abs, er, stat, cb) { | ||
| if (er) { | ||
| this.statCache[abs] = false | ||
| return cb() | ||
| } | ||
| var needDir = f.slice(-1) === '/' | ||
| this.statCache[abs] = stat | ||
| if (abs.slice(-1) === '/' && !stat.isDirectory()) | ||
| return cb(null, false, stat) | ||
| var c = stat.isDirectory() ? 'DIR' : 'FILE' | ||
| this.cache[abs] = this.cache[abs] || c | ||
| if (needDir && c !== 'DIR') | ||
| return cb() | ||
| return cb(null, c, stat) | ||
| } |
| The ISC License | ||
| Copyright (c) Isaac Z. Schlueter and Contributors | ||
| Permission to use, copy, modify, and/or distribute this software for any | ||
| purpose with or without fee is hereby granted, provided that the above | ||
| copyright notice and this permission notice appear in all copies. | ||
| THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR | ||
| IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| { | ||
| "_args": [ | ||
| [ | ||
| "glob@^6.0.3", | ||
| "/home/mk/src/mklabs/node-fileset" | ||
| ] | ||
| ], | ||
| "_from": "glob@>=6.0.3 <7.0.0", | ||
| "_id": "glob@6.0.4", | ||
| "_inCache": true, | ||
| "_installable": true, | ||
| "_location": "/glob", | ||
| "_nodeVersion": "4.0.0", | ||
| "_npmUser": { | ||
| "email": "i@izs.me", | ||
| "name": "isaacs" | ||
| }, | ||
| "_npmVersion": "2.14.15", | ||
| "_phantomChildren": {}, | ||
| "_requested": { | ||
| "name": "glob", | ||
| "raw": "glob@^6.0.3", | ||
| "rawSpec": "^6.0.3", | ||
| "scope": null, | ||
| "spec": ">=6.0.3 <7.0.0", | ||
| "type": "range" | ||
| }, | ||
| "_requiredBy": [ | ||
| "/", | ||
| "/globby" | ||
| ], | ||
| "_resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", | ||
| "_shasum": "0f08860f6a155127b2fadd4f9ce24b1aab6e4d22", | ||
| "_shrinkwrap": null, | ||
| "_spec": "glob@^6.0.3", | ||
| "_where": "/home/mk/src/mklabs/node-fileset", | ||
| "author": { | ||
| "email": "i@izs.me", | ||
| "name": "Isaac Z. Schlueter", | ||
| "url": "http://blog.izs.me/" | ||
| }, | ||
| "bugs": { | ||
| "url": "https://github.com/isaacs/node-glob/issues" | ||
| }, | ||
| "dependencies": { | ||
| "inflight": "^1.0.4", | ||
| "inherits": "2", | ||
| "minimatch": "2 || 3", | ||
| "once": "^1.3.0", | ||
| "path-is-absolute": "^1.0.0" | ||
| }, | ||
| "description": "a little globber", | ||
| "devDependencies": { | ||
| "mkdirp": "0", | ||
| "rimraf": "^2.2.8", | ||
| "tap": "^5.0.0", | ||
| "tick": "0.0.6" | ||
| }, | ||
| "directories": {}, | ||
| "dist": { | ||
| "shasum": "0f08860f6a155127b2fadd4f9ce24b1aab6e4d22", | ||
| "tarball": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz" | ||
| }, | ||
| "engines": { | ||
| "node": "*" | ||
| }, | ||
| "files": [ | ||
| "glob.js", | ||
| "sync.js", | ||
| "common.js" | ||
| ], | ||
| "gitHead": "3bd419c538737e56fda7e21c21ff52ca0c198df6", | ||
| "homepage": "https://github.com/isaacs/node-glob#readme", | ||
| "license": "ISC", | ||
| "main": "glob.js", | ||
| "maintainers": [ | ||
| { | ||
| "email": "i@izs.me", | ||
| "name": "isaacs" | ||
| } | ||
| ], | ||
| "name": "glob", | ||
| "optionalDependencies": {}, | ||
| "readme": "ERROR: No README data found!", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git://github.com/isaacs/node-glob.git" | ||
| }, | ||
| "scripts": { | ||
| "bench": "bash benchmark.sh", | ||
| "benchclean": "node benchclean.js", | ||
| "prepublish": "npm run benchclean", | ||
| "prof": "bash prof.sh && cat profile.txt", | ||
| "profclean": "rm -f v8.log profile.txt", | ||
| "test": "tap test/*.js --cov", | ||
| "test-regen": "npm run profclean && TEST_REGEN=1 node test/00-setup.js" | ||
| }, | ||
| "version": "6.0.4" | ||
| } |
| # Glob | ||
| Match files using the patterns the shell uses, like stars and stuff. | ||
| [](https://travis-ci.org/isaacs/node-glob/) [](https://ci.appveyor.com/project/isaacs/node-glob) [](https://coveralls.io/github/isaacs/node-glob?branch=master) | ||
| This is a glob implementation in JavaScript. It uses the `minimatch` | ||
| library to do its matching. | ||
|  | ||
| ## Usage | ||
| ```javascript | ||
| var glob = require("glob") | ||
| // options is optional | ||
| glob("**/*.js", options, function (er, files) { | ||
| // files is an array of filenames. | ||
| // If the `nonull` option is set, and nothing | ||
| // was found, then files is ["**/*.js"] | ||
| // er is an error object or null. | ||
| }) | ||
| ``` | ||
| ## Glob Primer | ||
| "Globs" are the patterns you type when you do stuff like `ls *.js` on | ||
| the command line, or put `build/*` in a `.gitignore` file. | ||
| Before parsing the path part patterns, braced sections are expanded | ||
| into a set. Braced sections start with `{` and end with `}`, with any | ||
| number of comma-delimited sections within. Braced sections may contain | ||
| slash characters, so `a{/b/c,bcd}` would expand into `a/b/c` and `abcd`. | ||
| The following characters have special magic meaning when used in a | ||
| path portion: | ||
| * `*` Matches 0 or more characters in a single path portion | ||
| * `?` Matches 1 character | ||
| * `[...]` Matches a range of characters, similar to a RegExp range. | ||
| If the first character of the range is `!` or `^` then it matches | ||
| any character not in the range. | ||
| * `!(pattern|pattern|pattern)` Matches anything that does not match | ||
| any of the patterns provided. | ||
| * `?(pattern|pattern|pattern)` Matches zero or one occurrence of the | ||
| patterns provided. | ||
| * `+(pattern|pattern|pattern)` Matches one or more occurrences of the | ||
| patterns provided. | ||
| * `*(a|b|c)` Matches zero or more occurrences of the patterns provided | ||
| * `@(pattern|pat*|pat?erN)` Matches exactly one of the patterns | ||
| provided | ||
| * `**` If a "globstar" is alone in a path portion, then it matches | ||
| zero or more directories and subdirectories searching for matches. | ||
| It does not crawl symlinked directories. | ||
| ### Dots | ||
| If a file or directory path portion has a `.` as the first character, | ||
| then it will not match any glob pattern unless that pattern's | ||
| corresponding path part also has a `.` as its first character. | ||
| For example, the pattern `a/.*/c` would match the file at `a/.b/c`. | ||
| However the pattern `a/*/c` would not, because `*` does not start with | ||
| a dot character. | ||
| You can make glob treat dots as normal characters by setting | ||
| `dot:true` in the options. | ||
| ### Basename Matching | ||
| If you set `matchBase:true` in the options, and the pattern has no | ||
| slashes in it, then it will seek for any file anywhere in the tree | ||
| with a matching basename. For example, `*.js` would match | ||
| `test/simple/basic.js`. | ||
| ### Empty Sets | ||
| If no matching files are found, then an empty array is returned. This | ||
| differs from the shell, where the pattern itself is returned. For | ||
| example: | ||
| $ echo a*s*d*f | ||
| a*s*d*f | ||
| To get the bash-style behavior, set the `nonull:true` in the options. | ||
| ### See Also: | ||
| * `man sh` | ||
| * `man bash` (Search for "Pattern Matching") | ||
| * `man 3 fnmatch` | ||
| * `man 5 gitignore` | ||
| * [minimatch documentation](https://github.com/isaacs/minimatch) | ||
| ## glob.hasMagic(pattern, [options]) | ||
| Returns `true` if there are any special characters in the pattern, and | ||
| `false` otherwise. | ||
| Note that the options affect the results. If `noext:true` is set in | ||
| the options object, then `+(a|b)` will not be considered a magic | ||
| pattern. If the pattern has a brace expansion, like `a/{b/c,x/y}` | ||
| then that is considered magical, unless `nobrace:true` is set in the | ||
| options. | ||
| ## glob(pattern, [options], cb) | ||
| * `pattern` `{String}` Pattern to be matched | ||
| * `options` `{Object}` | ||
| * `cb` `{Function}` | ||
| * `err` `{Error | null}` | ||
| * `matches` `{Array<String>}` filenames found matching the pattern | ||
| Perform an asynchronous glob search. | ||
| ## glob.sync(pattern, [options]) | ||
| * `pattern` `{String}` Pattern to be matched | ||
| * `options` `{Object}` | ||
| * return: `{Array<String>}` filenames found matching the pattern | ||
| Perform a synchronous glob search. | ||
| ## Class: glob.Glob | ||
| Create a Glob object by instantiating the `glob.Glob` class. | ||
| ```javascript | ||
| var Glob = require("glob").Glob | ||
| var mg = new Glob(pattern, options, cb) | ||
| ``` | ||
| It's an EventEmitter, and starts walking the filesystem to find matches | ||
| immediately. | ||
| ### new glob.Glob(pattern, [options], [cb]) | ||
| * `pattern` `{String}` pattern to search for | ||
| * `options` `{Object}` | ||
| * `cb` `{Function}` Called when an error occurs, or matches are found | ||
| * `err` `{Error | null}` | ||
| * `matches` `{Array<String>}` filenames found matching the pattern | ||
| Note that if the `sync` flag is set in the options, then matches will | ||
| be immediately available on the `g.found` member. | ||
| ### Properties | ||
| * `minimatch` The minimatch object that the glob uses. | ||
| * `options` The options object passed in. | ||
| * `aborted` Boolean which is set to true when calling `abort()`. There | ||
| is no way at this time to continue a glob search after aborting, but | ||
| you can re-use the statCache to avoid having to duplicate syscalls. | ||
| * `cache` Convenience object. Each field has the following possible | ||
| values: | ||
| * `false` - Path does not exist | ||
| * `true` - Path exists | ||
| * `'FILE'` - Path exists, and is not a directory | ||
| * `'DIR'` - Path exists, and is a directory | ||
| * `[file, entries, ...]` - Path exists, is a directory, and the | ||
| array value is the results of `fs.readdir` | ||
| * `statCache` Cache of `fs.stat` results, to prevent statting the same | ||
| path multiple times. | ||
| * `symlinks` A record of which paths are symbolic links, which is | ||
| relevant in resolving `**` patterns. | ||
| * `realpathCache` An optional object which is passed to `fs.realpath` | ||
| to minimize unnecessary syscalls. It is stored on the instantiated | ||
| Glob object, and may be re-used. | ||
| ### Events | ||
| * `end` When the matching is finished, this is emitted with all the | ||
| matches found. If the `nonull` option is set, and no match was found, | ||
| then the `matches` list contains the original pattern. The matches | ||
| are sorted, unless the `nosort` flag is set. | ||
| * `match` Every time a match is found, this is emitted with the specific | ||
| thing that matched. It is not deduplicated or resolved to a realpath. | ||
| * `error` Emitted when an unexpected error is encountered, or whenever | ||
| any fs error occurs if `options.strict` is set. | ||
| * `abort` When `abort()` is called, this event is raised. | ||
| ### Methods | ||
| * `pause` Temporarily stop the search | ||
| * `resume` Resume the search | ||
| * `abort` Stop the search forever | ||
| ### Options | ||
| All the options that can be passed to Minimatch can also be passed to | ||
| Glob to change pattern matching behavior. Also, some have been added, | ||
| or have glob-specific ramifications. | ||
| All options are false by default, unless otherwise noted. | ||
| All options are added to the Glob object, as well. | ||
| If you are running many `glob` operations, you can pass a Glob object | ||
| as the `options` argument to a subsequent operation to shortcut some | ||
| `stat` and `readdir` calls. At the very least, you may pass in shared | ||
| `symlinks`, `statCache`, `realpathCache`, and `cache` options, so that | ||
| parallel glob operations will be sped up by sharing information about | ||
| the filesystem. | ||
| * `cwd` The current working directory in which to search. Defaults | ||
| to `process.cwd()`. | ||
| * `root` The place where patterns starting with `/` will be mounted | ||
| onto. Defaults to `path.resolve(options.cwd, "/")` (`/` on Unix | ||
| systems, and `C:\` or some such on Windows.) | ||
| * `dot` Include `.dot` files in normal matches and `globstar` matches. | ||
| Note that an explicit dot in a portion of the pattern will always | ||
| match dot files. | ||
| * `nomount` By default, a pattern starting with a forward-slash will be | ||
| "mounted" onto the root setting, so that a valid filesystem path is | ||
| returned. Set this flag to disable that behavior. | ||
| * `mark` Add a `/` character to directory matches. Note that this | ||
| requires additional stat calls. | ||
| * `nosort` Don't sort the results. | ||
| * `stat` Set to true to stat *all* results. This reduces performance | ||
| somewhat, and is completely unnecessary, unless `readdir` is presumed | ||
| to be an untrustworthy indicator of file existence. | ||
| * `silent` When an unusual error is encountered when attempting to | ||
| read a directory, a warning will be printed to stderr. Set the | ||
| `silent` option to true to suppress these warnings. | ||
| * `strict` When an unusual error is encountered when attempting to | ||
| read a directory, the process will just continue on in search of | ||
| other matches. Set the `strict` option to raise an error in these | ||
| cases. | ||
| * `cache` See `cache` property above. Pass in a previously generated | ||
| cache object to save some fs calls. | ||
| * `statCache` A cache of results of filesystem information, to prevent | ||
| unnecessary stat calls. While it should not normally be necessary | ||
| to set this, you may pass the statCache from one glob() call to the | ||
| options object of another, if you know that the filesystem will not | ||
| change between calls. (See "Race Conditions" below.) | ||
| * `symlinks` A cache of known symbolic links. You may pass in a | ||
| previously generated `symlinks` object to save `lstat` calls when | ||
| resolving `**` matches. | ||
| * `sync` DEPRECATED: use `glob.sync(pattern, opts)` instead. | ||
| * `nounique` In some cases, brace-expanded patterns can result in the | ||
| same file showing up multiple times in the result set. By default, | ||
| this implementation prevents duplicates in the result set. Set this | ||
| flag to disable that behavior. | ||
| * `nonull` Set to never return an empty set, instead returning a set | ||
| containing the pattern itself. This is the default in glob(3). | ||
| * `debug` Set to enable debug logging in minimatch and glob. | ||
| * `nobrace` Do not expand `{a,b}` and `{1..3}` brace sets. | ||
| * `noglobstar` Do not match `**` against multiple filenames. (Ie, | ||
| treat it as a normal `*` instead.) | ||
| * `noext` Do not match `+(a|b)` "extglob" patterns. | ||
| * `nocase` Perform a case-insensitive match. Note: on | ||
| case-insensitive filesystems, non-magic patterns will match by | ||
| default, since `stat` and `readdir` will not raise errors. | ||
| * `matchBase` Perform a basename-only match if the pattern does not | ||
| contain any slash characters. That is, `*.js` would be treated as | ||
| equivalent to `**/*.js`, matching all js files in all directories. | ||
| * `nodir` Do not match directories, only files. (Note: to match | ||
| *only* directories, simply put a `/` at the end of the pattern.) | ||
| * `ignore` Add a pattern or an array of glob patterns to exclude matches. | ||
| Note: `ignore` patterns are *always* in `dot:true` mode, regardless | ||
| of any other settings. | ||
| * `follow` Follow symlinked directories when expanding `**` patterns. | ||
| Note that this can result in a lot of duplicate references in the | ||
| presence of cyclic links. | ||
| * `realpath` Set to true to call `fs.realpath` on all of the results. | ||
| In the case of a symlink that cannot be resolved, the full absolute | ||
| path to the matched entry is returned (though it will usually be a | ||
| broken symlink) | ||
| ## Comparisons to other fnmatch/glob implementations | ||
| While strict compliance with the existing standards is a worthwhile | ||
| goal, some discrepancies exist between node-glob and other | ||
| implementations, and are intentional. | ||
| The double-star character `**` is supported by default, unless the | ||
| `noglobstar` flag is set. This is supported in the manner of bsdglob | ||
| and bash 4.3, where `**` only has special significance if it is the only | ||
| thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but | ||
| `a/**b` will not. | ||
| Note that symlinked directories are not crawled as part of a `**`, | ||
| though their contents may match against subsequent portions of the | ||
| pattern. This prevents infinite loops and duplicates and the like. | ||
| If an escaped pattern has no matches, and the `nonull` flag is set, | ||
| then glob returns the pattern as-provided, rather than | ||
| interpreting the character escapes. For example, | ||
| `glob.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than | ||
| `"*a?"`. This is akin to setting the `nullglob` option in bash, except | ||
| that it does not resolve escaped pattern characters. | ||
| If brace expansion is not disabled, then it is performed before any | ||
| other interpretation of the glob pattern. Thus, a pattern like | ||
| `+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded | ||
| **first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are | ||
| checked for validity. Since those two are valid, matching proceeds. | ||
| ### Comments and Negation | ||
| Previously, this module let you mark a pattern as a "comment" if it | ||
| started with a `#` character, or a "negated" pattern if it started | ||
| with a `!` character. | ||
| These options were deprecated in version 5, and removed in version 6. | ||
| To specify things that should not match, use the `ignore` option. | ||
| ## Windows | ||
| **Please only use forward-slashes in glob expressions.** | ||
| Though windows uses either `/` or `\` as its path separator, only `/` | ||
| characters are used by this glob implementation. You must use | ||
| forward-slashes **only** in glob expressions. Back-slashes will always | ||
| be interpreted as escape characters, not path separators. | ||
| Results from absolute patterns such as `/foo/*` are mounted onto the | ||
| root setting using `path.join`. On windows, this will by default result | ||
| in `/foo/*` matching `C:\foo\bar.txt`. | ||
| ## Race Conditions | ||
| Glob searching, by its very nature, is susceptible to race conditions, | ||
| since it relies on directory walking and such. | ||
| As a result, it is possible that a file that exists when glob looks for | ||
| it may have been deleted or modified by the time it returns the result. | ||
| As part of its internal implementation, this program caches all stat | ||
| and readdir calls that it makes, in order to cut down on system | ||
| overhead. However, this also makes it even more susceptible to races, | ||
| especially if the cache or statCache objects are reused between glob | ||
| calls. | ||
| Users are thus advised not to use a glob result as a guarantee of | ||
| filesystem state in the face of rapid changes. For the vast majority | ||
| of operations, this is never a problem. | ||
| ## Contributing | ||
| Any change to behavior (including bugfixes) must come with a test. | ||
| Patches that fail tests or reduce performance will be rejected. | ||
| ``` | ||
| # to run tests | ||
| npm test | ||
| # to re-generate test fixtures | ||
| npm run test-regen | ||
| # to benchmark against bash/zsh | ||
| npm run bench | ||
| # to profile javascript | ||
| npm run prof | ||
| ``` |
| module.exports = globSync | ||
| globSync.GlobSync = GlobSync | ||
| var fs = require('fs') | ||
| var minimatch = require('minimatch') | ||
| var Minimatch = minimatch.Minimatch | ||
| var Glob = require('./glob.js').Glob | ||
| var util = require('util') | ||
| var path = require('path') | ||
| var assert = require('assert') | ||
| var isAbsolute = require('path-is-absolute') | ||
| var common = require('./common.js') | ||
| var alphasort = common.alphasort | ||
| var alphasorti = common.alphasorti | ||
| var setopts = common.setopts | ||
| var ownProp = common.ownProp | ||
| var childrenIgnored = common.childrenIgnored | ||
| function globSync (pattern, options) { | ||
| if (typeof options === 'function' || arguments.length === 3) | ||
| throw new TypeError('callback provided to sync glob\n'+ | ||
| 'See: https://github.com/isaacs/node-glob/issues/167') | ||
| return new GlobSync(pattern, options).found | ||
| } | ||
| function GlobSync (pattern, options) { | ||
| if (!pattern) | ||
| throw new Error('must provide pattern') | ||
| if (typeof options === 'function' || arguments.length === 3) | ||
| throw new TypeError('callback provided to sync glob\n'+ | ||
| 'See: https://github.com/isaacs/node-glob/issues/167') | ||
| if (!(this instanceof GlobSync)) | ||
| return new GlobSync(pattern, options) | ||
| setopts(this, pattern, options) | ||
| if (this.noprocess) | ||
| return this | ||
| var n = this.minimatch.set.length | ||
| this.matches = new Array(n) | ||
| for (var i = 0; i < n; i ++) { | ||
| this._process(this.minimatch.set[i], i, false) | ||
| } | ||
| this._finish() | ||
| } | ||
| GlobSync.prototype._finish = function () { | ||
| assert(this instanceof GlobSync) | ||
| if (this.realpath) { | ||
| var self = this | ||
| this.matches.forEach(function (matchset, index) { | ||
| var set = self.matches[index] = Object.create(null) | ||
| for (var p in matchset) { | ||
| try { | ||
| p = self._makeAbs(p) | ||
| var real = fs.realpathSync(p, self.realpathCache) | ||
| set[real] = true | ||
| } catch (er) { | ||
| if (er.syscall === 'stat') | ||
| set[self._makeAbs(p)] = true | ||
| else | ||
| throw er | ||
| } | ||
| } | ||
| }) | ||
| } | ||
| common.finish(this) | ||
| } | ||
| GlobSync.prototype._process = function (pattern, index, inGlobStar) { | ||
| assert(this instanceof GlobSync) | ||
| // 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: | ||
| this._processSimple(pattern.join('/'), index) | ||
| 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).join('/') | ||
| break | ||
| } | ||
| var remain = pattern.slice(n) | ||
| // get the list of entries. | ||
| var read | ||
| if (prefix === null) | ||
| read = '.' | ||
| else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { | ||
| if (!prefix || !isAbsolute(prefix)) | ||
| prefix = '/' + prefix | ||
| read = prefix | ||
| } else | ||
| read = prefix | ||
| var abs = this._makeAbs(read) | ||
| //if ignored, skip processing | ||
| if (childrenIgnored(this, read)) | ||
| return | ||
| var isGlobStar = remain[0] === minimatch.GLOBSTAR | ||
| if (isGlobStar) | ||
| this._processGlobStar(prefix, read, abs, remain, index, inGlobStar) | ||
| else | ||
| this._processReaddir(prefix, read, abs, remain, index, inGlobStar) | ||
| } | ||
| GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) { | ||
| var entries = this._readdir(abs, inGlobStar) | ||
| // if the abs isn't a dir, then nothing can match! | ||
| if (!entries) | ||
| return | ||
| // 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 = remain[0] | ||
| var negate = !!this.minimatch.negate | ||
| var rawGlob = pn._glob | ||
| var dotOk = this.dot || rawGlob.charAt(0) === '.' | ||
| var matchedEntries = [] | ||
| for (var i = 0; i < entries.length; i++) { | ||
| var e = entries[i] | ||
| if (e.charAt(0) !== '.' || dotOk) { | ||
| var m | ||
| if (negate && !prefix) { | ||
| m = !e.match(pn) | ||
| } else { | ||
| m = e.match(pn) | ||
| } | ||
| if (m) | ||
| matchedEntries.push(e) | ||
| } | ||
| } | ||
| var len = matchedEntries.length | ||
| // If there are no matched entries, then nothing matches. | ||
| if (len === 0) | ||
| return | ||
| // if this is the last remaining pattern bit, then no need for | ||
| // an additional stat *unless* the user has specified mark or | ||
| // stat explicitly. We know they exist, since readdir returned | ||
| // them. | ||
| if (remain.length === 1 && !this.mark && !this.stat) { | ||
| if (!this.matches[index]) | ||
| this.matches[index] = Object.create(null) | ||
| for (var i = 0; i < len; i ++) { | ||
| var e = matchedEntries[i] | ||
| if (prefix) { | ||
| if (prefix.slice(-1) !== '/') | ||
| e = prefix + '/' + e | ||
| else | ||
| e = prefix + e | ||
| } | ||
| if (e.charAt(0) === '/' && !this.nomount) { | ||
| e = path.join(this.root, e) | ||
| } | ||
| this.matches[index][e] = true | ||
| } | ||
| // This was the last one, and no stats were needed | ||
| return | ||
| } | ||
| // now test all matched entries as stand-ins for that part | ||
| // of the pattern. | ||
| remain.shift() | ||
| for (var i = 0; i < len; i ++) { | ||
| var e = matchedEntries[i] | ||
| var newPattern | ||
| if (prefix) | ||
| newPattern = [prefix, e] | ||
| else | ||
| newPattern = [e] | ||
| this._process(newPattern.concat(remain), index, inGlobStar) | ||
| } | ||
| } | ||
| GlobSync.prototype._emitMatch = function (index, e) { | ||
| var abs = this._makeAbs(e) | ||
| if (this.mark) | ||
| e = this._mark(e) | ||
| if (this.matches[index][e]) | ||
| return | ||
| if (this.nodir) { | ||
| var c = this.cache[this._makeAbs(e)] | ||
| if (c === 'DIR' || Array.isArray(c)) | ||
| return | ||
| } | ||
| this.matches[index][e] = true | ||
| if (this.stat) | ||
| this._stat(e) | ||
| } | ||
| GlobSync.prototype._readdirInGlobStar = function (abs) { | ||
| // follow all symlinked directories forever | ||
| // just proceed as if this is a non-globstar situation | ||
| if (this.follow) | ||
| return this._readdir(abs, false) | ||
| var entries | ||
| var lstat | ||
| var stat | ||
| try { | ||
| lstat = fs.lstatSync(abs) | ||
| } catch (er) { | ||
| // lstat failed, doesn't exist | ||
| return null | ||
| } | ||
| var isSym = lstat.isSymbolicLink() | ||
| this.symlinks[abs] = isSym | ||
| // If it's not a symlink or a dir, then it's definitely a regular file. | ||
| // don't bother doing a readdir in that case. | ||
| if (!isSym && !lstat.isDirectory()) | ||
| this.cache[abs] = 'FILE' | ||
| else | ||
| entries = this._readdir(abs, false) | ||
| return entries | ||
| } | ||
| GlobSync.prototype._readdir = function (abs, inGlobStar) { | ||
| var entries | ||
| if (inGlobStar && !ownProp(this.symlinks, abs)) | ||
| return this._readdirInGlobStar(abs) | ||
| if (ownProp(this.cache, abs)) { | ||
| var c = this.cache[abs] | ||
| if (!c || c === 'FILE') | ||
| return null | ||
| if (Array.isArray(c)) | ||
| return c | ||
| } | ||
| try { | ||
| return this._readdirEntries(abs, fs.readdirSync(abs)) | ||
| } catch (er) { | ||
| this._readdirError(abs, er) | ||
| return null | ||
| } | ||
| } | ||
| GlobSync.prototype._readdirEntries = function (abs, entries) { | ||
| // if we haven't asked to stat everything, then just | ||
| // assume that everything in there exists, so we can avoid | ||
| // having to stat it a second time. | ||
| if (!this.mark && !this.stat) { | ||
| for (var i = 0; i < entries.length; i ++) { | ||
| var e = entries[i] | ||
| if (abs === '/') | ||
| e = abs + e | ||
| else | ||
| e = abs + '/' + e | ||
| this.cache[e] = true | ||
| } | ||
| } | ||
| this.cache[abs] = entries | ||
| // mark and cache dir-ness | ||
| return entries | ||
| } | ||
| GlobSync.prototype._readdirError = function (f, er) { | ||
| // handle errors, and cache the information | ||
| switch (er.code) { | ||
| case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 | ||
| case 'ENOTDIR': // totally normal. means it *does* exist. | ||
| this.cache[this._makeAbs(f)] = 'FILE' | ||
| break | ||
| case 'ENOENT': // not terribly unusual | ||
| case 'ELOOP': | ||
| case 'ENAMETOOLONG': | ||
| case 'UNKNOWN': | ||
| this.cache[this._makeAbs(f)] = false | ||
| break | ||
| default: // some unusual error. Treat as failure. | ||
| this.cache[this._makeAbs(f)] = false | ||
| if (this.strict) | ||
| throw er | ||
| if (!this.silent) | ||
| console.error('glob error', er) | ||
| break | ||
| } | ||
| } | ||
| GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { | ||
| var entries = this._readdir(abs, inGlobStar) | ||
| // no entries means not a dir, so it can never have matches | ||
| // foo.txt/** doesn't match foo.txt | ||
| if (!entries) | ||
| return | ||
| // test without the globstar, and with every child both below | ||
| // and replacing the globstar. | ||
| var remainWithoutGlobStar = remain.slice(1) | ||
| var gspref = prefix ? [ prefix ] : [] | ||
| var noGlobStar = gspref.concat(remainWithoutGlobStar) | ||
| // the noGlobStar pattern exits the inGlobStar state | ||
| this._process(noGlobStar, index, false) | ||
| var len = entries.length | ||
| var isSym = this.symlinks[abs] | ||
| // If it's a symlink, and we're in a globstar, then stop | ||
| if (isSym && inGlobStar) | ||
| return | ||
| for (var i = 0; i < len; i++) { | ||
| var e = entries[i] | ||
| if (e.charAt(0) === '.' && !this.dot) | ||
| continue | ||
| // these two cases enter the inGlobStar state | ||
| var instead = gspref.concat(entries[i], remainWithoutGlobStar) | ||
| this._process(instead, index, true) | ||
| var below = gspref.concat(entries[i], remain) | ||
| this._process(below, index, true) | ||
| } | ||
| } | ||
| GlobSync.prototype._processSimple = function (prefix, index) { | ||
| // XXX review this. Shouldn't it be doing the mounting etc | ||
| // before doing stat? kinda weird? | ||
| var exists = this._stat(prefix) | ||
| if (!this.matches[index]) | ||
| this.matches[index] = Object.create(null) | ||
| // If it doesn't exist, then just mark the lack of results | ||
| if (!exists) | ||
| return | ||
| if (prefix && isAbsolute(prefix) && !this.nomount) { | ||
| var trail = /[\/\\]$/.test(prefix) | ||
| if (prefix.charAt(0) === '/') { | ||
| prefix = path.join(this.root, prefix) | ||
| } else { | ||
| prefix = path.resolve(this.root, prefix) | ||
| if (trail) | ||
| prefix += '/' | ||
| } | ||
| } | ||
| if (process.platform === 'win32') | ||
| prefix = prefix.replace(/\\/g, '/') | ||
| // Mark this as a match | ||
| this.matches[index][prefix] = true | ||
| } | ||
| // Returns either 'DIR', 'FILE', or false | ||
| GlobSync.prototype._stat = function (f) { | ||
| var abs = this._makeAbs(f) | ||
| var needDir = f.slice(-1) === '/' | ||
| if (f.length > this.maxLength) | ||
| return false | ||
| if (!this.stat && ownProp(this.cache, abs)) { | ||
| var c = this.cache[abs] | ||
| if (Array.isArray(c)) | ||
| c = 'DIR' | ||
| // It exists, but maybe not how we need it | ||
| if (!needDir || c === 'DIR') | ||
| return c | ||
| if (needDir && c === 'FILE') | ||
| return false | ||
| // otherwise we have to stat, because maybe c=true | ||
| // if we know it exists, but not what it is. | ||
| } | ||
| var exists | ||
| var stat = this.statCache[abs] | ||
| if (!stat) { | ||
| var lstat | ||
| try { | ||
| lstat = fs.lstatSync(abs) | ||
| } catch (er) { | ||
| return false | ||
| } | ||
| if (lstat.isSymbolicLink()) { | ||
| try { | ||
| stat = fs.statSync(abs) | ||
| } catch (er) { | ||
| stat = lstat | ||
| } | ||
| } else { | ||
| stat = lstat | ||
| } | ||
| } | ||
| this.statCache[abs] = stat | ||
| var c = stat.isDirectory() ? 'DIR' : 'FILE' | ||
| this.cache[abs] = this.cache[abs] || c | ||
| if (needDir && c !== 'DIR') | ||
| return false | ||
| return c | ||
| } | ||
| GlobSync.prototype._mark = function (p) { | ||
| return common.mark(this, p) | ||
| } | ||
| GlobSync.prototype._makeAbs = function (f) { | ||
| return common.makeAbs(this, f) | ||
| } |
| The ISC License | ||
| Copyright (c) Isaac Z. Schlueter and Contributors | ||
| Permission to use, copy, modify, and/or distribute this software for any | ||
| purpose with or without fee is hereby granted, provided that the above | ||
| copyright notice and this permission notice appear in all copies. | ||
| THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR | ||
| IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| module.exports = minimatch | ||
| minimatch.Minimatch = Minimatch | ||
| var path = { sep: '/' } | ||
| try { | ||
| path = require('path') | ||
| } catch (er) {} | ||
| var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} | ||
| var expand = require('brace-expansion') | ||
| // any single thing other than / | ||
| // don't need to escape / when using new RegExp() | ||
| var qmark = '[^/]' | ||
| // * => any number of characters | ||
| var star = qmark + '*?' | ||
| // ** when dots are allowed. Anything goes, except .. and . | ||
| // not (^ or / followed by one or two dots followed by $ or /), | ||
| // followed by anything, any number of times. | ||
| var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?' | ||
| // not a ^ or / followed by a dot, | ||
| // followed by anything, any number of times. | ||
| var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?' | ||
| // characters that need to be escaped in RegExp. | ||
| var reSpecials = charSet('().*{}+?[]^$\\!') | ||
| // "abc" -> { a:true, b:true, c:true } | ||
| function charSet (s) { | ||
| return s.split('').reduce(function (set, c) { | ||
| set[c] = true | ||
| return set | ||
| }, {}) | ||
| } | ||
| // normalizes slashes. | ||
| var slashSplit = /\/+/ | ||
| minimatch.filter = filter | ||
| function filter (pattern, options) { | ||
| options = options || {} | ||
| return function (p, i, list) { | ||
| return minimatch(p, pattern, options) | ||
| } | ||
| } | ||
| function ext (a, b) { | ||
| a = a || {} | ||
| b = b || {} | ||
| var t = {} | ||
| Object.keys(b).forEach(function (k) { | ||
| t[k] = b[k] | ||
| }) | ||
| Object.keys(a).forEach(function (k) { | ||
| t[k] = a[k] | ||
| }) | ||
| return t | ||
| } | ||
| minimatch.defaults = function (def) { | ||
| if (!def || !Object.keys(def).length) return minimatch | ||
| var orig = minimatch | ||
| var m = function minimatch (p, pattern, options) { | ||
| return orig.minimatch(p, pattern, ext(def, options)) | ||
| } | ||
| m.Minimatch = function Minimatch (pattern, options) { | ||
| return new orig.Minimatch(pattern, ext(def, options)) | ||
| } | ||
| return m | ||
| } | ||
| Minimatch.defaults = function (def) { | ||
| if (!def || !Object.keys(def).length) return Minimatch | ||
| return minimatch.defaults(def).Minimatch | ||
| } | ||
| function minimatch (p, pattern, options) { | ||
| if (typeof pattern !== 'string') { | ||
| throw new TypeError('glob pattern string required') | ||
| } | ||
| if (!options) options = {} | ||
| // shortcut: comments match nothing. | ||
| if (!options.nocomment && pattern.charAt(0) === '#') { | ||
| return false | ||
| } | ||
| // "" only matches "" | ||
| if (pattern.trim() === '') return p === '' | ||
| return new Minimatch(pattern, options).match(p) | ||
| } | ||
| function Minimatch (pattern, options) { | ||
| if (!(this instanceof Minimatch)) { | ||
| return new Minimatch(pattern, options) | ||
| } | ||
| if (typeof pattern !== 'string') { | ||
| throw new TypeError('glob pattern string required') | ||
| } | ||
| if (!options) options = {} | ||
| pattern = pattern.trim() | ||
| // windows support: need to use /, not \ | ||
| if (path.sep !== '/') { | ||
| pattern = pattern.split(path.sep).join('/') | ||
| } | ||
| this.options = options | ||
| this.set = [] | ||
| this.pattern = pattern | ||
| this.regexp = null | ||
| this.negate = false | ||
| this.comment = false | ||
| this.empty = false | ||
| // make the set of regexps etc. | ||
| this.make() | ||
| } | ||
| Minimatch.prototype.debug = function () {} | ||
| Minimatch.prototype.make = make | ||
| function make () { | ||
| // don't do it more than once. | ||
| if (this._made) return | ||
| var pattern = this.pattern | ||
| var options = this.options | ||
| // empty patterns and comments match nothing. | ||
| if (!options.nocomment && pattern.charAt(0) === '#') { | ||
| this.comment = true | ||
| return | ||
| } | ||
| if (!pattern) { | ||
| this.empty = true | ||
| return | ||
| } | ||
| // step 1: figure out negation, etc. | ||
| this.parseNegate() | ||
| // step 2: expand braces | ||
| var set = this.globSet = this.braceExpand() | ||
| if (options.debug) this.debug = console.error | ||
| this.debug(this.pattern, set) | ||
| // step 3: now we have a set, so turn each one into a series of path-portion | ||
| // matching patterns. | ||
| // These will be regexps, except in the case of "**", which is | ||
| // set to the GLOBSTAR object for globstar behavior, | ||
| // and will not contain any / characters | ||
| set = this.globParts = set.map(function (s) { | ||
| return s.split(slashSplit) | ||
| }) | ||
| this.debug(this.pattern, set) | ||
| // glob --> regexps | ||
| set = set.map(function (s, si, set) { | ||
| return s.map(this.parse, this) | ||
| }, this) | ||
| this.debug(this.pattern, set) | ||
| // filter out everything that didn't compile properly. | ||
| set = set.filter(function (s) { | ||
| return s.indexOf(false) === -1 | ||
| }) | ||
| this.debug(this.pattern, set) | ||
| this.set = set | ||
| } | ||
| Minimatch.prototype.parseNegate = parseNegate | ||
| function parseNegate () { | ||
| var pattern = this.pattern | ||
| var negate = false | ||
| var options = this.options | ||
| var negateOffset = 0 | ||
| if (options.nonegate) return | ||
| for (var i = 0, l = pattern.length | ||
| ; i < l && pattern.charAt(i) === '!' | ||
| ; i++) { | ||
| negate = !negate | ||
| negateOffset++ | ||
| } | ||
| if (negateOffset) this.pattern = pattern.substr(negateOffset) | ||
| this.negate = negate | ||
| } | ||
| // Brace expansion: | ||
| // a{b,c}d -> abd acd | ||
| // a{b,}c -> abc ac | ||
| // a{0..3}d -> a0d a1d a2d a3d | ||
| // a{b,c{d,e}f}g -> abg acdfg acefg | ||
| // a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg | ||
| // | ||
| // Invalid sets are not expanded. | ||
| // a{2..}b -> a{2..}b | ||
| // a{b}c -> a{b}c | ||
| minimatch.braceExpand = function (pattern, options) { | ||
| return braceExpand(pattern, options) | ||
| } | ||
| Minimatch.prototype.braceExpand = braceExpand | ||
| function braceExpand (pattern, options) { | ||
| if (!options) { | ||
| if (this instanceof Minimatch) { | ||
| options = this.options | ||
| } else { | ||
| options = {} | ||
| } | ||
| } | ||
| pattern = typeof pattern === 'undefined' | ||
| ? this.pattern : pattern | ||
| if (typeof pattern === 'undefined') { | ||
| throw new Error('undefined pattern') | ||
| } | ||
| if (options.nobrace || | ||
| !pattern.match(/\{.*\}/)) { | ||
| // shortcut. no need to expand. | ||
| return [pattern] | ||
| } | ||
| return expand(pattern) | ||
| } | ||
| // parse a component of the expanded set. | ||
| // At this point, no pattern may contain "/" in it | ||
| // so we're going to return a 2d array, where each entry is the full | ||
| // pattern, split on '/', and then turned into a regular expression. | ||
| // A regexp is made at the end which joins each array with an | ||
| // escaped /, and another full one which joins each regexp with |. | ||
| // | ||
| // Following the lead of Bash 4.1, note that "**" only has special meaning | ||
| // when it is the *only* thing in a path portion. Otherwise, any series | ||
| // of * is equivalent to a single *. Globstar behavior is enabled by | ||
| // default, and can be disabled by setting options.noglobstar. | ||
| Minimatch.prototype.parse = parse | ||
| var SUBPARSE = {} | ||
| function parse (pattern, isSub) { | ||
| var options = this.options | ||
| // shortcuts | ||
| if (!options.noglobstar && pattern === '**') return GLOBSTAR | ||
| if (pattern === '') return '' | ||
| var re = '' | ||
| var hasMagic = !!options.nocase | ||
| var escaping = false | ||
| // ? => one single character | ||
| var patternListStack = [] | ||
| var negativeLists = [] | ||
| var plType | ||
| var stateChar | ||
| var inClass = false | ||
| var reClassStart = -1 | ||
| var classStart = -1 | ||
| // . and .. never match anything that doesn't start with ., | ||
| // even when options.dot is set. | ||
| var patternStart = pattern.charAt(0) === '.' ? '' // anything | ||
| // not (start or / followed by . or .. followed by / or end) | ||
| : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))' | ||
| : '(?!\\.)' | ||
| var self = this | ||
| function clearStateChar () { | ||
| if (stateChar) { | ||
| // we had some state-tracking character | ||
| // that wasn't consumed by this pass. | ||
| switch (stateChar) { | ||
| case '*': | ||
| re += star | ||
| hasMagic = true | ||
| break | ||
| case '?': | ||
| re += qmark | ||
| hasMagic = true | ||
| break | ||
| default: | ||
| re += '\\' + stateChar | ||
| break | ||
| } | ||
| self.debug('clearStateChar %j %j', stateChar, re) | ||
| stateChar = false | ||
| } | ||
| } | ||
| for (var i = 0, len = pattern.length, c | ||
| ; (i < len) && (c = pattern.charAt(i)) | ||
| ; i++) { | ||
| this.debug('%s\t%s %s %j', pattern, i, re, c) | ||
| // skip over any that are escaped. | ||
| if (escaping && reSpecials[c]) { | ||
| re += '\\' + c | ||
| escaping = false | ||
| continue | ||
| } | ||
| switch (c) { | ||
| case '/': | ||
| // completely not allowed, even escaped. | ||
| // Should already be path-split by now. | ||
| return false | ||
| case '\\': | ||
| clearStateChar() | ||
| escaping = true | ||
| continue | ||
| // the various stateChar values | ||
| // for the "extglob" stuff. | ||
| case '?': | ||
| case '*': | ||
| case '+': | ||
| case '@': | ||
| case '!': | ||
| this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c) | ||
| // all of those are literals inside a class, except that | ||
| // the glob [!a] means [^a] in regexp | ||
| if (inClass) { | ||
| this.debug(' in class') | ||
| if (c === '!' && i === classStart + 1) c = '^' | ||
| re += c | ||
| continue | ||
| } | ||
| // if we already have a stateChar, then it means | ||
| // that there was something like ** or +? in there. | ||
| // Handle the stateChar, then proceed with this one. | ||
| self.debug('call clearStateChar %j', stateChar) | ||
| clearStateChar() | ||
| stateChar = c | ||
| // if extglob is disabled, then +(asdf|foo) isn't a thing. | ||
| // just clear the statechar *now*, rather than even diving into | ||
| // the patternList stuff. | ||
| if (options.noext) clearStateChar() | ||
| continue | ||
| case '(': | ||
| if (inClass) { | ||
| re += '(' | ||
| continue | ||
| } | ||
| if (!stateChar) { | ||
| re += '\\(' | ||
| continue | ||
| } | ||
| plType = stateChar | ||
| patternListStack.push({ | ||
| type: plType, | ||
| start: i - 1, | ||
| reStart: re.length | ||
| }) | ||
| // negation is (?:(?!js)[^/]*) | ||
| re += stateChar === '!' ? '(?:(?!(?:' : '(?:' | ||
| this.debug('plType %j %j', stateChar, re) | ||
| stateChar = false | ||
| continue | ||
| case ')': | ||
| if (inClass || !patternListStack.length) { | ||
| re += '\\)' | ||
| continue | ||
| } | ||
| clearStateChar() | ||
| hasMagic = true | ||
| re += ')' | ||
| var pl = patternListStack.pop() | ||
| plType = pl.type | ||
| // negation is (?:(?!js)[^/]*) | ||
| // The others are (?:<pattern>)<type> | ||
| switch (plType) { | ||
| case '!': | ||
| negativeLists.push(pl) | ||
| re += ')[^/]*?)' | ||
| pl.reEnd = re.length | ||
| break | ||
| case '?': | ||
| case '+': | ||
| case '*': | ||
| re += plType | ||
| break | ||
| case '@': break // the default anyway | ||
| } | ||
| continue | ||
| case '|': | ||
| if (inClass || !patternListStack.length || escaping) { | ||
| re += '\\|' | ||
| escaping = false | ||
| continue | ||
| } | ||
| clearStateChar() | ||
| re += '|' | ||
| continue | ||
| // these are mostly the same in regexp and glob | ||
| case '[': | ||
| // swallow any state-tracking char before the [ | ||
| clearStateChar() | ||
| if (inClass) { | ||
| re += '\\' + c | ||
| continue | ||
| } | ||
| inClass = true | ||
| classStart = i | ||
| reClassStart = re.length | ||
| re += c | ||
| continue | ||
| case ']': | ||
| // a right bracket shall lose its special | ||
| // meaning and represent itself in | ||
| // a bracket expression if it occurs | ||
| // first in the list. -- POSIX.2 2.8.3.2 | ||
| if (i === classStart + 1 || !inClass) { | ||
| re += '\\' + c | ||
| escaping = false | ||
| continue | ||
| } | ||
| // handle the case where we left a class open. | ||
| // "[z-a]" is valid, equivalent to "\[z-a\]" | ||
| if (inClass) { | ||
| // split where the last [ was, make sure we don't have | ||
| // an invalid re. if so, re-walk the contents of the | ||
| // would-be class to re-translate any characters that | ||
| // were passed through as-is | ||
| // TODO: It would probably be faster to determine this | ||
| // without a try/catch and a new RegExp, but it's tricky | ||
| // to do safely. For now, this is safe and works. | ||
| var cs = pattern.substring(classStart + 1, i) | ||
| try { | ||
| RegExp('[' + cs + ']') | ||
| } catch (er) { | ||
| // not a valid class! | ||
| var sp = this.parse(cs, SUBPARSE) | ||
| re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]' | ||
| hasMagic = hasMagic || sp[1] | ||
| inClass = false | ||
| continue | ||
| } | ||
| } | ||
| // finish up the class. | ||
| hasMagic = true | ||
| inClass = false | ||
| re += c | ||
| continue | ||
| default: | ||
| // swallow any state char that wasn't consumed | ||
| clearStateChar() | ||
| if (escaping) { | ||
| // no need | ||
| escaping = false | ||
| } else if (reSpecials[c] | ||
| && !(c === '^' && inClass)) { | ||
| re += '\\' | ||
| } | ||
| re += c | ||
| } // switch | ||
| } // for | ||
| // handle the case where we left a class open. | ||
| // "[abc" is valid, equivalent to "\[abc" | ||
| if (inClass) { | ||
| // split where the last [ was, and escape it | ||
| // this is a huge pita. We now have to re-walk | ||
| // the contents of the would-be class to re-translate | ||
| // any characters that were passed through as-is | ||
| cs = pattern.substr(classStart + 1) | ||
| sp = this.parse(cs, SUBPARSE) | ||
| re = re.substr(0, reClassStart) + '\\[' + sp[0] | ||
| hasMagic = hasMagic || sp[1] | ||
| } | ||
| // handle the case where we had a +( thing at the *end* | ||
| // of the pattern. | ||
| // each pattern list stack adds 3 chars, and we need to go through | ||
| // and escape any | chars that were passed through as-is for the regexp. | ||
| // Go through and escape them, taking care not to double-escape any | ||
| // | chars that were already escaped. | ||
| for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) { | ||
| var tail = re.slice(pl.reStart + 3) | ||
| // maybe some even number of \, then maybe 1 \, followed by a | | ||
| tail = tail.replace(/((?:\\{2})*)(\\?)\|/g, function (_, $1, $2) { | ||
| if (!$2) { | ||
| // the | isn't already escaped, so escape it. | ||
| $2 = '\\' | ||
| } | ||
| // need to escape all those slashes *again*, without escaping the | ||
| // one that we need for escaping the | character. As it works out, | ||
| // escaping an even number of slashes can be done by simply repeating | ||
| // it exactly after itself. That's why this trick works. | ||
| // | ||
| // I am sorry that you have to see this. | ||
| return $1 + $1 + $2 + '|' | ||
| }) | ||
| this.debug('tail=%j\n %s', tail, tail) | ||
| var t = pl.type === '*' ? star | ||
| : pl.type === '?' ? qmark | ||
| : '\\' + pl.type | ||
| hasMagic = true | ||
| re = re.slice(0, pl.reStart) + t + '\\(' + tail | ||
| } | ||
| // handle trailing things that only matter at the very end. | ||
| clearStateChar() | ||
| if (escaping) { | ||
| // trailing \\ | ||
| re += '\\\\' | ||
| } | ||
| // only need to apply the nodot start if the re starts with | ||
| // something that could conceivably capture a dot | ||
| var addPatternStart = false | ||
| switch (re.charAt(0)) { | ||
| case '.': | ||
| case '[': | ||
| case '(': addPatternStart = true | ||
| } | ||
| // Hack to work around lack of negative lookbehind in JS | ||
| // A pattern like: *.!(x).!(y|z) needs to ensure that a name | ||
| // like 'a.xyz.yz' doesn't match. So, the first negative | ||
| // lookahead, has to look ALL the way ahead, to the end of | ||
| // the pattern. | ||
| for (var n = negativeLists.length - 1; n > -1; n--) { | ||
| var nl = negativeLists[n] | ||
| var nlBefore = re.slice(0, nl.reStart) | ||
| var nlFirst = re.slice(nl.reStart, nl.reEnd - 8) | ||
| var nlLast = re.slice(nl.reEnd - 8, nl.reEnd) | ||
| var nlAfter = re.slice(nl.reEnd) | ||
| nlLast += nlAfter | ||
| // Handle nested stuff like *(*.js|!(*.json)), where open parens | ||
| // mean that we should *not* include the ) in the bit that is considered | ||
| // "after" the negated section. | ||
| var openParensBefore = nlBefore.split('(').length - 1 | ||
| var cleanAfter = nlAfter | ||
| for (i = 0; i < openParensBefore; i++) { | ||
| cleanAfter = cleanAfter.replace(/\)[+*?]?/, '') | ||
| } | ||
| nlAfter = cleanAfter | ||
| var dollar = '' | ||
| if (nlAfter === '' && isSub !== SUBPARSE) { | ||
| dollar = '$' | ||
| } | ||
| var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast | ||
| re = newRe | ||
| } | ||
| // if the re is not "" at this point, then we need to make sure | ||
| // it doesn't match against an empty path part. | ||
| // Otherwise a/* will match a/, which it should not. | ||
| if (re !== '' && hasMagic) { | ||
| re = '(?=.)' + re | ||
| } | ||
| if (addPatternStart) { | ||
| re = patternStart + re | ||
| } | ||
| // parsing just a piece of a larger pattern. | ||
| if (isSub === SUBPARSE) { | ||
| return [re, hasMagic] | ||
| } | ||
| // skip the regexp for non-magical patterns | ||
| // unescape anything in it, though, so that it'll be | ||
| // an exact match against a file etc. | ||
| if (!hasMagic) { | ||
| return globUnescape(pattern) | ||
| } | ||
| var flags = options.nocase ? 'i' : '' | ||
| var regExp = new RegExp('^' + re + '$', flags) | ||
| regExp._glob = pattern | ||
| regExp._src = re | ||
| return regExp | ||
| } | ||
| minimatch.makeRe = function (pattern, options) { | ||
| return new Minimatch(pattern, options || {}).makeRe() | ||
| } | ||
| Minimatch.prototype.makeRe = makeRe | ||
| function makeRe () { | ||
| if (this.regexp || this.regexp === false) return this.regexp | ||
| // at this point, this.set is a 2d array of partial | ||
| // pattern strings, or "**". | ||
| // | ||
| // It's better to use .match(). This function shouldn't | ||
| // be used, really, but it's pretty convenient sometimes, | ||
| // when you just want to work with a regex. | ||
| var set = this.set | ||
| if (!set.length) { | ||
| this.regexp = false | ||
| return this.regexp | ||
| } | ||
| var options = this.options | ||
| var twoStar = options.noglobstar ? star | ||
| : options.dot ? twoStarDot | ||
| : twoStarNoDot | ||
| var flags = options.nocase ? 'i' : '' | ||
| var re = set.map(function (pattern) { | ||
| return pattern.map(function (p) { | ||
| return (p === GLOBSTAR) ? twoStar | ||
| : (typeof p === 'string') ? regExpEscape(p) | ||
| : p._src | ||
| }).join('\\\/') | ||
| }).join('|') | ||
| // must match entire pattern | ||
| // ending in a * or ** will make it less strict. | ||
| re = '^(?:' + re + ')$' | ||
| // can match anything, as long as it's not this. | ||
| if (this.negate) re = '^(?!' + re + ').*$' | ||
| try { | ||
| this.regexp = new RegExp(re, flags) | ||
| } catch (ex) { | ||
| this.regexp = false | ||
| } | ||
| return this.regexp | ||
| } | ||
| minimatch.match = function (list, pattern, options) { | ||
| options = options || {} | ||
| var mm = new Minimatch(pattern, options) | ||
| list = list.filter(function (f) { | ||
| return mm.match(f) | ||
| }) | ||
| if (mm.options.nonull && !list.length) { | ||
| list.push(pattern) | ||
| } | ||
| return list | ||
| } | ||
| Minimatch.prototype.match = match | ||
| function match (f, partial) { | ||
| this.debug('match', f, this.pattern) | ||
| // short-circuit in the case of busted things. | ||
| // comments, etc. | ||
| if (this.comment) return false | ||
| if (this.empty) return f === '' | ||
| if (f === '/' && partial) return true | ||
| var options = this.options | ||
| // windows: need to use /, not \ | ||
| if (path.sep !== '/') { | ||
| f = f.split(path.sep).join('/') | ||
| } | ||
| // treat the test path as a set of pathparts. | ||
| f = f.split(slashSplit) | ||
| this.debug(this.pattern, 'split', f) | ||
| // just ONE of the pattern sets in this.set needs to match | ||
| // in order for it to be valid. If negating, then just one | ||
| // match means that we have failed. | ||
| // Either way, return on the first hit. | ||
| var set = this.set | ||
| this.debug(this.pattern, 'set', set) | ||
| // Find the basename of the path by looking for the last non-empty segment | ||
| var filename | ||
| var i | ||
| for (i = f.length - 1; i >= 0; i--) { | ||
| filename = f[i] | ||
| if (filename) break | ||
| } | ||
| for (i = 0; i < set.length; i++) { | ||
| var pattern = set[i] | ||
| var file = f | ||
| if (options.matchBase && pattern.length === 1) { | ||
| file = [filename] | ||
| } | ||
| var hit = this.matchOne(file, pattern, partial) | ||
| if (hit) { | ||
| if (options.flipNegate) return true | ||
| return !this.negate | ||
| } | ||
| } | ||
| // didn't get any hits. this is success if it's a negative | ||
| // pattern, failure otherwise. | ||
| if (options.flipNegate) return false | ||
| return this.negate | ||
| } | ||
| // set partial to true to test if, for example, | ||
| // "/a/b" matches the start of "/*/b/*/d" | ||
| // Partial means, if you run out of file before you run | ||
| // out of pattern, then that's fine, as long as all | ||
| // the parts match. | ||
| Minimatch.prototype.matchOne = function (file, pattern, partial) { | ||
| var options = this.options | ||
| this.debug('matchOne', | ||
| { 'this': this, file: file, pattern: pattern }) | ||
| this.debug('matchOne', file.length, pattern.length) | ||
| for (var fi = 0, | ||
| pi = 0, | ||
| fl = file.length, | ||
| pl = pattern.length | ||
| ; (fi < fl) && (pi < pl) | ||
| ; fi++, pi++) { | ||
| this.debug('matchOne loop') | ||
| var p = pattern[pi] | ||
| var f = file[fi] | ||
| this.debug(pattern, p, f) | ||
| // should be impossible. | ||
| // some invalid regexp stuff in the set. | ||
| if (p === false) return false | ||
| if (p === GLOBSTAR) { | ||
| this.debug('GLOBSTAR', [pattern, p, f]) | ||
| // "**" | ||
| // a/**/b/**/c would match the following: | ||
| // a/b/x/y/z/c | ||
| // a/x/y/z/b/c | ||
| // a/b/x/b/x/c | ||
| // a/b/c | ||
| // To do this, take the rest of the pattern after | ||
| // the **, and see if it would match the file remainder. | ||
| // If so, return success. | ||
| // If not, the ** "swallows" a segment, and try again. | ||
| // This is recursively awful. | ||
| // | ||
| // a/**/b/**/c matching a/b/x/y/z/c | ||
| // - a matches a | ||
| // - doublestar | ||
| // - matchOne(b/x/y/z/c, b/**/c) | ||
| // - b matches b | ||
| // - doublestar | ||
| // - matchOne(x/y/z/c, c) -> no | ||
| // - matchOne(y/z/c, c) -> no | ||
| // - matchOne(z/c, c) -> no | ||
| // - matchOne(c, c) yes, hit | ||
| var fr = fi | ||
| var pr = pi + 1 | ||
| if (pr === pl) { | ||
| this.debug('** at the end') | ||
| // a ** at the end will just swallow the rest. | ||
| // We have found a match. | ||
| // however, it will not swallow /.x, unless | ||
| // options.dot is set. | ||
| // . and .. are *never* matched by **, for explosively | ||
| // exponential reasons. | ||
| for (; fi < fl; fi++) { | ||
| if (file[fi] === '.' || file[fi] === '..' || | ||
| (!options.dot && file[fi].charAt(0) === '.')) return false | ||
| } | ||
| return true | ||
| } | ||
| // ok, let's see if we can swallow whatever we can. | ||
| while (fr < fl) { | ||
| var swallowee = file[fr] | ||
| this.debug('\nglobstar while', file, fr, pattern, pr, swallowee) | ||
| // XXX remove this slice. Just pass the start index. | ||
| if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { | ||
| this.debug('globstar found match!', fr, fl, swallowee) | ||
| // found a match. | ||
| return true | ||
| } else { | ||
| // can't swallow "." or ".." ever. | ||
| // can only swallow ".foo" when explicitly asked. | ||
| if (swallowee === '.' || swallowee === '..' || | ||
| (!options.dot && swallowee.charAt(0) === '.')) { | ||
| this.debug('dot detected!', file, fr, pattern, pr) | ||
| break | ||
| } | ||
| // ** swallows a segment, and continue. | ||
| this.debug('globstar swallow a segment, and continue') | ||
| fr++ | ||
| } | ||
| } | ||
| // no match was found. | ||
| // However, in partial mode, we can't say this is necessarily over. | ||
| // If there's more *pattern* left, then | ||
| if (partial) { | ||
| // ran out of file | ||
| this.debug('\n>>> no match, partial?', file, fr, pattern, pr) | ||
| if (fr === fl) return true | ||
| } | ||
| return false | ||
| } | ||
| // something other than ** | ||
| // non-magic patterns just have to match exactly | ||
| // patterns with magic have been turned into regexps. | ||
| var hit | ||
| if (typeof p === 'string') { | ||
| if (options.nocase) { | ||
| hit = f.toLowerCase() === p.toLowerCase() | ||
| } else { | ||
| hit = f === p | ||
| } | ||
| this.debug('string match', p, f, hit) | ||
| } else { | ||
| hit = f.match(p) | ||
| this.debug('pattern match', p, f, hit) | ||
| } | ||
| if (!hit) return false | ||
| } | ||
| // Note: ending in / means that we'll get a final "" | ||
| // at the end of the pattern. This can only match a | ||
| // corresponding "" at the end of the file. | ||
| // If the file ends in /, then it can only match a | ||
| // a pattern that ends in /, unless the pattern just | ||
| // doesn't have any more for it. But, a/b/ should *not* | ||
| // match "a/b/*", even though "" matches against the | ||
| // [^/]*? pattern, except in partial mode, where it might | ||
| // simply not be reached yet. | ||
| // However, a/b/ should still satisfy a/* | ||
| // now either we fell off the end of the pattern, or we're done. | ||
| if (fi === fl && pi === pl) { | ||
| // ran out of pattern and filename at the same time. | ||
| // an exact hit! | ||
| return true | ||
| } else if (fi === fl) { | ||
| // ran out of file, but still had pattern left. | ||
| // this is ok if we're doing the match as part of | ||
| // a glob fs traversal. | ||
| return partial | ||
| } else if (pi === pl) { | ||
| // ran out of pattern, still have file left. | ||
| // this is only acceptable if we're on the very last | ||
| // empty segment of a file with a trailing slash. | ||
| // a/* should match a/b/ | ||
| var emptyFileEnd = (fi === fl - 1) && (file[fi] === '') | ||
| return emptyFileEnd | ||
| } | ||
| // should be unreachable. | ||
| throw new Error('wtf?') | ||
| } | ||
| // replace stuff like \* with * | ||
| function globUnescape (s) { | ||
| return s.replace(/\\(.)/g, '$1') | ||
| } | ||
| function regExpEscape (s) { | ||
| return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') | ||
| } |
| { | ||
| "_args": [ | ||
| [ | ||
| "minimatch@^3.0.0", | ||
| "/home/mk/src/mklabs/node-fileset" | ||
| ] | ||
| ], | ||
| "_from": "minimatch@>=3.0.0 <4.0.0", | ||
| "_id": "minimatch@3.0.0", | ||
| "_inCache": true, | ||
| "_installable": true, | ||
| "_location": "/minimatch", | ||
| "_nodeVersion": "4.0.0", | ||
| "_npmUser": { | ||
| "email": "isaacs@npmjs.com", | ||
| "name": "isaacs" | ||
| }, | ||
| "_npmVersion": "3.3.2", | ||
| "_phantomChildren": {}, | ||
| "_requested": { | ||
| "name": "minimatch", | ||
| "raw": "minimatch@^3.0.0", | ||
| "rawSpec": "^3.0.0", | ||
| "scope": null, | ||
| "spec": ">=3.0.0 <4.0.0", | ||
| "type": "range" | ||
| }, | ||
| "_requiredBy": [ | ||
| "/", | ||
| "/babel-cli/glob", | ||
| "/eslint/glob", | ||
| "/glob", | ||
| "/rimraf/glob" | ||
| ], | ||
| "_resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz", | ||
| "_shasum": "5236157a51e4f004c177fb3c527ff7dd78f0ef83", | ||
| "_shrinkwrap": null, | ||
| "_spec": "minimatch@^3.0.0", | ||
| "_where": "/home/mk/src/mklabs/node-fileset", | ||
| "author": { | ||
| "email": "i@izs.me", | ||
| "name": "Isaac Z. Schlueter", | ||
| "url": "http://blog.izs.me" | ||
| }, | ||
| "bugs": { | ||
| "url": "https://github.com/isaacs/minimatch/issues" | ||
| }, | ||
| "dependencies": { | ||
| "brace-expansion": "^1.0.0" | ||
| }, | ||
| "description": "a glob matcher in javascript", | ||
| "devDependencies": { | ||
| "standard": "^3.7.2", | ||
| "tap": "^1.2.0" | ||
| }, | ||
| "directories": {}, | ||
| "dist": { | ||
| "shasum": "5236157a51e4f004c177fb3c527ff7dd78f0ef83", | ||
| "tarball": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz" | ||
| }, | ||
| "engines": { | ||
| "node": "*" | ||
| }, | ||
| "files": [ | ||
| "minimatch.js" | ||
| ], | ||
| "gitHead": "270dbea567f0af6918cb18103e98c612aa717a20", | ||
| "homepage": "https://github.com/isaacs/minimatch#readme", | ||
| "license": "ISC", | ||
| "main": "minimatch.js", | ||
| "maintainers": [ | ||
| { | ||
| "email": "i@izs.me", | ||
| "name": "isaacs" | ||
| } | ||
| ], | ||
| "name": "minimatch", | ||
| "optionalDependencies": {}, | ||
| "readme": "ERROR: No README data found!", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git://github.com/isaacs/minimatch.git" | ||
| }, | ||
| "scripts": { | ||
| "posttest": "standard minimatch.js test/*.js", | ||
| "test": "tap test/*.js" | ||
| }, | ||
| "version": "3.0.0" | ||
| } |
| # minimatch | ||
| A minimal matching utility. | ||
| [](http://travis-ci.org/isaacs/minimatch) | ||
| This is the matching library used internally by npm. | ||
| It works by converting glob expressions into JavaScript `RegExp` | ||
| objects. | ||
| ## Usage | ||
| ```javascript | ||
| var minimatch = require("minimatch") | ||
| minimatch("bar.foo", "*.foo") // true! | ||
| minimatch("bar.foo", "*.bar") // false! | ||
| minimatch("bar.foo", "*.+(bar|foo)", { debug: true }) // true, and noisy! | ||
| ``` | ||
| ## Features | ||
| Supports these glob features: | ||
| * Brace Expansion | ||
| * Extended glob matching | ||
| * "Globstar" `**` matching | ||
| See: | ||
| * `man sh` | ||
| * `man bash` | ||
| * `man 3 fnmatch` | ||
| * `man 5 gitignore` | ||
| ## Minimatch Class | ||
| Create a minimatch object by instanting the `minimatch.Minimatch` class. | ||
| ```javascript | ||
| var Minimatch = require("minimatch").Minimatch | ||
| var mm = new Minimatch(pattern, options) | ||
| ``` | ||
| ### Properties | ||
| * `pattern` The original pattern the minimatch object represents. | ||
| * `options` The options supplied to the constructor. | ||
| * `set` A 2-dimensional array of regexp or string expressions. | ||
| Each row in the | ||
| array corresponds to a brace-expanded pattern. Each item in the row | ||
| corresponds to a single path-part. For example, the pattern | ||
| `{a,b/c}/d` would expand to a set of patterns like: | ||
| [ [ a, d ] | ||
| , [ b, c, d ] ] | ||
| If a portion of the pattern doesn't have any "magic" in it | ||
| (that is, it's something like `"foo"` rather than `fo*o?`), then it | ||
| will be left as a string rather than converted to a regular | ||
| expression. | ||
| * `regexp` Created by the `makeRe` method. A single regular expression | ||
| expressing the entire pattern. This is useful in cases where you wish | ||
| to use the pattern somewhat like `fnmatch(3)` with `FNM_PATH` enabled. | ||
| * `negate` True if the pattern is negated. | ||
| * `comment` True if the pattern is a comment. | ||
| * `empty` True if the pattern is `""`. | ||
| ### Methods | ||
| * `makeRe` Generate the `regexp` member if necessary, and return it. | ||
| Will return `false` if the pattern is invalid. | ||
| * `match(fname)` Return true if the filename matches the pattern, or | ||
| false otherwise. | ||
| * `matchOne(fileArray, patternArray, partial)` Take a `/`-split | ||
| filename, and match it against a single row in the `regExpSet`. This | ||
| method is mainly for internal use, but is exposed so that it can be | ||
| used by a glob-walker that needs to avoid excessive filesystem calls. | ||
| All other methods are internal, and will be called as necessary. | ||
| ## Functions | ||
| The top-level exported function has a `cache` property, which is an LRU | ||
| cache set to store 100 items. So, calling these methods repeatedly | ||
| with the same pattern and options will use the same Minimatch object, | ||
| saving the cost of parsing it multiple times. | ||
| ### minimatch(path, pattern, options) | ||
| Main export. Tests a path against the pattern using the options. | ||
| ```javascript | ||
| var isJS = minimatch(file, "*.js", { matchBase: true }) | ||
| ``` | ||
| ### minimatch.filter(pattern, options) | ||
| Returns a function that tests its | ||
| supplied argument, suitable for use with `Array.filter`. Example: | ||
| ```javascript | ||
| var javascripts = fileList.filter(minimatch.filter("*.js", {matchBase: true})) | ||
| ``` | ||
| ### minimatch.match(list, pattern, options) | ||
| Match against the list of | ||
| files, in the style of fnmatch or glob. If nothing is matched, and | ||
| options.nonull is set, then return a list containing the pattern itself. | ||
| ```javascript | ||
| var javascripts = minimatch.match(fileList, "*.js", {matchBase: true})) | ||
| ``` | ||
| ### minimatch.makeRe(pattern, options) | ||
| Make a regular expression object from the pattern. | ||
| ## Options | ||
| All options are `false` by default. | ||
| ### debug | ||
| Dump a ton of stuff to stderr. | ||
| ### nobrace | ||
| Do not expand `{a,b}` and `{1..3}` brace sets. | ||
| ### noglobstar | ||
| Disable `**` matching against multiple folder names. | ||
| ### dot | ||
| Allow patterns to match filenames starting with a period, even if | ||
| the pattern does not explicitly have a period in that spot. | ||
| Note that by default, `a/**/b` will **not** match `a/.d/b`, unless `dot` | ||
| is set. | ||
| ### noext | ||
| Disable "extglob" style patterns like `+(a|b)`. | ||
| ### nocase | ||
| Perform a case-insensitive match. | ||
| ### nonull | ||
| When a match is not found by `minimatch.match`, return a list containing | ||
| the pattern itself if this option is set. When not set, an empty list | ||
| is returned if there are no matches. | ||
| ### matchBase | ||
| If set, then patterns without slashes will be matched | ||
| against the basename of the path if it contains slashes. For example, | ||
| `a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`. | ||
| ### nocomment | ||
| Suppress the behavior of treating `#` at the start of a pattern as a | ||
| comment. | ||
| ### nonegate | ||
| Suppress the behavior of treating a leading `!` character as negation. | ||
| ### flipNegate | ||
| Returns from negate expressions the same as if they were not negated. | ||
| (Ie, true on a hit, false on a miss.) | ||
| ## Comparisons to other fnmatch/glob implementations | ||
| While strict compliance with the existing standards is a worthwhile | ||
| goal, some discrepancies exist between minimatch and other | ||
| implementations, and are intentional. | ||
| If the pattern starts with a `!` character, then it is negated. Set the | ||
| `nonegate` flag to suppress this behavior, and treat leading `!` | ||
| characters normally. This is perhaps relevant if you wish to start the | ||
| pattern with a negative extglob pattern like `!(a|B)`. Multiple `!` | ||
| characters at the start of a pattern will negate the pattern multiple | ||
| times. | ||
| If a pattern starts with `#`, then it is treated as a comment, and | ||
| will not match anything. Use `\#` to match a literal `#` at the | ||
| start of a line, or set the `nocomment` flag to suppress this behavior. | ||
| The double-star character `**` is supported by default, unless the | ||
| `noglobstar` flag is set. This is supported in the manner of bsdglob | ||
| and bash 4.1, where `**` only has special significance if it is the only | ||
| thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but | ||
| `a/**b` will not. | ||
| If an escaped pattern has no matches, and the `nonull` flag is set, | ||
| then minimatch.match returns the pattern as-provided, rather than | ||
| interpreting the character escapes. For example, | ||
| `minimatch.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than | ||
| `"*a?"`. This is akin to setting the `nullglob` option in bash, except | ||
| that it does not resolve escaped pattern characters. | ||
| If brace expansion is not disabled, then it is performed before any | ||
| other interpretation of the glob pattern. Thus, a pattern like | ||
| `+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded | ||
| **first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are | ||
| checked for validity. Since those two are valid, matching proceeds. |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Mixed license
LicensePackage contains multiple licenses.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
0
-100%0
-100%15249
-85.31%14
-39.13%195
-91.09%Updated