Skip to content

Commit

Permalink
Revert "Support openapiV3 oneOf for fields/responses (swaggo#1671)" (s…
Browse files Browse the repository at this point in the history
…waggo#1699)

This reverts commit 8f63cde.
  • Loading branch information
ubogdan authored Nov 7, 2023
1 parent 8f63cde commit 687052e
Show file tree
Hide file tree
Showing 10 changed files with 64 additions and 302 deletions.
67 changes: 0 additions & 67 deletions field_parser_v3_test.go

Large diffs are not rendered by default.

25 changes: 4 additions & 21 deletions field_parserv3.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,13 @@ func (sf *structFieldV3) setMax(valValue string) {

type tagBaseFieldParserV3 struct {
p *Parser
file *ast.File
field *ast.Field
tag reflect.StructTag
}

func newTagBaseFieldParserV3(p *Parser, file *ast.File, field *ast.Field) FieldParserV3 {
func newTagBaseFieldParserV3(p *Parser, field *ast.Field) FieldParserV3 {
fieldParser := tagBaseFieldParserV3{
p: p,
file: file,
field: field,
tag: "",
}
Expand Down Expand Up @@ -136,10 +134,9 @@ func (ps *tagBaseFieldParserV3) ComplementSchema(schema *spec.RefOrSpec[spec.Sch
if err != nil {
return err
}
if !reflect.ValueOf(newSchema).IsZero() {
newSchema.AllOf = []*spec.RefOrSpec[spec.Schema]{{Spec: schema.Spec}}
*schema = spec.RefOrSpec[spec.Schema]{Spec: &newSchema}
}
// if !reflect.ValueOf(newSchema).IsZero() {
// *schema = *(newSchema.WithAllOf(*schema.Spec))
// }
return nil
}

Expand Down Expand Up @@ -342,19 +339,6 @@ func (ps *tagBaseFieldParserV3) complementSchema(schema *spec.Schema, types []st
}
}

var oneOfSchemas []*spec.RefOrSpec[spec.Schema]
oneOfTagValue := ps.tag.Get(oneOfTag)
if oneOfTagValue != "" {
oneOfTypes := strings.Split((oneOfTagValue), ",")
for _, oneOfType := range oneOfTypes {
oneOfSchema, err := ps.p.getTypeSchemaV3(oneOfType, ps.file, true)
if err != nil {
return fmt.Errorf("can't find oneOf type %q: %v", oneOfType, err)
}
oneOfSchemas = append(oneOfSchemas, oneOfSchema)
}
}

elemSchema := schema

if field.schemaType == ARRAY {
Expand All @@ -378,7 +362,6 @@ func (ps *tagBaseFieldParserV3) complementSchema(schema *spec.Schema, types []st
elemSchema.MinLength = field.minLength
elemSchema.Enum = field.enums
elemSchema.Pattern = field.pattern
elemSchema.OneOf = oneOfSchemas

return nil
}
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.8.2
github.com/sv-tools/openapi v0.2.1
golang.org/x/tools v0.13.0
golang.org/x/tools v0.8.0
sigs.k8s.io/yaml v1.3.0
)

Expand All @@ -30,7 +30,7 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/urfave/cli/v2 v2.25.1
golang.org/x/sys v0.12.0 // indirect
golang.org/x/sys v0.7.0 // indirect
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1 // indirect
)
10 changes: 5 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw=
github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y=
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
1 change: 0 additions & 1 deletion operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,6 @@ const (
extensionsTag = "extensions"
collectionFormatTag = "collectionFormat"
patternTag = "pattern"
oneOfTag = "oneOf"
)

var regexAttributes = map[string]*regexp.Regexp{
Expand Down
128 changes: 49 additions & 79 deletions operationv3.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"go/ast"
"log"
"maps"
"net/http"
"strconv"
"strings"
Expand Down Expand Up @@ -927,15 +926,22 @@ func (o *OperationV3) ParseResponseComment(commentLine string, astFile *ast.File

for _, codeStr := range strings.Split(matches[1], ",") {
if strings.EqualFold(codeStr, defaultTag) {
codeStr = ""
} else {
code, err := strconv.Atoi(codeStr)
if err != nil {
return fmt.Errorf("can not parse response comment \"%s\"", commentLine)
}
if description == "" {
description = http.StatusText(code)
}
response := o.DefaultResponse()
response.Description = description

mimeType := "application/json" // TODO: set correct mimeType
setResponseSchema(response, mimeType, schema)

continue
}

code, err := strconv.Atoi(codeStr)
if err != nil {
return fmt.Errorf("can not parse response comment \"%s\"", commentLine)
}

if description == "" {
description = http.StatusText(code)
}

response := spec.NewResponseSpec()
Expand Down Expand Up @@ -973,12 +979,15 @@ func (o *OperationV3) ParseEmptyResponseComment(commentLine string) error {

for _, codeStr := range strings.Split(matches[1], ",") {
if strings.EqualFold(codeStr, defaultTag) {
codeStr = ""
} else {
_, err := strconv.Atoi(codeStr)
if err != nil {
return fmt.Errorf("can not parse response comment \"%s\"", commentLine)
}
response := o.DefaultResponse()
response.Description = description

continue
}

_, err := strconv.Atoi(codeStr)
if err != nil {
return fmt.Errorf("can not parse response comment \"%s\"", commentLine)
}

o.AddResponse(codeStr, newResponseWithDescription(description))
Expand All @@ -987,10 +996,21 @@ func (o *OperationV3) ParseEmptyResponseComment(commentLine string) error {
return nil
}

// DefaultResponse return the default response member pointer.
func (o *OperationV3) DefaultResponse() *spec.Response {
if o.Responses.Spec.Default == nil {
o.Responses.Spec.Default = spec.NewResponseSpec()
o.Responses.Spec.Default.Spec.Spec.Headers = make(map[string]*spec.RefOrSpec[spec.Extendable[spec.Header]])
}

if o.Responses.Spec.Default.Spec.Spec.Content == nil {
o.Responses.Spec.Default.Spec.Spec.Content = make(map[string]*spec.Extendable[spec.MediaType])
}

return o.Responses.Spec.Default.Spec.Spec
}

// AddResponse add a response for a code.
// If the code is already exist, it will merge with the old one:
// 1. The description will be replaced by the new one if the new one is not empty.
// 2. The content schema will be merged using `oneOf` if the new one is not empty.
func (o *OperationV3) AddResponse(code string, response *spec.RefOrSpec[spec.Extendable[spec.Response]]) {
if response.Spec.Spec.Headers == nil {
response.Spec.Spec.Headers = make(map[string]*spec.RefOrSpec[spec.Extendable[spec.Header]])
Expand All @@ -1000,74 +1020,24 @@ func (o *OperationV3) AddResponse(code string, response *spec.RefOrSpec[spec.Ext
o.Responses.Spec.Response = make(map[string]*spec.RefOrSpec[spec.Extendable[spec.Response]])
}

res := response
var prev *spec.RefOrSpec[spec.Extendable[spec.Response]]
if code != "" {
prev = o.Responses.Spec.Response[code]
} else {
prev = o.Responses.Spec.Default
}
if prev != nil { // merge into prev
res = prev
if response.Spec.Spec.Description != "" {
prev.Spec.Spec.Description = response.Spec.Spec.Description
}
if len(response.Spec.Spec.Content) > 0 {
// responses should only have one content type
singleKey := ""
for k := range response.Spec.Spec.Content {
singleKey = k
break
}
if prevMediaType := prev.Spec.Spec.Content[singleKey]; prevMediaType == nil {
prev.Spec.Spec.Content = response.Spec.Spec.Content
} else {
newMediaType := response.Spec.Spec.Content[singleKey]
if len(newMediaType.Extensions) > 0 {
if prevMediaType.Extensions == nil {
prevMediaType.Extensions = make(map[string]interface{})
}
maps.Copy(prevMediaType.Extensions, newMediaType.Extensions)
}
if len(newMediaType.Spec.Examples) > 0 {
if prevMediaType.Spec.Examples == nil {
prevMediaType.Spec.Examples = make(map[string]*spec.RefOrSpec[spec.Extendable[spec.Example]])
}
maps.Copy(prevMediaType.Spec.Examples, newMediaType.Spec.Examples)
}
if prevSchema := prevMediaType.Spec.Schema; prevSchema.Ref != nil || prevSchema.Spec.OneOf == nil {
oneOfSchema := spec.NewSchemaSpec()
oneOfSchema.Spec.OneOf = []*spec.RefOrSpec[spec.Schema]{prevSchema, newMediaType.Spec.Schema}
prevMediaType.Spec.Schema = oneOfSchema
} else {
prevSchema.Spec.OneOf = append(prevSchema.Spec.OneOf, newMediaType.Spec.Schema)
}
}
}
}

if code != "" {
o.Responses.Spec.Response[code] = res
} else {
o.Responses.Spec.Default = res
}
o.Responses.Spec.Response[code] = response
}

// ParseEmptyResponseOnly parse only comment out status code ,eg: @Success 200.
func (o *OperationV3) ParseEmptyResponseOnly(commentLine string) error {
for _, codeStr := range strings.Split(commentLine, ",") {
var description string
if strings.EqualFold(codeStr, defaultTag) {
codeStr = ""
} else {
code, err := strconv.Atoi(codeStr)
if err != nil {
return fmt.Errorf("can not parse response comment \"%s\"", commentLine)
}
description = http.StatusText(code)
_ = o.DefaultResponse()

continue
}

o.AddResponse(codeStr, newResponseWithDescription(description))
code, err := strconv.Atoi(codeStr)
if err != nil {
return fmt.Errorf("can not parse response comment \"%s\"", commentLine)
}

o.AddResponse(codeStr, newResponseWithDescription(http.StatusText(code)))
}

return nil
Expand Down
6 changes: 3 additions & 3 deletions parserv3.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import (
"github.com/sv-tools/openapi/spec"
)

// FieldParserFactoryV3 create FieldParser.
type FieldParserFactoryV3 func(ps *Parser, file *ast.File, field *ast.Field) FieldParserV3
// FieldParserFactoryV3 func(ps *Parser, field *ast.Field) FieldParserV3 create FieldParser.
type FieldParserFactoryV3 func(ps *Parser, field *ast.Field) FieldParserV3

// FieldParserV3 parse struct field.
type FieldParserV3 interface {
Expand Down Expand Up @@ -903,7 +903,7 @@ func (p *Parser) parseStructFieldV3(file *ast.File, field *ast.Field) (map[strin
}
}

ps := p.fieldParserFactoryV3(p, file, field)
ps := p.fieldParserFactoryV3(p, field)

if ps.ShouldSkip() {
return nil, nil, nil
Expand Down
Loading

0 comments on commit 687052e

Please sign in to comment.