github.com/josephspurrier/go-swagger@v0.2.1-0.20221129144919-1f672a142a00/codescan/operations.go (about)

     1  package codescan
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"regexp"
     7  	"strings"
     8  
     9  	"github.com/go-openapi/spec"
    10  )
    11  
    12  type operationsBuilder struct {
    13  	ctx        *scanCtx
    14  	path       parsedPathContent
    15  	operations map[string]*spec.Operation
    16  }
    17  
    18  func (o *operationsBuilder) Build(tgt *spec.Paths) error {
    19  	pthObj := tgt.Paths[o.path.Path]
    20  
    21  	op := setPathOperation(
    22  		o.path.Method, o.path.ID,
    23  		&pthObj, o.operations[o.path.ID])
    24  
    25  	op.Tags = o.path.Tags
    26  
    27  	sp := new(yamlSpecScanner)
    28  	sp.setTitle = func(lines []string) { op.Summary = joinDropLast(lines) }
    29  	sp.setDescription = func(lines []string) { op.Description = joinDropLast(lines) }
    30  
    31  	if err := sp.Parse(o.path.Remaining); err != nil {
    32  		return fmt.Errorf("operation (%s): %v", op.ID, err)
    33  	}
    34  	if err := sp.UnmarshalSpec(op.UnmarshalJSON); err != nil {
    35  		return fmt.Errorf("operation (%s): %v", op.ID, err)
    36  	}
    37  
    38  	if tgt.Paths == nil {
    39  		tgt.Paths = make(map[string]spec.PathItem)
    40  	}
    41  
    42  	tgt.Paths[o.path.Path] = pthObj
    43  	return nil
    44  }
    45  
    46  type parsedPathContent struct {
    47  	Method, Path, ID string
    48  	Tags             []string
    49  	Remaining        *ast.CommentGroup
    50  }
    51  
    52  func parsePathAnnotation(annotation *regexp.Regexp, lines []*ast.Comment) (cnt parsedPathContent) {
    53  	var justMatched bool
    54  
    55  	for _, cmt := range lines {
    56  		txt := cmt.Text
    57  		for _, line := range strings.Split(txt, "\n") {
    58  			matches := annotation.FindStringSubmatch(line)
    59  			if len(matches) > 3 {
    60  				cnt.Method, cnt.Path, cnt.ID = matches[1], matches[2], matches[len(matches)-1]
    61  				cnt.Tags = rxSpace.Split(matches[3], -1)
    62  				if len(matches[3]) == 0 {
    63  					cnt.Tags = nil
    64  				}
    65  				justMatched = true
    66  			} else if cnt.Method != "" {
    67  				if cnt.Remaining == nil {
    68  					cnt.Remaining = new(ast.CommentGroup)
    69  				}
    70  				if !justMatched || strings.TrimSpace(rxStripComments.ReplaceAllString(line, "")) != "" {
    71  					cc := new(ast.Comment)
    72  					cc.Slash = cmt.Slash
    73  					cc.Text = line
    74  					cnt.Remaining.List = append(cnt.Remaining.List, cc)
    75  					justMatched = false
    76  				}
    77  			}
    78  		}
    79  	}
    80  
    81  	return
    82  }
    83  
    84  func setPathOperation(method, id string, pthObj *spec.PathItem, op *spec.Operation) *spec.Operation {
    85  	if op == nil {
    86  		op = new(spec.Operation)
    87  		op.ID = id
    88  	}
    89  
    90  	switch strings.ToUpper(method) {
    91  	case "GET":
    92  		if pthObj.Get != nil {
    93  			if id == pthObj.Get.ID {
    94  				op = pthObj.Get
    95  			} else {
    96  				pthObj.Get = op
    97  			}
    98  		} else {
    99  			pthObj.Get = op
   100  		}
   101  
   102  	case "POST":
   103  		if pthObj.Post != nil {
   104  			if id == pthObj.Post.ID {
   105  				op = pthObj.Post
   106  			} else {
   107  				pthObj.Post = op
   108  			}
   109  		} else {
   110  			pthObj.Post = op
   111  		}
   112  
   113  	case "PUT":
   114  		if pthObj.Put != nil {
   115  			if id == pthObj.Put.ID {
   116  				op = pthObj.Put
   117  			} else {
   118  				pthObj.Put = op
   119  			}
   120  		} else {
   121  			pthObj.Put = op
   122  		}
   123  
   124  	case "PATCH":
   125  		if pthObj.Patch != nil {
   126  			if id == pthObj.Patch.ID {
   127  				op = pthObj.Patch
   128  			} else {
   129  				pthObj.Patch = op
   130  			}
   131  		} else {
   132  			pthObj.Patch = op
   133  		}
   134  
   135  	case "HEAD":
   136  		if pthObj.Head != nil {
   137  			if id == pthObj.Head.ID {
   138  				op = pthObj.Head
   139  			} else {
   140  				pthObj.Head = op
   141  			}
   142  		} else {
   143  			pthObj.Head = op
   144  		}
   145  
   146  	case "DELETE":
   147  		if pthObj.Delete != nil {
   148  			if id == pthObj.Delete.ID {
   149  				op = pthObj.Delete
   150  			} else {
   151  				pthObj.Delete = op
   152  			}
   153  		} else {
   154  			pthObj.Delete = op
   155  		}
   156  
   157  	case "OPTIONS":
   158  		if pthObj.Options != nil {
   159  			if id == pthObj.Options.ID {
   160  				op = pthObj.Options
   161  			} else {
   162  				pthObj.Options = op
   163  			}
   164  		} else {
   165  			pthObj.Options = op
   166  		}
   167  	}
   168  
   169  	return op
   170  }