1 var util = require('util');
\r
2 var minimatch = require('minimatch');
\r
3 var glob = require('glob');
\r
4 var Glob = glob.Glob;
\r
5 var EventEmitter = require('events').EventEmitter;
\r
7 module.exports = fileset;
\r
10 function fileset(include, exclude, options, cb) {
\r
11 if (typeof exclude === 'function') cb = exclude, exclude = '';
\r
12 else if (typeof options === 'function') cb = options, options = {};
\r
14 var includes = (typeof include === 'string') ? include.split(' ') : include;
\r
15 var excludes = (typeof exclude === 'string') ? exclude.split(' ') : exclude;
\r
17 var em = new EventEmitter;
\r
18 var remaining = includes.length;
\r
21 if (!includes.length) return cb(new Error('Must provide an include pattern'));
\r
23 em.includes = includes.map(function(pattern) {
\r
24 return new fileset.Fileset(pattern, options)
\r
25 .on('error', cb ? cb : em.emit.bind(em, 'error'))
\r
26 .on('match', em.emit.bind(em, 'match'))
\r
27 .on('match', em.emit.bind(em, 'include'))
\r
28 .on('end', next.bind({}, pattern))
\r
31 function next(pattern, matches) {
\r
32 results = results.concat(matches);
\r
34 if (!(--remaining)) {
\r
35 results = results.filter(function(file) {
\r
36 return !excludes.filter(function(glob) {
\r
37 var match = minimatch(file, glob, { matchBase: true });
\r
38 if(match) em.emit('exclude', file);
\r
43 if(cb) cb(null, results);
\r
44 em.emit('end', results);
\r
52 fileset.sync = function filesetSync(include, exclude) {
\r
53 if (!exclude) exclude = '';
\r
55 // includes / excludes, either an array or string separated by comma or whitespace
\r
56 var includes = (typeof include === 'string') ? include.split(/[\s,]/g) : include;
\r
57 var excludes = (typeof exclude === 'string') ? exclude.split(/[\s,]/g) : exclude;
\r
59 // Filter out any false positive '' empty strings
\r
60 includes = includes.filter(function(pattern) { return pattern; });
\r
61 excludes = excludes.filter(function(pattern) { return pattern; });
\r
63 // - todo: pass in glob options as last param
\r
64 var options = { matchBase: true };
\r
66 // First, glob match on all include patters into a single array
\r
67 var results = includes.map(function(include) {
\r
68 return glob.sync(include, options);
\r
69 }).reduce(function(a, b) {
\r
73 // Then filters out on any exclude match
\r
74 var ignored = excludes.map(function(exclude) {
\r
75 return glob.sync(exclude, options);
\r
76 }).reduce(function(a, b) {
\r
80 // And filter any exclude match
\r
81 results = results.filter(function(file) {
\r
82 return !ignored.filter(function(glob) {
\r
83 return minimatch(file, glob, { matchBase: true });
\r
90 fileset.Fileset = function Fileset(pattern, options, cb) {
\r
91 if (typeof options === 'function') cb = options, options = {};
\r
92 if (!options) options = {};
\r
94 Glob.call(this, pattern, options);
\r
96 if (typeof cb === 'function') {
\r
97 this.on('error', cb);
\r
98 this.on('end', function(matches) { cb(null, matches); });
\r
102 util.inherits(fileset.Fileset, Glob);
\r