├── .npmignore
├── .eslintignore
├── test
├── fixtures
│ ├── foo.md
│ └── an (odd) filename.js
└── mocha.js
├── .gitignore
├── .babelrc
├── .travis.yml
├── .eslintrc
├── Makefile
├── package.json
├── LICENSE-MIT
├── CHANGELOG.md
├── README.md
└── lib
└── fileset.js
/.npmignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | src
2 |
--------------------------------------------------------------------------------
/test/fixtures/foo.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/test/fixtures/an (odd) filename.js:
--------------------------------------------------------------------------------
1 | var odd = true;
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015"],
3 |
4 | "plugins": [
5 | "add-module-exports"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - '6'
5 | - '5'
6 | - '4'
7 | - '0.12'
8 | - '0.10'
9 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "es6": true,
4 | "mocha": true
5 | },
6 |
7 | "parserOptions": {
8 | "sourceType": "module"
9 | },
10 |
11 | "extends": "standard",
12 |
13 | "rules": {
14 | "semi": ["error", "always"],
15 | "no-multi-spaces": ["error", { "exceptions": { "VariableDeclarator": true } }],
16 | "promise/param-names": 0
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | all: help
3 |
4 | help:
5 | bake -h
6 |
7 | test:
8 | cd test && ../node_modules/.bin/mocha -R spec .
9 |
10 | eslint:
11 | eslint .
12 |
13 | fix:
14 | eslint . --fix
15 |
16 | release: version push publish
17 |
18 | version:
19 | standard-version -m '%s'
20 |
21 | push:
22 | git push origin master --tags
23 |
24 | publish:
25 | npm publish
26 |
27 | .PHONY: test
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fileset",
3 | "version": "2.0.3",
4 | "description": "Wrapper around miniglob / minimatch combo to allow multiple patterns matching and include-exclude ability",
5 | "main": "./lib/fileset",
6 | "scripts": {
7 | "test": "make test"
8 | },
9 | "dependencies": {
10 | "glob": "^7.0.3",
11 | "minimatch": "^3.0.3"
12 | },
13 | "devDependencies": {
14 | "babel-cli": "^6.9.0",
15 | "babel-plugin-add-module-exports": "^0.2.1",
16 | "babel-plugin-transform-regenerator": "^6.9.0",
17 | "babel-preset-es2015": "^6.9.0",
18 | "bake-cli": "^0.6.0",
19 | "eslint": "^3.7.1",
20 | "eslint-config-standard": "^6.2.0",
21 | "eslint-plugin-promise": "^3.0.0",
22 | "eslint-plugin-standard": "^2.0.1",
23 | "mocha": "^3.1.2",
24 | "standard-version": "^3.0.0",
25 | "watchd": "^0.1.1"
26 | },
27 | "homepage": "https://github.com/mklabs/node-fileset",
28 | "repository": {
29 | "type": "git",
30 | "url": "git://github.com/mklabs/node-fileset.git"
31 | },
32 | "license": "MIT",
33 | "author": "mklabs"
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012-2016 Mickael Daniel
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4 |
5 |
6 | ## [2.0.2](https://github.com/mklabs/node-fileset/compare/v1.0.1...v2.0.2) (2016-06-27)
7 |
8 |
9 |
10 |
11 | ## [2.0.0](https://github.com/mklabs/node-fileset/compare/v1.0.1...v2.0.0) (2016-06-26)
12 |
13 |
14 | ## [1.0.1](https://github.com/mklabs/node-fileset/compare/v1.0.0...v1.0.1) (2016-06-01)
15 |
16 |
17 |
18 |
19 | # [1.0.0](https://github.com/mklabs/node-fileset/compare/v0.2.1...v1.0.0) (2016-06-01)
20 |
21 |
22 | ### Bug Fixes
23 |
24 | * update old tests to use mocha instead ([f4e0d8e](https://github.com/mklabs/node-fileset/commit/f4e0d8e))
25 |
26 |
27 | ### Features
28 |
29 | * **sync:** always ignore node_modules in sync mode ([c6593c0](https://github.com/mklabs/node-fileset/commit/c6593c0))
30 | * update glob 7 ([954bab5](https://github.com/mklabs/node-fileset/commit/954bab5))
31 |
32 |
33 | ### BREAKING CHANGES
34 |
35 | * Includes an update to glob / minimatch. As described in
36 | 378de99522caf7b665c53472a34a41a0b295b489
37 |
38 | > Since glob 6 removes support for comment and negation patterns, this may
39 | > or may not be a breaking change from fileset's pov.
40 |
41 | ## Changelog
42 |
43 | - Releases: https://github.com/mklabs/node-fileset/releases
44 |
45 | ### 0.2.1
46 |
47 | - Sync API
48 |
49 | ### 0.2.0
50 |
51 | - Drop support for 0.8
52 | - PR mklabs/node-fileset#14 reapplied
53 | - [Minor code style changes](bf8afae22a49cf64720177d6036090db2852d744)
54 |
55 | ### 0.1.8
56 |
57 | - PR mklabs/node-fileset#17 - Reverts PR#14
58 |
59 | ### 0.1.6 / 0.1.7
60 |
61 | - PR mklabs/node-fileset#14
62 |
63 | ### 0.1.x
64 |
65 | - Initial commit
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # node-fileset [](http://travis-ci.org/mklabs/node-fileset)
2 |
3 | Exposes a basic wrapper on top of
4 | [Glob](https://github.com/isaacs/node-glob) /
5 | [minimatch](https://github.com/isaacs/minimatch) combo both written by
6 | @isaacs. Glob now uses JavaScript instead of C++ bindings which makes it
7 | usable in Node.js 0.6.x and Windows platforms.
8 |
9 | [](https://nodei.co/npm/fileset/)
10 |
11 | Adds multiples patterns matching and exlude ability. This is
12 | basically just a sugar API syntax where you can specify a list of includes
13 | and optional exclude patterns. It works by setting up the necessary
14 | miniglob "fileset" and filtering out the results using minimatch.
15 |
16 | *[Changelog](https://github.com/mklabs/node-fileset/blob/master/CHANGELOG.md#changelog)*
17 |
18 | ## Install
19 |
20 | npm install fileset
21 |
22 | ## Usage
23 |
24 | Can be used with callback or emitter style.
25 |
26 | * **include**: list of glob patterns `foo/**/*.js *.md src/lib/**/*`
27 | * **exclude**: *optional* list of glob patterns to filter include
28 | results `foo/**/*.js *.md`
29 | * **callback**: *optional* function that gets called with an error if
30 | something wrong happend, otherwise null with an array of results
31 |
32 | The callback is optional since the fileset method return an instance of
33 | EventEmitter which emit different events you might use:
34 |
35 | * *match*: Every time a match is found, miniglob emits this event with
36 | the pattern.
37 | * *include*: Emitted each time an include match is found.
38 | * *exclude*: Emitted each time an exclude match is found and filtered
39 | out from the fileset.
40 | * *end*: Emitted when the matching is finished with all the matches
41 | found, optionally filtered by the exclude patterns.
42 |
43 | #### Callback
44 |
45 | ```js
46 | var fileset = require('fileset');
47 |
48 | fileset('**/*.js', '**.min.js', function(err, files) {
49 | if (err) return console.error(err);
50 |
51 | console.log('Files: ', files.length);
52 | console.log(files);
53 | });
54 | ```
55 |
56 | #### Event emitter
57 |
58 | ```js
59 | var fileset = require('fileset');
60 |
61 | fileset('**.coffee README.md *.json Cakefile **.js', 'node_modules/**')
62 | .on('match', console.log.bind(console, 'error'))
63 | .on('include', console.log.bind(console, 'includes'))
64 | .on('exclude', console.log.bind(console, 'excludes'))
65 | .on('end', console.log.bind(console, 'end'));
66 | ```
67 |
68 | `fileset` returns an instance of EventEmitter, with an `includes` property
69 | which is the array of Fileset objects (inheriting from
70 | `miniglob.Miniglob`) that were used during the mathing process, should
71 | you want to use them individually.
72 |
73 | Check out the
74 | [tests](https://github.com/mklabs/node-fileset/tree/master/tests) for
75 | more examples.
76 |
77 | ## Sync usage
78 |
79 | ```js
80 | var results = fileset.sync('*.md *.js', 'CHANGELOG.md node_modules/**/*.md node_modules/**/*.js');
81 | ```
82 |
83 | The behavior should remain the same, although it lacks the last `options` arguments to pass to internal `glob` and `minimatch` dependencies.
84 |
85 | ## Tests
86 |
87 | Run `npm test`
88 |
89 | ## Why
90 |
91 | Mainly for a build tool with cake files, to provide me an easy way to get
92 | a list of files by either using glob or path patterns, optionally
93 | allowing exclude patterns to filter out the results.
94 |
95 | All the magic is happening in
96 | [Glob](https://github.com/isaacs/node-glob) and
97 | [minimatch](https://github.com/isaacs/minimatch). Check them out!
98 |
--------------------------------------------------------------------------------
/lib/fileset.js:
--------------------------------------------------------------------------------
1 | var util = require('util');
2 | var minimatch = require('minimatch');
3 | var glob = require('glob');
4 | var Glob = glob.Glob;
5 | var EventEmitter = require('events').EventEmitter;
6 |
7 | module.exports = fileset;
8 |
9 | // Async API
10 | function fileset(include, exclude, options, cb) {
11 | if (typeof exclude === 'function') cb = exclude, exclude = '';
12 | else if (typeof options === 'function') cb = options, options = {};
13 |
14 | var includes = (typeof include === 'string') ? include.split(' ') : include;
15 | var excludes = (typeof exclude === 'string') ? exclude.split(' ') : exclude;
16 |
17 | var em = new EventEmitter;
18 | var remaining = includes.length;
19 | var results = [];
20 |
21 | if (!includes.length) return cb(new Error('Must provide an include pattern'));
22 |
23 | em.includes = includes.map(function(pattern) {
24 | return new fileset.Fileset(pattern, options)
25 | .on('error', cb ? cb : em.emit.bind(em, 'error'))
26 | .on('match', em.emit.bind(em, 'match'))
27 | .on('match', em.emit.bind(em, 'include'))
28 | .on('end', next.bind({}, pattern))
29 | });
30 |
31 | function next(pattern, matches) {
32 | results = results.concat(matches);
33 |
34 | if (!(--remaining)) {
35 | results = results.filter(function(file) {
36 | return !excludes.filter(function(glob) {
37 | var match = minimatch(file, glob, { matchBase: true });
38 | if(match) em.emit('exclude', file);
39 | return match;
40 | }).length;
41 | });
42 |
43 | if(cb) cb(null, results);
44 | em.emit('end', results);
45 | }
46 | }
47 |
48 | return em;
49 | }
50 |
51 | // Sync API
52 | fileset.sync = function filesetSync(include, exclude) {
53 | if (!exclude) exclude = '';
54 |
55 | // includes / excludes, either an array or string separated by comma or whitespace
56 | var includes = (typeof include === 'string') ? include.split(/[\s,]/g) : include;
57 | var excludes = (typeof exclude === 'string') ? exclude.split(/[\s,]/g) : exclude;
58 |
59 | // Filter out any false positive '' empty strings
60 | includes = includes.filter(function(pattern) { return pattern; });
61 | excludes = excludes.filter(function(pattern) { return pattern; });
62 |
63 | // - todo: pass in glob options as last param
64 | var options = { matchBase: true };
65 |
66 | // always ignore node_modules for sync api
67 | options.ignore = ['node_modules/**/*'];
68 |
69 | // First, glob match on all include patters into a single array
70 | var results = includes.map(function(include) {
71 | return glob.sync(include, options);
72 | }).reduce(function(a, b) {
73 | return a.concat(b);
74 | }, []);
75 |
76 | // Then filters out on any exclude match
77 | var ignored = excludes.map(function(exclude) {
78 | return glob.sync(exclude, options);
79 | }).reduce(function(a, b) {
80 | return a.concat(b);
81 | }, []);
82 |
83 | // And filter any exclude match
84 | results = results.filter(function(file) {
85 | return !ignored.filter(function(glob) {
86 | return minimatch(file, glob, { matchBase: true });
87 | }).length;
88 | });
89 |
90 | return results;
91 | };
92 |
93 | fileset.Fileset = function Fileset(pattern, options, cb) {
94 | if (typeof options === 'function') cb = options, options = {};
95 | if (!options) options = {};
96 |
97 | // ignore node_modules by default, unless specified
98 | options.ignore = options.ignore || ['node_modules/**/*'];
99 |
100 | Glob.call(this, pattern, options);
101 |
102 | if (typeof cb === 'function') {
103 | this.on('error', cb);
104 | this.on('end', function(matches) { cb(null, matches); });
105 | }
106 | };
107 |
108 | util.inherits(fileset.Fileset, Glob);
109 |
--------------------------------------------------------------------------------
/test/mocha.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert');
2 | var fileset = require('..');
3 | var EventEmitter = require('events').EventEmitter;
4 |
5 | describe('Sync API - Given a **.md pattern', function() {
6 | it('returns the list of matching file in this repo', function() {
7 | var results = fileset.sync('*.md', 'test/fixtures/**/*.md');
8 | assert.ok(Array.isArray(results), 'should be an array');
9 | assert.ok(results.length, 'should return at least one element');
10 | assert.equal(results.length, 1, 'actually, should return only one');
11 | });
12 | });
13 |
14 | describe('Sync API - Given a *.md and **.js pattern, and two exclude', function() {
15 | it('returns the list of matching file in this repo', function() {
16 | var results = fileset.sync('*.md *.js', 'CHANGELOG.md test/fixtures/**/*.md test/fixtures/**/*.js');
17 |
18 | assert.ok(Array.isArray(results), 'should be an array');
19 | assert.ok(results.length, 'should return at least one element');
20 | assert.equal(results.length, 3, 'actually, should return only 3');
21 | });
22 | });
23 |
24 | // Given a **.md pattern
25 | describe('Given a **.md pattern', function() {
26 | it('returns the list of matching file in this repo', function(done) {
27 | fileset('*.js', function(err, results) {
28 | if(err) return done(err);
29 | assert.ok(Array.isArray(results), 'should be an array');
30 | assert.ok(results.length, 'should return at least one element');
31 | assert.equal(results.length, 1, 'actually, should return only two');
32 | done();
33 | });
34 | });
35 | });
36 |
37 | describe('Say we want the **.js files, but not those in node_modules', function() {
38 | it('recursively walks the dir and returns the matching list', function(done) {
39 | fileset('**/*.js', '', function(err, results) {
40 | if(err) return done(err);
41 | assert.ok(Array.isArray(results), 'should be an array');
42 | assert.equal(results.length, 2);
43 | done();
44 | });
45 | });
46 |
47 | it('recursively walks the dir and returns the matching list', function(done) {
48 | fileset('**/*.js', function(err, results) {
49 | if(err) return done(err);
50 | assert.ok(Array.isArray(results), 'should be an array');
51 | assert.equal(results.length, 2);
52 | done();
53 | });
54 | });
55 |
56 | it('supports multiple paths at once', function(done) {
57 | fileset('**/*.js *.md', 'node_modules/**', function(err, results) {
58 | if(err) return done(err);
59 |
60 | assert.ok(Array.isArray(results), 'should be an array');
61 | assert.equal(results.length, 2);
62 |
63 | assert.deepEqual(results, [
64 | 'fixtures/an (odd) filename.js',
65 | 'mocha.js'
66 | ]);
67 |
68 | done();
69 | });
70 | });
71 |
72 | it('Should support multiple paths for excludes as well', function(done) {
73 | fileset('**/*.js *.md', 'node_modules/** **.md tests/*.js', function(err, results) {
74 | if(err) return done(err);
75 | assert.ok(Array.isArray(results), 'should be an array');
76 | assert.equal(results.length, 2);
77 |
78 | assert.deepEqual(results, [
79 | 'fixtures/an (odd) filename.js',
80 | 'mocha.js'
81 | ]);
82 |
83 | done();
84 | });
85 | });
86 | });
87 |
88 | describe('Testing out emmited events', function() {
89 | it('recursively walk the dir and return the matching list', function(done) {
90 | fileset('**/*.js', 'node_modules/**')
91 | .on('error', done)
92 | .on('end', function(results) {
93 | assert.ok(Array.isArray(results), 'should be an array');
94 | assert.equal(results.length, 2);
95 | done();
96 | });
97 | });
98 |
99 | it('support multiple paths at once', function(done) {
100 | fileset('**/*.js *.md', 'node_modules/**')
101 | .on('error', done)
102 | .on('end', function(results) {
103 | assert.ok(Array.isArray(results), 'should be an array');
104 | assert.equal(results.length, 2);
105 |
106 | assert.deepEqual(results, [
107 | 'fixtures/an (odd) filename.js',
108 | 'mocha.js'
109 | ]);
110 |
111 | done();
112 | });
113 | });
114 | });
115 |
116 | describe('Testing patterns passed as arrays', function() {
117 | it('match files passed as an array with odd filenames', function(done) {
118 | fileset(['fixtures/*.md', 'fixtures/an (odd) filename.js'], ['*.md'])
119 | .on('error', done)
120 | .on('end', function(results) {
121 | assert.ok(Array.isArray(results), 'should be an array');
122 | assert.equal(results.length, 1);
123 | assert.deepEqual(results, [
124 | 'fixtures/an (odd) filename.js',
125 | ]);
126 |
127 | done();
128 | });
129 | });
130 | });
131 |
--------------------------------------------------------------------------------