shift73k/assets_old/node_modules/glob-all/glob-all.js

195 lines
4.8 KiB
JavaScript

var util = require("util");
var Glob = require("glob").Glob;
var EventEmitter = require("events").EventEmitter;
// helper class to store and compare glob results
function File(pattern1, patternId1, path1, fileId1) {
this.pattern = pattern1;
this.patternId = patternId1;
this.path = path1;
this.fileId = fileId1;
this.include = true;
while (this.pattern.charAt(0) === "!") {
this.include = !this.include;
this.pattern = this.pattern.substr(1);
}
}
File.prototype.stars = /((\/\*\*)?\/\*)?\.(\w+)$/;
// strip stars and compare pattern length
// longest length wins
File.prototype.compare = function(other) {
var p1 = this.pattern.replace(this.stars, "");
var p2 = other.pattern.replace(this.stars, "");
if (p1.length > p2.length) {
return this;
} else {
return other;
}
};
File.prototype.toString = function() {
return this.path + " (" + this.patternId + ": " + this.fileId + ": " + this.pattern + ")";
};
// using standard node inheritance
util.inherits(GlobAll, EventEmitter);
// allows the use arrays with "node-glob"
// interatively combines the resulting arrays
// api is exactly the same
function GlobAll(sync, patterns, opts, callback) {
if (opts == null) {
opts = {};
}
EventEmitter.call(this);
// init array
if (typeof patterns === "string") {
patterns = [patterns];
}
if (!(patterns instanceof Array)) {
return (typeof callback === "function") ? callback("Invalid input") : null;
}
// use copy of array
this.patterns = patterns.slice();
// no opts provided
if (typeof opts === "function") {
callback = opts;
opts = {};
}
// allow sync+nocallback or async+callback
if (sync !== (typeof callback !== "function")) {
throw new Error("should" + (sync ? " not" : "") + " have callback");
}
// all globs share the same stat cache
this.statCache = opts.statCache = opts.statCache || {};
opts.sync = sync;
this.opts = opts;
this.set = {};
this.results = null;
this.globs = [];
this.callback = callback;
// bound functions
this.globbedOne = this.globbedOne.bind(this);
}
GlobAll.prototype.run = function() {
this.globNext();
return this.results;
};
GlobAll.prototype.globNext = function() {
var g, pattern, include = true;
if (this.patterns.length === 0) {
return this.globbedAll();
}
pattern = this.patterns[0]; // peek!
// check whether this is an exclude pattern and
// strip the leading ! if it is
if (pattern.charAt(0) === "!") {
include = false;
pattern = pattern.substr(1);
}
// run
if (this.opts.sync) {
// sync - callback straight away
g = new Glob(pattern, this.opts);
this.globs.push(g);
this.globbedOne(null, include, g.found);
} else {
// async
var self = this;
g = new Glob(pattern, this.opts, function(err, files) {
self.globbedOne(err, include, files);
});
this.globs.push(g);
}
};
// collect results
GlobAll.prototype.globbedOne = function(err, include, files) {
// handle callback error early
if (err) {
if (!this.callback) {
this.emit("error", err);
}
this.removeAllListeners();
if (this.callback) {
this.callback(err);
}
return;
}
var patternId = this.patterns.length;
var pattern = this.patterns.shift();
// insert each into the results set
for (var fileId = 0; fileId < files.length; fileId++) {
// convert to file instance
var path = files[fileId];
var f = new File(pattern, patternId, path, fileId);
var existing = this.set[path];
// new item
if (!existing) {
if (include) {
this.set[path] = f;
this.emit("match", path);
}
continue;
}
// compare or delete
if (include) {
this.set[path] = f.compare(existing);
} else {
delete this.set[path];
}
}
// run next
this.globNext();
};
GlobAll.prototype.globbedAll = function() {
// map result set into an array
var files = [];
for (var k in this.set) {
files.push(this.set[k]);
}
// sort files by index
files.sort(function(a, b) {
if (a.patternId < b.patternId) {
return 1;
}
if (a.patternId > b.patternId) {
return -1;
}
if (a.fileId >= b.fileId) {
return 1;
} else {
return -1;
}
});
// finally, convert back into a path string
this.results = files.map(function(f) {
return f.path;
});
this.emit("end");
this.removeAllListeners();
// return string paths
if (!this.opts.sync) {
this.callback(null, this.results);
}
return this.results;
};
// expose
var globAll = function(array, opts, callback) {
var g = new GlobAll(false, array, opts, callback);
g.run(); //async, so results are empty
return g;
};
// sync is actually the same function :)
globAll.sync = function(array, opts) {
return new GlobAll(true, array, opts).run();
};
module.exports = globAll;