github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/courier/swagger/gen/openapi_generator.go (about) 1 package gen 2 3 import ( 4 "fmt" 5 "go/parser" 6 "go/types" 7 "regexp" 8 "strings" 9 10 "github.com/morlay/oas" 11 "golang.org/x/tools/go/loader" 12 13 "encoding/json" 14 15 "github.com/johnnyeven/libtools/codegen" 16 ) 17 18 type SwaggerGenerator struct { 19 RootRouterName string 20 Next bool 21 pkgImportPath string 22 program *loader.Program 23 openapi *oas.OpenAPI 24 routerScanner *RouterScanner 25 operatorScanner *OperatorScanner 26 } 27 28 func (g *SwaggerGenerator) Load(cwd string) { 29 ldr := loader.Config{ 30 ParserMode: parser.ParseComments, 31 } 32 33 pkgImportPath := codegen.GetPackageImportPath(cwd) 34 ldr.Import(pkgImportPath) 35 36 p, err := ldr.Load() 37 if err != nil { 38 panic(err) 39 } 40 41 g.program = p 42 g.pkgImportPath = pkgImportPath 43 g.openapi = oas.NewOpenAPI() 44 g.operatorScanner = NewOperatorScanner(p) 45 g.routerScanner = NewRouterScanner(p) 46 } 47 48 func (g *SwaggerGenerator) Pick() { 49 for _, pkgInfo := range g.program.AllPackages { 50 for _, def := range pkgInfo.Defs { 51 if typeVar, ok := def.(*types.Var); ok { 52 if typeVar.Name() == g.RootRouterName { 53 router := g.routerScanner.Router(typeVar) 54 routes := router.Routes(g.program) 55 operationIDs := map[string]*Route{} 56 for _, route := range routes { 57 operation := g.getOperationByOperatorTypes(route.Method, route.operators...) 58 if _, exists := operationIDs[operation.OperationId]; exists { 59 panic(fmt.Errorf("operationID %s should be unique", operation.OperationId)) 60 } 61 operationIDs[operation.OperationId] = route 62 g.openapi.AddOperation(oas.HttpMethod(strings.ToLower(route.Method)), g.patchPath(route.Path, operation), operation) 63 } 64 g.operatorScanner.BindSchemas(g.openapi) 65 return 66 } 67 } 68 } 69 } 70 } 71 72 var RxHttpRouterPath = regexp.MustCompile("/:([^/]+)") 73 74 func (g *SwaggerGenerator) patchPath(swaggerPath string, operation *oas.Operation) string { 75 return RxHttpRouterPath.ReplaceAllStringFunc(swaggerPath, func(str string) string { 76 name := RxHttpRouterPath.FindAllStringSubmatch(str, -1)[0][1] 77 78 var isParameterDefined = false 79 80 for _, parameter := range operation.Parameters { 81 if parameter.In == "path" && parameter.Name == name { 82 isParameterDefined = true 83 } 84 } 85 86 if isParameterDefined { 87 return "/{" + name + "}" 88 } 89 90 return "/0" 91 }) 92 } 93 94 func (g *SwaggerGenerator) getOperationByOperatorTypes(method string, operatorTypes ...*types.TypeName) *oas.Operation { 95 operators := make([]Operator, 0) 96 97 for _, operatorType := range operatorTypes { 98 operators = append(operators, *g.operatorScanner.Operator(operatorType)) 99 } 100 101 return ConcatToOperation(method, operators...) 102 } 103 104 func (g *SwaggerGenerator) Output(cwd string) codegen.Outputs { 105 bytes, _ := json.MarshalIndent(g.openapi, "", " ") 106 107 return codegen.Outputs{ 108 "swagger.json": string(bytes), 109 } 110 }