GeezerVison is showing github.com — src: move package resolver to c++ · nodejs/node@45e4f82
File treeExpand file treeCollapse file tree Open diff view settings fixtures/node_modules/pkgexports-number
Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/cjs/loader.js +14-15Lines changed: 14 additions & 15 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -427,7 +427,7 @@ ObjectDefineProperty(Module, '_readPackage', { | 427 | 427 | * @param {string} originalPath The specifier passed to `require` | 428 | 428 | */ | 429 | 429 | function tryPackage(requestPath, exts, isMain, originalPath) { | 430 | | - const pkg = _readPackage(requestPath).main; | | 430 | + const { main: pkg, pjsonPath } = _readPackage(requestPath); | 431 | 431 |
| 432 | 432 | if (!pkg) { | 433 | 433 | return tryExtensions(path.resolve(requestPath, 'index'), exts, isMain); | @@ -446,14 +446,13 @@ function tryPackage(requestPath, exts, isMain, originalPath) { | 446 | 446 | 'Please verify that the package.json has a valid "main" entry', | 447 | 447 | ); | 448 | 448 | err.code = 'MODULE_NOT_FOUND'; | 449 | | - err.path = path.resolve(requestPath, 'package.json'); | | 449 | + err.path = pjsonPath; | 450 | 450 | err.requestPath = originalPath; | 451 | 451 | // TODO(BridgeAR): Add the requireStack as well. | 452 | 452 | throw err; | 453 | 453 | } else { | 454 | | - const jsonPath = path.resolve(requestPath, 'package.json'); | 455 | 454 | process.emitWarning( | 456 | | - `Invalid 'main' field in '${jsonPath}' of '${pkg}'. ` + | | 455 | + `Invalid 'main' field in '${pjsonPath}' of '${pkg}'. ` + | 457 | 456 | 'Please either fix that or report it to the module author', | 458 | 457 | 'DeprecationWarning', | 459 | 458 | 'DEP0128', | @@ -539,28 +538,28 @@ function trySelfParentPath(parent) { | 539 | 538 | function trySelf(parentPath, request) { | 540 | 539 | if (!parentPath) { return false; } | 541 | 540 |
| 542 | | - const { data: pkg, path: pkgPath } = packageJsonReader.readPackageScope(parentPath); | 543 | | - if (!pkg || pkg.exports == null || pkg.name === undefined) { | | 541 | + const pkg = packageJsonReader.getNearestParentPackageJSON(parentPath); | | 542 | + if (pkg?.data.exports === undefined || pkg.data.name === undefined) { | 544 | 543 | return false; | 545 | 544 | } | 546 | 545 |
| 547 | 546 | let expansion; | 548 | | - if (request === pkg.name) { | | 547 | + if (request === pkg.data.name) { | 549 | 548 | expansion = '.'; | 550 | | - } else if (StringPrototypeStartsWith(request, `${pkg.name}/`)) { | 551 | | - expansion = '.' + StringPrototypeSlice(request, pkg.name.length); | | 549 | + } else if (StringPrototypeStartsWith(request, `${pkg.data.name}/`)) { | | 550 | + expansion = '.' + StringPrototypeSlice(request, pkg.data.name.length); | 552 | 551 | } else { | 553 | 552 | return false; | 554 | 553 | } | 555 | 554 |
| 556 | 555 | try { | 557 | 556 | const { packageExportsResolve } = require('internal/modules/esm/resolve'); | 558 | 557 | return finalizeEsmResolution(packageExportsResolve( | 559 | | - pathToFileURL(pkgPath + '/package.json'), expansion, pkg, | 560 | | - pathToFileURL(parentPath), getCjsConditions()), parentPath, pkgPath); | | 558 | + pathToFileURL(pkg.path + '/package.json'), expansion, pkg.data, | | 559 | + pathToFileURL(parentPath), getCjsConditions()), parentPath, pkg.path); | 561 | 560 | } catch (e) { | 562 | 561 | if (e.code === 'ERR_MODULE_NOT_FOUND') { | 563 | | - throw createEsmNotFoundErr(request, pkgPath + '/package.json'); | | 562 | + throw createEsmNotFoundErr(request, pkg.path + '/package.json'); | 564 | 563 | } | 565 | 564 | throw e; | 566 | 565 | } | @@ -1099,7 +1098,7 @@ Module._resolveFilename = function(request, parent, isMain, options) { | 1099 | 1098 |
| 1100 | 1099 | if (request[0] === '#' && (parent?.filename || parent?.id === '<repl>')) { | 1101 | 1100 | const parentPath = parent?.filename ?? process.cwd() + path.sep; | 1102 | | - const pkg = packageJsonReader.readPackageScope(parentPath) || { __proto__: null }; | | 1101 | + const pkg = packageJsonReader.getNearestParentPackageJSON(parentPath) || { __proto__: null }; | 1103 | 1102 | if (pkg.data?.imports != null) { | 1104 | 1103 | try { | 1105 | 1104 | const { packageImportsResolve } = require('internal/modules/esm/resolve'); | @@ -1397,9 +1396,9 @@ Module._extensions['.js'] = function(module, filename) { | 1397 | 1396 | content = fs.readFileSync(filename, 'utf8'); | 1398 | 1397 | } | 1399 | 1398 | if (StringPrototypeEndsWith(filename, '.js')) { | 1400 | | - const pkg = packageJsonReader.readPackageScope(filename) || { __proto__: null }; | | 1399 | + const pkg = packageJsonReader.getNearestParentPackageJSON(filename); | 1401 | 1400 | // Function require shouldn't be used in ES modules. | 1402 | | - if (pkg.data?.type === 'module') { | | 1401 | + if (pkg?.data.type === 'module') { | 1403 | 1402 | // This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed. | 1404 | 1403 | const parent = moduleParentCache.get(module); | 1405 | 1404 | const parentPath = parent?.filename; | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/esm/get_format.js +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -19,7 +19,7 @@ const { | 19 | 19 | const experimentalNetworkImports = | 20 | 20 | getOptionValue('--experimental-network-imports'); | 21 | 21 | const { containsModuleSyntax } = internalBinding('contextify'); | 22 | | -const { getPackageType } = require('internal/modules/esm/resolve'); | | 22 | +const { getPackageType } = require('internal/modules/esm/package_config'); | 23 | 23 | const { fileURLToPath } = require('internal/url'); | 24 | 24 | const { ERR_UNKNOWN_FILE_EXTENSION } = require('internal/errors').codes; | 25 | 25 |
| |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/esm/module_job.js +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -228,7 +228,7 @@ class ModuleJob { | 228 | 228 | const packageConfig = | 229 | 229 | StringPrototypeStartsWith(this.module.url, 'file://') && | 230 | 230 | RegExpPrototypeExec(/\.js(\?[^#]*)?(#.*)?$/, this.module.url) !== null && | 231 | | - require('internal/modules/esm/resolve') | | 231 | + require('internal/modules/esm/package_config') | 232 | 232 | .getPackageScopeConfig(this.module.url); | 233 | 233 | if (packageConfig.type === 'module') { | 234 | 234 | e.message += | |
Collapse file Copy file name to clipboard +22-47Lines changed: 22 additions & 47 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 1 | 1 | 'use strict'; | 2 | 2 |
| 3 | | -const { | 4 | | - StringPrototypeEndsWith, | 5 | | -} = primordials; | 6 | | -const { URL, fileURLToPath } = require('internal/url'); | 7 | | -const packageJsonReader = require('internal/modules/package_json_reader'); | | 3 | +const { ArrayIsArray } = primordials; | | 4 | +const modulesBinding = internalBinding('modules'); | | 5 | +const { deserializePackageJSON } = require('internal/modules/package_json_reader'); | 8 | 6 |
| 9 | | -/** | 10 | | - * @typedef {object} PackageConfig | 11 | | - * @property {string} pjsonPath - The path to the package.json file. | 12 | | - * @property {boolean} exists - Whether the package.json file exists. | 13 | | - * @property {'none' | 'commonjs' | 'module'} type - The type of the package. | 14 | | - * @property {string} [name] - The name of the package. | 15 | | - * @property {string} [main] - The main entry point of the package. | 16 | | - * @property {PackageTarget} [exports] - The exports configuration of the package. | 17 | | - * @property {Record<string, string | Record<string, string>>} [imports] - The imports configuration of the package. | 18 | | - */ | 19 | | -/** | 20 | | - * @typedef {string | string[] | Record<string, string | Record<string, string>>} PackageTarget | 21 | | - */ | | 7 | +// TODO(@anonrig): Merge this file with internal/esm/package_json_reader.js | 22 | 8 |
| 23 | 9 | /** | 24 | 10 | * Returns the package configuration for the given resolved URL. | 25 | 11 | * @param {URL | string} resolved - The resolved URL. | 26 | | - * @returns {PackageConfig} - The package configuration. | | 12 | + * @returns {import('typings/internalBinding/modules').PackageConfig} - The package configuration. | 27 | 13 | */ | 28 | 14 | function getPackageScopeConfig(resolved) { | 29 | | - let packageJSONUrl = new URL('./package.json', resolved); | 30 | | - while (true) { | 31 | | - const packageJSONPath = packageJSONUrl.pathname; | 32 | | - if (StringPrototypeEndsWith(packageJSONPath, 'node_modules/package.json')) { | 33 | | - break; | 34 | | - } | 35 | | - const packageConfig = packageJsonReader.read(fileURLToPath(packageJSONUrl), { | 36 | | - __proto__: null, | 37 | | - specifier: resolved, | 38 | | - isESM: true, | 39 | | - }); | 40 | | - if (packageConfig.exists) { | 41 | | - return packageConfig; | 42 | | - } | 43 | | - | 44 | | - const lastPackageJSONUrl = packageJSONUrl; | 45 | | - packageJSONUrl = new URL('../package.json', packageJSONUrl); | | 15 | + const result = modulesBinding.getPackageScopeConfig(`${resolved}`); | 46 | 16 |
| 47 | | - // Terminates at root where ../package.json equals ../../package.json | 48 | | - // (can't just check "/package.json" for Windows support). | 49 | | - if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) { | 50 | | - break; | 51 | | - } | | 17 | + if (ArrayIsArray(result)) { | | 18 | + return deserializePackageJSON(`${resolved}`, result, false /* checkIntegrity */); | 52 | 19 | } | 53 | | - const packageJSONPath = fileURLToPath(packageJSONUrl); | | 20 | + | | 21 | + // This means that the response is a string | | 22 | + // and it is the path to the package.json file | 54 | 23 | return { | 55 | 24 | __proto__: null, | 56 | | - pjsonPath: packageJSONPath, | | 25 | + pjsonPath: result, | 57 | 26 | exists: false, | 58 | | - main: undefined, | 59 | | - name: undefined, | 60 | 27 | type: 'none', | 61 | | - exports: undefined, | 62 | | - imports: undefined, | 63 | 28 | }; | 64 | 29 | } | 65 | 30 |
| | 31 | +/** | | 32 | + * Returns the package type for a given URL. | | 33 | + * @param {URL} url - The URL to get the package type for. | | 34 | + */ | | 35 | +function getPackageType(url) { | | 36 | + // TODO(@anonrig): Write a C++ function that returns only "type". | | 37 | + return getPackageScopeConfig(url).type; | | 38 | +} | | 39 | + | 66 | 40 |
| 67 | 41 | module.exports = { | 68 | 42 | getPackageScopeConfig, | | 43 | + getPackageType, | 69 | 44 | }; |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/esm/resolve.js +4-14Lines changed: 4 additions & 14 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -198,7 +198,7 @@ const legacyMainResolveExtensionsIndexes = { | 198 | 198 | * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node) | 199 | 199 | * 5. NOT_FOUND | 200 | 200 | * @param {URL} packageJSONUrl | 201 | | - * @param {PackageConfig} packageConfig | | 201 | + * @param {import('typings/internalBinding/modules').PackageConfig} packageConfig | 202 | 202 | * @param {string | URL | undefined} base | 203 | 203 | * @returns {URL} | 204 | 204 | */ | @@ -502,7 +502,7 @@ function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath, | 502 | 502 | } | 503 | 503 | return resolveResult; | 504 | 504 | } | 505 | | - if (lastException === undefined || lastException === null) { | | 505 | + if (lastException == null) { | 506 | 506 | return lastException; | 507 | 507 | } | 508 | 508 | throw lastException; | @@ -575,7 +575,7 @@ function isConditionalExportsMainSugar(exports, packageJSONUrl, base) { | 575 | 575 | */ | 576 | 576 | function packageExportsResolve( | 577 | 577 | packageJSONUrl, packageSubpath, packageConfig, base, conditions) { | 578 | | - let exports = packageConfig.exports; | | 578 | + let { exports } = packageConfig; | 579 | 579 | if (isConditionalExportsMainSugar(exports, packageJSONUrl, base)) { | 580 | 580 | exports = { '.': exports }; | 581 | 581 | } | @@ -740,15 +740,6 @@ function packageImportsResolve(name, base, conditions) { | 740 | 740 | throw importNotDefined(name, packageJSONUrl, base); | 741 | 741 | } | 742 | 742 |
| 743 | | -/** | 744 | | - * Returns the package type for a given URL. | 745 | | - * @param {URL} url - The URL to get the package type for. | 746 | | - */ | 747 | | -function getPackageType(url) { | 748 | | - const packageConfig = getPackageScopeConfig(url); | 749 | | - return packageConfig.type; | 750 | | -} | 751 | | - | 752 | 743 | /** | 753 | 744 | * Parse a package name from a specifier. | 754 | 745 | * @param {string} specifier - The import specifier. | @@ -796,6 +787,7 @@ function parsePackageName(specifier, base) { | 796 | 787 | * @returns {URL} - The resolved URL. | 797 | 788 | */ | 798 | 789 | function packageResolve(specifier, base, conditions) { | | 790 | + // TODO(@anonrig): Move this to a C++ function. | 799 | 791 | if (BuiltinModule.canBeRequiredWithoutScheme(specifier)) { | 800 | 792 | return new URL('node:' + specifier); | 801 | 793 | } | @@ -1179,8 +1171,6 @@ module.exports = { | 1179 | 1171 | decorateErrorWithCommonJSHints, | 1180 | 1172 | defaultResolve, | 1181 | 1173 | encodedSepRegEx, | 1182 | | - getPackageScopeConfig, | 1183 | | - getPackageType, | 1184 | 1174 | packageExportsResolve, | 1185 | 1175 | packageImportsResolve, | 1186 | 1176 | throwIfInvalidParentURL, | |
|