diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 99489d2e7d8589..201af11f017733 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -214,4 +214,3 @@ globals: LTTNG_HTTP_SERVER_RESPONSE: false LTTNG_NET_SERVER_CONNECTION: false LTTNG_NET_STREAM_END: false - internalBinding: false diff --git a/lib/domain.js b/lib/domain.js index 08fbd207f171d3..b4d0bea6647a82 100644 --- a/lib/domain.js +++ b/lib/domain.js @@ -30,6 +30,7 @@ const util = require('util'); const EventEmitter = require('events'); const errors = require('internal/errors'); const { createHook } = require('async_hooks'); +const { internalBinding } = require('internal/bootstrap/loaders'); // overwrite process.domain with a getter/setter that will allow for more // effective optimizations diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js new file mode 100644 index 00000000000000..e6d30e2aa919f6 --- /dev/null +++ b/lib/internal/bootstrap/loaders.js @@ -0,0 +1,217 @@ +// This file creates the internal module & binding loaders used by built-in +// modules. In contrast, user land modules are loaded using +// lib/internal/modules/cjs/loader.js (CommonJS Modules) or +// lib/internal/modules/esm/* (ES Modules). +// +// This file is compiled and run by node.cc before bootstrap/node.js +// was called, therefore the loaders are bootstraped before we start to +// actually bootstrap Node.js. It creates the following objects: +// +// C++ binding loaders: +// - process.binding(): the legacy C++ binding loader, accessible from user land +// because it is an object attached to the global process object. +// These C++ bindings are created using NODE_BUILTIN_MODULE_CONTEXT_AWARE() +// and have their nm_flags set to NM_F_BUILTIN. We do not make any guarantees +// about the stability of these bindings, but still have to take care of +// compatibility issues caused by them from time to time. +// - process._linkedBinding(): intended to be used by embedders to add +// additional C++ bindings in their applications. These C++ bindings +// can be created using NODE_MODULE_CONTEXT_AWARE_CPP() with the flag +// NM_F_LINKED. +// - internalBinding(): the private internal C++ binding loader, inaccessible +// from user land because they are only available from NativeModule.require() +// These C++ bindings are created using NODE_MODULE_CONTEXT_AWARE_INTERNAL() +// and have their nm_flags set to NM_F_INTERNAL. +// +// Internal JavaScript module loader: +// - NativeModule: a minimal module system used to load the JavaScript core +// modules found in lib/**/*.js and deps/**/*.js. All core modules are +// compiled into the node binary via node_javascript.cc generated by js2c.py, +// so they can be loaded faster without the cost of I/O. This class makes the +// lib/internal/*, deps/internal/* modules and internalBinding() available by +// default to core modules, and lets the core modules require itself via +// require('internal/bootstrap/loaders') even when this file is not written in +// CommonJS style. +// +// Other objects: +// - process.moduleLoadList: an array recording the bindings and the modules +// loaded in the process and the order in which they are loaded. + +'use strict'; + +(function bootstrapInternalLoaders(process, getBinding, getLinkedBinding, + getInternalBinding) { + + // Set up process.moduleLoadList + const moduleLoadList = []; + Object.defineProperty(process, 'moduleLoadList', { + value: moduleLoadList, + configurable: true, + enumerable: true, + writable: false + }); + + // Set up process.binding() and process._linkedBinding() + { + const bindingObj = Object.create(null); + + process.binding = function binding(module) { + module = String(module); + let mod = bindingObj[module]; + if (typeof mod !== 'object') { + mod = bindingObj[module] = getBinding(module); + moduleLoadList.push(`Binding ${module}`); + } + return mod; + }; + + process._linkedBinding = function _linkedBinding(module) { + module = String(module); + let mod = bindingObj[module]; + if (typeof mod !== 'object') + mod = bindingObj[module] = getLinkedBinding(module); + return mod; + }; + } + + // Set up internalBinding() in the closure + let internalBinding; + { + const bindingObj = Object.create(null); + internalBinding = function internalBinding(module) { + let mod = bindingObj[module]; + if (typeof mod !== 'object') { + mod = bindingObj[module] = getInternalBinding(module); + moduleLoadList.push(`Internal Binding ${module}`); + } + return mod; + }; + } + + // Minimal sandbox helper + const ContextifyScript = process.binding('contextify').ContextifyScript; + function runInThisContext(code, options) { + const script = new ContextifyScript(code, options); + return script.runInThisContext(); + } + + // Set up NativeModule + function NativeModule(id) { + this.filename = `${id}.js`; + this.id = id; + this.exports = {}; + this.loaded = false; + this.loading = false; + } + + NativeModule._source = getBinding('natives'); + NativeModule._cache = {}; + + const config = getBinding('config'); + + // Think of this as module.exports in this file even though it is not + // written in CommonJS style. + const loaderExports = { internalBinding, NativeModule }; + const loaderId = 'internal/bootstrap/loaders'; + NativeModule.require = function(id) { + if (id === loaderId) { + return loaderExports; + } + + const cached = NativeModule.getCached(id); + if (cached && (cached.loaded || cached.loading)) { + return cached.exports; + } + + 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 + 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; + } + + moduleLoadList.push(`NativeModule ${id}`); + + const nativeModule = new NativeModule(id); + + nativeModule.cache(); + nativeModule.compile(); + + return nativeModule.exports; + }; + + NativeModule.getCached = function(id) { + return NativeModule._cache[id]; + }; + + NativeModule.exists = function(id) { + return NativeModule._source.hasOwnProperty(id); + }; + + if (config.exposeInternals) { + NativeModule.nonInternalExists = function(id) { + // Do not expose this to user land even with --expose-internals + if (id === loaderId) { + return false; + } + return NativeModule.exists(id); + }; + + NativeModule.isInternal = function(id) { + // Do not expose this to user land even with --expose-internals + return id === loaderId; + }; + } else { + NativeModule.nonInternalExists = function(id) { + return NativeModule.exists(id) && !NativeModule.isInternal(id); + }; + + NativeModule.isInternal = function(id) { + return id.startsWith('internal/'); + }; + } + + NativeModule.getSource = function(id) { + return NativeModule._source[id]; + }; + + NativeModule.wrap = function(script) { + return NativeModule.wrapper[0] + script + NativeModule.wrapper[1]; + }; + + NativeModule.wrapper = [ + '(function (exports, require, module, process) {', + '\n});' + ]; + + NativeModule.prototype.compile = function() { + let source = NativeModule.getSource(this.id); + source = NativeModule.wrap(source); + + this.loading = true; + + try { + const fn = runInThisContext(source, { + filename: this.filename, + lineOffset: 0, + displayErrors: true + }); + fn(this.exports, NativeModule.require, this, process); + + this.loaded = true; + } finally { + this.loading = false; + } + }; + + NativeModule.prototype.cache = function() { + NativeModule._cache[this.id] = this; + }; + + // This will be passed to the bootstrapNodeJSCore function in + // bootstrap/node.js. + return loaderExports; +}); diff --git a/lib/internal/bootstrap_node.js b/lib/internal/bootstrap/node.js similarity index 75% rename from lib/internal/bootstrap_node.js rename to lib/internal/bootstrap/node.js index d8096f90e172ea..8a87712613de7c 100644 --- a/lib/internal/bootstrap_node.js +++ b/lib/internal/bootstrap/node.js @@ -4,11 +4,16 @@ // responsible for bootstrapping the node.js core. As special caution is given // to the performance of the startup process, many dependencies are invoked // lazily. +// +// Before this file is run, lib/internal/bootstrap/loaders.js gets run first +// to bootstrap the internal binding and module loaders, including +// process.binding(), process._linkedBinding(), internalBinding() and +// NativeModule. And then { internalBinding, NativeModule } will be passed +// into this bootstrapper to bootstrap Node.js core. 'use strict'; -(function(process) { - let internalBinding; +(function bootstrapNodeJSCore(process, { internalBinding, NativeModule }) { const exceptionHandlerState = { captureFn: null }; function startup() { @@ -105,7 +110,7 @@ process.emitWarning( 'The ESM module loader is experimental.', 'ExperimentalWarning', undefined); - NativeModule.require('internal/process/modules').setup(); + NativeModule.require('internal/process/esm_loader').setup(); } @@ -165,8 +170,10 @@ preloadModules(); perf.markMilestone(NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END); - const internalModule = NativeModule.require('internal/module'); - internalModule.addBuiltinLibsToObject(global); + const { + addBuiltinLibsToObject + } = NativeModule.require('internal/modules/cjs/helpers'); + addBuiltinLibsToObject(global); evalScript('[eval]'); } else if (process.argv[1] && process.argv[1] !== '-') { perf.markMilestone(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_START); @@ -174,13 +181,13 @@ const path = NativeModule.require('path'); process.argv[1] = path.resolve(process.argv[1]); - const Module = NativeModule.require('module'); + const CJSModule = NativeModule.require('internal/modules/cjs/loader'); // check if user passed `-c` or `--check` arguments to Node. if (process._syntax_check_only != null) { const fs = NativeModule.require('fs'); // read the source - const filename = Module._resolveFilename(process.argv[1]); + const filename = CJSModule._resolveFilename(process.argv[1]); const source = fs.readFileSync(filename, 'utf-8'); checkScriptSyntax(source, filename); process.exit(0); @@ -191,7 +198,7 @@ preloadModules(); perf.markMilestone( NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END); - Module.runMain(); + CJSModule.runMain(); } else { perf.markMilestone(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_START); perf.markMilestone(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_END); @@ -246,54 +253,6 @@ perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE); } - const moduleLoadList = []; - Object.defineProperty(process, 'moduleLoadList', { - value: moduleLoadList, - configurable: true, - enumerable: true, - writable: false - }); - - { - const bindingObj = Object.create(null); - - const getBinding = process.binding; - process.binding = function binding(module) { - module = String(module); - let mod = bindingObj[module]; - if (typeof mod !== 'object') { - mod = bindingObj[module] = getBinding(module); - moduleLoadList.push(`Binding ${module}`); - } - return mod; - }; - - const getLinkedBinding = process._linkedBinding; - process._linkedBinding = function _linkedBinding(module) { - module = String(module); - let mod = bindingObj[module]; - if (typeof mod !== 'object') - mod = bindingObj[module] = getLinkedBinding(module); - return mod; - }; - } - - { - const bindingObj = Object.create(null); - - const getInternalBinding = process._internalBinding; - delete process._internalBinding; - - internalBinding = function internalBinding(module) { - let mod = bindingObj[module]; - if (typeof mod !== 'object') { - mod = bindingObj[module] = getInternalBinding(module); - moduleLoadList.push(`Internal Binding ${module}`); - } - return mod; - }; - } - function setupProcessObject() { process._setupProcessObject(pushValueToArray); @@ -364,7 +323,7 @@ function setupGlobalConsole() { const originalConsole = global.console; - const Module = NativeModule.require('module'); + const CJSModule = NativeModule.require('internal/modules/cjs/loader'); // Setup Node.js global.console const wrappedConsole = NativeModule.require('console'); Object.defineProperty(global, 'console', { @@ -374,22 +333,23 @@ return wrappedConsole; } }); - setupInspector(originalConsole, wrappedConsole, Module); + setupInspector(originalConsole, wrappedConsole, CJSModule); } - function setupInspector(originalConsole, wrappedConsole, Module) { + function setupInspector(originalConsole, wrappedConsole, CJSModule) { if (!process.config.variables.v8_enable_inspector) { return; } const { addCommandLineAPI, consoleCall } = process.binding('inspector'); // Setup inspector command line API - const { makeRequireFunction } = NativeModule.require('internal/module'); + const { makeRequireFunction } = + NativeModule.require('internal/modules/cjs/helpers'); const path = NativeModule.require('path'); const cwd = tryGetCwd(path); - const consoleAPIModule = new Module(''); + const consoleAPIModule = new CJSModule(''); consoleAPIModule.paths = - Module._nodeModulePaths(cwd).concat(Module.globalPaths); + CJSModule._nodeModulePaths(cwd).concat(CJSModule.globalPaths); addCommandLineAPI('require', makeRequireFunction(consoleAPIModule)); const config = {}; for (const key of Object.keys(wrappedConsole)) { @@ -504,13 +464,13 @@ } function evalScript(name) { - const Module = NativeModule.require('module'); + const CJSModule = NativeModule.require('internal/modules/cjs/loader'); const path = NativeModule.require('path'); const cwd = tryGetCwd(path); - const module = new Module(name); + const module = new CJSModule(name); module.filename = path.join(cwd, name); - module.paths = Module._nodeModulePaths(cwd); + module.paths = CJSModule._nodeModulePaths(cwd); const body = wrapForBreakOnFirstLine(process._eval); const script = `global.__filename = ${JSON.stringify(name)};\n` + 'global.exports = exports;\n' + @@ -529,139 +489,29 @@ // Load preload modules function preloadModules() { if (process._preload_modules) { - NativeModule.require('module')._preloadModules(process._preload_modules); + const { + _preloadModules + } = NativeModule.require('internal/modules/cjs/loader'); + _preloadModules(process._preload_modules); } } function checkScriptSyntax(source, filename) { - const Module = NativeModule.require('module'); + const CJSModule = NativeModule.require('internal/modules/cjs/loader'); const vm = NativeModule.require('vm'); - const internalModule = NativeModule.require('internal/module'); + const { + stripShebang, stripBOM + } = NativeModule.require('internal/modules/cjs/helpers'); // remove Shebang - source = internalModule.stripShebang(source); + source = stripShebang(source); // remove BOM - source = internalModule.stripBOM(source); + source = stripBOM(source); // wrap it - source = Module.wrap(source); + source = CJSModule.wrap(source); // compile the script, this will throw if it fails new vm.Script(source, { displayErrors: true, filename }); } - // Below you find a minimal module system, which is used to load the node - // core modules found in lib/*.js. All core modules are compiled into the - // node binary, so they can be loaded faster. - - const ContextifyScript = process.binding('contextify').ContextifyScript; - function runInThisContext(code, options) { - const script = new ContextifyScript(code, options); - return script.runInThisContext(); - } - - function NativeModule(id) { - this.filename = `${id}.js`; - this.id = id; - this.exports = {}; - this.loaded = false; - this.loading = false; - } - - NativeModule._source = process.binding('natives'); - NativeModule._cache = {}; - - const config = process.binding('config'); - - NativeModule.require = function(id) { - if (id === 'native_module') { - return NativeModule; - } - - const cached = NativeModule.getCached(id); - if (cached && (cached.loaded || cached.loading)) { - return cached.exports; - } - - 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 - 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; - } - - moduleLoadList.push(`NativeModule ${id}`); - - const nativeModule = new NativeModule(id); - - nativeModule.cache(); - nativeModule.compile(); - - return nativeModule.exports; - }; - - NativeModule.getCached = function(id) { - return NativeModule._cache[id]; - }; - - NativeModule.exists = function(id) { - return NativeModule._source.hasOwnProperty(id); - }; - - if (config.exposeInternals) { - NativeModule.nonInternalExists = NativeModule.exists; - - NativeModule.isInternal = function(id) { - return false; - }; - } else { - NativeModule.nonInternalExists = function(id) { - return NativeModule.exists(id) && !NativeModule.isInternal(id); - }; - - NativeModule.isInternal = function(id) { - return id.startsWith('internal/'); - }; - } - - - NativeModule.getSource = function(id) { - return NativeModule._source[id]; - }; - - NativeModule.wrap = function(script) { - return NativeModule.wrapper[0] + script + NativeModule.wrapper[1]; - }; - - NativeModule.wrapper = [ - '(function (exports, require, module, internalBinding, process) {', - '\n});' - ]; - - NativeModule.prototype.compile = function() { - let source = NativeModule.getSource(this.id); - source = NativeModule.wrap(source); - - this.loading = true; - - try { - const fn = runInThisContext(source, { - filename: this.filename, - lineOffset: 0, - displayErrors: true - }); - fn(this.exports, NativeModule.require, this, internalBinding, process); - - this.loaded = true; - } finally { - this.loading = false; - } - }; - - NativeModule.prototype.cache = function() { - NativeModule._cache[this.id] = this; - }; - startup(); }); diff --git a/lib/internal/module.js b/lib/internal/modules/cjs/helpers.js similarity index 100% rename from lib/internal/module.js rename to lib/internal/modules/cjs/helpers.js diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js new file mode 100644 index 00000000000000..39333f049f6c1a --- /dev/null +++ b/lib/internal/modules/cjs/loader.js @@ -0,0 +1,761 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +const { NativeModule } = require('internal/bootstrap/loaders'); +const util = require('util'); +const { decorateErrorStack } = require('internal/util'); +const { getURLFromFilePath } = require('internal/url'); +const vm = require('vm'); +const assert = require('assert').ok; +const fs = require('fs'); +const internalFS = require('internal/fs'); +const path = require('path'); +const { + internalModuleReadFile, + internalModuleStat +} = process.binding('fs'); +const { + makeRequireFunction, + requireDepth, + stripBOM, + stripShebang +} = require('internal/modules/cjs/helpers'); +const preserveSymlinks = !!process.binding('config').preserveSymlinks; +const experimentalModules = !!process.binding('config').experimentalModules; + +const errors = require('internal/errors'); + +module.exports = Module; + +// these are below module.exports for the circular reference +const asyncESM = require('internal/process/esm_loader'); +const ModuleJob = require('internal/modules/esm/ModuleJob'); +const createDynamicModule = require('internal/modules/esm/CreateDynamicModule'); + +function stat(filename) { + filename = path.toNamespacedPath(filename); + const cache = stat.cache; + if (cache !== null) { + const result = cache.get(filename); + if (result !== undefined) return result; + } + const result = internalModuleStat(filename); + if (cache !== null) cache.set(filename, result); + return result; +} +stat.cache = null; + +function updateChildren(parent, child, scan) { + var children = parent && parent.children; + if (children && !(scan && children.includes(child))) + children.push(child); +} + +function Module(id, parent) { + this.id = id; + this.exports = {}; + this.parent = parent; + updateChildren(parent, this, false); + this.filename = null; + this.loaded = false; + this.children = []; +} + +const builtinModules = Object.keys(NativeModule._source) + .filter(NativeModule.nonInternalExists); + +Object.freeze(builtinModules); +Module.builtinModules = builtinModules; + +Module._cache = Object.create(null); +Module._pathCache = Object.create(null); +Module._extensions = Object.create(null); +var modulePaths = []; +Module.globalPaths = []; + +Module.wrap = function(script) { + return Module.wrapper[0] + script + Module.wrapper[1]; +}; + +Module.wrapper = [ + '(function (exports, require, module, __filename, __dirname) { ', + '\n});' +]; + +const debug = util.debuglog('module'); + +Module._debug = util.deprecate(debug, 'Module._debug is deprecated.', + 'DEP0077'); + +// given a module name, and a list of paths to test, returns the first +// matching file in the following precedence. +// +// require("a.") +// -> a. +// +// require("a") +// -> a +// -> a. +// -> a/index. + +// check if the directory is a package.json dir +const packageMainCache = Object.create(null); + +function readPackage(requestPath) { + const entry = packageMainCache[requestPath]; + if (entry) + return entry; + + const jsonPath = path.resolve(requestPath, 'package.json'); + const json = internalModuleReadFile(path.toNamespacedPath(jsonPath)); + + if (json === undefined) { + return false; + } + + try { + var pkg = packageMainCache[requestPath] = JSON.parse(json).main; + } catch (e) { + e.path = jsonPath; + e.message = 'Error parsing ' + jsonPath + ': ' + e.message; + throw e; + } + return pkg; +} + +function tryPackage(requestPath, exts, isMain) { + var pkg = readPackage(requestPath); + + if (!pkg) return false; + + var filename = path.resolve(requestPath, pkg); + return tryFile(filename, isMain) || + tryExtensions(filename, exts, isMain) || + tryExtensions(path.resolve(filename, 'index'), exts, isMain); +} + +// In order to minimize unnecessary lstat() calls, +// this cache is a list of known-real paths. +// Set to an empty Map to reset. +const realpathCache = new Map(); + +// check if the file exists and is not a directory +// if using --preserve-symlinks and isMain is false, +// keep symlinks intact, otherwise resolve to the +// absolute realpath. +function tryFile(requestPath, isMain) { + const rc = stat(requestPath); + if (preserveSymlinks && !isMain) { + return rc === 0 && path.resolve(requestPath); + } + return rc === 0 && toRealPath(requestPath); +} + +function toRealPath(requestPath) { + return fs.realpathSync(requestPath, { + [internalFS.realpathCacheKey]: realpathCache + }); +} + +// given a path, check if the file exists with any of the set extensions +function tryExtensions(p, exts, isMain) { + for (var i = 0; i < exts.length; i++) { + const filename = tryFile(p + exts[i], isMain); + + if (filename) { + return filename; + } + } + return false; +} + +var warned = false; +Module._findPath = function(request, paths, isMain) { + if (path.isAbsolute(request)) { + paths = ['']; + } else if (!paths || paths.length === 0) { + return false; + } + + var cacheKey = request + '\x00' + + (paths.length === 1 ? paths[0] : paths.join('\x00')); + var entry = Module._pathCache[cacheKey]; + if (entry) + return entry; + + var exts; + var trailingSlash = request.length > 0 && + request.charCodeAt(request.length - 1) === 47/*/*/; + + // For each path + for (var i = 0; i < paths.length; i++) { + // Don't search further if path doesn't exist + const curPath = paths[i]; + if (curPath && stat(curPath) < 1) continue; + var basePath = path.resolve(curPath, request); + var filename; + + var rc = stat(basePath); + if (!trailingSlash) { + if (rc === 0) { // File. + if (preserveSymlinks && !isMain) { + filename = path.resolve(basePath); + } else { + filename = toRealPath(basePath); + } + } else if (rc === 1) { // Directory. + if (exts === undefined) + exts = Object.keys(Module._extensions); + filename = tryPackage(basePath, exts, isMain); + } + + if (!filename) { + // try it with each of the extensions + if (exts === undefined) + exts = Object.keys(Module._extensions); + filename = tryExtensions(basePath, exts, isMain); + } + } + + if (!filename && rc === 1) { // Directory. + if (exts === undefined) + exts = Object.keys(Module._extensions); + filename = tryPackage(basePath, exts, isMain) || + // try it with each of the extensions at "index" + tryExtensions(path.resolve(basePath, 'index'), exts, isMain); + } + + if (filename) { + // Warn once if '.' resolved outside the module dir + if (request === '.' && i > 0) { + if (!warned) { + warned = true; + process.emitWarning( + 'warning: require(\'.\') resolved outside the package ' + + 'directory. This functionality is deprecated and will be removed ' + + 'soon.', + 'DeprecationWarning', 'DEP0019'); + } + } + + Module._pathCache[cacheKey] = filename; + return filename; + } + } + return false; +}; + +// 'node_modules' character codes reversed +var nmChars = [ 115, 101, 108, 117, 100, 111, 109, 95, 101, 100, 111, 110 ]; +var nmLen = nmChars.length; +if (process.platform === 'win32') { + // 'from' is the __dirname of the module. + Module._nodeModulePaths = function(from) { + // guarantee that 'from' is absolute. + from = path.resolve(from); + + // note: this approach *only* works when the path is guaranteed + // to be absolute. Doing a fully-edge-case-correct path.split + // that works on both Windows and Posix is non-trivial. + + // return root node_modules when path is 'D:\\'. + // path.resolve will make sure from.length >=3 in Windows. + if (from.charCodeAt(from.length - 1) === 92/*\*/ && + from.charCodeAt(from.length - 2) === 58/*:*/) + return [from + 'node_modules']; + + const paths = []; + var p = 0; + var last = from.length; + for (var i = from.length - 1; i >= 0; --i) { + const code = from.charCodeAt(i); + // The path segment separator check ('\' and '/') was used to get + // node_modules path for every path segment. + // Use colon as an extra condition since we can get node_modules + // path for drive root like 'C:\node_modules' and don't need to + // parse drive name. + if (code === 92/*\*/ || code === 47/*/*/ || code === 58/*:*/) { + if (p !== nmLen) + paths.push(from.slice(0, last) + '\\node_modules'); + last = i; + p = 0; + } else if (p !== -1) { + if (nmChars[p] === code) { + ++p; + } else { + p = -1; + } + } + } + + return paths; + }; +} else { // posix + // 'from' is the __dirname of the module. + Module._nodeModulePaths = function(from) { + // guarantee that 'from' is absolute. + from = path.resolve(from); + // Return early not only to avoid unnecessary work, but to *avoid* returning + // an array of two items for a root: [ '//node_modules', '/node_modules' ] + if (from === '/') + return ['/node_modules']; + + // note: this approach *only* works when the path is guaranteed + // to be absolute. Doing a fully-edge-case-correct path.split + // that works on both Windows and Posix is non-trivial. + const paths = []; + var p = 0; + var last = from.length; + for (var i = from.length - 1; i >= 0; --i) { + const code = from.charCodeAt(i); + if (code === 47/*/*/) { + if (p !== nmLen) + paths.push(from.slice(0, last) + '/node_modules'); + last = i; + p = 0; + } else if (p !== -1) { + if (nmChars[p] === code) { + ++p; + } else { + p = -1; + } + } + } + + // Append /node_modules to handle root paths. + paths.push('/node_modules'); + + return paths; + }; +} + + +// 'index.' character codes +var indexChars = [ 105, 110, 100, 101, 120, 46 ]; +var indexLen = indexChars.length; +Module._resolveLookupPaths = function(request, parent, newReturn) { + if (NativeModule.nonInternalExists(request)) { + debug('looking for %j in []', request); + return (newReturn ? null : [request, []]); + } + + // Check for relative path + if (request.length < 2 || + request.charCodeAt(0) !== 46/*.*/ || + (request.charCodeAt(1) !== 46/*.*/ && + request.charCodeAt(1) !== 47/*/*/)) { + var paths = modulePaths; + if (parent) { + if (!parent.paths) + paths = parent.paths = []; + else + paths = parent.paths.concat(paths); + } + + // Maintain backwards compat with certain broken uses of require('.') + // by putting the module's directory in front of the lookup paths. + if (request === '.') { + if (parent && parent.filename) { + paths.unshift(path.dirname(parent.filename)); + } else { + paths.unshift(path.resolve(request)); + } + } + + debug('looking for %j in %j', request, paths); + return (newReturn ? (paths.length > 0 ? paths : null) : [request, paths]); + } + + // with --eval, parent.id is not set and parent.filename is null + if (!parent || !parent.id || !parent.filename) { + // make require('./path/to/foo') work - normally the path is taken + // from realpath(__filename) but with eval there is no filename + var mainPaths = ['.'].concat(Module._nodeModulePaths('.'), modulePaths); + + debug('looking for %j in %j', request, mainPaths); + return (newReturn ? mainPaths : [request, mainPaths]); + } + + // Is the parent an index module? + // We can assume the parent has a valid extension, + // as it already has been accepted as a module. + const base = path.basename(parent.filename); + var parentIdPath; + if (base.length > indexLen) { + var i = 0; + for (; i < indexLen; ++i) { + if (indexChars[i] !== base.charCodeAt(i)) + break; + } + if (i === indexLen) { + // We matched 'index.', let's validate the rest + for (; i < base.length; ++i) { + const code = base.charCodeAt(i); + if (code !== 95/*_*/ && + (code < 48/*0*/ || code > 57/*9*/) && + (code < 65/*A*/ || code > 90/*Z*/) && + (code < 97/*a*/ || code > 122/*z*/)) + break; + } + if (i === base.length) { + // Is an index module + parentIdPath = parent.id; + } else { + // Not an index module + parentIdPath = path.dirname(parent.id); + } + } else { + // Not an index module + parentIdPath = path.dirname(parent.id); + } + } else { + // Not an index module + parentIdPath = path.dirname(parent.id); + } + var id = path.resolve(parentIdPath, request); + + // make sure require('./path') and require('path') get distinct ids, even + // when called from the toplevel js file + if (parentIdPath === '.' && id.indexOf('/') === -1) { + id = './' + id; + } + + debug('RELATIVE: requested: %s set ID to: %s from %s', request, id, + parent.id); + + var parentDir = [path.dirname(parent.filename)]; + debug('looking for %j in %j', id, parentDir); + return (newReturn ? parentDir : [id, parentDir]); +}; + +// 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 +// 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 +// object. +Module._load = function(request, parent, isMain) { + if (parent) { + debug('Module._load REQUEST %s parent: %s', request, parent.id); + } + + if (experimentalModules && isMain) { + asyncESM.loaderPromise.then((loader) => { + return loader.import(getURLFromFilePath(request).pathname); + }) + .catch((e) => { + decorateErrorStack(e); + console.error(e); + process.exit(1); + }); + return; + } + + var filename = Module._resolveFilename(request, parent, isMain); + + var cachedModule = Module._cache[filename]; + if (cachedModule) { + updateChildren(parent, cachedModule, true); + return cachedModule.exports; + } + + if (NativeModule.nonInternalExists(filename)) { + debug('load native module %s', request); + return NativeModule.require(filename); + } + + // Don't call updateChildren(), Module constructor already does. + var module = new Module(filename, parent); + + if (isMain) { + process.mainModule = module; + module.id = '.'; + } + + Module._cache[filename] = module; + + tryModuleLoad(module, filename); + + return module.exports; +}; + +function tryModuleLoad(module, filename) { + var threw = true; + try { + module.load(filename); + threw = false; + } finally { + if (threw) { + delete Module._cache[filename]; + } + } +} + +Module._resolveFilename = function(request, parent, isMain, options) { + if (NativeModule.nonInternalExists(request)) { + return request; + } + + var paths; + + if (typeof options === 'object' && options !== null && + Array.isArray(options.paths)) { + const fakeParent = new Module('', null); + + paths = []; + + for (var i = 0; i < options.paths.length; i++) { + const path = options.paths[i]; + fakeParent.paths = Module._nodeModulePaths(path); + const lookupPaths = Module._resolveLookupPaths(request, fakeParent, 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); + if (!filename) { + var err = new Error(`Cannot find module '${request}'`); + err.code = 'MODULE_NOT_FOUND'; + throw err; + } + return filename; +}; + + +// Given a file name, pass it to the proper extension handler. +Module.prototype.load = function(filename) { + debug('load %j for module %j', filename, this.id); + + assert(!this.loaded); + this.filename = filename; + this.paths = Module._nodeModulePaths(path.dirname(filename)); + + var extension = path.extname(filename) || '.js'; + if (!Module._extensions[extension]) extension = '.js'; + Module._extensions[extension](this, filename); + this.loaded = true; + + if (experimentalModules) { + const ESMLoader = asyncESM.ESMLoader; + const url = getURLFromFilePath(filename); + const urlString = `${url}`; + const exports = this.exports; + if (ESMLoader.moduleMap.has(urlString) !== true) { + ESMLoader.moduleMap.set( + urlString, + new ModuleJob(ESMLoader, url, async () => { + const ctx = createDynamicModule( + ['default'], url); + ctx.reflect.exports.default.set(exports); + return ctx; + }) + ); + } else { + const job = ESMLoader.moduleMap.get(urlString); + if (job.reflect) + job.reflect.exports.default.set(exports); + } + } +}; + + +// Loads a module at the given file path. Returns that module's +// `exports` property. +Module.prototype.require = function(path) { + assert(path, 'missing path'); + assert(typeof path === 'string', 'path must be a string'); + return Module._load(path, this, /* isMain */ false); +}; + + +// Resolved path to process.argv[1] will be lazily placed here +// (needed for setting breakpoint when called with --inspect-brk) +var resolvedArgv; + + +// Run the file contents in the correct scope or sandbox. Expose +// the correct helper variables (require, module, exports) to +// the file. +// Returns exception, if any. +Module.prototype._compile = function(content, filename) { + + content = stripShebang(content); + + // create wrapper function + var wrapper = Module.wrap(content); + + var compiledWrapper = vm.runInThisContext(wrapper, { + filename: filename, + lineOffset: 0, + displayErrors: true + }); + + var inspectorWrapper = null; + if (process._breakFirstLine && process._eval == null) { + if (!resolvedArgv) { + // we enter the repl if we're not given a filename argument. + if (process.argv[1]) { + resolvedArgv = Module._resolveFilename(process.argv[1], null, false); + } else { + resolvedArgv = 'repl'; + } + } + + // Set breakpoint on module start + if (filename === resolvedArgv) { + delete process._breakFirstLine; + inspectorWrapper = process.binding('inspector').callAndPauseOnStart; + if (!inspectorWrapper) { + const Debug = vm.runInDebugContext('Debug'); + Debug.setBreakPoint(compiledWrapper, 0, 0); + } + } + } + var dirname = path.dirname(filename); + var require = makeRequireFunction(this); + var depth = requireDepth; + if (depth === 0) stat.cache = new Map(); + var result; + if (inspectorWrapper) { + result = inspectorWrapper(compiledWrapper, this.exports, this.exports, + require, this, filename, dirname); + } else { + result = compiledWrapper.call(this.exports, this.exports, require, this, + filename, dirname); + } + if (depth === 0) stat.cache = null; + return result; +}; + + +// Native extension for .js +Module._extensions['.js'] = function(module, filename) { + var content = fs.readFileSync(filename, 'utf8'); + module._compile(stripBOM(content), filename); +}; + + +// Native extension for .json +Module._extensions['.json'] = function(module, filename) { + var content = fs.readFileSync(filename, 'utf8'); + try { + module.exports = JSON.parse(stripBOM(content)); + } catch (err) { + err.message = filename + ': ' + err.message; + throw err; + } +}; + + +//Native extension for .node +Module._extensions['.node'] = function(module, filename) { + return process.dlopen(module, path.toNamespacedPath(filename)); +}; + +if (experimentalModules) { + Module._extensions['.mjs'] = function(module, filename) { + throw new errors.Error('ERR_REQUIRE_ESM', filename); + }; +} + +// bootstrap main module. +Module.runMain = function() { + // Load the main module--the command line argument. + Module._load(process.argv[1], null, true); + // Handle any nextTicks added in the first tick of the program + process._tickCallback(); +}; + +Module._initPaths = function() { + const isWindows = process.platform === 'win32'; + + var homeDir; + if (isWindows) { + homeDir = process.env.USERPROFILE; + } else { + homeDir = process.env.HOME; + } + + // $PREFIX/lib/node, where $PREFIX is the root of the Node.js installation. + var prefixDir; + // process.execPath is $PREFIX/bin/node except on Windows where it is + // $PREFIX\node.exe. + if (isWindows) { + prefixDir = path.resolve(process.execPath, '..'); + } else { + prefixDir = path.resolve(process.execPath, '..', '..'); + } + var paths = [path.resolve(prefixDir, 'lib', 'node')]; + + if (homeDir) { + paths.unshift(path.resolve(homeDir, '.node_libraries')); + paths.unshift(path.resolve(homeDir, '.node_modules')); + } + + var nodePath = process.env.NODE_PATH; + if (nodePath) { + paths = nodePath.split(path.delimiter).filter(function(path) { + return !!path; + }).concat(paths); + } + + modulePaths = paths; + + // clone as a shallow copy, for introspection. + Module.globalPaths = modulePaths.slice(0); +}; + +Module._preloadModules = function(requests) { + if (!Array.isArray(requests)) + return; + + // Preloaded modules have a dummy parent module which is deemed to exist + // in the current working directory. This seeds the search path for + // preloaded modules. + var parent = new Module('internal/preload', null); + try { + parent.paths = Module._nodeModulePaths(process.cwd()); + } catch (e) { + if (e.code !== 'ENOENT') { + throw e; + } + } + for (var n = 0; n < requests.length; n++) + parent.require(requests[n]); +}; + +Module._initPaths(); + +// backwards compatibility +Module.Module = Module; diff --git a/lib/internal/loader/CreateDynamicModule.js b/lib/internal/modules/esm/CreateDynamicModule.js similarity index 96% rename from lib/internal/loader/CreateDynamicModule.js rename to lib/internal/modules/esm/CreateDynamicModule.js index f2596de04bfcb3..7e9777af51ee2b 100644 --- a/lib/internal/loader/CreateDynamicModule.js +++ b/lib/internal/modules/esm/CreateDynamicModule.js @@ -1,5 +1,6 @@ 'use strict'; +const { internalBinding } = require('internal/bootstrap/loaders'); const { ModuleWrap } = internalBinding('module_wrap'); const debug = require('util').debuglog('esm'); const ArrayJoin = Function.call.bind(Array.prototype.join); diff --git a/lib/internal/loader/DefaultResolve.js b/lib/internal/modules/esm/DefaultResolve.js similarity index 94% rename from lib/internal/loader/DefaultResolve.js rename to lib/internal/modules/esm/DefaultResolve.js index bd99f31e54c599..093075e09659fe 100644 --- a/lib/internal/loader/DefaultResolve.js +++ b/lib/internal/modules/esm/DefaultResolve.js @@ -1,9 +1,9 @@ 'use strict'; const { URL } = require('url'); -const CJSmodule = require('module'); +const CJSmodule = require('internal/modules/cjs/loader'); const internalFS = require('internal/fs'); -const NativeModule = require('native_module'); +const { NativeModule, internalBinding } = require('internal/bootstrap/loaders'); const { extname } = require('path'); const { realpathSync } = require('fs'); const preserveSymlinks = !!process.binding('config').preserveSymlinks; diff --git a/lib/internal/loader/Loader.js b/lib/internal/modules/esm/Loader.js similarity index 92% rename from lib/internal/loader/Loader.js rename to lib/internal/modules/esm/Loader.js index f0edbbf921f40f..170fa23ec798ff 100644 --- a/lib/internal/loader/Loader.js +++ b/lib/internal/modules/esm/Loader.js @@ -1,11 +1,11 @@ 'use strict'; const errors = require('internal/errors'); -const ModuleMap = require('internal/loader/ModuleMap'); -const ModuleJob = require('internal/loader/ModuleJob'); -const defaultResolve = require('internal/loader/DefaultResolve'); -const createDynamicModule = require('internal/loader/CreateDynamicModule'); -const translators = require('internal/loader/Translators'); +const ModuleMap = require('internal/modules/esm/ModuleMap'); +const ModuleJob = require('internal/modules/esm/ModuleJob'); +const defaultResolve = require('internal/modules/esm/DefaultResolve'); +const createDynamicModule = require('internal/modules/esm/CreateDynamicModule'); +const translators = require('internal/modules/esm/Translators'); const FunctionBind = Function.call.bind(Function.prototype.bind); diff --git a/lib/internal/loader/ModuleJob.js b/lib/internal/modules/esm/ModuleJob.js similarity index 98% rename from lib/internal/loader/ModuleJob.js rename to lib/internal/modules/esm/ModuleJob.js index b3553fc7235d95..d948252829ddbf 100644 --- a/lib/internal/loader/ModuleJob.js +++ b/lib/internal/modules/esm/ModuleJob.js @@ -1,5 +1,6 @@ 'use strict'; +const { internalBinding } = require('internal/bootstrap/loaders'); const { ModuleWrap } = internalBinding('module_wrap'); const { SafeSet, SafePromise } = require('internal/safe_globals'); const { decorateErrorStack } = require('internal/util'); diff --git a/lib/internal/loader/ModuleMap.js b/lib/internal/modules/esm/ModuleMap.js similarity index 93% rename from lib/internal/loader/ModuleMap.js rename to lib/internal/modules/esm/ModuleMap.js index aa238afbaedc05..7f5ee8bf9e7762 100644 --- a/lib/internal/loader/ModuleMap.js +++ b/lib/internal/modules/esm/ModuleMap.js @@ -1,6 +1,6 @@ 'use strict'; -const ModuleJob = require('internal/loader/ModuleJob'); +const ModuleJob = require('internal/modules/esm/ModuleJob'); const { SafeMap } = require('internal/safe_globals'); const debug = require('util').debuglog('esm'); const errors = require('internal/errors'); diff --git a/lib/internal/loader/ModuleWrap.js b/lib/internal/modules/esm/ModuleWrap.js similarity index 62% rename from lib/internal/loader/ModuleWrap.js rename to lib/internal/modules/esm/ModuleWrap.js index b2b11daead7dde..e589960193c94c 100644 --- a/lib/internal/loader/ModuleWrap.js +++ b/lib/internal/modules/esm/ModuleWrap.js @@ -2,4 +2,5 @@ // exposes ModuleWrap for testing +const { internalBinding } = require('internal/bootstrap/loaders'); module.exports = internalBinding('module_wrap').ModuleWrap; diff --git a/lib/internal/loader/Translators.js b/lib/internal/modules/esm/Translators.js similarity index 88% rename from lib/internal/loader/Translators.js rename to lib/internal/modules/esm/Translators.js index 18b1b12fd15854..2928115be515e0 100644 --- a/lib/internal/loader/Translators.js +++ b/lib/internal/modules/esm/Translators.js @@ -1,11 +1,14 @@ 'use strict'; +const { NativeModule, internalBinding } = require('internal/bootstrap/loaders'); const { ModuleWrap } = internalBinding('module_wrap'); -const NativeModule = require('native_module'); -const internalCJSModule = require('internal/module'); -const CJSModule = require('module'); +const { + stripShebang, + stripBOM +} = require('internal/modules/cjs/helpers'); +const CJSModule = require('internal/modules/cjs/loader'); const internalURLModule = require('internal/url'); -const createDynamicModule = require('internal/loader/CreateDynamicModule'); +const createDynamicModule = require('internal/modules/esm/CreateDynamicModule'); const fs = require('fs'); const { _makeLong } = require('path'); const { SafeMap } = require('internal/safe_globals'); @@ -24,7 +27,7 @@ translators.set('esm', async (url) => { const source = `${await readFileAsync(new URL(url))}`; debug(`Translating StandardModule ${url}`); return { - module: new ModuleWrap(internalCJSModule.stripShebang(source), url), + module: new ModuleWrap(stripShebang(source), url), reflect: undefined }; }); @@ -82,7 +85,7 @@ translators.set('json', async (url) => { const pathname = internalURLModule.getPathFromURL(new URL(url)); const content = readFileSync(pathname, 'utf8'); try { - const exports = JsonParse(internalCJSModule.stripBOM(content)); + const exports = JsonParse(stripBOM(content)); reflect.exports.default.set(exports); } catch (err) { err.message = pathname + ': ' + err.message; diff --git a/lib/internal/process/modules.js b/lib/internal/process/esm_loader.js similarity index 91% rename from lib/internal/process/modules.js rename to lib/internal/process/esm_loader.js index bc977c718725f2..ca2ce57feb54d8 100644 --- a/lib/internal/process/modules.js +++ b/lib/internal/process/esm_loader.js @@ -1,11 +1,12 @@ 'use strict'; +const { internalBinding } = require('internal/bootstrap/loaders'); const { setImportModuleDynamicallyCallback } = internalBinding('module_wrap'); const { getURLFromFilePath } = require('internal/url'); -const Loader = require('internal/loader/Loader'); +const Loader = require('internal/modules/esm/Loader'); const path = require('path'); const { URL } = require('url'); diff --git a/lib/internal/vm/Module.js b/lib/internal/vm/Module.js index a8fb7303aec131..f0fa55f39b8103 100644 --- a/lib/internal/vm/Module.js +++ b/lib/internal/vm/Module.js @@ -1,5 +1,6 @@ 'use strict'; +const { internalBinding } = require('internal/bootstrap/loaders'); const { emitExperimentalWarning } = require('internal/util'); const { URL } = require('internal/url'); const { kParsingContext, isContext } = process.binding('contextify'); diff --git a/lib/module.js b/lib/module.js index 877cca590f077b..962f18b054cc90 100644 --- a/lib/module.js +++ b/lib/module.js @@ -1,756 +1,3 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - 'use strict'; -const NativeModule = require('native_module'); -const util = require('util'); -const { decorateErrorStack } = require('internal/util'); -const { getURLFromFilePath } = require('internal/url'); -const vm = require('vm'); -const assert = require('assert').ok; -const fs = require('fs'); -const internalFS = require('internal/fs'); -const path = require('path'); -const { - internalModuleReadFile, - internalModuleStat -} = process.binding('fs'); -const internalModule = require('internal/module'); -const preserveSymlinks = !!process.binding('config').preserveSymlinks; -const experimentalModules = !!process.binding('config').experimentalModules; - -const errors = require('internal/errors'); - -module.exports = Module; - -// these are below module.exports for the circular reference -const internalESModule = require('internal/process/modules'); -const ModuleJob = require('internal/loader/ModuleJob'); -const createDynamicModule = require('internal/loader/CreateDynamicModule'); - -function stat(filename) { - filename = path.toNamespacedPath(filename); - const cache = stat.cache; - if (cache !== null) { - const result = cache.get(filename); - if (result !== undefined) return result; - } - const result = internalModuleStat(filename); - if (cache !== null) cache.set(filename, result); - return result; -} -stat.cache = null; - -function updateChildren(parent, child, scan) { - var children = parent && parent.children; - if (children && !(scan && children.includes(child))) - children.push(child); -} - -function Module(id, parent) { - this.id = id; - this.exports = {}; - this.parent = parent; - updateChildren(parent, this, false); - this.filename = null; - this.loaded = false; - this.children = []; -} - -const builtinModules = Object.keys(NativeModule._source) - .filter(NativeModule.nonInternalExists); - -Object.freeze(builtinModules); -Module.builtinModules = builtinModules; - -Module._cache = Object.create(null); -Module._pathCache = Object.create(null); -Module._extensions = Object.create(null); -var modulePaths = []; -Module.globalPaths = []; - -Module.wrap = function(script) { - return Module.wrapper[0] + script + Module.wrapper[1]; -}; - -Module.wrapper = [ - '(function (exports, require, module, __filename, __dirname) { ', - '\n});' -]; - -const debug = util.debuglog('module'); - -Module._debug = util.deprecate(debug, 'Module._debug is deprecated.', - 'DEP0077'); - -// given a module name, and a list of paths to test, returns the first -// matching file in the following precedence. -// -// require("a.") -// -> a. -// -// require("a") -// -> a -// -> a. -// -> a/index. - -// check if the directory is a package.json dir -const packageMainCache = Object.create(null); - -function readPackage(requestPath) { - const entry = packageMainCache[requestPath]; - if (entry) - return entry; - - const jsonPath = path.resolve(requestPath, 'package.json'); - const json = internalModuleReadFile(path.toNamespacedPath(jsonPath)); - - if (json === undefined) { - return false; - } - - try { - var pkg = packageMainCache[requestPath] = JSON.parse(json).main; - } catch (e) { - e.path = jsonPath; - e.message = 'Error parsing ' + jsonPath + ': ' + e.message; - throw e; - } - return pkg; -} - -function tryPackage(requestPath, exts, isMain) { - var pkg = readPackage(requestPath); - - if (!pkg) return false; - - var filename = path.resolve(requestPath, pkg); - return tryFile(filename, isMain) || - tryExtensions(filename, exts, isMain) || - tryExtensions(path.resolve(filename, 'index'), exts, isMain); -} - -// In order to minimize unnecessary lstat() calls, -// this cache is a list of known-real paths. -// Set to an empty Map to reset. -const realpathCache = new Map(); - -// check if the file exists and is not a directory -// if using --preserve-symlinks and isMain is false, -// keep symlinks intact, otherwise resolve to the -// absolute realpath. -function tryFile(requestPath, isMain) { - const rc = stat(requestPath); - if (preserveSymlinks && !isMain) { - return rc === 0 && path.resolve(requestPath); - } - return rc === 0 && toRealPath(requestPath); -} - -function toRealPath(requestPath) { - return fs.realpathSync(requestPath, { - [internalFS.realpathCacheKey]: realpathCache - }); -} - -// given a path, check if the file exists with any of the set extensions -function tryExtensions(p, exts, isMain) { - for (var i = 0; i < exts.length; i++) { - const filename = tryFile(p + exts[i], isMain); - - if (filename) { - return filename; - } - } - return false; -} - -var warned = false; -Module._findPath = function(request, paths, isMain) { - if (path.isAbsolute(request)) { - paths = ['']; - } else if (!paths || paths.length === 0) { - return false; - } - - var cacheKey = request + '\x00' + - (paths.length === 1 ? paths[0] : paths.join('\x00')); - var entry = Module._pathCache[cacheKey]; - if (entry) - return entry; - - var exts; - var trailingSlash = request.length > 0 && - request.charCodeAt(request.length - 1) === 47/*/*/; - - // For each path - for (var i = 0; i < paths.length; i++) { - // Don't search further if path doesn't exist - const curPath = paths[i]; - if (curPath && stat(curPath) < 1) continue; - var basePath = path.resolve(curPath, request); - var filename; - - var rc = stat(basePath); - if (!trailingSlash) { - if (rc === 0) { // File. - if (preserveSymlinks && !isMain) { - filename = path.resolve(basePath); - } else { - filename = toRealPath(basePath); - } - } else if (rc === 1) { // Directory. - if (exts === undefined) - exts = Object.keys(Module._extensions); - filename = tryPackage(basePath, exts, isMain); - } - - if (!filename) { - // try it with each of the extensions - if (exts === undefined) - exts = Object.keys(Module._extensions); - filename = tryExtensions(basePath, exts, isMain); - } - } - - if (!filename && rc === 1) { // Directory. - if (exts === undefined) - exts = Object.keys(Module._extensions); - filename = tryPackage(basePath, exts, isMain) || - // try it with each of the extensions at "index" - tryExtensions(path.resolve(basePath, 'index'), exts, isMain); - } - - if (filename) { - // Warn once if '.' resolved outside the module dir - if (request === '.' && i > 0) { - if (!warned) { - warned = true; - process.emitWarning( - 'warning: require(\'.\') resolved outside the package ' + - 'directory. This functionality is deprecated and will be removed ' + - 'soon.', - 'DeprecationWarning', 'DEP0019'); - } - } - - Module._pathCache[cacheKey] = filename; - return filename; - } - } - return false; -}; - -// 'node_modules' character codes reversed -var nmChars = [ 115, 101, 108, 117, 100, 111, 109, 95, 101, 100, 111, 110 ]; -var nmLen = nmChars.length; -if (process.platform === 'win32') { - // 'from' is the __dirname of the module. - Module._nodeModulePaths = function(from) { - // guarantee that 'from' is absolute. - from = path.resolve(from); - - // note: this approach *only* works when the path is guaranteed - // to be absolute. Doing a fully-edge-case-correct path.split - // that works on both Windows and Posix is non-trivial. - - // return root node_modules when path is 'D:\\'. - // path.resolve will make sure from.length >=3 in Windows. - if (from.charCodeAt(from.length - 1) === 92/*\*/ && - from.charCodeAt(from.length - 2) === 58/*:*/) - return [from + 'node_modules']; - - const paths = []; - var p = 0; - var last = from.length; - for (var i = from.length - 1; i >= 0; --i) { - const code = from.charCodeAt(i); - // The path segment separator check ('\' and '/') was used to get - // node_modules path for every path segment. - // Use colon as an extra condition since we can get node_modules - // path for drive root like 'C:\node_modules' and don't need to - // parse drive name. - if (code === 92/*\*/ || code === 47/*/*/ || code === 58/*:*/) { - if (p !== nmLen) - paths.push(from.slice(0, last) + '\\node_modules'); - last = i; - p = 0; - } else if (p !== -1) { - if (nmChars[p] === code) { - ++p; - } else { - p = -1; - } - } - } - - return paths; - }; -} else { // posix - // 'from' is the __dirname of the module. - Module._nodeModulePaths = function(from) { - // guarantee that 'from' is absolute. - from = path.resolve(from); - // Return early not only to avoid unnecessary work, but to *avoid* returning - // an array of two items for a root: [ '//node_modules', '/node_modules' ] - if (from === '/') - return ['/node_modules']; - - // note: this approach *only* works when the path is guaranteed - // to be absolute. Doing a fully-edge-case-correct path.split - // that works on both Windows and Posix is non-trivial. - const paths = []; - var p = 0; - var last = from.length; - for (var i = from.length - 1; i >= 0; --i) { - const code = from.charCodeAt(i); - if (code === 47/*/*/) { - if (p !== nmLen) - paths.push(from.slice(0, last) + '/node_modules'); - last = i; - p = 0; - } else if (p !== -1) { - if (nmChars[p] === code) { - ++p; - } else { - p = -1; - } - } - } - - // Append /node_modules to handle root paths. - paths.push('/node_modules'); - - return paths; - }; -} - - -// 'index.' character codes -var indexChars = [ 105, 110, 100, 101, 120, 46 ]; -var indexLen = indexChars.length; -Module._resolveLookupPaths = function(request, parent, newReturn) { - if (NativeModule.nonInternalExists(request)) { - debug('looking for %j in []', request); - return (newReturn ? null : [request, []]); - } - - // Check for relative path - if (request.length < 2 || - request.charCodeAt(0) !== 46/*.*/ || - (request.charCodeAt(1) !== 46/*.*/ && - request.charCodeAt(1) !== 47/*/*/)) { - var paths = modulePaths; - if (parent) { - if (!parent.paths) - paths = parent.paths = []; - else - paths = parent.paths.concat(paths); - } - - // Maintain backwards compat with certain broken uses of require('.') - // by putting the module's directory in front of the lookup paths. - if (request === '.') { - if (parent && parent.filename) { - paths.unshift(path.dirname(parent.filename)); - } else { - paths.unshift(path.resolve(request)); - } - } - - debug('looking for %j in %j', request, paths); - return (newReturn ? (paths.length > 0 ? paths : null) : [request, paths]); - } - - // with --eval, parent.id is not set and parent.filename is null - if (!parent || !parent.id || !parent.filename) { - // make require('./path/to/foo') work - normally the path is taken - // from realpath(__filename) but with eval there is no filename - var mainPaths = ['.'].concat(Module._nodeModulePaths('.'), modulePaths); - - debug('looking for %j in %j', request, mainPaths); - return (newReturn ? mainPaths : [request, mainPaths]); - } - - // Is the parent an index module? - // We can assume the parent has a valid extension, - // as it already has been accepted as a module. - const base = path.basename(parent.filename); - var parentIdPath; - if (base.length > indexLen) { - var i = 0; - for (; i < indexLen; ++i) { - if (indexChars[i] !== base.charCodeAt(i)) - break; - } - if (i === indexLen) { - // We matched 'index.', let's validate the rest - for (; i < base.length; ++i) { - const code = base.charCodeAt(i); - if (code !== 95/*_*/ && - (code < 48/*0*/ || code > 57/*9*/) && - (code < 65/*A*/ || code > 90/*Z*/) && - (code < 97/*a*/ || code > 122/*z*/)) - break; - } - if (i === base.length) { - // Is an index module - parentIdPath = parent.id; - } else { - // Not an index module - parentIdPath = path.dirname(parent.id); - } - } else { - // Not an index module - parentIdPath = path.dirname(parent.id); - } - } else { - // Not an index module - parentIdPath = path.dirname(parent.id); - } - var id = path.resolve(parentIdPath, request); - - // make sure require('./path') and require('path') get distinct ids, even - // when called from the toplevel js file - if (parentIdPath === '.' && id.indexOf('/') === -1) { - id = './' + id; - } - - debug('RELATIVE: requested: %s set ID to: %s from %s', request, id, - parent.id); - - var parentDir = [path.dirname(parent.filename)]; - debug('looking for %j in %j', id, parentDir); - return (newReturn ? parentDir : [id, parentDir]); -}; - -// 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 -// 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 -// object. -Module._load = function(request, parent, isMain) { - if (parent) { - debug('Module._load REQUEST %s parent: %s', request, parent.id); - } - - if (experimentalModules && isMain) { - internalESModule.loaderPromise.then((loader) => { - return loader.import(getURLFromFilePath(request).pathname); - }) - .catch((e) => { - decorateErrorStack(e); - console.error(e); - process.exit(1); - }); - return; - } - - var filename = Module._resolveFilename(request, parent, isMain); - - var cachedModule = Module._cache[filename]; - if (cachedModule) { - updateChildren(parent, cachedModule, true); - return cachedModule.exports; - } - - if (NativeModule.nonInternalExists(filename)) { - debug('load native module %s', request); - return NativeModule.require(filename); - } - - // Don't call updateChildren(), Module constructor already does. - var module = new Module(filename, parent); - - if (isMain) { - process.mainModule = module; - module.id = '.'; - } - - Module._cache[filename] = module; - - tryModuleLoad(module, filename); - - return module.exports; -}; - -function tryModuleLoad(module, filename) { - var threw = true; - try { - module.load(filename); - threw = false; - } finally { - if (threw) { - delete Module._cache[filename]; - } - } -} - -Module._resolveFilename = function(request, parent, isMain, options) { - if (NativeModule.nonInternalExists(request)) { - return request; - } - - var paths; - - if (typeof options === 'object' && options !== null && - Array.isArray(options.paths)) { - const fakeParent = new Module('', null); - - paths = []; - - for (var i = 0; i < options.paths.length; i++) { - const path = options.paths[i]; - fakeParent.paths = Module._nodeModulePaths(path); - const lookupPaths = Module._resolveLookupPaths(request, fakeParent, 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); - if (!filename) { - var err = new Error(`Cannot find module '${request}'`); - err.code = 'MODULE_NOT_FOUND'; - throw err; - } - return filename; -}; - - -// Given a file name, pass it to the proper extension handler. -Module.prototype.load = function(filename) { - debug('load %j for module %j', filename, this.id); - - assert(!this.loaded); - this.filename = filename; - this.paths = Module._nodeModulePaths(path.dirname(filename)); - - var extension = path.extname(filename) || '.js'; - if (!Module._extensions[extension]) extension = '.js'; - Module._extensions[extension](this, filename); - this.loaded = true; - - if (experimentalModules) { - const ESMLoader = internalESModule.ESMLoader; - const url = getURLFromFilePath(filename); - const urlString = `${url}`; - const exports = this.exports; - if (ESMLoader.moduleMap.has(urlString) !== true) { - ESMLoader.moduleMap.set( - urlString, - new ModuleJob(ESMLoader, url, async () => { - const ctx = createDynamicModule( - ['default'], url); - ctx.reflect.exports.default.set(exports); - return ctx; - }) - ); - } else { - const job = ESMLoader.moduleMap.get(urlString); - if (job.reflect) - job.reflect.exports.default.set(exports); - } - } -}; - - -// Loads a module at the given file path. Returns that module's -// `exports` property. -Module.prototype.require = function(path) { - assert(path, 'missing path'); - assert(typeof path === 'string', 'path must be a string'); - return Module._load(path, this, /* isMain */ false); -}; - - -// Resolved path to process.argv[1] will be lazily placed here -// (needed for setting breakpoint when called with --inspect-brk) -var resolvedArgv; - - -// Run the file contents in the correct scope or sandbox. Expose -// the correct helper variables (require, module, exports) to -// the file. -// Returns exception, if any. -Module.prototype._compile = function(content, filename) { - - content = internalModule.stripShebang(content); - - // create wrapper function - var wrapper = Module.wrap(content); - - var compiledWrapper = vm.runInThisContext(wrapper, { - filename: filename, - lineOffset: 0, - displayErrors: true - }); - - var inspectorWrapper = null; - if (process._breakFirstLine && process._eval == null) { - if (!resolvedArgv) { - // we enter the repl if we're not given a filename argument. - if (process.argv[1]) { - resolvedArgv = Module._resolveFilename(process.argv[1], null, false); - } else { - resolvedArgv = 'repl'; - } - } - - // Set breakpoint on module start - if (filename === resolvedArgv) { - delete process._breakFirstLine; - inspectorWrapper = process.binding('inspector').callAndPauseOnStart; - if (!inspectorWrapper) { - const Debug = vm.runInDebugContext('Debug'); - Debug.setBreakPoint(compiledWrapper, 0, 0); - } - } - } - var dirname = path.dirname(filename); - var require = internalModule.makeRequireFunction(this); - var depth = internalModule.requireDepth; - if (depth === 0) stat.cache = new Map(); - var result; - if (inspectorWrapper) { - result = inspectorWrapper(compiledWrapper, this.exports, this.exports, - require, this, filename, dirname); - } else { - result = compiledWrapper.call(this.exports, this.exports, require, this, - filename, dirname); - } - if (depth === 0) stat.cache = null; - return result; -}; - - -// Native extension for .js -Module._extensions['.js'] = function(module, filename) { - var content = fs.readFileSync(filename, 'utf8'); - module._compile(internalModule.stripBOM(content), filename); -}; - - -// Native extension for .json -Module._extensions['.json'] = function(module, filename) { - var content = fs.readFileSync(filename, 'utf8'); - try { - module.exports = JSON.parse(internalModule.stripBOM(content)); - } catch (err) { - err.message = filename + ': ' + err.message; - throw err; - } -}; - - -//Native extension for .node -Module._extensions['.node'] = function(module, filename) { - return process.dlopen(module, path.toNamespacedPath(filename)); -}; - -if (experimentalModules) { - Module._extensions['.mjs'] = function(module, filename) { - throw new errors.Error('ERR_REQUIRE_ESM', filename); - }; -} - -// bootstrap main module. -Module.runMain = function() { - // Load the main module--the command line argument. - Module._load(process.argv[1], null, true); - // Handle any nextTicks added in the first tick of the program - process._tickCallback(); -}; - -Module._initPaths = function() { - const isWindows = process.platform === 'win32'; - - var homeDir; - if (isWindows) { - homeDir = process.env.USERPROFILE; - } else { - homeDir = process.env.HOME; - } - - // $PREFIX/lib/node, where $PREFIX is the root of the Node.js installation. - var prefixDir; - // process.execPath is $PREFIX/bin/node except on Windows where it is - // $PREFIX\node.exe. - if (isWindows) { - prefixDir = path.resolve(process.execPath, '..'); - } else { - prefixDir = path.resolve(process.execPath, '..', '..'); - } - var paths = [path.resolve(prefixDir, 'lib', 'node')]; - - if (homeDir) { - paths.unshift(path.resolve(homeDir, '.node_libraries')); - paths.unshift(path.resolve(homeDir, '.node_modules')); - } - - var nodePath = process.env.NODE_PATH; - if (nodePath) { - paths = nodePath.split(path.delimiter).filter(function(path) { - return !!path; - }).concat(paths); - } - - modulePaths = paths; - - // clone as a shallow copy, for introspection. - Module.globalPaths = modulePaths.slice(0); -}; - -Module._preloadModules = function(requests) { - if (!Array.isArray(requests)) - return; - - // Preloaded modules have a dummy parent module which is deemed to exist - // in the current working directory. This seeds the search path for - // preloaded modules. - var parent = new Module('internal/preload', null); - try { - parent.paths = Module._nodeModulePaths(process.cwd()); - } catch (e) { - if (e.code !== 'ENOENT') { - throw e; - } - } - for (var n = 0; n < requests.length; n++) - parent.require(requests[n]); -}; - -Module._initPaths(); - -// backwards compatibility -Module.Module = Module; +module.exports = require('internal/modules/cjs/loader'); diff --git a/lib/repl.js b/lib/repl.js index 5779e849f06017..83d6b59a721061 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -42,7 +42,11 @@ 'use strict'; -const internalModule = require('internal/module'); +const { + builtinLibs, + makeRequireFunction, + addBuiltinLibsToObject +} = require('internal/modules/cjs/helpers'); const internalUtil = require('internal/util'); const { isTypedArray } = require('internal/util/types'); const util = require('util'); @@ -54,7 +58,7 @@ const path = require('path'); const fs = require('fs'); const { Interface } = require('readline'); const { Console } = require('console'); -const Module = require('module'); +const CJSModule = require('internal/modules/cjs/loader'); const domain = require('domain'); const debug = util.debuglog('repl'); const errors = require('internal/errors'); @@ -90,7 +94,7 @@ try { } // Hack for repl require to work properly with node_modules folders -module.paths = Module._nodeModulePaths(module.filename); +module.paths = CJSModule._nodeModulePaths(module.filename); // If obj.hasOwnProperty has been overridden, then calling // obj.hasOwnProperty(prop) will break. @@ -103,7 +107,7 @@ function hasOwnProperty(obj, prop) { // This is the default "writer" value if none is passed in the REPL options. exports.writer = util.inspect; -exports._builtinLibs = internalModule.builtinLibs; +exports._builtinLibs = builtinLibs; function REPLServer(prompt, stream, @@ -673,14 +677,15 @@ REPLServer.prototype.createContext = function() { } } - var module = new Module(''); - module.paths = Module._resolveLookupPaths('', parentModule, true) || []; + var module = new CJSModule(''); + module.paths = + CJSModule._resolveLookupPaths('', parentModule, true) || []; - var require = internalModule.makeRequireFunction(module); + var require = makeRequireFunction(module); context.module = module; context.require = require; - internalModule.addBuiltinLibsToObject(context); + addBuiltinLibsToObject(context); return context; }; @@ -889,7 +894,7 @@ function complete(line, callback) { } else if (/^\.\.?\//.test(completeOn)) { paths = [process.cwd()]; } else { - paths = module.paths.concat(Module.globalPaths); + paths = module.paths.concat(CJSModule.globalPaths); } for (i = 0; i < paths.length; i++) { diff --git a/node.gyp b/node.gyp index 1ab7b207e21339..7e77dacce34f05 100644 --- a/node.gyp +++ b/node.gyp @@ -25,7 +25,8 @@ 'node_lib_target_name%': 'node_lib', 'node_intermediate_lib_type%': 'static_library', 'library_files': [ - 'lib/internal/bootstrap_node.js', + 'lib/internal/bootstrap/loaders.js', + 'lib/internal/bootstrap/node.js', 'lib/async_hooks.js', 'lib/assert.js', 'lib/buffer.js', @@ -104,18 +105,19 @@ 'lib/internal/http.js', 'lib/internal/inspector_async_hook.js', 'lib/internal/linkedlist.js', - 'lib/internal/loader/Loader.js', - 'lib/internal/loader/CreateDynamicModule.js', - 'lib/internal/loader/DefaultResolve.js', - 'lib/internal/loader/ModuleJob.js', - 'lib/internal/loader/ModuleMap.js', - 'lib/internal/loader/ModuleWrap.js', - 'lib/internal/loader/Translators.js', + 'lib/internal/modules/cjs/helpers.js', + 'lib/internal/modules/cjs/loader.js', + 'lib/internal/modules/esm/Loader.js', + 'lib/internal/modules/esm/CreateDynamicModule.js', + 'lib/internal/modules/esm/DefaultResolve.js', + 'lib/internal/modules/esm/ModuleJob.js', + 'lib/internal/modules/esm/ModuleMap.js', + 'lib/internal/modules/esm/ModuleWrap.js', + 'lib/internal/modules/esm/Translators.js', 'lib/internal/safe_globals.js', 'lib/internal/net.js', - 'lib/internal/module.js', 'lib/internal/os.js', - 'lib/internal/process/modules.js', + 'lib/internal/process/esm_loader.js', 'lib/internal/process/next_tick.js', 'lib/internal/process/promises.js', 'lib/internal/process/stdio.js', diff --git a/src/node.cc b/src/node.cc index a180f97cd4140e..33ed558cfe14ba 100644 --- a/src/node.cc +++ b/src/node.cc @@ -250,7 +250,7 @@ bool config_experimental_vm_modules = false; // Set in node.cc by ParseArgs when --loader is used. // Used in node_config.cc to set a constant on process.binding('config') -// that is used by lib/internal/bootstrap_node.js +// that is used by lib/internal/bootstrap/node.js std::string config_userland_loader; // NOLINT(runtime/string) // Set by ParseArgs when --pending-deprecation or NODE_PENDING_DEPRECATION @@ -263,7 +263,7 @@ std::string config_warning_file; // NOLINT(runtime/string) // Set in node.cc by ParseArgs when --expose-internals or --expose_internals is // used. // Used in node_config.cc to set a constant on process.binding('config') -// that is used by lib/internal/bootstrap_node.js +// that is used by lib/internal/bootstrap/node.js bool config_expose_internals = false; bool v8_initialized = false; @@ -2854,7 +2854,7 @@ static void ThrowIfNoSuchModule(Environment* env, const char* module_v) { env->ThrowError(errmsg); } -static void Binding(const FunctionCallbackInfo& args) { +static void GetBinding(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); CHECK(args[0]->IsString()); @@ -2881,7 +2881,7 @@ static void Binding(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(exports); } -static void InternalBinding(const FunctionCallbackInfo& args) { +static void GetInternalBinding(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); CHECK(args[0]->IsString()); @@ -2896,7 +2896,7 @@ static void InternalBinding(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(exports); } -static void LinkedBinding(const FunctionCallbackInfo& args) { +static void GetLinkedBinding(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args.GetIsolate()); CHECK(args[0]->IsString()); @@ -3596,10 +3596,6 @@ void SetupProcessObject(Environment* env, env->SetMethod(process, "uptime", Uptime); env->SetMethod(process, "memoryUsage", MemoryUsage); - env->SetMethod(process, "binding", Binding); - env->SetMethod(process, "_linkedBinding", LinkedBinding); - env->SetMethod(process, "_internalBinding", InternalBinding); - env->SetMethod(process, "_setupProcessObject", SetupProcessObject); env->SetMethod(process, "_setupNextTick", SetupNextTick); env->SetMethod(process, "_setupPromises", SetupPromises); @@ -3637,8 +3633,10 @@ static void RawDebug(const FunctionCallbackInfo& args) { fflush(stderr); } -void LoadEnvironment(Environment* env) { - HandleScope handle_scope(env->isolate()); + +static Local GetBootstrapper(Environment* env, Local source, + Local script_name) { + EscapableHandleScope scope(env->isolate()); TryCatch try_catch(env->isolate()); @@ -3647,20 +3645,61 @@ void LoadEnvironment(Environment* env) { // are not safe to ignore. try_catch.SetVerbose(false); - // Execute the lib/internal/bootstrap_node.js file which was included as a - // static C string in node_natives.h by node_js2c. - // 'internal_bootstrap_node_native' is the string containing that source code. - Local script_name = FIXED_ONE_BYTE_STRING(env->isolate(), - "bootstrap_node.js"); - Local f_value = ExecuteString(env, MainSource(env), script_name); + // Execute the bootstrapper javascript file + Local bootstrapper_v = ExecuteString(env, source, script_name); if (try_catch.HasCaught()) { ReportException(env, try_catch); exit(10); } - // The bootstrap_node.js file returns a function 'f' - CHECK(f_value->IsFunction()); - Local f = Local::Cast(f_value); + CHECK(bootstrapper_v->IsFunction()); + Local bootstrapper = Local::Cast(bootstrapper_v); + + return scope.Escape(bootstrapper); +} + +static bool ExecuteBootstrapper(Environment* env, Local bootstrapper, + int argc, Local argv[], + Local* out) { + bool ret = bootstrapper->Call( + env->context(), Null(env->isolate()), argc, argv).ToLocal(out); + + // If there was an error during bootstrap then it was either handled by the + // FatalException handler or it's unrecoverable (e.g. max call stack + // exceeded). Either way, clear the stack so that the AsyncCallbackScope + // destructor doesn't fail on the id check. + // There are only two ways to have a stack size > 1: 1) the user manually + // called MakeCallback or 2) user awaited during bootstrap, which triggered + // _tickCallback(). + if (!ret) { + env->async_hooks()->clear_async_id_stack(); + } + + return ret; +} + + +void LoadEnvironment(Environment* env) { + HandleScope handle_scope(env->isolate()); + + TryCatch try_catch(env->isolate()); + // Disable verbose mode to stop FatalException() handler from trying + // to handle the exception. Errors this early in the start-up phase + // are not safe to ignore. + try_catch.SetVerbose(false); + + // The bootstrapper scripts are lib/internal/bootstrap/loaders.js and + // lib/internal/bootstrap/node.js, each included as a static C string + // defined in node_javascript.h, generated in node_javascript.cc by + // node_js2c. + Local loaders_name = + FIXED_ONE_BYTE_STRING(env->isolate(), "internal/bootstrap/loaders.js"); + Local loaders_bootstrapper = + GetBootstrapper(env, LoadersBootstrapperSource(env), loaders_name); + Local node_name = + FIXED_ONE_BYTE_STRING(env->isolate(), "internal/bootstrap/node.js"); + Local node_bootstrapper = + GetBootstrapper(env, NodeBootstrapperSource(env), node_name); // Add a reference to the global object Local global = env->context()->Global(); @@ -3691,25 +3730,47 @@ void LoadEnvironment(Environment* env) { // (Allows you to set stuff on `global` from anywhere in JavaScript.) global->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "global"), global); - // Now we call 'f' with the 'process' variable that we've built up with - // all our bindings. Inside bootstrap_node.js and internal/process we'll - // take care of assigning things to their places. + // Create binding loaders + v8::Local get_binding_fn = + env->NewFunctionTemplate(GetBinding)->GetFunction(env->context()) + .ToLocalChecked(); - // We start the process this way in order to be more modular. Developers - // who do not like how bootstrap_node.js sets up the module system but do - // like Node's I/O bindings may want to replace 'f' with their own function. - Local arg = env->process_object(); + v8::Local get_linked_binding_fn = + env->NewFunctionTemplate(GetLinkedBinding)->GetFunction(env->context()) + .ToLocalChecked(); - auto ret = f->Call(env->context(), Null(env->isolate()), 1, &arg); - // If there was an error during bootstrap then it was either handled by the - // FatalException handler or it's unrecoverable (e.g. max call stack - // exceeded). Either way, clear the stack so that the AsyncCallbackScope - // destructor doesn't fail on the id check. - // There are only two ways to have a stack size > 1: 1) the user manually - // called MakeCallback or 2) user awaited during bootstrap, which triggered - // _tickCallback(). - if (ret.IsEmpty()) - env->async_hooks()->clear_async_id_stack(); + v8::Local get_internal_binding_fn = + env->NewFunctionTemplate(GetInternalBinding)->GetFunction(env->context()) + .ToLocalChecked(); + + Local loaders_bootstrapper_args[] = { + env->process_object(), + get_binding_fn, + get_linked_binding_fn, + get_internal_binding_fn + }; + + // Bootstrap internal loaders + Local bootstrapped_loaders; + if (!ExecuteBootstrapper(env, loaders_bootstrapper, + arraysize(loaders_bootstrapper_args), + loaders_bootstrapper_args, + &bootstrapped_loaders)) { + return; + } + + // Bootstrap Node.js + Local bootstrapped_node; + Local node_bootstrapper_args[] = { + env->process_object(), + bootstrapped_loaders + }; + if (!ExecuteBootstrapper(env, node_bootstrapper, + arraysize(node_bootstrapper_args), + node_bootstrapper_args, + &bootstrapped_node)) { + return; + } } static void PrintHelp() { diff --git a/src/node_internals.h b/src/node_internals.h index 46a1be4e19b433..27ab40a39f5998 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -180,13 +180,13 @@ extern bool config_experimental_vm_modules; // Set in node.cc by ParseArgs when --loader is used. // Used in node_config.cc to set a constant on process.binding('config') -// that is used by lib/internal/bootstrap_node.js +// that is used by lib/internal/bootstrap/node.js extern std::string config_userland_loader; // Set in node.cc by ParseArgs when --expose-internals or --expose_internals is // used. // Used in node_config.cc to set a constant on process.binding('config') -// that is used by lib/internal/bootstrap_node.js +// that is used by lib/internal/bootstrap/node.js extern bool config_expose_internals; // Set in node.cc by ParseArgs when --redirect-warnings= is used. diff --git a/src/node_javascript.h b/src/node_javascript.h index 664778091ff669..d1ad9a25745e9b 100644 --- a/src/node_javascript.h +++ b/src/node_javascript.h @@ -29,7 +29,8 @@ namespace node { void DefineJavaScript(Environment* env, v8::Local target); -v8::Local MainSource(Environment* env); +v8::Local LoadersBootstrapperSource(Environment* env); +v8::Local NodeBootstrapperSource(Environment* env); } // namespace node diff --git a/src/node_url.cc b/src/node_url.cc index cac2831af6ef7f..6b56628d753f60 100644 --- a/src/node_url.cc +++ b/src/node_url.cc @@ -2275,7 +2275,7 @@ const Local URL::ToObject(Environment* env) const { // The SetURLConstructor method must have been called already to // set the constructor function used below. SetURLConstructor is // called automatically when the internal/url.js module is loaded - // during the internal/bootstrap_node.js processing. + // during the internal/bootstrap/node.js processing. ret = env->url_constructor_function() ->Call(env->context(), undef, arraysize(argv), argv); } diff --git a/test/es-module/test-esm-loader-modulemap.js b/test/es-module/test-esm-loader-modulemap.js index 1c1623b680e7bd..e9faa6d9f122f4 100644 --- a/test/es-module/test-esm-loader-modulemap.js +++ b/test/es-module/test-esm-loader-modulemap.js @@ -7,10 +7,10 @@ const common = require('../common'); const { URL } = require('url'); -const Loader = require('internal/loader/Loader'); -const ModuleMap = require('internal/loader/ModuleMap'); -const ModuleJob = require('internal/loader/ModuleJob'); -const createDynamicModule = require('internal/loader/CreateDynamicModule'); +const Loader = require('internal/modules/esm/Loader'); +const ModuleMap = require('internal/modules/esm/ModuleMap'); +const ModuleJob = require('internal/modules/esm/ModuleJob'); +const createDynamicModule = require('internal/modules/esm/CreateDynamicModule'); const stubModuleUrl = new URL('file://tmp/test'); const stubModule = createDynamicModule(['default'], stubModuleUrl); diff --git a/test/es-module/test-esm-loader-search.js b/test/es-module/test-esm-loader-search.js index 4eb6b9fd4b3889..5a1f5a562a0d3e 100644 --- a/test/es-module/test-esm-loader-search.js +++ b/test/es-module/test-esm-loader-search.js @@ -5,7 +5,7 @@ const common = require('../common'); -const { search } = require('internal/loader/DefaultResolve'); +const { search } = require('internal/modules/esm/DefaultResolve'); const errors = require('internal/errors'); common.expectsError( diff --git a/test/fixtures/module-require-depth/one.js b/test/fixtures/module-require-depth/one.js index 5927908b7540ab..02b451465bb76c 100644 --- a/test/fixtures/module-require-depth/one.js +++ b/test/fixtures/module-require-depth/one.js @@ -1,9 +1,11 @@ // Flags: --expose_internals 'use strict'; const assert = require('assert'); -const internalModule = require('internal/module'); +const { + requireDepth +} = require('internal/modules/cjs/helpers'); -exports.requireDepth = internalModule.requireDepth; -assert.strictEqual(internalModule.requireDepth, 1); +exports.requireDepth = requireDepth; +assert.strictEqual(requireDepth, 1); assert.deepStrictEqual(require('./two'), { requireDepth: 2 }); -assert.strictEqual(internalModule.requireDepth, 1); +assert.strictEqual(requireDepth, 1); diff --git a/test/fixtures/module-require-depth/two.js b/test/fixtures/module-require-depth/two.js index aea49947d1152d..5c94c4c89aa9ef 100644 --- a/test/fixtures/module-require-depth/two.js +++ b/test/fixtures/module-require-depth/two.js @@ -1,9 +1,11 @@ // Flags: --expose_internals 'use strict'; const assert = require('assert'); -const internalModule = require('internal/module'); +const { + requireDepth +} = require('internal/modules/cjs/helpers'); -exports.requireDepth = internalModule.requireDepth; -assert.strictEqual(internalModule.requireDepth, 2); +exports.requireDepth = requireDepth; +assert.strictEqual(requireDepth, 2); assert.deepStrictEqual(require('./one'), { requireDepth: 1 }); -assert.strictEqual(internalModule.requireDepth, 2); +assert.strictEqual(requireDepth, 2); diff --git a/test/message/core_line_numbers.out b/test/message/core_line_numbers.out index 1049fdc3e935df..b50e1678f49fb7 100644 --- a/test/message/core_line_numbers.out +++ b/test/message/core_line_numbers.out @@ -6,10 +6,10 @@ RangeError: Invalid input at error (punycode.js:42:*) at Object.decode (punycode.js:*:*) at Object. (*test*message*core_line_numbers.js:*:*) - at Module._compile (module.js:*:*) - at Object.Module._extensions..js (module.js:*:*) - at Module.load (module.js:*:*) - at tryModuleLoad (module.js:*:*) - at Function.Module._load (module.js:*:*) - at Function.Module.runMain (module.js:*:*) - at startup (bootstrap_node.js:*:*) + at Module._compile (internal/modules/cjs/loader.js:*:*) + at Object.Module._extensions..js (internal/modules/cjs/loader.js:*:*) + at Module.load (internal/modules/cjs/loader.js:*:*) + at tryModuleLoad (internal/modules/cjs/loader.js:*:*) + at Function.Module._load (internal/modules/cjs/loader.js:*:*) + at Function.Module.runMain (internal/modules/cjs/loader.js:*:*) + at startup (internal/bootstrap/node.js:*:*) diff --git a/test/message/error_exit.out b/test/message/error_exit.out index 8f03f08a7e0392..fd580c389af0bd 100644 --- a/test/message/error_exit.out +++ b/test/message/error_exit.out @@ -5,11 +5,11 @@ assert.js:* AssertionError [ERR_ASSERTION]: 1 === 2 at Object. (*test*message*error_exit.js:*:*) - at Module._compile (module.js:*:*) - at Object.Module._extensions..js (module.js:*:*) - at Module.load (module.js:*:*) - at tryModuleLoad (module.js:*:*) - at Function.Module._load (module.js:*:*) - at Function.Module.runMain (module.js:*:*) - at startup (bootstrap_node.js:*:*) - at bootstrap_node.js:*:* + at Module._compile (internal/modules/cjs/loader.js:*:*) + at Object.Module._extensions..js (internal/modules/cjs/loader.js:*:*) + at Module.load (internal/modules/cjs/loader.js:*:*) + at tryModuleLoad (internal/modules/cjs/loader.js:*:*) + at Function.Module._load (internal/modules/cjs/loader.js:*:*) + at Function.Module.runMain (internal/modules/cjs/loader.js:*:*) + at startup (internal/bootstrap/node.js:*:*) + at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) diff --git a/test/message/esm_display_syntax_error.out b/test/message/esm_display_syntax_error.out index a47a7e1339273f..73c9495824038e 100644 --- a/test/message/esm_display_syntax_error.out +++ b/test/message/esm_display_syntax_error.out @@ -3,5 +3,5 @@ file:///*/test/message/esm_display_syntax_error.mjs:3 await async () => 0; ^^^^^ SyntaxError: Unexpected reserved word - at translators.set (internal/loader/Translators.js:*:*) + at translators.set (internal/modules/esm/Translators.js:*:*) at diff --git a/test/message/esm_display_syntax_error_import.out b/test/message/esm_display_syntax_error_import.out index 1fb7fdc34a7de4..e257f0eb7a94e5 100644 --- a/test/message/esm_display_syntax_error_import.out +++ b/test/message/esm_display_syntax_error_import.out @@ -3,5 +3,5 @@ file:///*/test/message/esm_display_syntax_error_import.mjs:6 notfound ^^^^^^^^ SyntaxError: The requested module does not provide an export named 'notfound' - at ModuleJob._instantiate (internal/loader/ModuleJob.js:*:*) + at ModuleJob._instantiate (internal/modules/esm/ModuleJob.js:*:*) at diff --git a/test/message/esm_display_syntax_error_import_module.out b/test/message/esm_display_syntax_error_import_module.out index 77fd63891f1ea0..c6286a2a987282 100644 --- a/test/message/esm_display_syntax_error_import_module.out +++ b/test/message/esm_display_syntax_error_import_module.out @@ -3,5 +3,5 @@ file:///*/test/fixtures/es-module-loaders/syntax-error-import.mjs:1 import { foo, notfound } from './module-named-exports'; ^^^^^^^^ SyntaxError: The requested module does not provide an export named 'notfound' - at ModuleJob._instantiate (internal/loader/ModuleJob.js:*:*) + at ModuleJob._instantiate (internal/modules/esm/ModuleJob.js:*:*) at diff --git a/test/message/esm_display_syntax_error_module.out b/test/message/esm_display_syntax_error_module.out index 23da9f350e5efe..122e352102ad0f 100644 --- a/test/message/esm_display_syntax_error_module.out +++ b/test/message/esm_display_syntax_error_module.out @@ -3,5 +3,5 @@ file:///*/test/fixtures/es-module-loaders/syntax-error.mjs:2 await async () => 0; ^^^^^ SyntaxError: Unexpected reserved word - at translators.set (internal/loader/Translators.js:*:*) + at translators.set (internal/modules/esm/Translators.js:*:*) at diff --git a/test/message/eval_messages.out b/test/message/eval_messages.out index 6c725cb1cc8a14..d01dfe547cbd73 100644 --- a/test/message/eval_messages.out +++ b/test/message/eval_messages.out @@ -7,10 +7,10 @@ SyntaxError: Strict mode code may not include a with statement at createScript (vm.js:*:*) at Object.runInThisContext (vm.js:*:*) at Object. ([eval]-wrapper:*:*) - at Module._compile (module.js:*:*) - at evalScript (bootstrap_node.js:*:*) - at startup (bootstrap_node.js:*:*) - at bootstrap_node.js:*:* + at Module._compile (internal/modules/cjs/loader.js:*:*) + at evalScript (internal/bootstrap/node.js:*:*) + at startup (internal/bootstrap/node.js:*:*) + at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) 42 42 [eval]:1 @@ -22,10 +22,10 @@ Error: hello at Script.runInThisContext (vm.js:*:*) at Object.runInThisContext (vm.js:*:*) at Object. ([eval]-wrapper:*:*) - at Module._compile (module.js:*:*) - at evalScript (bootstrap_node.js:*:*) - at startup (bootstrap_node.js:*:*) - at bootstrap_node.js:*:* + at Module._compile (internal/modules/cjs/loader.js:*:*) + at evalScript (internal/bootstrap/node.js:*:*) + at startup (internal/bootstrap/node.js:*:*) + at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) [eval]:1 throw new Error("hello") @@ -36,10 +36,10 @@ Error: hello at Script.runInThisContext (vm.js:*:*) at Object.runInThisContext (vm.js:*:*) at Object. ([eval]-wrapper:*:*) - at Module._compile (module.js:*:*) - at evalScript (bootstrap_node.js:*:*) - at startup (bootstrap_node.js:*:*) - at bootstrap_node.js:*:* + at Module._compile (internal/modules/cjs/loader.js:*:*) + at evalScript (internal/bootstrap/node.js:*:*) + at startup (internal/bootstrap/node.js:*:*) + at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) 100 [eval]:1 var x = 100; y = x; @@ -50,10 +50,10 @@ ReferenceError: y is not defined at Script.runInThisContext (vm.js:*:*) at Object.runInThisContext (vm.js:*:*) at Object. ([eval]-wrapper:*:*) - at Module._compile (module.js:*:*) - at evalScript (bootstrap_node.js:*:*) - at startup (bootstrap_node.js:*:*) - at bootstrap_node.js:*:* + at Module._compile (internal/modules/cjs/loader.js:*:*) + at evalScript (internal/bootstrap/node.js:*:*) + at startup (internal/bootstrap/node.js:*:*) + at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) [eval]:1 var ______________________________________________; throw 10 diff --git a/test/message/events_unhandled_error_common_trace.out b/test/message/events_unhandled_error_common_trace.out index d39a95cb77f068..f6b74e9991306b 100644 --- a/test/message/events_unhandled_error_common_trace.out +++ b/test/message/events_unhandled_error_common_trace.out @@ -6,17 +6,17 @@ Error: foo:bar at bar (*events_unhandled_error_common_trace.js:*:*) at foo (*events_unhandled_error_common_trace.js:*:*) at Object. (*events_unhandled_error_common_trace.js:*:*) - at Module._compile (module.js:*:*) - at Object.Module._extensions..js (module.js:*:*) - at Module.load (module.js:*:*) - at tryModuleLoad (module.js:*:*) - at Function.Module._load (module.js:*:*) - at Function.Module.runMain (module.js:*:*) - at startup (bootstrap_node.js:*:*) + at Module._compile (internal/modules/cjs/loader.js:*:*) + at Object.Module._extensions..js (internal/modules/cjs/loader.js:*:*) + at Module.load (internal/modules/cjs/loader.js:*:*) + at tryModuleLoad (internal/modules/cjs/loader.js:*:*) + at Function.Module._load (internal/modules/cjs/loader.js:*:*) + at Function.Module.runMain (internal/modules/cjs/loader.js:*:*) + at startup (internal/bootstrap/node.js:*:*) Emitted 'error' event at: at quux (*events_unhandled_error_common_trace.js:*:*) at Object. (*events_unhandled_error_common_trace.js:*:*) - at Module._compile (module.js:*:*) + at Module._compile (internal/modules/cjs/loader.js:*:*) [... lines matching original stack trace ...] - at startup (bootstrap_node.js:*:*) - at bootstrap_node.js:*:* + at startup (internal/bootstrap/node.js:*:*) + at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) diff --git a/test/message/events_unhandled_error_nexttick.out b/test/message/events_unhandled_error_nexttick.out index f0591610ffdb31..e00580ce93cf45 100644 --- a/test/message/events_unhandled_error_nexttick.out +++ b/test/message/events_unhandled_error_nexttick.out @@ -4,17 +4,17 @@ events.js:* Error at Object. (*events_unhandled_error_nexttick.js:*:*) - at Module._compile (module.js:*:*) - at Object.Module._extensions..js (module.js:*:*) - at Module.load (module.js:*:*) - at tryModuleLoad (module.js:*:*) - at Function.Module._load (module.js:*:*) - at Function.Module.runMain (module.js:*:*) - at startup (bootstrap_node.js:*:*) - at bootstrap_node.js:*:* + at Module._compile (internal/modules/cjs/loader.js:*:*) + at Object.Module._extensions..js (internal/modules/cjs/loader.js:*:*) + at Module.load (internal/modules/cjs/loader.js:*:*) + at tryModuleLoad (internal/modules/cjs/loader.js:*:*) + at Function.Module._load (internal/modules/cjs/loader.js:*:*) + at Function.Module.runMain (internal/modules/cjs/loader.js:*:*) + at startup (internal/bootstrap/node.js:*:*) + at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) Emitted 'error' event at: at process.nextTick (*events_unhandled_error_nexttick.js:*:*) at process._tickCallback (internal/process/next_tick.js:*:*) - at Function.Module.runMain (module.js:*:*) - at startup (bootstrap_node.js:*:*) - at bootstrap_node.js:*:* + at Function.Module.runMain (internal/modules/cjs/loader.js:*:*) + at startup (internal/bootstrap/node.js:*:*) + at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) diff --git a/test/message/events_unhandled_error_sameline.out b/test/message/events_unhandled_error_sameline.out index 100c294276d04b..55841cdbc345d7 100644 --- a/test/message/events_unhandled_error_sameline.out +++ b/test/message/events_unhandled_error_sameline.out @@ -4,16 +4,16 @@ events.js:* Error at Object. (*events_unhandled_error_sameline.js:*:*) - at Module._compile (module.js:*:*) - at Object.Module._extensions..js (module.js:*:*) - at Module.load (module.js:*:*) - at tryModuleLoad (module.js:*:*) - at Function.Module._load (module.js:*:*) - at Function.Module.runMain (module.js:*:*) - at startup (bootstrap_node.js:*:*) - at bootstrap_node.js:*:* + at Module._compile (internal/modules/cjs/loader.js:*:*) + at Object.Module._extensions..js (internal/modules/cjs/loader.js:*:*) + at Module.load (internal/modules/cjs/loader.js:*:*) + at tryModuleLoad (internal/modules/cjs/loader.js:*:*) + at Function.Module._load (internal/modules/cjs/loader.js:*:*) + at Function.Module.runMain (internal/modules/cjs/loader.js:*:*) + at startup (internal/bootstrap/node.js:*:*) + at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) Emitted 'error' event at: at Object. (*events_unhandled_error_sameline.js:*:*) - at Module._compile (module.js:*:*) + at Module._compile (internal/modules/cjs/loader.js:*:*) [... lines matching original stack trace ...] - at bootstrap_node.js:*:* + at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) diff --git a/test/message/nexttick_throw.out b/test/message/nexttick_throw.out index 1c9eca8405d928..16e41f6343baec 100644 --- a/test/message/nexttick_throw.out +++ b/test/message/nexttick_throw.out @@ -5,6 +5,6 @@ ReferenceError: undefined_reference_error_maker is not defined at *test*message*nexttick_throw.js:*:* at process._tickCallback (internal/process/next_tick.js:*:*) - at Function.Module.runMain (module.js:*:*) - at startup (bootstrap_node.js:*:*) - at bootstrap_node.js:*:* + at Function.Module.runMain (internal/modules/cjs/loader.js:*:*) + at startup (internal/bootstrap/node.js:*:*) + at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) diff --git a/test/message/stdin_messages.out b/test/message/stdin_messages.out index d2192050dd4196..d4498b452aa6ba 100644 --- a/test/message/stdin_messages.out +++ b/test/message/stdin_messages.out @@ -7,9 +7,9 @@ SyntaxError: Strict mode code may not include a with statement at createScript (vm.js:*) at Object.runInThisContext (vm.js:*) at Object. ([stdin]-wrapper:*:*) - at Module._compile (module.js:*:*) - at evalScript (bootstrap_node.js:*:*) - at Socket. (bootstrap_node.js:*:*) + at Module._compile (internal/modules/cjs/loader.js:*:*) + at evalScript (internal/bootstrap/node.js:*:*) + at Socket. (internal/bootstrap/node.js:*:*) at Socket.emit (events.js:*:*) at endReadableNT (_stream_readable.js:*:*) at process._tickCallback (internal/process/next_tick.js:*:*) @@ -24,9 +24,9 @@ Error: hello at Script.runInThisContext (vm.js:*) at Object.runInThisContext (vm.js:*) at Object. ([stdin]-wrapper:*:*) - at Module._compile (module.js:*:*) - at evalScript (bootstrap_node.js:*:*) - at Socket. (bootstrap_node.js:*:*) + at Module._compile (internal/modules/cjs/loader.js:*:*) + at evalScript (internal/bootstrap/node.js:*:*) + at Socket. (internal/bootstrap/node.js:*:*) at Socket.emit (events.js:*:*) at endReadableNT (_stream_readable.js:*:*) at process._tickCallback (internal/process/next_tick.js:*:*) @@ -39,9 +39,9 @@ Error: hello at Script.runInThisContext (vm.js:*) at Object.runInThisContext (vm.js:*) at Object. ([stdin]-wrapper:*:*) - at Module._compile (module.js:*:*) - at evalScript (bootstrap_node.js:*:*) - at Socket. (bootstrap_node.js:*:*) + at Module._compile (internal/modules/cjs/loader.js:*:*) + at evalScript (internal/bootstrap/node.js:*:*) + at Socket. (internal/bootstrap/node.js:*:*) at Socket.emit (events.js:*:*) at endReadableNT (_stream_readable.js:*:*) at process._tickCallback (internal/process/next_tick.js:*:*) @@ -55,9 +55,9 @@ ReferenceError: y is not defined at Script.runInThisContext (vm.js:*) at Object.runInThisContext (vm.js:*) at Object. ([stdin]-wrapper:*:*) - at Module._compile (module.js:*:*) - at evalScript (bootstrap_node.js:*:*) - at Socket. (bootstrap_node.js:*:*) + at Module._compile (internal/modules/cjs/loader.js:*:*) + at evalScript (internal/bootstrap/node.js:*:*) + at Socket. (internal/bootstrap/node.js:*:*) at Socket.emit (events.js:*:*) at endReadableNT (_stream_readable.js:*:*) at process._tickCallback (internal/process/next_tick.js:*:*) diff --git a/test/message/undefined_reference_in_new_context.out b/test/message/undefined_reference_in_new_context.out index ff517cc981a255..6b5fedfa993701 100644 --- a/test/message/undefined_reference_in_new_context.out +++ b/test/message/undefined_reference_in_new_context.out @@ -9,8 +9,8 @@ ReferenceError: foo is not defined at Script.runInNewContext (vm.js:*) at Object.runInNewContext (vm.js:*) at Object. (*test*message*undefined_reference_in_new_context.js:*) - at Module._compile (module.js:*) - at *..js (module.js:*) - at Module.load (module.js:*) - at tryModuleLoad (module.js:*:*) - at Function.Module._load (module.js:*:*) + at Module._compile (internal/modules/cjs/loader.js:*) + at *..js (internal/modules/cjs/loader.js:*) + at Module.load (internal/modules/cjs/loader.js:*) + at tryModuleLoad (internal/modules/cjs/loader.js:*:*) + at Function.Module._load (internal/modules/cjs/loader.js:*:*) diff --git a/test/message/vm_display_runtime_error.out b/test/message/vm_display_runtime_error.out index 056ea79f8d39b4..bc95b2a7b092f5 100644 --- a/test/message/vm_display_runtime_error.out +++ b/test/message/vm_display_runtime_error.out @@ -8,12 +8,12 @@ Error: boo! at Script.runInThisContext (vm.js:*) at Object.runInThisContext (vm.js:*) at Object. (*test*message*vm_display_runtime_error.js:*) - at Module._compile (module.js:*) - at Object.Module._extensions..js (module.js:*) - at Module.load (module.js:*) - at tryModuleLoad (module.js:*:*) - at Function.Module._load (module.js:*) - at Function.Module.runMain (module.js:*) + at Module._compile (internal/modules/cjs/loader.js:*) + at Object.Module._extensions..js (internal/modules/cjs/loader.js:*) + at Module.load (internal/modules/cjs/loader.js:*) + at tryModuleLoad (internal/modules/cjs/loader.js:*:*) + at Function.Module._load (internal/modules/cjs/loader.js:*) + at Function.Module.runMain (internal/modules/cjs/loader.js:*) test.vm:1 throw new Error("spooky!") ^ @@ -23,9 +23,9 @@ Error: spooky! at Script.runInThisContext (vm.js:*) at Object.runInThisContext (vm.js:*) at Object. (*test*message*vm_display_runtime_error.js:*) - at Module._compile (module.js:*) - at Object.Module._extensions..js (module.js:*) - at Module.load (module.js:*) - at tryModuleLoad (module.js:*:*) - at Function.Module._load (module.js:*) - at Function.Module.runMain (module.js:*) + at Module._compile (internal/modules/cjs/loader.js:*) + at Object.Module._extensions..js (internal/modules/cjs/loader.js:*) + at Module.load (internal/modules/cjs/loader.js:*) + at tryModuleLoad (internal/modules/cjs/loader.js:*:*) + at Function.Module._load (internal/modules/cjs/loader.js:*) + at Function.Module.runMain (internal/modules/cjs/loader.js:*) diff --git a/test/message/vm_display_syntax_error.out b/test/message/vm_display_syntax_error.out index f3b9953307db19..f0692723e81257 100644 --- a/test/message/vm_display_syntax_error.out +++ b/test/message/vm_display_syntax_error.out @@ -7,12 +7,12 @@ SyntaxError: Unexpected number at createScript (vm.js:*) at Object.runInThisContext (vm.js:*) at Object. (*test*message*vm_display_syntax_error.js:*) - at Module._compile (module.js:*) - at Object.Module._extensions..js (module.js:*) - at Module.load (module.js:*) - at tryModuleLoad (module.js:*:*) - at Function.Module._load (module.js:*) - at Function.Module.runMain (module.js:*) + at Module._compile (internal/modules/cjs/loader.js:*) + at Object.Module._extensions..js (internal/modules/cjs/loader.js:*) + at Module.load (internal/modules/cjs/loader.js:*) + at tryModuleLoad (internal/modules/cjs/loader.js:*:*) + at Function.Module._load (internal/modules/cjs/loader.js:*) + at Function.Module.runMain (internal/modules/cjs/loader.js:*) test.vm:1 var 5; ^ @@ -21,9 +21,9 @@ SyntaxError: Unexpected number at createScript (vm.js:*) at Object.runInThisContext (vm.js:*) at Object. (*test*message*vm_display_syntax_error.js:*) - at Module._compile (module.js:*) - at Object.Module._extensions..js (module.js:*) - at Module.load (module.js:*) - at tryModuleLoad (module.js:*:*) - at Function.Module._load (module.js:*) - at Function.Module.runMain (module.js:*) + at Module._compile (internal/modules/cjs/loader.js:*) + at Object.Module._extensions..js (internal/modules/cjs/loader.js:*) + at Module.load (internal/modules/cjs/loader.js:*) + at tryModuleLoad (internal/modules/cjs/loader.js:*:*) + at Function.Module._load (internal/modules/cjs/loader.js:*) + at Function.Module.runMain (internal/modules/cjs/loader.js:*) diff --git a/test/message/vm_dont_display_runtime_error.out b/test/message/vm_dont_display_runtime_error.out index a7e06d49f85a7c..532cfbf4dd8125 100644 --- a/test/message/vm_dont_display_runtime_error.out +++ b/test/message/vm_dont_display_runtime_error.out @@ -9,9 +9,9 @@ Error: boo! at Script.runInThisContext (vm.js:*) at Object.runInThisContext (vm.js:*) at Object. (*test*message*vm_dont_display_runtime_error.js:*) - at Module._compile (module.js:*) - at Object.Module._extensions..js (module.js:*) - at Module.load (module.js:*) - at tryModuleLoad (module.js:*:*) - at Function.Module._load (module.js:*) - at Function.Module.runMain (module.js:*) + at Module._compile (internal/modules/cjs/loader.js:*) + at Object.Module._extensions..js (internal/modules/cjs/loader.js:*) + at Module.load (internal/modules/cjs/loader.js:*) + at tryModuleLoad (internal/modules/cjs/loader.js:*:*) + at Function.Module._load (internal/modules/cjs/loader.js:*) + at Function.Module.runMain (internal/modules/cjs/loader.js:*) diff --git a/test/message/vm_dont_display_syntax_error.out b/test/message/vm_dont_display_syntax_error.out index 5c74c25dd8aa3b..f27cb1a0859d8c 100644 --- a/test/message/vm_dont_display_syntax_error.out +++ b/test/message/vm_dont_display_syntax_error.out @@ -9,9 +9,9 @@ SyntaxError: Unexpected number at createScript (vm.js:*) at Object.runInThisContext (vm.js:*) at Object. (*test*message*vm_dont_display_syntax_error.js:*) - at Module._compile (module.js:*) - at Object.Module._extensions..js (module.js:*) - at Module.load (module.js:*) - at tryModuleLoad (module.js:*:*) - at Function.Module._load (module.js:*) - at Function.Module.runMain (module.js:*) + at Module._compile (internal/modules/cjs/loader.js:*) + at Object.Module._extensions..js (internal/modules/cjs/loader.js:*) + at Module.load (internal/modules/cjs/loader.js:*) + at tryModuleLoad (internal/modules/cjs/loader.js:*:*) + at Function.Module._load (internal/modules/cjs/loader.js:*) + at Function.Module.runMain (internal/modules/cjs/loader.js:*) diff --git a/test/parallel/test-internal-module-map-asserts.js b/test/parallel/test-internal-module-map-asserts.js index 1160c910421b80..330f04cfd96800 100644 --- a/test/parallel/test-internal-module-map-asserts.js +++ b/test/parallel/test-internal-module-map-asserts.js @@ -3,7 +3,7 @@ const common = require('../common'); const assert = require('assert'); -const ModuleMap = require('internal/loader/ModuleMap'); +const ModuleMap = require('internal/modules/esm/ModuleMap'); // ModuleMap.get, ModuleMap.has and ModuleMap.set should only accept string // values as url argument. diff --git a/test/parallel/test-internal-module-wrap.js b/test/parallel/test-internal-module-wrap.js index 634d1ebc6f678e..050cc18a4dbee6 100644 --- a/test/parallel/test-internal-module-wrap.js +++ b/test/parallel/test-internal-module-wrap.js @@ -6,7 +6,7 @@ const common = require('../common'); common.crashOnUnhandledRejection(); const assert = require('assert'); -const ModuleWrap = require('internal/loader/ModuleWrap'); +const ModuleWrap = require('internal/modules/esm/ModuleWrap'); const { getPromiseDetails, isPromise } = process.binding('util'); const setTimeoutAsync = require('util').promisify(setTimeout); diff --git a/test/parallel/test-internal-modules-strip-shebang.js b/test/parallel/test-internal-modules-strip-shebang.js index 93be3d41981f50..6c23848a969231 100644 --- a/test/parallel/test-internal-modules-strip-shebang.js +++ b/test/parallel/test-internal-modules-strip-shebang.js @@ -3,7 +3,7 @@ require('../common'); const assert = require('assert'); -const stripShebang = require('internal/module').stripShebang; +const stripShebang = require('internal/modules/cjs/helpers').stripShebang; [ ['', ''], diff --git a/test/parallel/test-loaders-hidden-from-users.js b/test/parallel/test-loaders-hidden-from-users.js new file mode 100644 index 00000000000000..0d752f5718b729 --- /dev/null +++ b/test/parallel/test-loaders-hidden-from-users.js @@ -0,0 +1,25 @@ +// Flags: --expose-internals + +'use strict'; + +const common = require('../common'); + +common.expectsError( + () => { + require('internal/bootstrap/loaders'); + }, { + code: 'MODULE_NOT_FOUND', + message: 'Cannot find module \'internal/bootstrap/loaders\'' + } +); + +common.expectsError( + () => { + const source = 'module.exports = require("internal/bootstrap/loaders")'; + process.binding('natives').owo = source; + require('owo'); + }, { + code: 'MODULE_NOT_FOUND', + message: 'Cannot find module \'owo\'' + } +); diff --git a/test/parallel/test-module-cjs-helpers.js b/test/parallel/test-module-cjs-helpers.js index 5407464d57942d..1ed9746198a606 100644 --- a/test/parallel/test-module-cjs-helpers.js +++ b/test/parallel/test-module-cjs-helpers.js @@ -3,7 +3,7 @@ require('../common'); const assert = require('assert'); -const { builtinLibs } = require('internal/module'); +const { builtinLibs } = require('internal/modules/cjs/helpers'); const hasInspector = process.config.variables.v8_enable_inspector === 1; diff --git a/test/parallel/test-module-loading-globalpaths.js b/test/parallel/test-module-loading-globalpaths.js index aff96543735428..798b7765bb6d5b 100644 --- a/test/parallel/test-module-loading-globalpaths.js +++ b/test/parallel/test-module-loading-globalpaths.js @@ -41,8 +41,6 @@ if (process.argv[2] === 'child') { const testFixturesDir = fixtures.path(path.basename(__filename, '.js')); const env = Object.assign({}, process.env); - // Turn on module debug to aid diagnosing failures. - env.NODE_DEBUG = 'module'; // Unset NODE_PATH. delete env.NODE_PATH; diff --git a/test/parallel/test-module-require-depth.js b/test/parallel/test-module-require-depth.js index 151934917cd678..0a3fc2826c71f4 100644 --- a/test/parallel/test-module-require-depth.js +++ b/test/parallel/test-module-require-depth.js @@ -3,12 +3,14 @@ require('../common'); const fixtures = require('../common/fixtures'); const assert = require('assert'); -const internalModule = require('internal/module'); +const { + requireDepth +} = require('internal/modules/cjs/helpers'); // Module one loads two too so the expected depth for two is, well, two. -assert.strictEqual(internalModule.requireDepth, 0); +assert.strictEqual(requireDepth, 0); const one = require(fixtures.path('module-require-depth', 'one')); const two = require(fixtures.path('module-require-depth', 'two')); assert.deepStrictEqual(one, { requireDepth: 1 }); assert.deepStrictEqual(two, { requireDepth: 2 }); -assert.strictEqual(internalModule.requireDepth, 0); +assert.strictEqual(requireDepth, 0); diff --git a/test/sequential/test-inspector-overwrite-config.js b/test/sequential/test-inspector-overwrite-config.js index ecb14c6638edb5..9aa3ca9d963828 100644 --- a/test/sequential/test-inspector-overwrite-config.js +++ b/test/sequential/test-inspector-overwrite-config.js @@ -2,7 +2,8 @@ 'use strict'; // This test ensures that overwriting a process configuration -// value does not affect code in bootstrap_node.js. Specifically this tests +// value does not affect code in lib/internal/bootstrap/node.js. +// Specifically this tests // that the inspector console functions are bound even though // overwrite-config-preload-module.js overwrote the process.config variable. diff --git a/tools/js2c.py b/tools/js2c.py index d2d63ad571205d..a0119257b3f0e8 100755 --- a/tools/js2c.py +++ b/tools/js2c.py @@ -175,7 +175,11 @@ def ReadMacros(lines): {definitions} -v8::Local MainSource(Environment* env) {{ +v8::Local LoadersBootstrapperSource(Environment* env) {{ + return internal_bootstrap_loaders_value.ToStringChecked(env->isolate()); +}} + +v8::Local NodeBootstrapperSource(Environment* env) {{ return internal_bootstrap_node_value.ToStringChecked(env->isolate()); }}