Skip to content

Commit 51f4ff2

Browse files
module: move helpers out of cjs loader
PR-URL: #49912 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]>
1 parent 2990390 commit 51f4ff2

File tree

4 files changed

+79
-70
lines changed

4 files changed

+79
-70
lines changed

lib/internal/modules/cjs/loader.js

+6-66
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ const {
5555
StringPrototypeCharAt,
5656
StringPrototypeCharCodeAt,
5757
StringPrototypeEndsWith,
58-
StringPrototypeLastIndexOf,
5958
StringPrototypeIndexOf,
6059
StringPrototypeRepeat,
6160
StringPrototypeSlice,
@@ -68,7 +67,7 @@ const cjsParseCache = new SafeWeakMap();
6867

6968
// Set first due to cycle with ESM loader functions.
7069
module.exports = {
71-
wrapSafe, Module, toRealPath, readPackageScope, cjsParseCache,
70+
wrapSafe, Module, cjsParseCache,
7271
get hasLoadedAnyUserCJSModule() { return hasLoadedAnyUserCJSModule; },
7372
initializeCJS,
7473
};
@@ -88,9 +87,7 @@ const {
8887
const { internalCompileFunction } = require('internal/vm');
8988
const assert = require('internal/assert');
9089
const fs = require('fs');
91-
const internalFS = require('internal/fs/utils');
9290
const path = require('path');
93-
const { sep } = path;
9491
const { internalModuleStat } = internalBinding('fs');
9592
const { safeGetenv } = internalBinding('credentials');
9693
const {
@@ -106,6 +103,7 @@ const {
106103
makeRequireFunction,
107104
normalizeReferrerURL,
108105
stripBOM,
106+
toRealPath,
109107
} = require('internal/modules/helpers');
110108
const packageJsonReader = require('internal/modules/package_json_reader');
111109
const { getOptionValue, getEmbedderOptions } = require('internal/options');
@@ -403,15 +401,7 @@ function initializeCJS() {
403401
// -> a.<ext>
404402
// -> a/index.<ext>
405403

406-
/**
407-
* @param {string} requestPath
408-
* @return {PackageConfig}
409-
*/
410-
function readPackage(requestPath) {
411-
return packageJsonReader.read(path.resolve(requestPath, 'package.json'));
412-
}
413-
414-
let _readPackage = readPackage;
404+
let _readPackage = packageJsonReader.readPackage;
415405
ObjectDefineProperty(Module, '_readPackage', {
416406
__proto__: null,
417407
get() { return _readPackage; },
@@ -423,37 +413,6 @@ ObjectDefineProperty(Module, '_readPackage', {
423413
configurable: true,
424414
});
425415

426-
/**
427-
* Get the nearest parent package.json file from a given path.
428-
* Return the package.json data and the path to the package.json file, or false.
429-
* @param {string} checkPath The path to start searching from.
430-
*/
431-
function readPackageScope(checkPath) {
432-
const rootSeparatorIndex = StringPrototypeIndexOf(checkPath, sep);
433-
let separatorIndex;
434-
const enabledPermission = permission.isEnabled();
435-
do {
436-
separatorIndex = StringPrototypeLastIndexOf(checkPath, sep);
437-
checkPath = StringPrototypeSlice(checkPath, 0, separatorIndex);
438-
// Stop the search when the process doesn't have permissions
439-
// to walk upwards
440-
if (enabledPermission && !permission.has('fs.read', checkPath + sep)) {
441-
return false;
442-
}
443-
if (StringPrototypeEndsWith(checkPath, sep + 'node_modules')) {
444-
return false;
445-
}
446-
const pjson = _readPackage(checkPath + sep);
447-
if (pjson.exists) {
448-
return {
449-
data: pjson,
450-
path: checkPath,
451-
};
452-
}
453-
} while (separatorIndex > rootSeparatorIndex);
454-
return false;
455-
}
456-
457416
/**
458417
* Try to load a specifier as a package.
459418
* @param {string} requestPath The path to what we are trying to load
@@ -498,14 +457,6 @@ function tryPackage(requestPath, exts, isMain, originalPath) {
498457
return actual;
499458
}
500459

501-
/**
502-
* Cache for storing resolved real paths of modules.
503-
* In order to minimize unnecessary lstat() calls, this cache is a list of known-real paths.
504-
* Set to an empty Map to reset.
505-
* @type {Map<string, string>}
506-
*/
507-
const realpathCache = new SafeMap();
508-
509460
/**
510461
* Check if the file exists and is not a directory if using `--preserve-symlinks` and `isMain` is false, keep symlinks
511462
* intact, otherwise resolve to the absolute realpath.
@@ -521,17 +472,6 @@ function tryFile(requestPath, isMain) {
521472
return toRealPath(requestPath);
522473
}
523474

524-
525-
/**
526-
* Resolves the path of a given `require` specifier, following symlinks.
527-
* @param {string} requestPath The `require` specifier
528-
*/
529-
function toRealPath(requestPath) {
530-
return fs.realpathSync(requestPath, {
531-
[internalFS.realpathCacheKey]: realpathCache,
532-
});
533-
}
534-
535475
/**
536476
* Given a path, check if the file exists with any of the set extensions.
537477
* @param {string} basePath The path and filename without extension
@@ -593,7 +533,7 @@ function trySelfParentPath(parent) {
593533
function trySelf(parentPath, request) {
594534
if (!parentPath) { return false; }
595535

596-
const { data: pkg, path: pkgPath } = readPackageScope(parentPath);
536+
const { data: pkg, path: pkgPath } = packageJsonReader.readPackageScope(parentPath);
597537
if (!pkg || pkg.exports == null || pkg.name === undefined) {
598538
return false;
599539
}
@@ -1153,7 +1093,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
11531093

11541094
if (request[0] === '#' && (parent?.filename || parent?.id === '<repl>')) {
11551095
const parentPath = parent?.filename ?? process.cwd() + path.sep;
1156-
const pkg = readPackageScope(parentPath) || { __proto__: null };
1096+
const pkg = packageJsonReader.readPackageScope(parentPath) || { __proto__: null };
11571097
if (pkg.data?.imports != null) {
11581098
try {
11591099
const { packageImportsResolve } = require('internal/modules/esm/resolve');
@@ -1450,7 +1390,7 @@ Module._extensions['.js'] = function(module, filename) {
14501390
content = fs.readFileSync(filename, 'utf8');
14511391
}
14521392
if (StringPrototypeEndsWith(filename, '.js')) {
1453-
const pkg = readPackageScope(filename) || { __proto__: null };
1393+
const pkg = packageJsonReader.readPackageScope(filename) || { __proto__: null };
14541394
// Function require shouldn't be used in ES modules.
14551395
if (pkg.data?.type === 'module') {
14561396
const parent = moduleParentCache.get(module);

lib/internal/modules/helpers.js

+20
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ const {
2121
const { BuiltinModule } = require('internal/bootstrap/realm');
2222

2323
const { validateString } = require('internal/validators');
24+
const fs = require('fs'); // Import all of `fs` so that it can be monkey-patched.
25+
const internalFS = require('internal/fs/utils');
2426
const path = require('path');
2527
const { pathToFileURL, fileURLToPath, URL } = require('internal/url');
2628

@@ -39,6 +41,23 @@ let debug = require('internal/util/debuglog').debuglog('module', (fn) => {
3941

4042
/** @typedef {import('internal/modules/cjs/loader.js').Module} Module */
4143

44+
/**
45+
* Cache for storing resolved real paths of modules.
46+
* In order to minimize unnecessary lstat() calls, this cache is a list of known-real paths.
47+
* Set to an empty Map to reset.
48+
* @type {Map<string, string>}
49+
*/
50+
const realpathCache = new SafeMap();
51+
/**
52+
* Resolves the path of a given `require` specifier, following symlinks.
53+
* @param {string} requestPath The `require` specifier
54+
*/
55+
function toRealPath(requestPath) {
56+
return fs.realpathSync(requestPath, {
57+
[internalFS.realpathCacheKey]: realpathCache,
58+
});
59+
}
60+
4261
/** @type {Set<string>} */
4362
let cjsConditions;
4463
/**
@@ -310,4 +329,5 @@ module.exports = {
310329
makeRequireFunction,
311330
normalizeReferrerURL,
312331
stripBOM,
332+
toRealPath,
313333
};

lib/internal/modules/package_json_reader.js

+50-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@ const {
44
JSONParse,
55
ObjectPrototypeHasOwnProperty,
66
SafeMap,
7+
StringPrototypeEndsWith,
8+
StringPrototypeIndexOf,
9+
StringPrototypeLastIndexOf,
10+
StringPrototypeSlice,
711
} = primordials;
812
const {
913
ERR_INVALID_PACKAGE_CONFIG,
1014
} = require('internal/errors').codes;
1115
const { internalModuleReadJSON } = internalBinding('fs');
12-
const { toNamespacedPath } = require('path');
16+
const { resolve, sep, toNamespacedPath } = require('path');
17+
const permission = require('internal/process/permission');
1318
const { kEmptyObject, setOwnProperty } = require('internal/util');
1419

1520
const { fileURLToPath, pathToFileURL } = require('internal/url');
@@ -111,4 +116,47 @@ function read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
111116
return result;
112117
}
113118

114-
module.exports = { read };
119+
/**
120+
* @param {string} requestPath
121+
* @return {PackageConfig}
122+
*/
123+
function readPackage(requestPath) {
124+
return read(resolve(requestPath, 'package.json'));
125+
}
126+
127+
/**
128+
* Get the nearest parent package.json file from a given path.
129+
* Return the package.json data and the path to the package.json file, or false.
130+
* @param {string} checkPath The path to start searching from.
131+
*/
132+
function readPackageScope(checkPath) {
133+
const rootSeparatorIndex = StringPrototypeIndexOf(checkPath, sep);
134+
let separatorIndex;
135+
const enabledPermission = permission.isEnabled();
136+
do {
137+
separatorIndex = StringPrototypeLastIndexOf(checkPath, sep);
138+
checkPath = StringPrototypeSlice(checkPath, 0, separatorIndex);
139+
// Stop the search when the process doesn't have permissions
140+
// to walk upwards
141+
if (enabledPermission && !permission.has('fs.read', checkPath + sep)) {
142+
return false;
143+
}
144+
if (StringPrototypeEndsWith(checkPath, sep + 'node_modules')) {
145+
return false;
146+
}
147+
const pjson = readPackage(checkPath + sep);
148+
if (pjson.exists) {
149+
return {
150+
data: pjson,
151+
path: checkPath,
152+
};
153+
}
154+
} while (separatorIndex > rootSeparatorIndex);
155+
return false;
156+
}
157+
158+
module.exports = {
159+
read,
160+
readPackage,
161+
readPackageScope,
162+
};

lib/internal/modules/run_main.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ function resolveMainPath(main) {
1515
// Note extension resolution for the main entry point can be deprecated in a
1616
// future major.
1717
// Module._findPath is monkey-patchable here.
18-
const { Module, toRealPath } = require('internal/modules/cjs/loader');
18+
const { Module } = require('internal/modules/cjs/loader');
1919
let mainPath = Module._findPath(path.resolve(main), null, true);
2020
if (!mainPath) { return; }
2121

2222
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
2323
if (!preserveSymlinksMain) {
24+
const { toRealPath } = require('internal/modules/helpers');
2425
mainPath = toRealPath(mainPath);
2526
}
2627

@@ -48,7 +49,7 @@ function shouldUseESMLoader(mainPath) {
4849
if (mainPath && StringPrototypeEndsWith(mainPath, '.mjs')) { return true; }
4950
if (!mainPath || StringPrototypeEndsWith(mainPath, '.cjs')) { return false; }
5051

51-
const { readPackageScope } = require('internal/modules/cjs/loader');
52+
const { readPackageScope } = require('internal/modules/package_json_reader');
5253
const pkg = readPackageScope(mainPath);
5354
// No need to guard `pkg` as it can only be an object or `false`.
5455
return pkg.data?.type === 'module' || getOptionValue('--experimental-default-type') === 'module';

0 commit comments

Comments
 (0)