1'use strict'; 2 3const { 4 ArrayIsArray, 5 ArrayPrototypeJoin, 6 ArrayPrototypeShift, 7 JSONStringify, 8 ObjectGetOwnPropertyNames, 9 ObjectPrototypeHasOwnProperty, 10 RegExp, 11 RegExpPrototypeExec, 12 RegExpPrototypeSymbolReplace, 13 SafeMap, 14 SafeSet, 15 String, 16 StringPrototypeEndsWith, 17 StringPrototypeIncludes, 18 StringPrototypeIndexOf, 19 StringPrototypeLastIndexOf, 20 StringPrototypeReplace, 21 StringPrototypeSlice, 22 StringPrototypeSplit, 23 StringPrototypeStartsWith, 24} = primordials; 25const internalFS = require('internal/fs/utils'); 26const { BuiltinModule } = require('internal/bootstrap/realm'); 27const { realpathSync } = require('fs'); 28const { getOptionValue } = require('internal/options'); 29const pendingDeprecation = getOptionValue('--pending-deprecation'); 30// Do not eagerly grab .manifest, it may be in TDZ 31const policy = getOptionValue('--experimental-policy') ? 32 require('internal/process/policy') : 33 null; 34const { sep, relative, resolve, toNamespacedPath } = require('path'); 35const preserveSymlinks = getOptionValue('--preserve-symlinks'); 36const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main'); 37const experimentalNetworkImports = 38 getOptionValue('--experimental-network-imports'); 39const inputTypeFlag = getOptionValue('--input-type'); 40const { URL, pathToFileURL, fileURLToPath, isURL, toPathIfFileURL } = require('internal/url'); 41const { getCWDURL } = require('internal/util'); 42const { canParse: URLCanParse } = internalBinding('url'); 43const { 44 ERR_INPUT_TYPE_NOT_ALLOWED, 45 ERR_INVALID_ARG_TYPE, 46 ERR_INVALID_MODULE_SPECIFIER, 47 ERR_INVALID_PACKAGE_CONFIG, 48 ERR_INVALID_PACKAGE_TARGET, 49 ERR_MANIFEST_DEPENDENCY_MISSING, 50 ERR_MODULE_NOT_FOUND, 51 ERR_PACKAGE_IMPORT_NOT_DEFINED, 52 ERR_PACKAGE_PATH_NOT_EXPORTED, 53 ERR_UNSUPPORTED_DIR_IMPORT, 54 ERR_NETWORK_IMPORT_DISALLOWED, 55} = require('internal/errors').codes; 56 57const { Module: CJSModule } = require('internal/modules/cjs/loader'); 58const { getPackageScopeConfig } = require('internal/modules/esm/package_config'); 59const { getConditionsSet } = require('internal/modules/esm/utils'); 60const packageJsonReader = require('internal/modules/package_json_reader'); 61const { internalModuleStat } = internalBinding('fs'); 62 63/** 64 * @typedef {import('internal/modules/esm/package_config.js').PackageConfig} PackageConfig 65 */ 66 67 68const emittedPackageWarnings = new SafeSet(); 69 70/** 71 * Emits a deprecation warning for the use of a deprecated trailing slash pattern mapping in the "exports" field 72 * module resolution of a package. 73 * @param {string} match - The deprecated trailing slash pattern mapping. 74 * @param {string} pjsonUrl - The URL of the package.json file. 75 * @param {string} base - The URL of the module that imported the package. 76 */ 77function emitTrailingSlashPatternDeprecation(match, pjsonUrl, base) { 78 const pjsonPath = fileURLToPath(pjsonUrl); 79 if (emittedPackageWarnings.has(pjsonPath + '|' + match)) { return; } 80 emittedPackageWarnings.add(pjsonPath + '|' + match); 81 process.emitWarning( 82 `Use of deprecated trailing slash pattern mapping "${match}" in the ` + 83 `"exports" field module resolution of the package at ${pjsonPath}${ 84 base ? ` imported from ${fileURLToPath(base)}` : 85 ''}. Mapping specifiers ending in "/" is no longer supported.`, 86 'DeprecationWarning', 87 'DEP0155', 88 ); 89} 90 91const doubleSlashRegEx = /[/\\][/\\]/; 92 93/** 94 * Emits a deprecation warning for invalid segment in module resolution. 95 * @param {string} target - The target module. 96 * @param {string} request - The requested module. 97 * @param {string} match - The matched module. 98 * @param {string} pjsonUrl - The package.json URL. 99 * @param {boolean} internal - Whether the module is in the "imports" or "exports" field. 100 * @param {string} base - The base URL. 101 * @param {boolean} isTarget - Whether the target is a module. 102 */ 103function emitInvalidSegmentDeprecation(target, request, match, pjsonUrl, internal, base, isTarget) { 104 if (!pendingDeprecation) { return; } 105 const pjsonPath = fileURLToPath(pjsonUrl); 106 const double = RegExpPrototypeExec(doubleSlashRegEx, isTarget ? target : request) !== null; 107 process.emitWarning( 108 `Use of deprecated ${double ? 'double slash' : 109 'leading or trailing slash matching'} resolving "${target}" for module ` + 110 `request "${request}" ${request !== match ? `matched to "${match}" ` : '' 111 }in the "${internal ? 'imports' : 'exports'}" field module resolution of the package at ${ 112 pjsonPath}${base ? ` imported from ${fileURLToPath(base)}` : ''}.`, 113 'DeprecationWarning', 114 'DEP0166', 115 ); 116} 117 118/** 119 * Emits a deprecation warning if the given URL is a module and 120 * the package.json file does not define a "main" or "exports" field. 121 * @param {URL} url - The URL of the module being resolved. 122 * @param {URL} packageJSONUrl - The URL of the package.json file for the module. 123 * @param {string | URL} [base] - The base URL for the module being resolved. 124 * @param {string} [main] - The "main" field from the package.json file. 125 */ 126function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) { 127 const format = defaultGetFormatWithoutErrors(url); 128 if (format !== 'module') { return; } 129 const path = fileURLToPath(url); 130 const pkgPath = fileURLToPath(new URL('.', packageJSONUrl)); 131 const basePath = fileURLToPath(base); 132 if (!main) { 133 process.emitWarning( 134 `No "main" or "exports" field defined in the package.json for ${pkgPath 135 } resolving the main entry point "${ 136 StringPrototypeSlice(path, pkgPath.length)}", imported from ${basePath 137 }.\nDefault "index" lookups for the main are deprecated for ES modules.`, 138 'DeprecationWarning', 139 'DEP0151', 140 ); 141 } else if (resolve(pkgPath, main) !== path) { 142 process.emitWarning( 143 `Package ${pkgPath} has a "main" field set to "${main}", ` + 144 `excluding the full filename and extension to the resolved file at "${ 145 StringPrototypeSlice(path, pkgPath.length)}", imported from ${ 146 basePath}.\n Automatic extension resolution of the "main" field is ` + 147 'deprecated for ES modules.', 148 'DeprecationWarning', 149 'DEP0151', 150 ); 151 } 152} 153 154const realpathCache = new SafeMap(); 155 156/** 157 * @param {string | URL} url 158 * @returns {boolean} 159 */ 160function fileExists(url) { 161 return internalModuleStat(toNamespacedPath(toPathIfFileURL(url))) === 0; 162} 163 164/** 165 * Legacy CommonJS main resolution: 166 * 1. let M = pkg_url + (json main field) 167 * 2. TRY(M, M.js, M.json, M.node) 168 * 3. TRY(M/index.js, M/index.json, M/index.node) 169 * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node) 170 * 5. NOT_FOUND 171 * @param {URL} packageJSONUrl 172 * @param {PackageConfig} packageConfig 173 * @param {string | URL | undefined} base 174 * @returns {URL} 175 */ 176function legacyMainResolve(packageJSONUrl, packageConfig, base) { 177 let guess; 178 if (packageConfig.main !== undefined) { 179 // Note: fs check redundances will be handled by Descriptor cache here. 180 if (fileExists(guess = new URL(`./${packageConfig.main}`, packageJSONUrl))) { 181 return guess; 182 } else if (fileExists(guess = new URL(`./${packageConfig.main}.js`, packageJSONUrl))) { 183 // Handled below. 184 } else if (fileExists(guess = new URL(`./${packageConfig.main}.json`, packageJSONUrl))) { 185 // Handled below. 186 } else if (fileExists(guess = new URL(`./${packageConfig.main}.node`, packageJSONUrl))) { 187 // Handled below. 188 } else if (fileExists(guess = new URL(`./${packageConfig.main}/index.js`, packageJSONUrl))) { 189 // Handled below. 190 } else if (fileExists(guess = new URL(`./${packageConfig.main}/index.json`, packageJSONUrl))) { 191 // Handled below. 192 } else if (fileExists(guess = new URL(`./${packageConfig.main}/index.node`, packageJSONUrl))) { 193 // Handled below. 194 } else { 195 guess = undefined; 196 } 197 if (guess) { 198 emitLegacyIndexDeprecation(guess, packageJSONUrl, base, 199 packageConfig.main); 200 return guess; 201 } 202 // Fallthrough. 203 } 204 if (fileExists(guess = new URL('./index.js', packageJSONUrl))) { 205 // Handled below. 206 } else if (fileExists(guess = new URL('./index.json', packageJSONUrl))) { 207 // Handled below. 208 } else if (fileExists(guess = new URL('./index.node', packageJSONUrl))) { 209 // Handled below. 210 } else { 211 guess = undefined; 212 } 213 if (guess) { 214 emitLegacyIndexDeprecation(guess, packageJSONUrl, base, packageConfig.main); 215 return guess; 216 } 217 // Not found. 218 throw new ERR_MODULE_NOT_FOUND( 219 fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base)); 220} 221 222/** 223 * @param {URL} search 224 * @returns {URL | undefined} 225 */ 226function resolveExtensionsWithTryExactName(search) { 227 if (fileExists(search)) { return search; } 228 return resolveExtensions(search); 229} 230 231const extensions = ['.js', '.json', '.node', '.mjs']; 232 233/** 234 * @param {URL} search 235 * @returns {URL | undefined} 236 */ 237function resolveExtensions(search) { 238 for (let i = 0; i < extensions.length; i++) { 239 const extension = extensions[i]; 240 const guess = new URL(`${search.pathname}${extension}`, search); 241 if (fileExists(guess)) { return guess; } 242 } 243 return undefined; 244} 245 246/** 247 * @param {URL} search 248 * @returns {URL | undefined} 249 */ 250function resolveDirectoryEntry(search) { 251 const dirPath = fileURLToPath(search); 252 const pkgJsonPath = resolve(dirPath, 'package.json'); 253 if (fileExists(pkgJsonPath)) { 254 const pkgJson = packageJsonReader.read(pkgJsonPath); 255 if (pkgJson.exists) { 256 const { main } = pkgJson; 257 if (main != null) { 258 const mainUrl = pathToFileURL(resolve(dirPath, main)); 259 return resolveExtensionsWithTryExactName(mainUrl); 260 } 261 } 262 } 263 return resolveExtensions(new URL('index', search)); 264} 265 266const encodedSepRegEx = /%2F|%5C/i; 267/** 268 * Finalizes the resolution of a module specifier by checking if the resolved pathname contains encoded "/" or "\\" 269 * characters, checking if the resolved pathname is a directory or file, and resolving any symlinks if necessary. 270 * @param {URL} resolved - The resolved URL object. 271 * @param {string | URL | undefined} base - The base URL object. 272 * @param {boolean} preserveSymlinks - Whether to preserve symlinks or not. 273 * @returns {URL} - The finalized URL object. 274 * @throws {ERR_INVALID_MODULE_SPECIFIER} - If the resolved pathname contains encoded "/" or "\\" characters. 275 * @throws {ERR_UNSUPPORTED_DIR_IMPORT} - If the resolved pathname is a directory. 276 * @throws {ERR_MODULE_NOT_FOUND} - If the resolved pathname is not a file. 277 */ 278function finalizeResolution(resolved, base, preserveSymlinks) { 279 if (RegExpPrototypeExec(encodedSepRegEx, resolved.pathname) !== null) { 280 throw new ERR_INVALID_MODULE_SPECIFIER( 281 resolved.pathname, 'must not include encoded "/" or "\\" characters', 282 fileURLToPath(base)); 283 } 284 285 let path; 286 try { 287 path = fileURLToPath(resolved); 288 } catch (err) { 289 const { setOwnProperty } = require('internal/util'); 290 setOwnProperty(err, 'input', `${resolved}`); 291 setOwnProperty(err, 'module', `${base}`); 292 throw err; 293 } 294 295 if (getOptionValue('--experimental-specifier-resolution') === 'node') { 296 let file = resolveExtensionsWithTryExactName(resolved); 297 298 // Directory 299 if (file === undefined) { 300 file = StringPrototypeEndsWith(path, '/') ? 301 (resolveDirectoryEntry(resolved) || resolved) : resolveDirectoryEntry(new URL(`${resolved}/`)); 302 303 if (file === resolved) { return file; } 304 305 if (file === undefined) { 306 throw new ERR_MODULE_NOT_FOUND( 307 resolved.pathname, fileURLToPath(base), 'module'); 308 } 309 } 310 // If `preserveSymlinks` is false, `resolved` is returned and `path` 311 // is used only to check that the resolved path exists. 312 resolved = file; 313 path = fileURLToPath(resolved); 314 } 315 316 const stats = internalModuleStat(toNamespacedPath(StringPrototypeEndsWith(path, '/') ? 317 StringPrototypeSlice(path, -1) : path)); 318 319 // Check for stats.isDirectory() 320 if (stats === 1) { 321 throw new ERR_UNSUPPORTED_DIR_IMPORT(path, fileURLToPath(base), String(resolved)); 322 } else if (stats !== 0) { 323 // Check for !stats.isFile() 324 if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) { 325 process.send({ 'watch:require': [path || resolved.pathname] }); 326 } 327 throw new ERR_MODULE_NOT_FOUND( 328 path || resolved.pathname, base && fileURLToPath(base), resolved); 329 } 330 331 if (!preserveSymlinks) { 332 const real = realpathSync(path, { 333 [internalFS.realpathCacheKey]: realpathCache, 334 }); 335 const { search, hash } = resolved; 336 resolved = 337 pathToFileURL(real + (StringPrototypeEndsWith(path, sep) ? '/' : '')); 338 resolved.search = search; 339 resolved.hash = hash; 340 } 341 342 return resolved; 343} 344 345/** 346 * Returns an error object indicating that the specified import is not defined. 347 * @param {string} specifier - The import specifier that is not defined. 348 * @param {URL} packageJSONUrl - The URL of the package.json file, or null if not available. 349 * @param {string | URL | undefined} base - The base URL to use for resolving relative URLs. 350 * @returns {ERR_PACKAGE_IMPORT_NOT_DEFINED} - The error object. 351 */ 352function importNotDefined(specifier, packageJSONUrl, base) { 353 return new ERR_PACKAGE_IMPORT_NOT_DEFINED( 354 specifier, packageJSONUrl && fileURLToPath(new URL('.', packageJSONUrl)), 355 fileURLToPath(base)); 356} 357 358/** 359 * Returns an error object indicating that the specified subpath was not exported by the package. 360 * @param {string} subpath - The subpath that was not exported. 361 * @param {URL} packageJSONUrl - The URL of the package.json file. 362 * @param {string | URL | undefined} [base] - The base URL to use for resolving the subpath. 363 * @returns {ERR_PACKAGE_PATH_NOT_EXPORTED} - The error object. 364 */ 365function exportsNotFound(subpath, packageJSONUrl, base) { 366 return new ERR_PACKAGE_PATH_NOT_EXPORTED( 367 fileURLToPath(new URL('.', packageJSONUrl)), subpath, 368 base && fileURLToPath(base)); 369} 370 371/** 372 * Throws an error indicating that the given request is not a valid subpath match for the specified pattern. 373 * @param {string} request - The request that failed to match the pattern. 374 * @param {string} match - The pattern that the request was compared against. 375 * @param {URL} packageJSONUrl - The URL of the package.json file being resolved. 376 * @param {boolean} internal - Whether the resolution is for an "imports" or "exports" field in package.json. 377 * @param {string | URL | undefined} base - The base URL for the resolution. 378 * @throws {ERR_INVALID_MODULE_SPECIFIER} When the request is not a valid match for the pattern. 379 */ 380function throwInvalidSubpath(request, match, packageJSONUrl, internal, base) { 381 const reason = `request is not a valid match in pattern "${match}" for the "${ 382 internal ? 'imports' : 'exports'}" resolution of ${ 383 fileURLToPath(packageJSONUrl)}`; 384 throw new ERR_INVALID_MODULE_SPECIFIER(request, reason, 385 base && fileURLToPath(base)); 386} 387 388/** 389 * Creates an error object for an invalid package target. 390 * @param {string} subpath - The subpath. 391 * @param {import('internal/modules/esm/package_config.js').PackageTarget} target - The target. 392 * @param {URL} packageJSONUrl - The URL of the package.json file. 393 * @param {boolean} internal - Whether the package is internal. 394 * @param {string | URL | undefined} base - The base URL. 395 * @returns {ERR_INVALID_PACKAGE_TARGET} - The error object. 396 */ 397function invalidPackageTarget( 398 subpath, target, packageJSONUrl, internal, base) { 399 if (typeof target === 'object' && target !== null) { 400 target = JSONStringify(target, null, ''); 401 } else { 402 target = `${target}`; 403 } 404 return new ERR_INVALID_PACKAGE_TARGET( 405 fileURLToPath(new URL('.', packageJSONUrl)), subpath, target, 406 internal, base && fileURLToPath(base)); 407} 408 409const invalidSegmentRegEx = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))?(\\|\/|$)/i; 410const deprecatedInvalidSegmentRegEx = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i; 411const invalidPackageNameRegEx = /^\.|%|\\/; 412const patternRegEx = /\*/g; 413 414/** 415 * Resolves the package target string to a URL object. 416 * @param {string} target - The target string to resolve. 417 * @param {string} subpath - The subpath to append to the resolved URL. 418 * @param {RegExpMatchArray} match - The matched string array from the import statement. 419 * @param {string} packageJSONUrl - The URL of the package.json file. 420 * @param {string} base - The base URL to resolve the target against. 421 * @param {RegExp} pattern - The pattern to replace in the target string. 422 * @param {boolean} internal - Whether the target is internal to the package. 423 * @param {boolean} isPathMap - Whether the target is a path map. 424 * @param {string[]} conditions - The import conditions. 425 * @returns {URL} - The resolved URL object. 426 * @throws {ERR_INVALID_PACKAGE_TARGET} - If the target is invalid. 427 * @throws {ERR_INVALID_SUBPATH} - If the subpath is invalid. 428 */ 429function resolvePackageTargetString( 430 target, 431 subpath, 432 match, 433 packageJSONUrl, 434 base, 435 pattern, 436 internal, 437 isPathMap, 438 conditions, 439) { 440 441 if (subpath !== '' && !pattern && target[target.length - 1] !== '/') { 442 throw invalidPackageTarget(match, target, packageJSONUrl, internal, base); 443 } 444 445 if (!StringPrototypeStartsWith(target, './')) { 446 if (internal && !StringPrototypeStartsWith(target, '../') && 447 !StringPrototypeStartsWith(target, '/')) { 448 // No need to convert target to string, since it's already presumed to be 449 if (!URLCanParse(target)) { 450 const exportTarget = pattern ? 451 RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) : 452 target + subpath; 453 return packageResolve( 454 exportTarget, packageJSONUrl, conditions); 455 } 456 } 457 throw invalidPackageTarget(match, target, packageJSONUrl, internal, base); 458 } 459 460 if (RegExpPrototypeExec(invalidSegmentRegEx, StringPrototypeSlice(target, 2)) !== null) { 461 if (RegExpPrototypeExec(deprecatedInvalidSegmentRegEx, StringPrototypeSlice(target, 2)) === null) { 462 if (!isPathMap) { 463 const request = pattern ? 464 StringPrototypeReplace(match, '*', () => subpath) : 465 match + subpath; 466 const resolvedTarget = pattern ? 467 RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) : 468 target; 469 emitInvalidSegmentDeprecation(resolvedTarget, request, match, packageJSONUrl, internal, base, true); 470 } 471 } else { 472 throw invalidPackageTarget(match, target, packageJSONUrl, internal, base); 473 } 474 } 475 476 const resolved = new URL(target, packageJSONUrl); 477 const resolvedPath = resolved.pathname; 478 const packagePath = new URL('.', packageJSONUrl).pathname; 479 480 if (!StringPrototypeStartsWith(resolvedPath, packagePath)) { 481 throw invalidPackageTarget(match, target, packageJSONUrl, internal, base); 482 } 483 484 if (subpath === '') { return resolved; } 485 486 if (RegExpPrototypeExec(invalidSegmentRegEx, subpath) !== null) { 487 const request = pattern ? StringPrototypeReplace(match, '*', () => subpath) : match + subpath; 488 if (RegExpPrototypeExec(deprecatedInvalidSegmentRegEx, subpath) === null) { 489 if (!isPathMap) { 490 const resolvedTarget = pattern ? 491 RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) : 492 target; 493 emitInvalidSegmentDeprecation(resolvedTarget, request, match, packageJSONUrl, internal, base, false); 494 } 495 } else { 496 throwInvalidSubpath(request, match, packageJSONUrl, internal, base); 497 } 498 } 499 500 if (pattern) { 501 return new URL( 502 RegExpPrototypeSymbolReplace(patternRegEx, resolved.href, () => subpath), 503 ); 504 } 505 506 return new URL(subpath, resolved); 507} 508 509/** 510 * Checks if the given key is a valid array index. 511 * @param {string} key - The key to check. 512 * @returns {boolean} - Returns `true` if the key is a valid array index, else `false`. 513 */ 514function isArrayIndex(key) { 515 const keyNum = +key; 516 if (`${keyNum}` !== key) { return false; } 517 return keyNum >= 0 && keyNum < 0xFFFF_FFFF; 518} 519 520/** 521 * Resolves the target of a package based on the provided parameters. 522 * @param {string} packageJSONUrl - The URL of the package.json file. 523 * @param {import('internal/modules/esm/package_config.js').PackageTarget} target - The target to resolve. 524 * @param {string} subpath - The subpath to resolve. 525 * @param {string} packageSubpath - The subpath of the package to resolve. 526 * @param {string} base - The base path to resolve. 527 * @param {RegExp} pattern - The pattern to match. 528 * @param {boolean} internal - Whether the package is internal. 529 * @param {boolean} isPathMap - Whether the package is a path map. 530 * @param {Set<string>} conditions - The conditions to match. 531 * @returns {URL | null | undefined} - The resolved target, or null if not found, or undefined if not resolvable. 532 */ 533function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath, 534 base, pattern, internal, isPathMap, conditions) { 535 if (typeof target === 'string') { 536 return resolvePackageTargetString( 537 target, subpath, packageSubpath, packageJSONUrl, base, pattern, internal, 538 isPathMap, conditions); 539 } else if (ArrayIsArray(target)) { 540 if (target.length === 0) { 541 return null; 542 } 543 544 let lastException; 545 for (let i = 0; i < target.length; i++) { 546 const targetItem = target[i]; 547 let resolveResult; 548 try { 549 resolveResult = resolvePackageTarget( 550 packageJSONUrl, targetItem, subpath, packageSubpath, base, pattern, 551 internal, isPathMap, conditions); 552 } catch (e) { 553 lastException = e; 554 if (e.code === 'ERR_INVALID_PACKAGE_TARGET') { 555 continue; 556 } 557 throw e; 558 } 559 if (resolveResult === undefined) { 560 continue; 561 } 562 if (resolveResult === null) { 563 lastException = null; 564 continue; 565 } 566 return resolveResult; 567 } 568 if (lastException === undefined || lastException === null) { 569 return lastException; 570 } 571 throw lastException; 572 } else if (typeof target === 'object' && target !== null) { 573 const keys = ObjectGetOwnPropertyNames(target); 574 for (let i = 0; i < keys.length; i++) { 575 const key = keys[i]; 576 if (isArrayIndex(key)) { 577 throw new ERR_INVALID_PACKAGE_CONFIG( 578 fileURLToPath(packageJSONUrl), base, 579 '"exports" cannot contain numeric property keys.'); 580 } 581 } 582 for (let i = 0; i < keys.length; i++) { 583 const key = keys[i]; 584 if (key === 'default' || conditions.has(key)) { 585 const conditionalTarget = target[key]; 586 const resolveResult = resolvePackageTarget( 587 packageJSONUrl, conditionalTarget, subpath, packageSubpath, base, 588 pattern, internal, isPathMap, conditions); 589 if (resolveResult === undefined) { continue; } 590 return resolveResult; 591 } 592 } 593 return undefined; 594 } else if (target === null) { 595 return null; 596 } 597 throw invalidPackageTarget(packageSubpath, target, packageJSONUrl, internal, 598 base); 599} 600 601/** 602 * Is the given exports object using the shorthand syntax? 603 * @param {import('internal/modules/esm/package_config.js').PackageConfig['exports']} exports 604 * @param {URL} packageJSONUrl The URL of the package.json file. 605 * @param {string | URL | undefined} base The base URL. 606 */ 607function isConditionalExportsMainSugar(exports, packageJSONUrl, base) { 608 if (typeof exports === 'string' || ArrayIsArray(exports)) { return true; } 609 if (typeof exports !== 'object' || exports === null) { return false; } 610 611 const keys = ObjectGetOwnPropertyNames(exports); 612 let isConditionalSugar = false; 613 let i = 0; 614 for (let j = 0; j < keys.length; j++) { 615 const key = keys[j]; 616 const curIsConditionalSugar = key === '' || key[0] !== '.'; 617 if (i++ === 0) { 618 isConditionalSugar = curIsConditionalSugar; 619 } else if (isConditionalSugar !== curIsConditionalSugar) { 620 throw new ERR_INVALID_PACKAGE_CONFIG( 621 fileURLToPath(packageJSONUrl), base, 622 '"exports" cannot contain some keys starting with \'.\' and some not.' + 623 ' The exports object must either be an object of package subpath keys' + 624 ' or an object of main entry condition name keys only.'); 625 } 626 } 627 return isConditionalSugar; 628} 629 630/** 631 * Resolves the exports of a package. 632 * @param {URL} packageJSONUrl - The URL of the package.json file. 633 * @param {string} packageSubpath - The subpath of the package to resolve. 634 * @param {import('internal/modules/esm/package_config.js').PackageConfig} packageConfig - The package metadata. 635 * @param {string | URL | undefined} base - The base path to resolve from. 636 * @param {Set<string>} conditions - An array of conditions to match. 637 * @returns {URL} - The resolved package target. 638 */ 639function packageExportsResolve( 640 packageJSONUrl, packageSubpath, packageConfig, base, conditions) { 641 let exports = packageConfig.exports; 642 if (isConditionalExportsMainSugar(exports, packageJSONUrl, base)) { 643 exports = { '.': exports }; 644 } 645 646 if (ObjectPrototypeHasOwnProperty(exports, packageSubpath) && 647 !StringPrototypeIncludes(packageSubpath, '*') && 648 !StringPrototypeEndsWith(packageSubpath, '/')) { 649 const target = exports[packageSubpath]; 650 const resolveResult = resolvePackageTarget( 651 packageJSONUrl, target, '', packageSubpath, base, false, false, false, 652 conditions, 653 ); 654 655 if (resolveResult == null) { 656 throw exportsNotFound(packageSubpath, packageJSONUrl, base); 657 } 658 659 return resolveResult; 660 } 661 662 let bestMatch = ''; 663 let bestMatchSubpath; 664 const keys = ObjectGetOwnPropertyNames(exports); 665 for (let i = 0; i < keys.length; i++) { 666 const key = keys[i]; 667 const patternIndex = StringPrototypeIndexOf(key, '*'); 668 if (patternIndex !== -1 && 669 StringPrototypeStartsWith(packageSubpath, 670 StringPrototypeSlice(key, 0, patternIndex))) { 671 // When this reaches EOL, this can throw at the top of the whole function: 672 // 673 // if (StringPrototypeEndsWith(packageSubpath, '/')) 674 // throwInvalidSubpath(packageSubpath) 675 // 676 // To match "imports" and the spec. 677 if (StringPrototypeEndsWith(packageSubpath, '/')) { 678 emitTrailingSlashPatternDeprecation(packageSubpath, packageJSONUrl, 679 base); 680 } 681 const patternTrailer = StringPrototypeSlice(key, patternIndex + 1); 682 if (packageSubpath.length >= key.length && 683 StringPrototypeEndsWith(packageSubpath, patternTrailer) && 684 patternKeyCompare(bestMatch, key) === 1 && 685 StringPrototypeLastIndexOf(key, '*') === patternIndex) { 686 bestMatch = key; 687 bestMatchSubpath = StringPrototypeSlice( 688 packageSubpath, patternIndex, 689 packageSubpath.length - patternTrailer.length); 690 } 691 } 692 } 693 694 if (bestMatch) { 695 const target = exports[bestMatch]; 696 const resolveResult = resolvePackageTarget( 697 packageJSONUrl, 698 target, 699 bestMatchSubpath, 700 bestMatch, 701 base, 702 true, 703 false, 704 StringPrototypeEndsWith(packageSubpath, '/'), 705 conditions); 706 707 if (resolveResult == null) { 708 throw exportsNotFound(packageSubpath, packageJSONUrl, base); 709 } 710 return resolveResult; 711 } 712 713 throw exportsNotFound(packageSubpath, packageJSONUrl, base); 714} 715 716/** 717 * Compares two strings that may contain a wildcard character ('*') and returns a value indicating their order. 718 * @param {string} a - The first string to compare. 719 * @param {string} b - The second string to compare. 720 * @returns {number} - A negative number if `a` should come before `b`, a positive number if `a` should come after `b`, 721 * or 0 if they are equal. 722 */ 723function patternKeyCompare(a, b) { 724 const aPatternIndex = StringPrototypeIndexOf(a, '*'); 725 const bPatternIndex = StringPrototypeIndexOf(b, '*'); 726 const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1; 727 const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1; 728 if (baseLenA > baseLenB) { return -1; } 729 if (baseLenB > baseLenA) { return 1; } 730 if (aPatternIndex === -1) { return 1; } 731 if (bPatternIndex === -1) { return -1; } 732 if (a.length > b.length) { return -1; } 733 if (b.length > a.length) { return 1; } 734 return 0; 735} 736 737/** 738 * Resolves the given import name for a package. 739 * @param {string} name - The name of the import to resolve. 740 * @param {string | URL | undefined} base - The base URL to resolve the import from. 741 * @param {Set<string>} conditions - An object containing the import conditions. 742 * @throws {ERR_INVALID_MODULE_SPECIFIER} If the import name is not valid. 743 * @throws {ERR_PACKAGE_IMPORT_NOT_DEFINED} If the import name cannot be resolved. 744 * @returns {URL} The resolved import URL. 745 */ 746function packageImportsResolve(name, base, conditions) { 747 if (name === '#' || StringPrototypeStartsWith(name, '#/') || 748 StringPrototypeEndsWith(name, '/')) { 749 const reason = 'is not a valid internal imports specifier name'; 750 throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath(base)); 751 } 752 let packageJSONUrl; 753 const packageConfig = getPackageScopeConfig(base); 754 if (packageConfig.exists) { 755 packageJSONUrl = pathToFileURL(packageConfig.pjsonPath); 756 const imports = packageConfig.imports; 757 if (imports) { 758 if (ObjectPrototypeHasOwnProperty(imports, name) && 759 !StringPrototypeIncludes(name, '*')) { 760 const resolveResult = resolvePackageTarget( 761 packageJSONUrl, imports[name], '', name, base, false, true, false, 762 conditions, 763 ); 764 if (resolveResult != null) { 765 return resolveResult; 766 } 767 } else { 768 let bestMatch = ''; 769 let bestMatchSubpath; 770 const keys = ObjectGetOwnPropertyNames(imports); 771 for (let i = 0; i < keys.length; i++) { 772 const key = keys[i]; 773 const patternIndex = StringPrototypeIndexOf(key, '*'); 774 if (patternIndex !== -1 && 775 StringPrototypeStartsWith(name, 776 StringPrototypeSlice(key, 0, 777 patternIndex))) { 778 const patternTrailer = StringPrototypeSlice(key, patternIndex + 1); 779 if (name.length >= key.length && 780 StringPrototypeEndsWith(name, patternTrailer) && 781 patternKeyCompare(bestMatch, key) === 1 && 782 StringPrototypeLastIndexOf(key, '*') === patternIndex) { 783 bestMatch = key; 784 bestMatchSubpath = StringPrototypeSlice( 785 name, patternIndex, name.length - patternTrailer.length); 786 } 787 } 788 } 789 790 if (bestMatch) { 791 const target = imports[bestMatch]; 792 const resolveResult = resolvePackageTarget(packageJSONUrl, target, 793 bestMatchSubpath, 794 bestMatch, base, true, 795 true, false, conditions); 796 if (resolveResult != null) { 797 return resolveResult; 798 } 799 } 800 } 801 } 802 } 803 throw importNotDefined(name, packageJSONUrl, base); 804} 805 806/** 807 * Returns the package type for a given URL. 808 * @param {URL} url - The URL to get the package type for. 809 */ 810function getPackageType(url) { 811 const packageConfig = getPackageScopeConfig(url); 812 return packageConfig.type; 813} 814 815/** 816 * Parse a package name from a specifier. 817 * @param {string} specifier - The import specifier. 818 * @param {string | URL | undefined} base - The parent URL. 819 */ 820function parsePackageName(specifier, base) { 821 let separatorIndex = StringPrototypeIndexOf(specifier, '/'); 822 let validPackageName = true; 823 let isScoped = false; 824 if (specifier[0] === '@') { 825 isScoped = true; 826 if (separatorIndex === -1 || specifier.length === 0) { 827 validPackageName = false; 828 } else { 829 separatorIndex = StringPrototypeIndexOf( 830 specifier, '/', separatorIndex + 1); 831 } 832 } 833 834 const packageName = separatorIndex === -1 ? 835 specifier : StringPrototypeSlice(specifier, 0, separatorIndex); 836 837 // Package name cannot have leading . and cannot have percent-encoding or 838 // \\ separators. 839 if (RegExpPrototypeExec(invalidPackageNameRegEx, packageName) !== null) { 840 validPackageName = false; 841 } 842 843 if (!validPackageName) { 844 throw new ERR_INVALID_MODULE_SPECIFIER( 845 specifier, 'is not a valid package name', fileURLToPath(base)); 846 } 847 848 const packageSubpath = '.' + (separatorIndex === -1 ? '' : 849 StringPrototypeSlice(specifier, separatorIndex)); 850 851 return { packageName, packageSubpath, isScoped }; 852} 853 854/** 855 * Resolves a package specifier to a URL. 856 * @param {string} specifier - The package specifier to resolve. 857 * @param {string | URL | undefined} base - The base URL to use for resolution. 858 * @param {Set<string>} conditions - An object containing the conditions for resolution. 859 * @returns {URL} - The resolved URL. 860 */ 861function packageResolve(specifier, base, conditions) { 862 if (BuiltinModule.canBeRequiredWithoutScheme(specifier)) { 863 return new URL('node:' + specifier); 864 } 865 866 const { packageName, packageSubpath, isScoped } = 867 parsePackageName(specifier, base); 868 869 // ResolveSelf 870 const packageConfig = getPackageScopeConfig(base); 871 if (packageConfig.exists) { 872 const packageJSONUrl = pathToFileURL(packageConfig.pjsonPath); 873 if (packageConfig.exports != null && packageConfig.name === packageName) { 874 return packageExportsResolve( 875 packageJSONUrl, packageSubpath, packageConfig, base, conditions); 876 } 877 } 878 879 let packageJSONUrl = 880 new URL('./node_modules/' + packageName + '/package.json', base); 881 let packageJSONPath = fileURLToPath(packageJSONUrl); 882 let lastPath; 883 do { 884 const stat = internalModuleStat(toNamespacedPath(StringPrototypeSlice(packageJSONPath, 0, 885 packageJSONPath.length - 13))); 886 // Check for !stat.isDirectory() 887 if (stat !== 1) { 888 lastPath = packageJSONPath; 889 packageJSONUrl = new URL((isScoped ? 890 '../../../../node_modules/' : '../../../node_modules/') + 891 packageName + '/package.json', packageJSONUrl); 892 packageJSONPath = fileURLToPath(packageJSONUrl); 893 continue; 894 } 895 896 // Package match. 897 const packageConfig = packageJsonReader.read(packageJSONPath, { __proto__: null, specifier, base, isESM: true }); 898 if (packageConfig.exports != null) { 899 return packageExportsResolve( 900 packageJSONUrl, packageSubpath, packageConfig, base, conditions); 901 } 902 if (packageSubpath === '.') { 903 return legacyMainResolve( 904 packageJSONUrl, 905 packageConfig, 906 base, 907 ); 908 } 909 910 return new URL(packageSubpath, packageJSONUrl); 911 // Cross-platform root check. 912 } while (packageJSONPath.length !== lastPath.length); 913 914 // eslint can't handle the above code. 915 // eslint-disable-next-line no-unreachable 916 throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null); 917} 918 919/** 920 * Checks if a specifier is a bare specifier. 921 * @param {string} specifier - The specifier to check. 922 */ 923function isBareSpecifier(specifier) { 924 return specifier[0] && specifier[0] !== '/' && specifier[0] !== '.'; 925} 926 927/** 928 * Determines whether a specifier is a relative path. 929 * @param {string} specifier - The specifier to check. 930 */ 931function isRelativeSpecifier(specifier) { 932 if (specifier[0] === '.') { 933 if (specifier.length === 1 || specifier[1] === '/') { return true; } 934 if (specifier[1] === '.') { 935 if (specifier.length === 2 || specifier[2] === '/') { return true; } 936 } 937 } 938 return false; 939} 940 941/** 942 * Determines whether a specifier should be treated as a relative or absolute path. 943 * @param {string} specifier - The specifier to check. 944 */ 945function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) { 946 if (specifier === '') { return false; } 947 if (specifier[0] === '/') { return true; } 948 return isRelativeSpecifier(specifier); 949} 950 951/** 952 * Resolves a module specifier to a URL. 953 * @param {string} specifier - The module specifier to resolve. 954 * @param {string | URL | undefined} base - The base URL to resolve against. 955 * @param {Set<string>} conditions - An object containing environment conditions. 956 * @param {boolean} preserveSymlinks - Whether to preserve symlinks in the resolved URL. 957 */ 958function moduleResolve(specifier, base, conditions, preserveSymlinks) { 959 const isRemote = base.protocol === 'http:' || 960 base.protocol === 'https:'; 961 // Order swapped from spec for minor perf gain. 962 // Ok since relative URLs cannot parse as URLs. 963 let resolved; 964 if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) { 965 resolved = new URL(specifier, base); 966 } else if (!isRemote && specifier[0] === '#') { 967 resolved = packageImportsResolve(specifier, base, conditions); 968 } else { 969 try { 970 resolved = new URL(specifier); 971 } catch { 972 if (!isRemote) { 973 resolved = packageResolve(specifier, base, conditions); 974 } 975 } 976 } 977 if (resolved.protocol !== 'file:') { 978 return resolved; 979 } 980 return finalizeResolution(resolved, base, preserveSymlinks); 981} 982 983/** 984 * Try to resolve an import as a CommonJS module. 985 * @param {string} specifier - The specifier to resolve. 986 * @param {string} parentURL - The base URL. 987 */ 988function resolveAsCommonJS(specifier, parentURL) { 989 try { 990 const parent = fileURLToPath(parentURL); 991 const tmpModule = new CJSModule(parent, null); 992 tmpModule.paths = CJSModule._nodeModulePaths(parent); 993 994 let found = CJSModule._resolveFilename(specifier, tmpModule, false); 995 996 // If it is a relative specifier return the relative path 997 // to the parent 998 if (isRelativeSpecifier(specifier)) { 999 found = relative(parent, found); 1000 // Add '.separator if the path does not start with '..separator' 1001 // This should be a safe assumption because when loading 1002 // esm modules there should be always a file specified so 1003 // there should not be a specifier like '..' or '.' 1004 if (!StringPrototypeStartsWith(found, `..${sep}`)) { 1005 found = `.${sep}${found}`; 1006 } 1007 } else if (isBareSpecifier(specifier)) { 1008 // If it is a bare specifier return the relative path within the 1009 // module 1010 const pkg = StringPrototypeSplit(specifier, '/')[0]; 1011 const index = StringPrototypeIndexOf(found, pkg); 1012 if (index !== -1) { 1013 found = StringPrototypeSlice(found, index); 1014 } 1015 } 1016 // Normalize the path separator to give a valid suggestion 1017 // on Windows 1018 if (process.platform === 'win32') { 1019 found = RegExpPrototypeSymbolReplace(new RegExp(`\\${sep}`, 'g'), 1020 found, '/'); 1021 } 1022 return found; 1023 } catch { 1024 return false; 1025 } 1026} 1027 1028/** 1029 * Throw an error if an import is not allowed. 1030 * TODO(@JakobJingleheimer): de-dupe `specifier` & `parsed` 1031 * @param {string} specifier - The import specifier. 1032 * @param {URL} parsed - The parsed URL of the import specifier. 1033 * @param {URL} parsedParentURL - The parsed URL of the parent module. 1034 * @throws {ERR_NETWORK_IMPORT_DISALLOWED} - If the import is disallowed. 1035 */ 1036function checkIfDisallowedImport(specifier, parsed, parsedParentURL) { 1037 if (parsedParentURL) { 1038 // Avoid accessing the `protocol` property due to the lazy getters. 1039 const parentProtocol = parsedParentURL.protocol; 1040 if ( 1041 parentProtocol === 'http:' || 1042 parentProtocol === 'https:' 1043 ) { 1044 if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) { 1045 // Avoid accessing the `protocol` property due to the lazy getters. 1046 const parsedProtocol = parsed?.protocol; 1047 // data: and blob: disallowed due to allowing file: access via 1048 // indirection 1049 if (parsedProtocol && 1050 parsedProtocol !== 'https:' && 1051 parsedProtocol !== 'http:' 1052 ) { 1053 throw new ERR_NETWORK_IMPORT_DISALLOWED( 1054 specifier, 1055 parsedParentURL, 1056 'remote imports cannot import from a local location.', 1057 ); 1058 } 1059 1060 return { url: parsed.href }; 1061 } 1062 if (BuiltinModule.canBeRequiredWithoutScheme(specifier)) { 1063 throw new ERR_NETWORK_IMPORT_DISALLOWED( 1064 specifier, 1065 parsedParentURL, 1066 'remote imports cannot import from a local location.', 1067 ); 1068 } 1069 1070 throw new ERR_NETWORK_IMPORT_DISALLOWED( 1071 specifier, 1072 parsedParentURL, 1073 'only relative and absolute specifiers are supported.', 1074 ); 1075 } 1076 } 1077} 1078 1079/** 1080 * Validate user-input in `context` supplied by a custom loader. 1081 * @param {string | URL | undefined} parentURL - The parent URL. 1082 */ 1083function throwIfInvalidParentURL(parentURL) { 1084 if (parentURL === undefined) { 1085 return; // Main entry point, so no parent 1086 } 1087 if (typeof parentURL !== 'string' && !isURL(parentURL)) { 1088 throw new ERR_INVALID_ARG_TYPE('parentURL', ['string', 'URL'], parentURL); 1089 } 1090} 1091 1092/** 1093 * Resolves the given specifier using the provided context, which includes the parent URL and conditions. 1094 * Throws an error if the parent URL is invalid or if the resolution is disallowed by the policy manifest. 1095 * Otherwise, attempts to resolve the specifier and returns the resulting URL and format. 1096 * @param {string} specifier - The specifier to resolve. 1097 * @param {object} [context={}] - The context object containing the parent URL and conditions. 1098 * @param {string} [context.parentURL] - The URL of the parent module. 1099 * @param {string[]} [context.conditions] - The conditions for resolving the specifier. 1100 */ 1101function defaultResolve(specifier, context = {}) { 1102 let { parentURL, conditions } = context; 1103 throwIfInvalidParentURL(parentURL); 1104 if (parentURL && policy?.manifest) { 1105 const redirects = policy.manifest.getDependencyMapper(parentURL); 1106 if (redirects) { 1107 const { resolve, reaction } = redirects; 1108 const destination = resolve(specifier, new SafeSet(conditions)); 1109 let missing = true; 1110 if (destination === true) { 1111 missing = false; 1112 } else if (destination) { 1113 const href = destination.href; 1114 return { url: href }; 1115 } 1116 if (missing) { 1117 // Prevent network requests from firing if resolution would be banned. 1118 // Network requests can extract data by doing things like putting 1119 // secrets in query params 1120 reaction(new ERR_MANIFEST_DEPENDENCY_MISSING( 1121 parentURL, 1122 specifier, 1123 ArrayPrototypeJoin([...conditions], ', ')), 1124 ); 1125 } 1126 } 1127 } 1128 1129 let parsedParentURL; 1130 if (parentURL) { 1131 try { 1132 parsedParentURL = new URL(parentURL); 1133 } catch { 1134 // Ignore exception 1135 } 1136 } 1137 1138 let parsed; 1139 try { 1140 if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) { 1141 parsed = new URL(specifier, parsedParentURL); 1142 } else { 1143 parsed = new URL(specifier); 1144 } 1145 1146 // Avoid accessing the `protocol` property due to the lazy getters. 1147 const protocol = parsed.protocol; 1148 if (protocol === 'data:' || 1149 (experimentalNetworkImports && 1150 ( 1151 protocol === 'https:' || 1152 protocol === 'http:' 1153 ) 1154 ) 1155 ) { 1156 return { __proto__: null, url: parsed.href }; 1157 } 1158 } catch { 1159 // Ignore exception 1160 } 1161 1162 // There are multiple deep branches that can either throw or return; instead 1163 // of duplicating that deeply nested logic for the possible returns, DRY and 1164 // check for a return. This seems the least gnarly. 1165 const maybeReturn = checkIfDisallowedImport( 1166 specifier, 1167 parsed, 1168 parsedParentURL, 1169 ); 1170 1171 if (maybeReturn) { return maybeReturn; } 1172 1173 // This must come after checkIfDisallowedImport 1174 if (parsed && parsed.protocol === 'node:') { return { __proto__: null, url: specifier }; } 1175 1176 1177 const isMain = parentURL === undefined; 1178 if (isMain) { 1179 parentURL = getCWDURL().href; 1180 1181 // This is the initial entry point to the program, and --input-type has 1182 // been passed as an option; but --input-type can only be used with 1183 // --eval, --print or STDIN string input. It is not allowed with file 1184 // input, to avoid user confusion over how expansive the effect of the 1185 // flag should be (i.e. entry point only, package scope surrounding the 1186 // entry point, etc.). 1187 if (inputTypeFlag) { throw new ERR_INPUT_TYPE_NOT_ALLOWED(); } 1188 } 1189 1190 conditions = getConditionsSet(conditions); 1191 let url; 1192 try { 1193 url = moduleResolve( 1194 specifier, 1195 parentURL, 1196 conditions, 1197 isMain ? preserveSymlinksMain : preserveSymlinks, 1198 ); 1199 } catch (error) { 1200 // Try to give the user a hint of what would have been the 1201 // resolved CommonJS module 1202 if (error.code === 'ERR_MODULE_NOT_FOUND' || 1203 error.code === 'ERR_UNSUPPORTED_DIR_IMPORT') { 1204 if (StringPrototypeStartsWith(specifier, 'file://')) { 1205 specifier = fileURLToPath(specifier); 1206 } 1207 decorateErrorWithCommonJSHints(error, specifier, parentURL); 1208 } 1209 throw error; 1210 } 1211 1212 return { 1213 // Do NOT cast `url` to a string: that will work even when there are real 1214 // problems, silencing them 1215 url: url.href, 1216 format: defaultGetFormatWithoutErrors(url, context), 1217 }; 1218} 1219 1220/** 1221 * Decorates the given error with a hint for CommonJS modules. 1222 * @param {Error} error - The error to decorate. 1223 * @param {string} specifier - The specifier that was attempted to be imported. 1224 * @param {string} parentURL - The URL of the parent module. 1225 */ 1226function decorateErrorWithCommonJSHints(error, specifier, parentURL) { 1227 const found = resolveAsCommonJS(specifier, parentURL); 1228 if (found) { 1229 // Modify the stack and message string to include the hint 1230 const lines = StringPrototypeSplit(error.stack, '\n'); 1231 const hint = `Did you mean to import ${found}?`; 1232 error.stack = 1233 ArrayPrototypeShift(lines) + '\n' + 1234 hint + '\n' + 1235 ArrayPrototypeJoin(lines, '\n'); 1236 error.message += `\n${hint}`; 1237 } 1238} 1239 1240module.exports = { 1241 decorateErrorWithCommonJSHints, 1242 defaultResolve, 1243 encodedSepRegEx, 1244 getPackageScopeConfig, 1245 getPackageType, 1246 packageExportsResolve, 1247 packageImportsResolve, 1248 throwIfInvalidParentURL, 1249}; 1250 1251// cycle 1252const { 1253 defaultGetFormatWithoutErrors, 1254} = require('internal/modules/esm/get_format'); 1255 1256if (policy) { 1257 const $defaultResolve = defaultResolve; 1258 module.exports.defaultResolve = function defaultResolve( 1259 specifier, 1260 context, 1261 ) { 1262 const ret = $defaultResolve(specifier, context); 1263 // This is a preflight check to avoid data exfiltration by query params etc. 1264 policy.manifest.mightAllow(ret.url, () => 1265 new ERR_MANIFEST_DEPENDENCY_MISSING( 1266 context.parentURL, 1267 specifier, 1268 context.conditions, 1269 ), 1270 ); 1271 return ret; 1272 }; 1273} 1274