module: support custom paths to require.resolve()

This commit allows custom lookup paths to be passed to
require.resolve(). It also adds require.resolve.paths()
which retrieves the default resolution paths.

Fixes: https://github.com/nodejs/node/issues/5963
Fixes: https://github.com/nodejs/node/issues/16389
PR-URL: https://github.com/nodejs/node/pull/16397
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Wyatt Preul <wpreul@gmail.com>
Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
This commit is contained in:
cjihrig 2016-04-25 12:19:28 -04:00
parent 4997894390
commit 9c6f6b0633
No known key found for this signature in database
GPG Key ID: 7434390BDBE9B9C5
6 changed files with 111 additions and 7 deletions

View File

@ -598,14 +598,36 @@ filename scales linearly with the number of registered extensions.
In other words, adding extensions slows down the module loader and
should be discouraged.
#### require.resolve()
#### require.resolve(request[, options])
<!-- YAML
added: v0.3.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/16397
description: The `paths` option is now supported.
-->
* `request` {string} The module path to resolve.
* `options` {Object}
* `paths` {Array} Paths to resolve module location from. If present, these
paths are used instead of the default resolution paths. Note that each of
these paths is used as a starting point for the module resolution algorithm,
meaning that the `node_modules` hierarchy is checked from this location.
* Returns: {string}
Use the internal `require()` machinery to look up the location of a module,
but rather than loading the module, just return the resolved filename.
#### require.resolve.paths(request)
<!-- YAML
added: REPLACEME
-->
* `request` {string} The module path whose lookup paths are being retrieved.
* Returns: {Array}
Returns an array containing the paths searched during resolution of `request`.
## The `module` Object
<!-- YAML
added: v0.1.16

View File

@ -1899,7 +1899,7 @@ cases:
[`promise.catch()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
[`require()`]: globals.html#globals_require
[`require.main`]: modules.html#modules_accessing_the_main_module
[`require.resolve()`]: modules.html#modules_require_resolve
[`require.resolve()`]: modules.html#modules_require_resolve_request_options
[`setTimeout(fn, 0)`]: timers.html#timers_settimeout_callback_delay_args
[Child Process]: child_process.html
[Cluster]: cluster.html

View File

@ -14,12 +14,18 @@ function makeRequireFunction(mod) {
}
}
function resolve(request) {
return Module._resolveFilename(request, mod);
function resolve(request, options) {
return Module._resolveFilename(request, mod, false, options);
}
require.resolve = resolve;
function paths(request) {
return Module._resolveLookupPaths(request, mod, true);
}
resolve.paths = paths;
require.main = process.mainModule;
// Enable support to add extra extension types.

View File

@ -484,12 +484,32 @@ function tryModuleLoad(module, filename) {
}
}
Module._resolveFilename = function(request, parent, isMain) {
Module._resolveFilename = function(request, parent, isMain, options) {
if (NativeModule.nonInternalExists(request)) {
return request;
}
var paths = Module._resolveLookupPaths(request, parent, true);
var paths;
if (typeof options === 'object' && options !== null &&
Array.isArray(options.paths)) {
paths = [];
for (var i = 0; i < options.paths.length; i++) {
const path = options.paths[i];
const lookupPaths = Module._resolveLookupPaths(path, parent, true);
if (!paths.includes(path))
paths.push(path);
for (var j = 0; j < lookupPaths.length; j++) {
if (!paths.includes(lookupPaths[j]))
paths.push(lookupPaths[j]);
}
}
} else {
paths = Module._resolveLookupPaths(request, parent, true);
}
// look up the filename first, since that's the cache key.
var filename = Module._findPath(request, paths, isMain);

55
test/fixtures/require-resolve.js vendored Normal file
View File

@ -0,0 +1,55 @@
'use strict';
require('../common');
const assert = require('assert');
const path = require('path');
const nodeModules = path.join(__dirname, 'node_modules');
const nestedNodeModules = path.join(__dirname, 'node_modules', 'node_modules');
const nestedIndex = path.join(__dirname, 'nested-index');
// Test the default behavior.
assert.strictEqual(
require.resolve('bar'),
path.join(nodeModules, 'bar.js')
);
// Verify that existing paths are removed.
assert.throws(() => {
require.resolve('bar', { paths: [] })
}, /^Error: Cannot find module 'bar'$/);
// Verify that resolution path can be overwritten.
{
// three.js cannot be loaded from this file by default.
assert.throws(() => {
require.resolve('three')
}, /^Error: Cannot find module 'three'$/);
// However, it can be found if resolution contains the nested index directory.
assert.strictEqual(
require.resolve('three', { paths: [nestedIndex] }),
path.join(nestedIndex, 'three.js')
);
// Resolution from nested index directory also checks node_modules.
assert.strictEqual(
require.resolve('bar', { paths: [nestedIndex] }),
path.join(nodeModules, 'bar.js')
);
}
// Verify that the default paths can be used and modified.
{
const paths = require.resolve.paths('bar');
assert.strictEqual(paths[0], nodeModules);
assert.strictEqual(
require.resolve('bar', { paths }),
path.join(nodeModules, 'bar.js')
);
paths.unshift(nestedNodeModules);
assert.strictEqual(
require.resolve('bar', { paths }),
path.join(nestedNodeModules, 'bar.js')
);
}

View File

@ -35,4 +35,5 @@ assert.strictEqual(
require.resolve(fixtures.path('nested-index', 'one').toLowerCase()));
assert.strictEqual('path', require.resolve('path'));
console.log('ok');
// Test configurable resolve() paths.
require(fixtures.path('require-resolve.js'));