| var util = require('util'); | |
| var minimatch = require('minimatch'); | |
| var glob = require('glob'); | |
| var Glob = glob.Glob; | |
| var EventEmitter = require('events').EventEmitter; | |
| module.exports = fileset; | |
| // Async API | |
| function fileset(include, exclude, options, cb) { | |
| if (typeof exclude === 'function') cb = exclude, exclude = ''; | |
| else if (typeof options === 'function') cb = options, options = {}; | |
| var includes = (typeof include === 'string') ? include.split(' ') : include; | |
| var excludes = (typeof exclude === 'string') ? exclude.split(' ') : exclude; | |
| var em = new EventEmitter; | |
| var remaining = includes.length; | |
| var results = []; | |
| if (!includes.length) return cb(new Error('Must provide an include pattern')); | |
| em.includes = includes.map(function(pattern) { | |
| return new fileset.Fileset(pattern, options) | |
| .on('error', cb ? cb : em.emit.bind(em, 'error')) | |
| .on('match', em.emit.bind(em, 'match')) | |
| .on('match', em.emit.bind(em, 'include')) | |
| .on('end', next.bind({}, pattern)) | |
| }); | |
| function next(pattern, matches) { | |
| results = results.concat(matches); | |
| if (!(--remaining)) { | |
| results = results.filter(function(file) { | |
| return !excludes.filter(function(glob) { | |
| var match = minimatch(file, glob, { matchBase: true }); | |
| if(match) em.emit('exclude', file); | |
| return match; | |
| }).length; | |
| }); | |
| if(cb) cb(null, results); | |
| em.emit('end', results); | |
| } | |
| } | |
| return em; | |
| } | |
| // Sync API | |
| fileset.sync = function filesetSync(include, exclude) { | |
| if (!exclude) exclude = ''; | |
| // includes / excludes, either an array or string separated by comma or whitespace | |
| var includes = (typeof include === 'string') ? include.split(/[\s,]/g) : include; | |
| var excludes = (typeof exclude === 'string') ? exclude.split(/[\s,]/g) : exclude; | |
| // Filter out any false positive '' empty strings | |
| includes = includes.filter(function(pattern) { return pattern; }); | |
| excludes = excludes.filter(function(pattern) { return pattern; }); | |
| // - todo: pass in glob options as last param | |
| var options = { matchBase: true }; | |
| // always ignore node_modules for sync api | |
| options.ignore = ['node_modules/**/*']; | |
| // First, glob match on all include patters into a single array | |
| var results = includes.map(function(include) { | |
| return glob.sync(include, options); | |
| }).reduce(function(a, b) { | |
| return a.concat(b); | |
| }, []); | |
| // Then filters out on any exclude match | |
| var ignored = excludes.map(function(exclude) { | |
| return glob.sync(exclude, options); | |
| }).reduce(function(a, b) { | |
| return a.concat(b); | |
| }, []); | |
| // And filter any exclude match | |
| results = results.filter(function(file) { | |
| return !ignored.filter(function(glob) { | |
| return minimatch(file, glob, { matchBase: true }); | |
| }).length; | |
| }); | |
| return results; | |
| }; | |
| fileset.Fileset = function Fileset(pattern, options, cb) { | |
| if (typeof options === 'function') cb = options, options = {}; | |
| if (!options) options = {}; | |
| // ignore node_modules by default, unless specified | |
| options.ignore = options.ignore || ['node_modules/**/*']; | |
| Glob.call(this, pattern, options); | |
| if (typeof cb === 'function') { | |
| this.on('error', cb); | |
| this.on('end', function(matches) { cb(null, matches); }); | |
| } | |
| }; | |
| util.inherits(fileset.Fileset, Glob); |