Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
00272ba
fix(downgrader): drop a 3.2 discriminator that has a defaultMapping
claude Nov 2, 2026
b47582b
fix(downgrader): drop extensions in a discriminator, which 3.0 allows…
claude Nov 2, 2026
45b0b18
Merge remote-tracking branch 'origin/claude/project-thread-ttohne' in…
claude Nov 2, 2026
03b2efc
Merge remote-tracking branch 'origin/claude/project-thread-ttohne' in…
claude Nov 2, 2026
83019e9
docs(downgrader): note datamodel-code-generator makes a one-value enu…
claude Nov 2, 2026
31b2ec5
docs(downgrader): name the datamodel-code-generator flag that keeps t…
claude Nov 2, 2026
e0a7297
Merge remote-tracking branch 'origin/claude/project-thread-ttohne' in…
claude Nov 2, 2026
d5fe028
docs(downgrader): note Hey API's Zod and Valibot plugins pin a one-va…
claude Nov 2, 2026
aea5d19
Merge remote-tracking branch 'origin/claude/project-thread-ttohne' in…
claude Nov 2, 2026
2e60837
docs(downgrader): note validators that reject 1.0 for an integer unde…
claude Nov 2, 2026
29f1249
merge
claude Nov 2, 2026
2a72f89
docs(downgrader): note Hey API drops a bare object anyOf branch besid…
claude Nov 2, 2026
7d6094d
Merge remote-tracking branch 'origin/claude/project-thread-ttohne' in…
claude Nov 3, 2026
8ed8ba0
fix(downgrader): keep a $ref to a component named items or additional…
claude Nov 3, 2026
97a7fdb
Merge remote-tracking branch 'origin/claude/project-thread-ttohne' in…
claude Nov 4, 2026
ab51d02
fix(downgrader): read a bare null in a type list as "null"
claude Nov 4, 2026
8a87557
test(downgrader): cover a type list with both null and "null"
claude Nov 4, 2026
46529a0
test(downgrader): pin a lone bare null type list to the "null" output
claude Nov 4, 2026
34f539e
fix(downgrader): replace a $ref into a key that becomes an extension
claude Nov 4, 2026
b85e02a
Merge remote-tracking branch 'origin/claude/project-thread-ttohne' in…
claude Nov 4, 2026
4da1921
test(downgrader): pin the discriminator drop over grouped-schema bran…
claude Nov 4, 2026
2542f8d
fix(downgrader): replace a $ref into a schema root's key that becomes…
claude Nov 5, 2026
3745909
Merge remote-tracking branch 'origin/claude/project-thread-ttohne' in…
claude Nov 5, 2026
ffcbb96
docs(downgrader): name a converted schema's root in the draft-07 limi…
claude Nov 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/downgrader/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ Accepts the default OAS dialect, which adds `discriminator`, `xml`, `externalDoc
| [`unevaluatedProperties`][js-unevaluated-properties] | `additionalProperties`, when nothing beside it but `properties` evaluates properties. Otherwise removed. |
| An array without `items`, or an empty `required` | `items: {}`, which 3.0 requires, and no `required`, which 3.0 requires to be non-empty. |
| An empty [`enum`][js-enum], which 3.0 forbids | `allOf: [{ not: {} }]`, which also rejects every value. |
| Keywords that 3.0 does not define | `x-` extensions of the same name, since the 3.0 Schema Object allows no others. An existing extension of that name wins. A `$ref` into one right under a component schema, as NocoDB writes for schemas grouped under one name, is replaced by its converted target. |
| Keywords that 3.0 does not define | `x-` extensions of the same name, since the 3.0 Schema Object allows no others. An existing extension of that name wins. A `$ref` into one right under a component schema or a converted schema's root, as NocoDB writes for schemas grouped under one name, is replaced by its converted target. |
Comment thread
dinwwwh marked this conversation as resolved.
Resolved
| [`nullable`][3.0-schema-nullable], a 3.0 keyword | Kept beside a single `type`, where it means in 3.0 what its author meant, and the schema counts as having lost a restriction. Removed otherwise, so a `$ref` beside it, as aide writes one, gets no `allOf`. |
| A boolean `exclusiveMinimum` or `exclusiveMaximum`, the 3.0 form, as NestJS writes in 3.1 | Kept beside a numeric `minimum` or `maximum`, where it means in 3.0 what its author meant. Removed otherwise. |
| [`readOnly`][3.0-schema-read-only] or [`writeOnly`][3.0-schema-write-only] | Kept. 3.0 requires such a property in responses or in requests only, where 3.1 requires it everywhere, so the schema counts as having lost a restriction, and the property tells no `oneOf` branch apart. |
Expand Down Expand Up @@ -268,7 +268,7 @@ Accepts the default OAS dialect, which adds `discriminator`, `xml`, `externalDoc
- `$ref`s into a keyword 3.0 removes, such as `prefixItems/0` or `propertyNames`, into a `oneOf` that becomes `anyOf`, into a `not` removed over a schema that lost a restriction, into an `anyOf` removed for a branch that holds only `contentMediaType`, or into the `items` or `properties` of a schema whose `type` list names more than one type besides `"null"`, which move into the branches of the `anyOf` or `oneOf` that takes the place of the list, are left as written and dangle. A `$ref` into the `allOf` of a schema that also holds a `$ref` resolves one member off, since that `$ref` becomes the first member of the `allOf`.
- Recursion through `$defs` is cut to `{}` after one level. Where several `$ref`s enter the same cycle, the first copy made is reused, so a later one can be cut sooner. Such a cut `$ref` tells no `oneOf` branch apart, and counts as taking null, wherever its copy is reused.
- Each `$ref` into `$defs` or an extension repeats its target once serialized, so definitions that reference each other in many layers make a large document, or one too large to serialize: SchemaStore's Kestra flow schema, 4 MB as compact JSON, would serialize to about 84 TB. In a document, move such definitions to `components/schemas`, where `$ref`s stay as written.
- Older drafts are not supported. `definitions` is read as `$defs`, but other keywords that only draft-07 or 2019-09 define, such as `dependencies` and `additionalItems`, become extensions unconverted, so `$ref`s into them dangle, except right under a component schema, and array-form `items` passes through. Convert such schemas to 2020-12 first. oRPC 1.x's Valibot converter writes draft-07 unless it is given `{ target: 'draft-2020-12' }`. The Rust crate aide writes draft-07 through schemars in its 3.1 documents, so a Rust tuple or tuple enum variant becomes array-form `items`, unless `aide::generate::in_context` sets its schema generator to `SchemaSettings::draft2020_12()`, with `definitions_path` kept at `#/components/schemas/`. TypeBox, up to 1.4, also writes `Type.Tuple` as array-form `items`, as Elysia's OpenAPI plugin does in its 3.1 documents.
- Older drafts are not supported. `definitions` is read as `$defs`, but other keywords that only draft-07 or 2019-09 define, such as `dependencies` and `additionalItems`, become extensions unconverted, so `$ref`s into them dangle, except right under a component schema or a converted schema's root, and array-form `items` passes through. Convert such schemas to 2020-12 first. oRPC 1.x's Valibot converter writes draft-07 unless it is given `{ target: 'draft-2020-12' }`. The Rust crate aide writes draft-07 through schemars in its 3.1 documents, so a Rust tuple or tuple enum variant becomes array-form `items`, unless `aide::generate::in_context` sets its schema generator to `SchemaSettings::draft2020_12()`, with `definitions_path` kept at `#/components/schemas/`. TypeBox, up to 1.4, also writes `Type.Tuple` as array-form `items`, as Elysia's OpenAPI plugin does in its 3.1 documents.
- `patternProperties` that matches every name, as TypeBox emits for a record, gives `additionalProperties: true`, so its value schema is lost.
- A record keyed by a union of literals, which Zod and Valibot write as an `anyOf` of `const` branches in `propertyNames`, loses its key names, so 3.0 allows any key. Key it by an enum instead, such as `z.enum` or `v.picklist`.
- A record keyed by an enum repeats its value schema for each name once serialized, so a large enum, or such records nested in each other, make a large document: three levels of 20 names repeat the innermost schema 8,000 times. Register the value schema, as with Zod's `.meta({ id })`, so each name repeats only a `$ref`.
Expand Down
Loading
Loading