diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index f2c737bddd8c68..a9991fc3da310a 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -2439,6 +2439,19 @@ The `_channel` property of child process objects returned by `spawn()` and similar functions is not intended for public use. Use `ChildProcess.channel` instead. + +### DEP00XX: Module.createRequireFromPath() + + +Type: Documentation-only + +Module.createRequireFromPath() is deprecated. Please use [`module.createRequire()`][] instead. + [`--pending-deprecation`]: cli.html#cli_pending_deprecation [`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size [`Buffer.from(array)`]: buffer.html#buffer_class_method_buffer_from_array @@ -2486,6 +2499,7 @@ instead. [`http.request()`]: http.html#http_http_request_options_callback [`https.get()`]: https.html#https_https_get_options_callback [`https.request()`]: https.html#https_https_request_options_callback +[`module.createRequire()`]: modules.html#modules_module_createrequire_filename [`os.networkInterfaces()`]: os.html#os_os_networkinterfaces [`os.tmpdir()`]: os.html#os_os_tmpdir [`process.env`]: process.html#process_process_env diff --git a/doc/api/modules.md b/doc/api/modules.md index 8638b137ade732..4acead178e4093 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -905,15 +905,36 @@ by the [module wrapper][]. To access it, require the `Module` module: const builtin = require('module').builtinModules; ``` +### module.createRequire(filename) + + +* `filename` {string|URL} Filename to be used to construct the require + function. Must be a file URL object, file URL string, or absolute path + string. +* Returns: {require} Require function + +```js +const { createRequire } = require('module'); +const requireUtil = createRequire(require.resolve('../src/utils/')); + +// Require `../src/utils/some-tool` +requireUtil('./some-tool'); +``` + ### module.createRequireFromPath(filename) * `filename` {string} Filename to be used to construct the relative require function. * Returns: {require} Require function +> Stability: 0 - Deprecated: Please use [`createRequire()`][] instead. + ```js const { createRequireFromPath } = require('module'); const requireUtil = createRequireFromPath('../src/utils/'); @@ -926,6 +947,7 @@ requireUtil('./some-tool'); [`Error`]: errors.html#errors_class_error [`__dirname`]: #modules_dirname [`__filename`]: #modules_filename +[`createRequire()`]: #modules_module_createrequire_filename [`module` object]: #modules_the_module_object [`path.dirname()`]: path.html#path_path_dirname_path [exports shortcut]: #modules_exports_shortcut diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 5df34cb3f022b4..ff1128e903dc2e 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -24,7 +24,7 @@ const { JSON, Object, Reflect } = primordials; const { NativeModule } = require('internal/bootstrap/loaders'); -const { pathToFileURL } = require('internal/url'); +const { pathToFileURL, fileURLToPath, URL } = require('internal/url'); const { deprecate } = require('internal/util'); const vm = require('vm'); const assert = require('internal/assert'); @@ -824,7 +824,7 @@ Module.runMain = function() { Module._load(process.argv[1], null, true); }; -Module.createRequireFromPath = (filename) => { +function createRequireFromPath(filename) { // Allow a directory to be passed as the filename const trailingSlash = filename.endsWith(path.sep) || path.sep !== '/' && filename.endsWith('\\'); @@ -838,7 +838,34 @@ Module.createRequireFromPath = (filename) => { m.paths = Module._nodeModulePaths(m.path); return makeRequireFunction(m); -}; +} + +Module.createRequireFromPath = createRequireFromPath; + +const createRequireError = 'must be a file URL object, file URL string, or' + + 'absolute path string'; + +function createRequire(filename) { + let filepath; + if (typeof filename === 'object' && !(filename instanceof URL)) { + throw new ERR_INVALID_ARG_VALUE('filename', filename, createRequireError); + } else if (typeof filename === 'object' || + typeof filename === 'string' && !path.isAbsolute(filename)) { + try { + filepath = fileURLToPath(filename); + } catch { + throw new ERR_INVALID_ARG_VALUE('filename', filename, + createRequireError); + } + } else if (typeof filename !== 'string') { + throw new ERR_INVALID_ARG_VALUE('filename', filename, createRequireError); + } else { + filepath = filename; + } + return createRequireFromPath(filepath); +} + +Module.createRequire = createRequire; Module._initPaths = function() { var homeDir; diff --git a/test/parallel/test-module-create-require.js b/test/parallel/test-module-create-require.js index 03ed31939fba67..fa25b87f95921b 100644 --- a/test/parallel/test-module-create-require.js +++ b/test/parallel/test-module-create-require.js @@ -4,9 +4,31 @@ require('../common'); const assert = require('assert'); const path = require('path'); -const { createRequireFromPath } = require('module'); +const { createRequire, createRequireFromPath } = require('module'); const p = path.resolve(__dirname, '..', 'fixtures', 'fake.js'); +const u = new URL(`file://${p}`); const req = createRequireFromPath(p); assert.strictEqual(req('./baz'), 'perhaps I work'); + +const reqToo = createRequire(u); +assert.deepStrictEqual(reqToo('./experimental'), { ofLife: 42 }); + +assert.throws(() => { + createRequire('https://github.com/nodejs/node/pull/27405/'); +}, { + code: 'ERR_INVALID_ARG_VALUE' +}); + +assert.throws(() => { + createRequire('../'); +}, { + code: 'ERR_INVALID_ARG_VALUE' +}); + +assert.throws(() => { + createRequire({}); +}, { + code: 'ERR_INVALID_ARG_VALUE' +});