Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
4.8 KiB
232 lines
4.8 KiB
package codescan |
|
|
|
import ( |
|
"github.com/go-openapi/spec" |
|
) |
|
|
|
func newSpecBuilder(input *spec.Swagger, sc *scanCtx, scanModels bool) *specBuilder { |
|
if input == nil { |
|
input = new(spec.Swagger) |
|
input.Swagger = "2.0" |
|
} |
|
|
|
if input.Paths == nil { |
|
input.Paths = new(spec.Paths) |
|
} |
|
if input.Definitions == nil { |
|
input.Definitions = make(map[string]spec.Schema) |
|
} |
|
if input.Responses == nil { |
|
input.Responses = make(map[string]spec.Response) |
|
} |
|
if input.Extensions == nil { |
|
input.Extensions = make(spec.Extensions) |
|
} |
|
|
|
return &specBuilder{ |
|
ctx: sc, |
|
input: input, |
|
scanModels: scanModels, |
|
operations: collectOperationsFromInput(input), |
|
definitions: input.Definitions, |
|
responses: input.Responses, |
|
} |
|
} |
|
|
|
type specBuilder struct { |
|
scanModels bool |
|
input *spec.Swagger |
|
ctx *scanCtx |
|
discovered []*entityDecl |
|
definitions map[string]spec.Schema |
|
responses map[string]spec.Response |
|
operations map[string]*spec.Operation |
|
} |
|
|
|
func (s *specBuilder) Build() (*spec.Swagger, error) { |
|
if err := s.buildModels(); err != nil { |
|
return nil, err |
|
} |
|
|
|
if err := s.buildParameters(); err != nil { |
|
return nil, err |
|
} |
|
|
|
if err := s.buildRespones(); err != nil { |
|
return nil, err |
|
} |
|
|
|
// build definitions dictionary |
|
if err := s.buildDiscovered(); err != nil { |
|
return nil, err |
|
} |
|
|
|
if err := s.buildRoutes(); err != nil { |
|
return nil, err |
|
} |
|
|
|
if err := s.buildOperations(); err != nil { |
|
return nil, err |
|
} |
|
|
|
if err := s.buildMeta(); err != nil { |
|
return nil, err |
|
} |
|
|
|
if s.input.Swagger == "" { |
|
s.input.Swagger = "2.0" |
|
} |
|
|
|
return s.input, nil |
|
} |
|
|
|
func (s *specBuilder) buildDiscovered() error { |
|
// loop over discovered until all the items are in definitions |
|
keepGoing := len(s.discovered) > 0 |
|
for keepGoing { |
|
var queue []*entityDecl |
|
for _, d := range s.discovered { |
|
nm, _ := d.Names() |
|
if _, ok := s.definitions[nm]; !ok { |
|
queue = append(queue, d) |
|
} |
|
} |
|
s.discovered = nil |
|
for _, sd := range queue { |
|
if err := s.buildDiscoveredSchema(sd); err != nil { |
|
return err |
|
} |
|
} |
|
keepGoing = len(s.discovered) > 0 |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func (s *specBuilder) buildDiscoveredSchema(decl *entityDecl) error { |
|
sb := &schemaBuilder{ |
|
ctx: s.ctx, |
|
decl: decl, |
|
discovered: s.discovered, |
|
} |
|
if err := sb.Build(s.definitions); err != nil { |
|
return err |
|
} |
|
s.discovered = append(s.discovered, sb.postDecls...) |
|
return nil |
|
} |
|
|
|
func (s *specBuilder) buildMeta() error { |
|
// build swagger object |
|
for _, decl := range s.ctx.app.Meta { |
|
if err := newMetaParser(s.input).Parse(decl.Comments); err != nil { |
|
return err |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
func (s *specBuilder) buildOperations() error { |
|
for _, pp := range s.ctx.app.Operations { |
|
ob := &operationsBuilder{ |
|
operations: s.operations, |
|
ctx: s.ctx, |
|
path: pp, |
|
} |
|
if err := ob.Build(s.input.Paths); err != nil { |
|
return err |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
func (s *specBuilder) buildRoutes() error { |
|
// build paths dictionary |
|
for _, pp := range s.ctx.app.Routes { |
|
rb := &routesBuilder{ |
|
ctx: s.ctx, |
|
route: pp, |
|
responses: s.responses, |
|
operations: s.operations, |
|
definitions: s.definitions, |
|
} |
|
if err := rb.Build(s.input.Paths); err != nil { |
|
return err |
|
} |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func (s *specBuilder) buildRespones() error { |
|
// build responses dictionary |
|
for _, decl := range s.ctx.app.Responses { |
|
rb := &responseBuilder{ |
|
ctx: s.ctx, |
|
decl: decl, |
|
} |
|
if err := rb.Build(s.responses); err != nil { |
|
return err |
|
} |
|
s.discovered = append(s.discovered, rb.postDecls...) |
|
} |
|
return nil |
|
} |
|
|
|
func (s *specBuilder) buildParameters() error { |
|
// build parameters dictionary |
|
for _, decl := range s.ctx.app.Parameters { |
|
pb := ¶meterBuilder{ |
|
ctx: s.ctx, |
|
decl: decl, |
|
} |
|
if err := pb.Build(s.operations); err != nil { |
|
return err |
|
} |
|
s.discovered = append(s.discovered, pb.postDecls...) |
|
} |
|
return nil |
|
} |
|
|
|
func (s *specBuilder) buildModels() error { |
|
// build models dictionary |
|
if !s.scanModels { |
|
return nil |
|
} |
|
for _, decl := range s.ctx.app.Models { |
|
if err := s.buildDiscoveredSchema(decl); err != nil { |
|
return err |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
func collectOperationsFromInput(input *spec.Swagger) map[string]*spec.Operation { |
|
operations := make(map[string]*spec.Operation) |
|
if input != nil && input.Paths != nil { |
|
for _, pth := range input.Paths.Paths { |
|
if pth.Get != nil { |
|
operations[pth.Get.ID] = pth.Get |
|
} |
|
if pth.Post != nil { |
|
operations[pth.Post.ID] = pth.Post |
|
} |
|
if pth.Put != nil { |
|
operations[pth.Put.ID] = pth.Put |
|
} |
|
if pth.Patch != nil { |
|
operations[pth.Patch.ID] = pth.Patch |
|
} |
|
if pth.Delete != nil { |
|
operations[pth.Delete.ID] = pth.Delete |
|
} |
|
if pth.Head != nil { |
|
operations[pth.Head.ID] = pth.Head |
|
} |
|
if pth.Options != nil { |
|
operations[pth.Options.ID] = pth.Options |
|
} |
|
} |
|
} |
|
return operations |
|
}
|
|
|