FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Propagate one-sided type and format in allOf merges by mromaszewicz · Pull Request #2526 · oapi-codegen/oapi-codegen · GitHub

Propagate one-sided type and format in allOf merges - #2526

Merged
mromaszewicz merged 1 commit into
oapi-codegen:mainfrom
mromaszewicz:fix/allof-type-format-propagation
Aug 16, 2026
Merged

Propagate one-sided type and format in allOf merges#2526
mromaszewicz merged 1 commit into
oapi-codegen:mainfrom
mromaszewicz:fix/allof-type-format-propagation

Conversation

Copy link
Copy Markdown
Member

Fixes #2524.

Problem

mergeOpenapiSchemas only errored on a type conflict when both members declared a type; otherwise it kept the first member's type, silently discarding the second's. Because allOf members merge pairwise in order, the generated Go shape depended on member ordering (see the issue for the repro — a struct in one order, any in the other).

Format had the mirror-image problem: any mismatch errored, including set-vs-unset, so the allOf decorator idiom over a $ref to a format-carrying scalar failed generation outright:

NullableUuid:
  allOf:
    - $ref: "#/components/schemas/Uuid"   # type: string, format: uuid
    - description: decorated              # no format -> "can not merge incompatible formats"

Fix

Both fields now follow the same one-sidedness rule: when exactly one member declares a type/format, it propagates to the merged schema; when both declare and they differ, the existing errors remain.

Compatibility notes

  • Repo-wide make generate changes no existing committed .gen.go — the entire test corpus is unaffected.
  • The format half is purely additive: specs that previously failed generation now work.
  • The type half changes output only for specs whose allOf mixes a typeless member with a non-object-typed member — output there was order-dependent (and per JSON Schema semantics, wrong: properties doesn't constrain non-object instances, so allOf: [{properties…}, {type: string}] only ever validates strings). Specs hiding two conflicting types behind a typeless member (e.g. [{properties…}, {type: string}, {type: number}]) now hit the existing incompatible-types error instead of silently generating a struct; such specs are unsatisfiable. compatibility.old-merge-schemas routes to the untouched legacy codepath and remains the escape hatch.

Tests

  • Unit tests in merge_schemas_test.go for both propagation rules, order symmetry, and the preserved error cases.
  • Conformance fixtures in internal/test/aggregates/allof/: the issue's repro in both member orders (both lower to any), single-type in both orders (both lower to string), and the format-decorator idiom in both orders (both lower to openapi_types.UUID), pinned by TestIssue2524.

make tidy && make test && make generate && make lint all pass.

🤖 Generated with Claude Code

MergeSchemas only errored on a type conflict when both members declared a
type; otherwise it kept the first member's type, silently discarding the
second's. Because allOf members merge pairwise in order, the generated Go
shape depended on member ordering. Format had the mirror-image problem:
any mismatch errored, including set-vs-unset, which broke the allOf
decorator idiom over refs to format-carrying scalars.

Both now follow the same rule: when exactly one member declares a
type/format it propagates to the merged schema; when both declare and
they differ, the existing errors remain.

Fixes oapi-codegen#2524

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mromaszewicz requested a review from a team as a code owner August 16, 2026 14:53
mromaszewicz added the bug Something isn't working label Aug 16, 2026

greptile-apps Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR makes the current allOf merger propagate a type or format declared by only one member while preserving errors for conflicting declarations.

  • Adds symmetric unit coverage for one-sided type and format propagation.
  • Adds allOf conformance fixtures covering primitive, union, and UUID decorator cases in both member orders.
  • Updates committed generated output to pin the corrected generated Go shapes.

Confidence Score: 5/5

The PR appears safe to merge with no actionable correctness, security, or maintainability issues identified.

The merge logic handles absent declarations symmetrically, retains conflict errors when both members declare incompatible values, preserves the legacy compatibility path, and includes focused unit and generated-output regression coverage.

Important Files Changed

Filename Overview
pkg/codegen/merge_schemas.go Propagates one-sided type and format values during current-path allOf merging while retaining explicit conflict detection.
pkg/codegen/merge_schemas_test.go Adds focused tests for symmetric propagation, unchanged typeless behavior, and preserved type/format conflict errors.
internal/test/aggregates/allof/spec_new_merge.yaml Adds category-appropriate regression schemas for order-independent primitive, union, and format-carrying allOf merges.
internal/test/aggregates/allof/allof_test.go Adds compile-time shape checks for the newly generated aliases.
internal/test/aggregates/allof/allof_new_merge.gen.go Contains the expected generated string, any, and UUID aliases without unrelated generated-code drift.

Reviews (1): Last reviewed commit: "Propagate one-sided type and format in a..." | Re-trigger Greptile

mromaszewicz merged commit 5a6c494 into oapi-codegen:main Aug 16, 2026
15 checks passed
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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MergeSchemas silently drops a member's type when an earlier allOf member has none (order-dependent output)

1 participant


Back | FazBrowse Home | New Git URL