1'use strict'; 2 3const { 4 ArrayIsArray, 5 ArrayPrototypeJoin, 6 ArrayPrototypeShift, 7 JSONParse, 8 JSONStringify, 9 ObjectFreeze, 10 ObjectGetOwnPropertyNames, 11 ObjectPrototypeHasOwnProperty, 12 RegExp, 13 RegExpPrototypeTest, 14 SafeMap, 15 SafeSet, 16 String, 17 StringPrototypeEndsWith, 18 StringPrototypeIncludes, 19 StringPrototypeIndexOf, 20 StringPrototypeLastIndexOf, 21 StringPrototypeReplace, 22 StringPrototypeSlice, 23 StringPrototypeSplit, 24 StringPrototypeStartsWith, 25} = primordials; 26const internalFS = require('internal/fs/utils'); 27const { NativeModule } = require('internal/bootstrap/loaders'); 28const { 29 realpathSync, 30 statSync, 31 Stats, 32} = require('fs'); 33const { getOptionValue } = require('internal/options'); 34// Do not eagerly grab .manifest, it may be in TDZ 35const policy = getOptionValue('--experimental-policy') ? 36 require('internal/process/policy') : 37 null; 38const { sep, relative, resolve } = require('path'); 39const preserveSymlinks = getOptionValue('--preserve-symlinks'); 40const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main'); 41const typeFlag = getOptionValue('--input-type'); 42const { URL, pathToFileURL, fileURLToPath } = require('internal/url'); 43const { 44 ERR_INPUT_TYPE_NOT_ALLOWED, 45 ERR_INVALID_ARG_VALUE, 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_UNSUPPORTED_ESM_URL_SCHEME, 55} = require('internal/errors').codes; 56const { Module: CJSModule } = require('internal/modules/cjs/loader'); 57 58const packageJsonReader = require('internal/modules/package_json_reader'); 59const userConditions = getOptionValue('--conditions'); 60const noAddons = getOptionValue('--no-addons'); 61const addonConditions = noAddons ? [] : ['node-addons']; 62 63const DEFAULT_CONDITIONS = ObjectFreeze([ 64 'node', 65 'import', 66 ...addonConditions, 67 ...userConditions, 68]); 69 70const DEFAULT_CONDITIONS_SET = new SafeSet(DEFAULT_CONDITIONS); 71 72const pendingDeprecation = getOptionValue('--pending-deprecation'); 73 74function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) { 75 if (!pendingDeprecation) 76 return; 77 const { format } = defaultGetFormat(url); 78 if (format !== 'module') 79 return; 80 const path = fileURLToPath(url); 81 const pkgPath = fileURLToPath(new URL('.', packageJSONUrl)); 82 const basePath = fileURLToPath(base); 83 if (main) 84 process.emitWarning( 85 `Package ${pkgPath} has a "main" field set to ${JSONStringify(main)}, ` + 86 `excluding the full filename and extension to the resolved file at "${ 87 StringPrototypeSlice(path, pkgPath.length)}", imported from ${ 88 basePath}.\n Automatic extension resolution of the "main" field is` + 89 'deprecated for ES modules.', 90 'DeprecationWarning', 91 'DEP0151' 92 ); 93 else 94 process.emitWarning( 95 `No "main" or "exports" field defined in the package.json for ${pkgPath 96 } resolving the main entry point "${ 97 StringPrototypeSlice(path, pkgPath.length)}", imported from ${basePath 98 }.\nDefault "index" lookups for the main are deprecated for ES modules.`, 99 'DeprecationWarning', 100 'DEP0151' 101 ); 102} 103 104function getConditionsSet(conditions) { 105 if (conditions !== undefined && conditions !== DEFAULT_CONDITIONS) { 106 if (!ArrayIsArray(conditions)) { 107 throw new ERR_INVALID_ARG_VALUE('conditions', conditions, 108 'expected an array'); 109 } 110 return new SafeSet(conditions); 111 } 112 return DEFAULT_CONDITIONS_SET; 113} 114 115const realpathCache = new SafeMap(); 116const packageJSONCache = new SafeMap(); /* string -> PackageConfig */ 117 118const tryStatSync = 119 (path) => statSync(path, { throwIfNoEntry: false }) ?? new Stats(); 120 121function getPackageConfig(path, specifier, base) { 122 const existing = packageJSONCache.get(path); 123 if (existing !== undefined) { 124 return existing; 125 } 126 const source = packageJsonReader.read(path).string; 127 if (source === undefined) { 128 const packageConfig = { 129 pjsonPath: path, 130 exists: false, 131 main: undefined, 132 name: undefined, 133 type: 'none', 134 exports: undefined, 135 imports: undefined, 136 }; 137 packageJSONCache.set(path, packageConfig); 138 return packageConfig; 139 } 140 141 let packageJSON; 142 try { 143 packageJSON = JSONParse(source); 144 } catch (error) { 145 throw new ERR_INVALID_PACKAGE_CONFIG( 146 path, 147 (base ? `"${specifier}" from ` : '') + fileURLToPath(base || specifier), 148 error.message 149 ); 150 } 151 152 let { imports, main, name, type } = packageJSON; 153 const { exports } = packageJSON; 154 if (typeof imports !== 'object' || imports === null) imports = undefined; 155 if (typeof main !== 'string') main = undefined; 156 if (typeof name !== 'string') name = undefined; 157 // Ignore unknown types for forwards compatibility 158 if (type !== 'module' && type !== 'commonjs') type = 'none'; 159 160 const packageConfig = { 161 pjsonPath: path, 162 exists: true, 163 main, 164 name, 165 type, 166 exports, 167 imports, 168 }; 169 packageJSONCache.set(path, packageConfig); 170 return packageConfig; 171} 172 173function getPackageScopeConfig(resolved) { 174 let packageJSONUrl = new URL('./package.json', resolved); 175 while (true) { 176 const packageJSONPath = packageJSONUrl.pathname; 177 if (StringPrototypeEndsWith(packageJSONPath, 'node_modules/package.json')) 178 break; 179 const packageConfig = getPackageConfig(fileURLToPath(packageJSONUrl), 180 resolved); 181 if (packageConfig.exists) return packageConfig; 182 183 const lastPackageJSONUrl = packageJSONUrl; 184 packageJSONUrl = new URL('../package.json', packageJSONUrl); 185 186 // Terminates at root where ../package.json equals ../../package.json 187 // (can't just check "/package.json" for Windows support). 188 if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) break; 189 } 190 const packageJSONPath = fileURLToPath(packageJSONUrl); 191 const packageConfig = { 192 pjsonPath: packageJSONPath, 193 exists: false, 194 main: undefined, 195 name: undefined, 196 type: 'none', 197 exports: undefined, 198 imports: undefined, 199 }; 200 packageJSONCache.set(packageJSONPath, packageConfig); 201 return packageConfig; 202} 203 204/** 205 * Legacy CommonJS main resolution: 206 * 1. let M = pkg_url + (json main field) 207 * 2. TRY(M, M.js, M.json, M.node) 208 * 3. TRY(M/index.js, M/index.json, M/index.node) 209 * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node) 210 * 5. NOT_FOUND 211 * @param {string | URL} url 212 * @returns {boolean} 213 */ 214function fileExists(url) { 215 return statSync(url, { throwIfNoEntry: false })?.isFile() ?? false; 216} 217 218function legacyMainResolve(packageJSONUrl, packageConfig, base) { 219 let guess; 220 if (packageConfig.main !== undefined) { 221 // Note: fs check redundances will be handled by Descriptor cache here. 222 if (fileExists(guess = new URL(`./${packageConfig.main}`, 223 packageJSONUrl))) { 224 return guess; 225 } else if (fileExists(guess = new URL(`./${packageConfig.main}.js`, 226 packageJSONUrl))); 227 else if (fileExists(guess = new URL(`./${packageConfig.main}.json`, 228 packageJSONUrl))); 229 else if (fileExists(guess = new URL(`./${packageConfig.main}.node`, 230 packageJSONUrl))); 231 else if (fileExists(guess = new URL(`./${packageConfig.main}/index.js`, 232 packageJSONUrl))); 233 else if (fileExists(guess = new URL(`./${packageConfig.main}/index.json`, 234 packageJSONUrl))); 235 else if (fileExists(guess = new URL(`./${packageConfig.main}/index.node`, 236 packageJSONUrl))); 237 else guess = undefined; 238 if (guess) { 239 emitLegacyIndexDeprecation(guess, packageJSONUrl, base, 240 packageConfig.main); 241 return guess; 242 } 243 // Fallthrough. 244 } 245 if (fileExists(guess = new URL('./index.js', packageJSONUrl))); 246 // So fs. 247 else if (fileExists(guess = new URL('./index.json', packageJSONUrl))); 248 else if (fileExists(guess = new URL('./index.node', packageJSONUrl))); 249 else guess = undefined; 250 if (guess) { 251 emitLegacyIndexDeprecation(guess, packageJSONUrl, base, packageConfig.main); 252 return guess; 253 } 254 // Not found. 255 throw new ERR_MODULE_NOT_FOUND( 256 fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base)); 257} 258 259function resolveExtensionsWithTryExactName(search) { 260 if (fileExists(search)) return search; 261 return resolveExtensions(search); 262} 263 264const extensions = ['.js', '.json', '.node', '.mjs']; 265function resolveExtensions(search) { 266 for (let i = 0; i < extensions.length; i++) { 267 const extension = extensions[i]; 268 const guess = new URL(`${search.pathname}${extension}`, search); 269 if (fileExists(guess)) return guess; 270 } 271 return undefined; 272} 273 274function resolveDirectoryEntry(search) { 275 const dirPath = fileURLToPath(search); 276 const pkgJsonPath = resolve(dirPath, 'package.json'); 277 if (fileExists(pkgJsonPath)) { 278 const pkgJson = packageJsonReader.read(pkgJsonPath); 279 if (pkgJson.containsKeys) { 280 const { main } = JSONParse(pkgJson.string); 281 if (main != null) { 282 const mainUrl = pathToFileURL(resolve(dirPath, main)); 283 return resolveExtensionsWithTryExactName(mainUrl); 284 } 285 } 286 } 287 return resolveExtensions(new URL('index', search)); 288} 289 290const encodedSepRegEx = /%2F|%5C/i; 291function finalizeResolution(resolved, base) { 292 if (RegExpPrototypeTest(encodedSepRegEx, resolved.pathname)) 293 throw new ERR_INVALID_MODULE_SPECIFIER( 294 resolved.pathname, 'must not include encoded "/" or "\\" characters', 295 fileURLToPath(base)); 296 297 const path = fileURLToPath(resolved); 298 if (getOptionValue('--experimental-specifier-resolution') === 'node') { 299 let file = resolveExtensionsWithTryExactName(resolved); 300 if (file !== undefined) return file; 301 if (!StringPrototypeEndsWith(path, '/')) { 302 file = resolveDirectoryEntry(new URL(`${resolved}/`)); 303 if (file !== undefined) return file; 304 } else { 305 return resolveDirectoryEntry(resolved) || resolved; 306 } 307 throw new ERR_MODULE_NOT_FOUND( 308 resolved.pathname, fileURLToPath(base), 'module'); 309 } 310 311 const stats = tryStatSync(StringPrototypeEndsWith(path, '/') ? 312 StringPrototypeSlice(path, -1) : path); 313 if (stats.isDirectory()) { 314 const err = new ERR_UNSUPPORTED_DIR_IMPORT(path, fileURLToPath(base)); 315 err.url = String(resolved); 316 throw err; 317 } else if (!stats.isFile()) { 318 throw new ERR_MODULE_NOT_FOUND( 319 path || resolved.pathname, base && fileURLToPath(base), 'module'); 320 } 321 322 return resolved; 323} 324 325function throwImportNotDefined(specifier, packageJSONUrl, base) { 326 throw new ERR_PACKAGE_IMPORT_NOT_DEFINED( 327 specifier, packageJSONUrl && fileURLToPath(new URL('.', packageJSONUrl)), 328 fileURLToPath(base)); 329} 330 331function throwExportsNotFound(subpath, packageJSONUrl, base) { 332 throw new ERR_PACKAGE_PATH_NOT_EXPORTED( 333 fileURLToPath(new URL('.', packageJSONUrl)), subpath, 334 base && fileURLToPath(base)); 335} 336 337function throwInvalidSubpath(subpath, packageJSONUrl, internal, base) { 338 const reason = `request is not a valid subpath for the "${internal ? 339 'imports' : 'exports'}" resolution of ${fileURLToPath(packageJSONUrl)}`; 340 throw new ERR_INVALID_MODULE_SPECIFIER(subpath, reason, 341 base && fileURLToPath(base)); 342} 343 344function throwInvalidPackageTarget( 345 subpath, target, packageJSONUrl, internal, base) { 346 if (typeof target === 'object' && target !== null) { 347 target = JSONStringify(target, null, ''); 348 } else { 349 target = `${target}`; 350 } 351 throw new ERR_INVALID_PACKAGE_TARGET( 352 fileURLToPath(new URL('.', packageJSONUrl)), subpath, target, 353 internal, base && fileURLToPath(base)); 354} 355 356const invalidSegmentRegEx = /(^|\\|\/)(\.\.?|node_modules)(\\|\/|$)/; 357const patternRegEx = /\*/g; 358 359function resolvePackageTargetString( 360 target, subpath, match, packageJSONUrl, base, pattern, internal, conditions) { 361 if (subpath !== '' && !pattern && target[target.length - 1] !== '/') 362 throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); 363 364 if (!StringPrototypeStartsWith(target, './')) { 365 if (internal && !StringPrototypeStartsWith(target, '../') && 366 !StringPrototypeStartsWith(target, '/')) { 367 let isURL = false; 368 try { 369 new URL(target); 370 isURL = true; 371 } catch {} 372 if (!isURL) { 373 const exportTarget = pattern ? 374 StringPrototypeReplace(target, patternRegEx, subpath) : 375 target + subpath; 376 return packageResolve(exportTarget, packageJSONUrl, conditions); 377 } 378 } 379 throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); 380 } 381 382 if (RegExpPrototypeTest(invalidSegmentRegEx, StringPrototypeSlice(target, 2))) 383 throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); 384 385 const resolved = new URL(target, packageJSONUrl); 386 const resolvedPath = resolved.pathname; 387 const packagePath = new URL('.', packageJSONUrl).pathname; 388 389 if (!StringPrototypeStartsWith(resolvedPath, packagePath)) 390 throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); 391 392 if (subpath === '') return resolved; 393 394 if (RegExpPrototypeTest(invalidSegmentRegEx, subpath)) 395 throwInvalidSubpath(match + subpath, packageJSONUrl, internal, base); 396 397 if (pattern) 398 return new URL(StringPrototypeReplace(resolved.href, patternRegEx, 399 subpath)); 400 return new URL(subpath, resolved); 401} 402 403/** 404 * @param {string} key 405 * @returns {boolean} 406 */ 407function isArrayIndex(key) { 408 const keyNum = +key; 409 if (`${keyNum}` !== key) return false; 410 return keyNum >= 0 && keyNum < 0xFFFF_FFFF; 411} 412 413function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath, 414 base, pattern, internal, conditions) { 415 if (typeof target === 'string') { 416 return resolvePackageTargetString( 417 target, subpath, packageSubpath, packageJSONUrl, base, pattern, internal, 418 conditions); 419 } else if (ArrayIsArray(target)) { 420 if (target.length === 0) 421 return null; 422 423 let lastException; 424 for (let i = 0; i < target.length; i++) { 425 const targetItem = target[i]; 426 let resolved; 427 try { 428 resolved = resolvePackageTarget( 429 packageJSONUrl, targetItem, subpath, packageSubpath, base, pattern, 430 internal, conditions); 431 } catch (e) { 432 lastException = e; 433 if (e.code === 'ERR_INVALID_PACKAGE_TARGET') 434 continue; 435 throw e; 436 } 437 if (resolved === undefined) 438 continue; 439 if (resolved === null) { 440 lastException = null; 441 continue; 442 } 443 return resolved; 444 } 445 if (lastException === undefined || lastException === null) 446 return lastException; 447 throw lastException; 448 } else if (typeof target === 'object' && target !== null) { 449 const keys = ObjectGetOwnPropertyNames(target); 450 for (let i = 0; i < keys.length; i++) { 451 const key = keys[i]; 452 if (isArrayIndex(key)) { 453 throw new ERR_INVALID_PACKAGE_CONFIG( 454 fileURLToPath(packageJSONUrl), base, 455 '"exports" cannot contain numeric property keys.'); 456 } 457 } 458 for (let i = 0; i < keys.length; i++) { 459 const key = keys[i]; 460 if (key === 'default' || conditions.has(key)) { 461 const conditionalTarget = target[key]; 462 const resolved = resolvePackageTarget( 463 packageJSONUrl, conditionalTarget, subpath, packageSubpath, base, 464 pattern, internal, conditions); 465 if (resolved === undefined) 466 continue; 467 return resolved; 468 } 469 } 470 return undefined; 471 } else if (target === null) { 472 return null; 473 } 474 throwInvalidPackageTarget(packageSubpath, target, packageJSONUrl, internal, 475 base); 476} 477 478function isConditionalExportsMainSugar(exports, packageJSONUrl, base) { 479 if (typeof exports === 'string' || ArrayIsArray(exports)) return true; 480 if (typeof exports !== 'object' || exports === null) return false; 481 482 const keys = ObjectGetOwnPropertyNames(exports); 483 let isConditionalSugar = false; 484 let i = 0; 485 for (let j = 0; j < keys.length; j++) { 486 const key = keys[j]; 487 const curIsConditionalSugar = key === '' || key[0] !== '.'; 488 if (i++ === 0) { 489 isConditionalSugar = curIsConditionalSugar; 490 } else if (isConditionalSugar !== curIsConditionalSugar) { 491 throw new ERR_INVALID_PACKAGE_CONFIG( 492 fileURLToPath(packageJSONUrl), base, 493 '"exports" cannot contain some keys starting with \'.\' and some not.' + 494 ' The exports object must either be an object of package subpath keys' + 495 ' or an object of main entry condition name keys only.'); 496 } 497 } 498 return isConditionalSugar; 499} 500 501/** 502 * @param {URL} packageJSONUrl 503 * @param {string} packageSubpath 504 * @param {object} packageConfig 505 * @param {string} base 506 * @param {Set<string>} conditions 507 * @returns {URL} 508 */ 509function packageExportsResolve( 510 packageJSONUrl, packageSubpath, packageConfig, base, conditions) { 511 let exports = packageConfig.exports; 512 if (isConditionalExportsMainSugar(exports, packageJSONUrl, base)) 513 exports = { '.': exports }; 514 515 if (ObjectPrototypeHasOwnProperty(exports, packageSubpath) && 516 !StringPrototypeIncludes(packageSubpath, '*') && 517 !StringPrototypeEndsWith(packageSubpath, '/')) { 518 const target = exports[packageSubpath]; 519 const resolved = resolvePackageTarget( 520 packageJSONUrl, target, '', packageSubpath, base, false, false, conditions 521 ); 522 if (resolved === null || resolved === undefined) 523 throwExportsNotFound(packageSubpath, packageJSONUrl, base); 524 return { resolved, exact: true }; 525 } 526 527 let bestMatch = ''; 528 let bestMatchSubpath; 529 const keys = ObjectGetOwnPropertyNames(exports); 530 for (let i = 0; i < keys.length; i++) { 531 const key = keys[i]; 532 const patternIndex = StringPrototypeIndexOf(key, '*'); 533 if (patternIndex !== -1 && 534 StringPrototypeStartsWith(packageSubpath, 535 StringPrototypeSlice(key, 0, patternIndex))) { 536 const patternTrailer = StringPrototypeSlice(key, patternIndex + 1); 537 if (packageSubpath.length >= key.length && 538 StringPrototypeEndsWith(packageSubpath, patternTrailer) && 539 patternKeyCompare(bestMatch, key) === 1 && 540 StringPrototypeLastIndexOf(key, '*') === patternIndex) { 541 bestMatch = key; 542 bestMatchSubpath = StringPrototypeSlice( 543 packageSubpath, patternIndex, 544 packageSubpath.length - patternTrailer.length); 545 } 546 } else if (key[key.length - 1] === '/' && 547 StringPrototypeStartsWith(packageSubpath, key) && 548 patternKeyCompare(bestMatch, key) === 1) { 549 bestMatch = key; 550 bestMatchSubpath = StringPrototypeSlice(packageSubpath, key.length); 551 } 552 } 553 554 if (bestMatch) { 555 const target = exports[bestMatch]; 556 const pattern = StringPrototypeIncludes(bestMatch, '*'); 557 const resolved = resolvePackageTarget(packageJSONUrl, target, 558 bestMatchSubpath, bestMatch, base, 559 pattern, false, conditions); 560 if (resolved === null || resolved === undefined) 561 throwExportsNotFound(packageSubpath, packageJSONUrl, base); 562 return { resolved, exact: pattern }; 563 } 564 565 throwExportsNotFound(packageSubpath, packageJSONUrl, base); 566} 567 568function patternKeyCompare(a, b) { 569 const aPatternIndex = StringPrototypeIndexOf(a, '*'); 570 const bPatternIndex = StringPrototypeIndexOf(b, '*'); 571 const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1; 572 const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1; 573 if (baseLenA > baseLenB) return -1; 574 if (baseLenB > baseLenA) return 1; 575 if (aPatternIndex === -1) return 1; 576 if (bPatternIndex === -1) return -1; 577 if (a.length > b.length) return -1; 578 if (b.length > a.length) return 1; 579 return 0; 580} 581 582function packageImportsResolve(name, base, conditions) { 583 if (name === '#' || StringPrototypeStartsWith(name, '#/')) { 584 const reason = 'is not a valid internal imports specifier name'; 585 throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath(base)); 586 } 587 let packageJSONUrl; 588 const packageConfig = getPackageScopeConfig(base); 589 if (packageConfig.exists) { 590 packageJSONUrl = pathToFileURL(packageConfig.pjsonPath); 591 const imports = packageConfig.imports; 592 if (imports) { 593 if (ObjectPrototypeHasOwnProperty(imports, name) && 594 !StringPrototypeIncludes(name, '*') && 595 !StringPrototypeEndsWith(name, '/')) { 596 const resolved = resolvePackageTarget( 597 packageJSONUrl, imports[name], '', name, base, false, true, conditions 598 ); 599 if (resolved !== null) 600 return { resolved, exact: true }; 601 } else { 602 let bestMatch = ''; 603 let bestMatchSubpath; 604 const keys = ObjectGetOwnPropertyNames(imports); 605 for (let i = 0; i < keys.length; i++) { 606 const key = keys[i]; 607 const patternIndex = StringPrototypeIndexOf(key, '*'); 608 if (patternIndex !== -1 && 609 StringPrototypeStartsWith(name, 610 StringPrototypeSlice(key, 0, 611 patternIndex))) { 612 const patternTrailer = StringPrototypeSlice(key, patternIndex + 1); 613 if (name.length >= key.length && 614 StringPrototypeEndsWith(name, patternTrailer) && 615 patternKeyCompare(bestMatch, key) === 1 && 616 StringPrototypeLastIndexOf(key, '*') === patternIndex) { 617 bestMatch = key; 618 bestMatchSubpath = StringPrototypeSlice( 619 name, patternIndex, name.length - patternTrailer.length); 620 } 621 } else if (key[key.length - 1] === '/' && 622 StringPrototypeStartsWith(name, key) && 623 patternKeyCompare(bestMatch, key) === 1) { 624 bestMatch = key; 625 bestMatchSubpath = StringPrototypeSlice(name, key.length); 626 } 627 } 628 629 if (bestMatch) { 630 const target = imports[bestMatch]; 631 const pattern = StringPrototypeIncludes(bestMatch, '*'); 632 const resolved = resolvePackageTarget(packageJSONUrl, target, 633 bestMatchSubpath, bestMatch, 634 base, pattern, true, 635 conditions); 636 if (resolved !== null) 637 return { resolved, exact: pattern }; 638 } 639 } 640 } 641 } 642 throwImportNotDefined(name, packageJSONUrl, base); 643} 644 645function getPackageType(url) { 646 const packageConfig = getPackageScopeConfig(url); 647 return packageConfig.type; 648} 649 650/** 651 * @param {string} specifier 652 * @param {URL} base 653 * @param {Set<string>} conditions 654 * @returns {URL} 655 */ 656function packageResolve(specifier, base, conditions) { 657 let separatorIndex = StringPrototypeIndexOf(specifier, '/'); 658 let validPackageName = true; 659 let isScoped = false; 660 if (specifier[0] === '@') { 661 isScoped = true; 662 if (separatorIndex === -1 || specifier.length === 0) { 663 validPackageName = false; 664 } else { 665 separatorIndex = StringPrototypeIndexOf( 666 specifier, '/', separatorIndex + 1); 667 } 668 } 669 670 const packageName = separatorIndex === -1 ? 671 specifier : StringPrototypeSlice(specifier, 0, separatorIndex); 672 673 // Package name cannot have leading . and cannot have percent-encoding or 674 // separators. 675 for (let i = 0; i < packageName.length; i++) { 676 if (packageName[i] === '%' || packageName[i] === '\\') { 677 validPackageName = false; 678 break; 679 } 680 } 681 682 if (!validPackageName) { 683 throw new ERR_INVALID_MODULE_SPECIFIER( 684 specifier, 'is not a valid package name', fileURLToPath(base)); 685 } 686 687 const packageSubpath = '.' + (separatorIndex === -1 ? '' : 688 StringPrototypeSlice(specifier, separatorIndex)); 689 690 // ResolveSelf 691 const packageConfig = getPackageScopeConfig(base); 692 if (packageConfig.exists) { 693 const packageJSONUrl = pathToFileURL(packageConfig.pjsonPath); 694 if (packageConfig.name === packageName && 695 packageConfig.exports !== undefined && packageConfig.exports !== null) { 696 return packageExportsResolve( 697 packageJSONUrl, packageSubpath, packageConfig, base, conditions 698 ).resolved; 699 } 700 } 701 702 let packageJSONUrl = 703 new URL('./node_modules/' + packageName + '/package.json', base); 704 let packageJSONPath = fileURLToPath(packageJSONUrl); 705 let lastPath; 706 do { 707 const stat = tryStatSync(StringPrototypeSlice(packageJSONPath, 0, 708 packageJSONPath.length - 13)); 709 if (!stat.isDirectory()) { 710 lastPath = packageJSONPath; 711 packageJSONUrl = new URL((isScoped ? 712 '../../../../node_modules/' : '../../../node_modules/') + 713 packageName + '/package.json', packageJSONUrl); 714 packageJSONPath = fileURLToPath(packageJSONUrl); 715 continue; 716 } 717 718 // Package match. 719 const packageConfig = getPackageConfig(packageJSONPath, specifier, base); 720 if (packageConfig.exports !== undefined && packageConfig.exports !== null) 721 return packageExportsResolve( 722 packageJSONUrl, packageSubpath, packageConfig, base, conditions 723 ).resolved; 724 if (packageSubpath === '.') 725 return legacyMainResolve(packageJSONUrl, packageConfig, base); 726 return new URL(packageSubpath, packageJSONUrl); 727 // Cross-platform root check. 728 } while (packageJSONPath.length !== lastPath.length); 729 730 // eslint can't handle the above code. 731 // eslint-disable-next-line no-unreachable 732 throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base)); 733} 734 735function isBareSpecifier(specifier) { 736 return specifier[0] && specifier[0] !== '/' && specifier[0] !== '.'; 737} 738 739function isRelativeSpecifier(specifier) { 740 if (specifier[0] === '.') { 741 if (specifier.length === 1 || specifier[1] === '/') return true; 742 if (specifier[1] === '.') { 743 if (specifier.length === 2 || specifier[2] === '/') return true; 744 } 745 } 746 return false; 747} 748 749function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) { 750 if (specifier === '') return false; 751 if (specifier[0] === '/') return true; 752 return isRelativeSpecifier(specifier); 753} 754 755/** 756 * @param {string} specifier 757 * @param {URL} base 758 * @param {Set<string>} conditions 759 * @returns {URL} 760 */ 761function moduleResolve(specifier, base, conditions) { 762 // Order swapped from spec for minor perf gain. 763 // Ok since relative URLs cannot parse as URLs. 764 let resolved; 765 if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) { 766 resolved = new URL(specifier, base); 767 } else if (specifier[0] === '#') { 768 ({ resolved } = packageImportsResolve(specifier, base, conditions)); 769 } else { 770 try { 771 resolved = new URL(specifier); 772 } catch { 773 resolved = packageResolve(specifier, base, conditions); 774 } 775 } 776 return finalizeResolution(resolved, base); 777} 778 779/** 780 * Try to resolve an import as a CommonJS module 781 * @param {string} specifier 782 * @param {string} parentURL 783 * @returns {boolean|string} 784 */ 785function resolveAsCommonJS(specifier, parentURL) { 786 try { 787 const parent = fileURLToPath(parentURL); 788 const tmpModule = new CJSModule(parent, null); 789 tmpModule.paths = CJSModule._nodeModulePaths(parent); 790 791 let found = CJSModule._resolveFilename(specifier, tmpModule, false); 792 793 // If it is a relative specifier return the relative path 794 // to the parent 795 if (isRelativeSpecifier(specifier)) { 796 found = relative(parent, found); 797 // Add '.separator if the path does not start with '..separator' 798 // This should be a safe assumption because when loading 799 // esm modules there should be always a file specified so 800 // there should not be a specifier like '..' or '.' 801 if (!StringPrototypeStartsWith(found, `..${sep}`)) { 802 found = `.${sep}${found}`; 803 } 804 } else if (isBareSpecifier(specifier)) { 805 // If it is a bare specifier return the relative path within the 806 // module 807 const pkg = StringPrototypeSplit(specifier, '/')[0]; 808 const index = StringPrototypeIndexOf(found, pkg); 809 if (index !== -1) { 810 found = StringPrototypeSlice(found, index); 811 } 812 } 813 // Normalize the path separator to give a valid suggestion 814 // on Windows 815 if (process.platform === 'win32') { 816 found = StringPrototypeReplace(found, new RegExp(`\\${sep}`, 'g'), '/'); 817 } 818 return found; 819 } catch { 820 return false; 821 } 822} 823 824function defaultResolve(specifier, context = {}, defaultResolveUnused) { 825 let { parentURL, conditions } = context; 826 if (parentURL && policy?.manifest) { 827 const redirects = policy.manifest.getDependencyMapper(parentURL); 828 if (redirects) { 829 const { resolve, reaction } = redirects; 830 const destination = resolve(specifier, new SafeSet(conditions)); 831 let missing = true; 832 if (destination === true) { 833 missing = false; 834 } else if (destination) { 835 const href = destination.href; 836 return { url: href }; 837 } 838 if (missing) { 839 reaction(new ERR_MANIFEST_DEPENDENCY_MISSING( 840 parentURL, 841 specifier, 842 ArrayPrototypeJoin([...conditions], ', ')) 843 ); 844 } 845 } 846 } 847 let parsed; 848 try { 849 parsed = new URL(specifier); 850 if (parsed.protocol === 'data:') { 851 return { 852 url: specifier 853 }; 854 } 855 } catch {} 856 if (parsed && parsed.protocol === 'node:') 857 return { url: specifier }; 858 if (parsed && parsed.protocol !== 'file:' && parsed.protocol !== 'data:') 859 throw new ERR_UNSUPPORTED_ESM_URL_SCHEME(parsed); 860 if (NativeModule.canBeRequiredByUsers(specifier)) { 861 return { 862 url: 'node:' + specifier 863 }; 864 } 865 if (parentURL && StringPrototypeStartsWith(parentURL, 'data:')) { 866 // This is gonna blow up, we want the error 867 new URL(specifier, parentURL); 868 } 869 870 const isMain = parentURL === undefined; 871 if (isMain) { 872 parentURL = pathToFileURL(`${process.cwd()}/`).href; 873 874 // This is the initial entry point to the program, and --input-type has 875 // been passed as an option; but --input-type can only be used with 876 // --eval, --print or STDIN string input. It is not allowed with file 877 // input, to avoid user confusion over how expansive the effect of the 878 // flag should be (i.e. entry point only, package scope surrounding the 879 // entry point, etc.). 880 if (typeFlag) 881 throw new ERR_INPUT_TYPE_NOT_ALLOWED(); 882 } 883 884 conditions = getConditionsSet(conditions); 885 let url; 886 try { 887 url = moduleResolve(specifier, parentURL, conditions); 888 } catch (error) { 889 // Try to give the user a hint of what would have been the 890 // resolved CommonJS module 891 if (error.code === 'ERR_MODULE_NOT_FOUND' || 892 error.code === 'ERR_UNSUPPORTED_DIR_IMPORT') { 893 if (StringPrototypeStartsWith(specifier, 'file://')) { 894 specifier = fileURLToPath(specifier); 895 } 896 const found = resolveAsCommonJS(specifier, parentURL); 897 if (found) { 898 // Modify the stack and message string to include the hint 899 const lines = StringPrototypeSplit(error.stack, '\n'); 900 const hint = `Did you mean to import ${found}?`; 901 error.stack = 902 ArrayPrototypeShift(lines) + '\n' + 903 hint + '\n' + 904 ArrayPrototypeJoin(lines, '\n'); 905 error.message += `\n${hint}`; 906 } 907 } 908 throw error; 909 } 910 911 if (isMain ? !preserveSymlinksMain : !preserveSymlinks) { 912 const urlPath = fileURLToPath(url); 913 const real = realpathSync(urlPath, { 914 [internalFS.realpathCacheKey]: realpathCache 915 }); 916 const old = url; 917 url = pathToFileURL( 918 real + (StringPrototypeEndsWith(urlPath, sep) ? '/' : '')); 919 url.search = old.search; 920 url.hash = old.hash; 921 } 922 923 return { url: `${url}` }; 924} 925 926module.exports = { 927 DEFAULT_CONDITIONS, 928 defaultResolve, 929 encodedSepRegEx, 930 getPackageScopeConfig, 931 getPackageType, 932 packageExportsResolve, 933 packageImportsResolve 934}; 935 936// cycle 937const { defaultGetFormat } = require('internal/modules/esm/get_format'); 938