genpacket.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package tsgen
  2. import (
  3. _ "embed"
  4. "fmt"
  5. "path"
  6. "strings"
  7. "text/template"
  8. "github.com/zeromicro/go-zero/tools/goctl/api/spec"
  9. apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
  10. "github.com/zeromicro/go-zero/tools/goctl/util"
  11. "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
  12. )
  13. //go:embed handler.tpl
  14. var handlerTemplate string
  15. func genHandler(dir, webAPI, caller string, api *spec.ApiSpec, unwrapAPI bool) error {
  16. filename := strings.Replace(api.Service.Name, "-api", "", 1) + ".ts"
  17. if err := pathx.RemoveIfExist(path.Join(dir, filename)); err != nil {
  18. return err
  19. }
  20. fp, created, err := apiutil.MaybeCreateFile(dir, "", filename)
  21. if err != nil {
  22. return err
  23. }
  24. if !created {
  25. return nil
  26. }
  27. defer fp.Close()
  28. imports := ""
  29. if len(caller) == 0 {
  30. caller = "webapi"
  31. }
  32. importCaller := caller
  33. if unwrapAPI {
  34. importCaller = "{ " + importCaller + " }"
  35. }
  36. if len(webAPI) > 0 {
  37. imports += `import ` + importCaller + ` from ` + "\"" + webAPI + "\""
  38. }
  39. if len(api.Types) != 0 {
  40. if len(imports) > 0 {
  41. imports += pathx.NL
  42. }
  43. outputFile := apiutil.ComponentName(api)
  44. imports += fmt.Sprintf(`import * as components from "%s"`, "./"+outputFile)
  45. imports += fmt.Sprintf(`%sexport * from "%s"`, pathx.NL, "./"+outputFile)
  46. }
  47. apis, err := genAPI(api, caller)
  48. if err != nil {
  49. return err
  50. }
  51. t := template.Must(template.New("handlerTemplate").Parse(handlerTemplate))
  52. return t.Execute(fp, map[string]string{
  53. "imports": imports,
  54. "apis": strings.TrimSpace(apis),
  55. })
  56. }
  57. func genAPI(api *spec.ApiSpec, caller string) (string, error) {
  58. var builder strings.Builder
  59. for _, group := range api.Service.Groups {
  60. for _, route := range group.Routes {
  61. handler := route.Handler
  62. if len(handler) == 0 {
  63. return "", fmt.Errorf("missing handler annotation for route %q", route.Path)
  64. }
  65. handler = util.Untitle(handler)
  66. handler = strings.Replace(handler, "Handler", "", 1)
  67. comment := commentForRoute(route)
  68. if len(comment) > 0 {
  69. fmt.Fprintf(&builder, "%s\n", comment)
  70. }
  71. fmt.Fprintf(&builder, "export function %s(%s) {\n", handler, paramsForRoute(route))
  72. writeIndent(&builder, 1)
  73. responseGeneric := "<null>"
  74. if len(route.ResponseTypeName()) > 0 {
  75. val, err := goTypeToTs(route.ResponseType, true)
  76. if err != nil {
  77. return "", err
  78. }
  79. responseGeneric = fmt.Sprintf("<%s>", val)
  80. }
  81. fmt.Fprintf(&builder, `return %s.%s%s(%s)`, caller, strings.ToLower(route.Method),
  82. util.Title(responseGeneric), callParamsForRoute(route, group))
  83. builder.WriteString("\n}\n\n")
  84. }
  85. }
  86. apis := builder.String()
  87. return apis, nil
  88. }
  89. func paramsForRoute(route spec.Route) string {
  90. if route.RequestType == nil {
  91. return ""
  92. }
  93. hasParams := pathHasParams(route)
  94. hasBody := hasRequestBody(route)
  95. rt, err := goTypeToTs(route.RequestType, true)
  96. if err != nil {
  97. fmt.Println(err.Error())
  98. return ""
  99. }
  100. if hasParams && hasBody {
  101. return fmt.Sprintf("params: %s, req: %s", rt+"Params", rt)
  102. } else if hasParams {
  103. return fmt.Sprintf("params: %s", rt+"Params")
  104. } else if hasBody {
  105. return fmt.Sprintf("req: %s", rt)
  106. }
  107. return ""
  108. }
  109. func commentForRoute(route spec.Route) string {
  110. var builder strings.Builder
  111. comment := route.JoinedDoc()
  112. builder.WriteString("/**")
  113. builder.WriteString("\n * @description " + comment)
  114. hasParams := pathHasParams(route)
  115. hasBody := hasRequestBody(route)
  116. if hasParams && hasBody {
  117. builder.WriteString("\n * @param params")
  118. builder.WriteString("\n * @param req")
  119. } else if hasParams {
  120. builder.WriteString("\n * @param params")
  121. } else if hasBody {
  122. builder.WriteString("\n * @param req")
  123. }
  124. builder.WriteString("\n */")
  125. return builder.String()
  126. }
  127. func callParamsForRoute(route spec.Route, group spec.Group) string {
  128. hasParams := pathHasParams(route)
  129. hasBody := hasRequestBody(route)
  130. if hasParams && hasBody {
  131. return fmt.Sprintf("%s, %s, %s", pathForRoute(route, group), "params", "req")
  132. } else if hasParams {
  133. return fmt.Sprintf("%s, %s", pathForRoute(route, group), "params")
  134. } else if hasBody {
  135. return fmt.Sprintf("%s, %s", pathForRoute(route, group), "req")
  136. }
  137. return pathForRoute(route, group)
  138. }
  139. func pathForRoute(route spec.Route, group spec.Group) string {
  140. prefix := group.GetAnnotation(pathPrefix)
  141. if len(prefix) == 0 {
  142. return "\"" + route.Path + "\""
  143. }
  144. prefix = strings.TrimPrefix(prefix, `"`)
  145. prefix = strings.TrimSuffix(prefix, `"`)
  146. return fmt.Sprintf(`"%s/%s"`, prefix, strings.TrimPrefix(route.Path, "/"))
  147. }
  148. func pathHasParams(route spec.Route) bool {
  149. ds, ok := route.RequestType.(spec.DefineStruct)
  150. if !ok {
  151. return false
  152. }
  153. return len(ds.Members) != len(ds.GetBodyMembers())
  154. }
  155. func hasRequestBody(route spec.Route) bool {
  156. ds, ok := route.RequestType.(spec.DefineStruct)
  157. if !ok {
  158. return false
  159. }
  160. return len(route.RequestTypeName()) > 0 && len(ds.GetBodyMembers()) > 0
  161. }