Skip to content

Commit 1769bf3

Browse files
committed
lib: merge cjs and esm package json reader caches
PR-URL: nodejs/node#48477 Backport-PR-URL: nodejs/node#50669 Reviewed-By: Jacob Smith <[email protected]> Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Mohammed Keyvanzadeh <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent f2f4dd6 commit 1769bf3

File tree

9 files changed

+196
-217
lines changed

9 files changed

+196
-217
lines changed

graal-nodejs/lib/internal/modules/cjs/loader.js

+15-39
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ const {
8383
pendingDeprecate,
8484
emitExperimentalWarning,
8585
kEmptyObject,
86-
filterOwnProperties,
8786
setOwnProperty,
8887
getLazy,
8988
} = require('internal/util');
@@ -354,36 +353,12 @@ function initializeCJS() {
354353
// -> a.<ext>
355354
// -> a/index.<ext>
356355

357-
const packageJsonCache = new SafeMap();
358-
356+
/**
357+
* @param {string} requestPath
358+
* @return {PackageConfig}
359+
*/
359360
function readPackage(requestPath) {
360-
const jsonPath = path.resolve(requestPath, 'package.json');
361-
362-
const existing = packageJsonCache.get(jsonPath);
363-
if (existing !== undefined) return existing;
364-
365-
const result = packageJsonReader.read(jsonPath);
366-
const json = result.containsKeys === false ? '{}' : result.string;
367-
if (json === undefined) {
368-
packageJsonCache.set(jsonPath, false);
369-
return false;
370-
}
371-
372-
try {
373-
const filtered = filterOwnProperties(JSONParse(json), [
374-
'name',
375-
'main',
376-
'exports',
377-
'imports',
378-
'type',
379-
]);
380-
packageJsonCache.set(jsonPath, filtered);
381-
return filtered;
382-
} catch (e) {
383-
e.path = jsonPath;
384-
e.message = 'Error parsing ' + jsonPath + ': ' + e.message;
385-
throw e;
386-
}
361+
return packageJsonReader.read(path.resolve(requestPath, 'package.json'));
387362
}
388363

389364
let _readPackage = readPackage;
@@ -407,7 +382,7 @@ function readPackageScope(checkPath) {
407382
if (StringPrototypeEndsWith(checkPath, sep + 'node_modules'))
408383
return false;
409384
const pjson = _readPackage(checkPath + sep);
410-
if (pjson) return {
385+
if (pjson.exists) return {
411386
data: pjson,
412387
path: checkPath,
413388
};
@@ -416,7 +391,7 @@ function readPackageScope(checkPath) {
416391
}
417392

418393
function tryPackage(requestPath, exts, isMain, originalPath) {
419-
const pkg = _readPackage(requestPath)?.main;
394+
const pkg = _readPackage(requestPath).main;
420395

421396
if (!pkg) {
422397
return tryExtensions(path.resolve(requestPath, 'index'), exts, isMain);
@@ -521,9 +496,10 @@ function trySelfParentPath(parent) {
521496
function trySelf(parentPath, request) {
522497
if (!parentPath) return false;
523498

524-
const { data: pkg, path: pkgPath } = readPackageScope(parentPath) || {};
525-
if (!pkg || pkg.exports === undefined) return false;
526-
if (typeof pkg.name !== 'string') return false;
499+
const { data: pkg, path: pkgPath } = readPackageScope(parentPath);
500+
if (!pkg || pkg.exports == null || pkg.name === undefined) {
501+
return false;
502+
}
527503

528504
let expansion;
529505
if (request === pkg.name) {
@@ -558,7 +534,7 @@ function resolveExports(nmPath, request) {
558534
return;
559535
const pkgPath = path.resolve(nmPath, name);
560536
const pkg = _readPackage(pkgPath);
561-
if (pkg?.exports != null) {
537+
if (pkg.exists && pkg.exports != null) {
562538
try {
563539
const { packageExportsResolve } = require('internal/modules/esm/resolve');
564540
return finalizeEsmResolution(packageExportsResolve(
@@ -1016,7 +992,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
1016992

1017993
if (request[0] === '#' && (parent?.filename || parent?.id === '<repl>')) {
1018994
const parentPath = parent?.filename ?? process.cwd() + path.sep;
1019-
const pkg = readPackageScope(parentPath) || {};
995+
const pkg = readPackageScope(parentPath) || { __proto__: null };
1020996
if (pkg.data?.imports != null) {
1021997
try {
1022998
const { packageImportsResolve } = require('internal/modules/esm/resolve');
@@ -1262,9 +1238,9 @@ Module._extensions['.js'] = function(module, filename) {
12621238
content = fs.readFileSync(filename, 'utf8');
12631239
}
12641240
if (StringPrototypeEndsWith(filename, '.js')) {
1265-
const pkg = readPackageScope(filename);
1241+
const pkg = readPackageScope(filename) || { __proto__: null };
12661242
// Function require shouldn't be used in ES modules.
1267-
if (pkg?.data?.type === 'module') {
1243+
if (pkg.data?.type === 'module') {
12681244
const parent = moduleParentCache.get(module);
12691245
const parentPath = parent?.filename;
12701246
const packageJsonPath = path.resolve(pkg.path, 'package.json');
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,10 @@
11
'use strict';
22

33
const {
4-
JSONParse,
5-
ObjectPrototypeHasOwnProperty,
6-
SafeMap,
74
StringPrototypeEndsWith,
85
} = primordials;
96
const { URL, fileURLToPath } = require('internal/url');
10-
const {
11-
ERR_INVALID_PACKAGE_CONFIG,
12-
} = require('internal/errors').codes;
13-
14-
const { filterOwnProperties } = require('internal/util');
15-
16-
17-
/**
18-
* @typedef {string | string[] | Record<string, unknown>} Exports
19-
* @typedef {'module' | 'commonjs'} PackageType
20-
* @typedef {{
21-
* pjsonPath: string,
22-
* exports?: ExportConfig,
23-
* name?: string,
24-
* main?: string,
25-
* type?: PackageType,
26-
* }} PackageConfig
27-
*/
28-
29-
/** @type {Map<string, PackageConfig>} */
30-
const packageJSONCache = new SafeMap();
31-
32-
33-
/**
34-
* @param {string} path
35-
* @param {string} specifier
36-
* @param {string | URL | undefined} base
37-
* @returns {PackageConfig}
38-
*/
39-
function getPackageConfig(path, specifier, base) {
40-
const existing = packageJSONCache.get(path);
41-
if (existing !== undefined) {
42-
return existing;
43-
}
44-
const packageJsonReader = require('internal/modules/package_json_reader');
45-
const source = packageJsonReader.read(path).string;
46-
if (source === undefined) {
47-
const packageConfig = {
48-
pjsonPath: path,
49-
exists: false,
50-
main: undefined,
51-
name: undefined,
52-
type: 'none',
53-
exports: undefined,
54-
imports: undefined,
55-
};
56-
packageJSONCache.set(path, packageConfig);
57-
return packageConfig;
58-
}
59-
60-
let packageJSON;
61-
try {
62-
packageJSON = JSONParse(source);
63-
} catch (error) {
64-
throw new ERR_INVALID_PACKAGE_CONFIG(
65-
path,
66-
(base ? `"${specifier}" from ` : '') + fileURLToPath(base || specifier),
67-
error.message,
68-
);
69-
}
70-
71-
let { imports, main, name, type } = filterOwnProperties(packageJSON, ['imports', 'main', 'name', 'type']);
72-
const exports = ObjectPrototypeHasOwnProperty(packageJSON, 'exports') ? packageJSON.exports : undefined;
73-
if (typeof imports !== 'object' || imports === null) {
74-
imports = undefined;
75-
}
76-
if (typeof main !== 'string') {
77-
main = undefined;
78-
}
79-
if (typeof name !== 'string') {
80-
name = undefined;
81-
}
82-
// Ignore unknown types for forwards compatibility
83-
if (type !== 'module' && type !== 'commonjs') {
84-
type = 'none';
85-
}
86-
87-
const packageConfig = {
88-
pjsonPath: path,
89-
exists: true,
90-
main,
91-
name,
92-
type,
93-
exports,
94-
imports,
95-
};
96-
packageJSONCache.set(path, packageConfig);
97-
return packageConfig;
98-
}
99-
7+
const packageJsonReader = require('internal/modules/package_json_reader');
1008

1019
/**
10210
* @param {URL | string} resolved
@@ -109,7 +17,11 @@ function getPackageScopeConfig(resolved) {
10917
if (StringPrototypeEndsWith(packageJSONPath, 'node_modules/package.json')) {
11018
break;
11119
}
112-
const packageConfig = getPackageConfig(fileURLToPath(packageJSONUrl), resolved);
20+
const packageConfig = packageJsonReader.read(fileURLToPath(packageJSONUrl), {
21+
__proto__: null,
22+
specifier: resolved,
23+
isESM: true,
24+
});
11325
if (packageConfig.exists) {
11426
return packageConfig;
11527
}
@@ -124,7 +36,8 @@ function getPackageScopeConfig(resolved) {
12436
}
12537
}
12638
const packageJSONPath = fileURLToPath(packageJSONUrl);
127-
const packageConfig = {
39+
return {
40+
__proto__: null,
12841
pjsonPath: packageJSONPath,
12942
exists: false,
13043
main: undefined,
@@ -133,12 +46,9 @@ function getPackageScopeConfig(resolved) {
13346
exports: undefined,
13447
imports: undefined,
13548
};
136-
packageJSONCache.set(packageJSONPath, packageConfig);
137-
return packageConfig;
13849
}
13950

14051

14152
module.exports = {
142-
getPackageConfig,
14353
getPackageScopeConfig,
14454
};

graal-nodejs/lib/internal/modules/esm/resolve.js

+7-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const {
44
ArrayIsArray,
55
ArrayPrototypeJoin,
66
ArrayPrototypeShift,
7-
JSONParse,
87
JSONStringify,
98
ObjectGetOwnPropertyNames,
109
ObjectPrototypeHasOwnProperty,
@@ -55,9 +54,9 @@ const {
5554
} = require('internal/errors').codes;
5655

5756
const { Module: CJSModule } = require('internal/modules/cjs/loader');
58-
const packageJsonReader = require('internal/modules/package_json_reader');
59-
const { getPackageConfig, getPackageScopeConfig } = require('internal/modules/esm/package_config');
57+
const { getPackageScopeConfig } = require('internal/modules/esm/package_config');
6058
const { getConditionsSet } = require('internal/modules/esm/utils');
59+
const packageJsonReader = require('internal/modules/package_json_reader');
6160
const { internalModuleStat } = internalBinding('fs');
6261

6362
/**
@@ -231,8 +230,8 @@ function resolveDirectoryEntry(search) {
231230
const pkgJsonPath = resolve(dirPath, 'package.json');
232231
if (fileExists(pkgJsonPath)) {
233232
const pkgJson = packageJsonReader.read(pkgJsonPath);
234-
if (pkgJson.containsKeys) {
235-
const { main } = JSONParse(pkgJson.string);
233+
if (pkgJson.exists) {
234+
const { main } = pkgJson;
236235
if (main != null) {
237236
const mainUrl = pathToFileURL(resolve(dirPath, main));
238237
return resolveExtensionsWithTryExactName(mainUrl);
@@ -810,8 +809,7 @@ function packageResolve(specifier, base, conditions) {
810809
const packageConfig = getPackageScopeConfig(base);
811810
if (packageConfig.exists) {
812811
const packageJSONUrl = pathToFileURL(packageConfig.pjsonPath);
813-
if (packageConfig.name === packageName &&
814-
packageConfig.exports !== undefined && packageConfig.exports !== null) {
812+
if (packageConfig.exports != null && packageConfig.name === packageName) {
815813
return packageExportsResolve(
816814
packageJSONUrl, packageSubpath, packageConfig, base, conditions);
817815
}
@@ -835,8 +833,8 @@ function packageResolve(specifier, base, conditions) {
835833
}
836834

837835
// Package match.
838-
const packageConfig = getPackageConfig(packageJSONPath, specifier, base);
839-
if (packageConfig.exports !== undefined && packageConfig.exports !== null) {
836+
const packageConfig = packageJsonReader.read(packageJSONPath, { __proto__: null, specifier, base, isESM: true });
837+
if (packageConfig.exports != null) {
840838
return packageExportsResolve(
841839
packageJSONUrl, packageSubpath, packageConfig, base, conditions);
842840
}

0 commit comments

Comments
 (0)