fix(reference): preserve directory intent when resolving source imports (#2770)

Keep directory requests from becoming unresolved or pointing at sibling files
when constructing reference-source dependency graphs. Canonicalize index
candidates and preserve directory intent while retaining ordinary lookup rules.

Constraint: Preserve current TypeScript candidate objects and exact-before-Unicode lookup
Rejected: Reorder all file probes before index probes | Changes ordinary CommonJS candidate priority
Confidence: high
Scope-risk: narrow
Tested: Public CLI regression fails on base; focused reference and resolver suites pass; npm run check
Not-tested: Full suite on refreshed base; earlier full run had 12 baseline-reproduced failures
This commit is contained in:
Shenrui Ma authored and GitHub committed 2026-10-13 20:06:19 +08:00
1 parent 1dd6c2dff9
commit 68ecdcd7a1
2 files changed
+129 -7

No files matched your search

@@ -97,18 +97,22 @@ const resolveInternalSpecifier = (
);
if (logicalPathEscapesRoot(normalized))
return { to: normalized, resolution: "unresolved" };
// Preserve directory intent before normalization removes terminal dot segments.
const directoryReference =
specifier.endsWith("/") || [".", ".."].includes(posix.basename(specifier));
const suffixes = ["", ".ts", ".js", ".mjs", ".cjs", ".tsx", ".jsx"];
const candidates = suffixes.flatMap((suffix) => [
`${normalized}${suffix}`,
`${normalized}/index${suffix}`,
...(directoryReference ? [] : [`${normalized}${suffix}`]),
posix.join(normalized, `index${suffix}`),
]);
// Retain present runtime files first; substitute only a missing counterpart.
// Counterparts cover explicit filenames, not directory/index resolution.
candidates.push(
...typescriptEmittedSourceCandidates(fromPath, normalized).map(
({ path }) => path,
),
);
if (!directoryReference)
candidates.push(
...typescriptEmittedSourceCandidates(fromPath, normalized).map(
({ path }) => path,
),
);
const match = lookupPath.resolveCandidates(candidates);
return match === undefined
? { to: normalized, resolution: "unresolved" }