├── .npmignore ├── spec ├── dummies │ ├── ignore │ │ └── IGNORED.js │ ├── include │ │ ├── INCLUDED.js │ │ ├── INCLUDED2.js │ │ └── nesting │ │ │ └── NESTED_INCLUDE.js │ └── template │ │ ├── TEMPLATED.hbs │ │ └── TEMPLATED.js ├── comments-1.2.0.spec.js ├── util.js ├── issues-1.2.1.spec.js ├── expand-1.2.0.spec.js ├── hash-1.2.0.spec.js └── list-1.3.0.spec.js ├── resolvers ├── reduce.js ├── index.js ├── path.js ├── reduce-prefix.js ├── path-reduce.js ├── reduce-postfix.js └── strip-ext.js ├── modes ├── expand.js ├── hash.js └── list.js ├── .travis.yml ├── .gitignore ├── LICENSE ├── package.json ├── index.js └── README.md /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | spec -------------------------------------------------------------------------------- /spec/dummies/ignore/IGNORED.js: -------------------------------------------------------------------------------- 1 | module.exports = "IGNORED_CONTENT"; 2 | -------------------------------------------------------------------------------- /spec/dummies/include/INCLUDED.js: -------------------------------------------------------------------------------- 1 | module.exports = "INCLUDED_CONTENT"; 2 | -------------------------------------------------------------------------------- /spec/dummies/include/INCLUDED2.js: -------------------------------------------------------------------------------- 1 | module.exports = "INCLUDED2_CONTENT"; 2 | -------------------------------------------------------------------------------- /spec/dummies/template/TEMPLATED.hbs: -------------------------------------------------------------------------------- 1 | {{TEMPLATED_CONTENT}} 2 | -------------------------------------------------------------------------------- /spec/dummies/template/TEMPLATED.js: -------------------------------------------------------------------------------- 1 | module.exports = "TEMPLATED_JS_CONTENT"; 2 | -------------------------------------------------------------------------------- /spec/dummies/include/nesting/NESTED_INCLUDE.js: -------------------------------------------------------------------------------- 1 | module.exports = "NESTED_INCLUDED_CONTENT"; 2 | -------------------------------------------------------------------------------- /resolvers/reduce.js: -------------------------------------------------------------------------------- 1 | prefix = require('./reduce-prefix.js'); 2 | postfix = require('./reduce-postfix.js'); 3 | 4 | module.exports = function(base, files, config) { 5 | return postfix(base, prefix(base, files, config), config); 6 | } 7 | -------------------------------------------------------------------------------- /modes/expand.js: -------------------------------------------------------------------------------- 1 | module.exports = function(base, files, config) { 2 | if (files.length === 0) { 3 | return ''; 4 | } 5 | return files.reduce( 6 | function(acc, file, idx, arr) { 7 | return (acc ? acc + ";" : "") + "require('" + file + "')"; 8 | }, false); 9 | }; 10 | -------------------------------------------------------------------------------- /resolvers/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'path-reduce': require('./path-reduce'), 3 | 'path': require('./path'), 4 | 'reduce-postfix': require('./reduce-postfix'), 5 | 'reduce-prefix': require('./reduce-prefix'), 6 | 'reduce': require('./reduce'), 7 | 'strip-ext': require('./strip-ext') 8 | }; 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.12' 5 | deploy: 6 | provider: npm 7 | email: adriaan.callaerts@gmail.com 8 | api_key: 9 | secure: adha9WPYIjf0QSGS+X28+8oK2QZVQNdaTCTNKOFlJk/rR1TRsnS9KWAnKvFjOhjWyzY85ku+n8rrs6cfZDmxf2IO5BD1uw3Hy8eLakE8lhVi3W5pKzcKqe8iVZObr1kMuQLtrT+r5F3pdTNpzpnP137VGPAODD4EwLLPV7ugawU= 10 | on: 11 | tags: true 12 | all_branches: true 13 | repo: capaj/require-globify 14 | -------------------------------------------------------------------------------- /resolvers/path.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = function(base, files, config) { 4 | var keys, key, relative; 5 | 6 | base = path.dirname(base); 7 | 8 | keys = Object.keys(files); 9 | for (var i=0, l=keys.length, key=keys[i]; i (https://coderwall.com/capaj)", 25 | "contributors": [ 26 | { 27 | "name": "Adriaan Callaerts", 28 | "email": "adriaan.callaerts@gmail.com", 29 | "url": "https://github.com/call-a3" 30 | }, 31 | { 32 | "name": "Pat Collins", 33 | "email": "pat@burned.com", 34 | "url": "http://burned.com" 35 | } 36 | ], 37 | "license": "MIT", 38 | "bugs": { 39 | "url": "https://github.com/capaj/require-globify/issues" 40 | }, 41 | "homepage": "https://github.com/capaj/require-globify", 42 | "dependencies": { 43 | "browserify-transform-tools": "^1.6.0", 44 | "glob": "^7.0.5" 45 | }, 46 | "devDependencies": { 47 | "chai": "^3.5.0", 48 | "mocha": "^3.0.2" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /spec/issues-1.2.1.spec.js: -------------------------------------------------------------------------------- 1 | var util = require('./util'); 2 | var test = util.test; 3 | var compare = util.compare; 4 | var expect = util.expect; 5 | 6 | describe('issues/12', function() { 7 | 8 | it('should output a reduced path with extensions stripped when resolver: ["path-reduce", "strip-ext"] is used', function(done) { 9 | test( 10 | './dummies/include/module.js', 11 | 'var deps = require("./*", {mode: "hash", resolve: [ "strip-ext", "path-reduce" ]});', 12 | function(data) { 13 | expect(data).to.equal("var deps = {'INCLUDED': require('./INCLUDED.js'),'INCLUDED2': require('./INCLUDED2.js')};"); 14 | }, done); 15 | }); 16 | 17 | it('should output a reduced path with extensions stripped when resolver: ["strip-ext", "path-reduce"] is used', function(done) { 18 | test( 19 | './dummies/include/module.js', 20 | 'var deps = require("./*", {mode: "hash", resolve: [ "path-reduce", "strip-ext" ]});', 21 | function(data) { 22 | expect(data).to.equal("var deps = {'INCLUDED': require('./INCLUDED.js'),'INCLUDED2': require('./INCLUDED2.js')};"); 23 | }, done); 24 | }); 25 | 26 | it('should return the same whether path-reduce or strip-ext comes first', function(done) { 27 | compare('./dummies/module.js', 28 | 'require("./include/**/*", {mode: "hash", resolve: [ "strip-ext", "path-reduce" ]});', 29 | 'require("./include/**/*", {mode: "hash", resolve: [ "path-reduce", "strip-ext" ]});', 30 | done); 31 | }); 32 | 33 | }); 34 | 35 | describe('issues/13', function() { 36 | // // Input 37 | // var templates = require('./templates/*.hbs', { mode: 'hash' }); 38 | // 39 | // // Output 40 | // var templates = { 41 | // './templates/zoning': require('./templates/zoning.hbs') 42 | // }; 43 | // 44 | // // Output expected 45 | // var templates = { 46 | // 'zoning.hbs': require('./templates/zoning.hbs') 47 | // }; 48 | it('should output a single file with relative directory without extension', function(done) { 49 | test( 50 | './dummies/include/module.js', 51 | 'var deps = require("./nesting/*.js", {mode: "hash"});', //default resolve: ["path-reduce", "strip-ext"] 52 | function(data) { 53 | expect(data).to.equal("var deps = {'NESTED_INCLUDE': require('./nesting/NESTED_INCLUDE.js')};"); 54 | }, done); 55 | }); 56 | 57 | it('should output a single file with relative directory with extension if only path-reduce is specified', function(done) { 58 | test( 59 | './dummies/include/module.js', 60 | 'var deps = require("./nesting/*.js", {mode: "hash", resolve:["path-reduce"]});', //default resolve: ["path-reduce", "strip-ext"] 61 | function(data) { 62 | expect(data).to.equal("var deps = {'NESTED_INCLUDE.js': require('./nesting/NESTED_INCLUDE.js')};"); 63 | }, done); 64 | }); 65 | }); 66 | 67 | describe('issues/14', function() { 68 | it('should allow the use of a custom mode', function(done) { 69 | test( 70 | './dummies/include/module.js', 71 | 'var deps = require("./nesting/*.js", {mode: function(base, files, config) {return "require(\'nothing\')"}});', //default resolve: ["path-reduce", "strip-ext"] 72 | function(data) { 73 | expect(data).to.equal("var deps = require(\'nothing\');"); 74 | }, done); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var glob = require('glob'); 2 | var path = require('path'); 3 | var fs = require('fs'); 4 | 5 | var modes = { 6 | 'expand': require('./modes/expand'), 7 | 'hash': require('./modes/hash'), 8 | 'list': require('./modes/list') 9 | }; 10 | 11 | module.exports = require('browserify-transform-tools').makeRequireTransform( 12 | 'require-globify', { 13 | jsFilesOnly: true, 14 | evaluateArguments: true, 15 | falafelOptions: {ecmaVersion: 6} 16 | }, 17 | function(args, opts, done) { 18 | // args: args passed to require() 19 | // opts: opts used by browserify for the current file 20 | // done: browserify callback 21 | 22 | var config, pattern, globOpts, mode, result, sei; 23 | 24 | // only trigger if require was used with exactly 2 params that match our expectations 25 | if (args.length !== 2 || typeof args[0] !== 'string' || typeof args[1] !== 'object') { 26 | return done(); 27 | } 28 | 29 | // get the second param to require as our config 30 | config = args[1]; 31 | 32 | var skipExtCompat = typeof config.resolve !== 'undefined'; 33 | 34 | // backwards compatibility for glob and hash options, replaced by mode 35 | if (config.glob) { 36 | config.mode = "expand"; 37 | } else if (config.hash) { 38 | config.mode = "hash"; 39 | if (config.hash === "path") { 40 | config.resolve = ["path"]; 41 | } 42 | } 43 | 44 | // set default resolve option to ["path-reduce", "strip-ext"] 45 | config.resolve = config.resolve || ["path-reduce", "strip-ext"]; 46 | if (!Array.isArray(config.resolve)) { 47 | config.resolve = [config.resolve]; 48 | } 49 | 50 | // backwards compatibility for ext option 51 | if (!skipExtCompat) { 52 | if (typeof config.ext === 'undefined' || config.ext === false) { 53 | if (config.resolve.indexOf('strip-ext') === -1) { 54 | config.resolve.push('strip-ext'); 55 | } 56 | } else { // remove ext 57 | sei = config.resolve.indexOf('strip-ext'); 58 | // this wont work if strip-ext is there multiple times 59 | // but what's the change of that happening? 60 | if (sei !== -1) { 61 | config.resolve.splice(sei, 1); 62 | } 63 | } 64 | } 65 | 66 | // if the config object doesn't match our specs, abort 67 | if (typeof config.mode === 'undefined') { 68 | console.warn('doesn\'t match require-globify api'); 69 | return done(); 70 | } 71 | 72 | // find mode 73 | if (typeof config.mode === 'function') { 74 | mode = config.mode; 75 | } else if (modes.hasOwnProperty(config.mode)) { 76 | mode = modes[config.mode]; 77 | } else { 78 | console.warn("Unknown mode: " + config.mode); 79 | return done(); 80 | } 81 | 82 | 83 | // take the first param to require as pattern 84 | pattern = args[0]; 85 | 86 | // use any additional options given 87 | globOpts = config.options || {}; 88 | 89 | // if no override; set the cwd for glob to the dirname of the current file 90 | globOpts.cwd = globOpts.cwd || path.dirname(opts.file); 91 | // only match files 92 | globOpts.nodir = true; 93 | 94 | glob(pattern, globOpts, function(err, files) { 95 | // if there was an error with glob, abort here 96 | if (err) { 97 | return done(err); 98 | } 99 | 100 | try { 101 | // sort files to ensure consistent order upon multiple runs 102 | files.sort(); 103 | 104 | result = mode(opts.file, files, config); 105 | 106 | done(null, result); 107 | } catch (err) { 108 | return done(err); 109 | } 110 | 111 | }); 112 | } 113 | ); 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # require-globify 2 | 3 | [![Build Status][travis-shield]][travis] 4 | [![Build Status][travis-shield-develop]][travis] 5 | [![Dependency Status][dependencies-shield]][dependencies] 6 | [![devDependency Status][dependencies-dev-shield]][dependencies-dev] 7 | 8 | Transform for browserify, which allows to require files with globbing expressions. 9 | 10 | 11 | ## Installation 12 | 13 | [![require-globify](https://nodei.co/npm/require-globify.png?small=true)][npm] 14 | 15 | ## Usage 16 | 17 | ``` bash 18 | browserify -t require-globify entry.js > bundle.js 19 | ``` 20 | 21 | ## Example 22 | 23 | The transform is triggered by adding an additional parameter to the classic require() call. 24 | ```javascript 25 | // just expand to multiple require calls, one for each matched file 26 | require('./includes/*.js', {mode: 'expand'}); 27 | 28 | // return an object that maps each matched path to it's require() call 29 | var hash = require('./includes/*.js', {mode: 'hash'}); 30 | ``` 31 | 32 | ## Interface 33 | The second parameter to require must be an object and supports the following keys: 34 | 35 | ### mode *[required]* 36 | Possible values are 37 | - `'expand'`: replaces the call with multiple calls, one for each match. 38 | 39 | This replaces the option `glob: true` in *<1.2.0*. 40 | 41 | - `'hash'`: replaces the call with an object. 42 | 43 | Every matched file is represented by a key and it's respective require call as the value. The keys are generated by the resolver option. 44 | This replaces the option `hash: true` in *<1.2.0*. 45 | 46 | - `'list'`: replaces the call with an array. 47 | 48 | Every matched file is represented by an object that contains two properties: 49 | + `name` which represents it's key. The keys are generated by the resolver option. 50 | + `module` which contains it's respective require call as the value. 51 | 52 | 53 | - function(base, files, config) { return "require(...)" } 54 | 55 | You can provide a custom function. It takes the parameters base (the path of the file that is being transformed), files (an array that contains all the files matched by the glob, sorted on their full path) and config (the config object passed to the require call in the source file). 56 | If you believe your custom function is of general purpose to others, you can add a pull request for it. 57 | 58 | - You are very welcome to suggest other options by starting an [issue](https://github.com/capaj/require-globify/issues)!. 59 | 60 | E.g. 'list' to return the require calls wrapped in an array, if you'd find a use-case for it :p 61 | 62 | ### resolve *[optional, default:["path-reduce", "strip-ext"]]* 63 | The list of functions to determine the key of a matched file. 64 | You can provide a single value, but you can also provide an array of these values. 65 | In the case an array is provided, the resolvers are executed in order to determine the final key. 66 | 67 | Possible values are 68 | - `'path'` 69 | 70 | Every file uses it's relative path as its key. The relative path will always begin with either `../` or `./`. On Windows, paths will be written unix-style (so `\` will be replaced by `/`). 71 | This replaces the options `hash: "path", ext: true` in *<1.2.0*. 72 | 73 | - `'strip-ext'` 74 | 75 | Every file has it\'s extension removed, but only if it would not cause a duplicate key. 76 | This replaces the options `ext: false` in *<1.2.0*. 77 | 78 | - `'path-reduce'` 79 | 80 | Strips the common path from all matches. In most cases this will replace the options `hash: true, ext: false` in *<1.2.0*. 81 | 82 | - `'reduce-prefix'` 83 | 84 | Tries to reduce the key by determining the largest common prefix of each match and removing them from the matched filename. 85 | 86 | - `'reduce-postfix'` 87 | 88 | Tries to reduce the key by determining the largest common postfix of each match and removing them from the matched filename. 89 | 90 | - `'reduce'` 91 | 92 | Combination of `reduce-prefix` and `reduce-postfix`. 93 | 94 | - function(base, files, config) { return {"path": "key"} } 95 | 96 | You can provide a custom function. It takes the parameters base (the path of the file that is being transformed), files (an object that contains all the files matched by the glob, using their full path as keys) and config (the config object passed to the require call in the source file). 97 | If you believe your custom function is of general purpose to others, you can add a pull request for it. 98 | 99 | - You are very welcome to suggest other options by starting an [issue](https://github.com/capaj/require-globify/issues)!. 100 | 101 | 102 | 103 | ### options *[optional, default:{}]* 104 | This allows options to be provided to [node-glob](https://www.npmjs.com/package/glob), which is used internally to find matching files. 105 | 106 | ### ext *[deprecated, optional, default:false]* 107 | This option is replaced by `resolve: 'strip-ext'`, but remains supported until version 2.0.0. 108 | **WARNING**: Backwards compatibility is not available in combination with the newer "resolve" option. 109 | 110 | ### glob *[deprecated]* 111 | This option is replaced by `mode: 'expand'`, but remains supported until version 2.0.0 112 | 113 | ### hash *[deprecated]* 114 | This option is replaced by `mode: 'hash'` and `resolve: ['path', 'strip-ext']`, but remains supported until version 2.0.0 115 | 116 | 117 | ## Credits 118 | Original concept from Jiří špác, completely reimplemented by Adriaan Callaerts([@call-a3](https://github.com/call-a3)). 119 | Hashing with paths implemented by Pat Collins([@patcoll](https://github.com/patcoll)). 120 | 121 | 122 | ## License 123 | [MIT](http://github.com/capaj/require-globify/blob/master/LICENSE) 124 | 125 | 126 | ## Changelog 127 | - 1.2.1: 128 | - Fixed bugs [#12](https://github.com/capaj/require-globify/issues/12), [#13](https://github.com/capaj/require-globify/issues/13) and [#14](https://github.com/capaj/require-globify/issues/14) 129 | - Streamlined badges on README 130 | - 1.2.0: Complete overhaul of architecture, adding new features such as pass-through options for node-glob and multiple bugfixes. 131 | - 1.1.0: Added hashing with path. 132 | - 1.0.\*: Bugfixes. 133 | - 1.0.0: Rewrite based on browserify-transform-tools. 134 | - 0.\* : Base implementation by Jiří špác([@capaj](https://github.com/capaj)). 135 | 136 | [npm]: https://www.npmjs.com/package/require-globify 137 | [travis]: https://travis-ci.org/capaj/require-globify 138 | [travis-shield]: https://img.shields.io/travis/capaj/require-globify.svg 139 | [travis-shield-develop]: https://img.shields.io/travis/capaj/require-globify/develop.svg?label=develop%20build 140 | [dependencies]: https://david-dm.org/capaj/require-globify 141 | [dependencies-dev]: https://david-dm.org/capaj/require-globify#info=devDependencies 142 | [dependencies-shield]: https://img.shields.io/david/capaj/require-globify.svg 143 | [dependencies-dev-shield]: https://img.shields.io/david/dev/capaj/require-globify.svg 144 | -------------------------------------------------------------------------------- /spec/expand-1.2.0.spec.js: -------------------------------------------------------------------------------- 1 | var util = require('./util'); 2 | var test = util.test; 3 | var compare = util.compare; 4 | var expect = util.expect; 5 | 6 | describe('mode:"expand"', function() { 7 | 8 | describe('without recursion', function() { 9 | 10 | it('should contain a file that matches the glob', function(done) { 11 | test( 12 | './dummies/module.js', 13 | 'require("./include/*", {mode: "expand"});', 14 | function(data) { 15 | expect(data).to.contain('./include/INCLUDED.js'); 16 | expect(data).to.contain('./include/INCLUDED2.js'); 17 | expect(data).to.not.contain('./include/nesting/NESTED_INCLUDE.js'); 18 | }, done); 19 | }); 20 | 21 | it('should pass on options to node-glob', function(done) { 22 | test( 23 | './dummies/module.js', 24 | 'require("./include/*.js", {mode: "expand", options: {ignore: \'./include/*2.*\'}});', 25 | function(data) { 26 | expect(data).to.contain('./include/INCLUDED.js'); 27 | expect(data).to.not.contain('./include/INCLUDED2.js'); 28 | }, done); 29 | }); 30 | 31 | it('should remove itself if it doesn\'t match anything', function(done) { 32 | test( 33 | './dummies/module.js', 34 | 'require("./*", {mode: "expand"});', 35 | function(data) { 36 | expect(data).to.not.contain('./module.js'); 37 | expect(data).to.not.match(/require\(\s?("")|('')\)/); 38 | }, done); 39 | }); 40 | 41 | it('should not contain itself, even if it matches the glob', function(done) { 42 | test( 43 | './dummies/include/module.js', 44 | 'require("./*", {mode: "expand"});', 45 | function(data) { 46 | expect(data).to.not.contain('./module.js'); 47 | expect(data).to.contain('./INCLUDED.js'); 48 | }, done); 49 | }); 50 | 51 | it('should be able to match non-js files', function(done) { 52 | test( 53 | './dummies/module.js', 54 | 'require("./template/*", {mode: "expand"});', 55 | function(data) { 56 | expect(data).to.not.contain('./module.js'); 57 | expect(data).to.contain('./template/TEMPLATED.hbs'); 58 | }, done); 59 | }); 60 | 61 | }); 62 | 63 | describe('with recursion', function() { 64 | 65 | describe('starting from current directory', function() { 66 | 67 | it('should contain a file that matches the glob', function(done) { 68 | test( 69 | './dummies/module.js', 70 | 'require("./**/*.js", {mode: "expand"});', 71 | function(data) { 72 | expect(data).to.contain('./include/INCLUDED.js'); 73 | expect(data).to.contain('./include/nesting/NESTED_INCLUDE.js'); 74 | expect(data).to.contain('./ignore/IGNORED.js'); 75 | }, done); 76 | }); 77 | 78 | it('should pass on options to node-glob', function(done) { 79 | test( 80 | './dummies/module.js', 81 | 'require("./**/*.js", {mode: "expand", options: {ignore: \'./ignore/**/*\'}});', 82 | function(data) { 83 | expect(data).to.contain('./include/INCLUDED.js'); 84 | expect(data).to.contain('./include/nesting/NESTED_INCLUDE.js'); 85 | expect(data).to.not.contain('./ignore/IGNORED.js'); 86 | }, done); 87 | }); 88 | 89 | it('should remove itself if it doesn\'t match anything', function(done) { 90 | test( 91 | './dummies/module.js', 92 | 'require("./**/*.bogus", {mode: "expand"});', 93 | function(data) { 94 | expect(data).to.not.match(/require\(\s?("")|('')\)/); 95 | }, done); 96 | }); 97 | 98 | it('should not contain itself, even if it matches the glob', function(done) { 99 | test( 100 | './dummies/include/module.js', 101 | 'require("./*", {mode: "expand"});', 102 | function(data) { 103 | expect(data).to.not.contain('./module.js'); 104 | expect(data).to.contain('./INCLUDED.js'); 105 | }, done); 106 | }); 107 | 108 | it('should be able to match non-js files', function(done) { 109 | test( 110 | './dummies/module.js', 111 | 'require("./template/*", {mode: "expand"});', 112 | function(data) { 113 | expect(data).to.not.contain('./module.js'); 114 | expect(data).to.contain('./template/TEMPLATED.hbs'); 115 | }, done); 116 | }); 117 | 118 | }); 119 | 120 | describe('starting from an ancestor directory', function() { 121 | 122 | it('should contain a file that matches the glob', function(done) { 123 | test( 124 | './dummies/include/module.js', 125 | 'require("../**/*.js", {mode: "expand"});', 126 | function(data) { 127 | expect(data).to.contain('../include/INCLUDED.js'); 128 | expect(data).to.contain('../include/nesting/NESTED_INCLUDE.js'); 129 | expect(data).to.contain('../ignore/IGNORED.js'); 130 | expect(data).to.not.contain('../template/TEMPLATED.hbs'); 131 | }, done); 132 | }); 133 | 134 | it('should pass on options to node-glob', function(done) { 135 | test( 136 | './dummies/include/module.js', 137 | 'require("../**/*.js", {mode: "expand", options: {ignore: \'../ignore/**/*\'}});', 138 | function(data) { 139 | expect(data).to.contain('../include/INCLUDED.js'); 140 | expect(data).to.contain('../include/nesting/NESTED_INCLUDE.js'); 141 | expect(data).to.not.contain('../ignore/IGNORED.js'); 142 | expect(data).to.not.contain('../template/TEMPLATED.hbs'); 143 | }, done); 144 | }); 145 | 146 | it('should remove itself if it doesn\'t match anything', function(done) { 147 | test( 148 | './dummies/include/module.js', 149 | 'require("../**/*.bogus", {mode: "expand"});', 150 | function(data) { 151 | expect(data).to.not.match(/require\(\s?("")|('')\)/); 152 | }, done); 153 | }); 154 | 155 | it('should not contain itself, even if it matches the glob', function(done) { 156 | test( 157 | './dummies/include/nesting/module.js', 158 | 'require("../*", {mode: "expand"});', 159 | function(data) { 160 | expect(data).to.not.contain('./module.js'); 161 | expect(data).to.contain('../INCLUDED.js'); 162 | }, done); 163 | }); 164 | 165 | it('should be able to match non-js files', function(done) { 166 | test( 167 | './dummies/include/module.js', 168 | 'require("../template/*", {mode: "expand"});', 169 | function(data) { 170 | expect(data).to.not.contain('./module.js'); 171 | expect(data).to.contain('../template/TEMPLATED.hbs'); 172 | }, done); 173 | }); 174 | 175 | }); 176 | 177 | }); 178 | 179 | }); 180 | 181 | describe('glob:true (should behave exactly like mode: "expand")', function() { 182 | 183 | describe('without recursion', function() { 184 | 185 | it('should contain a file that matches the glob', function(done) { 186 | compare('./dummies/module.js', 187 | 'require("./include/*", {mode: "expand"});', 188 | 'require("./include/*", {glob: true});', 189 | done); 190 | }); 191 | 192 | it('should pass on options to node-glob', function(done) { 193 | compare('./dummies/module.js', 194 | 'require("./include/*.js", {mode: "expand", options: {ignore: \'./include/*2.*\'}});', 195 | 'require("./include/*.js", {glob: true, options: {ignore: \'./include/*2.*\'}});', 196 | done); 197 | }); 198 | 199 | it('should remove itself if it doesn\'t match anything', function(done) { 200 | compare('./dummies/module.js', 201 | 'require("./*", {mode: "expand"});', 202 | 'require("./*", {glob: true});', 203 | done); 204 | }); 205 | 206 | it('should not contain itself, even if it matches the glob', function(done) { 207 | compare('./dummies/include/module.js', 208 | 'require("./*", {mode: "expand"});', 209 | 'require("./*", {glob: true});', 210 | done); 211 | }); 212 | 213 | it('should be able to match non-js files', function(done) { 214 | compare('./dummies/module.js', 215 | 'require("./template/*", {mode: "expand"});', 216 | 'require("./template/*", {glob: true});', 217 | done); 218 | }); 219 | 220 | }); 221 | 222 | describe('with recursion', function() { 223 | 224 | describe('starting from current directory', function() { 225 | 226 | it('should contain a file that matches the glob', function(done) { 227 | compare('./dummies/module.js', 228 | 'require("./**/*.js", {mode: "expand"});', 229 | 'require("./**/*.js", {glob: true});', 230 | done); 231 | }); 232 | 233 | it('should pass on options to node-glob', function(done) { 234 | compare('./dummies/module.js', 235 | 'require("./**/*.js", {mode: "expand", options: {ignore: \'./ignore/**/*\'}});', 236 | 'require("./**/*.js", {glob: true, options: {ignore: \'./ignore/**/*\'}});', 237 | done); 238 | }); 239 | 240 | it('should remove itself if it doesn\'t match anything', function(done) { 241 | compare('./dummies/module.js', 242 | 'require("./**/*.bogus", {mode: "expand"});', 243 | 'require("./**/*.bogus", {glob: true});', 244 | done); 245 | }); 246 | 247 | it('should not contain itself, even if it matches the glob', function(done) { 248 | compare('./dummies/include/module.js', 249 | 'require("./*", {mode: "expand"});', 250 | 'require("./*", {glob: true});', 251 | done); 252 | }); 253 | 254 | it('should be able to match non-js files', function(done) { 255 | compare('./dummies/module.js', 256 | 'require("./template/*", {mode: "expand"});', 257 | 'require("./template/*", {glob: true});', 258 | done); 259 | }); 260 | 261 | }); 262 | 263 | describe('with recursion starting from an ancestor directory', function() { 264 | 265 | it('should contain a file that matches the glob', function(done) { 266 | compare('./dummies/include/module.js', 267 | 'require("../**/*.js", {mode: "expand"});', 268 | 'require("../**/*.js", {glob: true});', 269 | done); 270 | }); 271 | 272 | it('should pass on options to node-glob', function(done) { 273 | compare('./dummies/include/module.js', 274 | 'require("../**/*.js", {mode: "expand", options: {ignore: \'../ignore/**/*\'}});', 275 | 'require("../**/*.js", {glob: true, options: {ignore: \'../ignore/**/*\'}});', 276 | done); 277 | }); 278 | 279 | it('should remove itself if it doesn\'t match anything', function(done) { 280 | compare('./dummies/include/module.js', 281 | 'require("../**/*.bogus", {mode: "expand"});', 282 | 'require("../**/*.bogus", {glob: true});', 283 | done); 284 | }); 285 | 286 | it('should not contain itself, even if it matches the glob', function(done) { 287 | compare('./dummies/include/nesting/module.js', 288 | 'require("../*", {mode: "expand"});', 289 | 'require("../*", {glob: true});', 290 | done); 291 | }); 292 | 293 | it('should be able to match non-js files', function(done) { 294 | compare('./dummies/include/module.js', 295 | 'require("../template/*", {mode: "expand"});', 296 | 'require("../template/*", {glob: true});', 297 | done); 298 | }); 299 | 300 | }); 301 | 302 | }); 303 | 304 | }); 305 | -------------------------------------------------------------------------------- /spec/hash-1.2.0.spec.js: -------------------------------------------------------------------------------- 1 | var REGEX_FULL = /var deps = { *((?:(?:'(?:(?:(?:\\(?=')')|[^'])*)')|(?:"(?:(?:(?:\\(?=")")|[^"])*)")) *: *require\((?:(?:(?:'(?:(?:(?:\\(?=')')|[^'])*)')|(?:"(?:(?:(?:\\(?=")")|[^"])*)")))\)(?: *, *(?:(?:'(?:(?:(?:\\(?=')')|[^'])*)')|(?:"(?:(?:(?:\\(?=")")|[^"])*)")) *: *require\((?:(?:(?:'(?:(?:(?:\\(?=')')|[^'])*)')|(?:"(?:(?:(?:\\(?=")")|[^"])*)")))\))*)? *};/; 2 | var REGEX_DEPS = /((?:'(?:(?:(?:\\(?=')')|[^'])*)')|(?:"(?:(?:(?:\\(?=")")|[^"])*)")) *: *require\(((?:(?:'(?:(?:(?:\\(?=')')|[^'])*)')|(?:"(?:(?:(?:\\(?=")")|[^"])*)")))\)(?: *, *((?:'(?:(?:(?:\\(?=')')|[^'])*)')|(?:"(?:(?:(?:\\(?=")")|[^"])*)")) *: *require\(((?:(?:'(?:(?:(?:\\(?=')')|[^'])*)')|(?:"(?:(?:(?:\\(?=")")|[^"])*)")))\))*/; 3 | 4 | var util = require('./util'); 5 | var test = util.test; 6 | var compare = util.compare; 7 | var expect = util.expect; 8 | 9 | var matches = function(data) { 10 | var content = data.match(REGEX_FULL)[1]; 11 | if (typeof content === 'undefined') { 12 | return []; 13 | } else { 14 | var acc = []; 15 | acc.names = []; 16 | acc.paths = []; 17 | return content.match(REGEX_DEPS).slice(1).reduce(function(acc, cur, idx, lst) { 18 | var name = cur.substr(1, cur.length-2); 19 | if (acc.length === 0 || typeof acc[acc.length-1].path === 'string') { 20 | acc.push({name: name}); 21 | acc.names.push(name); 22 | } else { 23 | acc[acc.length-1].path = name; 24 | acc.paths.push(name); 25 | } 26 | return acc; 27 | }, acc); 28 | } 29 | }; 30 | 31 | 32 | describe('mode:"hash"', function() { 33 | 34 | describe('matching the right files', function() { 35 | 36 | describe('without recursion', function() { 37 | 38 | it('should contain a file that matches the glob', function(done) { 39 | test( 40 | './dummies/module.js', 41 | 'var deps = require("./include/*", {mode: "hash"});', 42 | function(data) { 43 | expect(data).to.match(REGEX_FULL); 44 | var includes = matches(data); 45 | expect(includes).to.have.length(2); 46 | expect(includes[0].name).to.equal('INCLUDED'); 47 | expect(includes[0].path).to.equal('./include/INCLUDED.js'); 48 | expect(includes[1].name).to.equal('INCLUDED2'); 49 | expect(includes[1].path).to.equal('./include/INCLUDED2.js'); 50 | }, done); 51 | }); 52 | 53 | it('should return an empty object if it doesn\'t match anything', function(done) { 54 | test( 55 | './dummies/module.js', 56 | 'var deps = require("./*", {mode: "hash"});', 57 | function(data) { 58 | expect(data).to.match(REGEX_FULL); 59 | var includes = matches(data); 60 | expect(includes).to.have.length(0); 61 | expect(data).to.contain('{}'); 62 | expect(data).to.not.match(/require\(\s?("")|('')\)/); 63 | }, done); 64 | }); 65 | 66 | it('should not contain itself, even if it matches the glob', function(done) { 67 | test( 68 | './dummies/include/module.js', 69 | 'var deps = require("./*", {mode: "hash"});', 70 | function(data) { 71 | expect(data).to.match(REGEX_FULL); 72 | var includes = matches(data); 73 | expect(includes.paths).to.not.contain('./module.js'); 74 | expect(includes.paths).to.contain('./INCLUDED.js'); 75 | }, done); 76 | }); 77 | 78 | it('should be able to match non-js files', function(done) { 79 | test( 80 | './dummies/module.js', 81 | 'var deps = require("./template/*", {mode: "hash"});', 82 | function(data) { 83 | expect(data).to.match(REGEX_FULL); 84 | expect(data).to.not.contain('./module.js'); 85 | expect(data).to.contain('./template/TEMPLATED.hbs'); 86 | }, done); 87 | }); 88 | 89 | }); 90 | 91 | describe('with recursion', function() { 92 | 93 | describe('starting from current directory', function() { 94 | 95 | it('should contain a file that matches the glob', function(done) { 96 | test( 97 | './dummies/module.js', 98 | 'var deps = require("./**/*.js", {mode: "hash"});', 99 | function(data) { 100 | expect(data).to.match(REGEX_FULL); 101 | expect(data).to.contain('./include/INCLUDED.js'); 102 | expect(data).to.contain('./include/nesting/NESTED_INCLUDE.js'); 103 | expect(data).to.contain('./ignore/IGNORED.js'); 104 | }, done); 105 | }); 106 | 107 | it('should pass on options to node-glob', function(done) { 108 | test( 109 | './dummies/module.js', 110 | 'var deps = require("./**/*.js", {mode: "hash", options: {ignore: \'./ignore/**/*\'}});', 111 | function(data) { 112 | expect(data).to.match(REGEX_FULL); 113 | expect(data).to.contain('./include/INCLUDED.js'); 114 | expect(data).to.contain('./include/nesting/NESTED_INCLUDE.js'); 115 | expect(data).to.not.contain('./ignore/IGNORED.js'); 116 | }, done); 117 | }); 118 | 119 | it('should return an empty object if it doesn\'t match anything', function(done) { 120 | test( 121 | './dummies/module.js', 122 | 'var deps = require("./**/*.bogus", {mode: "hash"});', 123 | function(data) { 124 | expect(data).to.contain('{}'); 125 | expect(data).to.not.match(/require\(\s?("")|('')\)/); 126 | }, done); 127 | }); 128 | 129 | it('should not contain itself, even if it matches the glob', function(done) { 130 | test( 131 | './dummies/include/module.js', 132 | 'var deps = require("./*", {mode: "hash"});', 133 | function(data) { 134 | expect(data).to.match(REGEX_FULL); 135 | expect(data).to.not.contain('./module.js'); 136 | expect(data).to.contain('./INCLUDED.js'); 137 | }, done); 138 | }); 139 | 140 | it('should be able to match non-js files', function(done) { 141 | test( 142 | './dummies/module.js', 143 | 'var deps = require("./template/*", {mode: "hash"});', 144 | function(data) { 145 | expect(data).to.match(REGEX_FULL); 146 | expect(data).to.not.contain('./module.js'); 147 | expect(data).to.contain('./template/TEMPLATED.hbs'); 148 | }, done); 149 | }); 150 | 151 | }); 152 | 153 | describe('starting from an ancestor directory', function() { 154 | 155 | it('should contain a file that matches the glob', function(done) { 156 | test( 157 | './dummies/include/module.js', 158 | 'var deps = require("../**/*.js", {mode: "hash"});', 159 | function(data) { 160 | expect(data).to.match(REGEX_FULL); 161 | expect(data).to.contain('../include/INCLUDED.js'); 162 | expect(data).to.contain('../include/nesting/NESTED_INCLUDE.js'); 163 | expect(data).to.contain('../ignore/IGNORED.js'); 164 | expect(data).to.not.contain('../template/TEMPLATED.hbs'); 165 | }, done); 166 | }); 167 | 168 | it('should pass on options to node-glob', function(done) { 169 | test( 170 | './dummies/include/module.js', 171 | 'var deps = require("../**/*.js", {mode: "hash", options: {ignore: \'../ignore/**/*\'}});', 172 | function(data) { 173 | expect(data).to.match(REGEX_FULL); 174 | expect(data).to.contain('../include/INCLUDED.js'); 175 | expect(data).to.contain('../include/nesting/NESTED_INCLUDE.js'); 176 | expect(data).to.not.contain('../ignore/IGNORED.js'); 177 | expect(data).to.not.contain('../template/TEMPLATED.hbs'); 178 | }, done); 179 | }); 180 | 181 | it('should return an empty object if it doesn\'t match anything', function(done) { 182 | test( 183 | './dummies/include/module.js', 184 | 'var deps = require("../**/*.bogus", {mode: "hash"});', 185 | function(data) { 186 | expect(data).to.match(REGEX_FULL); 187 | expect(data).to.not.match(/require\(\s?("")|('')\)/); 188 | expect(data).to.equal('var deps = {};'); 189 | }, done); 190 | }); 191 | 192 | it('should not contain itself, even if it matches the glob', function(done) { 193 | test( 194 | './dummies/include/nesting/module.js', 195 | 'var deps = require("../*", {mode: "hash"});', 196 | function(data) { 197 | expect(data).to.match(REGEX_FULL); 198 | expect(data).to.not.contain('./module.js'); 199 | expect(data).to.contain('../INCLUDED.js'); 200 | }, done); 201 | }); 202 | 203 | it('should be able to match non-js files', function(done) { 204 | test( 205 | './dummies/include/module.js', 206 | 'var deps = require("../template/*", {mode: "hash"});', 207 | function(data) { 208 | expect(data).to.match(REGEX_FULL); 209 | expect(data).to.not.contain('./module.js'); 210 | expect(data).to.contain('../template/TEMPLATED.hbs'); 211 | }, done); 212 | }); 213 | 214 | }); 215 | 216 | }); 217 | 218 | }); 219 | 220 | describe('with resolver option', function() { 221 | 222 | // - path 223 | // - strip-ext 224 | // - path-reduce 225 | // - reduce-prefix 226 | // - reduce-postfix 227 | // - reduce 228 | 229 | describe('default', function() { 230 | 231 | it('should use ["path-reduce", "strip-ext"] as default', function(done) { 232 | compare('./dummies/module.js', 233 | 'require("./include/**", {mode: "hash"});', 234 | 'require("./include/**", {mode: "hash", resolve:["path-reduce", "strip-ext"]});', 235 | done); 236 | }); 237 | 238 | }); 239 | 240 | describe('resolve:"path-reduce"', function() { 241 | 242 | it('should remove common path', function(done) { 243 | test( 244 | './dummies/module.js', 245 | 'var deps = require("./include/**/*", {mode: "hash", resolve: "path-reduce"});', 246 | function(data) { 247 | expect(data).to.match(REGEX_FULL); 248 | expect(data).to.contain("'INCLUDED.js': require("); 249 | expect(data).to.contain("'INCLUDED2.js': require("); 250 | expect(data).to.contain("'nesting/NESTED_INCLUDE.js': require("); 251 | }, done); 252 | }); 253 | 254 | }); 255 | 256 | describe('resolve:"path"', function() { 257 | 258 | it('should use relative path as key', function(done) { 259 | test( 260 | './dummies/module.js', 261 | 'var deps = require("./include/**/*", {mode: "hash", resolve: "path", ext:true});', 262 | function(data) { 263 | expect(data).to.match(REGEX_FULL); 264 | expect(data).to.contain("'./include/INCLUDED.js': require("); 265 | expect(data).to.contain("'./include/INCLUDED2.js': require("); 266 | expect(data).to.contain("'./include/nesting/NESTED_INCLUDE.js': require("); 267 | }, done); 268 | }); 269 | 270 | it('should use relative path as key, when referring to a sibling', function(done) { 271 | test( 272 | './dummies/ignore/module.js', 273 | 'var deps = require("../**/*", {mode: "hash", resolve: "path", ext:true});', 274 | function(data) { 275 | expect(data).to.match(REGEX_FULL); 276 | expect(data).to.contain("'../include/INCLUDED.js': require("); 277 | expect(data).to.contain("'../include/INCLUDED2.js': require("); 278 | expect(data).to.contain("'../include/nesting/NESTED_INCLUDE.js': require("); 279 | }, done); 280 | }); 281 | 282 | }); 283 | 284 | describe('resolve:"reduce-postfix"', function() { 285 | 286 | it('should remove common postfix', function(done) { 287 | test( 288 | './dummies/module.js', 289 | 'var deps = require("./include/**/*", {mode: "hash", resolve: "reduce-postfix", ext:true});', 290 | function(data) { 291 | expect(data).to.match(REGEX_FULL); 292 | expect(data).to.contain("'./include/INCLUDED': require("); 293 | expect(data).to.contain("'./include/INCLUDED2': require("); 294 | expect(data).to.contain("'./include/nesting/NESTED_INCLUDE': require("); 295 | }, done); 296 | }); 297 | 298 | }); 299 | 300 | describe('resolve:"reduce-prefix"', function() { 301 | 302 | it('should remove common prefix', function(done) { 303 | test( 304 | './dummies/module.js', 305 | 'var deps = require("./include/*", {mode: "hash", resolve: "reduce-prefix", ext:true});', 306 | function(data) { 307 | expect(data).to.match(REGEX_FULL); 308 | expect(data).to.contain("'.js': require("); 309 | expect(data).to.contain("'2.js': require("); 310 | }, done); 311 | }); 312 | 313 | }); 314 | 315 | describe('resolve:"reduce"', function() { 316 | 317 | it('should remove common pre- and postfix', function(done) { 318 | test( 319 | './dummies/module.js', 320 | 'var deps = require("./include/*", {mode: "hash", resolve: "reduce", ext:true});', 321 | function(data) { 322 | expect(data).to.match(REGEX_FULL); 323 | expect(data).to.contain("'': require("); 324 | expect(data).to.contain("'2': require("); 325 | }, done); 326 | }); 327 | 328 | }); 329 | 330 | describe('resolve:"strip-ext"', function() { 331 | 332 | it('should remove extension', function(done) { 333 | test( 334 | './dummies/module.js', 335 | 'var deps = require("./include/*", {mode: "hash", resolve: "strip-ext"});', 336 | function(data) { 337 | expect(data).to.match(REGEX_FULL); 338 | expect(data).to.contain("'./include/INCLUDED': require("); 339 | expect(data).to.contain("'./include/INCLUDED2': require("); 340 | }, done); 341 | }); 342 | 343 | it('should not remove extension if it causes naming collisions', function(done) { 344 | test( 345 | './dummies/template/module.js', 346 | 'var deps = require("./*", {mode: "hash", resolve: "strip-ext"});', 347 | function(data) { 348 | expect(data).to.match(REGEX_FULL); 349 | expect(data).to.contain("'./TEMPLATED.hbs': require("); 350 | expect(data).to.contain("'./TEMPLATED.js': require("); 351 | }, done); 352 | }); 353 | 354 | }); 355 | 356 | }); 357 | 358 | }); 359 | 360 | describe('backwards compatibility', function() { 361 | 362 | describe('hash:true', function() { // default ext:false 363 | 364 | describe('[default]', function() { 365 | it('should equal {mode:"hash"}', function(done) { 366 | compare('./dummies/module.js', 367 | 'require("./include/**/*", {hash: true});', 368 | 'require("./include/**/*", {mode: "hash"});', 369 | done); 370 | }); 371 | 372 | }); 373 | 374 | describe(', ext:false', function() { 375 | 376 | it('should equal {mode:"hash"}', function(done) { 377 | compare('./dummies/module.js', 378 | 'require("./include/**/*", {hash: true, ext: false});', 379 | 'require("./include/**/*", {mode: "hash"});', 380 | done); 381 | }); 382 | 383 | }); 384 | 385 | describe(', ext:true', function() { 386 | 387 | it('should equal {mode:"hash", resolve:"path-reduce"}', function(done) { 388 | compare('./dummies/module.js', 389 | 'require("./include/**/*", {hash: true, ext: true});', 390 | 'require("./include/**/*", {mode: "hash", resolve:"path-reduce"});', 391 | done); 392 | }); 393 | 394 | }); 395 | 396 | }); 397 | 398 | describe('hash:"path"', function() { // default ext:false 399 | 400 | describe('[default]', function() { 401 | it('should equal {mode:"hash", resolve:["path", "strip-ext"]}', function(done) { 402 | compare('./dummies/module.js', 403 | 'require("./include/**/*", {hash: "path"});', 404 | 'require("./include/**/*", {mode: "hash", resolve:["path", "strip-ext"]});', 405 | done); 406 | }); 407 | 408 | }); 409 | 410 | describe(', ext:false', function() { 411 | 412 | it('should equal {mode:"hash", resolve:["path", "strip-ext"]}', function(done) { 413 | compare('./dummies/module.js', 414 | 'require("./include/**/*", {hash: "path", ext: false});', 415 | 'require("./include/**/*", {mode: "hash", resolve:["path", "strip-ext"]});', 416 | done); 417 | }); 418 | 419 | }); 420 | 421 | describe(', ext:true', function() { 422 | 423 | it('should equal {mode:"hash", resolve:"path"}', function(done) { 424 | compare('./dummies/module.js', 425 | 'require("./include/**/*", {hash: "path", ext: true});', 426 | 'require("./include/**/*", {mode: "hash", resolve:"path"});', 427 | done); 428 | }); 429 | 430 | }); 431 | 432 | }); 433 | 434 | }); 435 | -------------------------------------------------------------------------------- /spec/list-1.3.0.spec.js: -------------------------------------------------------------------------------- 1 | var REGEX_FULL = /var deps = \[ *({ *name: *(?:(?:(?:'(?:(?:(?:\\(?=')')|[^'])*)')|(?:"(?:(?:(?:\\(?=")")|[^"])*)"))) *, *module: *require\((?:(?:(?:'(?:(?:(?:\\(?=')')|[^'])*)')|(?:"(?:(?:(?:\\(?=")")|[^"])*)")))\) *}(?: *, *{name: *(?:(?:(?:'(?:(?:(?:\\(?=')')|[^'])*)')|(?:"(?:(?:(?:\\(?=")")|[^"])*)"))) *, *module: *require\((?:(?:(?:'(?:(?:(?:\\(?=')')|[^'])*)')|(?:"(?:(?:(?:\\(?=")")|[^"])*)")))\) *})*)? *];/; 2 | var REGEX_DEPS = /{ *name: *((?:'(?:(?:(?:\\(?=')')|[^'])*?)')|(?:"(?:(?:(?:\\(?=")")|[^"])*?)")) *, *module: *require\(((?:(?:'(?:(?:(?:\\(?=')')|[^'])*?)')|(?:"(?:(?:(?:\\(?=")")|[^"])*?)")))\) *} *,? */g; 3 | //" atom's syntax highlighter has issues with quotation in the above regex 4 | var REGEX_DEP_ONE = /{ *name: *((?:'(?:(?:(?:\\(?=')')|[^'])*?)')|(?:"(?:(?:(?:\\(?=")")|[^"])*?)")) *, *module: *require\(((?:(?:'(?:(?:(?:\\(?=')')|[^'])*?)')|(?:"(?:(?:(?:\\(?=")")|[^"])*?)")))\) *}/; 5 | 6 | var util = require('./util'); 7 | var test = util.test; 8 | var compare = util.compare; 9 | var expect = util.expect; 10 | 11 | var matches = function(data) { 12 | var content = data.match(REGEX_FULL)[1]; 13 | if (typeof content === 'undefined') { 14 | return []; 15 | } else { 16 | var acc = []; 17 | acc.names = []; 18 | acc.paths = []; 19 | content.replace(REGEX_DEPS, function(match) { 20 | var mapping = match.match(REGEX_DEP_ONE).slice(1).map(function(str) { 21 | return str.substr(1, str.length-2); 22 | }); 23 | acc.push({name: mapping[0], path: mapping[1]}); 24 | acc.names.push(mapping[0]); 25 | acc.paths.push(mapping[1]); 26 | return ''; 27 | }); 28 | return acc; 29 | } 30 | }; 31 | 32 | describe('mode:"list"', function() { 33 | 34 | describe('matching the right files', function() { 35 | 36 | describe('without recursion', function() { 37 | 38 | it('should contain a file that matches the glob', function(done) { 39 | test( 40 | './dummies/module.js', 41 | 'var deps = require("./include/*", {mode: "list"});', 42 | function(data) { 43 | expect(data).to.match(REGEX_FULL); 44 | var includes = matches(data); 45 | expect(includes).to.have.length(2); 46 | expect(includes[0].name).to.equal('INCLUDED'); 47 | expect(includes[0].path).to.equal('./include/INCLUDED.js'); 48 | expect(includes[1].name).to.equal('INCLUDED2'); 49 | expect(includes[1].path).to.equal('./include/INCLUDED2.js'); 50 | }, done); 51 | }); 52 | 53 | it('should return an empty array if it doesn\'t match anything', function(done) { 54 | test( 55 | './dummies/module.js', 56 | 'var deps = require("./*", {mode: "list"});', 57 | function(data) { 58 | expect(data).to.match(REGEX_FULL); 59 | var includes = matches(data); 60 | expect(data).to.not.contain('./module.js'); 61 | expect(data).to.contain('[]'); 62 | expect(data).to.not.match(/require\(\s?("")|('')\)/); 63 | }, done); 64 | }); 65 | 66 | it('should not contain itself, even if it matches the glob', function(done) { 67 | test( 68 | './dummies/include/module.js', 69 | 'var deps = require("./*", {mode: "list"});', 70 | function(data) { 71 | expect(data).to.match(REGEX_FULL); 72 | var includes = matches(data); 73 | expect(data).to.not.contain('./module.js'); 74 | expect(data).to.contain('./INCLUDED.js'); 75 | }, done); 76 | }); 77 | 78 | it('should be able to match non-js files', function(done) { 79 | test( 80 | './dummies/module.js', 81 | 'var deps = require("./template/*", {mode: "list"});', 82 | function(data) { 83 | expect(data).to.match(REGEX_FULL); 84 | var includes = matches(data); 85 | expect(data).to.not.contain('./module.js'); 86 | expect(data).to.contain('./template/TEMPLATED.hbs'); 87 | }, done); 88 | }); 89 | 90 | }); 91 | 92 | describe('with recursion', function() { 93 | 94 | describe('starting from current directory', function() { 95 | 96 | it('should contain a file that matches the glob', function(done) { 97 | test( 98 | './dummies/module.js', 99 | 'var deps = require("./**/*.js", {mode: "list"});', 100 | function(data) { 101 | expect(data).to.match(REGEX_FULL); 102 | var includes = matches(data); 103 | expect(data).to.contain('./include/INCLUDED.js'); 104 | expect(data).to.contain('./include/nesting/NESTED_INCLUDE.js'); 105 | expect(data).to.contain('./ignore/IGNORED.js'); 106 | }, done); 107 | }); 108 | 109 | it('should pass on options to node-glob', function(done) { 110 | test( 111 | './dummies/module.js', 112 | 'var deps = require("./**/*.js", {mode: "list", options: {ignore: \'./ignore/**/*\'}});', 113 | function(data) { 114 | expect(data).to.match(REGEX_FULL); 115 | var includes = matches(data); 116 | expect(data).to.contain('./include/INCLUDED.js'); 117 | expect(data).to.contain('./include/nesting/NESTED_INCLUDE.js'); 118 | expect(data).to.not.contain('./ignore/IGNORED.js'); 119 | }, done); 120 | }); 121 | 122 | it('should return an empty array if it doesn\'t match anything', function(done) { 123 | test( 124 | './dummies/module.js', 125 | 'var deps = require("./**/*.bogus", {mode: "list"});', 126 | function(data) { 127 | expect(data).to.match(REGEX_FULL); 128 | var includes = matches(data); 129 | expect(data).to.contain('[]'); 130 | expect(data).to.not.match(/require\(\s?("")|('')\)/); 131 | }, done); 132 | }); 133 | 134 | it('should not contain itself, even if it matches the glob', function(done) { 135 | test( 136 | './dummies/include/module.js', 137 | 'var deps = require("./*", {mode: "list"});', 138 | function(data) { 139 | expect(data).to.match(REGEX_FULL); 140 | var includes = matches(data); 141 | expect(data).to.not.contain('./module.js'); 142 | expect(data).to.contain('./INCLUDED.js'); 143 | }, done); 144 | }); 145 | 146 | it('should be able to match non-js files', function(done) { 147 | test( 148 | './dummies/module.js', 149 | 'var deps = require("./template/*", {mode: "list"});', 150 | function(data) { 151 | expect(data).to.match(REGEX_FULL); 152 | var includes = matches(data); 153 | expect(data).to.not.contain('./module.js'); 154 | expect(data).to.contain('./template/TEMPLATED.hbs'); 155 | }, done); 156 | }); 157 | 158 | }); 159 | 160 | describe('starting from an ancestor directory', function() { 161 | 162 | it('should contain a file that matches the glob', function(done) { 163 | test( 164 | './dummies/include/module.js', 165 | 'var deps = require("../**/*.js", {mode: "list"});', 166 | function(data) { 167 | expect(data).to.match(REGEX_FULL); 168 | var includes = matches(data); 169 | expect(data).to.contain('../include/INCLUDED.js'); 170 | expect(data).to.contain('../include/nesting/NESTED_INCLUDE.js'); 171 | expect(data).to.contain('../ignore/IGNORED.js'); 172 | expect(data).to.not.contain('../template/TEMPLATED.hbs'); 173 | }, done); 174 | }); 175 | 176 | it('should pass on options to node-glob', function(done) { 177 | test( 178 | './dummies/include/module.js', 179 | 'var deps = require("../**/*.js", {mode: "list", options: {ignore: \'../ignore/**/*\'}});', 180 | function(data) { 181 | expect(data).to.match(REGEX_FULL); 182 | var includes = matches(data); 183 | expect(data).to.contain('../include/INCLUDED.js'); 184 | expect(data).to.contain('../include/nesting/NESTED_INCLUDE.js'); 185 | expect(data).to.not.contain('../ignore/IGNORED.js'); 186 | expect(data).to.not.contain('../template/TEMPLATED.hbs'); 187 | }, done); 188 | }); 189 | 190 | it('should return an empty array if it doesn\'t match anything', function(done) { 191 | test( 192 | './dummies/include/module.js', 193 | 'var deps = require("../**/*.bogus", {mode: "list"});', 194 | function(data) { 195 | expect(data).to.match(REGEX_FULL); 196 | var includes = matches(data); 197 | expect(data).to.not.match(/require\(\s?("")|('')\)/); 198 | expect(data).to.equal('var deps = [];'); 199 | }, done); 200 | }); 201 | 202 | it('should not contain itself, even if it matches the glob', function(done) { 203 | test( 204 | './dummies/include/nesting/module.js', 205 | 'var deps = require("../*", {mode: "list"});', 206 | function(data) { 207 | expect(data).to.match(REGEX_FULL); 208 | var includes = matches(data); 209 | expect(data).to.not.contain('./module.js'); 210 | expect(data).to.contain('../INCLUDED.js'); 211 | }, done); 212 | }); 213 | 214 | it('should be able to match non-js files', function(done) { 215 | test( 216 | './dummies/include/module.js', 217 | 'var deps = require("../template/*", {mode: "list"});', 218 | function(data) { 219 | expect(data).to.match(REGEX_FULL); 220 | var includes = matches(data); 221 | expect(data).to.not.contain('./module.js'); 222 | expect(data).to.contain('../template/TEMPLATED.hbs'); 223 | }, done); 224 | }); 225 | 226 | }); 227 | 228 | }); 229 | 230 | }); 231 | 232 | describe('with resolver option', function() { 233 | 234 | // - path 235 | // - strip-ext 236 | // - path-reduce 237 | // - reduce-prefix 238 | // - reduce-postfix 239 | // - reduce 240 | 241 | describe('default', function() { 242 | 243 | it('should use ["path-reduce", "strip-ext"] as default', function(done) { 244 | compare('./dummies/module.js', 245 | 'require("./include/**", {mode: "list"});', 246 | 'require("./include/**", {mode: "list", resolve:["path-reduce", "strip-ext"]});', 247 | done); 248 | }); 249 | 250 | }); 251 | 252 | describe('resolve:"path-reduce"', function() { 253 | 254 | it('should remove common path', function(done) { 255 | test( 256 | './dummies/module.js', 257 | 'var deps = require("./include/**/*", {mode: "list", resolve: "path-reduce"});', 258 | function(data) { 259 | expect(data).to.match(REGEX_FULL); 260 | var includes = matches(data); 261 | expect(includes).to.have.length(3); 262 | expect(includes[0].name).to.equal('INCLUDED.js'); 263 | expect(includes[0].path).to.equal('./include/INCLUDED.js'); 264 | expect(includes[1].name).to.equal('INCLUDED2.js'); 265 | expect(includes[1].path).to.equal('./include/INCLUDED2.js'); 266 | expect(includes[2].name).to.equal('nesting/NESTED_INCLUDE.js'); 267 | expect(includes[2].path).to.equal('./include/nesting/NESTED_INCLUDE.js'); 268 | }, done); 269 | }); 270 | 271 | }); 272 | 273 | describe('resolve:"path"', function() { 274 | 275 | it('should use relative path as key', function(done) { 276 | test( 277 | './dummies/module.js', 278 | 'var deps = require("./include/**/*", {mode: "list", resolve: "path", ext:true});', 279 | function(data) { 280 | expect(data).to.match(REGEX_FULL); 281 | var includes = matches(data); 282 | expect(includes).to.have.length(3); 283 | expect(includes[0].name).to.equal('./include/INCLUDED.js'); 284 | expect(includes[0].path).to.equal('./include/INCLUDED.js'); 285 | expect(includes[1].name).to.equal('./include/INCLUDED2.js'); 286 | expect(includes[1].path).to.equal('./include/INCLUDED2.js'); 287 | expect(includes[2].name).to.equal('./include/nesting/NESTED_INCLUDE.js'); 288 | expect(includes[2].path).to.equal('./include/nesting/NESTED_INCLUDE.js'); 289 | }, done); 290 | }); 291 | 292 | it('should use relative path as key, even when referring to a sibling', function(done) { 293 | test( 294 | './dummies/ignore/module.js', 295 | 'var deps = require("../**/*", {mode: "list", resolve: "path", ext:true});', 296 | function(data) { 297 | expect(data).to.match(REGEX_FULL); 298 | var includes = matches(data); 299 | expect(includes).to.have.length(6); 300 | expect(includes[0].name).to.equal('./IGNORED.js'); 301 | expect(includes[0].path).to.equal('../ignore/IGNORED.js'); 302 | expect(includes[1].name).to.equal('../include/INCLUDED.js'); 303 | expect(includes[1].path).to.equal('../include/INCLUDED.js'); 304 | expect(includes[2].name).to.equal('../include/INCLUDED2.js'); 305 | expect(includes[2].path).to.equal('../include/INCLUDED2.js'); 306 | expect(includes[3].name).to.equal('../include/nesting/NESTED_INCLUDE.js'); 307 | expect(includes[3].path).to.equal('../include/nesting/NESTED_INCLUDE.js'); 308 | expect(includes[4].name).to.equal('../template/TEMPLATED.hbs'); 309 | expect(includes[4].path).to.equal('../template/TEMPLATED.hbs'); 310 | expect(includes[5].name).to.equal('../template/TEMPLATED.js'); 311 | expect(includes[5].path).to.equal('../template/TEMPLATED.js'); 312 | }, done); 313 | }); 314 | 315 | }); 316 | 317 | describe('resolve:"reduce-postfix"', function() { 318 | 319 | it('should remove common postfix', function(done) { 320 | test( 321 | './dummies/module.js', 322 | 'var deps = require("./include/**/*", {mode: "list", resolve: "reduce-postfix", ext:true});', 323 | function(data) { 324 | expect(data).to.match(REGEX_FULL); 325 | var includes = matches(data); 326 | expect(includes).to.have.length(3); 327 | expect(includes[0].name).to.equal('./include/INCLUDED'); 328 | expect(includes[0].path).to.equal('./include/INCLUDED.js'); 329 | expect(includes[1].name).to.equal('./include/INCLUDED2'); 330 | expect(includes[1].path).to.equal('./include/INCLUDED2.js'); 331 | expect(includes[2].name).to.equal('./include/nesting/NESTED_INCLUDE'); 332 | expect(includes[2].path).to.equal('./include/nesting/NESTED_INCLUDE.js'); 333 | }, done); 334 | }); 335 | 336 | }); 337 | 338 | describe('resolve:"reduce-prefix"', function() { 339 | 340 | it('should remove common prefix', function(done) { 341 | test( 342 | './dummies/module.js', 343 | 'var deps = require("./include/*", {mode: "list", resolve: "reduce-prefix", ext:true});', 344 | function(data) { 345 | expect(data).to.match(REGEX_FULL); 346 | var includes = matches(data); 347 | expect(includes).to.have.length(2); 348 | expect(includes[0].name).to.equal('.js'); 349 | expect(includes[0].path).to.equal('./include/INCLUDED.js'); 350 | expect(includes[1].name).to.equal('2.js'); 351 | expect(includes[1].path).to.equal('./include/INCLUDED2.js'); 352 | }, done); 353 | }); 354 | 355 | }); 356 | 357 | describe('resolve:"reduce"', function() { 358 | 359 | it('should remove common pre- and postfix', function(done) { 360 | test( 361 | './dummies/module.js', 362 | 'var deps = require("./include/*", {mode: "list", resolve: "reduce", ext:true});', 363 | function(data) { 364 | expect(data).to.match(REGEX_FULL); 365 | var includes = matches(data); 366 | expect(includes).to.have.length(2); 367 | expect(includes[0].name).to.equal(''); 368 | expect(includes[0].path).to.equal('./include/INCLUDED.js'); 369 | expect(includes[1].name).to.equal('2'); 370 | expect(includes[1].path).to.equal('./include/INCLUDED2.js'); 371 | }, done); 372 | }); 373 | 374 | }); 375 | 376 | describe('resolve:"strip-ext"', function() { 377 | 378 | it('should remove extension', function(done) { 379 | test( 380 | './dummies/module.js', 381 | 'var deps = require("./include/*", {mode: "list", resolve: "strip-ext"});', 382 | function(data) { 383 | expect(data).to.match(REGEX_FULL); 384 | var includes = matches(data); 385 | expect(includes).to.have.length(2); 386 | expect(includes[0].name).to.equal('./include/INCLUDED'); 387 | expect(includes[0].path).to.equal('./include/INCLUDED.js'); 388 | expect(includes[1].name).to.equal('./include/INCLUDED2'); 389 | expect(includes[1].path).to.equal('./include/INCLUDED2.js'); 390 | }, done); 391 | }); 392 | 393 | it('should not remove extension if it causes naming collisions', function(done) { 394 | test( 395 | './dummies/template/module.js', 396 | 'var deps = require("./*", {mode: "list", resolve: "strip-ext"});', 397 | function(data) { 398 | expect(data).to.match(REGEX_FULL); 399 | var includes = matches(data); 400 | expect(includes).to.have.length(2); 401 | expect(includes[0].name).to.equal('./TEMPLATED.hbs'); 402 | expect(includes[0].path).to.equal('./TEMPLATED.hbs'); 403 | expect(includes[1].name).to.equal('./TEMPLATED.js'); 404 | expect(includes[1].path).to.equal('./TEMPLATED.js'); 405 | }, done); 406 | }); 407 | 408 | }); 409 | 410 | }); 411 | 412 | }); 413 | --------------------------------------------------------------------------------