README.MD (3436B)
1 # odin-jsonschema 2 3 Generates Odin type declarations from JSON Schema documents (draft-07 and 4 2020-12). The generated types parse with `core:encoding/json` — no runtime 5 library required. 6 7 ## Usage 8 9 ### CLI 10 11 ```sh 12 make build # -> build/jschema 13 14 build/jschema schema.json -o:types.odin # file to file 15 cat schema.json | build/jschema # stdin to stdout 16 build/jschema schema.json -pkg:api -root:Document 17 ``` 18 19 Flags: 20 21 | flag | meaning | default | 22 |------|---------|---------| 23 | `-o:<path>` | output file | stdout | 24 | `-pkg:<name>` | package name of the generated file | `schema` | 25 | `-root:<name>` | name of the root declaration | `Root` | 26 27 Debug builds (`odin build src/cmd/jschema -debug`) wrap the allocator in 28 `mem.Tracking_Allocator` and report leaks and bad frees on exit. 29 30 ### Library 31 32 ```odin 33 import "src/pkg/jschema" 34 35 err := jschema.generate("schema.json", "types.odin") 36 ``` 37 38 `generate_source` is the in-memory variant used for stdin/pipelines. All 39 intermediate state lives in an internal arena that is freed before returning; 40 the only caller-facing allocation is the returned source string. 41 42 ## Type mapping 43 44 | schema | Odin | 45 |--------|------| 46 | `string` / `integer` / `number` / `boolean` | `string` / `i64` / `f64` / `bool` | 47 | `object` with `properties` (or `allOf`) | named `struct`, merged across `allOf` and `$ref` | 48 | `object` with `additionalProperties` / single-pattern `patternProperties` | `map[string]T` | 49 | `array` | `[]T` | 50 | optional or nullable field | `Maybe(T)` | 51 | `enum` of strings that are valid Odin identifiers | named `enum` (variant names match the JSON strings exactly, as required by `core:encoding/json`) | 52 | `enum` otherwise | `string` | 53 | `oneOf` / `anyOf` | `union {..}` (a `null` variant folds into `Maybe`/nil) | 54 | `type: [..]` with several types | `union {..}` | 55 | no usable constraints | `json.Value` | 56 | `$ref` | named type; local pointers (`#/$defs/..`, `#/definitions/..`) and relative file refs are resolved | 57 58 Recursive schemas work through slices and maps. A schema that contains itself 59 *by value* (illegal in Odin, and `core:encoding/json` cannot unmarshal pointer 60 fields) has the offending property emitted as `json.Value`. 61 62 Known limitations: 63 64 - `core:encoding/json` tries union variants in declaration order and skips 65 unknown object keys, so for `oneOf` of similar objects the first variant 66 that parses wins. 67 - Tuple-form `items` / `prefixItems` degrade to `[]json.Value`. 68 - `$anchor` and remote (URL) refs are not supported; unresolvable refs are an 69 error. 70 71 ## Internals 72 73 The schema is stored data-oriented: one flat pool of fixed-size nodes plus 74 shared side arrays (`props`, `children`, `names`, `strings`), all cross-linked 75 by `u32` indices. Documents are lowered straight from the JSON tokenizer into 76 the pool — no intermediate `json.Value` tree — which preserves declaration 77 order and keeps output deterministic. 78 79 ## Testing 80 81 ```sh 82 make test # unit + golden tests (odin test src/pkg/jschema) 83 make e2e # generate -> compile -> parse sample.json per testdata case 84 make bench # performance report (time, throughput, allocations, leaks) 85 make check # test + e2e 86 ``` 87 88 Each directory under `testdata/cases/` holds a `schema.json`, the expected 89 generated code (`expected.odin`), a `sample.json` instance, and a 90 `check.odin` test that asserts the parsed values. The `openapi` case runs the 91 full OpenAPI 3.2 document schema end-to-end.