@@ -59,6 +59,7 @@ const enableSourceMaps = getOptionValue('--enable-source-maps'); |
59 | 59 | const preserveSymlinks = getOptionValue('--preserve-symlinks'); |
60 | 60 | const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main'); |
61 | 61 | const experimentalModules = getOptionValue('--experimental-modules'); |
| 62 | +const experimentalSelf = getOptionValue('--experimental-resolve-self'); |
62 | 63 | const manifest = getOptionValue('--experimental-policy') ? |
63 | 64 | require('internal/process/policy').manifest : |
64 | 65 | null; |
@@ -237,6 +238,7 @@ function readPackage(requestPath) { |
237 | 238 | try { |
238 | 239 | const parsed = JSON.parse(json); |
239 | 240 | const filtered = { |
| 241 | + name: parsed.name, |
240 | 242 | main: parsed.main, |
241 | 243 | exports: parsed.exports, |
242 | 244 | type: parsed.type |
@@ -366,6 +368,125 @@ function findLongestRegisteredExtension(filename) { |
366 | 368 | return '.js'; |
367 | 369 | } |
368 | 370 |
|
| 371 | +function resolveBasePath(basePath, exts, isMain, trailingSlash, request) { |
| 372 | + let filename; |
| 373 | + |
| 374 | + const rc = stat(basePath); |
| 375 | + if (!trailingSlash) { |
| 376 | + if (rc === 0) { // File. |
| 377 | + if (!isMain) { |
| 378 | + if (preserveSymlinks) { |
| 379 | + filename = path.resolve(basePath); |
| 380 | + } else { |
| 381 | + filename = toRealPath(basePath); |
| 382 | + } |
| 383 | + } else if (preserveSymlinksMain) { |
| 384 | + // For the main module, we use the preserveSymlinksMain flag instead |
| 385 | + // mainly for backward compatibility, as the preserveSymlinks flag |
| 386 | + // historically has not applied to the main module. Most likely this |
| 387 | + // was intended to keep .bin/ binaries working, as following those |
| 388 | + // symlinks is usually required for the imports in the corresponding |
| 389 | + // files to resolve; that said, in some use cases following symlinks |
| 390 | + // causes bigger problems which is why the preserveSymlinksMain option |
| 391 | + // is needed. |
| 392 | + filename = path.resolve(basePath); |
| 393 | + } else { |
| 394 | + filename = toRealPath(basePath); |
| 395 | + } |
| 396 | + } |
| 397 | + |
| 398 | + if (!filename) { |
| 399 | + // Try it with each of the extensions |
| 400 | + if (exts === undefined) |
| 401 | + exts = Object.keys(Module._extensions); |
| 402 | + filename = tryExtensions(basePath, exts, isMain); |
| 403 | + } |
| 404 | + } |
| 405 | + |
| 406 | + if (!filename && rc === 1) { // Directory. |
| 407 | + // try it with each of the extensions at "index" |
| 408 | + if (exts === undefined) |
| 409 | + exts = Object.keys(Module._extensions); |
| 410 | + filename = tryPackage(basePath, exts, isMain, request); |
| 411 | + } |
| 412 | + |
| 413 | + return filename; |
| 414 | +} |
| 415 | + |
| 416 | +function trySelf(paths, exts, isMain, trailingSlash, request) { |
| 417 | + if (!experimentalSelf) { |
| 418 | + return false; |
| 419 | + } |
| 420 | + |
| 421 | + const { data: pkg, path: basePath } = readPackageScope(paths[0]); |
| 422 | + if (!pkg) return false; |
| 423 | + if (typeof pkg.name !== 'string') return false; |
| 424 | + |
| 425 | + let expansion; |
| 426 | + if (request === pkg.name) { |
| 427 | + expansion = ''; |
| 428 | + } else if (StringPrototype.startsWith(request, `${pkg.name}/`)) { |
| 429 | + expansion = StringPrototype.slice(request, pkg.name.length); |
| 430 | + } else { |
| 431 | + return false; |
| 432 | + } |
| 433 | + |
| 434 | + if (exts === undefined) |
| 435 | + exts = Object.keys(Module._extensions); |
| 436 | + |
| 437 | + if (expansion) { |
| 438 | + // Use exports |
| 439 | + const fromExports = applyExports(basePath, expansion); |
| 440 | + if (!fromExports) return false; |
| 441 | + return resolveBasePath(fromExports, exts, isMain, trailingSlash, request); |
| 442 | + } else { |
| 443 | + // Use main field |
| 444 | + return tryPackage(basePath, exts, isMain, request); |
| 445 | + } |
| 446 | +} |
| 447 | + |
| 448 | +function applyExports(basePath, expansion) { |
| 449 | + const pkgExports = readPackageExports(basePath); |
| 450 | + const mappingKey = `.${expansion}`; |
| 451 | + |
| 452 | + if (typeof pkgExports === 'object' && pkgExports !== null) { |
| 453 | + if (ObjectPrototype.hasOwnProperty(pkgExports, mappingKey)) { |
| 454 | + const mapping = pkgExports[mappingKey]; |
| 455 | + return resolveExportsTarget(pathToFileURL(basePath + '/'), mapping, '', |
| 456 | + basePath, mappingKey); |
| 457 | + } |
| 458 | + |
| 459 | + let dirMatch = ''; |
| 460 | + for (const candidateKey of Object.keys(pkgExports)) { |
| 461 | + if (candidateKey[candidateKey.length - 1] !== '/') continue; |
| 462 | + if (candidateKey.length > dirMatch.length && |
| 463 | + StringPrototype.startsWith(mappingKey, candidateKey)) { |
| 464 | + dirMatch = candidateKey; |
| 465 | + } |
| 466 | + } |
| 467 | + |
| 468 | + if (dirMatch !== '') { |
| 469 | + const mapping = pkgExports[dirMatch]; |
| 470 | + const subpath = StringPrototype.slice(mappingKey, dirMatch.length); |
| 471 | + return resolveExportsTarget(pathToFileURL(basePath + '/'), mapping, |
| 472 | + subpath, basePath, mappingKey); |
| 473 | + } |
| 474 | + } |
| 475 | + if (mappingKey === '.' && typeof pkgExports === 'string') { |
| 476 | + return resolveExportsTarget(pathToFileURL(basePath + '/'), pkgExports, |
| 477 | + '', basePath, mappingKey); |
| 478 | + } |
| 479 | + if (pkgExports != null) { |
| 480 | + // eslint-disable-next-line no-restricted-syntax |
| 481 | + const e = new Error(`Package exports for '${basePath}' do not define ` + |
| 482 | + `a '${mappingKey}' subpath`); |
| 483 | + e.code = 'MODULE_NOT_FOUND'; |
| 484 | + throw e; |
| 485 | + } |
| 486 | + |
| 487 | + return path.resolve(basePath, mappingKey); |
| 488 | +} |
| 489 | + |
369 | 490 | // This only applies to requests of a specific form: |
370 | 491 | // 1. name/.* |
371 | 492 | // 2. @scope/name/.* |
@@ -380,43 +501,7 @@ function resolveExports(nmPath, request, absoluteRequest) { |
380 | 501 | } |
381 | 502 |
|
382 | 503 | const basePath = path.resolve(nmPath, name); |
383 | | - const pkgExports = readPackageExports(basePath); |
384 | | - const mappingKey = `.${expansion}`; |
385 | | - |
386 | | - if (typeof pkgExports === 'object' && pkgExports !== null) { |
387 | | - if (ObjectPrototype.hasOwnProperty(pkgExports, mappingKey)) { |
388 | | - const mapping = pkgExports[mappingKey]; |
389 | | - return resolveExportsTarget(pathToFileURL(basePath + '/'), mapping, '', |
390 | | - basePath, mappingKey); |
391 | | - } |
392 | | - |
393 | | - let dirMatch = ''; |
394 | | - for (const candidateKey of Object.keys(pkgExports)) { |
395 | | - if (candidateKey[candidateKey.length - 1] !== '/') continue; |
396 | | - if (candidateKey.length > dirMatch.length && |
397 | | - StringPrototype.startsWith(mappingKey, candidateKey)) { |
398 | | - dirMatch = candidateKey; |
399 | | - } |
400 | | - } |
401 | | - |
402 | | - if (dirMatch !== '') { |
403 | | - const mapping = pkgExports[dirMatch]; |
404 | | - const subpath = StringPrototype.slice(mappingKey, dirMatch.length); |
405 | | - return resolveExportsTarget(pathToFileURL(basePath + '/'), mapping, |
406 | | - subpath, basePath, mappingKey); |
407 | | - } |
408 | | - } |
409 | | - if (mappingKey === '.' && typeof pkgExports === 'string') { |
410 | | - return resolveExportsTarget(pathToFileURL(basePath + '/'), pkgExports, |
411 | | - '', basePath, mappingKey); |
412 | | - } |
413 | | - if (pkgExports != null) { |
414 | | - // eslint-disable-next-line no-restricted-syntax |
415 | | - const e = new Error(`Package exports for '${basePath}' do not define ` + |
416 | | - `a '${mappingKey}' subpath`); |
417 | | - e.code = 'MODULE_NOT_FOUND'; |
418 | | - throw e; |
419 | | - } |
| 504 | + return applyExports(basePath, expansion); |
420 | 505 | } |
421 | 506 |
|
422 | 507 | return path.resolve(nmPath, request); |
@@ -532,6 +617,13 @@ Module._findPath = function(request, paths, isMain) { |
532 | 617 | return filename; |
533 | 618 | } |
534 | 619 | } |
| 620 | + |
| 621 | + const selfFilename = trySelf(paths, exts, isMain, trailingSlash, request); |
| 622 | + if (selfFilename) { |
| 623 | + Module._pathCache[cacheKey] = selfFilename; |
| 624 | + return selfFilename; |
| 625 | + } |
| 626 | + |
535 | 627 | return false; |
536 | 628 | }; |
537 | 629 |
|
|