From 5d725884e068bb20b13d112d633c2c76a8911ce9 Mon Sep 17 00:00:00 2001 From: Etienne Folio Date: Wed, 7 Jan 2015 16:59:39 +0100 Subject: [PATCH] add support for group of patterns --- README.md | 9 ++++++++- lib/globule.js | 33 ++++++++++++++++++++++++++++----- test/globule_test.js | 8 +++++++- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 036c11e..6e47830 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ var filepaths = globule.find('**/*.js'); ## Documentation ### globule.find -Returns a unique array of all file or directory paths that match the given globbing pattern(s). This method accepts either comma separated globbing patterns or an array of globbing patterns. Paths matching patterns that begin with `!` will be excluded from the returned array. Patterns are processed in order, so inclusion and exclusion order is significant. Patterns may be specified as function arguments or as a `src` property of the options object. +Returns a unique array of all file or directory paths that match the given globbing pattern(s). This method accepts either comma separated globbing patterns, an array of globbing patterns, or an array of arrays of globbing patterns. Paths matching patterns that begin with `!` will be excluded from the returned array. Patterns are processed in order, so inclusion and exclusion order is significant. Patterns may be specified as function arguments or as a `src` property of the options object. If you specify patterns inside arrays of arrays, each level will glob together, and the results will be flattened without duplicates. ```js globule.find(patterns [, patterns [, ...]] [, options]) @@ -31,6 +31,13 @@ The `options` object supports all [glob][] library options, along with a few ext [glob]: https://github.com/isaacs/node-glob +**Note:** Patterns as arrays of arrays are useful if you want to negate only in part of your glob results. + +```js +globule.find([['**/*.js'], ['**/*.html', '!**/excl/**/*']]) +``` +In this example, `excl/a.js` will be matched, but not `excl/a.html`. + ### globule.match Match one or more globbing patterns against one or more file paths. Returns a uniqued array of all file paths that match any of the specified globbing patterns. Both the `patterns` and `filepaths` arguments can be a single string or array of strings. Paths matching patterns that begin with `!` will be excluded from the returned array. Patterns are processed in order, so inclusion and exclusion order is significant. diff --git a/lib/globule.js b/lib/globule.js index 5a3eeac..5893ebf 100644 --- a/lib/globule.js +++ b/lib/globule.js @@ -46,7 +46,18 @@ globule.match = function(patterns, filepaths, options) { // Return empty set if either patterns or filepaths was omitted. if (patterns == null || filepaths == null) { return []; } // Normalize patterns and filepaths to flattened arrays. - patterns = _.isArray(patterns) ? _.flatten(patterns) : [patterns]; + patterns = _.isArray(patterns) ? patterns : [patterns]; + // Merge merge results if patterns are grouped + if (_.any(patterns, _.isArray)) { + return _(patterns) + .map(function(patternArray) { + return globule.match(patternArray, filepaths, options); + }) + .flatten() + .uniq() + .value() + ; + } filepaths = _.isArray(filepaths) ? _.flatten(filepaths) : [filepaths]; // Return empty set if there are no patterns or filepaths. if (patterns.length === 0 || filepaths.length === 0) { return []; } @@ -68,15 +79,27 @@ globule.find = function() { // If the last argument is an options object, remove it from args. var options = _.isPlainObject(args[args.length - 1]) ? args.pop() : {}; // If options.src was specified, use it. Otherwise, use all non-options - // arguments. Flatten nested arrays. + // arguments. var patterns; if (options.src) { - patterns = _.isArray(options.src) ? _.flatten(options.src) : [options.src]; - } else { - patterns = _.flatten(args); + patterns = _.isArray(options.src) ? options.src : [options.src]; + } + else { + patterns = _.flatten(args, true); } // Return empty set if there are no patterns. if (patterns.length === 0) { return []; } + // Merge find results if patterns are grouped + if (_.any(patterns, _.isArray)) { + return _(patterns) + .map(function(patternArray) { + return globule.find(patternArray, _.omit(options, 'src')); + }) + .flatten() + .uniq() + .value() + ; + } var srcBase = options.srcBase || options.cwd; // Create glob-specific options object. var globOptions = _.extend({}, options); diff --git a/test/globule_test.js b/test/globule_test.js index 4b921ea..a91d7ae 100644 --- a/test/globule_test.js +++ b/test/globule_test.js @@ -186,7 +186,7 @@ exports['find'] = { test.done(); }, 'exclusion': function(test) { - test.expect(8); + test.expect(10); test.deepEqual(globule.find(['!js/*.js']), [], 'solitary exclusion should match nothing'); test.deepEqual(globule.find(['js/bar.js','!js/bar.js']), [], 'exclusion should negate match'); test.deepEqual(globule.find(['**/*.js', '!js/foo.js']), @@ -207,6 +207,12 @@ exports['find'] = { test.deepEqual(globule.find(['js/bar.js', '!**/b*.*', 'js/foo.js', 'css/baz.css', 'css/qux.css']), ['js/foo.js', 'css/baz.css', 'css/qux.css'], 'inclusion / exclusion order matters'); + test.deepEqual(globule.find([['js/bar.js'], ['!js/b*.*', 'js/foo.js']]), + ['js/bar.js', 'js/foo.js'], + 'exclusion in subarray should not exclude from previous sub arrays'); + test.deepEqual(globule.find([['js/bar.js'], ['js/foo.js', '!js/*']]), + ['js/bar.js'], + 'exclusion in subarray should exclude from current sub arrays'); test.done(); }, 'options.src': function(test) {