Skip to content

Fix recursive type dependency collection issue#195

Merged
branchseer merged 3 commits intomainfrom
claude/fix-recursive-dependencies-e6gFO
Mar 4, 2026
Merged

Fix recursive type dependency collection issue#195
branchseer merged 3 commits intomainfrom
claude/fix-recursive-dependencies-e6gFO

Conversation

@branchseer
Copy link
Copy Markdown
Member

@branchseer branchseer commented Mar 4, 2026

Summary

  • The DeclCollector in generate_ts_definition only called visit_dependencies on UserRunConfig, which per the ts_rs API only visits direct type dependencies. Any type referenced indirectly through a chain of dependencies (e.g. a type nested inside a flattened struct) would appear in the generated TypeScript output but never be declared as its own type.
  • Fix the collector to recursively call T::visit_dependencies(self) for each visited type, using a HashSet<TypeId> to prevent infinite loops from circular references.
  • Add an auto-generated header comment to run-config.ts to make it clear the file should not be edited manually.

Why this matters

The bug is latent today because all indirect types happen to be #[serde(flatten)]-ed, which causes ts_rs to inline their fields rather than emit separate type declarations. But as soon as a non-flattened custom type is added at depth > 1 (e.g. a struct referenced by EnabledCacheConfig), the generated TypeScript would reference that type by name without ever declaring it — producing invalid TypeScript. The recursive fix future-proofs the collector so any new nested types are automatically included. The new UserGlobalCacheConfig type (added on main) is now correctly emitted thanks to this fix.

Test plan

  • cargo test -p vite_task_graph — all 14 tests pass
  • cargo check — full project compiles cleanly
  • Generated run-config.ts includes header and all types

https://claude.ai/code/session_01VQvSgXNnYL8tNWydvtbCvg

claude added 3 commits March 4, 2026 16:01
The DeclCollector in generate_ts_definition only called
visit_dependencies on UserRunConfig, collecting direct dependencies
but missing indirect ones. This meant any type referenced through
a chain of dependencies (e.g. a type used by EnabledCacheConfig,
which is flattened into UserTaskConfig) would be referenced in the
generated TypeScript but never declared.

Fix the collector to recursively visit each type's dependencies,
using a HashSet<TypeId> to prevent infinite loops from circular
references.

Also add CacheOutputs as an indirect type (referenced through the
flatten chain) that confirms the fix works — it's now properly
declared in the generated run-config.ts.

https://claude.ai/code/session_01VQvSgXNnYL8tNWydvtbCvg
Remove the CacheOutputs indirect type that was added to demonstrate
the bug. The recursive DeclCollector fix is retained.

https://claude.ai/code/session_01VQvSgXNnYL8tNWydvtbCvg
@branchseer branchseer merged commit d2b8f83 into main Mar 4, 2026
6 checks passed
@branchseer branchseer deleted the claude/fix-recursive-dependencies-e6gFO branch March 4, 2026 17:58
branchseer added a commit that referenced this pull request Mar 5, 2026
## Summary

- The `DeclCollector` in `generate_ts_definition` only called
`visit_dependencies` on `UserRunConfig`, which per the `ts_rs` API only
visits **direct** type dependencies. Any type referenced indirectly
through a chain of dependencies (e.g. a type nested inside a flattened
struct) would appear in the generated TypeScript output but never be
declared as its own type.
- Fix the collector to recursively call `T::visit_dependencies(self)`
for each visited type, using a `HashSet<TypeId>` to prevent infinite
loops from circular references.
- Add an auto-generated header comment to `run-config.ts` to make it
clear the file should not be edited manually.

### Why this matters

The bug is latent today because all indirect types happen to be
`#[serde(flatten)]`-ed, which causes `ts_rs` to inline their fields
rather than emit separate type declarations. But as soon as a
non-flattened custom type is added at depth > 1 (e.g. a struct
referenced by `EnabledCacheConfig`), the generated TypeScript would
reference that type by name without ever declaring it — producing
invalid TypeScript. The recursive fix future-proofs the collector so any
new nested types are automatically included. The new
`UserGlobalCacheConfig` type (added on `main`) is now correctly emitted
thanks to this fix.

## Test plan
- [x] `cargo test -p vite_task_graph` — all 14 tests pass
- [x] `cargo check` — full project compiles cleanly
- [x] Generated `run-config.ts` includes header and all types

https://claude.ai/code/session_01VQvSgXNnYL8tNWydvtbCvg

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants