Resolve symlinked project-reference directory (index.ts) subpaths to source#4374
Open
sverrejoh wants to merge 1 commit into
Open
Resolve symlinked project-reference directory (index.ts) subpaths to source#4374sverrejoh wants to merge 1 commit into
index.ts) subpaths to source#4374sverrejoh wants to merge 1 commit into
Conversation
…source The source-of-project-reference redirect failed for a directory subpath import (e.g. b/lib/File, source b/src/File/index.ts) when the referenced package is reached through a symlinked node_modules entry and its lib/ is unbuilt. knownSymlinks is populated lazily by handleDirectoryCouldBeSymlink only when an existing directory is probed. For a directory subpath the resolver DirectoryExists-probes the unbuilt subpath before the package root, so the symlink isn't registered yet and the (cached) lookup misses. Discover and register the package symlink on demand on a node_modules miss, by walking up to the nearest existing ancestor and reusing handleDirectoryCouldBeSymlink; the existing symlink-aware fallback then resolves to source. Runs only on a miss, so built/normal resolution is unaffected. Fixes microsoft#4373
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a path-resolution edge case in the project-reference “use source instead of .d.ts outputs” redirect when the referenced package is reached via a symlinked node_modules entry and the resolver probes an unbuilt directory subpath (e.g. b/lib/File → b/src/File/index.ts) before ever probing the package root, causing a cached negative lookup.
Changes:
- Teach the project-reference d.ts faking VFS to opportunistically discover/register a
node_modulespackage symlink by walking up to the nearest existing ancestor directory on a miss, so subsequent symlink-aware fallback can map to source. - Add a regression test covering a directory-subpath (
index.ts) import through a symlinked referenced project.
Show a summary per file
| File | Description |
|---|---|
| internal/compiler/projectreferencedtsfakinghost.go | On a miss, walks up to an existing ancestor under node_modules and calls existing symlink registration logic so directory-subpath redirects can resolve to source. |
| internal/project/projectreferencesprogram_test.go | Adds a regression test for resolving a symlinked project reference via a directory subpath that maps to src/.../index.ts when outputs are unbuilt. |
Copilot's findings
- Files reviewed: 2/2 changed files
- Comments generated: 0
jakebailey
reviewed
Jun 19, 2026
| // records it in knownSymlinks. This handles the case where the resolver probes a | ||
| // path inside an unbuilt package before directory-probing the package root, so | ||
| // handleDirectoryCouldBeSymlink has not fired for it yet. | ||
| func (fs *projectReferenceDtsFakingVfs) registerNodeModulesSymlinkFromAncestor(fileOrDirectory string) { |
Member
There was a problem hiding this comment.
This seems very special case-y. Surely any dir we resolve into could be under be a symlink? How are we not working with realpaths already?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4373. This is a 6.0 → 7.0 regression: TypeScript 6.0.3 resolves the same project from source; the native compiler reports
TS2307(details + runnable repro in the issue).The source-of-project-reference redirect failed to resolve a directory subpath import (e.g.
b/lib/Filewhere the source isb/src/File/index.ts) when the referenced package is reached through a symlinkednode_modulesentry and itslib/is unbuilt.Cause
The dts faking host resolves symlinked paths through
knownSymlinks, which is populated lazily byhandleDirectoryCouldBeSymlink— and only when an existing directory is probed. For a directory subpath the resolverDirectoryExists-probes the unbuilt subpath (node_modules/b/lib/File) before it ever directory-probes the package root (node_modules/b), so the package symlink isn't inknownSymlinksyet, the lookup misses, and the cached negative sticks. (File subpaths happen to probe the package root first, which is why the existing symlink tests pass.)Fix
On a
node_modulesmiss infileOrDirectoryExistsUsingSource, discover and register the package symlink on demand: walk up to the nearest existing ancestor directory and reuse the existinghandleDirectoryCouldBeSymlink. The existing symlink-aware fallback then resolves the subpath to source. It only runs on a miss, so built/normal resolution is unaffected.Test
Added
internal/projectTestProjectReferencesProgram/ "references through symlink to a directory subpath (index file)", which fails without the change (indexFile is nil) and passes with it.internal/projectandinternal/compilersuites are green.AI assistance
This change was authored with AI assistance (Claude Code). I investigated the bug, directed and reviewed the work, understand the change, and will shepherd it through review and respond to feedback myself.