Skip to content

experimental: merge allOf member extensions before type generation#22

Merged
mromaszewicz merged 1 commit intomainfrom
issue1957
Feb 14, 2026
Merged

experimental: merge allOf member extensions before type generation#22
mromaszewicz merged 1 commit intomainfrom
issue1957

Conversation

@mromaszewicz
Copy link
Member

Refactor allOf type generation to merge extensions from all allOf members into a composite before deciding what code to generate, mirroring V2's MergeSchemas approach. This was surfaced by the issue 1957 test, which uses the standard OpenAPI 3.0 pattern of combining a $ref with extension-only allOf members:

id:
  allOf:
    - $ref: '#/components/schemas/ID'        # has x-go-type
    - x-go-type-skip-optional-pointer: true   # extension-only

Previously, V3 preserved the allOf structure as-is, so generateAllOfType() only collected struct fields from each member. When a $ref target was a type-override alias (no struct properties), there were no fields to collect, producing an empty struct. Extensions on allOf members were also never propagated to the parent field.

The fix adds three pieces:

  • mergeExtensions(dst, src) in extension.go: field-by-field merge helper for the Extensions struct (later values win).

  • mergeAllOfExtensions() + hasAnyFields() in codegen.go: iterates allOf member descriptors, resolves $ref targets from the schema index, and merges all extensions. generateAllOfType() now calls this at the top and, when the composite has no struct fields but carries a TypeOverride, emits a type alias instead of an empty struct.

  • GenerateStructFields() in typegen.go: when a property is itself an allOf, merges extensions from its allOf members into the property's extensions, so x-go-type-skip-optional-pointer propagates to the field declaration in the parent struct.

Refactor allOf type generation to merge extensions from all allOf members
into a composite before deciding what code to generate, mirroring V2's
MergeSchemas approach. This was surfaced by the issue 1957 test, which
uses the standard OpenAPI 3.0 pattern of combining a $ref with
extension-only allOf members:

    id:
      allOf:
        - $ref: '#/components/schemas/ID'        # has x-go-type
        - x-go-type-skip-optional-pointer: true   # extension-only

Previously, V3 preserved the allOf structure as-is, so
generateAllOfType() only collected struct fields from each member. When a
$ref target was a type-override alias (no struct properties), there were
no fields to collect, producing an empty struct. Extensions on allOf
members were also never propagated to the parent field.

The fix adds three pieces:

- mergeExtensions(dst, src) in extension.go: field-by-field merge helper
  for the Extensions struct (later values win).

- mergeAllOfExtensions() + hasAnyFields() in codegen.go: iterates allOf
  member descriptors, resolves $ref targets from the schema index, and
  merges all extensions. generateAllOfType() now calls this at the top
  and, when the composite has no struct fields but carries a TypeOverride,
  emits a type alias instead of an empty struct.

- GenerateStructFields() in typegen.go: when a property is itself an
  allOf, merges extensions from its allOf members into the property's
  extensions, so x-go-type-skip-optional-pointer propagates to the
  field declaration in the parent struct.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mromaszewicz mromaszewicz merged commit bb4e2af into main Feb 14, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant