Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

refactor to use miniglob / minimatch combo, working on windows \o/

  • Loading branch information...
commit 5bbb1bd81f2b8bcf972d7334302844241ec1daa6 1 parent 58dc14a
@mklabs authored
View
5 .travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+
+node_js:
+ - 0.4
+ - 0.6
View
6 README.md
@@ -16,7 +16,7 @@ Can be used with callback or emitter style.
* **exclude**: *optional* list of glob patterns to filter include results `foo/**/*.js *.md`
* **callback**: *optional* function that gets called with an error if something wrong happend, otherwise null with an array of results
-The callback is optional since the fileset method return an instance of EventEmitter which emit different events you might use:
+The callback is optional since the fileset method return an instance of EventEmitter which emit different events you might use:
* *match*: triggered on findit.file and each glob returned by node-glob, triggerd multiple times
* *includes*: array of includes files, triggered once
@@ -42,8 +42,8 @@ The callback is optional since the fileset method return an instance of EventEmi
fileset('**.coffee README.md *.json Cakefile **.js', 'node_modules')
.on('match', console.log.bind(console, 'error'))
- .on('includes', console.log.bind(console, 'includes'))
- .on('excludes', console.log.bind(console, 'excludes'))
+ .on('include', console.log.bind(console, 'includes'))
+ .on('exclude', console.log.bind(console, 'excludes'))
.on('end', console.log.bind(console, 'end'));
Check out the [tests](https://github.com/mklabs/node-fileset/tree/master/tests) for more examples.
View
193 lib/fileset.js
@@ -1,134 +1,65 @@
-(function() {
- var EventEmitter, findit, fs, glob, globs, path, rsplit;
- glob = require('glob');
+
+
+
+var util = require('util'),
+ minimatch = require('minimatch'),
+ Miniglob = require('miniglob').Miniglob,
EventEmitter = require('events').EventEmitter;
- path = require('path');
- fs = require('fs');
- findit = require('findit');
- rsplit = /\s|,\s/;
- module.exports = function(include, exclude, callback) {
- var em, excludes, exludesLength, includes, includesLength, match;
- em = new EventEmitter;
- match = {
- includes: [],
- excludes: []
- };
- if (!callback && typeof exclude === 'function') {
- callback = exclude;
- exclude = "";
- }
- if (!callback && !exclude) {
- exclude = "";
- }
- includes = include.split(rsplit).filter(function(it) {
- return it;
- }) || [];
- excludes = exclude.split(rsplit).filter(function(it) {
- return it;
- }) || [];
- exludesLength = excludes.length;
- includesLength = includes.length;
- globs(includes, em, function(err, results) {
- if (err) {
- if (callback) {
- callback(err);
- }
- return em.emit('error', err);
- }
- match.includes = results;
- em.emit('include', results);
- if (!excludes.length) {
- if (callback) {
- callback(null, results);
- }
- return em.emit('end', results);
- }
- return globs(excludes, em, function(err, results) {
- if (err) {
- if (callback) {
- callback(err);
- }
- return em.emit('error', err);
- }
- match.excludes = results;
- em.emit('exclude', results);
- match.includes = match.includes.filter(function(it) {
- var dotbegin, excluded;
- dotbegin = /^\./.test(it.split('/').reverse()[0]);
- excluded = !!~match.excludes.indexOf(it);
- return !excluded;
- });
- em.emit('end', match.includes);
- if (callback) {
- return callback(null, match.includes);
- }
+
+module.exports = fileset;
+
+function fileset(include, exclude, cb) {
+ if (typeof exclude === 'function') cb = exclude, exclude = '';
+
+ var em = new EventEmitter,
+ includes = include.split(' '),
+ excludes = exclude.split(' '),
+ remaining = includes.length,
+ results = [];
+
+ if(!includes.length) return cb(new Error('Must provide an include pattern'));
+
+ em.includes = includes.map(function(pattern) {
+ return new fileset.Fileset(pattern)
+ .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;
});
- });
- return em;
- };
- globs = function(patterns, em, callback) {
- var index, matches, pattern, remaining, _len, _results;
- if (!patterns.length) {
- return callback(new Error('patterns is empty'));
- }
- matches = [];
- patterns = patterns.filter(function(it) {
- return it;
- });
- remaining = patterns.length;
- _results = [];
- for (index = 0, _len = patterns.length; index < _len; index++) {
- pattern = patterns[index];
- _results.push((function(pattern, index) {
- var absolute, errors, files, isGlob;
- isGlob = /\*/.test(pattern);
- if (isGlob) {
- return glob(pattern, function(err, results) {
- if (err) {
- return callback(err);
- }
- matches = matches.concat(results.map(function(it) {
- return path.resolve(it);
- }));
- if (--remaining === 0) {
- return callback(null, matches);
- }
- });
- }
- files = [];
- errors = [];
- absolute = path.resolve(pattern);
- return fs.stat(absolute, function(err, stat) {
- if (err) {
- if (--remaining === 0) {
- callback(null, matches);
- }
- return;
- }
- if (stat && stat.isFile()) {
- matches = matches.concat([absolute]);
- if (--remaining === 0) {
- callback(null, matches);
- }
- return;
- }
- return findit(absolute).on('file', function(file) {
- em.emit('match', file);
- return files.push(file);
- }).on('error', function(err) {
- return errors.push(err);
- }).on('end', function() {
- if (errors.length) {
- return callback(new Error('findit returned with errors'), errors);
- }
- matches = matches.concat(files);
- if (--remaining === 0) {
- return callback(null, matches);
- }
- });
- });
- })(pattern, index));
+
+ if(cb) cb(null, results);
+ em.emit('end', results);
}
- return _results;
- };
-}).call(this);
+ }
+
+ return em;
+}
+
+fileset.Fileset = function Fileset(pattern, options, cb) {
+
+ if (typeof options === 'function') cb = options, options = {};
+ if (!options) options = {};
+
+ Miniglob.call(this, pattern, options);
+
+ if(typeof cb === 'function') {
+ this.on('error', cb);
+ this.on('end', function(matches) { cb(null, matches); });
+ }
+};
+
+util.inherits(fileset.Fileset, Miniglob);
+
+
View
44 lib/mini-fileset.js
@@ -1,44 +0,0 @@
-
-
-
-var findit = require('findit'),
- path = require('path'),
- minimatch = require('minimatch'),
- EventEmitter = require('events').EventEmitter;
-
-module.exports = fileset;
-
-
-function fileset(include, exclude, cb) {
- console.log('fileset', arguments);
- debugger;
- var em = new EventEmitter,
- // change api to support options, at least options.cwd
- root = process.cwd();
-
- if(!cb) {
- console.log(typeof exclude)
- if(typeof exclude === 'function') {
- cb = exclude;
- delete exclude;
- }
- }
-
- var dir = path.dirname(path.join(root, include)),
- filter = minimatch.filter(include, { matchBase : true }),
- files = {};
-
- console.log('b', dir, path.join(root, include));
-
- findit.find(dir)
- .on('error', cb)
- .on('end', function(err, results) {
- console.log('end findit', arguments);
- if(err) return cb(err);
- cb(null, Array.prototype.slice.call(arguments, 1).filter(filter));
- });
-
-
- console.log('fileset', arguments);
- return em;
-}
View
8 package.json
@@ -8,15 +8,15 @@
"type": "git",
"url": "git://github.com/mklabs/node-fileset.git"
},
- "main": "./lib/mini-fileset",
+ "main": "./lib/fileset",
"scripts": {
"test": "node tests/test.js"
},
"engines": {
- "node": "> 0.4"
+ "node": "*"
},
"dependencies": {
- "findit": "~0.1.2",
- "minimatch": "~0.1.3"
+ "miniglob": "https://nodeload.github.com/isaacs/miniglob/tarball/master",
+ "minimatch": "https://nodeload.github.com/mklabs/minimatch/tarball/windows-path-prefixing"
}
}
View
70 tests/callback.js
@@ -1,70 +0,0 @@
-
-
-var vows = require('vows'),
- EventEmitter = require('events').EventEmitter,
- fileset = require('../'),
- assert = require('assert');
-
-
-vows.describe('Callback api test suite for node-fileset')
- .addBatch({
- 'Given a **.coffee pattern': {
- topic: function() {
- var self = this,
- em = new EventEmitter;
-
- fileset('**.coffee', function(err, results) {
- if (err) return em.emit('error', err);
- em.emit('success', results);
- });
-
- return em;
- },
-
- 'should return the list of matching file in this repo': function(err, results) {
- assert.ok(results.length);
- },
- },
-
- 'exludes pattern to node_modules': {
- topic: function() {
- var self = this,
- em = new EventEmitter;
-
- fileset('**.coffee', 'node_modules', function(err, results) {
- if (err) return em.emit('error', err);
- em.emit('success', results);
- });
-
- return em;
- },
-
- 'should return a list of files without node_modules in their path': function(err, results) {
- var ok = results.filter(function(it) {
- return (/node_modules/.test(it))
- });
-
- assert.ok(!ok.length);
- }
- },
-
- 'a more complex example': {
- topic: function() {
- var self = this,
- em = new EventEmitter;
-
- fileset('**.coffee README.md *.json Cakefile **.js', 'node_modules', function(err, results) {
- if (err) return em.emit('error', err);
- em.emit('success', results);
- });
-
- return em;
- },
-
- 'should work as expected': function(err, results) {
- assert.equal(results.length, 7);
- }
- }
-
- })
- .export(module)
View
66 tests/emitter.js
@@ -1,66 +0,0 @@
-
-
-var vows = require('vows'),
- EventEmitter = require('events').EventEmitter,
- fileset = require('../'),
- assert = require('assert');
-
-
-vows.describe('Emitter api test suite for node-fileset')
- .addBatch({
- 'Given a **.coffee pattern': {
- topic: function() {
- var self = this,
- em = new EventEmitter;
-
- fileset('**.coffee')
- .on('error', em.emit.bind(em, 'error'))
- .on('end', em.emit.bind(em, 'success'));
-
- return em;
- },
-
- 'should return the list of matching file in this repo': function(err, results) {
- assert.ok(results.length);
- },
- },
-
- 'exludes pattern to node_modules': {
- topic: function() {
- var self = this,
- em = new EventEmitter;
-
- fileset('**.coffee', 'node_modules')
- .on('error', em.emit.bind(em, 'error'))
- .on('end', em.emit.bind(em, 'success'));
- return em;
- },
-
- 'should return a list of files without node_modules in their path': function(err, results) {
- var ok = results.filter(function(it) {
- return (/node_modules/.test(it))
- });
-
- assert.ok(!ok.length);
- }
- },
-
- 'a more complex example': {
- topic: function() {
- var self = this,
- em = new EventEmitter;
-
- fileset('**.coffee README.md *.json Cakefile **.js', 'node_modules')
- .on('error', em.emit.bind(em, 'error'))
- .on('end', em.emit.bind(em, 'success'));
-
- return em;
- },
-
- 'should work as expected': function(err, results) {
- assert.ok(results.length === 7);
- }
- }
-
- })
- .export(module)
View
61 tests/helper.js
@@ -0,0 +1,61 @@
+
+var EventEmitter = require('events').EventEmitter,
+ assert = require('assert'),
+ tests = {};
+
+module.exports = test;
+test.run = run;
+
+// ## Test helpers
+
+function test(msg, handler) {
+ tests[msg] = handler;
+}
+
+function run() {
+ var specs = Object.keys(tests),
+ specsRemaining = specs.length;
+
+ specs.forEach(function(spec) {
+ var handler = tests[spec];
+
+ // grab the set of asserts for this spec
+ var shoulds = handler(),
+ keys = Object.keys(shoulds),
+ remaining = keys.length;
+
+ keys.forEach(function(should) {
+ var em = new EventEmitter(),
+ to = setTimeout(function() {
+ assert.fail('never ended');
+ }, 5000);
+
+ em
+ .on('error', function assertFail(err) { assert.fail(err) })
+ .on('end', function assertOk() {
+ clearTimeout(to);
+ shoulds[should].status = true;
+
+ // till we get to 0
+ if(!(--remaining)) {
+ console.log([
+ '',
+ '» ' + spec,
+ keys.map(function(k) { return ' » ' + k; }).join('\n'),
+ '',
+ ' Total: ' + keys.length,
+ ' Failed: ' + keys.map(function(item) { return shoulds[should].status; }).filter(function(status) { return !status; }).length,
+ ''
+ ].join('\n'));
+
+ if(!(--specsRemaining)) {
+ console.log('All done');
+ }
+
+ }
+ });
+
+ shoulds[should](em);
+ });
+ });
+}
View
24 tests/runner.js
@@ -1,24 +0,0 @@
-
-
-var exec = require('child_process').exec,
- windows = process.platform === 'win32';
-
-// basic test runner test suite
-
-// Needed only to be able to run the test seamlessly on posix / windows platform.
-//
-// If we don't want to rely on the vows global executable and rely on the
-// devDependencies' installed locally, that's how I do it. I may need some advice on this.
-//
-// Bin executables are made available "locally" in node_modules/.bin. On posix, this map the
-// `./node_modules/.bin/packagename`. On windows, the command is slightly different and needs to use
-// `./node_modules/.bin/packagename.cmd`
-
-var cmd = windows ? '\"./node_modules/.bin/vows.cmd\"' : './node_modules/.bin/vows';
-
-exec(cmd + ' ./tests/callback.js ./tests/emitter.js --spec', function(err, stdout, stderr) {
- console.log(stdout);
- console.log(stderr);
-
- process.exit(err ? 1 : 0);
-});
View
198 tests/test.js
@@ -2,46 +2,63 @@
var EventEmitter = require('events').EventEmitter,
fileset = require('../'),
assert = require('assert'),
- tests = {};
+ test = require('./helper');
// Given a **.coffee pattern
-test('Given a **.md pattern', function(em) {
+test('Given a **.md pattern', function() {
return {
'should return the list of matching file in this repo': function(em) {
- console.log('should should', this, arguments);
-
fileset('*.md', function(err, results) {
if(err) return em.emit('error', err);
- assert.ok(results && results.length);
assert.ok(Array.isArray(results), 'should be an array');
- console.log(results.length, results);
-
- assert.equal(results.length, 1);
-
+ assert.ok(results.length, 'should return at least one element');
+ assert.equal(results.length, 1, 'actually, should return only one');
em.emit('end');
});
}
}
});
-
-test('Say we want the **.js files', function(em) {
+test('Say we want the **.js files, but not those in node_modules', function() {
return {
'Should recursively walk the dir and return the matching list': function(em) {
- console.log('should should', this, arguments);
+ fileset('**/*.js', 'node_modules/**', function(err, results) {
+ if(err) return em.emit('error', err);
+ assert.ok(Array.isArray(results), 'should be an array');
+ assert.equal(results.length, 3);
+ em.emit('end');
+ });
+ },
- fileset('**.js', function(err, results) {
+ 'Should support multiple paths at once': function(em) {
+ fileset('**/*.js *.md', 'node_modules/**', function(err, results) {
if(err) return em.emit('error', err);
assert.ok(Array.isArray(results), 'should be an array');
- console.log(results.length, results);
- assert.ok(results.length);
+ assert.equal(results.length, 4);
+ assert.deepEqual(results, [
+ 'README.md',
+ 'lib/fileset.js',
+ 'tests/helper.js',
+ 'tests/test.js'
+ ]);
+ em.emit('end');
+ });
+ },
+ 'Should support multiple paths for excludes as well': function(em) {
+ fileset('**/*.js *.md', 'node_modules/** **.md tests/*.js', function(err, results) {
+ if(err) return em.emit('error', err);
+ assert.ok(Array.isArray(results), 'should be an array');
assert.equal(results.length, 1);
+ assert.deepEqual(results, [
+ 'lib/fileset.js'
+ ]);
+
em.emit('end');
});
}
@@ -49,135 +66,42 @@ test('Say we want the **.js files', function(em) {
});
-run();
-
-
-
-
-
-
-
-
-
-
-
-
-
-// ## Test helpers
-function test(msg, handler) {
- tests[msg] = handler;
-}
-
-function run() {
- var specs = Object.keys(tests),
- specsRemaining = specs.length;
+test('Testing out emmited events', function() {
- specs.forEach(function(spec) {
- var handler = tests[spec];
-
- // grab the set of asserts for this spec
- var shoulds = handler(),
- keys = Object.keys(shoulds),
- remaining = keys.length;
-
- keys.forEach(function(should) {
- var em = new EventEmitter();
-
- em
- .on('error', function assertFail(err) { assert.ifError(err) })
- .on('end', function assertOk() {
- shoulds[should].status = true;
-
- // till we get to 0
- if(!(--remaining)) {
- console.log([
- '',
- '» ' + should,
- '',
- ' Total: ' + keys.length,
- ' Failed: ' + keys.map(function(item) { return shoulds[should].status; }).filter(function(status) { return !status; }).length,
- ''
- ].join('\n'));
-
- if(!(--specsRemaining)) {
- console.log('All done');
- }
-
- }
- });
-
- shoulds[should](em);
- });
-
-
-
- console.log(shoulds);
- });
-}
-
-
-
-/*
-vows.describe('Callback api test suite for node-fileset')
- .addBatch({
- 'Given a **.coffee pattern': {
- topic: function() {
- var self = this,
- em = new EventEmitter;
-
- fileset('**.coffee', function(err, results) {
- if (err) return em.emit('error', err);
- em.emit('success', results);
+ // todos: the tests for match, include, exclude events, but seems like it's ok
+ return {
+ 'Should recursively walk the dir and return the matching list': function(em) {
+ fileset('**/*.js', 'node_modules/**')
+ .on('error', em.emit.bind(em, 'error'))
+ .on('end', function(results) {
+ assert.ok(Array.isArray(results), 'should be an array');
+ assert.equal(results.length, 3);
+ em.emit('end');
});
-
- return em;
- },
-
- 'should return the list of matching file in this repo': function(err, results) {
- assert.ok(results.length);
- },
},
- 'exludes pattern to node_modules': {
- topic: function() {
- var self = this,
- em = new EventEmitter;
-
- fileset('**.coffee', 'node_modules', function(err, results) {
- if (err) return em.emit('error', err);
- em.emit('success', results);
- });
-
- return em;
- },
-
- 'should return a list of files without node_modules in their path': function(err, results) {
- var ok = results.filter(function(it) {
- return (/node_modules/.test(it))
+ 'Should support multiple paths at once': function(em) {
+ fileset('**/*.js *.md', 'node_modules/**')
+ .on('error', em.emit.bind(em, 'error'))
+ .on('end', function(results) {
+ assert.ok(Array.isArray(results), 'should be an array');
+ assert.equal(results.length, 4);
+
+ assert.deepEqual(results, [
+ 'README.md',
+ 'lib/fileset.js',
+ 'tests/helper.js',
+ 'tests/test.js'
+ ]);
+
+ em.emit('end');
});
+ }
+ }
+});
- assert.ok(!ok.length);
- }
- },
-
- 'a more complex example': {
- topic: function() {
- var self = this,
- em = new EventEmitter;
- fileset('**.coffee README.md *.json Cakefile **.js', 'node_modules', function(err, results) {
- if (err) return em.emit('error', err);
- em.emit('success', results);
- });
- return em;
- },
+test.run();
- 'should work as expected': function(err, results) {
- assert.equal(results.length, 7);
- }
- }
- })
- .export(module)
-*/
Please sign in to comment.
Something went wrong with that request. Please try again.