Skip to content
Closed
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
18 changes: 18 additions & 0 deletions internal/test/issues/issue-1202/pkg1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
openapi: "3.0.1"
info:
version: 1.0.0
title: Test1
license:
name: MIT
components:
schemas:
TestAllOf:
allOf:
- $ref: "pkg2.yaml#/components/schemas/TestObj2"
- $ref: "#/components/schemas/TestObj1"
TestObj1:
properties:
Field1:
type: string
Field2:
type: string
8 changes: 8 additions & 0 deletions internal/test/issues/issue-1202/pkg1/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package: pkg1
generate:
models: true
output: pkg1.gen.go
output-options:
skip-prune: true
import-mapping:
pkg2.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1202/pkg2
3 changes: 3 additions & 0 deletions internal/test/issues/issue-1202/pkg1/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package pkg1

//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../pkg1.yaml
22 changes: 22 additions & 0 deletions internal/test/issues/issue-1202/pkg1/pkg1.gen.go

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

22 changes: 22 additions & 0 deletions internal/test/issues/issue-1202/pkg2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
openapi: "3.0.1"
info:
version: 1.0.0
title: Test2
license:
name: MIT
components:
schemas:
TestObj2:
properties:
Field3:
type: array
items:
$ref: "#/components/schemas/TestObj3"
Field4:
type: string
TestObj3:
properties:
FieldA:
type: string
FieldB:
type: string
6 changes: 6 additions & 0 deletions internal/test/issues/issue-1202/pkg2/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package: pkg2
generate:
models: true
output: pkg2.gen.go
output-options:
skip-prune: true
3 changes: 3 additions & 0 deletions internal/test/issues/issue-1202/pkg2/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package pkg2

//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../pkg2.yaml
16 changes: 16 additions & 0 deletions internal/test/issues/issue-1202/pkg2/pkg2.gen.go

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

71 changes: 71 additions & 0 deletions pkg/codegen/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"io/fs"
"net/http"
"os"
"reflect"
"runtime/debug"
"sort"
"strings"
Expand Down Expand Up @@ -111,6 +112,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {

filterOperationsByTag(spec, opts)
filterOperationsByOperationID(spec, opts)
fixExternalRefPropagation(spec)
if !opts.OutputOptions.SkipPrune {
pruneUnusedComponents(spec)
}
Expand Down Expand Up @@ -1183,3 +1185,72 @@ func GetParametersImports(params map[string]*openapi3.ParameterRef) (map[string]
func SetGlobalStateSpec(spec *openapi3.T) {
globalState.spec = spec
}

func fixExternalRefPropagation(doc *openapi3.T) {
visited := make(map[interface{}]struct{})
fixExternalRefPropagationCore(reflect.ValueOf(doc), visited, "")
}

func fixExternalRefPropagationCore(vObj reflect.Value, visited map[interface{}]struct{}, curUri string) {
if !vObj.IsValid() {
return
}

switch vObj.Kind() {
case reflect.Pointer:
if !vObj.IsNil() && vObj.Elem().Kind() == reflect.Struct && vObj.CanInterface() {
iObj := vObj.Interface()
if _, exist := visited[iObj]; exist {
return
}
visited[iObj] = struct{}{}
}
fallthrough
case reflect.Interface:
fixExternalRefPropagationCore(vObj.Elem(), visited, curUri)
case reflect.Map:
iter := vObj.MapRange()
for iter.Next() {
fixExternalRefPropagationCore(iter.Value(), visited, curUri)
}
case reflect.Slice:
for i := 0; i < vObj.Len(); i++ {
fixExternalRefPropagationCore(vObj.Index(i), visited, curUri)
}
case reflect.Struct:
vRef := vObj.FieldByName("Ref")
vValue := vObj.FieldByName("Value")
if vRef.IsValid() && (vValue.IsValid() || vObj.Type() == reflect.TypeOf(openapi3.PathItem{})) {
ref := vRef.String()
if ref != "" {
split := strings.SplitN(ref, "#", 2)
if len(split) == 2 {
if split[0] != "" {
curUri = split[0]
} else {
vRef.SetString(curUri + "#" + split[1])
}
} else {
curUri = split[0]
}
}
}
if vObj.Type() == reflect.TypeOf(openapi3.Paths{}) {
for _, r := range vObj.Addr().Interface().(*openapi3.Paths).Map() {
fixExternalRefPropagationCore(reflect.ValueOf(r), visited, curUri)
}
} else if vObj.Type() == reflect.TypeOf(openapi3.Responses{}) {
for _, r := range vObj.Addr().Interface().(*openapi3.Responses).Map() {
fixExternalRefPropagationCore(reflect.ValueOf(r), visited, curUri)
}
} else if vObj.Type() == reflect.TypeOf(openapi3.Callback{}) {
for _, r := range vObj.Addr().Interface().(*openapi3.Callback).Map() {
fixExternalRefPropagationCore(reflect.ValueOf(r), visited, curUri)
}
} else {
for i := 0; i < vObj.NumField(); i++ {
fixExternalRefPropagationCore(vObj.Field(i), visited, curUri)
}
}
}
}