├── .gitignore ├── test ├── tr_flags │ └── empty.js ├── expose │ ├── bar.js │ ├── foo.js │ ├── lib │ │ ├── abc.js │ │ └── xyz.js │ └── main.js ├── invalid_pkg │ ├── index.js │ ├── file.js │ └── package.json ├── pkg │ ├── node_modules │ │ ├── pkga │ │ │ ├── main.js │ │ │ └── package.json │ │ └── pkgb │ │ │ ├── main.js │ │ │ ├── node_modules │ │ │ └── pkgc │ │ │ │ ├── main.js │ │ │ │ └── package.json │ │ │ └── package.json │ ├── main.js │ └── package.json ├── files │ ├── extra.js │ ├── pkg_filter │ │ ├── one.js │ │ ├── two.js │ │ ├── test.js │ │ └── package.json │ ├── tr_no_entry │ │ └── main.js │ ├── quotes │ │ ├── bar.js │ │ ├── baz.js │ │ ├── foo.js │ │ └── main.js │ ├── tr_rel │ │ ├── subdir │ │ │ └── main.js │ │ ├── package.json │ │ └── xxx.js │ ├── transformdeps.js │ ├── syntax_error.js │ ├── tr_module │ │ ├── f.js │ │ ├── node_modules │ │ │ ├── g │ │ │ │ ├── index.js │ │ │ │ ├── package.json │ │ │ │ ├── x.js │ │ │ │ └── node_modules │ │ │ │ │ └── insert-ggg │ │ │ │ │ └── index.js │ │ │ ├── m │ │ │ │ └── index.js │ │ │ ├── insert-aaa │ │ │ │ └── index.js │ │ │ └── insert-bbb │ │ │ │ └── index.js │ │ ├── package.json │ │ ├── index.js │ │ ├── xxx.js │ │ └── main.js │ ├── tr_sh │ │ ├── f.js │ │ ├── node_modules │ │ │ ├── g │ │ │ │ ├── index.js │ │ │ │ ├── package.json │ │ │ │ └── tr_g.js │ │ │ └── m │ │ │ │ └── index.js │ │ ├── tr_a.js │ │ ├── tr_b.js │ │ └── main.js │ ├── tr_2dep_module │ │ ├── f.js │ │ ├── node_modules │ │ │ ├── g │ │ │ │ ├── index.js │ │ │ │ ├── package.json │ │ │ │ └── node_modules │ │ │ │ │ └── insert-ggg │ │ │ │ │ └── index.js │ │ │ ├── m │ │ │ │ ├── index.js │ │ │ │ ├── package.json │ │ │ │ └── node_modules │ │ │ │ │ └── insert-mmm │ │ │ │ │ └── index.js │ │ │ ├── insert-aaa │ │ │ │ └── index.js │ │ │ └── insert-bbb │ │ │ │ └── index.js │ │ └── main.js │ ├── tr_global │ │ ├── main.js │ │ ├── package.json │ │ └── node_modules │ │ │ ├── tr-a │ │ │ └── index.js │ │ │ ├── tr-b │ │ │ └── index.js │ │ │ ├── tr-c │ │ │ └── index.js │ │ │ ├── tr-d │ │ │ └── index.js │ │ │ ├── tr-e │ │ │ └── index.js │ │ │ └── tr-f │ │ │ └── index.js │ ├── bar.js │ ├── main.js │ ├── xyz.js │ ├── resolve │ │ ├── bar │ │ │ ├── bar2.js │ │ │ └── bar.js │ │ └── foo │ │ │ ├── baz │ │ │ └── baz.js │ │ │ └── foo.js │ ├── unicode │ │ ├── bar.js │ │ ├── main.js │ │ └── foo.js │ ├── tr_whole_package │ │ ├── node_modules │ │ │ └── algo │ │ │ │ ├── lib │ │ │ │ └── decrement.js │ │ │ │ ├── package.json │ │ │ │ ├── index.js │ │ │ │ └── node_modules │ │ │ │ └── insert-ggg │ │ │ │ └── index.js │ │ ├── main.js │ │ └── f.js │ ├── foo.js │ └── filterable.js ├── dotdot │ ├── index.js │ └── abc │ │ └── index.js ├── ignore_missing │ ├── main.js │ └── other.js ├── tr_opts │ ├── main.js │ ├── package.json │ └── node_modules │ │ ├── hhh │ │ └── index.js │ │ ├── fff │ │ └── index.js │ │ └── ggg │ │ └── index.js ├── tr_write │ └── main.js ├── cycle │ ├── bar.js │ ├── main.js │ └── foo.js ├── cache_persistent │ └── error_transform.js ├── node_modules │ └── insert-www │ │ └── index.js ├── invalid_pkg.js ├── pkg.js ├── dotdot.js ├── cycle.js ├── tr_err.js ├── tr_whole_package.js ├── tr_opts.js ├── bundle.js ├── tr_sh.js ├── tr_module.js ├── tr_2dep_module.js ├── tr_rel.js ├── pkg_filter.js ├── syntax.js ├── row_expose.js ├── tr_write.js ├── filter.js ├── row_expose_transform.js ├── detect.js ├── tr_global.js ├── tr_fn.js ├── tr_no_entry.js ├── noparse_row.js ├── expose.js ├── row_expose_name_is_file_transform.js ├── quotes.js ├── noparse.js ├── cache_partial.js ├── cache.js ├── tr_flags.js ├── deps.js ├── undef_file.js ├── unicode.js ├── cache_expose.js ├── ignore_missing_cache.js ├── file_cache.js ├── ignore_missing.js ├── source.js ├── tr_deps.js ├── cache_partial_expose.js ├── resolve.js └── cache_persistent.js ├── .npmrc ├── example ├── files │ ├── bar.js │ ├── xyz.js │ ├── main.js │ └── foo.js └── deps.js ├── bin ├── usage.txt └── cmd.js ├── .travis.yml ├── appveyor.yml ├── LICENSE ├── package.json ├── CHANGELOG.md ├── readme.markdown └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /test/tr_flags/empty.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /test/expose/bar.js: -------------------------------------------------------------------------------- 1 | require('xyz'); 2 | -------------------------------------------------------------------------------- /test/invalid_pkg/index.js: -------------------------------------------------------------------------------- 1 | T.pass() 2 | -------------------------------------------------------------------------------- /test/pkg/node_modules/pkga/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/invalid_pkg/file.js: -------------------------------------------------------------------------------- 1 | require('./') 2 | -------------------------------------------------------------------------------- /test/expose/foo.js: -------------------------------------------------------------------------------- 1 | require('./lib/abc'); 2 | -------------------------------------------------------------------------------- /test/expose/lib/abc.js: -------------------------------------------------------------------------------- 1 | console.log('abc'); 2 | -------------------------------------------------------------------------------- /test/files/extra.js: -------------------------------------------------------------------------------- 1 | module.exports = 555 2 | -------------------------------------------------------------------------------- /test/dotdot/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 'whatever' 2 | -------------------------------------------------------------------------------- /test/files/pkg_filter/one.js: -------------------------------------------------------------------------------- 1 | module.exports = 1 2 | -------------------------------------------------------------------------------- /test/files/pkg_filter/two.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 2 | -------------------------------------------------------------------------------- /test/files/tr_no_entry/main.js: -------------------------------------------------------------------------------- 1 | console.log(AAA) 2 | -------------------------------------------------------------------------------- /test/ignore_missing/main.js: -------------------------------------------------------------------------------- 1 | require('./other'); 2 | -------------------------------------------------------------------------------- /test/invalid_pkg/package.json: -------------------------------------------------------------------------------- 1 | "just a string" 2 | -------------------------------------------------------------------------------- /test/pkg/node_modules/pkgb/main.js: -------------------------------------------------------------------------------- 1 | require('pkgc'); -------------------------------------------------------------------------------- /test/pkg/node_modules/pkgb/node_modules/pkgc/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/files/quotes/bar.js: -------------------------------------------------------------------------------- 1 | module.exports = 'success'; 2 | -------------------------------------------------------------------------------- /test/files/quotes/baz.js: -------------------------------------------------------------------------------- 1 | module.exports = 'success'; 2 | -------------------------------------------------------------------------------- /test/files/quotes/foo.js: -------------------------------------------------------------------------------- 1 | module.exports = 'success'; 2 | -------------------------------------------------------------------------------- /test/files/tr_rel/subdir/main.js: -------------------------------------------------------------------------------- 1 | console.log(XXX * 3) 2 | -------------------------------------------------------------------------------- /test/ignore_missing/other.js: -------------------------------------------------------------------------------- 1 | require('missingModule'); 2 | -------------------------------------------------------------------------------- /test/pkg/main.js: -------------------------------------------------------------------------------- 1 | require('pkga'); 2 | require('pkgb'); 3 | -------------------------------------------------------------------------------- /test/tr_opts/main.js: -------------------------------------------------------------------------------- 1 | console.log(FFF * GGG * HHH); 2 | -------------------------------------------------------------------------------- /test/tr_write/main.js: -------------------------------------------------------------------------------- 1 | console.log(WWW.toUpperCase()); 2 | -------------------------------------------------------------------------------- /test/files/pkg_filter/test.js: -------------------------------------------------------------------------------- 1 | t.equal(require('./'), 2); 2 | -------------------------------------------------------------------------------- /test/files/transformdeps.js: -------------------------------------------------------------------------------- 1 | // dependencies added by transform 2 | -------------------------------------------------------------------------------- /test/dotdot/abc/index.js: -------------------------------------------------------------------------------- 1 | var x = require('..'); 2 | console.log(x); 3 | -------------------------------------------------------------------------------- /test/expose/lib/xyz.js: -------------------------------------------------------------------------------- 1 | require('../foo'); 2 | console.log('xyz'); 3 | -------------------------------------------------------------------------------- /test/files/pkg_filter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "one.js" 3 | } 4 | -------------------------------------------------------------------------------- /test/files/syntax_error.js: -------------------------------------------------------------------------------- 1 | const a = require('a'); 2 | const a = 0; 3 | -------------------------------------------------------------------------------- /test/files/tr_module/f.js: -------------------------------------------------------------------------------- 1 | module.exports = function (x) { return x + BBB } 2 | -------------------------------------------------------------------------------- /test/files/tr_sh/f.js: -------------------------------------------------------------------------------- 1 | module.exports = function (x) { return x + BBB } 2 | -------------------------------------------------------------------------------- /test/pkg/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dir": "", 3 | "main": "index.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/expose/main.js: -------------------------------------------------------------------------------- 1 | require('abc'); 2 | require('xyz'); 3 | require('./bar'); 4 | -------------------------------------------------------------------------------- /test/files/tr_2dep_module/f.js: -------------------------------------------------------------------------------- 1 | module.exports = function (x) { return x + BBB } 2 | -------------------------------------------------------------------------------- /test/files/tr_global/main.js: -------------------------------------------------------------------------------- 1 | console.log(AAA + BBB + CCC + DDD + EEE + FFF); 2 | -------------------------------------------------------------------------------- /example/files/bar.js: -------------------------------------------------------------------------------- 1 | module.exports = function (n) { 2 | return n * 100; 3 | }; 4 | -------------------------------------------------------------------------------- /example/files/xyz.js: -------------------------------------------------------------------------------- 1 | var foo = require('./foo'); 2 | console.log('xyz: ' + foo(6)); 3 | -------------------------------------------------------------------------------- /test/files/bar.js: -------------------------------------------------------------------------------- 1 | module.exports = function (n) { 2 | return n * 100; 3 | }; 4 | -------------------------------------------------------------------------------- /test/files/main.js: -------------------------------------------------------------------------------- 1 | var foo = require('./foo'); 2 | console.log('main: ' + foo(5)); 3 | -------------------------------------------------------------------------------- /test/files/xyz.js: -------------------------------------------------------------------------------- 1 | var foo = require('./foo'); 2 | console.log('xyz: ' + foo(6)); 3 | -------------------------------------------------------------------------------- /example/files/main.js: -------------------------------------------------------------------------------- 1 | var foo = require('./foo'); 2 | console.log('main: ' + foo(5)); 3 | -------------------------------------------------------------------------------- /test/files/resolve/bar/bar2.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return 'bar2'; 3 | }; -------------------------------------------------------------------------------- /test/files/resolve/foo/baz/baz.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return 'baz'; 3 | }; -------------------------------------------------------------------------------- /test/files/tr_sh/node_modules/g/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function (x) { return x * GGG } 2 | -------------------------------------------------------------------------------- /test/files/unicode/bar.js: -------------------------------------------------------------------------------- 1 | module.exports = function (ñ) { 2 | return ñ * 100; 3 | }; 4 | -------------------------------------------------------------------------------- /test/files/unicode/main.js: -------------------------------------------------------------------------------- 1 | var π = require('./foo'); 2 | console.log('main: ' + foo(5)); 3 | -------------------------------------------------------------------------------- /test/files/tr_2dep_module/node_modules/g/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function (x) { return x * GGG } 2 | -------------------------------------------------------------------------------- /test/files/tr_rel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "browserify": { 3 | "transform": [ "./xxx.js" ] 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/files/tr_module/node_modules/g/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function (x) { return x * (GGG - 3 * XXX + 9) } 2 | -------------------------------------------------------------------------------- /test/files/tr_module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "browserify": { 3 | "transform": [ "./xxx.js" ] 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/pkg/node_modules/pkga/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dir": "/node_modules/pkga", 3 | "main": "main.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/pkg/node_modules/pkgb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dir": "/node_modules/pkgb", 3 | "main": "main.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/cycle/bar.js: -------------------------------------------------------------------------------- 1 | var foo = require('./foo.js'); 2 | 3 | module.exports = function (n) { return foo.p(n, 1) }; 4 | -------------------------------------------------------------------------------- /test/files/tr_global/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "browserify": { 3 | "transform": [ "tr-a", "tr-b" ] 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/files/tr_whole_package/node_modules/algo/lib/decrement.js: -------------------------------------------------------------------------------- 1 | module.exports = function (x) { return x - GGG } 2 | -------------------------------------------------------------------------------- /test/files/quotes/main.js: -------------------------------------------------------------------------------- 1 | var foo = require('./foo'); 2 | var bar = require("./bar"); 3 | var baz = require(`./baz`); 4 | -------------------------------------------------------------------------------- /test/files/tr_whole_package/main.js: -------------------------------------------------------------------------------- 1 | var f = require('./f.js'); 2 | 3 | t.equal(f(14), 11, 'transformation scope'); 4 | -------------------------------------------------------------------------------- /test/cycle/main.js: -------------------------------------------------------------------------------- 1 | var foo = require('./foo.js'); 2 | var bar = require('./bar.js'); 3 | 4 | console.log(foo.ooo(bar(2))); 5 | -------------------------------------------------------------------------------- /test/files/resolve/bar/bar.js: -------------------------------------------------------------------------------- 1 | var bar2 = require('./bar2'); 2 | 3 | module.exports = function () { 4 | return 'bar'; 5 | }; -------------------------------------------------------------------------------- /test/files/tr_whole_package/f.js: -------------------------------------------------------------------------------- 1 | var calc = require('algo').calc; 2 | 3 | module.exports = function (x) { return calc(x); } 4 | -------------------------------------------------------------------------------- /example/files/foo.js: -------------------------------------------------------------------------------- 1 | var bar = require('./bar'); 2 | 3 | module.exports = function (n) { 4 | return n * 111 + bar(n); 5 | }; 6 | -------------------------------------------------------------------------------- /test/files/foo.js: -------------------------------------------------------------------------------- 1 | var bar = require('./bar'); 2 | 3 | module.exports = function (n) { 4 | return n * 111 + bar(n); 5 | }; 6 | -------------------------------------------------------------------------------- /test/files/tr_module/node_modules/m/index.js: -------------------------------------------------------------------------------- 1 | var AAA = 200, BBB = 300; 2 | 3 | module.exports = function (x) { return AAA + BBB + x } 4 | -------------------------------------------------------------------------------- /test/files/tr_sh/node_modules/m/index.js: -------------------------------------------------------------------------------- 1 | var AAA = 200, BBB = 300; 2 | 3 | module.exports = function (x) { return AAA + BBB + x } 4 | -------------------------------------------------------------------------------- /test/files/unicode/foo.js: -------------------------------------------------------------------------------- 1 | var é = require('./bar'); 2 | 3 | module.exports = function (ñ) { 4 | return ñ * 111 + é(n); 5 | }; 6 | -------------------------------------------------------------------------------- /test/tr_opts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "mdtr": [ 3 | [ "fff", { "x": 3 } ], 4 | [ "ggg", { "z": 111 } ], 5 | [ "hhh" ] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /test/files/tr_sh/node_modules/g/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "index.js", 3 | "browserify": { 4 | "transform": "./tr_g.js" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/pkg/node_modules/pkgb/node_modules/pkgc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dir": "/node_modules/pkgb/node_modules/pkgc", 3 | "main": "main.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/files/tr_2dep_module/node_modules/m/index.js: -------------------------------------------------------------------------------- 1 | var AAA = 200, BBB = 300; 2 | 3 | module.exports = function (x) { return AAA + BBB + MMM + x } 4 | -------------------------------------------------------------------------------- /test/files/tr_2dep_module/node_modules/g/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "index.js", 3 | "browserify": { 4 | "transform": "insert-ggg" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/files/tr_2dep_module/node_modules/m/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "index.js", 3 | "browserify": { 4 | "transform": "insert-mmm" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/cycle/foo.js: -------------------------------------------------------------------------------- 1 | var bar = require('./bar.js'); 2 | 3 | exports.ooo = function (n) { return n * bar(110) }; 4 | exports.p = function (a, b) { return a + b } 5 | -------------------------------------------------------------------------------- /test/files/tr_whole_package/node_modules/algo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "index.js", 3 | "browserify": { 4 | "transform": "insert-ggg" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/files/tr_module/node_modules/g/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "index.js", 3 | "browserify": { 4 | "transform": [ "insert-ggg", "./x.js" ] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/files/resolve/foo/foo.js: -------------------------------------------------------------------------------- 1 | var bar = require('../bar/bar.js'); 2 | var baz = require('./baz/baz.js'); 3 | 4 | module.exports = function () { 5 | return 'foo'; 6 | }; -------------------------------------------------------------------------------- /test/files/tr_whole_package/node_modules/algo/index.js: -------------------------------------------------------------------------------- 1 | var decrement = require('./lib/decrement'); 2 | 3 | exports.calc = function (x) { return decrement(x) - GGG - GGG } 4 | -------------------------------------------------------------------------------- /example/deps.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var JSONStream = require('JSONStream'); 3 | 4 | var md = mdeps(); 5 | md.pipe(JSONStream.stringify()).pipe(process.stdout); 6 | md.end({ file: __dirname + '/files/main.js' }); 7 | -------------------------------------------------------------------------------- /bin/usage.txt: -------------------------------------------------------------------------------- 1 | module-deps [FILES] OPTIONS 2 | 3 | Generate json output for the entry point FILES. 4 | 5 | OPTIONS are: 6 | 7 | -t TRANSFORM Apply a TRANSFORM. 8 | -g TRANSFORM Apply a global TRANSFORM. 9 | 10 | -------------------------------------------------------------------------------- /test/cache_persistent/error_transform.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | module.exports = function (file) { 3 | return through(function (chunk, enc, callback) { 4 | callback(new Error('rawr')); 5 | }); 6 | }; 7 | -------------------------------------------------------------------------------- /test/files/tr_sh/tr_a.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | module.exports = function (file) { 3 | return through(function (buf, enc, next) { 4 | this.push(String(buf).replace(/AAA/g, '5')); 5 | next(); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /test/files/tr_sh/tr_b.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | module.exports = function (file) { 3 | return through(function (buf, enc, next) { 4 | this.push(String(buf).replace(/BBB/g, '50')); 5 | next(); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /test/files/tr_rel/xxx.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/XXX/g, '111')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_module/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/XXX/g, '123')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_module/xxx.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/XXX/g, '123')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_sh/node_modules/g/tr_g.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | module.exports = function (file) { 3 | return through(function (buf, enc, next) { 4 | this.push(String(buf).replace(/GGG/g, '111')); 5 | next(); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /test/files/tr_module/node_modules/g/x.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/XXX/g, '3')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_sh/main.js: -------------------------------------------------------------------------------- 1 | var f = require('./f.js'); 2 | var m = require('m'); 3 | var g = require('g'); 4 | 5 | t.equal(m(f(AAA)), 555, 'transformation scope'); 6 | t.equal(g(3), 333, 'sub-transformation applied'); 7 | t.equal(typeof GGG, 'undefined', 'GGG leak'); 8 | -------------------------------------------------------------------------------- /test/files/tr_2dep_module/main.js: -------------------------------------------------------------------------------- 1 | var f = require('./f.js'); 2 | var m = require('m'); 3 | var g = require('g'); 4 | 5 | t.equal(m(f(AAA)), 777, 'transformation scope'); 6 | t.equal(g(3), 333, 'sub-transformation applied'); 7 | t.equal(typeof GGG, 'undefined', 'GGG leak'); 8 | -------------------------------------------------------------------------------- /test/files/tr_global/node_modules/tr-a/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(buf.toString().replace(/AAA/g, '1')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_global/node_modules/tr-b/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(buf.toString().replace(/BBB/g, '10')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_global/node_modules/tr-c/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(buf.toString().replace(/CCC/g, '100')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_global/node_modules/tr-d/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(buf.toString().replace(/DDD/g, '1000')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_module/node_modules/insert-aaa/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/AAA/g, '5')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/node_modules/insert-www/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/WWW/g, '"world wide wow"')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/filterable.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | events: require('events'), 4 | fs : require('fs'), 5 | net : require('net'), 6 | http : require('http'), 7 | https : require('https'), 8 | dgram : require('dgram'), 9 | dns : require('dns') 10 | } 11 | -------------------------------------------------------------------------------- /test/files/tr_2dep_module/node_modules/insert-aaa/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/AAA/g, '5')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_global/node_modules/tr-e/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(buf.toString().replace(/EEE/g, '10000')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_global/node_modules/tr-f/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(buf.toString().replace(/FFF/g, '100000')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_module/node_modules/insert-bbb/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/BBB/g, '50')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_2dep_module/node_modules/insert-bbb/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/BBB/g, '50')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_module/main.js: -------------------------------------------------------------------------------- 1 | var f = require('./f.js'); 2 | var m = require('m'); 3 | var g = require('g'); 4 | 5 | t.equal(m(f(AAA)), 555, 'transformation scope'); 6 | t.equal(g(3), 333, 'sub-transformation applied'); 7 | t.equal(typeof GGG, 'undefined', 'GGG leak'); 8 | t.equal(XXX, 123, 'XXX'); 9 | -------------------------------------------------------------------------------- /test/files/tr_module/node_modules/g/node_modules/insert-ggg/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/GGG/g, '111')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_2dep_module/node_modules/g/node_modules/insert-ggg/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/GGG/g, '111')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_2dep_module/node_modules/m/node_modules/insert-mmm/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/MMM/g, '222')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/tr_whole_package/node_modules/algo/node_modules/insert-ggg/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file) { 4 | return through(function (buf, enc, next) { 5 | this.push(String(buf).replace(/GGG/g, '1')); 6 | next(); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/invalid_pkg.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | 6 | test('invalid pkg', function (t) { 7 | var d = mdeps(); 8 | d.on('package', function (pkg_) { 9 | // console.error({pkg_}); 10 | }); 11 | d.end(path.join(__dirname, '/invalid_pkg/file.js')); 12 | d.on('data', function () {}); 13 | d.on('end', function () { 14 | t.end(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "12" 4 | - "11" 5 | - "10" 6 | - "8" 7 | - "6" 8 | - "4" 9 | - "iojs" 10 | - "0.12" 11 | - "0.10" 12 | - "0.8" 13 | sudo: false 14 | before_install: 15 | # Old npm certs are untrusted https://github.com/npm/npm/issues/20191 16 | - 'if [ "${TRAVIS_NODE_VERSION}" = "0.6" ] || [ "${TRAVIS_NODE_VERSION}" = "0.8" ]; then export NPM_CONFIG_STRICT_SSL=false; fi' 17 | - 'nvm install-latest-npm' 18 | matrix: 19 | fast_finish: true 20 | -------------------------------------------------------------------------------- /test/tr_opts/node_modules/hhh/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file, opts) { 4 | var bufs = []; 5 | return through(write, end); 6 | 7 | function write (buf, enc, next) { 8 | if (!Buffer.isBuffer(buf)) buf = Buffer(buf); 9 | bufs.push(buf); 10 | next(); 11 | } 12 | 13 | function end () { 14 | var str = Buffer.concat(bufs).toString('utf8'); 15 | this.push(str.replace(/HHH/g, 3)); 16 | this.push(null); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /test/tr_opts/node_modules/fff/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file, opts) { 4 | var bufs = []; 5 | return through(write, end); 6 | 7 | function write (buf, enc, next) { 8 | if (!Buffer.isBuffer(buf)) buf = Buffer(buf); 9 | bufs.push(buf); 10 | next(); 11 | } 12 | 13 | function end () { 14 | var str = Buffer.concat(bufs).toString('utf8'); 15 | this.push(str.replace(/FFF/g, opts.x)); 16 | this.push(null); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /test/tr_opts/node_modules/ggg/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | 3 | module.exports = function (file, opts) { 4 | var bufs = []; 5 | return through(write, end); 6 | 7 | function write (buf, enc, next) { 8 | if (!Buffer.isBuffer(buf)) buf = Buffer(buf); 9 | bufs.push(buf); 10 | next(); 11 | } 12 | 13 | function end () { 14 | var str = Buffer.concat(bufs).toString('utf8'); 15 | this.push(str.replace(/GGG/g, opts.z)); 16 | this.push(null); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /test/pkg.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | 6 | var dirname = path.join(__dirname, '/pkg'); 7 | 8 | test('pkg', function (t) { 9 | t.plan(4); 10 | 11 | var d = mdeps(); 12 | d.on('package', function (pkg_) { 13 | var pkg = JSON.parse(fs.readFileSync(dirname + pkg_.dir + '/package.json')); 14 | pkg.__dirname = path.join(dirname, pkg_.dir); 15 | 16 | t.deepEqual(pkg_, pkg); 17 | }); 18 | d.end(path.join(__dirname, '/pkg/main.js')); 19 | d.resume(); 20 | }); 21 | -------------------------------------------------------------------------------- /test/dotdot.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var through = require('through2'); 4 | var path = require('path'); 5 | 6 | test('dotdot', function (t) { 7 | var expected = [ 8 | path.join(__dirname, '/dotdot/index.js'), 9 | path.join(__dirname, '/dotdot/abc/index.js') 10 | ]; 11 | t.plan(expected.length); 12 | 13 | var d = mdeps(); 14 | d.end(path.join(__dirname, '/dotdot/abc/index.js')); 15 | 16 | d.pipe(through.obj(function (row, enc, next) { 17 | t.deepEqual(row.file, expected.shift()); 18 | next(); 19 | })); 20 | }); 21 | -------------------------------------------------------------------------------- /test/cycle.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var concat = require('concat-stream'); 6 | var path = require('path'); 7 | 8 | test('cycle', function (t) { 9 | t.plan(1); 10 | var p = mdeps(); 11 | p.end(path.join(__dirname, '/cycle/main.js')); 12 | var pack = packer(); 13 | 14 | p.pipe(JSONStream.stringify()).pipe(pack).pipe(concat(function (src) { 15 | Function('console', src.toString('utf8'))({ 16 | log: function (msg) { t.equal(msg, 333) } 17 | }); 18 | })); 19 | }); 20 | -------------------------------------------------------------------------------- /test/tr_err.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var through = require('through2'); 6 | var path = require('path'); 7 | 8 | test('transform', function (t) { 9 | t.plan(1); 10 | var p = mdeps({ 11 | transform: function (file) { 12 | return through(function () { 13 | this.emit('error', new Error('rawr')); 14 | }); 15 | } 16 | }); 17 | p.on('error', function (err) { 18 | t.ok(/tr_sh[\\\/]main\.js/.test(err)); 19 | }); 20 | p.end(path.join(__dirname, '/files/tr_sh/main.js')); 21 | }); 22 | -------------------------------------------------------------------------------- /test/tr_whole_package.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var path = require('path'); 6 | 7 | test('transform', function (t) { 8 | t.plan(1); 9 | var p = mdeps({ 10 | transformKey: [ 'browserify', 'transform' ] 11 | }); 12 | p.end(path.join(__dirname, '/files/tr_whole_package/main.js')); 13 | var pack = packer(); 14 | 15 | p.pipe(JSONStream.stringify()).pipe(pack); 16 | 17 | var src = ''; 18 | pack.on('data', function (buf) { src += buf }); 19 | pack.on('end', function () { 20 | Function('t', src)(t); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/tr_opts.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var concat = require('concat-stream'); 6 | var path = require('path'); 7 | 8 | test('transform options', function (t) { 9 | t.plan(1); 10 | var p = mdeps({ 11 | transformKey: [ 'mdtr' ] 12 | }); 13 | p.end(path.join(__dirname, '/tr_opts/main.js')); 14 | var pack = packer(); 15 | 16 | p.pipe(JSONStream.stringify()).pipe(pack).pipe(concat(function (src) { 17 | Function('console', src.toString('utf8'))({ 18 | log: function (msg) { t.equal(msg, 999) } 19 | }); 20 | })); 21 | }); 22 | -------------------------------------------------------------------------------- /test/bundle.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var path = require('path'); 6 | 7 | test('bundle', function (t) { 8 | t.plan(1); 9 | var p = parser(); 10 | p.end(path.join(__dirname, '/files/main.js')); 11 | p.on('error', t.fail.bind(t)); 12 | var pack = packer(); 13 | 14 | p.pipe(JSONStream.stringify()).pipe(pack); 15 | 16 | var src = ''; 17 | pack.on('data', function (buf) { src += buf }); 18 | pack.on('end', function () { 19 | Function('console', src)({ 20 | log: function (s) { t.equal(s, 'main: 1055') } 21 | }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/tr_sh.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var path = require('path'); 6 | 7 | test('transform', function (t) { 8 | t.plan(3); 9 | var p = mdeps({ 10 | transform: [ './tr_a.js', './tr_b.js' ], 11 | transformKey: [ 'browserify', 'transform' ] 12 | }); 13 | p.end(path.join(__dirname, '/files/tr_sh/main.js')); 14 | var pack = packer(); 15 | 16 | p.pipe(JSONStream.stringify()).pipe(pack); 17 | 18 | var src = ''; 19 | pack.on('data', function (buf) { src += buf }); 20 | pack.on('end', function () { 21 | Function('t', src)(t); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/tr_module.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var path = require('path'); 6 | 7 | test('transform', function (t) { 8 | t.plan(4); 9 | var p = mdeps({ 10 | transform: [ 'insert-aaa', 'insert-bbb' ], 11 | transformKey: [ 'browserify', 'transform' ] 12 | }); 13 | p.end(path.join(__dirname, '/files/tr_module/main.js')); 14 | var pack = packer(); 15 | 16 | p.pipe(JSONStream.stringify()).pipe(pack); 17 | 18 | var src = ''; 19 | pack.on('data', function (buf) { src += buf }); 20 | pack.on('end', function () { 21 | Function('t', src)(t); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/tr_2dep_module.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var path = require('path'); 6 | 7 | test('transform', function (t) { 8 | t.plan(3); 9 | var p = mdeps({ 10 | transform: [ 'insert-aaa', 'insert-bbb' ], 11 | transformKey: [ 'browserify', 'transform' ] 12 | }); 13 | p.end(path.join(__dirname, '/files/tr_2dep_module/main.js')); 14 | var pack = packer(); 15 | 16 | p.pipe(JSONStream.stringify()).pipe(pack); 17 | 18 | var src = ''; 19 | pack.on('data', function (buf) { src += buf }); 20 | pack.on('end', function () { 21 | Function('t', src)(t); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/tr_rel.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var path = require('path'); 6 | 7 | test('transform', function (t) { 8 | t.plan(1); 9 | var p = mdeps({ 10 | transformKey: [ 'browserify', 'transform' ] 11 | }); 12 | p.end(path.join(__dirname, '/files/tr_rel/subdir/main.js')); 13 | var pack = packer(); 14 | 15 | p.pipe(JSONStream.stringify()).pipe(pack); 16 | 17 | var src = ''; 18 | pack.on('data', function (buf) { src += buf }); 19 | pack.on('end', function () { 20 | Function('console', src)({ log: function (msg) { 21 | t.equal(msg, 333); 22 | } }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | # not yet available on appveyor 4 | # - nodejs_version: "12" 5 | - nodejs_version: "11" 6 | - nodejs_version: "10" 7 | - nodejs_version: "8" 8 | - nodejs_version: "6" 9 | - nodejs_version: "4" 10 | - nodejs_version: "0.12" 11 | - nodejs_version: "0.10" 12 | 13 | # Install scripts. (runs after repo cloning) 14 | install: 15 | # Get the latest stable version of Node.js or io.js 16 | - ps: Install-Product node $env:nodejs_version 17 | # install modules 18 | - npm install 19 | 20 | # Post-install test scripts. 21 | test_script: 22 | # Output useful info for debugging. 23 | - node --version 24 | - npm --version 25 | # run tests 26 | - npm test 27 | 28 | # Don't actually build. 29 | build: off 30 | -------------------------------------------------------------------------------- /test/pkg_filter.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var concat = require('concat-stream'); 6 | var path = require('path'); 7 | 8 | test('pkg filter', function (t) { 9 | t.plan(3); 10 | 11 | var p = mdeps({ 12 | packageFilter: function (pkg) { 13 | if (pkg.name === undefined) { 14 | t.equal(pkg.main, 'one.js'); 15 | pkg.main = 'two.js' 16 | } 17 | return pkg; 18 | } 19 | }); 20 | p.end(path.join(__dirname, '/files/pkg_filter/test.js')); 21 | 22 | var pack = packer(); 23 | p.pipe(JSONStream.stringify()).pipe(pack); 24 | 25 | pack.pipe(concat(function (src) { 26 | Function('t', src)(t); 27 | })); 28 | }); 29 | -------------------------------------------------------------------------------- /bin/cmd.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var mdeps = require('../'); 3 | var subarg = require('subarg'); 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | 7 | var argv = subarg(process.argv.slice(2), { 8 | alias: { h: 'help', t: 'transform', g: 'globalTransform' } 9 | }); 10 | if (argv.help) return usage(0); 11 | 12 | var JSONStream = require('JSONStream'); 13 | 14 | var files = argv._.map(function (file) { 15 | if (file === '-') return process.stdin; 16 | return path.resolve(file); 17 | }); 18 | var md = mdeps(argv); 19 | md.pipe(JSONStream.stringify()).pipe(process.stdout); 20 | 21 | files.forEach(function (file) { md.write(file) }); 22 | md.end(); 23 | 24 | function usage (code) { 25 | var r = fs.createReadStream(__dirname + '/usage.txt'); 26 | r.pipe(process.stdout); 27 | if (code) r.on('end', function () { process.exit(code) }); 28 | } 29 | -------------------------------------------------------------------------------- /test/syntax.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var through = require('through2'); 6 | var path = require('path'); 7 | 8 | test('syntax error', function (t) { 9 | t.plan(2); 10 | var input = path.join(__dirname, '/files/syntax_error.js'); 11 | // ensure transformDeps functionality does not break when parse errors happen 12 | // see https://github.com/browserify/module-deps/commit/9fe46d5#commitcomment-28273437 13 | var p = mdeps({ 14 | transform: function () { return through(); } 15 | }); 16 | p.on('file', function (file) { 17 | t.equal(file, input, 'should emit a file event even if there was an error'); 18 | }); 19 | p.on('error', function (err) { 20 | t.ok(err); 21 | }); 22 | p.end(input); 23 | }); 24 | -------------------------------------------------------------------------------- /test/row_expose.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var through = require('through2'); 4 | var path = require('path'); 5 | 6 | // Test that p.options.expose is defined and that the row is properly exposed 7 | // (resolved to the absolute pathname corresponding to the `file` value passed 8 | // in the row, and set in opts.expose). 9 | test('row is exposed', function (t) { 10 | t.plan(1); 11 | var common_path = path.join(__dirname, '/files/main'); 12 | var opts = { expose: {} }; 13 | var p = parser(opts); 14 | // Note pathname without extension. 15 | p.end({ file: common_path, expose: "whatever" }); 16 | p.on('error', t.fail.bind(t)); 17 | 18 | p.pipe(through.obj()); 19 | 20 | p.on('end', function () { 21 | // Note pathname with extension. 22 | t.equal(opts.expose.whatever, common_path + '.js'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /test/tr_write.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var path = require('path'); 6 | var concat = require('concat-stream'); 7 | 8 | test('transform write', function (t) { 9 | t.plan(1); 10 | var p = mdeps(); 11 | 12 | p.write({ 13 | transform: 'insert-www', 14 | options: {} 15 | }); 16 | p.write({ 17 | file: path.join(__dirname, 'tr_write/main.js'), 18 | id: path.join(__dirname, 'tr_write/main.js'), 19 | entry: true 20 | }); 21 | p.end(); 22 | 23 | var pack = packer(); 24 | p.pipe(JSONStream.stringify()).pipe(pack); 25 | 26 | pack.pipe(concat(function (buf) { 27 | var src = buf.toString('utf8'); 28 | Function('console', src)({ log: function (msg) { 29 | t.equal(msg, 'WORLD WIDE WOW'); 30 | } }); 31 | })); 32 | }); 33 | -------------------------------------------------------------------------------- /test/filter.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | var path = require('path') 3 | var mdeps = require('../') 4 | 5 | var core = ['events', 'util', 'dns', 'dgram', 'http', 'https', 'net', 'fs'] 6 | 7 | var collect = [] 8 | 9 | var entry = path.join(__dirname, 'files', 'filterable.js') 10 | 11 | test('can filter core deps', function (t) { 12 | var p = mdeps({ 13 | filter: function (e) { 14 | return !~core.indexOf(e) 15 | } 16 | }) 17 | p.on('data', function (d) { 18 | collect.push(d) 19 | t.equal(d.id, entry) 20 | t.deepEqual(d.deps, { 21 | events: false, 22 | fs: false, 23 | net: false, 24 | http: false, 25 | https: false, 26 | dgram: false, 27 | dns: false 28 | }) 29 | t.equal(d.entry, true) 30 | }); 31 | p.on('end', function () { 32 | t.equal(collect.length, 1) 33 | t.end() 34 | }); 35 | p.end(entry); 36 | }) 37 | -------------------------------------------------------------------------------- /test/row_expose_transform.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var through = require('through2'); 4 | var path = require('path'); 5 | 6 | // test that (non global) transforms are applied to an exposed module 7 | test('row is exposed and transformed', function (t) { 8 | t.plan(2); 9 | var exposed_path = path.join(__dirname, '/files/main.js'); 10 | var found_exposed_path = false; 11 | var opts = { 12 | expose: {}, 13 | transform: function(file) { 14 | if (file === exposed_path) { 15 | found_exposed_path = true; 16 | } 17 | return through(); 18 | } 19 | }; 20 | 21 | var p = parser(opts); 22 | p.end({ file: exposed_path, expose: "whatever" }); 23 | p.on('error', t.fail.bind(t)); 24 | 25 | p.pipe(through.obj()); 26 | 27 | p.on('end', function () { 28 | t.equal(opts.expose.whatever, exposed_path); 29 | t.ok(found_exposed_path); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/detect.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var path = require('path'); 6 | 7 | test('detect', function (t) { 8 | t.plan(1); 9 | var p = parser({ 10 | detect: function (source) { 11 | var rx = /require\(["'](.*?)["']\)/g; 12 | var m, deps = []; 13 | while (m = rx.exec(source)) { 14 | deps.push(m[1]); 15 | } 16 | return deps; 17 | } 18 | }); 19 | p.end(path.join(__dirname, '/files/main.js')); 20 | p.on('error', t.fail.bind(t)); 21 | var pack = packer(); 22 | 23 | p.pipe(JSONStream.stringify()).pipe(pack); 24 | 25 | var src = ''; 26 | pack.on('data', function (buf) { src += buf }); 27 | pack.on('end', function () { 28 | Function('console', src)({ 29 | log: function (s) { t.equal(s, 'main: 1055') } 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/tr_global.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var concat = require('concat-stream'); 6 | var path = require('path'); 7 | 8 | test('global transforms', function (t) { 9 | t.plan(1); 10 | 11 | var p = mdeps({ 12 | transform: [ 'tr-c', 'tr-d' ], 13 | globalTransform: [ 14 | path.join(__dirname, '/files/tr_global/node_modules/tr-e'), 15 | path.join(__dirname, '/files/tr_global/node_modules/tr-f') 16 | ], 17 | transformKey: [ 'browserify', 'transform' ] 18 | }); 19 | p.end(path.join(__dirname, '/files/tr_global/main.js')); 20 | var pack = packer(); 21 | 22 | p.pipe(JSONStream.stringify()).pipe(pack).pipe(concat(function (src) { 23 | Function(['console'], src)({ 24 | log: function (msg) { 25 | t.equal(msg, 111111); 26 | } 27 | }); 28 | })); 29 | }); 30 | -------------------------------------------------------------------------------- /test/tr_fn.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var through = require('through2'); 6 | var path = require('path'); 7 | 8 | test('transform', function (t) { 9 | t.plan(3); 10 | var p = mdeps({ 11 | transform: function (file) { 12 | return through(function (buf, enc, next) { 13 | this.push(String(buf) 14 | .replace(/AAA/g, '5') 15 | .replace(/BBB/g, '50') 16 | ); 17 | next(); 18 | }); 19 | }, 20 | transformKey: [ 'browserify', 'transform' ] 21 | }); 22 | p.end(path.join(__dirname, '/files/tr_sh/main.js')); 23 | var pack = packer(); 24 | 25 | p.pipe(JSONStream.stringify()).pipe(pack); 26 | 27 | var src = ''; 28 | pack.on('data', function (buf) { src += buf }); 29 | pack.on('end', function () { 30 | Function('t', src)(t); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/tr_no_entry.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var JSONStream = require('JSONStream'); 4 | var packer = require('browser-pack'); 5 | var through = require('through2'); 6 | var concat = require('concat-stream'); 7 | var path = require('path'); 8 | 9 | test('transform no entry', function (t) { 10 | t.plan(1); 11 | var p = mdeps({ 12 | transform: [ function (file) { 13 | return through(function (buf, enc, next) { 14 | this.push(String(buf).replace(/AAA/g, '"WOW"')); 15 | next(); 16 | }); 17 | } ] 18 | }); 19 | p.end({ 20 | file: path.join(__dirname, '/files/tr_no_entry/main.js'), 21 | id: 'xxx' 22 | }); 23 | 24 | p.pipe(JSONStream.stringify()).pipe(packer()) 25 | .pipe(concat(function (body) { 26 | var con = { log: function (x) { t.equal(x, 'WOW') } }; 27 | var src = 'require=' + body.toString('utf8') + ';require("xxx")'; 28 | Function('console', src)(con); 29 | })) 30 | ; 31 | }); 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This software is released under the MIT license: 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /test/noparse_row.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var fs = require('fs'); 4 | var concat = require('concat-stream'); 5 | var path = require('path'); 6 | 7 | var files = { 8 | main: path.join(__dirname, '/files/main.js'), 9 | foo: path.join(__dirname, '/files/foo.js'), 10 | bar: path.join(__dirname, '/files/bar.js') 11 | }; 12 | 13 | var sources = Object.keys(files).reduce(function (acc, file) { 14 | acc[file] = fs.readFileSync(files[file], 'utf8'); 15 | return acc; 16 | }, {}); 17 | 18 | test('noParse row', function (t) { 19 | t.plan(1); 20 | var p = parser(); 21 | p.end({ file: files.main, noparse: true }); 22 | var rows = []; 23 | 24 | p.on('data', function (row) { rows.push(row) }); 25 | p.on('end', function () { 26 | t.deepEqual(rows.sort(cmp), [ 27 | { 28 | id: files.main, 29 | file: files.main, 30 | source: sources.main, 31 | entry: true, 32 | noparse: true, 33 | deps: {} 34 | } 35 | ].sort(cmp)); 36 | }); 37 | }); 38 | 39 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 40 | -------------------------------------------------------------------------------- /test/expose.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | var files = { 7 | foo: path.join(__dirname, '/files/foo.js'), 8 | bar: path.join(__dirname, '/files/bar.js') 9 | }; 10 | 11 | var sources = Object.keys(files).reduce(function (acc, file) { 12 | acc[file] = fs.readFileSync(files[file], 'utf8'); 13 | return acc; 14 | }, {}); 15 | 16 | test('single id export', function (t) { 17 | t.plan(1); 18 | var p = parser(); 19 | p.end({ id: 'foo', file: files.foo, entry: false }); 20 | 21 | var rows = []; 22 | p.on('data', function (row) { rows.push(row) }); 23 | p.on('end', function () { 24 | t.same(rows.sort(cmp), [ 25 | { 26 | id: 'foo', 27 | file: files.foo, 28 | source: sources.foo, 29 | deps: { './bar': files.bar } 30 | }, 31 | { 32 | id: files.bar, 33 | file: files.bar, 34 | source: sources.bar, 35 | deps: {} 36 | } 37 | ].sort(cmp)); 38 | }); 39 | }); 40 | 41 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 42 | -------------------------------------------------------------------------------- /test/row_expose_name_is_file_transform.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var through = require('through2'); 4 | var path = require('path'); 5 | 6 | // test that (non global) transforms are applied to an exposed module, where in the 7 | // exposed name is identical to the file path. 8 | test('row is exposed with a name equal to the path, and transformed', function (t) { 9 | t.plan(2); 10 | var exposed_path = path.join(__dirname, '/files/main.js'); 11 | var found_exposed_path = false; 12 | var opts = { 13 | expose: {}, 14 | transform: function(file) { 15 | if (file === exposed_path) { 16 | found_exposed_path = true; 17 | } 18 | return through(); 19 | } 20 | }; 21 | 22 | var p = parser(opts); 23 | p.end({ file: exposed_path, expose: exposed_path }); 24 | p.on('error', t.fail.bind(t)); 25 | 26 | p.pipe(through.obj()); 27 | 28 | p.on('end', function () { 29 | t.equal(opts.expose[exposed_path], exposed_path); 30 | t.ok(found_exposed_path); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/quotes.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | var files = { 7 | main: path.join(__dirname, '/files/quotes/main.js'), 8 | foo: path.join(__dirname, '/files/quotes/foo.js'), 9 | bar: path.join(__dirname, '/files/quotes/bar.js'), 10 | baz: path.join(__dirname, '/files/quotes/baz.js') 11 | }; 12 | 13 | var sources = Object.keys(files).reduce(function (acc, file) { 14 | acc[file] = fs.readFileSync(files[file], 'utf8'); 15 | return acc; 16 | }, {}); 17 | 18 | test('different quote styles', function (t) { 19 | t.plan(1); 20 | var p = parser(); 21 | p.end(files.main); 22 | var main = null 23 | 24 | p.on('data', function (row) { 25 | if (row.id === files.main) { 26 | main = row 27 | } 28 | }); 29 | p.on('end', function () { 30 | t.same(main, { 31 | id: files.main, 32 | file: files.main, 33 | source: sources.main, 34 | entry: true, 35 | deps: { 36 | './foo': files.foo, 37 | './bar': files.bar, 38 | './baz': files.baz 39 | } 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /test/noparse.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | var files = { 7 | main: path.join(__dirname, '/files/main.js'), 8 | foo: path.join(__dirname, '/files/foo.js'), 9 | bar: path.join(__dirname, '/files/bar.js') 10 | }; 11 | 12 | var sources = Object.keys(files).reduce(function (acc, file) { 13 | acc[file] = fs.readFileSync(files[file], 'utf8'); 14 | return acc; 15 | }, {}); 16 | 17 | test('noParse', function (t) { 18 | t.plan(1); 19 | var p = parser({ noParse: [ files.foo ] }); 20 | p.end(files.main); 21 | var rows = []; 22 | 23 | p.on('data', function (row) { rows.push(row) }); 24 | p.on('end', function () { 25 | t.deepEqual(rows.sort(cmp), [ 26 | { 27 | id: files.main, 28 | file: files.main, 29 | source: sources.main, 30 | entry: true, 31 | deps: { './foo': files.foo } 32 | }, 33 | { 34 | id: files.foo, 35 | file: files.foo, 36 | source: sources.foo, 37 | deps: {} 38 | } 39 | ].sort(cmp)); 40 | }); 41 | }); 42 | 43 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 44 | -------------------------------------------------------------------------------- /test/cache_partial.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | var files = { 7 | foo: path.join(__dirname, '/files/foo.js'), 8 | bar: path.join(__dirname, '/files/bar.js') 9 | }; 10 | 11 | var sources = { 12 | foo: 'notreal foo', 13 | bar: fs.readFileSync(files.bar, 'utf8') 14 | }; 15 | 16 | var cache = {}; 17 | cache[files.foo] = { 18 | source: sources.foo, 19 | deps: { './bar': files.bar } 20 | }; 21 | 22 | test('uses cache and reads from disk', function (t) { 23 | t.plan(1); 24 | var p = parser({ cache: cache }); 25 | p.end({ id: 'foo', file: files.foo, entry: false }); 26 | 27 | var rows = []; 28 | p.on('data', function (row) { rows.push(row) }); 29 | p.on('end', function () { 30 | t.same(rows.sort(cmp), [ 31 | { 32 | id: 'foo', 33 | file: files.foo, 34 | source: sources.foo, 35 | deps: { './bar': files.bar } 36 | }, 37 | { 38 | id: files.bar, 39 | file: files.bar, 40 | source: sources.bar, 41 | deps: {} 42 | } 43 | ].sort(cmp)); 44 | }); 45 | }); 46 | 47 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 48 | -------------------------------------------------------------------------------- /test/cache.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var path = require('path'); 4 | 5 | var files = { 6 | foo: path.join(__dirname, '/files/foo.js'), 7 | bar: path.join(__dirname, '/files/bar.js') 8 | }; 9 | 10 | var sources = { 11 | foo: 'notreal foo', 12 | bar: 'notreal bar' 13 | }; 14 | 15 | var cache = {}; 16 | cache[files.foo] = { 17 | source: sources.foo, 18 | deps: { './bar': files.bar } 19 | }; 20 | cache[files.bar] = { 21 | source: sources.bar, 22 | deps: {} 23 | }; 24 | 25 | test('uses cache', function (t) { 26 | t.plan(1); 27 | var p = parser({ cache: cache }); 28 | p.end({ id: 'foo', file: files.foo, entry: false }); 29 | 30 | var rows = []; 31 | p.on('data', function (row) { rows.push(row) }); 32 | p.on('end', function () { 33 | t.same(rows.sort(cmp), [ 34 | { 35 | id: 'foo', 36 | file: files.foo, 37 | source: sources.foo, 38 | deps: { './bar': files.bar } 39 | }, 40 | { 41 | id: files.bar, 42 | file: files.bar, 43 | source: sources.bar, 44 | deps: {} 45 | } 46 | ].sort(cmp)); 47 | }); 48 | }); 49 | 50 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 51 | -------------------------------------------------------------------------------- /test/tr_flags.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | var mdeps = require('../'); 3 | var test = require('tap').test; 4 | 5 | test('--debug passed to transforms', function (t) { 6 | var empty = require.resolve('./tr_flags/empty.js'); 7 | 8 | t.plan(5); 9 | 10 | var p 11 | [true, false].forEach(function(debug) { 12 | p = mdeps({ 13 | debug: debug, 14 | transform: function (file, opts) { 15 | t.equal(opts._flags.debug, debug, 'debug: ' + debug); 16 | return through(); 17 | } 18 | }) 19 | p.on('error', function (err) { return t.fail(err.message) }) 20 | p.end(empty); 21 | 22 | p = mdeps({ debug: debug }) 23 | p.write({ 24 | transform: function (file, opts) { 25 | t.equal(opts._flags.debug, debug, 'debug: ' + debug); 26 | return through(); 27 | }, 28 | options: {} 29 | }) 30 | p.on('error', function (err) { return t.fail(err.message) }) 31 | p.end(empty); 32 | }); 33 | 34 | p = mdeps({ debug: true }) 35 | p.write({ 36 | transform: function (file, opts) { 37 | t.equal(opts._flags, Infinity, 'transform arguments are preserved'); 38 | return through(); 39 | }, 40 | options: { _flags: Infinity } 41 | }) 42 | p.on('error', function (err) { return t.fail(err.message) }) 43 | p.end(empty); 44 | }); 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "module-deps", 3 | "version": "6.2.3", 4 | "description": "walk the dependency graph to generate json output that can be fed into browser-pack", 5 | "main": "index.js", 6 | "bin": { 7 | "module-deps": "bin/cmd.js" 8 | }, 9 | "dependencies": { 10 | "JSONStream": "^1.0.3", 11 | "browser-resolve": "^2.0.0", 12 | "cached-path-relative": "^1.0.2", 13 | "concat-stream": "~1.6.0", 14 | "defined": "^1.0.0", 15 | "detective": "^5.2.0", 16 | "duplexer2": "^0.1.2", 17 | "inherits": "^2.0.1", 18 | "parents": "^1.0.0", 19 | "readable-stream": "^2.0.2", 20 | "resolve": "^1.4.0", 21 | "stream-combiner2": "^1.1.1", 22 | "subarg": "^1.0.0", 23 | "through2": "^2.0.0", 24 | "xtend": "^4.0.0" 25 | }, 26 | "devDependencies": { 27 | "browser-pack": "^6.0.2", 28 | "tap": "^10.7.3" 29 | }, 30 | "scripts": { 31 | "test": "tap test/*.js" 32 | }, 33 | "repository": { 34 | "type": "git", 35 | "url": "git://github.com/browserify/module-deps.git" 36 | }, 37 | "homepage": "https://github.com/browserify/module-deps", 38 | "keywords": [ 39 | "dependency", 40 | "graph", 41 | "browser", 42 | "require", 43 | "module", 44 | "exports", 45 | "json" 46 | ], 47 | "author": { 48 | "name": "James Halliday", 49 | "email": "mail@substack.net", 50 | "url": "http://substack.net" 51 | }, 52 | "engines": { 53 | "node": ">= 0.8.0" 54 | }, 55 | "license": "MIT" 56 | } 57 | -------------------------------------------------------------------------------- /test/deps.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | var files = { 7 | main: path.join(__dirname, '/files/main.js'), 8 | foo: path.join(__dirname, '/files/foo.js'), 9 | bar: path.join(__dirname, '/files/bar.js') 10 | }; 11 | 12 | var sources = Object.keys(files).reduce(function (acc, file) { 13 | acc[file] = fs.readFileSync(files[file], 'utf8'); 14 | return acc; 15 | }, {}); 16 | 17 | test('deps', function (t) { 18 | t.plan(1); 19 | var p = parser(); 20 | p.end({ file: files.main, entry: true }); 21 | 22 | var rows = []; 23 | p.on('data', function (row) { rows.push(row) }); 24 | p.on('end', function () { 25 | t.same(rows.sort(cmp), [ 26 | { 27 | id: files.main, 28 | file: files.main, 29 | source: sources.main, 30 | entry: true, 31 | deps: { './foo': files.foo } 32 | }, 33 | { 34 | id: files.foo, 35 | file: files.foo, 36 | source: sources.foo, 37 | deps: { './bar': files.bar } 38 | }, 39 | { 40 | id: files.bar, 41 | file: files.bar, 42 | source: sources.bar, 43 | deps: {} 44 | } 45 | ].sort(cmp)); 46 | }); 47 | }); 48 | 49 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 50 | -------------------------------------------------------------------------------- /test/undef_file.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | var files = { 7 | main: path.join(__dirname, '/files/main.js'), 8 | foo: path.join(__dirname, '/files/foo.js'), 9 | bar: path.join(__dirname, '/files/bar.js') 10 | }; 11 | 12 | var sources = Object.keys(files).reduce(function (acc, file) { 13 | acc[file] = fs.readFileSync(files[file], 'utf8'); 14 | return acc; 15 | }, {}); 16 | 17 | test('undef file', function (t) { 18 | t.plan(1); 19 | var p = parser(); 20 | p.end({ id: files.main, entry: true }); 21 | 22 | var rows = []; 23 | p.on('data', function (row) { rows.push(row) }); 24 | p.on('end', function () { 25 | t.same(rows.sort(cmp), [ 26 | { 27 | id: files.main, 28 | file: files.main, 29 | source: sources.main, 30 | entry: true, 31 | deps: { './foo': files.foo } 32 | }, 33 | { 34 | id: files.foo, 35 | file: files.foo, 36 | source: sources.foo, 37 | deps: { './bar': files.bar } 38 | }, 39 | { 40 | id: files.bar, 41 | file: files.bar, 42 | source: sources.bar, 43 | deps: {} 44 | } 45 | ].sort(cmp)); 46 | }); 47 | }); 48 | 49 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 50 | -------------------------------------------------------------------------------- /test/unicode.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | var files = { 7 | main: path.join(__dirname, '/files/unicode/main.js'), 8 | foo: path.join(__dirname, '/files/unicode/foo.js'), 9 | bar: path.join(__dirname, '/files/unicode/bar.js') 10 | }; 11 | 12 | var sources = Object.keys(files).reduce(function (acc, file) { 13 | acc[file] = fs.readFileSync(files[file], 'utf8'); 14 | return acc; 15 | }, {}); 16 | 17 | test('unicode deps', function (t) { 18 | t.plan(1); 19 | var p = parser(); 20 | p.end(files.main); 21 | var rows = []; 22 | 23 | p.on('data', function (row) { rows.push(row) }); 24 | p.on('end', function () { 25 | t.same(rows.sort(cmp), [ 26 | { 27 | id: files.main, 28 | file: files.main, 29 | source: sources.main, 30 | entry: true, 31 | deps: { './foo': files.foo } 32 | }, 33 | { 34 | id: files.foo, 35 | file: files.foo, 36 | source: sources.foo, 37 | deps: { './bar': files.bar } 38 | }, 39 | { 40 | id: files.bar, 41 | file: files.bar, 42 | source: sources.bar, 43 | deps: {} 44 | } 45 | ].sort(cmp)); 46 | }); 47 | }); 48 | 49 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 50 | -------------------------------------------------------------------------------- /test/cache_expose.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var path = require('path'); 4 | 5 | var files = { 6 | foo: path.join(__dirname, '/files/foo.js'), 7 | bar: path.join(__dirname, '/files/bar.js') 8 | }; 9 | 10 | var sources = { 11 | foo: 'notreal foo', 12 | bar: 'notreal bar' 13 | }; 14 | 15 | var cache = {}; 16 | cache[files.foo] = { 17 | source: sources.foo, 18 | deps: { './bar': files.bar } 19 | }; 20 | cache[files.bar] = { 21 | source: sources.bar, 22 | deps: {} 23 | }; 24 | 25 | test('cache preserves expose and entry', function (t) { 26 | t.plan(1); 27 | var p = parser({ cache: cache }); 28 | p.write({ id: files.bar, expose: 'bar2', entry: false }); 29 | p.end({ id: 'foo', file: files.foo, entry: true, expose: 'foo2' }); 30 | 31 | var rows = []; 32 | p.on('data', function (row) { rows.push(row) }); 33 | p.on('end', function () { 34 | t.same(rows.sort(cmp), [ 35 | { 36 | id: 'foo', 37 | expose: 'foo2', 38 | entry: true, 39 | file: files.foo, 40 | source: sources.foo, 41 | deps: { './bar': files.bar } 42 | }, 43 | { 44 | id: files.bar, 45 | expose: 'bar2', 46 | file: files.bar, 47 | source: sources.bar, 48 | deps: {} 49 | } 50 | ].sort(cmp)); 51 | }); 52 | }); 53 | 54 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 55 | -------------------------------------------------------------------------------- /test/ignore_missing_cache.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | var files = { 7 | main: path.join(__dirname, '/ignore_missing/main.js'), 8 | other: path.join(__dirname, '/ignore_missing/other.js') 9 | }; 10 | 11 | var sources = Object.keys(files).reduce(function (acc, file) { 12 | acc[file] = fs.readFileSync(files[file], 'utf8'); 13 | return acc; 14 | }, {}); 15 | 16 | var cache = {}; 17 | cache[files.main] = { 18 | source: sources.main, 19 | deps: { './other': files.other } 20 | }; 21 | cache[files.other] = { 22 | source: sources.other, 23 | deps: { 'missingModule': undefined } 24 | }; 25 | 26 | test('ignoreMissing with cache', function (t) { 27 | t.plan(1); 28 | var p = parser({ cache: cache, ignoreMissing: true }); 29 | p.end({file: files.main, entry: true}); 30 | 31 | var rows = []; 32 | p.on('data', function (row) { rows.push(row) }); 33 | p.on('end', function () { 34 | t.same(rows.sort(cmp), [ 35 | { 36 | id: files.main, 37 | file: files.main, 38 | source: sources.main, 39 | entry: true, 40 | deps: { './other': files.other } 41 | }, 42 | { 43 | id: files.other, 44 | file: files.other, 45 | source: sources.other, 46 | deps: { 'missingModule': undefined } 47 | } 48 | ].sort(cmp)); 49 | }); 50 | }); 51 | 52 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 53 | -------------------------------------------------------------------------------- /test/file_cache.js: -------------------------------------------------------------------------------- 1 | var mdeps = require('../'); 2 | var test = require('tap').test; 3 | var path = require('path'); 4 | var through = require('through2'); 5 | 6 | var files = { 7 | foo: path.join(__dirname, '/files/foo.js'), 8 | bar: path.join(__dirname, '/files/bar.js') 9 | }; 10 | 11 | var sources = { 12 | foo: 'require("./bar"); var tongs;', 13 | bar: 'notreal tongs' 14 | }; 15 | 16 | var fileCache = {}; 17 | fileCache[files.foo] = sources.foo; 18 | fileCache[files.bar] = sources.bar; 19 | 20 | var specialReplace = function(input) { 21 | return input.replace(/tongs/g, 'tangs'); 22 | }; 23 | 24 | test('uses file cache', function (t) { 25 | t.plan(1); 26 | var p = mdeps({ 27 | fileCache: fileCache, 28 | transform: function (file) { 29 | return through(function (buf, enc, next) { 30 | this.push(specialReplace(String(buf))); 31 | next(); 32 | }); 33 | }, 34 | transformKey: [ 'browserify', 'transform' ] 35 | }); 36 | p.end({ id: 'foo', file: files.foo, entry: false }); 37 | 38 | var rows = []; 39 | p.on('data', function (row) { rows.push(row) }); 40 | p.on('end', function () { 41 | t.same(rows.sort(cmp), [ 42 | { 43 | id: 'foo', 44 | file: files.foo, 45 | source: specialReplace(sources.foo), 46 | deps: { './bar': files.bar } 47 | }, 48 | { 49 | id: files.bar, 50 | file: files.bar, 51 | source: specialReplace(sources.bar), 52 | deps: {} 53 | } 54 | ].sort(cmp)); 55 | }); 56 | }); 57 | 58 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 59 | -------------------------------------------------------------------------------- /test/ignore_missing.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | var files = { 7 | main: path.join(__dirname, '/ignore_missing/main.js'), 8 | other: path.join(__dirname, '/ignore_missing/other.js') 9 | }; 10 | 11 | var sources = Object.keys(files).reduce(function (acc, file) { 12 | acc[file] = fs.readFileSync(files[file], 'utf8'); 13 | return acc; 14 | }, {}); 15 | 16 | test('ignoreMissing', function (t) { 17 | t.plan(1); 18 | var p = parser({ignoreMissing: true}); 19 | p.end({file: files.main, entry: true}); 20 | 21 | var rows = []; 22 | p.on('data', function (row) { rows.push(row) }); 23 | p.on('end', function () { 24 | t.same(rows.sort(cmp), [ 25 | { 26 | id: files.main, 27 | file: files.main, 28 | source: sources.main, 29 | entry: true, 30 | deps: { './other': files.other } 31 | }, 32 | { 33 | id: files.other, 34 | file: files.other, 35 | source: sources.other, 36 | deps: { 'missingModule': undefined } 37 | } 38 | ].sort(cmp)); 39 | }); 40 | }); 41 | 42 | test('ignoreMissing off', function (t) { 43 | t.plan(1); 44 | var p = parser(); 45 | p.end({file: files.main, entry: true}); 46 | 47 | var rows = []; 48 | p.on('data', function (row) { rows.push(row) }); 49 | p.on('error', function (err) { 50 | t.match( 51 | String(err), 52 | /Cannot find module 'missingModule'/ 53 | ); 54 | }); 55 | p.on('end', function () { 56 | t.fail('should have errored'); 57 | }); 58 | }); 59 | 60 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 61 | -------------------------------------------------------------------------------- /test/source.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | var files = { 7 | main: path.join(__dirname, '/files/main.js'), 8 | foo: path.join(__dirname, '/files/foo.js'), 9 | bar: path.join(__dirname, '/files/bar.js'), 10 | extra: path.join(__dirname, '/files/extra.js') 11 | }; 12 | var sources = { 13 | foo: fs.readFileSync(files.foo, 'utf8'), 14 | bar: fs.readFileSync(files.bar, 'utf8'), 15 | extra: fs.readFileSync(files.extra, 'utf8'), 16 | main: "console.log(require('./foo')(5)); require('./extra.js')" 17 | }; 18 | 19 | test('source', function (t) { 20 | t.plan(1); 21 | var p = parser(); 22 | p.end({ 23 | file: files.main, 24 | source: sources.main, 25 | entry: true 26 | }); 27 | 28 | var rows = []; 29 | p.on('data', function (row) { rows.push(row) }); 30 | p.on('end', function () { 31 | t.same(rows.sort(cmp), [ 32 | { 33 | id: files.main, 34 | file: files.main, 35 | source: sources.main, 36 | entry: true, 37 | deps: { './foo': files.foo, './extra.js': files.extra } 38 | }, 39 | { 40 | id: files.foo, 41 | file: files.foo, 42 | source: sources.foo, 43 | deps: { './bar': files.bar } 44 | }, 45 | { 46 | id: files.bar, 47 | file: files.bar, 48 | source: sources.bar, 49 | deps: {} 50 | }, 51 | { 52 | id: files.extra, 53 | file: files.extra, 54 | source: sources.extra, 55 | deps: {} 56 | }, 57 | ].sort(cmp)); 58 | }); 59 | }); 60 | 61 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 62 | -------------------------------------------------------------------------------- /test/tr_deps.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var through = require('through2'); 3 | var test = require('tap').test; 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | 7 | var files = { 8 | transformdeps: path.join(__dirname, '/files/transformdeps.js'), 9 | foo: path.join(__dirname, '/files/foo.js'), 10 | bar: path.join(__dirname, '/files/bar.js') 11 | }; 12 | 13 | var sources = Object.keys(files).reduce(function (acc, file) { 14 | acc[file] = fs.readFileSync(files[file], 'utf8'); 15 | return acc; 16 | }, {}); 17 | 18 | test('deps added by transforms', function (t) { 19 | t.plan(1); 20 | var p = parser(); 21 | p.write({ transform: transform, options: {} }); 22 | p.end({ file: files.transformdeps, entry: true }); 23 | function transform (file) { 24 | if (file === files.transformdeps) return through(function(chunk, enc, cb) { 25 | cb(null, chunk); 26 | }, function (cb) { 27 | this.emit('dep', './foo'); 28 | cb(); 29 | }); 30 | return through(); 31 | } 32 | 33 | var rows = []; 34 | p.on('data', function (row) { rows.push(row) }); 35 | p.on('end', function () { 36 | t.same(rows.sort(cmp), [ 37 | { 38 | id: files.transformdeps, 39 | file: files.transformdeps, 40 | source: sources.transformdeps, 41 | entry: true, 42 | deps: { './foo': files.foo } 43 | }, 44 | { 45 | id: files.foo, 46 | file: files.foo, 47 | source: sources.foo, 48 | deps: { './bar': files.bar } 49 | }, 50 | { 51 | id: files.bar, 52 | file: files.bar, 53 | source: sources.bar, 54 | deps: {} 55 | } 56 | ].sort(cmp)); 57 | }); 58 | }); 59 | 60 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 61 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # module-deps Change Log 2 | All notable changes to this project will be documented in this file. 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## 6.2.3 - 2020-08-03 6 | * Improve error message when dependencies cannot be found [#123](https://github.com/browserify/module-deps/pull/123) 7 | * Upgrade `browser-resolve` to 2.0 [#164](https://github.com/browserify/module-deps/pull/164) 8 | 9 | ## 6.2.2 - 2019-12-13 10 | * Update minimum required version of `detective` [#161](https://github.com/browserify/module-deps/pull/161) 11 | 12 | ## 6.2.1 - 2019-05-24 13 | * Update minimum required version of `cached-path-relative` [#155](https://github.com/browserify/module-deps/pull/155) 14 | * Add CI testing on Windows [#152](https://github.com/browserify/module-deps/pull/152) 15 | * Add CI testing on recent Node.js versions (10, 11, 12) [#157](https://github.com/browserify/module-deps/pull/157) 16 | 17 | ## 6.2.0 - 2018-11-13 18 | * Add `.dirname` property to the object given to `opts.resolve` [#154](https://github.com/browserify/module-deps/pull/154) 19 | 20 | ## 6.1.0 - 2018-05-16 21 | * Add a `detect` option for custom dependency detection [#63](https://github.com/browserify/module-deps/pull/63), [2dcc339](https://github.com/browserify/module-deps/commit/2dcc3399ee67ba51ed26d9a0605a8ccdc70c9db7) 22 | 23 | ## 6.0.2 - 2018-03-28 24 | * Fix missing 'file' event when file has a syntax error [#146](https://github.com/browserify/module-deps/pull/146) 25 | 26 | ## 6.0.1 - 2018-03-27 27 | * Fix crash when file has a transform and a syntax error [#145](https://github.com/browserify/module-deps/pull/145) 28 | 29 | ## 6.0.0 - 2018-02-07 30 | * Ignore package.json files that do not contain JSON objects [#142](https://github.com/browserify/module-deps/pull/142) 31 | * Don't preserve symlinks when resolving transforms, matching Node resolution behaviour [#133](https://github.com/browserify/module-deps/pull/133) 32 | * Fix 'file' events with `persistentCache` [#127](https://github.com/browserify/module-deps/pull/127) 33 | * Add dependencies to a file when transforms emit 'dep' event [#141](https://github.com/browserify/module-deps/pull/141) 34 | 35 | ## 5.0.1 - 2018-01-06 36 | * Restore support for node < 4.0.0. 37 | 38 | ## 5.0.0 - 2018-01-02 39 | * Update deps 40 | * Drop support for node < 0.12 due due to detective dropping support 41 | * Add engines field set to `>=4.0.0` 42 | -------------------------------------------------------------------------------- /test/cache_partial_expose.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | var xtend = require('xtend'); 6 | 7 | var files = { 8 | abc: path.join(__dirname, '/expose/lib/abc.js'), 9 | xyz: path.join(__dirname, '/expose/lib/xyz.js'), 10 | foo: path.join(__dirname, '/expose/foo.js'), 11 | bar: path.join(__dirname, '/expose/bar.js'), 12 | main: path.join(__dirname, '/expose/main.js') 13 | }; 14 | 15 | var sources = Object.keys(files).reduce(function (acc, file) { 16 | acc[file] = fs.readFileSync(files[file], 'utf8'); 17 | return acc; 18 | }, {}); 19 | 20 | var cache = {}; 21 | cache[files.abc] = { 22 | source: sources.abc, 23 | deps: {} 24 | }; 25 | cache[files.xyz] = { 26 | source: sources.xyz, 27 | deps: {'../foo': files.foo} 28 | }; 29 | cache[files.foo] = { 30 | source: sources.foo, 31 | deps: {'./lib/abc': files.abc} 32 | }; 33 | cache[files.bar] = { 34 | source: sources.bar, 35 | deps: {xyz: files.xyz} 36 | }; 37 | cache[files.main] = { 38 | source: sources.main, 39 | deps: { 40 | abc: files.abc, 41 | xyz: files.xyz, 42 | './bar': files.bar 43 | } 44 | }; 45 | 46 | test('preserves expose and entry with partial cache', function(t) { 47 | t.plan(1); 48 | 49 | var partialCache = xtend(cache); 50 | delete partialCache[files.bar]; 51 | 52 | var p = parser({ cache: partialCache }); 53 | p.write({ id: 'abc', file: files.abc, expose: 'abc' }); 54 | p.write({ id: 'xyz', file: files.xyz, expose: 'xyz' }); 55 | p.end({ id: 'main', file: files.main, entry: true }); 56 | 57 | var rows = []; 58 | p.on('data', function (row) { rows.push(row); }); 59 | p.on('end', function () { 60 | t.same(rows.sort(cmp), [ 61 | { 62 | id: files.bar, 63 | file: files.bar, 64 | source: sources.bar, 65 | deps: {xyz: files.xyz} 66 | }, 67 | { 68 | file: files.foo, 69 | id: files.foo, 70 | source: sources.foo, 71 | deps: {'./lib/abc': files.abc} 72 | }, 73 | { 74 | id: 'abc', 75 | file: files.abc, 76 | source: sources.abc, 77 | deps: {}, 78 | entry: true, 79 | expose: 'abc' 80 | }, 81 | { 82 | id: 'main', 83 | file: files.main, 84 | source: sources.main, 85 | deps: { 86 | './bar': files.bar, 87 | abc: files.abc, 88 | xyz: files.xyz 89 | }, 90 | entry: true 91 | }, 92 | { 93 | id: 'xyz', 94 | file: files.xyz, 95 | source: sources.xyz, 96 | deps: {'../foo': files.foo}, 97 | entry: true, 98 | expose: 'xyz' 99 | } 100 | ].sort(cmp)); 101 | }); 102 | }); 103 | 104 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 105 | -------------------------------------------------------------------------------- /test/resolve.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | 4 | var mdeps = require('../'); 5 | var test = require('tap').test; 6 | var nodeResolve = require('resolve'); 7 | var browserResolve = require('browser-resolve'); 8 | 9 | var missing = path.join(__dirname, '/missing'); 10 | 11 | var files = { 12 | foo: path.join(__dirname, '/files/resolve/foo/foo.js'), 13 | bar: path.join(__dirname, '/files/resolve/bar/bar.js'), 14 | bar2: path.join(__dirname, '/files/resolve/bar/bar2.js'), 15 | baz: path.join(__dirname, '/files/resolve/foo/baz/baz.js') 16 | }; 17 | 18 | var sources = Object.keys(files) 19 | .reduce(function (acc, file) { 20 | acc[file] = fs.readFileSync(files[file], 'utf8'); 21 | return acc; 22 | }, {}); 23 | 24 | var expectedRows = [ 25 | { 26 | "deps": {}, 27 | "file": files.baz, 28 | "id": files.baz, 29 | "source": sources.baz 30 | }, 31 | { 32 | "deps": {}, 33 | "file": files.bar2, 34 | "id": files.bar2, 35 | "source": sources.bar2 36 | }, 37 | { 38 | "deps": { 39 | "./bar2": files.bar2 40 | }, 41 | "file": files.bar, 42 | "id": files.bar, 43 | "source": sources.bar 44 | }, 45 | { 46 | "deps": { 47 | "../bar/bar.js": files.bar, 48 | "./baz/baz.js": files.baz 49 | }, 50 | "entry": true, 51 | "file": files.foo, 52 | "id": "foo", 53 | "source": sources.foo 54 | } 55 | ]; 56 | 57 | test('browser resolve - missing', function (t) { 58 | t.plan(1); 59 | var d = mdeps({resolve: browserResolve}); 60 | 61 | d.end({id: 'missing', file: missing, entry: true}); 62 | 63 | d.on('end', function () { 64 | t.fail('errored'); 65 | }); 66 | d.on('error', function (err) { 67 | t.match( 68 | String(err), 69 | /Cannot find module .*/ 70 | ); 71 | }); 72 | }); 73 | 74 | test('node resolve - missing', function (t) { 75 | t.plan(1); 76 | var d = mdeps({resolve: nodeResolve}); 77 | 78 | d.end({id: 'missing', file: missing, entry: true}); 79 | 80 | d.on('end', function () { 81 | t.fail('errored'); 82 | }); 83 | d.on('error', function (err) { 84 | t.match( 85 | String(err), 86 | /Cannot find module .*/ 87 | ); 88 | }); 89 | }); 90 | 91 | test('browser resolve', function (t) { 92 | t.plan(1); 93 | var d = mdeps({resolve: browserResolve}); 94 | 95 | d.end({id: 'foo', file: files.foo, entry: true}); 96 | 97 | var rows = []; 98 | d.on('data', function (row) {rows.push(row)}); 99 | d.on('end', function () { 100 | t.same(rows, expectedRows); 101 | }); 102 | d.on('error', function () { 103 | t.fail('errored'); 104 | }); 105 | }); 106 | 107 | test('node resolve', function (t) { 108 | t.plan(1); 109 | var d = mdeps({resolve: nodeResolve}); 110 | 111 | d.end({id: 'foo', file: files.foo, entry: true}); 112 | 113 | var rows = []; 114 | d.on('data', function (row) {rows.push(row)}); 115 | d.on('end', function () { 116 | t.same(rows, expectedRows); 117 | }); 118 | d.on('error', function () { 119 | t.fail('errored'); 120 | }); 121 | }); -------------------------------------------------------------------------------- /test/cache_persistent.js: -------------------------------------------------------------------------------- 1 | var parser = require('../'); 2 | var test = require('tap').test; 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | 6 | var files = { 7 | foo: path.join(__dirname, '/files/foo.js'), 8 | bar: path.join(__dirname, '/files/bar.js') 9 | }; 10 | 11 | test('uses persistent cache', function (t) { 12 | t.plan(1); 13 | var p = parser({ 14 | persistentCache: function (file, id, pkg, fallback, cb) { 15 | if (file === files.bar) { 16 | return fallback(null, cb); 17 | } 18 | cb(null, { 19 | source: 'file at ' + file + '@' + id, 20 | package: pkg, 21 | deps: { './bar': files.bar } 22 | }); 23 | } 24 | }); 25 | p.end({ id: 'foo', file: files.foo, entry: false }); 26 | 27 | var rows = []; 28 | p.on('data', function (row) { rows.push(row) }); 29 | p.on('end', function () { 30 | t.same(rows.sort(cmp), [ 31 | { 32 | id: files.bar, 33 | file: files.bar, 34 | source: fs.readFileSync(files.bar, 'utf8'), 35 | deps: {} 36 | }, 37 | { 38 | id: 'foo', 39 | file: files.foo, 40 | source: 'file at ' + files.foo + '@' + files.foo, 41 | deps: { './bar': files.bar } 42 | } 43 | ].sort(cmp)); 44 | }); 45 | }); 46 | 47 | test('passes persistent cache error through', function (t) { 48 | t.plan(1); 49 | var p = parser({ 50 | persistentCache: function (file, id, pkg, fallback, cb) { 51 | cb(new Error('foo')); 52 | } 53 | }); 54 | p.end({ id: 'foo', file: files.foo, entry: false }); 55 | p.on('error', function (err) { t.equals(err.message, 'foo') }); 56 | }); 57 | 58 | test('allow passing of the raw source as string', function (t) { 59 | t.plan(1); 60 | var p = parser({ 61 | persistentCache: function (file, id, pkg, fallback, cb) { 62 | fallback(fs.readFileSync(files.bar, 'utf8'), cb); 63 | } 64 | }); 65 | p.end({ id: 'foo', file: files.foo, entry: false }); 66 | 67 | var rows = []; 68 | p.on('data', function (row) { rows.push(row) }); 69 | p.on('end', function () { 70 | t.same(rows.sort(cmp), [ 71 | { 72 | id: 'foo', 73 | file: files.foo, 74 | source: fs.readFileSync(files.bar, 'utf8'), 75 | deps: {} 76 | } 77 | ].sort(cmp)); 78 | }); 79 | }); 80 | 81 | test('send file event with persistent cache', function (t) { 82 | t.plan(2); 83 | var p = parser({ 84 | persistentCache: function (file, id, pkg, fallback, cb) { 85 | cb(null, { 86 | source: 'file at ' + file + '@' + id, 87 | package: pkg, 88 | deps: {} 89 | }); 90 | } 91 | }); 92 | p.end({ id: 'foo', file: files.foo, entry: false }); 93 | p.on('file', function (file, id) { 94 | t.same(file, path.resolve(files.foo)); 95 | t.same(id, path.resolve(files.foo)); 96 | }); 97 | }); 98 | 99 | test('errors of transforms occur in the correct order with a persistent cache', function (t) { 100 | t.plan(3); 101 | var p = parser({ 102 | transform: [ 103 | path.join(__dirname, 'cache_persistent', 'error_transform') 104 | ], 105 | persistentCache: function (file, id, pkg, fallback, cb) { 106 | fallback(fs.readFileSync(files.foo, 'utf8'), cb); 107 | } 108 | }); 109 | p.end({ id: 'foo', file: files.foo, entry: false }); 110 | var order = 0; 111 | p.on('file', function (file, id) { 112 | t.same(order, 0); 113 | order += 1; 114 | }); 115 | p.on('error', function (err) { 116 | t.same(order, 1); 117 | t.same(err.message, 'rawr while parsing file: ' + path.resolve(files.foo)); 118 | }); 119 | }); 120 | 121 | 122 | function cmp (a, b) { return a.id < b.id ? -1 : 1 } 123 | -------------------------------------------------------------------------------- /readme.markdown: -------------------------------------------------------------------------------- 1 | # module-deps 2 | 3 | walk the dependency graph to generate json output that can be fed into 4 | [browser-pack](https://github.com/browserify/browser-pack) 5 | 6 | [![build status](https://secure.travis-ci.org/browserify/module-deps.png)](http://travis-ci.org/browserify/module-deps) 7 | 8 | # example 9 | 10 | ``` js 11 | var mdeps = require('module-deps'); 12 | var JSONStream = require('JSONStream'); 13 | 14 | var md = mdeps(); 15 | md.pipe(JSONStream.stringify()).pipe(process.stdout); 16 | md.end({ file: __dirname + '/files/main.js' }); 17 | ``` 18 | 19 | output: 20 | 21 | ```json 22 | $ node example/deps.js 23 | [ 24 | {"id":"/home/substack/projects/module-deps/example/files/main.js","source":"var foo = require('./foo');\nconsole.log('main: ' + foo(5));\n","entry":true,"deps":{"./foo":"/home/substack/projects/module-deps/example/files/foo.js"}} 25 | , 26 | {"id":"/home/substack/projects/module-deps/example/files/foo.js","source":"var bar = require('./bar');\n\nmodule.exports = function (n) {\n return n * 111 + bar(n);\n};\n","deps":{"./bar":"/home/substack/projects/module-deps/example/files/bar.js"}} 27 | , 28 | {"id":"/home/substack/projects/module-deps/example/files/bar.js","source":"module.exports = function (n) {\n return n * 100;\n};\n","deps":{}} 29 | ] 30 | ``` 31 | 32 | and you can feed this json data into 33 | [browser-pack](https://github.com/browserify/browser-pack): 34 | 35 | ```bash 36 | $ node example/deps.js | browser-pack | node 37 | main: 1055 38 | ``` 39 | 40 | # usage 41 | 42 | ``` 43 | usage: module-deps [files] 44 | 45 | generate json output from each entry file 46 | 47 | ``` 48 | 49 | # methods 50 | 51 | ``` js 52 | var mdeps = require('module-deps') 53 | ``` 54 | 55 | ## var d = mdeps(opts={}) 56 | 57 | Return an object transform stream `d` that expects entry filenames or 58 | `{ id: ..., file: ... }` objects as input and produces objects for every 59 | dependency from a recursive module traversal as output. 60 | 61 | Each file in `files` can be a string filename or a stream. 62 | 63 | Optionally pass in some `opts`: 64 | 65 | * `opts.transform` - a string or array of string transforms (see below) 66 | 67 | * `opts.transformKey` - an array path of strings showing where to look in the 68 | package.json for source transformations. If falsy, don't look at the 69 | package.json at all. 70 | 71 | * `opts.resolve` - custom resolve function using the 72 | `opts.resolve(id, parent, cb)` signature that 73 | [browser-resolve](https://github.com/shtylman/node-browser-resolve) has 74 | 75 | * `opts.detect` - a custom dependency detection function. `opts.detect(source)` 76 | should return an array of dependency module names. By default 77 | [detective](https://github.com/browserify/detective) is used. 78 | 79 | * `opts.filter` - a function (id) to skip resolution of some module `id` strings. 80 | If defined, `opts.filter(id)` should return truthy for all the ids to include 81 | and falsey for all the ids to skip. 82 | 83 | * `opts.postFilter` - a function (id, file, pkg) that gets called after `id` has 84 | been resolved. Return false to skip this file. 85 | 86 | * `opts.packageFilter` - transform the parsed package.json contents before using 87 | the values. `opts.packageFilter(pkg, dir)` should return the new `pkg` object to 88 | use. 89 | 90 | * `opts.noParse` - an array of absolute paths to not parse for dependencies. Use 91 | this for large dependencies like jquery or threejs which take forever to parse. 92 | 93 | * `opts.cache` - an object mapping filenames to file objects to skip costly io 94 | 95 | * `opts.packageCache` - an object mapping filenames to their parent package.json 96 | contents for browser fields, main entries, and transforms 97 | 98 | * `opts.fileCache` - an object mapping filenames to raw source to avoid reading 99 | from disk. 100 | 101 | * `opts.persistentCache` - a complex cache handler that allows async and persistent 102 | caching of data. A `persistentCache` needs to follow this interface: 103 | ```js 104 | function persistentCache ( 105 | file, // the path to the file that is loaded 106 | id, // the id that is used to reference this file 107 | pkg, // the package that this file belongs to fallback 108 | fallback, // async fallback handler to be called if the cache doesn't hold the given file 109 | cb // callback handler that receives the cache data 110 | ) { 111 | if (hasError()) { 112 | return cb(error) // Pass any error to the callback 113 | } 114 | 115 | var fileData = fs.readFileSync(file) 116 | var key = keyFromFile(file, fileData) 117 | 118 | if (db.has(key)) { 119 | return cb(null, { 120 | source: db.get(key).toString(), 121 | package: pkg, // The package for housekeeping 122 | deps: { 123 | 'id': // id that is used to reference a required file 124 | 'file' // file path to the required file 125 | } 126 | }) 127 | } 128 | // 129 | // The fallback will process the file in case the file is not 130 | // in cache. 131 | // 132 | // Note that if your implementation doesn't need the file data 133 | // then you can pass `null` instead of the source and the fallback will 134 | // fetch the data by itself. 135 | // 136 | fallback(fileData, function (error, cacheableEntry) { 137 | if (error) { 138 | return cb(error) 139 | } 140 | db.addToCache(key, cacheableEntry) 141 | cb(null, cacheableEntry) 142 | }) 143 | } 144 | ``` 145 | 146 | * `opts.paths` - array of global paths to search. Defaults to splitting on `':'` 147 | in `process.env.NODE_PATH` 148 | 149 | * `opts.ignoreMissing` - ignore files that failed to resolve 150 | 151 | # input objects 152 | 153 | Input objects should be string filenames or objects with these parameters: 154 | 155 | * `row.file` - filename 156 | * `row.entry` - whether to treat this file as an entry point, defaults to 157 | `true`. Set to `false` to include this file, but not run it automatically. 158 | * `row.expose` - name to be exposed as 159 | * `row.noparse` - when true, don't parse the file contents for dependencies 160 | 161 | or objects can specify transforms: 162 | 163 | * `row.transform` - string name, path, or function 164 | * `row.options` - transform options as an object 165 | * `row.global` - boolean, whether the transform is global 166 | 167 | # output objects 168 | 169 | Output objects describe files with dependencies. They have these properties: 170 | 171 | * `row.id` - an identifier for the file, used in the `row.deps` prperty 172 | * `row.file` - path to the source file 173 | * `row.entry` - true if the file is an entry point 174 | * `row.expose` - name to be exposed as 175 | * `row.source` - source file content as a string 176 | * `row.deps` - object describing dependencies. The keys are strings as used 177 | in `require()` calls in the file, and values are the row IDs (file paths) 178 | of dependencies. 179 | 180 | # events 181 | 182 | ## d.on('transform', function (tr, file) {}) 183 | 184 | Every time a transform is applied to a `file`, a `'transform'` event fires with 185 | the instantiated transform stream `tr`. 186 | 187 | ## d.on('file', function (file) {}) 188 | 189 | Every time a file is read, this event fires with the file path. 190 | 191 | ## d.on('missing', function (id, parent) {}) 192 | 193 | When `opts.ignoreMissing` is enabled, this event fires for each missing package. 194 | 195 | ## d.on('package', function (pkg) {}) 196 | 197 | Every time a package is read, this event fires. The directory name of the 198 | package is available in `pkg.__dirname`. 199 | 200 | # transforms 201 | 202 | module-deps can be configured to run source transformations on files before 203 | parsing them for `require()` calls. These transforms are useful if you want to 204 | compile a language like [coffeescript](http://coffeescript.org/) on the fly or 205 | if you want to load static assets into your bundle by parsing the AST for 206 | `fs.readFileSync()` calls. 207 | 208 | If the transform is a function, it should take the `file` name as an argument 209 | and return a through stream that will be written file contents and should output 210 | the new transformed file contents. 211 | 212 | If the transform is a string, it is treated as a module name that will resolve 213 | to a module that is expected to follow this format: 214 | 215 | ``` js 216 | var through = require('through2'); 217 | module.exports = function (file, opts) { return through() }; 218 | ``` 219 | 220 | You don't necessarily need to use the 221 | [through2](https://github.com/rvagg/through2) module to create a 222 | readable/writable filter stream for transforming file contents, but this is an 223 | easy way to do it. 224 | 225 | module-deps looks for `require()` calls and adds their arguments as dependencies 226 | of a file. Transform streams can emit `'dep'` events to include additional 227 | dependencies that are not consumed with `require()`. 228 | 229 | When you call `mdeps()` with an `opts.transform`, the transformations you 230 | specify will not be run for any files in node_modules/. This is because modules 231 | you include should be self-contained and not need to worry about guarding 232 | themselves against transformations that may happen upstream. 233 | 234 | Modules can apply their own transformations by setting a transformation pipeline 235 | in their package.json at the `opts.transformKey` path. These transformations 236 | only apply to the files directly in the module itself, not to the module's 237 | dependants nor to its dependencies. 238 | 239 | ## package.json transformKey 240 | 241 | Transform keys live at a configurable location in the package.json denoted by 242 | the `opts.transformKey` array. 243 | 244 | For a transformKey of `['foo','bar']`, the transformKey can be a single string 245 | (`"fff"`): 246 | 247 | ``` json 248 | { 249 | "foo": { 250 | "bar": "fff" 251 | } 252 | } 253 | ``` 254 | 255 | or an array of strings (`["fff","ggg"]`): 256 | 257 | ``` json 258 | { 259 | "foo": { 260 | "bar": ["fff","ggg"] 261 | } 262 | } 263 | ``` 264 | 265 | If you want to pass options to the transforms, you can use a 2-element array 266 | inside of the primary array. Here `fff` gets an options object with `{"x":3}` 267 | and `ggg` gets `{"y":4}`: 268 | 269 | ``` json 270 | { 271 | "foo": { 272 | "bar": [["fff",{"x":3}],["ggg",{"y":4}]] 273 | } 274 | } 275 | ``` 276 | 277 | Options sent to the module-deps constructor are also provided under 278 | `opts._flags`. These options are sometimes required if your transform 279 | needs to do something different when browserify is run in debug mode, for 280 | example. 281 | 282 | # usage 283 | 284 | ``` 285 | module-deps [FILES] OPTIONS 286 | 287 | Generate json output for the entry point FILES. 288 | 289 | OPTIONS are: 290 | 291 | -t TRANSFORM Apply a TRANSFORM. 292 | -g TRANSFORM Apply a global TRANSFORM. 293 | 294 | ``` 295 | 296 | # install 297 | 298 | With [npm](http://npmjs.org), to get the module do: 299 | 300 | ``` 301 | npm install module-deps 302 | ``` 303 | 304 | and to get the `module-deps` command do: 305 | 306 | ``` 307 | npm install -g module-deps 308 | ``` 309 | 310 | # license 311 | 312 | MIT 313 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var relativePath = require('cached-path-relative'); 4 | 5 | var browserResolve = require('browser-resolve'); 6 | var nodeResolve = require('resolve'); 7 | var detective = require('detective'); 8 | var through = require('through2'); 9 | var concat = require('concat-stream'); 10 | var parents = require('parents'); 11 | var combine = require('stream-combiner2'); 12 | var duplexer = require('duplexer2'); 13 | var xtend = require('xtend'); 14 | var defined = require('defined'); 15 | 16 | var inherits = require('inherits'); 17 | var Transform = require('readable-stream').Transform; 18 | 19 | module.exports = Deps; 20 | inherits(Deps, Transform); 21 | 22 | function Deps (opts) { 23 | var self = this; 24 | if (!(this instanceof Deps)) return new Deps(opts); 25 | Transform.call(this, { objectMode: true }); 26 | 27 | if (!opts) opts = {}; 28 | 29 | this.basedir = opts.basedir || process.cwd(); 30 | this.persistentCache = opts.persistentCache || function (file, id, pkg, fallback, cb) { 31 | process.nextTick(function () { 32 | fallback(null, cb); 33 | }); 34 | }; 35 | this.cache = opts.cache; 36 | this.fileCache = opts.fileCache; 37 | this.pkgCache = opts.packageCache || {}; 38 | this.pkgFileCache = {}; 39 | this.pkgFileCachePending = {}; 40 | this._emittedPkg = {}; 41 | this._transformDeps = {}; 42 | this.visited = {}; 43 | this.walking = {}; 44 | this.entries = []; 45 | this._input = []; 46 | 47 | this.paths = opts.paths || process.env.NODE_PATH || ''; 48 | if (typeof this.paths === 'string') { 49 | var delimiter = path.delimiter || (process.platform === 'win32' ? ';' : ':'); 50 | this.paths = this.paths.split(delimiter); 51 | } 52 | this.paths = this.paths 53 | .filter(Boolean) 54 | .map(function (p) { 55 | return path.resolve(self.basedir, p); 56 | }); 57 | 58 | this.transforms = [].concat(opts.transform).filter(Boolean); 59 | this.globalTransforms = [].concat(opts.globalTransform).filter(Boolean); 60 | this.resolver = opts.resolve || browserResolve; 61 | this.detective = opts.detect || detective; 62 | this.options = xtend(opts); 63 | if (!this.options.modules) this.options.modules = {}; 64 | 65 | // If the caller passes options.expose, store resolved pathnames for exposed 66 | // modules in it. If not, set it anyway so it's defined later. 67 | if (!this.options.expose) this.options.expose = {}; 68 | this.pending = 0; 69 | this.inputPending = 0; 70 | 71 | var topfile = path.join(this.basedir, '__fake.js'); 72 | this.top = { 73 | id: topfile, 74 | filename: topfile, 75 | paths: this.paths, 76 | basedir: this.basedir 77 | }; 78 | } 79 | 80 | Deps.prototype._isTopLevel = function (file) { 81 | var isTopLevel = this.entries.some(function (main) { 82 | var m = relativePath(path.dirname(main), file); 83 | return m.split(/[\\\/]/).indexOf('node_modules') < 0; 84 | }); 85 | if (!isTopLevel) { 86 | var m = relativePath(this.basedir, file); 87 | isTopLevel = m.split(/[\\\/]/).indexOf('node_modules') < 0; 88 | } 89 | return isTopLevel; 90 | }; 91 | 92 | Deps.prototype._transform = function (row, enc, next) { 93 | var self = this; 94 | if (typeof row === 'string') { 95 | row = { file: row }; 96 | } 97 | if (row.transform && row.global) { 98 | this.globalTransforms.push([ row.transform, row.options ]); 99 | return next(); 100 | } 101 | else if (row.transform) { 102 | this.transforms.push([ row.transform, row.options ]); 103 | return next(); 104 | } 105 | 106 | self.pending ++; 107 | var basedir = defined(row.basedir, self.basedir); 108 | 109 | if (row.entry !== false) { 110 | self.entries.push(path.resolve(basedir, row.file || row.id)); 111 | } 112 | 113 | self.lookupPackage(row.file, function (err, pkg) { 114 | if (err && self.options.ignoreMissing) { 115 | self.emit('missing', row.file, self.top); 116 | self.pending --; 117 | return next(); 118 | } 119 | if (err) return self.emit('error', err) 120 | self.pending --; 121 | self._input.push({ row: row, pkg: pkg }); 122 | next(); 123 | }); 124 | }; 125 | 126 | Deps.prototype._flush = function () { 127 | var self = this; 128 | var files = {}; 129 | self._input.forEach(function (r) { 130 | var w = r.row, f = files[w.file || w.id]; 131 | if (f) { 132 | f.row.entry = f.row.entry || w.entry; 133 | var ex = f.row.expose || w.expose; 134 | f.row.expose = ex; 135 | if (ex && f.row.file === f.row.id && w.file !== w.id) { 136 | f.row.id = w.id; 137 | } 138 | } 139 | else files[w.file || w.id] = r; 140 | }); 141 | 142 | Object.keys(files).forEach(function (key) { 143 | var r = files[key]; 144 | var pkg = r.pkg || {}; 145 | var dir = r.row.file ? path.dirname(r.row.file) : self.basedir; 146 | if (!pkg.__dirname) pkg.__dirname = dir; 147 | self.walk(r.row, xtend(self.top, { 148 | filename: path.join(dir, '_fake.js') 149 | })); 150 | }); 151 | if (this.pending === 0) this.push(null); 152 | this._ended = true; 153 | }; 154 | 155 | Deps.prototype.resolve = function (id, parent, cb) { 156 | var self = this; 157 | var opts = self.options; 158 | 159 | if (xhas(self.cache, parent.id, 'deps', id) 160 | && self.cache[parent.id].deps[id]) { 161 | var file = self.cache[parent.id].deps[id]; 162 | var pkg = self.pkgCache[file]; 163 | if (pkg) return cb(null, file, pkg); 164 | return self.lookupPackage(file, function (err, pkg) { 165 | cb(null, file, pkg); 166 | }); 167 | } 168 | 169 | parent.packageFilter = function (p, x) { 170 | var pkgdir = path.dirname(x); 171 | if (opts.packageFilter) p = opts.packageFilter(p, x); 172 | p.__dirname = pkgdir; 173 | 174 | return p; 175 | }; 176 | 177 | // have `resolve` do all the package.json lookups, 178 | // see discussion in https://github.com/browserify/browser-resolve/issues/93#issuecomment-667837808 179 | parent.package = undefined; 180 | 181 | if (opts.extensions) parent.extensions = opts.extensions; 182 | if (opts.modules) parent.modules = opts.modules; 183 | 184 | self.resolver(id, parent, function onresolve (err, file, pkg, fakePath) { 185 | if (err) return cb(err); 186 | if (!file) return cb(new Error( 187 | 'module not found: "' + id + '" from file ' 188 | + parent.filename 189 | )); 190 | 191 | if (!pkg || !pkg.__dirname) { 192 | self.lookupPackage(file, function (err, p) { 193 | if (err) return cb(err); 194 | if (!p) p = {}; 195 | if (!p.__dirname) p.__dirname = path.dirname(file); 196 | self.pkgCache[file] = p; 197 | onresolve(err, file, opts.packageFilter 198 | ? opts.packageFilter(p, p.__dirname) : p, 199 | fakePath 200 | ); 201 | }); 202 | } 203 | else cb(err, file, pkg, fakePath); 204 | }); 205 | }; 206 | 207 | Deps.prototype.readFile = function (file, id, pkg) { 208 | var self = this; 209 | if (xhas(this.fileCache, file)) { 210 | return toStream(this.fileCache[file]); 211 | } 212 | var rs = fs.createReadStream(file, { 213 | encoding: 'utf8' 214 | }); 215 | return rs; 216 | }; 217 | 218 | Deps.prototype.getTransforms = function (file, pkg, opts) { 219 | if (!opts) opts = {}; 220 | var self = this; 221 | 222 | var isTopLevel; 223 | if (opts.builtin || opts.inNodeModules) isTopLevel = false; 224 | else isTopLevel = this._isTopLevel(file); 225 | 226 | var transforms = [].concat(isTopLevel ? this.transforms : []) 227 | .concat(getTransforms(pkg, { 228 | globalTransform: this.globalTransforms, 229 | transformKey: this.options.transformKey 230 | })) 231 | ; 232 | if (transforms.length === 0) return through(); 233 | 234 | var pending = transforms.length; 235 | var streams = []; 236 | var input = through(); 237 | var output = through(); 238 | var dup = duplexer(input, output); 239 | 240 | for (var i = 0; i < transforms.length; i++) (function (i) { 241 | makeTransform(transforms[i], function (err, trs) { 242 | if (err) { 243 | return dup.emit('error', err); 244 | } 245 | streams[i] = trs; 246 | if (-- pending === 0) done(); 247 | }); 248 | })(i); 249 | return dup; 250 | 251 | function done () { 252 | var middle = combine.apply(null, streams); 253 | middle.on('error', function (err) { 254 | err.message += ' while parsing file: ' + file; 255 | if (!err.filename) err.filename = file; 256 | dup.emit('error', err); 257 | }); 258 | input.pipe(middle).pipe(output); 259 | } 260 | 261 | function makeTransform (tr, cb) { 262 | var trOpts = {}; 263 | if (Array.isArray(tr)) { 264 | trOpts = tr[1] || {}; 265 | tr = tr[0]; 266 | } 267 | trOpts._flags = trOpts.hasOwnProperty('_flags') ? trOpts._flags : self.options; 268 | if (typeof tr === 'function') { 269 | var t = tr(file, trOpts); 270 | // allow transforms to `stream.emit('dep', path)` to add dependencies for this file 271 | t.on('dep', function (dep) { 272 | if (!self._transformDeps[file]) self._transformDeps[file] = []; 273 | self._transformDeps[file].push(dep); 274 | }); 275 | self.emit('transform', t, file); 276 | nextTick(cb, null, wrapTransform(t)); 277 | } 278 | else { 279 | loadTransform(tr, trOpts, function (err, trs) { 280 | if (err) return cb(err); 281 | cb(null, wrapTransform(trs)); 282 | }); 283 | } 284 | } 285 | 286 | function loadTransform (id, trOpts, cb) { 287 | var params = { 288 | basedir: path.dirname(file), 289 | preserveSymlinks: false 290 | }; 291 | nodeResolve(id, params, function nr (err, res, again) { 292 | if (err && again) return cb && cb(err); 293 | 294 | if (err) { 295 | params.basedir = pkg.__dirname; 296 | return nodeResolve(id, params, function (e, r) { 297 | nr(e, r, true); 298 | }); 299 | } 300 | 301 | if (!res) return cb(new Error( 302 | 'cannot find transform module ' + tr 303 | + ' while transforming ' + file 304 | )); 305 | 306 | var r = require(res); 307 | if (typeof r !== 'function') { 308 | return cb(new Error( 309 | 'Unexpected ' + typeof r + ' exported by the ' 310 | + JSON.stringify(res) + ' package. ' 311 | + 'Expected a transform function.' 312 | )); 313 | } 314 | 315 | var trs = r(file, trOpts); 316 | // allow transforms to `stream.emit('dep', path)` to add dependencies for this file 317 | trs.on('dep', function (dep) { 318 | if (!self._transformDeps[file]) self._transformDeps[file] = []; 319 | self._transformDeps[file].push(dep); 320 | }); 321 | self.emit('transform', trs, file); 322 | cb(null, trs); 323 | }); 324 | } 325 | }; 326 | 327 | Deps.prototype.walk = function (id, parent, cb) { 328 | var self = this; 329 | var opts = self.options; 330 | this.pending ++; 331 | 332 | var rec = {}; 333 | var input; 334 | if (typeof id === 'object') { 335 | rec = xtend(id); 336 | if (rec.entry === false) delete rec.entry; 337 | id = rec.file || rec.id; 338 | input = true; 339 | this.inputPending ++; 340 | } 341 | 342 | self.resolve(id, parent, function (err, file, pkg, fakePath) { 343 | // this is checked early because parent.modules is also modified 344 | // by this function. 345 | var builtin = has(parent.modules, id); 346 | 347 | if (rec.expose) { 348 | // Set options.expose to make the resolved pathname available to the 349 | // caller. They may or may not have requested it, but it's harmless 350 | // to set this if they didn't. 351 | self.options.expose[rec.expose] = 352 | self.options.modules[rec.expose] = file; 353 | } 354 | if (pkg && !self._emittedPkg[pkg.__dirname]) { 355 | self._emittedPkg[pkg.__dirname] = true; 356 | self.emit('package', pkg); 357 | } 358 | 359 | if (opts.postFilter && !opts.postFilter(id, file, pkg)) { 360 | if (--self.pending === 0) self.push(null); 361 | if (input) --self.inputPending; 362 | return cb && cb(null, undefined); 363 | } 364 | if (err && rec.source) { 365 | file = rec.file; 366 | 367 | var ts = self.getTransforms(file, pkg); 368 | ts.on('error', function (err) { 369 | self.emit('error', err); 370 | }); 371 | ts.pipe(concat(function (body) { 372 | rec.source = body.toString('utf8'); 373 | fromSource(file, rec.source, pkg); 374 | })); 375 | return ts.end(rec.source); 376 | } 377 | if (err && self.options.ignoreMissing) { 378 | if (--self.pending === 0) self.push(null); 379 | if (input) --self.inputPending; 380 | self.emit('missing', id, parent); 381 | return cb && cb(null, undefined); 382 | } 383 | if (err) { 384 | var message = 'Can\'t walk dependency graph: ' + err.message; 385 | message += '\n required by ' + parent.filename; 386 | err.message = message; 387 | return self.emit('error', err); 388 | } 389 | if (self.visited[file]) { 390 | if (-- self.pending === 0) self.push(null); 391 | if (input) --self.inputPending; 392 | return cb && cb(null, file); 393 | } 394 | self.visited[file] = true; 395 | 396 | if (rec.source) { 397 | var ts = self.getTransforms(file, pkg); 398 | ts.on('error', function (err) { 399 | self.emit('error', err); 400 | }); 401 | ts.pipe(concat(function (body) { 402 | rec.source = body.toString('utf8'); 403 | fromSource(file, rec.source, pkg); 404 | })); 405 | return ts.end(rec.source); 406 | } 407 | 408 | var c = self.cache && self.cache[file]; 409 | if (c) return fromDeps(file, c.source, c.package, fakePath, Object.keys(c.deps)); 410 | 411 | self.persistentCache(file, id, pkg, persistentCacheFallback, function (err, c) { 412 | self.emit('file', file, id); 413 | if (err) { 414 | self.emit('error', err); 415 | return; 416 | } 417 | fromDeps(file, c.source, c.package, fakePath, Object.keys(c.deps)); 418 | }); 419 | 420 | function persistentCacheFallback (dataAsString, cb) { 421 | var stream = dataAsString ? toStream(dataAsString) : self.readFile(file, id, pkg).on('error', cb); 422 | stream 423 | .pipe(self.getTransforms(fakePath || file, pkg, { 424 | builtin: builtin, 425 | inNodeModules: parent.inNodeModules 426 | })) 427 | .on('error', cb) 428 | .pipe(concat(function (body) { 429 | var src = body.toString('utf8'); 430 | try { var deps = getDeps(file, src); } 431 | catch (err) { cb(err); } 432 | if (deps) { 433 | cb(null, { 434 | source: src, 435 | package: pkg, 436 | deps: deps.reduce(function (deps, dep) { 437 | deps[dep] = true; 438 | return deps; 439 | }, {}) 440 | }); 441 | } 442 | })); 443 | } 444 | }); 445 | 446 | function getDeps (file, src) { 447 | var deps = rec.noparse ? [] : self.parseDeps(file, src); 448 | // dependencies emitted by transforms 449 | if (self._transformDeps[file]) deps = deps.concat(self._transformDeps[file]); 450 | return deps; 451 | } 452 | 453 | function fromSource (file, src, pkg, fakePath) { 454 | var deps = getDeps(file, src); 455 | if (deps) fromDeps(file, src, pkg, fakePath, deps); 456 | } 457 | 458 | function fromDeps (file, src, pkg, fakePath, deps) { 459 | var p = deps.length; 460 | var resolved = {}; 461 | 462 | if (input) --self.inputPending; 463 | 464 | (function resolve () { 465 | if (self.inputPending > 0) return setTimeout(resolve); 466 | deps.forEach(function (id) { 467 | if (opts.filter && !opts.filter(id)) { 468 | resolved[id] = false; 469 | if (--p === 0) done(); 470 | return; 471 | } 472 | var isTopLevel = self._isTopLevel(fakePath || file); 473 | var current = { 474 | id: file, 475 | filename: file, 476 | basedir: path.dirname(file), 477 | paths: self.paths, 478 | package: pkg, 479 | inNodeModules: parent.inNodeModules || !isTopLevel 480 | }; 481 | self.walk(id, current, function (err, r) { 482 | resolved[id] = r; 483 | if (--p === 0) done(); 484 | }); 485 | }); 486 | if (deps.length === 0) done(); 487 | })(); 488 | 489 | function done () { 490 | if (!rec.id) rec.id = file; 491 | if (!rec.source) rec.source = src; 492 | if (!rec.deps) rec.deps = resolved; 493 | if (!rec.file) rec.file = file; 494 | 495 | if (self.entries.indexOf(file) >= 0) { 496 | rec.entry = true; 497 | } 498 | self.push(rec); 499 | 500 | if (cb) cb(null, file); 501 | if (-- self.pending === 0) self.push(null); 502 | } 503 | } 504 | }; 505 | 506 | Deps.prototype.parseDeps = function (file, src, cb) { 507 | var self = this; 508 | if (this.options.noParse === true) return []; 509 | if (/\.json$/.test(file)) return []; 510 | 511 | if (Array.isArray(this.options.noParse) 512 | && this.options.noParse.indexOf(file) >= 0) { 513 | return []; 514 | } 515 | 516 | try { var deps = self.detective(src) } 517 | catch (ex) { 518 | var message = ex && ex.message ? ex.message : ex; 519 | throw new Error( 520 | 'Parsing file ' + file + ': ' + message 521 | ); 522 | } 523 | return deps; 524 | }; 525 | 526 | Deps.prototype.lookupPackage = function (file, cb) { 527 | var self = this; 528 | 529 | var cached = this.pkgCache[file]; 530 | if (cached) return nextTick(cb, null, cached); 531 | if (cached === false) return nextTick(cb, null, undefined); 532 | 533 | var dirs = parents(file ? path.dirname(file) : self.basedir); 534 | 535 | (function next () { 536 | if (dirs.length === 0) { 537 | self.pkgCache[file] = false; 538 | return cb(null, undefined); 539 | } 540 | var dir = dirs.shift(); 541 | if (dir.split(/[\\\/]/).slice(-1)[0] === 'node_modules') { 542 | return cb(null, undefined); 543 | } 544 | 545 | var pkgfile = path.join(dir, 'package.json'); 546 | 547 | var cached = self.pkgCache[pkgfile]; 548 | if (cached) return nextTick(cb, null, cached); 549 | else if (cached === false) return next(); 550 | 551 | var pcached = self.pkgFileCachePending[pkgfile]; 552 | if (pcached) return pcached.push(onpkg); 553 | pcached = self.pkgFileCachePending[pkgfile] = []; 554 | 555 | fs.readFile(pkgfile, function (err, src) { 556 | if (err) return onpkg(); 557 | try { var pkg = JSON.parse(src) } 558 | catch (err) { 559 | return onpkg(new Error([ 560 | err + ' while parsing json file ' + pkgfile 561 | ].join(''))); 562 | } 563 | pkg.__dirname = dir; 564 | 565 | self.pkgCache[pkgfile] = pkg; 566 | self.pkgCache[file] = pkg; 567 | onpkg(null, pkg); 568 | }); 569 | 570 | function onpkg (err, pkg) { 571 | if (self.pkgFileCachePending[pkgfile]) { 572 | var fns = self.pkgFileCachePending[pkgfile]; 573 | delete self.pkgFileCachePending[pkgfile]; 574 | fns.forEach(function (f) { f(err, pkg) }); 575 | } 576 | if (err) cb(err); 577 | else if (pkg && typeof pkg === 'object') cb(null, pkg); 578 | else { 579 | self.pkgCache[pkgfile] = false; 580 | next(); 581 | } 582 | } 583 | })(); 584 | }; 585 | 586 | function getTransforms (pkg, opts) { 587 | var trx = []; 588 | if (opts.transformKey) { 589 | var n = pkg; 590 | var keys = opts.transformKey; 591 | for (var i = 0; i < keys.length; i++) { 592 | if (n && typeof n === 'object') n = n[keys[i]]; 593 | else break; 594 | } 595 | if (i === keys.length) { 596 | trx = [].concat(n).filter(Boolean); 597 | } 598 | } 599 | return trx.concat(opts.globalTransform || []); 600 | } 601 | 602 | function nextTick (cb) { 603 | var args = [].slice.call(arguments, 1); 604 | process.nextTick(function () { cb.apply(null, args) }); 605 | } 606 | 607 | function xhas (obj) { 608 | if (!obj) return false; 609 | for (var i = 1; i < arguments.length; i++) { 610 | var key = arguments[i]; 611 | if (!has(obj, key)) return false; 612 | obj = obj[key]; 613 | } 614 | return true; 615 | } 616 | 617 | function toStream (dataAsString) { 618 | var tr = through(); 619 | tr.push(dataAsString); 620 | tr.push(null); 621 | return tr; 622 | } 623 | 624 | function has (obj, key) { 625 | return obj && Object.prototype.hasOwnProperty.call(obj, key); 626 | } 627 | 628 | function wrapTransform (tr) { 629 | if (typeof tr.read === 'function') return tr; 630 | var input = through(), output = through(); 631 | input.pipe(tr).pipe(output); 632 | var wrapper = duplexer(input, output); 633 | tr.on('error', function (err) { wrapper.emit('error', err) }); 634 | return wrapper; 635 | } 636 | --------------------------------------------------------------------------------