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