parser.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. package parser
  2. import (
  3. "fmt"
  4. "path/filepath"
  5. "unicode"
  6. "github.com/wuntsong-org/go-zero-plus/tools/goctlwt/api/parser/g4/ast"
  7. "github.com/wuntsong-org/go-zero-plus/tools/goctlwt/api/parser/g4/gen/api"
  8. "github.com/wuntsong-org/go-zero-plus/tools/goctlwt/api/spec"
  9. "github.com/wuntsong-org/go-zero-plus/tools/goctlwt/pkg/env"
  10. apiParser "github.com/wuntsong-org/go-zero-plus/tools/goctlwt/pkg/parser/api/parser"
  11. )
  12. type parser struct {
  13. ast *ast.Api
  14. spec *spec.ApiSpec
  15. }
  16. // Depreacted: use tools/goctl/pkg/parser/api/parser/parser.go:18 instead,
  17. // it will be removed in the future.
  18. // Parse parses the api file.
  19. func Parse(filename string) (*spec.ApiSpec, error) {
  20. if env.UseExperimental() {
  21. return apiParser.Parse(filename, "")
  22. }
  23. astParser := ast.NewParser(ast.WithParserPrefix(filepath.Base(filename)), ast.WithParserDebug())
  24. parsedApi, err := astParser.Parse(filename)
  25. if err != nil {
  26. return nil, err
  27. }
  28. apiSpec := new(spec.ApiSpec)
  29. p := parser{ast: parsedApi, spec: apiSpec}
  30. err = p.convert2Spec()
  31. if err != nil {
  32. return nil, err
  33. }
  34. return apiSpec, nil
  35. }
  36. func parseContent(content string, skipCheckTypeDeclaration bool, filename ...string) (*spec.ApiSpec, error) {
  37. var astParser *ast.Parser
  38. if skipCheckTypeDeclaration {
  39. astParser = ast.NewParser(ast.WithParserSkipCheckTypeDeclaration())
  40. } else {
  41. astParser = ast.NewParser()
  42. }
  43. parsedApi, err := astParser.ParseContent(content, filename...)
  44. if err != nil {
  45. return nil, err
  46. }
  47. apiSpec := new(spec.ApiSpec)
  48. p := parser{ast: parsedApi, spec: apiSpec}
  49. err = p.convert2Spec()
  50. if err != nil {
  51. return nil, err
  52. }
  53. return apiSpec, nil
  54. }
  55. // Depreacted: use tools/goctl/pkg/parser/api/parser/parser.go:18 instead,
  56. // it will be removed in the future.
  57. // ParseContent parses the api content
  58. func ParseContent(content string, filename ...string) (*spec.ApiSpec, error) {
  59. return parseContent(content, false, filename...)
  60. }
  61. // Depreacted: use tools/goctl/pkg/parser/api/parser/parser.go:18 instead,
  62. // it will be removed in the future.
  63. // ParseContentWithParserSkipCheckTypeDeclaration parses the api content with skip check type declaration
  64. func ParseContentWithParserSkipCheckTypeDeclaration(content string, filename ...string) (*spec.ApiSpec, error) {
  65. return parseContent(content, true, filename...)
  66. }
  67. func (p parser) convert2Spec() error {
  68. p.fillInfo()
  69. p.fillSyntax()
  70. p.fillImport()
  71. err := p.fillTypes()
  72. if err != nil {
  73. return err
  74. }
  75. return p.fillService()
  76. }
  77. func (p parser) fillInfo() {
  78. properties := make(map[string]string)
  79. if p.ast.Info != nil {
  80. for _, kv := range p.ast.Info.Kvs {
  81. properties[kv.Key.Text()] = kv.Value.Text()
  82. }
  83. }
  84. p.spec.Info.Properties = properties
  85. }
  86. func (p parser) fillSyntax() {
  87. if p.ast.Syntax != nil {
  88. p.spec.Syntax = spec.ApiSyntax{
  89. Version: p.ast.Syntax.Version.Text(),
  90. Doc: p.stringExprs(p.ast.Syntax.DocExpr),
  91. Comment: p.stringExprs([]ast.Expr{p.ast.Syntax.CommentExpr}),
  92. }
  93. }
  94. }
  95. func (p parser) fillImport() {
  96. if len(p.ast.Import) > 0 {
  97. for _, item := range p.ast.Import {
  98. p.spec.Imports = append(p.spec.Imports, spec.Import{
  99. Value: item.Value.Text(),
  100. Doc: p.stringExprs(item.DocExpr),
  101. Comment: p.stringExprs([]ast.Expr{item.CommentExpr}),
  102. })
  103. }
  104. }
  105. }
  106. func (p parser) fillTypes() error {
  107. for _, item := range p.ast.Type {
  108. switch v := (item).(type) {
  109. case *ast.TypeStruct:
  110. var members []spec.Member
  111. for _, item := range v.Fields {
  112. members = append(members, p.fieldToMember(item))
  113. }
  114. p.spec.Types = append(p.spec.Types, spec.DefineStruct{
  115. RawName: v.Name.Text(),
  116. Members: members,
  117. Docs: p.stringExprs(v.Doc()),
  118. })
  119. default:
  120. return fmt.Errorf("unknown type %+v", v)
  121. }
  122. }
  123. var types []spec.Type
  124. for _, item := range p.spec.Types {
  125. switch v := (item).(type) {
  126. case spec.DefineStruct:
  127. var members []spec.Member
  128. for _, member := range v.Members {
  129. switch v := member.Type.(type) {
  130. case spec.DefineStruct:
  131. tp, err := p.findDefinedType(v.RawName)
  132. if err != nil {
  133. return err
  134. }
  135. member.Type = *tp
  136. }
  137. members = append(members, member)
  138. }
  139. v.Members = members
  140. types = append(types, v)
  141. default:
  142. return fmt.Errorf("unknown type %+v", v)
  143. }
  144. }
  145. p.spec.Types = types
  146. return nil
  147. }
  148. func (p parser) findDefinedType(name string) (*spec.Type, error) {
  149. for _, item := range p.spec.Types {
  150. if _, ok := item.(spec.DefineStruct); ok {
  151. if item.Name() == name {
  152. return &item, nil
  153. }
  154. }
  155. }
  156. return nil, fmt.Errorf("type %s not defined", name)
  157. }
  158. func (p parser) fieldToMember(field *ast.TypeField) spec.Member {
  159. var name string
  160. var tag string
  161. if !field.IsAnonymous {
  162. name = field.Name.Text()
  163. if field.Tag != nil {
  164. tag = field.Tag.Text()
  165. }
  166. }
  167. return spec.Member{
  168. Name: name,
  169. Type: p.astTypeToSpec(field.DataType),
  170. Tag: tag,
  171. Comment: p.commentExprs(field.Comment()),
  172. Docs: p.stringExprs(field.Doc()),
  173. IsInline: field.IsAnonymous,
  174. }
  175. }
  176. func (p parser) astTypeToSpec(in ast.DataType) spec.Type {
  177. switch v := (in).(type) {
  178. case *ast.Literal:
  179. raw := v.Literal.Text()
  180. if api.IsBasicType(raw) {
  181. return spec.PrimitiveType{
  182. RawName: raw,
  183. }
  184. }
  185. return spec.DefineStruct{
  186. RawName: raw,
  187. }
  188. case *ast.Interface:
  189. return spec.InterfaceType{RawName: v.Literal.Text()}
  190. case *ast.Map:
  191. return spec.MapType{RawName: v.MapExpr.Text(), Key: v.Key.Text(), Value: p.astTypeToSpec(v.Value)}
  192. case *ast.Array:
  193. return spec.ArrayType{RawName: v.ArrayExpr.Text(), Value: p.astTypeToSpec(v.Literal)}
  194. case *ast.Pointer:
  195. raw := v.Name.Text()
  196. if api.IsBasicType(raw) {
  197. return spec.PointerType{RawName: v.PointerExpr.Text(), Type: spec.PrimitiveType{RawName: raw}}
  198. }
  199. return spec.PointerType{RawName: v.PointerExpr.Text(), Type: spec.DefineStruct{RawName: raw}}
  200. }
  201. panic(fmt.Sprintf("unspported type %+v", in))
  202. }
  203. func (p parser) stringExprs(docs []ast.Expr) []string {
  204. var result []string
  205. for _, item := range docs {
  206. if item == nil {
  207. continue
  208. }
  209. result = append(result, item.Text())
  210. }
  211. return result
  212. }
  213. func (p parser) commentExprs(comment ast.Expr) string {
  214. if comment == nil {
  215. return ""
  216. }
  217. return comment.Text()
  218. }
  219. func (p parser) fillService() error {
  220. var groups []spec.Group
  221. for _, item := range p.ast.Service {
  222. var group spec.Group
  223. p.fillAtServer(item, &group)
  224. for _, astRoute := range item.ServiceApi.ServiceRoute {
  225. route := spec.Route{
  226. AtServerAnnotation: spec.Annotation{},
  227. Method: astRoute.Route.Method.Text(),
  228. Path: astRoute.Route.Path.Text(),
  229. Doc: p.stringExprs(astRoute.Route.DocExpr),
  230. Comment: p.stringExprs([]ast.Expr{astRoute.Route.CommentExpr}),
  231. }
  232. if astRoute.AtHandler != nil {
  233. route.Handler = astRoute.AtHandler.Name.Text()
  234. route.HandlerDoc = append(route.HandlerDoc, p.stringExprs(astRoute.AtHandler.DocExpr)...)
  235. route.HandlerComment = append(route.HandlerComment, p.stringExprs([]ast.Expr{astRoute.AtHandler.CommentExpr})...)
  236. }
  237. err := p.fillRouteAtServer(astRoute, &route)
  238. if err != nil {
  239. return err
  240. }
  241. if astRoute.Route.Req != nil {
  242. route.RequestType = p.astTypeToSpec(astRoute.Route.Req.Name)
  243. }
  244. if astRoute.Route.Reply != nil {
  245. route.ResponseType = p.astTypeToSpec(astRoute.Route.Reply.Name)
  246. }
  247. if astRoute.AtDoc != nil {
  248. properties := make(map[string]string)
  249. for _, kv := range astRoute.AtDoc.Kv {
  250. properties[kv.Key.Text()] = kv.Value.Text()
  251. }
  252. route.AtDoc.Properties = properties
  253. if astRoute.AtDoc.LineDoc != nil {
  254. route.AtDoc.Text = astRoute.AtDoc.LineDoc.Text()
  255. }
  256. }
  257. err = p.fillRouteType(&route)
  258. if err != nil {
  259. return err
  260. }
  261. group.Routes = append(group.Routes, route)
  262. name := item.ServiceApi.Name.Text()
  263. if len(p.spec.Service.Name) > 0 && p.spec.Service.Name != name {
  264. return fmt.Errorf("multiple service names defined %s and %s",
  265. name, p.spec.Service.Name)
  266. }
  267. p.spec.Service.Name = name
  268. }
  269. groups = append(groups, group)
  270. }
  271. p.spec.Service.Groups = groups
  272. return nil
  273. }
  274. func (p parser) fillRouteAtServer(astRoute *ast.ServiceRoute, route *spec.Route) error {
  275. if astRoute.AtServer != nil {
  276. properties := make(map[string]string)
  277. for _, kv := range astRoute.AtServer.Kv {
  278. properties[kv.Key.Text()] = kv.Value.Text()
  279. }
  280. route.AtServerAnnotation.Properties = properties
  281. if len(route.Handler) == 0 {
  282. route.Handler = properties["handler"]
  283. }
  284. if len(route.Handler) == 0 {
  285. return fmt.Errorf("missing handler annotation for %q", route.Path)
  286. }
  287. for _, char := range route.Handler {
  288. if !unicode.IsDigit(char) && !unicode.IsLetter(char) {
  289. return fmt.Errorf("route [%s] handler [%s] invalid, handler name should only contains letter or digit",
  290. route.Path, route.Handler)
  291. }
  292. }
  293. }
  294. return nil
  295. }
  296. func (p parser) fillAtServer(item *ast.Service, group *spec.Group) {
  297. if item.AtServer != nil {
  298. properties := make(map[string]string)
  299. for _, kv := range item.AtServer.Kv {
  300. properties[kv.Key.Text()] = kv.Value.Text()
  301. }
  302. group.Annotation.Properties = properties
  303. }
  304. }
  305. func (p parser) fillRouteType(route *spec.Route) error {
  306. if route.RequestType != nil {
  307. switch route.RequestType.(type) {
  308. case spec.DefineStruct:
  309. tp, err := p.findDefinedType(route.RequestType.Name())
  310. if err != nil {
  311. return err
  312. }
  313. route.RequestType = *tp
  314. }
  315. }
  316. if route.ResponseType != nil {
  317. switch route.ResponseType.(type) {
  318. case spec.DefineStruct:
  319. tp, err := p.findDefinedType(route.ResponseType.Name())
  320. if err != nil {
  321. return err
  322. }
  323. route.ResponseType = *tp
  324. }
  325. }
  326. return nil
  327. }