Repository navigation
fix(downgrader): keep a $ref beside only annotations bare in a tagged union in 3.0 - #150
Merged
Merged
Conversation
… union in 3.0
A `oneOf` or `anyOf` branch that is a `$ref` beside a `description`, `title` or other annotation became `{ description, allOf: [{ $ref }] }` in 3.0, as every `$ref` with siblings does. Beside a `discriminator`, OpenAPI 3.0 maps values only to the `$ref`s among the branches, not to inline schemas, so the discriminator stopped describing the union, and oapi-codegen 2.8.1 stopped with "ambiguous discriminator.mapping" on the Anthropic and ElevenLabs API documents. Such a branch now stays the bare `$ref`, whose siblings 3.0 ignores, when the discriminator stays. Every other `$ref` with siblings keeps the `allOf`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VVaw7PJZWFiNWco7tWuntN
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
ℹ️ No critical issues — one minor suggestion inline.
Reviewed changes
- Tagged-union branch conversion — new
convertBranches/convertTaggedBranchwrite a branch that is a$refbeside only annotations, in aoneOf/anyOfbeside a retaineddiscriminator, as the bare$refrather than{ allOf: [{ $ref }] }, so 3.0's discriminator maps it again (OAS: "inline schemas will not be considered"). Verified the premise against the 3.1.0 spec. keepsDiscriminatorextraction — the$defsdiscriminator-removal check is shared between theanyOf/oneOffield converters andfinishSchema; the refactor is logically identical to the previous inline condition (out.discriminator !== undefinedimpliesschema.discriminator !== undefined, so the delete condition reduces to the same expression).- Tests + README — covers
oneOf/anyOf, the no-discriminator wrap, and the$defs-removed case; README row and Kiota bullet updated to match.
Local verification: vitest run passes 286/286, uncheck (oxlint/oxfmt/tsc) clean on the changed files, snapshots unchanged. The only observation is the input-key-based annotation check below — non-blocking.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
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.

Requested by dinwwwh · project thread
Problem
Real 3.1 documents give each branch of a tagged union its own description:
{ "oneOf": [ { "$ref": "#/components/schemas/RequestTextBlock", "description": "Regular text content." }, { "$ref": "#/components/schemas/RequestImageBlock", "description": "Image content ..." } ], "discriminator": { "propertyName": "type", "mapping": { "text": "#/components/schemas/RequestTextBlock", "image": "#/components/schemas/RequestImageBlock" } } }A
$refwith siblings becomes{ description, allOf: [{ $ref }] }in 3.0, so every branch turned into an inline schema. OpenAPI 3.0.4 says that beside adiscriminator"all possible schemas MUST be listed explicitly", and that "inlineoneOforanyOfsubschemas are not considered" for the mapping. Validation was unchanged, but the discriminator stopped describing the union. oapi-codegen 2.8.1 generates from 3.1 but stops on our 3.0 withambiguous discriminator.mapping: please replace inlined object with $reffor the Anthropic and ElevenLabs API documents.Fix
In a
oneOforanyOfbeside adiscriminatorthat stays in 3.0, a branch that is a$refbeside only annotations (description,title,deprecated,default,example,readOnly,writeOnly,externalDocs,xml,x-*) is written as the bare$ref. 3.0 ignores the siblings of a$refanyway. Every other$refwith siblings keeps theallOfwrapper, including a branch with a non-annotation sibling such astype, and branches beside a discriminator that is removed because a branch points into$defs(Pydantic, msgspec), so they keep their descriptions there.The existing
$defsdiscriminator check moves intokeepsDiscriminator, which theoneOf/anyOffields andfinishSchemashare.README: the "A
$refwith siblings" row says so, and the Kiota bullet from #145 now leaves out the branches this keeps bare, which Kiota reads fine.Checks
@seriousme/openapi-schema-validator) are identical to main's for all three.pnpm run checkclean, 286 tests pass, coverage 100%, snapshots unchanged.Generated by Claude Code