fix(javascript): resolve package exports targets only to the exact file (#1181)

A selected package exports target names one file, and Node tries no
extension or directory index for it. REA still resolved it like a relative
specifier, so `exports: "./file"` with only `file.js` present, or
`"./folder"` with only `folder/index.js`, reported a resolved import that
Node rejects under both import and require.

Resolve an exports target only to its exact file and otherwise report
not-found with a limitation naming the target. Legacy main entries keep
their extension and index fallbacks.

Fixes #1174

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kaoru0822
2026-10-08 20:49:32 -07:00
committed by GitHub
parent e1afbc1914
commit 2a620c06cd
3 changed files with 88 additions and 2 deletions
@@ -105,8 +105,11 @@ const resolvePackagePath = (
],
},
);
const resolved =
mode === "files-and-index"
// An exports target names one exact file; Node tries no extension or index.
const resolved = exportsTargetUrl
? (resolveFileCandidates(input, [confined]) ??
exactExportsTargetNotFound(confined))
: mode === "files-and-index"
? (resolveFileCandidates(input, [
...fileCandidates(confined),
...indexCandidates(confined),
@@ -619,6 +622,14 @@ const notFoundCandidate = (): CandidateResolution => ({
],
});
const exactExportsTargetNotFound = (path: string): CandidateResolution => ({
resolvedPath: null,
status: "not-found",
limitations: [
`The selected package exports target ${path} does not exist in the inventoried artifact container; exports targets are exact files, so no extension or directory index was tried.`,
],
});
const fileUrlPath = (value: string): string | undefined => {
if (!value.startsWith("file://")) return undefined;
try {