GeezerVison is showing github.com — lib: merge cjs and esm package json reader caches · nodejs/node@fe26f8a
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/cjs/loader.js +15-39Lines changed: 15 additions & 39 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -83,7 +83,6 @@ const { | 83 | 83 | pendingDeprecate, | 84 | 84 | emitExperimentalWarning, | 85 | 85 | kEmptyObject, | 86 | | - filterOwnProperties, | 87 | 86 | setOwnProperty, | 88 | 87 | getLazy, | 89 | 88 | } = require('internal/util'); | @@ -354,36 +353,12 @@ function initializeCJS() { | 354 | 353 | // -> a.<ext> | 355 | 354 | // -> a/index.<ext> | 356 | 355 |
| 357 | | -const packageJsonCache = new SafeMap(); | 358 | | - | | 356 | +/** | | 357 | + * @param {string} requestPath | | 358 | + * @return {PackageConfig} | | 359 | + */ | 359 | 360 | 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')); | 387 | 362 | } | 388 | 363 |
| 389 | 364 | let _readPackage = readPackage; | @@ -407,7 +382,7 @@ function readPackageScope(checkPath) { | 407 | 382 | if (StringPrototypeEndsWith(checkPath, sep + 'node_modules')) | 408 | 383 | return false; | 409 | 384 | const pjson = _readPackage(checkPath + sep); | 410 | | - if (pjson) return { | | 385 | + if (pjson.exists) return { | 411 | 386 | data: pjson, | 412 | 387 | path: checkPath, | 413 | 388 | }; | @@ -416,7 +391,7 @@ function readPackageScope(checkPath) { | 416 | 391 | } | 417 | 392 |
| 418 | 393 | function tryPackage(requestPath, exts, isMain, originalPath) { | 419 | | - const pkg = _readPackage(requestPath)?.main; | | 394 | + const pkg = _readPackage(requestPath).main; | 420 | 395 |
| 421 | 396 | if (!pkg) { | 422 | 397 | return tryExtensions(path.resolve(requestPath, 'index'), exts, isMain); | @@ -521,9 +496,10 @@ function trySelfParentPath(parent) { | 521 | 496 | function trySelf(parentPath, request) { | 522 | 497 | if (!parentPath) return false; | 523 | 498 |
| 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 | + } | 527 | 503 |
| 528 | 504 | let expansion; | 529 | 505 | if (request === pkg.name) { | @@ -558,7 +534,7 @@ function resolveExports(nmPath, request) { | 558 | 534 | return; | 559 | 535 | const pkgPath = path.resolve(nmPath, name); | 560 | 536 | const pkg = _readPackage(pkgPath); | 561 | | - if (pkg?.exports != null) { | | 537 | + if (pkg.exists && pkg.exports != null) { | 562 | 538 | try { | 563 | 539 | const { packageExportsResolve } = require('internal/modules/esm/resolve'); | 564 | 540 | return finalizeEsmResolution(packageExportsResolve( | @@ -1016,7 +992,7 @@ Module._resolveFilename = function(request, parent, isMain, options) { | 1016 | 992 |
| 1017 | 993 | if (request[0] === '#' && (parent?.filename || parent?.id === '<repl>')) { | 1018 | 994 | const parentPath = parent?.filename ?? process.cwd() + path.sep; | 1019 | | - const pkg = readPackageScope(parentPath) || {}; | | 995 | + const pkg = readPackageScope(parentPath) || { __proto__: null }; | 1020 | 996 | if (pkg.data?.imports != null) { | 1021 | 997 | try { | 1022 | 998 | const { packageImportsResolve } = require('internal/modules/esm/resolve'); | @@ -1262,9 +1238,9 @@ Module._extensions['.js'] = function(module, filename) { | 1262 | 1238 | content = fs.readFileSync(filename, 'utf8'); | 1263 | 1239 | } | 1264 | 1240 | if (StringPrototypeEndsWith(filename, '.js')) { | 1265 | | - const pkg = readPackageScope(filename); | | 1241 | + const pkg = readPackageScope(filename) || { __proto__: null }; | 1266 | 1242 | // Function require shouldn't be used in ES modules. | 1267 | | - if (pkg?.data?.type === 'module') { | | 1243 | + if (pkg.data?.type === 'module') { | 1268 | 1244 | const parent = moduleParentCache.get(module); | 1269 | 1245 | const parentPath = parent?.filename; | 1270 | 1246 | const packageJsonPath = path.resolve(pkg.path, 'package.json'); | |
Collapse file Copy file name to clipboard +8-98Lines changed: 8 additions & 98 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 1 | 1 | 'use strict'; | 2 | 2 |
| 3 | 3 | const { | 4 | | - JSONParse, | 5 | | - ObjectPrototypeHasOwnProperty, | 6 | | - SafeMap, | 7 | 4 | StringPrototypeEndsWith, | 8 | 5 | } = primordials; | 9 | 6 | 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'); | 100 | 8 |
| 101 | 9 | /** | 102 | 10 | * @param {URL | string} resolved | @@ -109,7 +17,11 @@ function getPackageScopeConfig(resolved) { | 109 | 17 | if (StringPrototypeEndsWith(packageJSONPath, 'node_modules/package.json')) { | 110 | 18 | break; | 111 | 19 | } | 112 | | - const packageConfig = getPackageConfig(fileURLToPath(packageJSONUrl), resolved); | | 20 | + const packageConfig = packageJsonReader.read(fileURLToPath(packageJSONUrl), { | | 21 | + __proto__: null, | | 22 | + specifier: resolved, | | 23 | + isESM: true, | | 24 | + }); | 113 | 25 | if (packageConfig.exists) { | 114 | 26 | return packageConfig; | 115 | 27 | } | @@ -124,7 +36,8 @@ function getPackageScopeConfig(resolved) { | 124 | 36 | } | 125 | 37 | } | 126 | 38 | const packageJSONPath = fileURLToPath(packageJSONUrl); | 127 | | - const packageConfig = { | | 39 | + return { | | 40 | + __proto__: null, | 128 | 41 | pjsonPath: packageJSONPath, | 129 | 42 | exists: false, | 130 | 43 | main: undefined, | @@ -133,12 +46,9 @@ function getPackageScopeConfig(resolved) { | 133 | 46 | exports: undefined, | 134 | 47 | imports: undefined, | 135 | 48 | }; | 136 | | - packageJSONCache.set(packageJSONPath, packageConfig); | 137 | | - return packageConfig; | 138 | 49 | } | 139 | 50 |
| 140 | 51 |
| 141 | 52 | module.exports = { | 142 | | - getPackageConfig, | 143 | 53 | getPackageScopeConfig, | 144 | 54 | }; |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/esm/resolve.js +7-9Lines changed: 7 additions & 9 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 4 | 4 | ArrayIsArray, | 5 | 5 | ArrayPrototypeJoin, | 6 | 6 | ArrayPrototypeShift, | 7 | | - JSONParse, | 8 | 7 | JSONStringify, | 9 | 8 | ObjectGetOwnPropertyNames, | 10 | 9 | ObjectPrototypeHasOwnProperty, | @@ -55,9 +54,9 @@ const { | 55 | 54 | } = require('internal/errors').codes; | 56 | 55 |
| 57 | 56 | 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'); | 60 | 58 | const { getConditionsSet } = require('internal/modules/esm/utils'); | | 59 | +const packageJsonReader = require('internal/modules/package_json_reader'); | 61 | 60 | const { internalModuleStat } = internalBinding('fs'); | 62 | 61 |
| 63 | 62 | /** | @@ -231,8 +230,8 @@ function resolveDirectoryEntry(search) { | 231 | 230 | const pkgJsonPath = resolve(dirPath, 'package.json'); | 232 | 231 | if (fileExists(pkgJsonPath)) { | 233 | 232 | const pkgJson = packageJsonReader.read(pkgJsonPath); | 234 | | - if (pkgJson.containsKeys) { | 235 | | - const { main } = JSONParse(pkgJson.string); | | 233 | + if (pkgJson.exists) { | | 234 | + const { main } = pkgJson; | 236 | 235 | if (main != null) { | 237 | 236 | const mainUrl = pathToFileURL(resolve(dirPath, main)); | 238 | 237 | return resolveExtensionsWithTryExactName(mainUrl); | @@ -810,8 +809,7 @@ function packageResolve(specifier, base, conditions) { | 810 | 809 | const packageConfig = getPackageScopeConfig(base); | 811 | 810 | if (packageConfig.exists) { | 812 | 811 | 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) { | 815 | 813 | return packageExportsResolve( | 816 | 814 | packageJSONUrl, packageSubpath, packageConfig, base, conditions); | 817 | 815 | } | @@ -835,8 +833,8 @@ function packageResolve(specifier, base, conditions) { | 835 | 833 | } | 836 | 834 |
| 837 | 835 | // 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) { | 840 | 838 | return packageExportsResolve( | 841 | 839 | packageJSONUrl, packageSubpath, packageConfig, base, conditions); | 842 | 840 | } | |
|