Skip to content

Restart a file's imports when a later arrival lowers its node_modules depth - #64632

Merged
Andrew Branch (andrewbranch) merged 2 commits into
microsoft:mainfrom
cplieger:fix-64498-external-library-depth
Oct 5, 2026
Merged

Andrew Branch (andrewbranch) merged 2 commits into
microsoft:mainfrom
cplieger:fix-64498-external-library-depth

Conversation

@cplieger

@cplieger Christopher Plieger (cplieger) commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

When the files parser reaches a file again at a lower depth, it lowers lowestDepth and sets startSubtasks, but the startedSubTasks guard skips the restart because the first arrival already started the file's imports. Those imports keep the first arrival's depth, so a file reached through node_modules first and then from a root file without passing through node_modules leaves its own imports in sourceFilesFoundSearchingNodeModules, and which arrival comes first depends on scheduling.

Impact: in a monorepo where a package is reached both by a relative import and through a node_modules link, which files count as library files changes between identical runs. The same build can then emit different files (#64498), and an analyzer on the API gives a different answer each run: on vitest, 20 opens of one configuration gave five different counts.

The change restarts the subtasks whenever the depth drops, even when they were already started. Each restart strictly lowers a file's lowestDepth, so the extra work is bounded.

The compiler test symlinkedPackageReachedRelativelyIsNotExternalLibrary has a.ts import ./lib/index and b.ts import lib through a node_modules symlink to lib/. Without the change, lib/util.ts counts as from an external library and its util.js is missing from the emit baseline.

I met this while building deadset-ts, the TypeScript analyzer of deadset, on the TypeScript 7 API. That work hit a small set of related defects, which is why a few reports come from me.

An AI coding agent wrote this patch. I have read, built and tested it and will handle the review.

  • There is an associated issue in the Backlog milestone (required)
  • Code is up-to-date with the main branch
  • You've successfully run npx hereby test
  • You've successfully run npx hereby lint
  • You've successfully run npx hereby check:format
  • There are new or updated tests validating the change

Fixes #64498

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The bounded restart logic addresses the root cause and is covered by a focused regression test.

Review effort: Balanced
Findings: None

What changed in this PR

Fixes nondeterministic external-library classification by propagating reduced node_modules depth through already-started imports.

Changes:

  • Restarts file subtasks whenever their discovered depth decreases.
  • Adds regression coverage for both root-file orderings.
File Description
tsc/​internal/​compiler/​filesparser.go Propagates lowered depth through imports.
tsc/​internal/​compiler/​filesparser_test.go Verifies deterministic classification.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread tsc/internal/compiler/filesparser_test.go Outdated
@jakebailey
Jake Bailey (jakebailey) requested a balanced review from Copilot October 5, 2026 16:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

Review effort: Lite
Findings: None

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The bounded restart logic directly addresses the scheduling-dependent classification and is covered by a focused compiler test.

Review effort: Balanced
Findings: None

@andrewbranch
Andrew Branch (andrewbranch) added this pull request to the merge queue Oct 5, 2026
Merged via the queue into microsoft:main with commit ca197b7 Oct 5, 2026
29 checks passed
@cplieger
Christopher Plieger (cplieger) deleted the fix-64498-external-library-depth branch October 5, 2026 18:07
Christopher Plieger (cplieger) added a commit to cplieger/deadset-ts that referenced this pull request Oct 6, 2026
This compiler nightly restarts a file's imports when a later import
reaches the file at a lower node_modules depth (microsoft/TypeScript#64632,
fixing microsoft/TypeScript#64498). Whether a file comes from an external
library no longer depends on which import the compiler followed first, so
a project on a monorepo layout that is not read as a workspace gets the
same own files, and the same report, on every run.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Milestone Bug PRs that fix a bug with a specific milestone

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Program.emitToString() silently omits real files due to nondeterministic isSourceFileFromExternalLibrary() misclassification

4 participants