Handle JSON Schema 2020-12 prefixItems tuples#2949
Merged
schani merged 4 commits intoJul 19, 2026
Conversation
JSON Schema draft 2020-12 renamed the array (tuple) form of `items` to `prefixItems`, which is now emitted by Pydantic v2 and Rust's schemars. `makeArrayType()` only read `schema.items`, so a `prefixItems`-based tuple fell through to the generic `any[]` branch and lost its member types; with `--just-types` and a top-level array that produced no output at all. `prefixItems` was also missing from the `needUnion` type-inference predicate. Apply the existing array-form `items` tuple-union logic to `schema.prefixItems` as well, and add `prefixItems` to the type-inference predicate. When `prefixItems` is absent, array handling is unchanged. Adds test/unit/prefix-items-schema.test.ts, which fails before this change and passes after. Fixes glideapps#2811
Two follow-ups to the prefixItems tuple support: - In 2020-12, an object-form `items` next to `prefixItems` describes the rest elements of an open tuple. It was previously dropped; now its type joins the tuple's element union (quicktype models tuples as arrays of a union of the member types). Boolean `items` (`false` closes the tuple, `true` allows anything) is still ignored. - Add `test/inputs/schema/prefix-items.schema` so the feature is covered by the end-to-end fixture tests, mirroring `tuple.schema` but with 2020-12 `prefixItems`, plus an open tuple that also has a rest `items` schema. The `.fail.union.json` sample has a tuple element outside the declared union, so validating languages must reject it — it would be accepted if the tuple degraded to `any[]`, which is exactly the regression this guards against. The unit test keeps only what fixtures cannot express (that `$ref`d member types survive into the generated code) and gains a case for the prefixItems-plus-rest-items union. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The generated cJSON deserializer silently drops array elements whose type is outside the union instead of aborting parsing, so the prefix-items.1.fail.union.json expected-failure sample does not fail. This is the already-documented "Union, Map and Arrays with invalid types are not checked" limitation; add the schema to that skip group. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
schani
force-pushed
the
fix/2811-prefixitems-tuple-schema
branch
from
July 19, 2026 14:28
4c42e72 to
3a00877
Compare
Both test drivers exit 0 on a failed decode (scala3 prints the circe DecodingFailure, haskell encodes the Maybe result as null), so the prefix-items.1.fail.union.json expected-failure sample cannot be detected. Same documented limitation as nested-intersection-union.schema. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Member
|
Thank you so much! |
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.
Description
JSON Schema inputs that describe a tuple with the 2020-12
prefixItemskeyword were silently mishandled: with
--just-typesthe tool emittednothing at all, and via the API the tuple degraded to a bare
any[], droppingevery member type. This teaches the JSON Schema input to treat
prefixItemsthe same way it already treats draft-07's array-valued
items.Related Issue
Fixes #2811
Root cause
In
packages/quicktype-core/src/input/JSONSchemaInput.ts:makeArrayType()only readschema.items. When a schema usedprefixItemsinstead (the 2020-12 rename of the array/tuple form ofitems, now emitted by Pydantic v2 and Rust'sschemars),itemswasundefined, so the code fell through to the genericitemType = anybranch and produced
any[]. With a top-level array and--just-types,any[]needs no named declaration, so the output was empty (exit 0, nointerface).
needUniontype-inference predicate (theschema.items !== undefined || ...chain) did not mentionprefixItems, so a schema whose onlyarray signal was
prefixItems(no explicittype) was not evenrecognized as needing an array/union type.
Fix
makeArrayType()now usesschema.prefixItemsas the tuple source when itis an array, running the exact same per-item union logic already used for
array-valued
items(with aprefixItemslocation for$refresolutionand diagnostics). When
prefixItemsis absent, behaviour is byte-for-byteunchanged.
schema.prefixItems !== undefinedis added to theneedUnionpredicate soa bare
prefixItemsschema is recognized as an array type.This matches the maintainer's directed fix from the triage note on #2811
("apply the existing
Array.isArray(items)tuple-union logic toschema.prefixItemsas well, and add it to the type-inference predicate nearline 1232").
Tests
New unit test
test/unit/prefix-items-schema.test.ts(mirrors the existingwindows-schema-paths.test.tspattern — it drives thequicktype-coreAPIdirectly, which the fixture harness cannot do here because a data round-trip
still accepts an
any[]degradation and would not notice the lost tupletypes):
type: array+prefixItems: [{$ref Bar}, {$ref Baz}]schemanow keeps its member field types (
barField,bazField) in the generatedTypeScript;
itemsschema still works (noregression).
Verification (before / after)
Reproduction schema
foo.schema.json:{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "array", "prefixItems": [{ "$ref": "#/$defs/Bar" }, { "$ref": "#/$defs/Baz" }], "$defs": { "Bar": { "type": "object", "properties": { "x": { "type": "integer" } }, "required": ["x"] }, "Baz": { "type": "object", "properties": { "y": { "type": "string" } }, "required": ["y"] } } }Command:
Before: empty output (exit 0, no interface emitted).
After:
(identical to the output the equivalent draft-07 array-form
itemsschemaalready produced.)
Regression test, before vs after the source change:
Full unit suite:
npx vitest run-> 72 passed (9 files).Lint:
npx biome checkon both changed files -> clean.Compatibility
Backward compatible. When
prefixItemsis not present the array-handlingpath is unchanged, so all existing draft-07
itemsbehaviour is preserved(covered by the existing
tuple.schemafixture and the new regression test'sdraft-07 case). When both
prefixItemsand a restitemsschema are present,prefixItemsdrives the tuple element union — consistent with how theexisting code already ignores
additionalItemsfor array-formitems.AI-authored and AI-reviewed; not yet human-reviewed.