diff --git a/lib/async.js b/lib/async.js index 83b2c6c4..c2d1120c 100644 --- a/lib/async.js +++ b/lib/async.js @@ -3,6 +3,7 @@ var fs = require('fs'); var path = require('path'); var caller = require('./caller.js'); var nodeModulesPaths = require('./node-modules-paths.js'); +var packagePathAndRemainder = require('./package-path-and-remainder.js'); module.exports = function resolve (x, opts, cb) { if (typeof opts === 'function') { @@ -51,21 +52,58 @@ module.exports = function resolve (x, opts, cb) { }); function loadAsFile (x, pkg, cb) { + if (typeof pkg === 'function') { cb = pkg; pkg = opts.package; } - - (function load (exts) { + + var pathAndRemainder = packagePathAndRemainder(x); + var exts = [''].concat(extensions); + + if(pathAndRemainder) { + var pkgfile = path.join(pathAndRemainder.path, 'package.json'); + var remainder = pathAndRemainder.remainder; + + isFile(pkgfile, function (err, ex) { + if (err) return cb(err); + if (!ex) return load(exts, x); + + readFile(pkgfile, function (err, body) { + if (err) return cb(err); + try { + pkg = JSON.parse(body); + } + catch (err) {} + + if (opts.packageFilter) { + pkg = opts.packageFilter(pkg, x); + } + if (opts.pathFilter && remainder) { + var newRemainder = opts.pathFilter(pkg, x, remainder); + if(newRemainder) { + return load(exts, path.resolve(pathAndRemainder.path, newRemainder)); + } + } + return load(exts, x); + }); + }); + } else { + return load(exts, x); + } + + + function load (exts, x) { if (exts.length === 0) return cb(null, undefined, pkg); var file = x + exts[0]; isFile(file, function (err, ex) { if (err) cb(err) else if (ex) cb(null, file, pkg) - else load(exts.slice(1)) + else load(exts.slice(1), x) }); - })([''].concat(extensions)); + } + } function loadAsDirectory (x, fpkg, cb) { diff --git a/lib/package-path-and-remainder.js b/lib/package-path-and-remainder.js new file mode 100644 index 00000000..86baf6e6 --- /dev/null +++ b/lib/package-path-and-remainder.js @@ -0,0 +1,18 @@ +var path = require('path'); + +module.exports = function packagePathAndRemainder(x) { + var nmStr = "node_modules"; + var splitRe = process.platform === 'win32' ? /[\/\\]/ : /\/+/; + var lastNodeModules = x.lastIndexOf(nmStr); + if(lastNodeModules !== -1) { + var afterNodeModules = x.substr(lastNodeModules+nmStr.length+1); + var parts = afterNodeModules.split(splitRe), + packageName = parts.shift(); + return { + path: path.join(x.substr(0, lastNodeModules+nmStr.length),packageName), + remainder: parts.length ? path.join.apply(path, parts) : null + }; + } else { + return null; + } +}; diff --git a/test/resolver.js b/test/resolver.js index 1301e55a..b8a4e679 100644 --- a/test/resolver.js +++ b/test/resolver.js @@ -279,3 +279,29 @@ test('#25: node modules with the same name as node stdlib modules', function (t) t.equal(res, resolverDir + '/node_modules/punycode/index.js'); }); }); + +test('#62: deep module references and the pathFilter', function(t){ + t.plan(6); + + var resolverDir = __dirname + '/resolver/deep_ref'; + var pathFilter = function(pkg, x, remainder){ + t.equal(pkg.version, "1.2.3"); + t.equal(x, resolverDir + '/node_modules/deep/ref'); + t.equal(remainder, "ref"); + return "alt"; + }; + + + resolve('deep/ref', { basedir : resolverDir }, function (err, res, pkg) { + if (err) t.fail(err); + t.equal(pkg.version, "1.2.3"); + t.equal(res, resolverDir + '/node_modules/deep/ref.js'); + }); + + resolve('deep/ref', { basedir : resolverDir, pathFilter : pathFilter }, function (err, res, pkg) { + if (err) t.fail(err); + t.equal(res, resolverDir + '/node_modules/deep/alt.js'); + }); + + +}); diff --git a/test/resolver/deep_ref/main.js b/test/resolver/deep_ref/main.js new file mode 100644 index 00000000..e69de29b diff --git a/test/resolver/deep_ref/node_modules/deep/alt.js b/test/resolver/deep_ref/node_modules/deep/alt.js new file mode 100644 index 00000000..e69de29b diff --git a/test/resolver/deep_ref/node_modules/deep/package.json b/test/resolver/deep_ref/node_modules/deep/package.json new file mode 100644 index 00000000..fe4b408a --- /dev/null +++ b/test/resolver/deep_ref/node_modules/deep/package.json @@ -0,0 +1,4 @@ +{ + "name": "deep", + "version": "1.2.3" +} diff --git a/test/resolver/deep_ref/node_modules/deep/ref.js b/test/resolver/deep_ref/node_modules/deep/ref.js new file mode 100644 index 00000000..e69de29b