feat(analyzer): allOf is honored wherever it appears, not only on named schemas - #117
Merged
Conversation
…ed schemas
allOf is JSON Schema 2020-12 composition, which 3.1 uses, and it is valid
anywhere a schema is. convertSchema composes it for a named component schema
and resolveGoType, which types every inline property, never looked at it, so
a property that composed anything resolved to any.
In a 3.1 spec today:
allOf: [$ref, {inline object}] -> any
allOf: [$ref] -> any
$ref with sibling keywords -> the referenced type
anyOf: [$ref, {type: null}] -> the referenced type
The first two are the inconsistency: the same composition on a named schema
builds a struct. A lone $ref inside an allOf says the value must match that
schema, so it resolves to it; anything more composes a shape of its own and
is named like other inline schemas, keeping both what it embeds and what it
adds.
The two idioms 3.1 offers instead already worked, and now have a test that
keeps them working.
giraffesyo
force-pushed
the
allof-properties
branch
from
August 21, 2026 19:00
4ab14fe to
6333288
Compare
…parts The composition path this PR adds converted its schema as if it were sent as JSON, so a multipart body written as allOf typed its binary properties as byte slices and the encoder sent them as base64 text in ordinary fields, the same failure #90 fixed for a body written as an object. Multipart is a property of where a schema is used, so the composition path consults it the same way the object path does.
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.
Closes #116.
allOfis JSON Schema 2020-12 composition, which 3.1 uses, and it is valid anywhere a schema is.convertSchemacomposes it for a named component schema.resolveGoType, which types every inline property schema, never looked at it, so a property that composed anything resolved toany.Measured on a 3.1 spec, before this change:
allOf: [$ref, {inline object}]anyallOf: [$ref]any$refwith sibling keywords*UseranyOf: [$ref, {type: "null"}]*UserThe first two are the inconsistency: the same composition written as a named schema builds a struct.
What it does
$refinside anallOfsays the value must match that schema, so the property is of that type.allOf: [{$ref: User}, {properties: {verdict}}]gives a struct embeddingUserand addingVerdictrather thanany.On the framing of my first version
I justified this by counting
anyfields in GitHub's client, 53 down to 38, and that was the wrong argument: GitHub is 3.0, where wrapping a$refinallOfis a workaround for sibling keywords being ignored. Of the four specs I have, only that one writes it, and Mealie and ACTIVATE, both 3.1, write it nowhere.The change stands on 3.1 grounds instead:
allOfis part of the schema language 3.1 uses, the generator already honors it for named schemas, and honoring it in one place and not the other is a hole a valid 3.1 spec falls into. The GitHub numbers are incidental corroboration, not the reason.Tests
All specs in them are 3.1.
internal/analyzer/schemas_allof_property_test.go: a lone$refresolves to it with and without sibling keywords, a two-entry composition is named and keeps both halves, a single inline entry composes just as much as several, and a separate test pins the idioms 3.1 offers instead, a$refwith siblings and ananyOfwith a null member, which already worked and now cannot regress.internal/generator/e2e_allof_property_test.go: compiles and runs, reading a composed$refwithout an assertion and checking a JSONnullleaves the pointer nil.gofmt,golangci-lint,go vet ./..., andgo test ./...pass.