diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index 879de1bc80a31d..bfc0ae52040ae0 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -175,15 +175,31 @@ const { } = internalBinding('native_module'); NativeModule._source = source; -NativeModule._cache = {}; +NativeModule._cache = Object.create(null); const config = internalBinding('config'); +const nonInternal = Object.create(null); // Think of this as module.exports in this file even though it is not // written in CommonJS style. -const loaderExports = { internalBinding, NativeModule }; +const loaderExports = { + internalBinding, + NativeModule, + nonInternal +}; const loaderId = 'internal/bootstrap/loaders'; +const throwNoSuchModule = (id) => { + // Model the error off the internal/errors.js model, but + // do not use that module given that it could actually be + // the one causing the error if there's a bug in Node.js. + // eslint-disable-next-line no-restricted-syntax + const err = new Error(`No such built-in module: ${id}`); + err.code = 'ERR_UNKNOWN_BUILTIN_MODULE'; + err.name = 'Error [ERR_UNKNOWN_BUILTIN_MODULE]'; + throw err; +}; + NativeModule.require = function(id) { if (id === loaderId) { return loaderExports; @@ -195,14 +211,7 @@ NativeModule.require = function(id) { } if (!NativeModule.exists(id)) { - // Model the error off the internal/errors.js model, but - // do not use that module given that it could actually be - // the one causing the error if there's a bug in Node.js. - // eslint-disable-next-line no-restricted-syntax - const err = new Error(`No such built-in module: ${id}`); - err.code = 'ERR_UNKNOWN_BUILTIN_MODULE'; - err.name = 'Error [ERR_UNKNOWN_BUILTIN_MODULE]'; - throw err; + throwNoSuchModule(id); } moduleLoadList.push(`NativeModule ${id}`); @@ -366,5 +375,33 @@ function internalBindingWhitelistHas(name) { return internalBindingWhitelistSet.has(name); } +const builtinModules = Object.keys(NativeModule._source) + .filter(NativeModule.nonInternalExists); + +const nonInternalDict = Object.create(null); +for (const id of builtinModules) { + nonInternalDict[id] = true; +} +Object.freeze(nonInternalDict); +Object.assign(nonInternal, { + ids: builtinModules, + exists: (id) => { + return nonInternalDict[id] === true; + }, + require: (id) => { + if (nonInternal.exists(id)) { + return NativeModule.require(id); + } + throwNoSuchModule(id); + }, + cached: (id) => { + if (nonInternal.exists(id)) { + return NativeModule.getCached(id); + } + throwNoSuchModule(id); + }, +}); +Object.freeze(nonInternal); + // This will be passed to internal/bootstrap/node.js. return loaderExports; diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index bf6a9d4029c2a5..3c2b05eb2f1d67 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -21,7 +21,7 @@ 'use strict'; -const { NativeModule } = require('internal/bootstrap/loaders'); +const { nonInternal } = require('internal/bootstrap/loaders'); const util = require('util'); const { pathToFileURL } = require('internal/url'); const vm = require('vm'); @@ -112,11 +112,7 @@ function Module(id, parent) { this.children = []; } -const builtinModules = Object.keys(NativeModule._source) - .filter(NativeModule.nonInternalExists); - -Object.freeze(builtinModules); -Module.builtinModules = builtinModules; +Module.builtinModules = nonInternal.ids; Module._cache = Object.create(null); Module._pathCache = Object.create(null); @@ -417,7 +413,7 @@ if (isWindows) { var indexChars = [ 105, 110, 100, 101, 120, 46 ]; var indexLen = indexChars.length; Module._resolveLookupPaths = function(request, parent, newReturn) { - if (NativeModule.nonInternalExists(request)) { + if (nonInternal.exists(request)) { debug('looking for %j in []', request); return (newReturn ? null : [request, []]); } @@ -516,7 +512,7 @@ Module._resolveLookupPaths = function(request, parent, newReturn) { // Check the cache for the requested file. // 1. If a module already exists in the cache: return its exports object. -// 2. If the module is native: call `NativeModule.require()` with the +// 2. If the module is builtin: call accessor with the // filename and return the result. // 3. Otherwise, create a new module for the file and save it to the cache. // Then have it load the file contents before returning its exports @@ -534,9 +530,9 @@ Module._load = function(request, parent, isMain) { return cachedModule.exports; } - if (NativeModule.nonInternalExists(filename)) { + if (nonInternal.exists(filename)) { debug('load native module %s', request); - return NativeModule.require(filename); + return nonInternal.require(filename); } // Don't call updateChildren(), Module constructor already does. @@ -567,7 +563,7 @@ function tryModuleLoad(module, filename) { } Module._resolveFilename = function(request, parent, isMain, options) { - if (NativeModule.nonInternalExists(request)) { + if (nonInternal.exists(request)) { return request; } diff --git a/lib/internal/modules/esm/default_resolve.js b/lib/internal/modules/esm/default_resolve.js index 9aa54d09a1b07c..3804bbe45d1120 100644 --- a/lib/internal/modules/esm/default_resolve.js +++ b/lib/internal/modules/esm/default_resolve.js @@ -3,7 +3,7 @@ const { URL } = require('url'); const CJSmodule = require('internal/modules/cjs/loader'); const internalFS = require('internal/fs/utils'); -const { NativeModule } = require('internal/bootstrap/loaders'); +const { nonInternal } = require('internal/bootstrap/loaders'); const { extname } = require('path'); const { realpathSync } = require('fs'); const { getOptionValue } = require('internal/options'); @@ -53,7 +53,7 @@ const extensionFormatMap = { }; function resolve(specifier, parentURL) { - if (NativeModule.nonInternalExists(specifier)) { + if (nonInternal.exists(specifier)) { return { url: specifier, format: 'builtin' diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index 6bfc4c8a98ed83..3c4e8ee864ae1e 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -1,6 +1,6 @@ 'use strict'; -const { NativeModule } = require('internal/bootstrap/loaders'); +const { nonInternal } = require('internal/bootstrap/loaders'); const { ModuleWrap, callbackMap } = internalBinding('module_wrap'); const { stripShebang, @@ -80,8 +80,8 @@ translators.set('builtin', async (url) => { debug(`Translating BuiltinModule ${url}`); // slice 'node:' scheme const id = url.slice(5); - NativeModule.require(id); - const module = NativeModule.getCached(id); + nonInternal.require(id); + const module = nonInternal.cached(id); return createDynamicModule( [...module.exportKeys, 'default'], url, (reflect) => { debug(`Loading BuiltinModule ${url}`);