From 7a375902fffb262f0c73ef1d2a54f63357094852 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 7 Nov 2020 11:08:09 +0100 Subject: [PATCH] module: refactor to use more primordials PR-URL: https://github.com/nodejs/node/pull/36024 Reviewed-By: Rich Trott Reviewed-By: Benjamin Gruenbaum --- lib/internal/modules/cjs/helpers.js | 18 +++-- lib/internal/modules/cjs/loader.js | 109 +++++++++++++++++----------- lib/internal/modules/run_main.js | 10 ++- 3 files changed, 83 insertions(+), 54 deletions(-) diff --git a/lib/internal/modules/cjs/helpers.js b/lib/internal/modules/cjs/helpers.js index 9b6944c59390fe..163c854ac26d48 100644 --- a/lib/internal/modules/cjs/helpers.js +++ b/lib/internal/modules/cjs/helpers.js @@ -1,11 +1,16 @@ 'use strict'; const { + ArrayPrototypeForEach, ArrayPrototypeJoin, ObjectDefineProperty, ObjectPrototypeHasOwnProperty, SafeMap, SafeSet, + StringPrototypeCharCodeAt, + StringPrototypeIncludes, + StringPrototypeSlice, + StringPrototypeStartsWith, } = primordials; const { ERR_MANIFEST_DEPENDENCY_MISSING, @@ -15,8 +20,7 @@ const { NativeModule } = require('internal/bootstrap/loaders'); const { validateString } = require('internal/validators'); const path = require('path'); -const { pathToFileURL, fileURLToPath } = require('internal/url'); -const { URL } = require('url'); +const { pathToFileURL, fileURLToPath, URL } = require('internal/url'); const { getOptionValue } = require('internal/options'); const userConditions = getOptionValue('--conditions'); @@ -119,8 +123,8 @@ function makeRequireFunction(mod, redirects) { * translates it to FEFF, the UTF-16 BOM. */ function stripBOM(content) { - if (content.charCodeAt(0) === 0xFEFF) { - content = content.slice(1); + if (StringPrototypeCharCodeAt(content) === 0xFEFF) { + content = StringPrototypeSlice(content, 1); } return content; } @@ -128,11 +132,11 @@ function stripBOM(content) { function addBuiltinLibsToObject(object) { // Make built-in modules available directly (loaded lazily). const { builtinModules } = require('internal/modules/cjs/loader').Module; - builtinModules.forEach((name) => { + ArrayPrototypeForEach(builtinModules, (name) => { // Neither add underscored modules, nor ones that contain slashes (e.g., // 'fs/promises') or ones that are already defined. - if (name.startsWith('_') || - name.includes('/') || + if (StringPrototypeStartsWith(name, '_') || + StringPrototypeIncludes(name, '/') || ObjectPrototypeHasOwnProperty(object, name)) { return; } diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 051cc23277865f..883af41c4eef1d 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -23,10 +23,17 @@ const { ArrayIsArray, + ArrayPrototypeConcat, + ArrayPrototypeFilter, + ArrayPrototypeIncludes, + ArrayPrototypeIndexOf, ArrayPrototypeJoin, + ArrayPrototypePush, + ArrayPrototypeSlice, + ArrayPrototypeSplice, + Boolean, Error, JSONParse, - Map, ObjectCreate, ObjectDefineProperty, ObjectFreeze, @@ -36,16 +43,20 @@ const { ObjectPrototype, ObjectPrototypeHasOwnProperty, ObjectSetPrototypeOf, + ReflectApply, ReflectSet, RegExpPrototypeTest, SafeMap, SafeWeakMap, String, + StringPrototypeCharAt, + StringPrototypeCharCodeAt, StringPrototypeEndsWith, StringPrototypeLastIndexOf, StringPrototypeIndexOf, StringPrototypeMatch, StringPrototypeSlice, + StringPrototypeSplit, StringPrototypeStartsWith, } = primordials; @@ -142,8 +153,8 @@ function stat(filename) { function updateChildren(parent, child, scan) { const children = parent && parent.children; - if (children && !(scan && children.includes(child))) - children.push(child); + if (children && !(scan && ArrayPrototypeIncludes(children, child))) + ArrayPrototypePush(children, child); } const moduleParentCache = new SafeWeakMap(); @@ -161,7 +172,7 @@ function Module(id = '', parent) { const builtinModules = []; for (const [id, mod] of NativeModule.map) { if (mod.canBeRequiredByUsers) { - builtinModules.push(id); + ArrayPrototypePush(builtinModules, id); } } @@ -349,7 +360,7 @@ function tryPackage(requestPath, exts, isMain, originalPath) { // 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(); +const realpathCache = new SafeMap(); // Check if the file exists and is not a directory // if using --preserve-symlinks and isMain is false, @@ -389,10 +400,10 @@ function findLongestRegisteredExtension(filename) { let currentExtension; let index; let startIndex = 0; - while ((index = name.indexOf('.', startIndex)) !== -1) { + while ((index = StringPrototypeIndexOf(name, '.', startIndex)) !== -1) { startIndex = index + 1; if (index === 0) continue; // Skip dotfiles like .gitignore - currentExtension = name.slice(index); + currentExtension = StringPrototypeSlice(name, index); if (Module._extensions[currentExtension]) return currentExtension; } return '.js'; @@ -473,15 +484,15 @@ Module._findPath = function(request, paths, isMain) { return false; } - const cacheKey = request + '\x00' + - (paths.length === 1 ? paths[0] : paths.join('\x00')); + const cacheKey = request + '\x00' + ArrayPrototypeJoin(paths, '\x00'); const entry = Module._pathCache[cacheKey]; if (entry) return entry; let exts; let trailingSlash = request.length > 0 && - request.charCodeAt(request.length - 1) === CHAR_FORWARD_SLASH; + StringPrototypeCharCodeAt(request, request.length - 1) === + CHAR_FORWARD_SLASH; if (!trailingSlash) { trailingSlash = RegExpPrototypeTest(trailingSlashRegex, request); } @@ -564,13 +575,14 @@ if (isWindows) { // return root node_modules when path is 'D:\\'. // path.resolve will make sure from.length >=3 in Windows. - if (from.charCodeAt(from.length - 1) === CHAR_BACKWARD_SLASH && - from.charCodeAt(from.length - 2) === CHAR_COLON) + if (StringPrototypeCharCodeAt(from, from.length - 1) === + CHAR_BACKWARD_SLASH && + StringPrototypeCharCodeAt(from, from.length - 2) === CHAR_COLON) return [from + 'node_modules']; const paths = []; for (let i = from.length - 1, p = 0, last = from.length; i >= 0; --i) { - const code = from.charCodeAt(i); + const code = StringPrototypeCharCodeAt(from, 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 @@ -580,7 +592,10 @@ if (isWindows) { code === CHAR_FORWARD_SLASH || code === CHAR_COLON) { if (p !== nmLen) - paths.push(from.slice(0, last) + '\\node_modules'); + ArrayPrototypePush( + paths, + StringPrototypeSlice(from, 0, last) + '\\node_modules' + ); last = i; p = 0; } else if (p !== -1) { @@ -609,10 +624,13 @@ if (isWindows) { // that works on both Windows and Posix is non-trivial. const paths = []; for (let i = from.length - 1, p = 0, last = from.length; i >= 0; --i) { - const code = from.charCodeAt(i); + const code = StringPrototypeCharCodeAt(from, i); if (code === CHAR_FORWARD_SLASH) { if (p !== nmLen) - paths.push(from.slice(0, last) + '/node_modules'); + ArrayPrototypePush( + paths, + StringPrototypeSlice(from, 0, last) + '/node_modules' + ); last = i; p = 0; } else if (p !== -1) { @@ -625,7 +643,7 @@ if (isWindows) { } // Append /node_modules to handle root paths. - paths.push('/node_modules'); + ArrayPrototypePush(paths, '/node_modules'); return paths; }; @@ -638,15 +656,15 @@ Module._resolveLookupPaths = function(request, parent) { } // Check for node modules paths. - if (request.charAt(0) !== '.' || + if (StringPrototypeCharAt(request, 0) !== '.' || (request.length > 1 && - request.charAt(1) !== '.' && - request.charAt(1) !== '/' && - (!isWindows || request.charAt(1) !== '\\'))) { + StringPrototypeCharAt(request, 1) !== '.' && + StringPrototypeCharAt(request, 1) !== '/' && + (!isWindows || StringPrototypeCharAt(request, 1) !== '\\'))) { let paths = modulePaths; if (parent != null && parent.paths && parent.paths.length) { - paths = parent.paths.concat(paths); + paths = ArrayPrototypeConcat(parent.paths, paths); } debug('looking for %j in %j', request, paths); @@ -796,9 +814,9 @@ Module._load = function(request, parent, isMain) { delete relativeResolveCache[relResolveCacheIdentifier]; const children = parent && parent.children; if (ArrayIsArray(children)) { - const index = children.indexOf(module); + const index = ArrayPrototypeIndexOf(children, module); if (index !== -1) { - children.splice(index, 1); + ArrayPrototypeSplice(children, index, 1); } } } @@ -822,10 +840,10 @@ Module._resolveFilename = function(request, parent, isMain, options) { if (typeof options === 'object' && options !== null) { if (ArrayIsArray(options.paths)) { - const isRelative = request.startsWith('./') || - request.startsWith('../') || - ((isWindows && request.startsWith('.\\')) || - request.startsWith('..\\')); + const isRelative = StringPrototypeStartsWith(request, './') || + StringPrototypeStartsWith(request, '../') || + ((isWindows && StringPrototypeStartsWith(request, '.\\')) || + StringPrototypeStartsWith(request, '..\\')); if (isRelative) { paths = options.paths; @@ -840,8 +858,8 @@ Module._resolveFilename = function(request, parent, isMain, options) { const lookupPaths = Module._resolveLookupPaths(request, fakeParent); for (let j = 0; j < lookupPaths.length; j++) { - if (!paths.includes(lookupPaths[j])) - paths.push(lookupPaths[j]); + if (!ArrayPrototypeIncludes(paths, lookupPaths[j])) + ArrayPrototypePush(paths, lookupPaths[j]); } } } @@ -890,11 +908,12 @@ Module._resolveFilename = function(request, parent, isMain, options) { for (let cursor = parent; cursor; cursor = moduleParentCache.get(cursor)) { - requireStack.push(cursor.filename || cursor.id); + ArrayPrototypePush(requireStack, cursor.filename || cursor.id); } let message = `Cannot find module '${request}'`; if (requireStack.length > 0) { - message = message + '\nRequire stack:\n- ' + requireStack.join('\n- '); + message = message + '\nRequire stack:\n- ' + + ArrayPrototypeJoin(requireStack, '\n- '); } // eslint-disable-next-line no-restricted-syntax const err = new Error(message); @@ -905,7 +924,7 @@ Module._resolveFilename = function(request, parent, isMain, options) { function finalizeEsmResolution(match, request, parentPath, pkgPath) { const { resolved, exact } = match; - if (StringPrototypeMatch(resolved, encodedSepRegEx)) + if (RegExpPrototypeTest(encodedSepRegEx, resolved)) throw new ERR_INVALID_MODULE_SPECIFIER( resolved, 'must not include encoded "/" or "\\" characters', parentPath); const filename = fileURLToPath(resolved); @@ -942,9 +961,9 @@ Module.prototype.load = function(filename) { const extension = findLongestRegisteredExtension(filename); // allow .mjs to be overridden - if (filename.endsWith('.mjs') && !Module._extensions['.mjs']) { + if (StringPrototypeEndsWith(filename, '.mjs') && !Module._extensions['.mjs']) throw new ERR_REQUIRE_ESM(filename); - } + Module._extensions[extension](this, filename); this.loaded = true; @@ -1075,13 +1094,13 @@ Module.prototype._compile = function(content, filename) { const exports = this.exports; const thisValue = exports; const module = this; - if (requireDepth === 0) statCache = new Map(); + if (requireDepth === 0) statCache = new SafeMap(); if (inspectorWrapper) { result = inspectorWrapper(compiledWrapper, thisValue, exports, require, module, filename, dirname); } else { - result = compiledWrapper.call(thisValue, exports, require, module, - filename, dirname); + result = ReflectApply(compiledWrapper, thisValue, + [exports, require, module, filename, dirname]); } hasLoadedAnyUserCJSModule = true; if (requireDepth === 0) statCache = null; @@ -1090,7 +1109,7 @@ Module.prototype._compile = function(content, filename) { // Native extension for .js Module._extensions['.js'] = function(module, filename) { - if (filename.endsWith('.js')) { + if (StringPrototypeEndsWith(filename, '.js')) { const pkg = readPackageScope(filename); // Function require shouldn't be used in ES modules. if (pkg && pkg.data && pkg.data.type === 'module') { @@ -1145,7 +1164,8 @@ Module._extensions['.node'] = function(module, filename) { function createRequireFromPath(filename) { // Allow a directory to be passed as the filename const trailingSlash = - filename.endsWith('/') || (isWindows && filename.endsWith('\\')); + StringPrototypeEndsWith(filename, '/') || + (isWindows && StringPrototypeEndsWith(filename, '\\')); const proxyPath = trailingSlash ? path.join(filename, 'noop.js') : @@ -1207,15 +1227,16 @@ Module._initPaths = function() { } if (nodePath) { - paths = nodePath.split(path.delimiter).filter(function pathsFilterCB(path) { - return !!path; - }).concat(paths); + paths = ArrayPrototypeConcat(ArrayPrototypeFilter( + StringPrototypeSplit(nodePath, path.delimiter), + Boolean + ), paths); } modulePaths = paths; // Clone as a shallow copy, for introspection. - Module.globalPaths = modulePaths.slice(0); + Module.globalPaths = ArrayPrototypeSlice(modulePaths); }; Module._preloadModules = function(requests) { diff --git a/lib/internal/modules/run_main.js b/lib/internal/modules/run_main.js index 892f6921745989..bc6f90ce7d089a 100644 --- a/lib/internal/modules/run_main.js +++ b/lib/internal/modules/run_main.js @@ -1,5 +1,9 @@ 'use strict'; +const { + PromisePrototypeFinally, + StringPrototypeEndsWith, +} = primordials; const CJSLoader = require('internal/modules/cjs/loader'); const { Module, toRealPath, readPackageScope } = CJSLoader; const { getOptionValue } = require('internal/options'); @@ -29,9 +33,9 @@ function shouldUseESMLoader(mainPath) { if (esModuleSpecifierResolution === 'node') return true; // Determine the module format of the main - if (mainPath && mainPath.endsWith('.mjs')) + if (mainPath && StringPrototypeEndsWith(mainPath, '.mjs')) return true; - if (!mainPath || mainPath.endsWith('.cjs')) + if (!mainPath || StringPrototypeEndsWith(mainPath, '.cjs')) return false; const pkg = readPackageScope(mainPath); return pkg && pkg.data.type === 'module'; @@ -56,7 +60,7 @@ function handleMainPromise(promise) { process.exitCode = 13; } process.on('exit', handler); - return promise.finally(() => process.off('exit', handler)); + return PromisePrototypeFinally(promise, () => process.off('exit', handler)); } // For backwards compatibility, we have to run a bunch of