From 3f672a7041c4bea0a92f94e767b360bca2955283 Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Thu, 28 Apr 2022 00:32:49 +0300 Subject: [PATCH 1/4] chore: refactor parser --- parser.go | 283 +++++++++++++++++++++++++++++-------------------- parser_test.go | 63 +++++++---- 2 files changed, 209 insertions(+), 137 deletions(-) diff --git a/parser.go b/parser.go index a390714f4..e322410c4 100644 --- a/parser.go +++ b/parser.go @@ -48,9 +48,21 @@ const ( deprecatedAttr = "@deprecated" securityAttr = "@security" titleAttr = "@title" + conNameAttr = "@contact.name" + conURLAttr = "@contact.url" + conEmailAttr = "@contact.email" + licNameAttr = "@license.name" + licURLAttr = "@license.url" versionAttr = "@version" descriptionAttr = "@description" descriptionMarkdownAttr = "@description.markdown" + secBasicAttr = "@securitydefinitions.basic" + secAPIKeyAttr = "@securitydefinitions.apikey" + secApplicationAttr = "@securitydefinitions.oauth2.application" + secImplicitAttr = "@securitydefinitions.oauth2.implicit" + secPasswordAttr = "@securitydefinitions.oauth2.password" + secAccessCodeAttr = "@securitydefinitions.oauth2.accesscode" + tosAttr = "@termsofservice" xCodeSamplesAttr = "@x-codesamples" scopeAttrPrefix = "@scope." ) @@ -356,14 +368,6 @@ func getPkgName(searchDir string) (string, error) { return outStr, nil } -func initIfEmpty(license *spec.License) *spec.License { - if license == nil { - return new(spec.License) - } - - return license -} - // ParseGeneralAPIInfo parses general api info for given mainAPIFile path. func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error { fileTree, err := goparser.ParseFile(token.NewFileSet(), mainAPIFile, nil, goparser.ParseComments) @@ -396,16 +400,15 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error { commentLine := comments[line] attribute := strings.Split(commentLine, " ")[0] value := strings.TrimSpace(commentLine[len(attribute):]) + multilineBlock := false if previousAttribute == attribute { multilineBlock = true } - switch strings.ToLower(attribute) { - case versionAttr: - parser.swagger.Info.Version = value - case titleAttr: - parser.swagger.Info.Title = value + switch attr := strings.ToLower(attribute); attr { + case versionAttr, titleAttr, tosAttr, licNameAttr, licURLAttr, conNameAttr, conURLAttr, conEmailAttr: + setSwaggerInfo(parser.swagger, attr, value) case descriptionAttr: if multilineBlock { parser.swagger.Info.Description += "\n" + value @@ -413,32 +416,20 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error { continue } - parser.swagger.Info.Description = value - case "@description.markdown": + setSwaggerInfo(parser.swagger, attr, value) + case descriptionMarkdownAttr: commentInfo, err := getMarkdownForTag("api", parser.markdownFileDir) if err != nil { return err } - parser.swagger.Info.Description = string(commentInfo) - case "@termsofservice": - parser.swagger.Info.TermsOfService = value - case "@contact.name": - parser.swagger.Info.Contact.Name = value - case "@contact.email": - parser.swagger.Info.Contact.Email = value - case "@contact.url": - parser.swagger.Info.Contact.URL = value - case "@license.name": - parser.swagger.Info.License = initIfEmpty(parser.swagger.Info.License) - parser.swagger.Info.License.Name = value - case "@license.url": - parser.swagger.Info.License = initIfEmpty(parser.swagger.Info.License) - parser.swagger.Info.License.URL = value + setSwaggerInfo(parser.swagger, descriptionAttr, string(commentInfo)) + case "@host": parser.swagger.Host = value case "@basepath": parser.swagger.BasePath = value + case acceptAttr: err := parser.ParseAcceptComment(value) if err != nil { @@ -487,43 +478,12 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error { tag.TagProps.ExternalDocs.Description = value replaceLastTag(parser.swagger.Tags, tag) - case "@securitydefinitions.basic": - parser.swagger.SecurityDefinitions[value] = spec.BasicAuth() - case "@securitydefinitions.apikey": - attrMap, _, extensions, err := parseSecAttr(attribute, []string{"@in", "@name"}, comments, &line) - if err != nil { - return err - } - - parser.swagger.SecurityDefinitions[value] = tryAddDescription(spec.APIKeyAuth(attrMap["@name"], attrMap["@in"]), extensions) - case "@securitydefinitions.oauth2.application": - attrMap, scopes, extensions, err := parseSecAttr(attribute, []string{"@tokenurl"}, comments, &line) - if err != nil { - return err - } - - parser.swagger.SecurityDefinitions[value] = tryAddDescription(secOAuth2Application(attrMap["@tokenurl"], scopes, extensions), extensions) - case "@securitydefinitions.oauth2.implicit": - attrs, scopes, ext, err := parseSecAttr(attribute, []string{"@authorizationurl"}, comments, &line) - if err != nil { - return err - } - - parser.swagger.SecurityDefinitions[value] = tryAddDescription(secOAuth2Implicit(attrs["@authorizationurl"], scopes, ext), ext) - case "@securitydefinitions.oauth2.password": - attrs, scopes, ext, err := parseSecAttr(attribute, []string{"@tokenurl"}, comments, &line) - if err != nil { - return err - } - parser.swagger.SecurityDefinitions[value] = tryAddDescription(secOAuth2Password(attrs["@tokenurl"], scopes, ext), ext) - case "@securitydefinitions.oauth2.accesscode": - attrs, scopes, ext, err := parseSecAttr(attribute, []string{"@tokenurl", "@authorizationurl"}, comments, &line) + case secBasicAttr, secAPIKeyAttr, secApplicationAttr, secImplicitAttr, secPasswordAttr, secAccessCodeAttr: + err := setSwaggerSecurity(parser.swagger, attr, value, comments, &line) if err != nil { return err } - - parser.swagger.SecurityDefinitions[value] = tryAddDescription(secOAuth2AccessToken(attrs["@authorizationurl"], attrs["@tokenurl"], scopes, ext), ext) case "@query.collection.format": parser.collectionFormatInQuery = value default: @@ -578,14 +538,153 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error { return nil } -func tryAddDescription(spec *spec.SecurityScheme, extensions map[string]interface{}) *spec.SecurityScheme { - if val, ok := extensions["@description"]; ok { +func setSwaggerInfo(swagger *spec.Swagger, attribute, value string) { + switch attribute { + case versionAttr: + swagger.Info.Version = value + case titleAttr: + swagger.Info.Title = value + case tosAttr: + swagger.Info.TermsOfService = value + case descriptionAttr: + swagger.Info.Description = value + case conNameAttr: + swagger.Info.Contact.Name = value + case conEmailAttr: + swagger.Info.Contact.Email = value + case conURLAttr: + swagger.Info.Contact.URL = value + case licNameAttr: + swagger.Info.License = initIfEmpty(swagger.Info.License) + swagger.Info.License.Name = value + case licURLAttr: + swagger.Info.License = initIfEmpty(swagger.Info.License) + swagger.Info.License.URL = value + } +} + +func setSwaggerSecurity(swagger *spec.Swagger, attribute, value string, comments []string, line *int) error { + const ( + in = "@in" + name = "@name" + description = "@description" + tokenURL = "@tokenurl" + authorizationURL = "@authorizationurl" + ) + var ( + attr, scopes authScopes + ext authExtensions + err error + scheme *spec.SecurityScheme + ) + + switch attribute { + case secBasicAttr: + swagger.SecurityDefinitions[value] = spec.BasicAuth() + + return nil + case secAPIKeyAttr: + attr, _, ext, err = parseSecAttr(attribute, []string{in, name}, comments, line) + if err != nil { + return err + } + + scheme = spec.APIKeyAuth(attr[name], attr[in]) + case secApplicationAttr: + attr, scopes, ext, err = parseSecAttr(attribute, []string{tokenURL}, comments, line) + if err != nil { + return err + } + + scheme = secOAuth2Application(attr[tokenURL], scopes, ext) + case secImplicitAttr: + attr, scopes, ext, err = parseSecAttr(attribute, []string{authorizationURL}, comments, line) + if err != nil { + return err + } + + scheme = secOAuth2Implicit(attr[authorizationURL], scopes, ext) + case secPasswordAttr: + attr, scopes, ext, err = parseSecAttr(attribute, []string{tokenURL}, comments, line) + if err != nil { + return err + } + + scheme = secOAuth2Password(attr[tokenURL], scopes, ext) + case secAccessCodeAttr: + attr, scopes, ext, err = parseSecAttr(attribute, []string{tokenURL, authorizationURL}, comments, line) + if err != nil { + return err + } + + scheme = secOAuth2AccessToken(attr[authorizationURL], attr[tokenURL], scopes, ext) + } + + if val, ok := ext[description]; ok { if str, ok := val.(string); ok { - spec.Description = str + scheme.Description = str } } - return spec + swagger.SecurityDefinitions[value] = scheme + + return nil +} + +type ( + authExtensions map[string]interface{} + authScopes map[string]string +) + +func secOAuth2Application(tokenURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme { + securityScheme := spec.OAuth2Application(tokenURL) + securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions) + for scope, description := range scopes { + securityScheme.AddScope(scope, description) + } + + return securityScheme +} + +func secOAuth2Implicit(authorizationURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme { + securityScheme := spec.OAuth2Implicit(authorizationURL) + securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions) + + for scope, description := range scopes { + securityScheme.AddScope(scope, description) + } + + return securityScheme +} + +func secOAuth2Password(tokenURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme { + securityScheme := spec.OAuth2Password(tokenURL) + securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions) + + for scope, description := range scopes { + securityScheme.AddScope(scope, description) + } + + return securityScheme +} + +func secOAuth2AccessToken(authorizationURL, tokenURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme { + securityScheme := spec.OAuth2AccessToken(authorizationURL, tokenURL) + securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions) + + for scope, description := range scopes { + securityScheme.AddScope(scope, description) + } + + return securityScheme +} + +func initIfEmpty(license *spec.License) *spec.License { + if license == nil { + return new(spec.License) + } + + return license } // ParseAcceptComment parses comment for given `accept` comment string. @@ -666,54 +765,6 @@ func parseSecAttr(context string, search []string, lines []string, index *int) ( return attrMap, scopes, extensions, nil } -type ( - authExtensions map[string]interface{} - authScopes map[string]string -) - -func secOAuth2Application(tokenURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme { - securityScheme := spec.OAuth2Application(tokenURL) - securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions) - for scope, description := range scopes { - securityScheme.AddScope(scope, description) - } - - return securityScheme -} - -func secOAuth2Implicit(authorizationURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme { - securityScheme := spec.OAuth2Implicit(authorizationURL) - securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions) - - for scope, description := range scopes { - securityScheme.AddScope(scope, description) - } - - return securityScheme -} - -func secOAuth2Password(tokenURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme { - securityScheme := spec.OAuth2Password(tokenURL) - securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions) - - for scope, description := range scopes { - securityScheme.AddScope(scope, description) - } - - return securityScheme -} - -func secOAuth2AccessToken(authorizationURL, tokenURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme { - securityScheme := spec.OAuth2AccessToken(authorizationURL, tokenURL) - securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions) - - for scope, description := range scopes { - securityScheme.AddScope(scope, description) - } - - return securityScheme -} - func handleSecuritySchemaExtensions(providedExtensions authExtensions) spec.Extensions { var extensions spec.Extensions if len(providedExtensions) > 0 { @@ -1365,7 +1416,7 @@ func replaceLastTag(slice []spec.Tag, element spec.Tag) { slice = append(slice[:len(slice)-1], element) } -// defineTypeOfExample example value define the type (object and array unsupported) +// defineTypeOfExample example value define the type (object and array unsupported). func defineTypeOfExample(schemaType, arrayType, exampleValue string) (interface{}, error) { switch schemaType { case STRING: diff --git a/parser_test.go b/parser_test.go index 392a04fe2..0e809b465 100644 --- a/parser_test.go +++ b/parser_test.go @@ -11,6 +11,7 @@ import ( "os" "path/filepath" "reflect" + "strings" "testing" "github.com/go-openapi/spec" @@ -3461,57 +3462,77 @@ func TestTryAddDescription(t *testing.T) { extensions map[string]interface{} } tests := []struct { - name string - args args - want *spec.SecurityScheme + name string + lines []string + args args + want *spec.SecurityScheme }{ { name: "added description", - args: args{ - spec: &spec.SecurityScheme{}, - extensions: map[string]interface{}{ - "@description": "some description", - }, + lines: []string{ + "@securitydefinitions.apikey test", + "@in header", + "@name x-api-key", + "@description some description", }, want: &spec.SecurityScheme{ SecuritySchemeProps: spec.SecuritySchemeProps{ + Name: "x-api-key", + Type: "apiKey", + In: "header", Description: "some description", }, }, }, { name: "no description", - args: args{ - spec: &spec.SecurityScheme{}, - extensions: map[string]interface{}{ - "@not-description": "some description", - }, + lines: []string{ + "@securitydefinitions.oauth2.application swagger", + "@tokenurl https://example.com/oauth/token", + "@not-description some description", }, want: &spec.SecurityScheme{ SecuritySchemeProps: spec.SecuritySchemeProps{ + Type: "oauth2", + Flow: "application", + TokenURL: "https://example.com/oauth/token", Description: "", }, }, }, + { name: "description has invalid format", - args: args{ - spec: &spec.SecurityScheme{}, - extensions: map[string]interface{}{ - "@description": 12345, - }, + lines: []string{ + "@securitydefinitions.oauth2.implicit swagger", + "@authorizationurl https://example.com/oauth/token", + "@description 12345", }, + want: &spec.SecurityScheme{ SecuritySchemeProps: spec.SecuritySchemeProps{ - Description: "", + Type: "oauth2", + Flow: "implicit", + AuthorizationURL: "https://example.com/oauth/token", + Description: "12345", }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tryAddDescription(tt.args.spec, tt.args.extensions); !reflect.DeepEqual(got, tt.want) { - t.Errorf("tryAddDescription() = %v, want %v", got, tt.want) + swag := spec.Swagger{ + SwaggerProps: spec.SwaggerProps{ + SecurityDefinitions: make(map[string]*spec.SecurityScheme), + }, + } + line := 0 + commentLine := tt.lines[line] + attribute := strings.Split(commentLine, " ")[0] + value := strings.TrimSpace(commentLine[len(attribute):]) + _ = setSwaggerSecurity(&swag, attribute, value, tt.lines, &line) + if !reflect.DeepEqual(swag.SecurityDefinitions[value], tt.want) { + t.Errorf("setSwaggerSecurity() = %#v, want %#v", swag.SecurityDefinitions[value], tt.want) } }) } From 119c383e4099035712d94bd9e82e39dbf0ceadb7 Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Thu, 28 Apr 2022 00:40:28 +0300 Subject: [PATCH 2/4] chore: refactor parser --- parser_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/parser_test.go b/parser_test.go index 0e809b465..126b7dc1d 100644 --- a/parser_test.go +++ b/parser_test.go @@ -3516,6 +3516,11 @@ func TestTryAddDescription(t *testing.T) { AuthorizationURL: "https://example.com/oauth/token", Description: "12345", }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "@description": "12345", + }, + }, }, }, } From 8027dbd415ac5f4810f77b95be2ec4a31e7ecdea Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Thu, 28 Apr 2022 02:18:33 +0300 Subject: [PATCH 3/4] chore: refactor parser --- parser.go | 219 ++++++++++++++++--------------------------------- parser_test.go | 9 +- 2 files changed, 74 insertions(+), 154 deletions(-) diff --git a/parser.go b/parser.go index e322410c4..b5b6ab267 100644 --- a/parser.go +++ b/parser.go @@ -480,10 +480,13 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error { replaceLastTag(parser.swagger.Tags, tag) case secBasicAttr, secAPIKeyAttr, secApplicationAttr, secImplicitAttr, secPasswordAttr, secAccessCodeAttr: - err := setSwaggerSecurity(parser.swagger, attr, value, comments, &line) + scheme, err := parseSecAttributes(attribute, comments, &line) if err != nil { return err } + + parser.swagger.SecurityDefinitions[value] = scheme + case "@query.collection.format": parser.collectionFormatInQuery = value default: @@ -563,120 +566,109 @@ func setSwaggerInfo(swagger *spec.Swagger, attribute, value string) { } } -func setSwaggerSecurity(swagger *spec.Swagger, attribute, value string, comments []string, line *int) error { +func parseSecAttributes(context string, lines []string, index *int) (*spec.SecurityScheme, error) { const ( in = "@in" name = "@name" - description = "@description" + descriptionAttr = "@description" tokenURL = "@tokenurl" authorizationURL = "@authorizationurl" ) - var ( - attr, scopes authScopes - ext authExtensions - err error - scheme *spec.SecurityScheme - ) + var search []string + + attribute := strings.ToLower(strings.Split(lines[*index], " ")[0]) switch attribute { case secBasicAttr: - swagger.SecurityDefinitions[value] = spec.BasicAuth() - - return nil + return spec.BasicAuth(), nil case secAPIKeyAttr: - attr, _, ext, err = parseSecAttr(attribute, []string{in, name}, comments, line) - if err != nil { - return err + search = []string{in, name} + case secApplicationAttr: + search = []string{tokenURL} + case secImplicitAttr: + search = []string{authorizationURL} + case secPasswordAttr: + search = []string{tokenURL} + case secAccessCodeAttr: + search = []string{tokenURL, authorizationURL} + } + + // For the first line we get the attributes in the context parameter, so we skip to the next one + *index++ + + attrMap, scopes := make(map[string]string), make(map[string]string) + extensions, description := make(map[string]interface{}), "" + + for ; *index < len(lines); *index++ { + v := lines[*index] + + securityAttr := strings.ToLower(strings.Split(v, " ")[0]) + for _, findterm := range search { + if securityAttr == findterm { + attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):]) + + continue + } } - scheme = spec.APIKeyAuth(attr[name], attr[in]) - case secApplicationAttr: - attr, scopes, ext, err = parseSecAttr(attribute, []string{tokenURL}, comments, line) + isExists, err := isExistsScope(securityAttr) if err != nil { - return err + return nil, err } - scheme = secOAuth2Application(attr[tokenURL], scopes, ext) - case secImplicitAttr: - attr, scopes, ext, err = parseSecAttr(attribute, []string{authorizationURL}, comments, line) - if err != nil { - return err + if isExists { + scopes[securityAttr[len(scopeAttrPrefix):]] = v[len(securityAttr):] } - scheme = secOAuth2Implicit(attr[authorizationURL], scopes, ext) - case secPasswordAttr: - attr, scopes, ext, err = parseSecAttr(attribute, []string{tokenURL}, comments, line) - if err != nil { - return err + if strings.HasPrefix(securityAttr, "@x-") { + // Add the custom attribute without the @ + extensions[securityAttr[1:]] = strings.TrimSpace(v[len(securityAttr):]) } - scheme = secOAuth2Password(attr[tokenURL], scopes, ext) - case secAccessCodeAttr: - attr, scopes, ext, err = parseSecAttr(attribute, []string{tokenURL, authorizationURL}, comments, line) - if err != nil { - return err + // Not mandatory field + if securityAttr == descriptionAttr { + description = strings.TrimSpace(v[len(securityAttr):]) } - scheme = secOAuth2AccessToken(attr[authorizationURL], attr[tokenURL], scopes, ext) - } + // next securityDefinitions + if strings.Index(securityAttr, "@securitydefinitions.") == 0 { + // Go back to the previous line and break + *index-- - if val, ok := ext[description]; ok { - if str, ok := val.(string); ok { - scheme.Description = str + break } } - swagger.SecurityDefinitions[value] = scheme - - return nil -} - -type ( - authExtensions map[string]interface{} - authScopes map[string]string -) - -func secOAuth2Application(tokenURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme { - securityScheme := spec.OAuth2Application(tokenURL) - securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions) - for scope, description := range scopes { - securityScheme.AddScope(scope, description) + if len(attrMap) != len(search) { + return nil, fmt.Errorf("%s is %v required", context, search) } - return securityScheme -} - -func secOAuth2Implicit(authorizationURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme { - securityScheme := spec.OAuth2Implicit(authorizationURL) - securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions) + var scheme *spec.SecurityScheme - for scope, description := range scopes { - securityScheme.AddScope(scope, description) + switch attribute { + case secAPIKeyAttr: + scheme = spec.APIKeyAuth(attrMap[name], attrMap[in]) + case secApplicationAttr: + scheme = spec.OAuth2Application(attrMap[tokenURL]) + case secImplicitAttr: + scheme = spec.OAuth2Implicit(attrMap[authorizationURL]) + case secPasswordAttr: + scheme = spec.OAuth2Password(attrMap[tokenURL]) + case secAccessCodeAttr: + scheme = spec.OAuth2AccessToken(attrMap[authorizationURL], attrMap[tokenURL]) } - return securityScheme -} - -func secOAuth2Password(tokenURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme { - securityScheme := spec.OAuth2Password(tokenURL) - securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions) + scheme.Description = description - for scope, description := range scopes { - securityScheme.AddScope(scope, description) + for extKey, extValue := range extensions { + scheme.VendorExtensible.AddExtension(extKey, extValue) } - return securityScheme -} - -func secOAuth2AccessToken(authorizationURL, tokenURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme { - securityScheme := spec.OAuth2AccessToken(authorizationURL, tokenURL) - securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions) - - for scope, description := range scopes { - securityScheme.AddScope(scope, description) + for scope, scopeDescription := range scopes { + scheme.AddScope(scope, scopeDescription) } - return securityScheme + return scheme, nil } func initIfEmpty(license *spec.License) *spec.License { @@ -710,73 +702,6 @@ func isGeneralAPIComment(comments []string) bool { return true } -func parseSecAttr(context string, search []string, lines []string, index *int) (map[string]string, map[string]string, map[string]interface{}, error) { - attrMap := map[string]string{} - scopes := map[string]string{} - extensions := map[string]interface{}{} - - // For the first line we get the attributes in the context parameter, so we skip to the next one - *index++ - - for ; *index < len(lines); *index++ { - v := lines[*index] - - securityAttr := strings.ToLower(strings.Split(v, " ")[0]) - for _, findterm := range search { - if securityAttr == findterm { - attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):]) - - continue - } - } - - isExists, err := isExistsScope(securityAttr) - if err != nil { - return nil, nil, nil, err - } - - if isExists { - scopes[securityAttr[len(scopeAttrPrefix):]] = v[len(securityAttr):] - } - - if strings.HasPrefix(securityAttr, "@x-") { - // Add the custom attribute without the @ - extensions[securityAttr[1:]] = strings.TrimSpace(v[len(securityAttr):]) - } - - // Not mandatory field - if securityAttr == "@description" { - extensions[securityAttr] = strings.TrimSpace(v[len(securityAttr):]) - } - - // next securityDefinitions - if strings.Index(securityAttr, "@securitydefinitions.") == 0 { - // Go back to the previous line and break - *index-- - - break - } - } - - if len(attrMap) != len(search) { - return nil, nil, nil, fmt.Errorf("%s is %v required", context, search) - } - - return attrMap, scopes, extensions, nil -} - -func handleSecuritySchemaExtensions(providedExtensions authExtensions) spec.Extensions { - var extensions spec.Extensions - if len(providedExtensions) > 0 { - extensions = make(map[string]interface{}, len(providedExtensions)) - for key, value := range providedExtensions { - extensions[key] = value - } - } - - return extensions -} - func getMarkdownForTag(tagName string, dirPath string) ([]byte, error) { filesInfos, err := ioutil.ReadDir(dirPath) if err != nil { diff --git a/parser_test.go b/parser_test.go index 126b7dc1d..a25aa7797 100644 --- a/parser_test.go +++ b/parser_test.go @@ -3516,11 +3516,6 @@ func TestTryAddDescription(t *testing.T) { AuthorizationURL: "https://example.com/oauth/token", Description: "12345", }, - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "@description": "12345", - }, - }, }, }, } @@ -3535,8 +3530,8 @@ func TestTryAddDescription(t *testing.T) { commentLine := tt.lines[line] attribute := strings.Split(commentLine, " ")[0] value := strings.TrimSpace(commentLine[len(attribute):]) - _ = setSwaggerSecurity(&swag, attribute, value, tt.lines, &line) - if !reflect.DeepEqual(swag.SecurityDefinitions[value], tt.want) { + secAttr, _ := parseSecAttributes(attribute, tt.lines, &line) + if !reflect.DeepEqual(secAttr, tt.want) { t.Errorf("setSwaggerSecurity() = %#v, want %#v", swag.SecurityDefinitions[value], tt.want) } }) From 84deffe3d9c2cc4bde47604532e96f0cd36b06a9 Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Thu, 28 Apr 2022 02:35:24 +0300 Subject: [PATCH 4/4] chore: refactor parser --- parser.go | 15 +++------------ parser_test.go | 8 -------- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/parser.go b/parser.go index b5b6ab267..0f9cbc43a 100644 --- a/parser.go +++ b/parser.go @@ -441,7 +441,7 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error { return err } case "@schemes": - parser.swagger.Schemes = getSchemes(commentLine) + parser.swagger.Schemes = strings.Split(value, " ") case "@tag.name": parser.swagger.Tags = append(parser.swagger.Tags, spec.Tag{ TagProps: spec.TagProps{ @@ -583,12 +583,10 @@ func parseSecAttributes(context string, lines []string, index *int) (*spec.Secur return spec.BasicAuth(), nil case secAPIKeyAttr: search = []string{in, name} - case secApplicationAttr: + case secApplicationAttr, secPasswordAttr: search = []string{tokenURL} case secImplicitAttr: search = []string{authorizationURL} - case secPasswordAttr: - search = []string{tokenURL} case secAccessCodeAttr: search = []string{tokenURL, authorizationURL} } @@ -661,7 +659,7 @@ func parseSecAttributes(context string, lines []string, index *int) (*spec.Secur scheme.Description = description for extKey, extValue := range extensions { - scheme.VendorExtensible.AddExtension(extKey, extValue) + scheme.AddExtension(extKey, extValue) } for scope, scopeDescription := range scopes { @@ -747,13 +745,6 @@ func isExistsScope(scope string) (bool, error) { return strings.Contains(scope, scopeAttrPrefix), nil } -// getSchemes parses swagger schemes for given commentLine. -func getSchemes(commentLine string) []string { - attribute := strings.ToLower(strings.Split(commentLine, " ")[0]) - - return strings.Split(strings.TrimSpace(commentLine[len(attribute):]), " ") -} - // ParseRouterAPIInfo parses router api info for given astFile. func (parser *Parser) ParseRouterAPIInfo(fileName string, astFile *ast.File) error { for _, astDescription := range astFile.Decls { diff --git a/parser_test.go b/parser_test.go index a25aa7797..a2a6af1fa 100644 --- a/parser_test.go +++ b/parser_test.go @@ -810,14 +810,6 @@ func TestParser_ParseType(t *testing.T) { assert.NotNil(t, p.packages.uniqueDefinitions["web.Pet2"]) } -func TestGetSchemes(t *testing.T) { - t.Parallel() - - schemes := getSchemes("@schemes http https") - expectedSchemes := []string{"http", "https"} - assert.Equal(t, expectedSchemes, schemes) -} - func TestParseSimpleApi1(t *testing.T) { t.Parallel()