[Pkg-javascript-commits] [node-globule] 01/03: Imported Upstream version 0.2.0

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Fri Feb 27 16:33:39 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository node-globule.

commit 945a532895d6c14dd227e15460e73b929e65de83
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Fri Feb 27 17:04:31 2015 +0100

    Imported Upstream version 0.2.0
---
 .gitignore                                         |   1 +
 .jshintrc                                          |  14 +
 .travis.yml                                        |   6 +
 Gruntfile.js                                       |  48 ++
 LICENSE-MIT                                        |  22 +
 README.md                                          | 127 +++++
 lib/globule.js                                     | 187 ++++++++
 package.json                                       |  52 ++
 test/fixtures/expand/README.md                     |   0
 test/fixtures/expand/css/baz.css                   |   0
 test/fixtures/expand/css/qux.css                   |   0
 test/fixtures/expand/deep/deep.txt                 |   0
 test/fixtures/expand/deep/deeper/deeper.txt        |   0
 .../expand/deep/deeper/deepest/deepest.txt         |   0
 test/fixtures/expand/js/bar.js                     |   0
 test/fixtures/expand/js/foo.js                     |   0
 test/globule_test.js                               | 521 +++++++++++++++++++++
 17 files changed, 978 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2ccbe46
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/node_modules/
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..8c86fc7
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,14 @@
+{
+  "curly": true,
+  "eqeqeq": true,
+  "immed": true,
+  "latedef": true,
+  "newcap": true,
+  "noarg": true,
+  "sub": true,
+  "undef": true,
+  "unused": true,
+  "boss": true,
+  "eqnull": true,
+  "node": true
+}
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..cbace30
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,6 @@
+language: node_js
+node_js:
+  - "0.8"
+  - "0.10"
+before_script:
+  - npm install -g grunt-cli
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..c3f7d74
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,48 @@
+'use strict';
+
+module.exports = function(grunt) {
+
+  // Project configuration.
+  grunt.initConfig({
+    nodeunit: {
+      files: ['test/**/*_test.js'],
+    },
+    jshint: {
+      options: {
+        jshintrc: '.jshintrc'
+      },
+      gruntfile: {
+        src: 'Gruntfile.js'
+      },
+      lib: {
+        src: ['lib/**/*.js']
+      },
+      test: {
+        src: ['test/*.js']
+      },
+    },
+    watch: {
+      gruntfile: {
+        files: '<%= jshint.gruntfile.src %>',
+        tasks: ['jshint:gruntfile']
+      },
+      lib: {
+        files: '<%= jshint.lib.src %>',
+        tasks: ['jshint:lib', 'nodeunit']
+      },
+      test: {
+        files: '<%= jshint.test.src %>',
+        tasks: ['jshint:test', 'nodeunit']
+      },
+    },
+  });
+
+  // These plugins provide necessary tasks.
+  grunt.loadNpmTasks('grunt-contrib-nodeunit');
+  grunt.loadNpmTasks('grunt-contrib-jshint');
+  grunt.loadNpmTasks('grunt-contrib-watch');
+
+  // Default task.
+  grunt.registerTask('default', ['jshint', 'nodeunit']);
+
+};
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..1056fb5
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,22 @@
+Copyright (c) 2014 "Cowboy" Ben Alman
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..036c11e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,127 @@
+# globule [![Build Status](https://secure.travis-ci.org/cowboy/node-globule.png?branch=master)](http://travis-ci.org/cowboy/node-globule)
+
+An easy-to-use wildcard globbing library.
+
+## Getting Started
+Install the module with: `npm install globule`
+
+```javascript
+var globule = require('globule');
+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.
+
+```js
+globule.find(patterns [, patterns [, ...]] [, options])
+globule.find({src: patterns, /* other options */})
+```
+
+The `options` object supports all [glob][] library options, along with a few extras. These are the most commonly used:
+
+* `src` This property may be used instead of specifying patterns as function arguments.
+* `filter` Either a valid [fs.Stats method name](http://nodejs.org/docs/latest/api/fs.html#fs_class_fs_stats) or a function that will be passed the matched `src` filepath and `options` object as arguments. This function should return a `Boolean` value.
+* `nonull` Retain globbing patterns in result set even if they fail to match files.
+* `matchBase` Patterns without slashes will match just the basename part. Eg. this makes `*.js` work like `**/*.js`.
+* `srcBase` Patterns will be matched relative to the specified path instead of the current working directory. This is a synonym for `cwd`.
+* `prefixBase` Any specified `srcBase` will be prefixed to all returned filepaths.
+
+[glob]: https://github.com/isaacs/node-glob
+
+### 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.
+
+```js
+globule.match(patterns, filepaths [, options])
+```
+
+### globule.isMatch
+This method contains the same signature and logic as the `globule.match` method, but returns `true` if any files were matched, otherwise `false`.
+
+```js
+globule.isMatch(patterns, filepaths [, options])
+```
+
+### globule.mapping
+Given a set of source file paths, returns an array of src-dest file mapping objects. Both src and dest paths may be renamed, depending on the options specified. Patterns may be specified as function arguments or as a `src` property of the options object.
+
+```js
+globule.mapping(filepaths [, filepaths [, ...]]  [, options])
+globule.mapping({src: filepaths, /* other options */})
+```
+
+In addition to the options the `globule.find` method supports, the options object also supports these properties:
+
+* `srcBase` The directory from which patterns are matched. Any string specified as `srcBase` is effectively stripped from the beginning of all matched paths.
+* `destBase` The specified path is prefixed to all `dest` filepaths.
+* `ext` Remove anything after (and including) the first `.` in the destination path, then append this value.
+* `extDot` Change the behavior of `ext`, `"first"` and `"last"` will remove anything after the first or last `.` in the destination filename, respectively. Defaults to `"first"`.
+* `flatten` Remove the path component from all matched src files. The src file path is still joined to the specified destBase.
+* `rename` If specified, this function will be responsible for returning the final `dest` filepath. By default, it flattens paths (if specified), changes extensions (if specified) and joins the matched path to the `destBase`.
+
+### globule.findMapping
+This method is a convenience wrapper around the `globule.find` and `globule.mapping` methods.
+
+```js
+globule.findMapping(patterns [, options])
+```
+
+
+## Examples
+
+Given the files `foo/a.js` and `foo/b.js`:
+
+### srcBase and destBase
+
+```js
+globule.find("foo/*.js")
+// ["foo/a.js", "foo/b.js"]
+
+globule.find("*.js", {srcBase: "foo"})
+// ["a.js", "b.js"]
+
+globule.find({src: "*.js", srcBase: "foo", prefixBase: true})
+// ["foo/a.js", "foo/b.js"]
+```
+
+```js
+globule.findMapping("foo/*.js")
+// [{src: ["foo/a.js"], dest: "foo/a.js"}, {src: ["foo/b.js"], dest: "foo/b.js"}]
+
+globule.findMapping("foo/*.js", {destBase: "bar"})
+// [{src: ["foo/a.js"], dest: "bar/foo/a.js"}, {src: ["foo/b.js"], dest: "bar/foo/b.js"}]
+
+globule.findMapping({src: "*.js", srcBase: "foo", destBase: "bar"})
+// [{src: ["foo/a.js"], dest: "bar/a.js"}, {src: ["foo/b.js"], dest: "bar/b.js"}]
+```
+
+```js
+globule.mapping(["foo/a.js", "foo/b.js"])
+// [{src: ["foo/a.js"], dest: "foo/a.js"}, {src: ["foo/b.js"], dest: "foo/b.js"}]
+
+globule.mapping(["foo/a.js", "foo/b.js"], {destBase: "bar"})
+// [{src: ["foo/a.js"], dest: "bar/foo/a.js"}, {src: ["foo/b.js"], dest: "bar/foo/b.js"}]
+
+globule.mapping("foo/a.js", "foo/b.js", {destBase: "bar"})
+// [{src: ["foo/a.js"], dest: "bar/foo/a.js"}, {src: ["foo/b.js"], dest: "bar/foo/b.js"}]
+
+globule.mapping(["a.js", "b.js"], {srcBase: "foo", destBase: "bar"})
+// [{src: ["foo/a.js"], dest: "bar/a.js"}, {src: ["foo/b.js"], dest: "bar/b.js"}]
+
+globule.mapping({src: ["a.js", "b.js"], srcBase: "foo", destBase: "bar"})
+// [{src: ["foo/a.js"], dest: "bar/a.js"}, {src: ["foo/b.js"], dest: "bar/b.js"}]
+```
+
+## Contributing
+In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/).
+
+## Release History
+2014-01-07 - v0.2.0 - Updated dependencies. Added `src` option. Improved exclusion speed significantly.
+2013-04-11 - v0.1.0 - Initial release.
+
+## License
+Copyright (c) 2014 "Cowboy" Ben Alman  
+Licensed under the MIT license.
diff --git a/lib/globule.js b/lib/globule.js
new file mode 100644
index 0000000..5a3eeac
--- /dev/null
+++ b/lib/globule.js
@@ -0,0 +1,187 @@
+/*
+ * globule
+ * https://github.com/cowboy/node-globule
+ *
+ * Copyright (c) 2014 "Cowboy" Ben Alman
+ * Licensed under the MIT license.
+ */
+
+'use strict';
+
+var fs = require('fs');
+var path = require('path');
+
+var _ = require('lodash');
+var glob = require('glob');
+var minimatch = require('minimatch');
+
+// The module.
+var globule = exports;
+
+// Process specified wildcard glob patterns or filenames against a
+// callback, excluding and uniquing files in the result set.
+function processPatterns(patterns, options, fn) {
+  var result = [];
+  _.each(patterns, function(pattern) {
+    // The first character is not ! (inclusion). Add all matching filepaths
+    // to the result set.
+    if (pattern.indexOf('!') !== 0) {
+      result = _.union(result, fn(pattern));
+      return;
+    }
+    // The first character is ! (exclusion). Remove any filepaths from the
+    // result set that match this pattern, sans leading !.
+    var filterFn = minimatch.filter(pattern.slice(1), options);
+    result = _.filter(result, function(filepath) {
+      return !filterFn(filepath);
+    });
+  });
+  return result;
+}
+
+// Match a filepath or filepaths against one or more wildcard patterns. Returns
+// all matching filepaths. This behaves just like minimatch.match, but supports
+// any number of patterns.
+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];
+  filepaths = _.isArray(filepaths) ? _.flatten(filepaths) : [filepaths];
+  // Return empty set if there are no patterns or filepaths.
+  if (patterns.length === 0 || filepaths.length === 0) { return []; }
+  // Return all matching filepaths.
+  return processPatterns(patterns, options, function(pattern) {
+    return minimatch.match(filepaths, pattern, options || {});
+  });
+};
+
+// Match a filepath or filepaths against one or more wildcard patterns. Returns
+// true if any of the patterns match.
+globule.isMatch = function() {
+  return globule.match.apply(null, arguments).length > 0;
+};
+
+// Return an array of all file paths that match the given wildcard patterns.
+globule.find = function() {
+  var args = _.toArray(arguments);
+  // 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.
+  var patterns;
+  if (options.src) {
+    patterns = _.isArray(options.src) ? _.flatten(options.src) : [options.src];
+  } else {
+    patterns = _.flatten(args);
+  }
+  // Return empty set if there are no patterns.
+  if (patterns.length === 0) { return []; }
+  var srcBase = options.srcBase || options.cwd;
+  // Create glob-specific options object.
+  var globOptions = _.extend({}, options);
+  if (srcBase) {
+    globOptions.cwd = srcBase;
+  }
+  // Get all matching filepaths.
+  var matches = processPatterns(patterns, options, function(pattern) {
+    return glob.sync(pattern, globOptions);
+  });
+  // If srcBase and prefixBase were specified, prefix srcBase to matched paths.
+  if (srcBase && options.prefixBase) {
+    matches = matches.map(function(filepath) {
+      return path.join(srcBase, filepath);
+    });
+  }
+  // Filter result set?
+  if (options.filter) {
+    matches = matches.filter(function(filepath) {
+      // If srcBase was specified but prefixBase was NOT, prefix srcBase
+      // temporarily, for filtering.
+      if (srcBase && !options.prefixBase) {
+        filepath = path.join(srcBase, filepath);
+      }
+      try {
+        if (_.isFunction(options.filter)) {
+          return options.filter(filepath, options);
+        } else {
+          // If the file is of the right type and exists, this should work.
+          return fs.statSync(filepath)[options.filter]();
+        }
+      } catch(err) {
+        // Otherwise, it's probably not the right type.
+        return false;
+      }
+    });
+  }
+  return matches;
+};
+
+var pathSeparatorRe = /[\/\\]/g;
+var extDotRe = {
+  first: /(\.[^\/]*)?$/,
+  last: /(\.[^\/\.]*)?$/,
+};
+function rename(dest, options) {
+  // Flatten path?
+  if (options.flatten) {
+    dest = path.basename(dest);
+  }
+  // Change the extension?
+  if (options.ext) {
+    dest = dest.replace(extDotRe[options.extDot], options.ext);
+  }
+  // Join dest and destBase?
+  if (options.destBase) {
+    dest = path.join(options.destBase, dest);
+  }
+  return dest;
+}
+
+// Build a mapping of src-dest filepaths from the given set of filepaths.
+globule.mapping = function(filepaths, options) {
+  // Return empty set if filepaths was omitted.
+  if (filepaths == null) { return []; }
+  options = _.defaults({}, options, {
+    extDot: 'first',
+    rename: rename,
+  });
+  var files = [];
+  var fileByDest = {};
+  // Find all files matching pattern, using passed-in options.
+  filepaths.forEach(function(src) {
+    // Generate destination filename.
+    var dest = options.rename(src, options);
+    // Prepend srcBase to all src paths.
+    if (options.srcBase) {
+      src = path.join(options.srcBase, src);
+    }
+    // Normalize filepaths to be unix-style.
+    dest = dest.replace(pathSeparatorRe, '/');
+    src = src.replace(pathSeparatorRe, '/');
+    // Map correct src path to dest path.
+    if (fileByDest[dest]) {
+      // If dest already exists, push this src onto that dest's src array.
+      fileByDest[dest].src.push(src);
+    } else {
+      // Otherwise create a new src-dest file mapping object.
+      files.push({
+        src: [src],
+        dest: dest,
+      });
+      // And store a reference for later use.
+      fileByDest[dest] = files[files.length - 1];
+    }
+  });
+  return files;
+};
+
+// Return a mapping of src-dest filepaths from files matching the given
+// wildcard patterns.
+globule.findMapping = function() {
+  var args = _.toArray(arguments);
+  // If the last argument is an options object, remove it from args.
+  var options = _.isPlainObject(args[args.length - 1]) ? args.pop() : {};
+  // Generate mapping from found filepaths.
+  return globule.mapping(globule.find(args, options), options);
+};
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..e040dc3
--- /dev/null
+++ b/package.json
@@ -0,0 +1,52 @@
+{
+  "name": "globule",
+  "description": "An easy-to-use wildcard globbing library.",
+  "version": "0.2.0",
+  "homepage": "https://github.com/cowboy/node-globule",
+  "author": {
+    "name": "\"Cowboy\" Ben Alman",
+    "url": "http://benalman.com/"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/cowboy/node-globule.git"
+  },
+  "bugs": {
+    "url": "https://github.com/cowboy/node-globule/issues"
+  },
+  "licenses": [
+    {
+      "type": "MIT",
+      "url": "https://github.com/cowboy/node-globule/blob/master/LICENSE-MIT"
+    }
+  ],
+  "main": "lib/globule",
+  "engines": {
+    "node": ">= 0.8.0"
+  },
+  "scripts": {
+    "test": "grunt nodeunit"
+  },
+  "devDependencies": {
+    "grunt-contrib-jshint": "~0.8.0",
+    "grunt-contrib-nodeunit": "~0.2.2",
+    "grunt-contrib-watch": "~0.5.3",
+    "grunt": "~0.4.2"
+  },
+  "keywords": [
+    "glob",
+    "file",
+    "match",
+    "mapping",
+    "expand",
+    "wildcard",
+    "pattern",
+    "sync",
+    "awesome"
+  ],
+  "dependencies": {
+    "lodash": "~2.4.1",
+    "glob": "~3.2.7",
+    "minimatch": "~0.2.11"
+  }
+}
diff --git a/test/fixtures/expand/README.md b/test/fixtures/expand/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/test/fixtures/expand/css/baz.css b/test/fixtures/expand/css/baz.css
new file mode 100644
index 0000000..e69de29
diff --git a/test/fixtures/expand/css/qux.css b/test/fixtures/expand/css/qux.css
new file mode 100644
index 0000000..e69de29
diff --git a/test/fixtures/expand/deep/deep.txt b/test/fixtures/expand/deep/deep.txt
new file mode 100644
index 0000000..e69de29
diff --git a/test/fixtures/expand/deep/deeper/deeper.txt b/test/fixtures/expand/deep/deeper/deeper.txt
new file mode 100644
index 0000000..e69de29
diff --git a/test/fixtures/expand/deep/deeper/deepest/deepest.txt b/test/fixtures/expand/deep/deeper/deepest/deepest.txt
new file mode 100644
index 0000000..e69de29
diff --git a/test/fixtures/expand/js/bar.js b/test/fixtures/expand/js/bar.js
new file mode 100644
index 0000000..e69de29
diff --git a/test/fixtures/expand/js/foo.js b/test/fixtures/expand/js/foo.js
new file mode 100644
index 0000000..e69de29
diff --git a/test/globule_test.js b/test/globule_test.js
new file mode 100644
index 0000000..4b921ea
--- /dev/null
+++ b/test/globule_test.js
@@ -0,0 +1,521 @@
+'use strict';
+
+var path = require('path');
+
+var globule = require('../lib/globule.js');
+
+/*
+  ======== A Handy Little Nodeunit Reference ========
+  https://github.com/caolan/nodeunit
+
+  Test methods:
+    test.expect(numAssertions)
+    test.done()
+  Test assertions:
+    test.ok(value, [message])
+    test.equal(actual, expected, [message])
+    test.notEqual(actual, expected, [message])
+    test.deepEqual(actual, expected, [message])
+    test.notDeepEqual(actual, expected, [message])
+    test.strictEqual(actual, expected, [message])
+    test.notStrictEqual(actual, expected, [message])
+    test.throws(block, [error], [message])
+    test.doesNotThrow(block, [error], [message])
+    test.ifError(value)
+*/
+
+exports['match'] = {
+  'empty set': function(test) {
+    test.expect(6);
+    // Should return empty set if a required argument is missing or an empty set.
+    test.deepEqual(globule.match(null, 'foo.js'), [], 'should return empty set.');
+    test.deepEqual(globule.match('*.js', null), [], 'should return empty set.');
+    test.deepEqual(globule.match([], 'foo.js'), [], 'should return empty set.');
+    test.deepEqual(globule.match('*.js', []), [], 'should return empty set.');
+    test.deepEqual(globule.match(null, ['foo.js']), [], 'should return empty set.');
+    test.deepEqual(globule.match(['*.js'], null), [], 'should return empty set.');
+    test.done();
+  },
+  'basic matching': function(test) {
+    test.expect(6);
+    test.deepEqual(globule.match('*.js', 'foo.js'), ['foo.js'], 'should match correctly.');
+    test.deepEqual(globule.match('*.js', ['foo.js']), ['foo.js'], 'should match correctly.');
+    test.deepEqual(globule.match('*.js', ['foo.js', 'bar.css']), ['foo.js'], 'should match correctly.');
+    test.deepEqual(globule.match(['*.js', '*.css'], 'foo.js'), ['foo.js'], 'should match correctly.');
+    test.deepEqual(globule.match(['*.js', '*.css'], ['foo.js']), ['foo.js'], 'should match correctly.');
+    test.deepEqual(globule.match(['*.js', '*.css'], ['foo.js', 'bar.css']), ['foo.js', 'bar.css'], 'should match correctly.');
+    test.done();
+  },
+  'no matches': function(test) {
+    test.expect(2);
+    test.deepEqual(globule.match('*.js', 'foo.css'), [], 'should fail to match.');
+    test.deepEqual(globule.match('*.js', ['foo.css', 'bar.css']), [], 'should fail to match.');
+    test.done();
+  },
+  'unique': function(test) {
+    test.expect(2);
+    test.deepEqual(globule.match('*.js', ['foo.js', 'foo.js']), ['foo.js'], 'should return a uniqued set.');
+    test.deepEqual(globule.match(['*.js', '*.*'], ['foo.js', 'foo.js']), ['foo.js'], 'should return a uniqued set.');
+    test.done();
+  },
+  'flatten': function(test) {
+    test.expect(1);
+    test.deepEqual(globule.match([['*.js', '*.css'], ['*.*', '*.js']], [['foo.js', ['bar.css']]]),
+      ['foo.js', 'bar.css'],
+      'should process nested pattern / filepaths arrays correctly.');
+    test.done();
+  },
+  'exclusion': function(test) {
+    test.expect(5);
+    test.deepEqual(globule.match(['!*.js'], ['foo.js', 'bar.js']), [], 'solitary exclusion should match nothing');
+    test.deepEqual(globule.match(['*.js', '!*.js'], ['foo.js', 'bar.js']), [], 'exclusion should cancel match');
+    test.deepEqual(globule.match(['*.js', '!f*.js'], ['foo.js', 'bar.js', 'baz.js']),
+      ['bar.js', 'baz.js'],
+      'partial exclusion should partially cancel match');
+    test.deepEqual(globule.match(['*.js', '!*.js', 'b*.js'], ['foo.js', 'bar.js', 'baz.js']),
+      ['bar.js', 'baz.js'],
+      'inclusion / exclusion order matters');
+    test.deepEqual(globule.match(['*.js', '!f*.js', '*.js'], ['foo.js', 'bar.js', 'baz.js']),
+      ['bar.js', 'baz.js', 'foo.js'],
+      'inclusion / exclusion order matters');
+    test.done();
+  },
+  'options.matchBase': function(test) {
+    test.expect(2);
+    test.deepEqual(globule.match('*.js', ['foo.js', 'bar', 'baz/xyz.js'], {matchBase: true}),
+      ['foo.js', 'baz/xyz.js'],
+      'should matchBase (minimatch) when specified.');
+    test.deepEqual(globule.match('*.js', ['foo.js', 'bar', 'baz/xyz.js']),
+      ['foo.js'],
+      'should not matchBase (minimatch) by default.');
+    test.done();
+  },
+};
+
+exports['isMatch'] = {
+  'basic matching': function(test) {
+    test.expect(6);
+    test.ok(globule.isMatch('*.js', 'foo.js'), 'should match correctly.');
+    test.ok(globule.isMatch('*.js', ['foo.js']), 'should match correctly.');
+    test.ok(globule.isMatch('*.js', ['foo.js', 'bar.css']), 'should match correctly.');
+    test.ok(globule.isMatch(['*.js', '*.css'], 'foo.js'), 'should match correctly.');
+    test.ok(globule.isMatch(['*.js', '*.css'], ['foo.js']), 'should match correctly.');
+    test.ok(globule.isMatch(['*.js', '*.css'], ['foo.js', 'bar.css']), 'should match correctly.');
+    test.done();
+  },
+  'no matches': function(test) {
+    test.expect(6);
+    test.ok(!globule.isMatch('*.js', 'foo.css'), 'should fail to match.');
+    test.ok(!globule.isMatch('*.js', ['foo.css', 'bar.css']), 'should fail to match.');
+    test.ok(!globule.isMatch(null, 'foo.css'), 'should fail to match.');
+    test.ok(!globule.isMatch('*.js', null), 'should fail to match.');
+    test.ok(!globule.isMatch([], 'foo.css'), 'should fail to match.');
+    test.ok(!globule.isMatch('*.js', []), 'should fail to match.');
+    test.done();
+  },
+  'options.matchBase': function(test) {
+    test.expect(2);
+    test.ok(globule.isMatch('*.js', ['baz/xyz.js'], {matchBase: true}), 'should matchBase (minimatch) when specified.');
+    test.ok(!globule.isMatch('*.js', ['baz/xyz.js']), 'should not matchBase (minimatch) by default.');
+    test.done();
+  },
+};
+
+exports['find'] = {
+  setUp: function(done) {
+    this.cwd = process.cwd();
+    process.chdir('test/fixtures/expand');
+    done();
+  },
+  tearDown: function(done) {
+    process.chdir(this.cwd);
+    done();
+  },
+  'basic matching': function(test) {
+    test.expect(5);
+    test.deepEqual(globule.find('**/*.js'), ['js/bar.js', 'js/foo.js'], 'single pattern argument should match.');
+    test.deepEqual(globule.find('**/*.js', '**/*.css'),
+      ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'],
+      'multiple pattern arguments should match.');
+    test.deepEqual(globule.find(['**/*.js', '**/*.css']),
+      ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'],
+      'array of patterns should match.');
+    test.deepEqual(globule.find([['**/*.js'], [['**/*.css', 'js/*.js']]]),
+      ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'],
+      'array of arrays of patterns should be flattened.');
+    test.deepEqual(globule.find('*.xyz'), [], 'bad pattern should fail to match.');
+    test.done();
+  },
+  'unique': function(test) {
+    test.expect(4);
+    test.deepEqual(globule.find('**/*.js', 'js/*.js'),
+      ['js/bar.js', 'js/foo.js'],
+      'file list should be uniqed.');
+    test.deepEqual(globule.find('**/*.js', '**/*.css', 'js/*.js'), ['js/bar.js', 'js/foo.js',
+      'css/baz.css', 'css/qux.css'],
+      'file list should be uniqed.');
+    test.deepEqual(globule.find('js', 'js/'),
+      ['js', 'js/'],
+      'mixed non-ending-/ and ending-/ dirs will not be uniqed by default.');
+    test.deepEqual(globule.find('js', 'js/', {mark: true}),
+      ['js/'],
+      'mixed non-ending-/ and ending-/ dirs will be uniqed when "mark" is specified.');
+    test.done();
+  },
+  'file order': function(test) {
+    test.expect(5);
+    var actual = globule.find('**/*.{js,css}');
+    var expected = ['css/baz.css', 'css/qux.css', 'js/bar.js', 'js/foo.js'];
+    test.deepEqual(actual, expected, 'should select 4 files in this order, by default.');
+
+    actual = globule.find('js/foo.js', 'js/bar.js', '**/*.{js,css}');
+    expected = ['js/foo.js', 'js/bar.js', 'css/baz.css', 'css/qux.css'];
+    test.deepEqual(actual, expected, 'specifically-specified-up-front file order should be maintained.');
+
+    actual = globule.find('js/bar.js', 'js/foo.js', '**/*.{js,css}');
+    expected = ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'];
+    test.deepEqual(actual, expected, 'specifically-specified-up-front file order should be maintained.');
+
+    actual = globule.find('**/*.{js,css}', '!css/qux.css', 'css/qux.css');
+    expected = ['css/baz.css', 'js/bar.js', 'js/foo.js', 'css/qux.css'];
+    test.deepEqual(actual, expected, 'if a file is excluded and then re-added, it should be added at the end.');
+
+    actual = globule.find('js/foo.js', '**/*.{js,css}', '!css/qux.css', 'css/qux.css');
+    expected = ['js/foo.js', 'css/baz.css', 'js/bar.js', 'css/qux.css'];
+    test.deepEqual(actual, expected, 'should be able to combine specified-up-front and excluded/added-at-end.');
+    test.done();
+  },
+  'exclusion': function(test) {
+    test.expect(8);
+    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']),
+      ['js/bar.js'],
+      'should omit single file from matched set');
+    test.deepEqual(globule.find(['!js/foo.js', '**/*.js']),
+      ['js/bar.js', 'js/foo.js'],
+      'inclusion / exclusion order matters');
+    test.deepEqual(globule.find(['**/*.js', '**/*.css', '!js/bar.js', '!css/baz.css']),
+      ['js/foo.js','css/qux.css'],
+      'multiple exclusions should be removed from the set');
+    test.deepEqual(globule.find(['**/*.js', '**/*.css', '!**/*.css']),
+      ['js/bar.js', 'js/foo.js'],
+      'excluded wildcards should be removed from the matched set');
+    test.deepEqual(globule.find(['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css', '!**/b*.*']),
+      ['js/foo.js', 'css/qux.css'],
+      'different pattern for exclusion should still work');
+    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.done();
+  },
+  'options.src': function(test) {
+    test.expect(4);
+    test.deepEqual(globule.find({src: '**/*.js'}), ['js/bar.js', 'js/foo.js'], 'single pattern argument should match.');
+    test.deepEqual(globule.find({src: ['**/*.js', '**/*.css']}),
+      ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'],
+      'array of patterns should match.');
+    test.deepEqual(globule.find({src: [['**/*.js'], [['**/*.css', 'js/*.js']]]}),
+      ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'],
+      'array of arrays of patterns should be flattened.');
+    test.deepEqual(globule.find({src: '*.xyz'}), [], 'bad pattern should fail to match.');
+    test.done();
+  },
+  'options.mark': function(test) {
+    test.expect(4);
+    test.deepEqual(globule.find('**d*/**'), [
+      'deep',
+      'deep/deep.txt',
+      'deep/deeper',
+      'deep/deeper/deeper.txt',
+      'deep/deeper/deepest',
+      'deep/deeper/deepest/deepest.txt'], 'should match files and directories.');
+    test.deepEqual(globule.find('**d*/**/'), [
+      'deep/',
+      'deep/deeper/',
+      'deep/deeper/deepest/'], 'trailing / in pattern should match directories only, matches end in /.');
+    test.deepEqual(globule.find('**d*/**', {mark: true}), [
+      'deep/',
+      'deep/deep.txt',
+      'deep/deeper/',
+      'deep/deeper/deeper.txt',
+      'deep/deeper/deepest/',
+      'deep/deeper/deepest/deepest.txt'], 'the minimatch "mark" option ensures directories end in /.');
+    test.deepEqual(globule.find('**d*/**/', {mark: true}), [
+      'deep/',
+      'deep/deeper/',
+      'deep/deeper/deepest/'], 'the minimatch "mark" option should not remove trailing / from matched paths.');
+    test.done();
+  },
+  'options.filter': function(test) {
+    test.expect(5);
+    test.deepEqual(globule.find('**d*/**', {filter: 'isFile'}), [
+      'deep/deep.txt',
+      'deep/deeper/deeper.txt',
+      'deep/deeper/deepest/deepest.txt'
+    ], 'should match files only.');
+    test.deepEqual(globule.find('**d*/**', {filter: 'isDirectory'}), [
+      'deep',
+      'deep/deeper',
+      'deep/deeper/deepest'
+    ], 'should match directories only.');
+    test.deepEqual(globule.find('**', {
+      arbitraryProp: /deepest/,
+      filter: function(filepath, options) {
+        return options.arbitraryProp.test(filepath);
+      }
+    }), [
+      'deep/deeper/deepest',
+      'deep/deeper/deepest/deepest.txt',
+    ], 'should filter arbitrarily.');
+    test.deepEqual(globule.find('js', 'css', {filter: 'isFile'}), [], 'should fail to match.');
+    test.deepEqual(globule.find('**/*.js', {filter: 'isDirectory'}), [], 'should fail to match.');
+    test.done();
+  },
+  'options.matchBase': function(test) {
+    test.expect(3);
+    test.deepEqual(globule.find('*.js'), [], 'should not matchBase (minimatch) by default.');
+    test.deepEqual(globule.find('*.js', {matchBase: true}),
+      ['js/bar.js', 'js/foo.js'],
+      'matchBase option should be passed through to minimatch.');
+    test.deepEqual(globule.find('*.js', '*.css', {matchBase: true}),
+      ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'],
+      'matchBase option should be passed through to minimatch.');
+    test.done();
+  },
+  'options.srcBase': function(test) {
+    test.expect(5);
+    test.deepEqual(globule.find(['**/deep*.txt'], {srcBase: 'deep'}),
+      ['deep.txt', 'deeper/deeper.txt', 'deeper/deepest/deepest.txt'],
+      'should find paths matching pattern relative to srcBase.');
+    test.deepEqual(globule.find(['**/deep*.txt'], {cwd: 'deep'}),
+      ['deep.txt', 'deeper/deeper.txt', 'deeper/deepest/deepest.txt'],
+      'cwd and srcBase should do the same thing.');
+    test.deepEqual(globule.find(['**/deep*'], {srcBase: 'deep', filter: 'isFile'}),
+      ['deep.txt', 'deeper/deeper.txt', 'deeper/deepest/deepest.txt'],
+      'srcBase should not prevent filtering.');
+    test.deepEqual(globule.find(['**/deep*'], {srcBase: 'deep', filter: 'isDirectory'}),
+      ['deeper', 'deeper/deepest'],
+      'srcBase should not prevent filtering.');
+    test.deepEqual(globule.find(['**/deep*.txt', '!**/deeper**'], {srcBase: 'deep'}),
+      ['deep.txt', 'deeper/deepest/deepest.txt'],
+      'srcBase should not prevent exclusions.');
+    test.done();
+  },
+  'options.prefixBase': function(test) {
+    test.expect(2);
+    test.deepEqual(globule.find(['**/deep*.txt'], {srcBase: 'deep', prefixBase: false}),
+      ['deep.txt', 'deeper/deeper.txt', 'deeper/deepest/deepest.txt'],
+      'should not prefix srcBase to returned paths.');
+    test.deepEqual(globule.find(['**/deep*.txt'], {srcBase: 'deep', prefixBase: true}),
+      ['deep/deep.txt', 'deep/deeper/deeper.txt', 'deep/deeper/deepest/deepest.txt'],
+      'should prefix srcBase to returned paths.');
+    test.done();
+  },
+  'options.nonull': function(test) {
+    test.expect(3);
+    test.deepEqual(globule.find(['*omg*'], {nonull: true}),
+      ['*omg*'],
+      'non-matching patterns should be returned in result set.');
+    test.deepEqual(globule.find(['js/a*', 'js/b*', 'js/c*'], {nonull: true}),
+      ['js/a*', 'js/bar.js', 'js/c*'],
+      'non-matching patterns should be returned in result set.');
+    test.deepEqual(globule.find(['js/foo.js', 'js/bar.js', 'js/nonexistent.js'], {nonull: true}),
+      ['js/foo.js', 'js/bar.js', 'js/nonexistent.js'],
+      'non-matching filenames should be returned in result set.');
+    test.done();
+  },
+};
+
+exports['mapping'] = {
+  'basic mapping': function(test) {
+    test.expect(1);
+
+    var actual = globule.mapping(['a.txt', 'b.txt', 'c.txt']);
+    var expected = [
+      {dest: 'a.txt', src: ['a.txt']},
+      {dest: 'b.txt', src: ['b.txt']},
+      {dest: 'c.txt', src: ['c.txt']},
+    ];
+    test.deepEqual(actual, expected, 'default options should create same-to-same src-dest mappings.');
+
+    test.done();
+  },
+  'options.srcBase': function(test) {
+    test.expect(2);
+    var actual, expected;
+    actual = globule.mapping(['a.txt', 'bar/b.txt', 'bar/baz/c.txt'], {srcBase: 'foo'});
+    expected = [
+      {dest: 'a.txt', src: ['foo/a.txt']},
+      {dest: 'bar/b.txt', src: ['foo/bar/b.txt']},
+      {dest: 'bar/baz/c.txt', src: ['foo/bar/baz/c.txt']},
+    ];
+    test.deepEqual(actual, expected, 'srcBase should be prefixed to src paths (no trailing /).');
+
+    actual = globule.mapping(['a.txt', 'bar/b.txt', 'bar/baz/c.txt'], {srcBase: 'foo/'});
+    test.deepEqual(actual, expected, 'srcBase should be prefixed to src paths (trailing /).');
+
+    test.done();
+  },
+  'options.destBase': function(test) {
+    test.expect(2);
+    var actual, expected;
+
+    actual = globule.mapping(['a.txt', 'bar/b.txt', 'bar/baz/c.txt'], {destBase: 'dest'});
+    expected = [
+      {dest: 'dest/a.txt', src: ['a.txt']},
+      {dest: 'dest/bar/b.txt', src: ['bar/b.txt']},
+      {dest: 'dest/bar/baz/c.txt', src: ['bar/baz/c.txt']},
+    ];
+    test.deepEqual(actual, expected, 'destBase should be prefixed to dest paths (no trailing /).');
+
+    actual = globule.mapping(['a.txt', 'bar/b.txt', 'bar/baz/c.txt'], {destBase: 'dest/'});
+    test.deepEqual(actual, expected, 'destBase should be prefixed to dest paths (trailing /).');
+
+    test.done();
+  },
+  'options.flatten': function(test) {
+    test.expect(1);
+    var actual, expected;
+
+    actual = globule.mapping(['a.txt', 'bar/b.txt', 'bar/baz/c.txt'], {flatten: true});
+    expected = [
+      {dest: 'a.txt', src: ['a.txt']},
+      {dest: 'b.txt', src: ['bar/b.txt']},
+      {dest: 'c.txt', src: ['bar/baz/c.txt']},
+    ];
+    test.deepEqual(actual, expected, 'flatten should remove all src path parts from dest.');
+
+    test.done();
+  },
+  'options.flatten + options.destBase': function(test) {
+    test.expect(1);
+    var actual, expected;
+
+    actual = globule.mapping(['a.txt', 'bar/b.txt', 'bar/baz/c.txt'], {destBase: 'dest', flatten: true});
+    expected = [
+      {dest: 'dest/a.txt', src: ['a.txt']},
+      {dest: 'dest/b.txt', src: ['bar/b.txt']},
+      {dest: 'dest/c.txt', src: ['bar/baz/c.txt']},
+    ];
+    test.deepEqual(actual, expected, 'flatten and destBase should work together.');
+
+    test.done();
+  },
+  'options.ext': function(test) {
+    test.expect(1);
+    var actual, expected;
+
+    actual = globule.mapping(['x/a.js', 'x.y/b.min.js', 'x.y/z.z/c'], {ext: '.foo'});
+    expected = [
+      {dest: 'x/a.foo', src: ['x/a.js']},
+      {dest: 'x.y/b.foo', src: ['x.y/b.min.js']},
+      {dest: 'x.y/z.z/c.foo', src: ['x.y/z.z/c']},
+    ];
+    test.deepEqual(actual, expected, 'by default, ext should replace everything after the first dot in the filename.');
+
+    test.done();
+  },
+  'options.extDot': function(test) {
+    test.expect(2);
+    var actual, expected;
+
+    actual = globule.mapping(['x/a.js', 'x.y/b.bbb.min.js', 'x.y/z.z/c'], {ext: '.foo', extDot: 'first'});
+    expected = [
+      {dest: 'x/a.foo', src: ['x/a.js']},
+      {dest: 'x.y/b.foo', src: ['x.y/b.bbb.min.js']},
+      {dest: 'x.y/z.z/c.foo', src: ['x.y/z.z/c']},
+    ];
+    test.deepEqual(actual, expected, 'extDot of "first" should replace everything after the first dot in the filename.');
+
+    actual = globule.mapping(['x/a.js', 'x.y/b.bbb.min.js', 'x.y/z.z/c'], {ext: '.foo', extDot: 'last'});
+    expected = [
+      {dest: 'x/a.foo', src: ['x/a.js']},
+      {dest: 'x.y/b.bbb.min.foo', src: ['x.y/b.bbb.min.js']},
+      {dest: 'x.y/z.z/c.foo', src: ['x.y/z.z/c']},
+    ];
+    test.deepEqual(actual, expected, 'extDot of "last" should replace everything after the last dot in the filename.');
+
+    test.done();
+  },
+  'options.rename': function(test) {
+    test.expect(1);
+    var actual, expected;
+    actual = globule.mapping(['a.txt', 'bar/b.txt', 'bar/baz/c.txt'], {
+      arbitraryProp: 'FOO',
+      rename: function(dest, options) {
+        return path.join(options.arbitraryProp, dest.toUpperCase());
+      }
+    });
+    expected = [
+      {dest: 'FOO/A.TXT', src: ['a.txt']},
+      {dest: 'FOO/BAR/B.TXT', src: ['bar/b.txt']},
+      {dest: 'FOO/BAR/BAZ/C.TXT', src: ['bar/baz/c.txt']},
+    ];
+    test.deepEqual(actual, expected, 'allow arbitrary renaming of files.');
+
+    test.done();
+  },
+};
+
+exports['findMapping'] = {
+  setUp: function(done) {
+    this.cwd = process.cwd();
+    process.chdir('test/fixtures');
+    done();
+  },
+  tearDown: function(done) {
+    process.chdir(this.cwd);
+    done();
+  },
+  'basic matching': function(test) {
+    test.expect(3);
+
+    var actual = globule.findMapping(['expand/**/*.txt']);
+    var expected = [
+      {dest: 'expand/deep/deep.txt', src: ['expand/deep/deep.txt']},
+      {dest: 'expand/deep/deeper/deeper.txt', src: ['expand/deep/deeper/deeper.txt']},
+      {dest: 'expand/deep/deeper/deepest/deepest.txt', src: ['expand/deep/deeper/deepest/deepest.txt']},
+    ];
+    test.deepEqual(actual, expected, 'default options');
+
+    actual = globule.findMapping({src: ['expand/**/*.txt']});
+    test.deepEqual(actual, expected, 'should also work when specifying src as option.');
+
+    expected = globule.mapping(globule.find(['expand/**/*.txt']));
+    test.deepEqual(actual, expected, 'this is what it\'s doing under the hood, anwyays.');
+
+    test.done();
+  },
+  'options.srcBase': function(test) {
+    test.expect(2);
+    var actual = globule.findMapping(['**/*.txt'], {destBase: 'dest', srcBase: 'expand/deep'});
+    var expected = [
+      {dest: 'dest/deep.txt', src: ['expand/deep/deep.txt']},
+      {dest: 'dest/deeper/deeper.txt', src: ['expand/deep/deeper/deeper.txt']},
+      {dest: 'dest/deeper/deepest/deepest.txt', src: ['expand/deep/deeper/deepest/deepest.txt']},
+    ];
+    test.deepEqual(actual, expected, 'srcBase should be stripped from front of destPath, pre-destBase+destPath join');
+
+    actual = globule.findMapping({src: ['**/*.txt'], destBase: 'dest', srcBase: 'expand/deep'});
+    test.deepEqual(actual, expected, 'should also work with src as option.');
+    test.done();
+  },
+  'multiple src per dest via rename': function(test) {
+    test.expect(1);
+    var actual = globule.findMapping('**/*.{js,css,txt}', {
+      srcBase: 'expand',
+      filter: 'isFile',
+      rename: function(dest) {
+        return 'build/all.' + dest.split('.').slice(-1);
+      },
+    });
+    var expected = [
+      {dest: 'build/all.css', src: ['expand/css/baz.css', 'expand/css/qux.css']},
+      {dest: 'build/all.txt', src: ['expand/deep/deep.txt', 'expand/deep/deeper/deeper.txt', 'expand/deep/deeper/deepest/deepest.txt']},
+      {dest: 'build/all.js', src: ['expand/js/bar.js', 'expand/js/foo.js']},
+    ];
+    test.deepEqual(actual, expected, 'multiple src files are grouped into a per-dest array when renamed dest is same');
+    test.done();
+  },
+};

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-globule.git



More information about the Pkg-javascript-commits mailing list