Skip to content

Commit

Permalink
module: refactor to use more primordials
Browse files Browse the repository at this point in the history
PR-URL: #36024
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
  • Loading branch information
aduh95 authored and targos committed May 16, 2021
1 parent 2fd37db commit 1f38c63
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 54 deletions.
18 changes: 11 additions & 7 deletions lib/internal/modules/cjs/helpers.js
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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 @@ -144,8 +155,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);
}

function Module(id = '', parent) {
Expand All @@ -162,7 +173,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 @@ -331,7 +342,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 @@ -371,10 +382,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 @@ -455,15 +466,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 @@ -546,13 +557,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 @@ -562,7 +574,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 @@ -591,10 +606,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 @@ -607,7 +625,7 @@ if (isWindows) {
}

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

return paths;
};
Expand All @@ -620,15 +638,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 @@ -778,9 +796,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 @@ -804,10 +822,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 @@ -822,8 +840,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 @@ -872,11 +890,12 @@ Module._resolveFilename = function(request, parent, isMain, options) {
for (let cursor = parent;
cursor;
cursor = cursor.parent) {
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 @@ -887,7 +906,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 @@ -924,9 +943,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 @@ -1057,13 +1076,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 @@ -1072,7 +1091,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 @@ -1127,7 +1146,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 @@ -1189,15 +1209,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
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 1f38c63

Please sign in to comment.