github.com/josephspurrier/go-swagger@v0.2.1-0.20221129144919-1f672a142a00/scan/routes.go (about) 1 //go:build !go1.11 2 // +build !go1.11 3 4 // Copyright 2015 go-swagger maintainers 5 // 6 // Licensed under the Apache License, Version 2.0 (the "License"); 7 // you may not use this file except in compliance with the License. 8 // You may obtain a copy of the License at 9 // 10 // http://www.apache.org/licenses/LICENSE-2.0 11 // 12 // Unless required by applicable law or agreed to in writing, software 13 // distributed under the License is distributed on an "AS IS" BASIS, 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package scan 19 20 import ( 21 "fmt" 22 "go/ast" 23 24 "github.com/go-openapi/spec" 25 26 "golang.org/x/tools/go/loader" 27 ) 28 29 func opConsumesSetter(op *spec.Operation) func([]string) { 30 return func(consumes []string) { op.Consumes = consumes } 31 } 32 33 func opProducesSetter(op *spec.Operation) func([]string) { 34 return func(produces []string) { op.Produces = produces } 35 } 36 37 func opSchemeSetter(op *spec.Operation) func([]string) { 38 return func(schemes []string) { op.Schemes = schemes } 39 } 40 41 func opSecurityDefsSetter(op *spec.Operation) func([]map[string][]string) { 42 return func(securityDefs []map[string][]string) { op.Security = securityDefs } 43 } 44 45 func opResponsesSetter(op *spec.Operation) func(*spec.Response, map[int]spec.Response) { 46 return func(def *spec.Response, scr map[int]spec.Response) { 47 if op.Responses == nil { 48 op.Responses = new(spec.Responses) 49 } 50 op.Responses.Default = def 51 op.Responses.StatusCodeResponses = scr 52 } 53 } 54 55 func opParamSetter(op *spec.Operation) func([]*spec.Parameter) { 56 return func(params []*spec.Parameter) { 57 for _, v := range params { 58 op.AddParam(v) 59 } 60 } 61 } 62 63 func newRoutesParser(prog *loader.Program) *routesParser { 64 return &routesParser{ 65 program: prog, 66 } 67 } 68 69 type routesParser struct { 70 program *loader.Program 71 definitions map[string]spec.Schema 72 operations map[string]*spec.Operation 73 responses map[string]spec.Response 74 parameters []*spec.Parameter 75 } 76 77 func (rp *routesParser) Parse(gofile *ast.File, target interface{}, includeTags map[string]bool, excludeTags map[string]bool) error { 78 tgt := target.(*spec.Paths) 79 for _, comsec := range gofile.Comments { 80 content := parsePathAnnotation(rxRoute, comsec.List) 81 82 if content.Method == "" { 83 continue // it's not, next! 84 } 85 86 if !shouldAcceptTag(content.Tags, includeTags, excludeTags) { 87 if Debug { 88 fmt.Printf("route %s %s is ignored due to tag rules\n", content.Method, content.Path) 89 } 90 continue 91 } 92 93 pthObj := tgt.Paths[content.Path] 94 op := setPathOperation( 95 content.Method, content.ID, 96 &pthObj, rp.operations[content.ID]) 97 98 op.Tags = content.Tags 99 100 sp := new(sectionedParser) 101 sp.setTitle = func(lines []string) { op.Summary = joinDropLast(lines) } 102 sp.setDescription = func(lines []string) { op.Description = joinDropLast(lines) } 103 sr := newSetResponses(rp.definitions, rp.responses, opResponsesSetter(op)) 104 spa := newSetParams(rp.parameters, opParamSetter(op)) 105 sp.taggers = []tagParser{ 106 newMultiLineTagParser("Consumes", newMultilineDropEmptyParser(rxConsumes, opConsumesSetter(op)), false), 107 newMultiLineTagParser("Produces", newMultilineDropEmptyParser(rxProduces, opProducesSetter(op)), false), 108 newSingleLineTagParser("Schemes", newSetSchemes(opSchemeSetter(op))), 109 newMultiLineTagParser("Security", newSetSecurity(rxSecuritySchemes, opSecurityDefsSetter(op)), false), 110 newMultiLineTagParser("Parameters", spa, false), 111 newMultiLineTagParser("Responses", sr, false), 112 } 113 if err := sp.Parse(content.Remaining); err != nil { 114 return fmt.Errorf("operation (%s): %v", op.ID, err) 115 } 116 117 if tgt.Paths == nil { 118 tgt.Paths = make(map[string]spec.PathItem) 119 } 120 tgt.Paths[content.Path] = pthObj 121 } 122 123 return nil 124 } 125 126 func shouldAcceptTag(tags []string, includeTags map[string]bool, excludeTags map[string]bool) bool { 127 for _, tag := range tags { 128 if len(includeTags) > 0 { 129 if includeTags[tag] { 130 return true 131 } 132 } else if len(excludeTags) > 0 { 133 if excludeTags[tag] { 134 return false 135 } 136 } 137 } 138 return len(includeTags) <= 0 139 }