mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-01-05 18:45:02 +03:00
9fe4437bda
* Use vendored go-swagger * vendor go-swagger * revert un wanteed change * remove un-needed GO111MODULE * Update Makefile Co-Authored-By: techknowlogick <matti@mdranta.net>
165 lines
4.4 KiB
Go
165 lines
4.4 KiB
Go
// +build !go1.11
|
|
|
|
// Copyright 2015 go-swagger maintainers
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package scan
|
|
|
|
import (
|
|
"fmt"
|
|
"go/ast"
|
|
"log"
|
|
"regexp"
|
|
|
|
"golang.org/x/tools/go/loader"
|
|
)
|
|
|
|
type packageFilter struct {
|
|
Name string
|
|
}
|
|
|
|
func (pf *packageFilter) Matches(path string) bool {
|
|
matched, err := regexp.MatchString(pf.Name, path)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
return matched
|
|
}
|
|
|
|
type packageFilters []packageFilter
|
|
|
|
func (pf packageFilters) HasFilters() bool {
|
|
return len(pf) > 0
|
|
}
|
|
|
|
func (pf packageFilters) Matches(path string) bool {
|
|
for _, mod := range pf {
|
|
if mod.Matches(path) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type classifiedProgram struct {
|
|
Meta []*ast.File
|
|
Models []*ast.File
|
|
Routes []*ast.File
|
|
Operations []*ast.File
|
|
Parameters []*ast.File
|
|
Responses []*ast.File
|
|
}
|
|
|
|
// programClassifier classifies the files of a program into buckets
|
|
// for processing by a swagger spec generator. This buckets files in
|
|
// 3 groups: Meta, Models and Operations.
|
|
//
|
|
// Each of these buckets is then processed with an appropriate parsing strategy
|
|
//
|
|
// When there are Include or Exclude filters provide they are used to limit the
|
|
// candidates prior to parsing.
|
|
// The include filters take precedence over the excludes. So when something appears
|
|
// in both filters it will be included.
|
|
type programClassifier struct {
|
|
Includes packageFilters
|
|
Excludes packageFilters
|
|
}
|
|
|
|
func (pc *programClassifier) Classify(prog *loader.Program) (*classifiedProgram, error) {
|
|
var cp classifiedProgram
|
|
for pkg, pkgInfo := range prog.AllPackages {
|
|
if Debug {
|
|
log.Printf("analyzing: %s\n", pkg.Path())
|
|
}
|
|
if pc.Includes.HasFilters() {
|
|
if !pc.Includes.Matches(pkg.Path()) {
|
|
continue
|
|
}
|
|
} else if pc.Excludes.HasFilters() {
|
|
if pc.Excludes.Matches(pkg.Path()) {
|
|
continue
|
|
}
|
|
}
|
|
|
|
for _, file := range pkgInfo.Files {
|
|
var ro, op, mt, pm, rs, mm bool // only add a particular file once
|
|
for _, comments := range file.Comments {
|
|
var seenStruct string
|
|
for _, cline := range comments.List {
|
|
if cline != nil {
|
|
matches := rxSwaggerAnnotation.FindStringSubmatch(cline.Text)
|
|
if len(matches) > 1 {
|
|
switch matches[1] {
|
|
case "route":
|
|
if !ro {
|
|
cp.Routes = append(cp.Routes, file)
|
|
ro = true
|
|
}
|
|
case "operation":
|
|
if !op {
|
|
cp.Operations = append(cp.Operations, file)
|
|
op = true
|
|
}
|
|
case "model":
|
|
if !mm {
|
|
cp.Models = append(cp.Models, file)
|
|
mm = true
|
|
}
|
|
if seenStruct == "" || seenStruct == matches[1] {
|
|
seenStruct = matches[1]
|
|
} else {
|
|
return nil, fmt.Errorf("classifier: already annotated as %s, can't also be %q", seenStruct, matches[1])
|
|
}
|
|
case "meta":
|
|
if !mt {
|
|
cp.Meta = append(cp.Meta, file)
|
|
mt = true
|
|
}
|
|
case "parameters":
|
|
if !pm {
|
|
cp.Parameters = append(cp.Parameters, file)
|
|
pm = true
|
|
}
|
|
if seenStruct == "" || seenStruct == matches[1] {
|
|
seenStruct = matches[1]
|
|
} else {
|
|
return nil, fmt.Errorf("classifier: already annotated as %s, can't also be %q", seenStruct, matches[1])
|
|
}
|
|
case "response":
|
|
if !rs {
|
|
cp.Responses = append(cp.Responses, file)
|
|
rs = true
|
|
}
|
|
if seenStruct == "" || seenStruct == matches[1] {
|
|
seenStruct = matches[1]
|
|
} else {
|
|
return nil, fmt.Errorf("classifier: already annotated as %s, can't also be %q", seenStruct, matches[1])
|
|
}
|
|
case "strfmt", "name", "discriminated", "file", "enum", "default", "alias", "type":
|
|
// TODO: perhaps collect these and pass along to avoid lookups later on
|
|
case "allOf":
|
|
case "ignore":
|
|
default:
|
|
return nil, fmt.Errorf("classifier: unknown swagger annotation %q", matches[1])
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return &cp, nil
|
|
}
|