docs(typedef): add $ref normalization step for TypeBox interop

TypeBox generates bare-name $ref values ("$ref": "Read") within
$defs blocks. The jsonschema crate requires full JSON Pointer paths
("$ref": "#/$defs/Read"). Verified by generating actual TypeBox
output and testing against jsonschema v0.46.5 — bare-name refs fail
with 'Resource is not present in a registry'.

Add a ~20-line normalize_refs() pre-processing step that rewrites
bare-name refs to full JSON Pointer paths at schema load time. The
normalization is idempotent — full paths pass through unchanged.
This commit is contained in:
deepseek-v4-pro committed 2026-07-20 12:27:52 +00:00
1 parent 85c5590001
commit a941d86c3a
1 file changed
+32 -6
@@ -175,8 +175,8 @@ validator implementations.
This is the same pattern as TypeBox's `TypeRegistry.Set` on the JS side.
Same semantics, different language, same JSON Schema wire format. A
TypeBox schema serialized to JSON feeds directly into
`jsonschema::validator_for(&schema)` on the Rust side — zero translation.
TypeBox schema serialized to JSON feeds into the typedef engine after a
single pre-processing step: normalizing `$ref` values (see below).
## TypeBox Interop
@@ -192,10 +192,36 @@ const TensorRef = Type.Object({
```
serialized to JSON is a standard JSON Schema with `type: "object"`,
`properties`, and `required`. That JSON feeds directly into the typedef
engine. The `TypeDef:*` custom keywords are added by TypeBox's
`TypeRegistry.Set` — they appear in the serialized JSON as additional
properties on the schema object.
`properties`, and `required`. That JSON feeds into the typedef engine
after `$ref` normalization. The `TypeDef:*` custom keywords are added by
TypeBox's `TypeRegistry.Set` — they appear in the serialized JSON as
additional properties on the schema object.
### `$ref` normalization
TypeBox generates bare-name `$ref` values (e.g., `"$ref": "Read"`),
referencing sibling definitions within the same `$defs` block. The
`jsonschema` crate requires full JSON Pointer paths (e.g.,
`"$ref": "#/$defs/Read"`). The typedef engine normalizes TypeBox-style
refs at schema load time:
```rust
fn normalize_refs(schema: &mut Value) {
// Walk the schema tree. For every "$ref" whose value is a bare name
// (no "#" prefix), rewrite it to "#/$defs/<name>".
// "$ref": "Read" → "$ref": "#/$defs/Read"
}
```
This is a ~20-line recursive walk of the schema JSON. It runs once at
load time, before the schema is passed to `jsonschema::validator_for`
or the offset computation. The normalization is idempotent — full JSON
Pointer refs pass through unchanged.
**Verification:** The jsonschema crate (v0.46.5) rejects bare-name refs
with `Resource 'Read' is not present in a registry`. Full JSON Pointer
refs (`#/$defs/Read`) resolve correctly. The normalization step bridges
the gap between TypeBox's output and jsonschema's input.
The typedef engine does not depend on TypeBox or any JS toolchain. It
consumes JSON — whether that JSON was authored in TypeBox, generated by