Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cmd/oapi-codegen/oapi-codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,17 @@ func main() {
_, _ = fmt.Fprint(os.Stderr, out.String())
}

if warnings := opts.Warnings(); len(warnings) > 0 {
var out strings.Builder
out.WriteString("WARNING: A number of cross-field configuration warning(s) were returned:")
for k, v := range warnings {
out.WriteString("\n- " + k + ": " + v)
}
out.WriteString("\n")

_, _ = fmt.Fprint(os.Stderr, out.String())
}

// If the user asked to output configuration, output it to stdout and exit
if flagOutputConfig {
var buf bytes.Buffer
Expand Down
5 changes: 5 additions & 0 deletions configuration-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,11 @@
"description": "When set to true, automatically renames types that collide across different OpenAPI component sections (schemas, parameters, requestBodies, responses, headers) by appending a suffix based on the component section. Also detects collisions between component types and client response wrapper types. Without this, the codegen will error on duplicate type names, requiring manual resolution via x-go-name.",
"default": false
},
"generate-types-for-anonymous-schemas": {
"type": "boolean",
"description": "When true, every inline schema that would otherwise generate as an anonymous Go struct is instead emitted as a named type with a path-derived name (e.g. `GetRolesIdResponseBody_Data`). Equivalent to adding `x-go-type-name` to every inline schema; when both are present at the same site, `x-go-type-name` wins. Default false. The hoisted named types are declared by the same emission path that `generate.models` controls; in a single-config setup, this flag is only effective when `generate.models: true` is also set in the same config — otherwise the generated client/server code will reference type names that no emission path declares, and `go build` will fail. In a multi-config setup where one config emits `models` and a sibling emits a client or server framework into the same Go package, the flag must be set consistently across all configs; the sibling config that does not emit `models` will produce a codegen-time warning noting that it does not declare the hoisted names, which can be safely ignored when a sibling config will. See https://github.com/oapi-codegen/oapi-codegen/issues/1139",
"default": false
},
"type-mapping": {
"type": "object",
"additionalProperties": false,
Expand Down
7 changes: 7 additions & 0 deletions internal/test/anonymous_inner_hoisting/global/cfg.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package: global
output: client.gen.go
generate:
models: true
client: true
output-options:
generate-types-for-anonymous-schemas: true
Comment thread
mromaszewicz marked this conversation as resolved.
297 changes: 297 additions & 0 deletions internal/test/anonymous_inner_hoisting/global/client.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions internal/test/anonymous_inner_hoisting/global/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package global

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// TestHoistedTypesExist verifies that with output-options.generate-types-for-
// anonymous-schemas enabled, the inline schemas in spec.yaml become named
// Go types we can reference directly. The spec is the canonical issue #1139
// shape: a response body using `allOf` to merge a $ref with sibling
// `properties:` containing an inline `data` object.
func TestHoistedTypesExist(t *testing.T) {
// Both the response root and the nested inline `data` schema should be
// emitted as named types — assigning a typed zero value would not
// compile if either were still anonymous structs.
var responseBody GetRolesId200JSONResponseBody
var dataField GetRolesId200JSONResponseBody_Data

// Field-level type identity: GetRolesId200JSONResponseBody.Data must be
// of the hoisted GetRolesId200JSONResponseBody_Data type. This
// assignment fails to compile if Data is still an anonymous struct.
responseBody.Data = dataField
_ = responseBody
}

func TestHoistedTypesRoundTrip(t *testing.T) {
body := GetRolesId200JSONResponseBody{
Data: GetRolesId200JSONResponseBody_Data{
Role: Role{Id: 7, Name: "admin"},
},
Ok: true,
}

encoded, err := json.Marshal(body)
require.NoError(t, err)

var decoded GetRolesId200JSONResponseBody
require.NoError(t, json.Unmarshal(encoded, &decoded))
assert.Equal(t, body, decoded)
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package anonymous_inner_hoisting
package global

//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=cfg.yaml spec.yaml
Loading