Skip to content

fix(codegen): resolve in-document pointer $refs during type generation - #120

Merged
Patrick Kelly (pk8189) merged 2 commits into
mainfrom
fix/codegen-in-document-recursive-refs
Jul 21, 2026
Merged

fix(codegen): resolve in-document pointer $refs during type generation#120
Patrick Kelly (pk8189) merged 2 commits into
mainfrom
fix/codegen-in-document-recursive-refs

Conversation

@pk8189

@pk8189 Patrick Kelly (pk8189) commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Problem

The v0.3.1 recursion fix (#113) handles $defs-named refs, but not a $ref that is an in-document JSON pointer. A hand-authored schema can express recursion that way — e.g. a query filter whose or/and groups reference the filter itself:

{ "$ref": "#/properties/filter/anyOf/0" }

schema_type::follow resolves a ref by its trailing path segment against the definitions map, so this became #/$defs/0does not existgenerate_types errored. Consumers then relaxed the whole tool's input to any.

Reproduced against such a schema:

Type generation error: Failed following JSON schema reference, `#/$defs/0` does not exist

Fix

A normalization pass — normalize::normalize_in_document_refs, run at the top of generate_types:

  • Collect every $ref that points into the document body (#/…, not #/$defs/ or #/definitions/).
  • Hoist each distinct target into definitions under a generated, collision-resistant name (InlineRef_<path>).
  • Repoint every ref to it at #/definitions/<name>including refs inside the hoisted target, so a self-referential filter becomes a proper named recursive type.
  • Schemas already using $defs/definitions refs (and plain schemas) pass through untouched.

It runs by round-tripping the RootSchema through 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:

export type ListRecordsInput = {
  object: string;
  filter?: …FilterUnion0Obj0 | …Obj1 | …Obj2 | null | undefined;
};
export type …InlineRefPropertiesFilterAnyOf0Obj1 = {
  or: …Obj0 | …Obj1 | …Obj2[];   // recurses
};

Tests

  • normalize.rs unit 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 with object: string preserved and no any.
  • Full pctx_codegen suite green, including the existing insta snapshots (round-trip is non-destructive).

🤖 Generated with Claude Code

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.
@pk8189
Patrick Kelly (pk8189) force-pushed the fix/codegen-in-document-recursive-refs branch from 3dc6c10 to 555ed2b Compare July 19, 2026 17:30
@pk8189 Patrick Kelly (pk8189) changed the title fix(codegen): resolve in-document pointer $refs (recursive Attio filter) fix(codegen): resolve in-document pointer $refs during type generation Jul 19, 2026
@eliasposen

Copy link
Copy Markdown
Contributor

Patrick Kelly (@pk8189) Can you update the changelog?

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pk8189
Patrick Kelly (pk8189) merged commit 123a8b0 into main Jul 21, 2026
8 checks passed
@eliasposen
Elias Posen (eliasposen) deleted the fix/codegen-in-document-recursive-refs branch July 21, 2026 15:19
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.

2 participants