Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

module: refactor to use more primordials #36024

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 11 additions & 7 deletions 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,
Expand All @@ -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');
Expand Down Expand Up @@ -119,20 +123,20 @@ 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;
}

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;
}
Expand Down
109 changes: 65 additions & 44 deletions lib/internal/modules/cjs/loader.js
Expand Up @@ -23,10 +23,17 @@

const {
ArrayIsArray,
ArrayPrototypeConcat,
ArrayPrototypeFilter,
ArrayPrototypeIncludes,
ArrayPrototypeIndexOf,
ArrayPrototypeJoin,
ArrayPrototypePush,
ArrayPrototypeSlice,
ArrayPrototypeSplice,
Boolean,
Error,
JSONParse,
Map,
ObjectCreate,
ObjectDefineProperty,
ObjectFreeze,
Expand All @@ -36,16 +43,20 @@ const {
ObjectPrototype,
ObjectPrototypeHasOwnProperty,
ObjectSetPrototypeOf,
ReflectApply,
ReflectSet,
RegExpPrototypeTest,
SafeMap,
SafeWeakMap,
String,
StringPrototypeCharAt,
StringPrototypeCharCodeAt,
StringPrototypeEndsWith,
StringPrototypeLastIndexOf,
StringPrototypeIndexOf,
StringPrototypeMatch,
StringPrototypeSlice,
StringPrototypeSplit,
StringPrototypeStartsWith,
} = primordials;

Expand Down Expand Up @@ -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();
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -625,7 +643,7 @@ if (isWindows) {
}

// Append /node_modules to handle root paths.
paths.push('/node_modules');
ArrayPrototypePush(paths, '/node_modules');

return paths;
};
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
}
}
Expand All @@ -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;
Expand All @@ -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]);
}
}
}
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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') {
Expand Down Expand Up @@ -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') :
Expand Down Expand Up @@ -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) {
Expand Down
10 changes: 7 additions & 3 deletions 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');
Expand Down Expand Up @@ -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';
Expand All @@ -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
Expand Down