diff --git a/lib/async.js b/lib/async.js index cf8c24b5..40227a1f 100644 --- a/lib/async.js +++ b/lib/async.js @@ -36,6 +36,14 @@ var maybeUnwrapSymlink = function maybeUnwrapSymlink(x, opts, cb) { } }; +var getPackageCandidates = function getPackageCandidates(x, start, opts) { + var dirs = nodeModulesPaths(start, opts, x); + for (var i = 0; i < dirs.length; i++) { + dirs[i] = path.join(dirs[i], x); + } + return dirs; +}; + module.exports = function resolve(x, options, callback) { var cb = callback; var opts = options; @@ -55,6 +63,7 @@ module.exports = function resolve(x, options, callback) { var isFile = opts.isFile || defaultIsFile; var isDirectory = opts.isDirectory || defaultIsDir; var readFile = opts.readFile || fs.readFile; + var packageIterator = opts.packageIterator; var extensions = opts.extensions || ['.js']; var basedir = opts.basedir || path.dirname(caller()); @@ -265,19 +274,18 @@ module.exports = function resolve(x, options, callback) { if (dirs.length === 0) return cb(null, undefined); var dir = dirs[0]; - isDirectory(dir, isdir); + isDirectory(path.dirname(dir), isdir); function isdir(err, isdir) { if (err) return cb(err); if (!isdir) return processDirs(cb, dirs.slice(1)); - var file = path.join(dir, x); - loadAsFile(file, opts.package, onfile); + loadAsFile(dir, opts.package, onfile); } function onfile(err, m, pkg) { if (err) return cb(err); if (m) return cb(null, m, pkg); - loadAsDirectory(path.join(dir, x), opts.package, ondir); + loadAsDirectory(dir, opts.package, ondir); } function ondir(err, n, pkg) { @@ -287,6 +295,10 @@ module.exports = function resolve(x, options, callback) { } } function loadNodeModules(x, start, cb) { - processDirs(cb, nodeModulesPaths(start, opts, x)); + var thunk = function () { return getPackageCandidates(x, start, opts); }; + processDirs( + cb, + packageIterator ? packageIterator(x, start, thunk, opts) : thunk() + ); } }; diff --git a/lib/sync.js b/lib/sync.js index 79633997..cc0ec56c 100644 --- a/lib/sync.js +++ b/lib/sync.js @@ -38,6 +38,14 @@ var maybeUnwrapSymlink = function maybeUnwrapSymlink(x, opts) { return x; }; +var getPackageCandidates = function getPackageCandidates(x, start, opts) { + var dirs = nodeModulesPaths(start, opts, x); + for (var i = 0; i < dirs.length; i++) { + dirs[i] = path.join(dirs[i], x); + } + return dirs; +}; + module.exports = function (x, options) { if (typeof x !== 'string') { throw new TypeError('Path must be a string.'); @@ -47,6 +55,7 @@ module.exports = function (x, options) { var isFile = opts.isFile || defaultIsFile; var isDirectory = opts.isDirectory || defaultIsDir; var readFileSync = opts.readFileSync || fs.readFileSync; + var packageIterator = opts.packageIterator; var extensions = opts.extensions || ['.js']; var basedir = opts.basedir || path.dirname(caller()); @@ -162,13 +171,15 @@ module.exports = function (x, options) { } function loadNodeModulesSync(x, start) { - var dirs = nodeModulesPaths(start, opts, x); + var thunk = function () { return getPackageCandidates(x, start, opts); }; + var dirs = packageIterator ? packageIterator(x, start, thunk, opts) : thunk(); + for (var i = 0; i < dirs.length; i++) { var dir = dirs[i]; - if (isDirectory(dir)) { - var m = loadAsFileSync(path.join(dir, '/', x)); + if (isDirectory(path.dirname(dir))) { + var m = loadAsFileSync(dir); if (m) return m; - var n = loadAsDirectorySync(path.join(dir, '/', x)); + var n = loadAsDirectorySync(dir); if (n) return n; } } diff --git a/readme.markdown b/readme.markdown index 64778cc9..cdea6778 100644 --- a/readme.markdown +++ b/readme.markdown @@ -80,6 +80,12 @@ options are: * getNodeModulesDirs - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution * opts - the resolution options +* `opts.packageIterator(request, start, opts)` - return the list of candidate paths where the packages sources may be found (probably don't use this) + * request - the import specifier being resolved + * start - lookup path + * getPackageCandidates - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution + * opts - the resolution options + * opts.moduleDirectory - directory (or directories) in which to recursively look for modules. default: `"node_modules"` * opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving. @@ -146,6 +152,18 @@ options are: * opts.paths - require.paths array to use if nothing is found on the normal `node_modules` recursive walk (probably don't use this) + For advanced users, `paths` can also be a `opts.paths(request, start, opts)` function + * request - the import specifier being resolved + * start - lookup path + * getNodeModulesDirs - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution + * opts - the resolution options + +* `opts.packageIterator(request, start, opts)` - return the list of candidate paths where the packages sources may be found (probably don't use this) + * request - the import specifier being resolved + * start - lookup path + * getPackageCandidates - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution + * opts - the resolution options + * opts.moduleDirectory - directory (or directories) in which to recursively look for modules. default: `"node_modules"` * opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving. diff --git a/test/resolver.js b/test/resolver.js index 521eacc0..5df8e1d0 100644 --- a/test/resolver.js +++ b/test/resolver.js @@ -256,6 +256,22 @@ test('other path', function (t) { }); }); +test('path iterator', function (t) { + t.plan(2); + + var resolverDir = path.join(__dirname, 'resolver'); + + var exactIterator = function (x, start, getPackageCandidates, opts) { + return [path.join(resolverDir, x)]; + }; + + resolve('baz', { packageIterator: exactIterator }, function (err, res, pkg) { + if (err) t.fail(err); + t.equal(res, path.join(resolverDir, 'baz/quux.js')); + t.equal(pkg && pkg.name, 'baz'); + }); +}); + test('incorrect main', function (t) { t.plan(1); diff --git a/test/resolver/baz/package.json b/test/resolver/baz/package.json index c41e4dbf..2f77720b 100644 --- a/test/resolver/baz/package.json +++ b/test/resolver/baz/package.json @@ -1,3 +1,4 @@ { + "name": "baz", "main": "quux.js" } diff --git a/test/resolver_sync.js b/test/resolver_sync.js index 65ea5dce..aa8e2568 100644 --- a/test/resolver_sync.js +++ b/test/resolver_sync.js @@ -172,6 +172,21 @@ test('other path', function (t) { t.end(); }); +test('path iterator', function (t) { + var resolverDir = path.join(__dirname, 'resolver'); + + var exactIterator = function (x, start, getPackageCandidates, opts) { + return [path.join(resolverDir, x)]; + }; + + t.equal( + resolve.sync('baz', { packageIterator: exactIterator }), + path.join(resolverDir, 'baz/quux.js') + ); + + t.end(); +}); + test('incorrect main', function (t) { var resolverDir = path.join(__dirname, 'resolver'); var dir = path.join(resolverDir, 'incorrect_main');