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  }