fix(codegen): resolve in-document pointer $refs during type generation - #120
Merged
Patrick Kelly (pk8189) merged 2 commits intoJul 21, 2026
Merged
Conversation
The recursion fix in v0.3.1 handles `$defs`-named recursive refs, but not a `$ref` that is an in-document JSON pointer — e.g. a recursive query filter whose `and`/`or` groups reference the filter itself via `#/properties/filter/anyOf/0`. `schema_type::follow` resolves a ref by its trailing segment against the definitions map, so that pointer became `#/$defs/0` → "does not exist" → type generation errored, and consumers dropped the whole tool's input type to `any`. Add a normalization pass (`normalize::normalize_in_document_refs`) run at the top of `generate_types`: each distinct in-document pointer target is hoisted into `definitions` under a generated name, and every ref to it — including refs inside the hoisted target, so a self-referential filter becomes a proper named recursive type — is repointed at `#/definitions/<name>`. Schemas that already use `$defs`/`definitions` refs pass through untouched (verified against the existing snapshots). Such a filter schema now generates a recursive TypeScript union instead of erroring; regression test added.
Patrick Kelly (pk8189)
force-pushed
the
fix/codegen-in-document-recursive-refs
branch
from
July 19, 2026 17:30
3dc6c10 to
555ed2b
Compare
Contributor
|
Patrick Kelly (@pk8189) Can you update the changelog? |
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Elias Posen (eliasposen)
deleted the
fix/codegen-in-document-recursive-refs
branch
July 21, 2026 15:19
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.
Problem
The v0.3.1 recursion fix (#113) handles
$defs-named refs, but not a$refthat is an in-document JSON pointer. A hand-authored schema can express recursion that way — e.g. a query filter whoseor/andgroups reference the filter itself:{ "$ref": "#/properties/filter/anyOf/0" }schema_type::followresolves a ref by its trailing path segment against the definitions map, so this became#/$defs/0→does not exist→generate_typeserrored. Consumers then relaxed the whole tool's input toany.Reproduced against such a schema:
Fix
A normalization pass —
normalize::normalize_in_document_refs, run at the top ofgenerate_types:$refthat points into the document body (#/…, not#/$defs/or#/definitions/).definitionsunder a generated, collision-resistant name (InlineRef_<path>).#/definitions/<name>— including refs inside the hoisted target, so a self-referential filter becomes a proper named recursive type.$defs/definitionsrefs (and plain schemas) pass through untouched.It runs by round-tripping the
RootSchemathrough JSON (pointer resolution needs the standard document where#/properties/…is meaningful); schemas are one tool's input, so cost is negligible and paid once at registration.Result
Such a filter schema now generates a recursive union instead of erroring:
Tests
normalize.rsunit tests: hoists the self-ref + rewrites the ref inside the hoisted def; leaves named-ref and plain schemas untouched.tests/in_document_recursive_refs.rs: a recursive in-document filter ref now generates real recursive types withobject: stringpreserved and noany.pctx_codegensuite green, including the existing insta snapshots (round-trip is non-destructive).🤖 Generated with Claude Code