GeezerVison is showing github.com — esm: move package config helpers · nodejs/node@c0d2098
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 clipboard +142Lines changed: 142 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +'use strict'; | | 2 | + | | 3 | +const { | | 4 | + JSONParse, | | 5 | + SafeMap, | | 6 | + StringPrototypeEndsWith, | | 7 | +} = primordials; | | 8 | +const { URL, fileURLToPath } = require('internal/url'); | | 9 | +const { | | 10 | + ERR_INVALID_PACKAGE_CONFIG, | | 11 | +} = require('internal/errors').codes; | | 12 | + | | 13 | +const packageJsonReader = require('internal/modules/package_json_reader'); | | 14 | + | | 15 | + | | 16 | +/** | | 17 | + * @typedef {string | string[] | Record<string, unknown>} Exports | | 18 | + * @typedef {'module' | 'commonjs'} PackageType | | 19 | + * @typedef {{ | | 20 | + * pjsonPath: string, | | 21 | + * exports?: ExportConfig, | | 22 | + * name?: string, | | 23 | + * main?: string, | | 24 | + * type?: PackageType, | | 25 | + * }} PackageConfig | | 26 | + */ | | 27 | + | | 28 | +/** @type {Map<string, PackageConfig>} */ | | 29 | +const packageJSONCache = new SafeMap(); | | 30 | + | | 31 | + | | 32 | +/** | | 33 | + * @param {string} path | | 34 | + * @param {string} specifier | | 35 | + * @param {string | URL | undefined} base | | 36 | + * @returns {PackageConfig} | | 37 | + */ | | 38 | +function getPackageConfig(path, specifier, base) { | | 39 | + const existing = packageJSONCache.get(path); | | 40 | + if (existing !== undefined) { | | 41 | + return existing; | | 42 | + } | | 43 | + const source = packageJsonReader.read(path).string; | | 44 | + if (source === undefined) { | | 45 | + const packageConfig = { | | 46 | + pjsonPath: path, | | 47 | + exists: false, | | 48 | + main: undefined, | | 49 | + name: undefined, | | 50 | + type: 'none', | | 51 | + exports: undefined, | | 52 | + imports: undefined, | | 53 | + }; | | 54 | + packageJSONCache.set(path, packageConfig); | | 55 | + return packageConfig; | | 56 | + } | | 57 | + | | 58 | + let packageJSON; | | 59 | + try { | | 60 | + packageJSON = JSONParse(source); | | 61 | + } catch (error) { | | 62 | + throw new ERR_INVALID_PACKAGE_CONFIG( | | 63 | + path, | | 64 | + (base ? `"${specifier}" from ` : '') + fileURLToPath(base || specifier), | | 65 | + error.message | | 66 | + ); | | 67 | + } | | 68 | + | | 69 | + let { imports, main, name, type } = packageJSON; | | 70 | + const { exports } = packageJSON; | | 71 | + if (typeof imports !== 'object' || imports === null) { | | 72 | + imports = undefined; | | 73 | + } | | 74 | + if (typeof main !== 'string') { | | 75 | + main = undefined; | | 76 | + } | | 77 | + if (typeof name !== 'string') { | | 78 | + name = undefined; | | 79 | + } | | 80 | + // Ignore unknown types for forwards compatibility | | 81 | + if (type !== 'module' && type !== 'commonjs') { | | 82 | + type = 'none'; | | 83 | + } | | 84 | + | | 85 | + const packageConfig = { | | 86 | + pjsonPath: path, | | 87 | + exists: true, | | 88 | + main, | | 89 | + name, | | 90 | + type, | | 91 | + exports, | | 92 | + imports, | | 93 | + }; | | 94 | + packageJSONCache.set(path, packageConfig); | | 95 | + return packageConfig; | | 96 | +} | | 97 | + | | 98 | + | | 99 | +/** | | 100 | + * @param {URL | string} resolved | | 101 | + * @returns {PackageConfig} | | 102 | + */ | | 103 | +function getPackageScopeConfig(resolved) { | | 104 | + let packageJSONUrl = new URL('./package.json', resolved); | | 105 | + while (true) { | | 106 | + const packageJSONPath = packageJSONUrl.pathname; | | 107 | + if (StringPrototypeEndsWith(packageJSONPath, 'node_modules/package.json')) { | | 108 | + break; | | 109 | + } | | 110 | + const packageConfig = getPackageConfig(fileURLToPath(packageJSONUrl), resolved); | | 111 | + if (packageConfig.exists) { | | 112 | + return packageConfig; | | 113 | + } | | 114 | + | | 115 | + const lastPackageJSONUrl = packageJSONUrl; | | 116 | + packageJSONUrl = new URL('../package.json', packageJSONUrl); | | 117 | + | | 118 | + // Terminates at root where ../package.json equals ../../package.json | | 119 | + // (can't just check "/package.json" for Windows support). | | 120 | + if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) { | | 121 | + break; | | 122 | + } | | 123 | + } | | 124 | + const packageJSONPath = fileURLToPath(packageJSONUrl); | | 125 | + const packageConfig = { | | 126 | + pjsonPath: packageJSONPath, | | 127 | + exists: false, | | 128 | + main: undefined, | | 129 | + name: undefined, | | 130 | + type: 'none', | | 131 | + exports: undefined, | | 132 | + imports: undefined, | | 133 | + }; | | 134 | + packageJSONCache.set(packageJSONPath, packageConfig); | | 135 | + return packageConfig; | | 136 | +} | | 137 | + | | 138 | + | | 139 | +module.exports = { | | 140 | + getPackageConfig, | | 141 | + getPackageScopeConfig, | | 142 | +}; |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/esm/resolve.js +10-109Lines changed: 10 additions & 109 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -58,9 +58,16 @@ const { | 58 | 58 | ERR_NETWORK_IMPORT_DISALLOWED, | 59 | 59 | ERR_UNSUPPORTED_ESM_URL_SCHEME, | 60 | 60 | } = require('internal/errors').codes; | 61 | | -const { Module: CJSModule } = require('internal/modules/cjs/loader'); | 62 | 61 |
| | 62 | +const { Module: CJSModule } = require('internal/modules/cjs/loader'); | 63 | 63 | const packageJsonReader = require('internal/modules/package_json_reader'); | | 64 | +const { getPackageConfig, getPackageScopeConfig } = require('internal/modules/esm/package_config'); | | 65 | + | | 66 | +/** | | 67 | + * @typedef {import('internal/modules/esm/package_config.js').PackageConfig} PackageConfig | | 68 | + */ | | 69 | + | | 70 | + | 64 | 71 | const userConditions = getOptionValue('--conditions'); | 65 | 72 | const noAddons = getOptionValue('--no-addons'); | 66 | 73 | const addonConditions = noAddons ? [] : ['node-addons']; | @@ -74,18 +81,6 @@ const DEFAULT_CONDITIONS = ObjectFreeze([ | 74 | 81 |
| 75 | 82 | const DEFAULT_CONDITIONS_SET = new SafeSet(DEFAULT_CONDITIONS); | 76 | 83 |
| 77 | | -/** | 78 | | - * @typedef {string | string[] | Record<string, unknown>} Exports | 79 | | - * @typedef {'module' | 'commonjs'} PackageType | 80 | | - * @typedef {{ | 81 | | - * pjsonPath: string, | 82 | | - * exports?: ExportConfig, | 83 | | - * name?: string, | 84 | | - * main?: string, | 85 | | - * type?: PackageType, | 86 | | - * }} PackageConfig | 87 | | - */ | 88 | | - | 89 | 84 | const emittedPackageWarnings = new SafeSet(); | 90 | 85 |
| 91 | 86 | function emitTrailingSlashPatternDeprecation(match, pjsonUrl, base) { | @@ -154,7 +149,6 @@ function getConditionsSet(conditions) { | 154 | 149 | } | 155 | 150 |
| 156 | 151 | const realpathCache = new SafeMap(); | 157 | | -const packageJSONCache = new SafeMap(); /* string -> PackageConfig */ | 158 | 152 |
| 159 | 153 | /** | 160 | 154 | * @param {string | URL} path | @@ -163,99 +157,6 @@ const packageJSONCache = new SafeMap(); /* string -> PackageConfig */ | 163 | 157 | const tryStatSync = | 164 | 158 | (path) => statSync(path, { throwIfNoEntry: false }) ?? new Stats(); | 165 | 159 |
| 166 | | -/** | 167 | | - * @param {string} path | 168 | | - * @param {string} specifier | 169 | | - * @param {string | URL | undefined} base | 170 | | - * @returns {PackageConfig} | 171 | | - */ | 172 | | -function getPackageConfig(path, specifier, base) { | 173 | | - const existing = packageJSONCache.get(path); | 174 | | - if (existing !== undefined) { | 175 | | - return existing; | 176 | | - } | 177 | | - const source = packageJsonReader.read(path).string; | 178 | | - if (source === undefined) { | 179 | | - const packageConfig = { | 180 | | - pjsonPath: path, | 181 | | - exists: false, | 182 | | - main: undefined, | 183 | | - name: undefined, | 184 | | - type: 'none', | 185 | | - exports: undefined, | 186 | | - imports: undefined, | 187 | | - }; | 188 | | - packageJSONCache.set(path, packageConfig); | 189 | | - return packageConfig; | 190 | | - } | 191 | | - | 192 | | - let packageJSON; | 193 | | - try { | 194 | | - packageJSON = JSONParse(source); | 195 | | - } catch (error) { | 196 | | - throw new ERR_INVALID_PACKAGE_CONFIG( | 197 | | - path, | 198 | | - (base ? `"${specifier}" from ` : '') + fileURLToPath(base || specifier), | 199 | | - error.message | 200 | | - ); | 201 | | - } | 202 | | - | 203 | | - let { imports, main, name, type } = packageJSON; | 204 | | - const { exports } = packageJSON; | 205 | | - if (typeof imports !== 'object' || imports === null) imports = undefined; | 206 | | - if (typeof main !== 'string') main = undefined; | 207 | | - if (typeof name !== 'string') name = undefined; | 208 | | - // Ignore unknown types for forwards compatibility | 209 | | - if (type !== 'module' && type !== 'commonjs') type = 'none'; | 210 | | - | 211 | | - const packageConfig = { | 212 | | - pjsonPath: path, | 213 | | - exists: true, | 214 | | - main, | 215 | | - name, | 216 | | - type, | 217 | | - exports, | 218 | | - imports, | 219 | | - }; | 220 | | - packageJSONCache.set(path, packageConfig); | 221 | | - return packageConfig; | 222 | | -} | 223 | | - | 224 | | -/** | 225 | | - * @param {URL | string} resolved | 226 | | - * @returns {PackageConfig} | 227 | | - */ | 228 | | -function getPackageScopeConfig(resolved) { | 229 | | - let packageJSONUrl = new URL('./package.json', resolved); | 230 | | - while (true) { | 231 | | - const packageJSONPath = packageJSONUrl.pathname; | 232 | | - if (StringPrototypeEndsWith(packageJSONPath, 'node_modules/package.json')) | 233 | | - break; | 234 | | - const packageConfig = getPackageConfig(fileURLToPath(packageJSONUrl), | 235 | | - resolved); | 236 | | - if (packageConfig.exists) return packageConfig; | 237 | | - | 238 | | - const lastPackageJSONUrl = packageJSONUrl; | 239 | | - packageJSONUrl = new URL('../package.json', packageJSONUrl); | 240 | | - | 241 | | - // Terminates at root where ../package.json equals ../../package.json | 242 | | - // (can't just check "/package.json" for Windows support). | 243 | | - if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) break; | 244 | | - } | 245 | | - const packageJSONPath = fileURLToPath(packageJSONUrl); | 246 | | - const packageConfig = { | 247 | | - pjsonPath: packageJSONPath, | 248 | | - exists: false, | 249 | | - main: undefined, | 250 | | - name: undefined, | 251 | | - type: 'none', | 252 | | - exports: undefined, | 253 | | - imports: undefined, | 254 | | - }; | 255 | | - packageJSONCache.set(packageJSONPath, packageConfig); | 256 | | - return packageConfig; | 257 | | -} | 258 | | - | 259 | 160 | /** | 260 | 161 | * @param {string | URL} url | 261 | 162 | * @returns {boolean} | @@ -609,7 +510,7 @@ function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath, | 609 | 510 |
| 610 | 511 | /** | 611 | 512 | * | 612 | | - * @param {Exports} exports | | 513 | + * @param {import('internal/modules/esm/package_config.js').Exports} exports | 613 | 514 | * @param {URL} packageJSONUrl | 614 | 515 | * @param {string | URL | undefined} base | 615 | 516 | * @returns {boolean} | @@ -799,7 +700,7 @@ function packageImportsResolve(name, base, conditions) { | 799 | 700 |
| 800 | 701 | /** | 801 | 702 | * @param {URL} url | 802 | | - * @returns {PackageType} | | 703 | + * @returns {import('internal/modules/esm/package_config.js').PackageType} | 803 | 704 | */ | 804 | 705 | function getPackageType(url) { | 805 | 706 | const packageConfig = getPackageScopeConfig(url); | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-bootstrap-modules.js +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -85,6 +85,7 @@ const expectedModules = new Set([ | 85 | 85 | 'NativeModule internal/modules/esm/loader', | 86 | 86 | 'NativeModule internal/modules/esm/module_job', | 87 | 87 | 'NativeModule internal/modules/esm/module_map', | | 88 | + 'NativeModule internal/modules/esm/package_config', | 88 | 89 | 'NativeModule internal/modules/esm/resolve', | 89 | 90 | 'NativeModule internal/modules/esm/translators', | 90 | 91 | 'NativeModule internal/modules/package_json_reader', | |
|