123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- // +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
- }
|