genpacket.go 4.7 KB

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