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