55 "fmt"
66 "go/ast"
77 "log"
8+ "maps"
89 "net/http"
910 "strconv"
1011 "strings"
@@ -926,22 +927,15 @@ func (o *OperationV3) ParseResponseComment(commentLine string, astFile *ast.File
926927
927928 for _ , codeStr := range strings .Split (matches [1 ], "," ) {
928929 if strings .EqualFold (codeStr , defaultTag ) {
929- response := o .DefaultResponse ()
930- response .Description = description
931-
932- mimeType := "application/json" // TODO: set correct mimeType
933- setResponseSchema (response , mimeType , schema )
934-
935- continue
936- }
937-
938- code , err := strconv .Atoi (codeStr )
939- if err != nil {
940- return fmt .Errorf ("can not parse response comment \" %s\" " , commentLine )
941- }
942-
943- if description == "" {
944- description = http .StatusText (code )
930+ codeStr = ""
931+ } else {
932+ code , err := strconv .Atoi (codeStr )
933+ if err != nil {
934+ return fmt .Errorf ("can not parse response comment \" %s\" " , commentLine )
935+ }
936+ if description == "" {
937+ description = http .StatusText (code )
938+ }
945939 }
946940
947941 response := spec .NewResponseSpec ()
@@ -979,15 +973,12 @@ func (o *OperationV3) ParseEmptyResponseComment(commentLine string) error {
979973
980974 for _ , codeStr := range strings .Split (matches [1 ], "," ) {
981975 if strings .EqualFold (codeStr , defaultTag ) {
982- response := o .DefaultResponse ()
983- response .Description = description
984-
985- continue
986- }
987-
988- _ , err := strconv .Atoi (codeStr )
989- if err != nil {
990- return fmt .Errorf ("can not parse response comment \" %s\" " , commentLine )
976+ codeStr = ""
977+ } else {
978+ _ , err := strconv .Atoi (codeStr )
979+ if err != nil {
980+ return fmt .Errorf ("can not parse response comment \" %s\" " , commentLine )
981+ }
991982 }
992983
993984 o .AddResponse (codeStr , newResponseWithDescription (description ))
@@ -996,21 +987,10 @@ func (o *OperationV3) ParseEmptyResponseComment(commentLine string) error {
996987 return nil
997988}
998989
999- // DefaultResponse return the default response member pointer.
1000- func (o * OperationV3 ) DefaultResponse () * spec.Response {
1001- if o .Responses .Spec .Default == nil {
1002- o .Responses .Spec .Default = spec .NewResponseSpec ()
1003- o .Responses .Spec .Default .Spec .Spec .Headers = make (map [string ]* spec.RefOrSpec [spec.Extendable [spec.Header ]])
1004- }
1005-
1006- if o .Responses .Spec .Default .Spec .Spec .Content == nil {
1007- o .Responses .Spec .Default .Spec .Spec .Content = make (map [string ]* spec.Extendable [spec.MediaType ])
1008- }
1009-
1010- return o .Responses .Spec .Default .Spec .Spec
1011- }
1012-
1013990// AddResponse add a response for a code.
991+ // If the code is already exist, it will merge with the old one:
992+ // 1. The description will be replaced by the new one if the new one is not empty.
993+ // 2. The content schema will be merged using `oneOf` if the new one is not empty.
1014994func (o * OperationV3 ) AddResponse (code string , response * spec.RefOrSpec [spec.Extendable [spec.Response ]]) {
1015995 if response .Spec .Spec .Headers == nil {
1016996 response .Spec .Spec .Headers = make (map [string ]* spec.RefOrSpec [spec.Extendable [spec.Header ]])
@@ -1020,24 +1000,74 @@ func (o *OperationV3) AddResponse(code string, response *spec.RefOrSpec[spec.Ext
10201000 o .Responses .Spec .Response = make (map [string ]* spec.RefOrSpec [spec.Extendable [spec.Response ]])
10211001 }
10221002
1023- o .Responses .Spec .Response [code ] = response
1003+ res := response
1004+ var prev * spec.RefOrSpec [spec.Extendable [spec.Response ]]
1005+ if code != "" {
1006+ prev = o .Responses .Spec .Response [code ]
1007+ } else {
1008+ prev = o .Responses .Spec .Default
1009+ }
1010+ if prev != nil { // merge into prev
1011+ res = prev
1012+ if response .Spec .Spec .Description != "" {
1013+ prev .Spec .Spec .Description = response .Spec .Spec .Description
1014+ }
1015+ if len (response .Spec .Spec .Content ) > 0 {
1016+ // responses should only have one content type
1017+ singleKey := ""
1018+ for k := range response .Spec .Spec .Content {
1019+ singleKey = k
1020+ break
1021+ }
1022+ if prevMediaType := prev .Spec .Spec .Content [singleKey ]; prevMediaType == nil {
1023+ prev .Spec .Spec .Content = response .Spec .Spec .Content
1024+ } else {
1025+ newMediaType := response .Spec .Spec .Content [singleKey ]
1026+ if len (newMediaType .Extensions ) > 0 {
1027+ if prevMediaType .Extensions == nil {
1028+ prevMediaType .Extensions = make (map [string ]interface {})
1029+ }
1030+ maps .Copy (prevMediaType .Extensions , newMediaType .Extensions )
1031+ }
1032+ if len (newMediaType .Spec .Examples ) > 0 {
1033+ if prevMediaType .Spec .Examples == nil {
1034+ prevMediaType .Spec .Examples = make (map [string ]* spec.RefOrSpec [spec.Extendable [spec.Example ]])
1035+ }
1036+ maps .Copy (prevMediaType .Spec .Examples , newMediaType .Spec .Examples )
1037+ }
1038+ if prevSchema := prevMediaType .Spec .Schema ; prevSchema .Ref != nil || prevSchema .Spec .OneOf == nil {
1039+ oneOfSchema := spec .NewSchemaSpec ()
1040+ oneOfSchema .Spec .OneOf = []* spec.RefOrSpec [spec.Schema ]{prevSchema , newMediaType .Spec .Schema }
1041+ prevMediaType .Spec .Schema = oneOfSchema
1042+ } else {
1043+ prevSchema .Spec .OneOf = append (prevSchema .Spec .OneOf , newMediaType .Spec .Schema )
1044+ }
1045+ }
1046+ }
1047+ }
1048+
1049+ if code != "" {
1050+ o .Responses .Spec .Response [code ] = res
1051+ } else {
1052+ o .Responses .Spec .Default = res
1053+ }
10241054}
10251055
10261056// ParseEmptyResponseOnly parse only comment out status code ,eg: @Success 200.
10271057func (o * OperationV3 ) ParseEmptyResponseOnly (commentLine string ) error {
10281058 for _ , codeStr := range strings .Split (commentLine , "," ) {
1059+ var description string
10291060 if strings .EqualFold (codeStr , defaultTag ) {
1030- _ = o .DefaultResponse ()
1031-
1032- continue
1033- }
1034-
1035- code , err := strconv .Atoi (codeStr )
1036- if err != nil {
1037- return fmt .Errorf ("can not parse response comment \" %s\" " , commentLine )
1061+ codeStr = ""
1062+ } else {
1063+ code , err := strconv .Atoi (codeStr )
1064+ if err != nil {
1065+ return fmt .Errorf ("can not parse response comment \" %s\" " , commentLine )
1066+ }
1067+ description = http .StatusText (code )
10381068 }
10391069
1040- o .AddResponse (codeStr , newResponseWithDescription (http . StatusText ( code ) ))
1070+ o .AddResponse (codeStr , newResponseWithDescription (description ))
10411071 }
10421072
10431073 return nil
0 commit comments