From 94417be0186622c2103aa2fd5f1cc64953f2bf2b Mon Sep 17 00:00:00 2001 From: anqiansong Date: Fri, 21 May 2021 10:40:59 +0800 Subject: [PATCH] Add document & comment for spec (#703) * Add document & comment for spec * remove duplicate field * use alias --- tools/goctl/api/parser/g4/ast/type.go | 2 + tools/goctl/api/parser/parser.go | 27 ++++++++++-- tools/goctl/api/parser/parser_test.go | 28 +++++++++++++ tools/goctl/api/spec/name.go | 60 +++++++++++++++++++++++++++ tools/goctl/api/spec/spec.go | 12 +++++- 5 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 tools/goctl/api/parser/parser_test.go diff --git a/tools/goctl/api/parser/g4/ast/type.go b/tools/goctl/api/parser/g4/ast/type.go index 97aa5f4c..d2a18986 100644 --- a/tools/goctl/api/parser/g4/ast/type.go +++ b/tools/goctl/api/parser/g4/ast/type.go @@ -114,8 +114,10 @@ func (v *ApiVisitor) VisitTypeLit(ctx *api.TypeLitContext) interface{} { return alias } + doc := v.getDoc(ctx) st, ok := typeLit.(*TypeStruct) if ok { + st.DocExpr = doc return st } diff --git a/tools/goctl/api/parser/parser.go b/tools/goctl/api/parser/parser.go index b4019162..bcb9c112 100644 --- a/tools/goctl/api/parser/parser.go +++ b/tools/goctl/api/parser/parser.go @@ -76,14 +76,22 @@ func (p parser) fillInfo() { func (p parser) fillSyntax() { if p.ast.Syntax != nil { - p.spec.Syntax = spec.ApiSyntax{Version: p.ast.Syntax.Version.Text()} + p.spec.Syntax = spec.ApiSyntax{ + Version: p.ast.Syntax.Version.Text(), + Doc: p.stringExprs(p.ast.Syntax.DocExpr), + Comment: p.stringExprs([]ast.Expr{p.ast.Syntax.CommentExpr}), + } } } func (p parser) fillImport() { if len(p.ast.Import) > 0 { for _, item := range p.ast.Import { - p.spec.Imports = append(p.spec.Imports, spec.Import{Value: item.Value.Text()}) + p.spec.Imports = append(p.spec.Imports, spec.Import{ + Value: item.Value.Text(), + Doc: p.stringExprs(item.DocExpr), + Comment: p.stringExprs([]ast.Expr{item.CommentExpr}), + }) } } } @@ -173,10 +181,14 @@ func (p parser) astTypeToSpec(in ast.DataType) spec.Type { case *ast.Literal: raw := v.Literal.Text() if api.IsBasicType(raw) { - return spec.PrimitiveType{RawName: raw} + return spec.PrimitiveType{ + RawName: raw, + } } - return spec.DefineStruct{RawName: raw} + return spec.DefineStruct{ + RawName: raw, + } case *ast.Interface: return spec.InterfaceType{RawName: v.Literal.Text()} case *ast.Map: @@ -198,6 +210,9 @@ func (p parser) astTypeToSpec(in ast.DataType) spec.Type { func (p parser) stringExprs(docs []ast.Expr) []string { var result []string for _, item := range docs { + if item == nil { + continue + } result = append(result, item.Text()) } return result @@ -222,9 +237,13 @@ func (p parser) fillService() error { AtServerAnnotation: spec.Annotation{}, Method: astRoute.Route.Method.Text(), Path: astRoute.Route.Path.Text(), + Doc: p.stringExprs(astRoute.Route.DocExpr), + Comment: p.stringExprs([]ast.Expr{astRoute.Route.CommentExpr}), } if astRoute.AtHandler != nil { route.Handler = astRoute.AtHandler.Name.Text() + route.HandlerDoc = append(route.HandlerDoc, p.stringExprs(astRoute.AtHandler.DocExpr)...) + route.HandlerComment = append(route.HandlerComment, p.stringExprs([]ast.Expr{astRoute.AtHandler.CommentExpr})...) } err := p.fillRouteAtServer(astRoute, &route) diff --git a/tools/goctl/api/parser/parser_test.go b/tools/goctl/api/parser/parser_test.go new file mode 100644 index 00000000..95c4dbb9 --- /dev/null +++ b/tools/goctl/api/parser/parser_test.go @@ -0,0 +1,28 @@ +package parser + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/tal-tech/go-zero/tools/goctl/api/spec" +) + +var testApi = "// syntax doc\nsyntax = \"v1\" // syntax comment\n\n// type doc\ntype Request {\n\tName string `path:\"name,options=you|me\"`\n}\n\ntype Response {\n\tMessage string `json:\"message\"`\n}\n\n// service doc\nservice greet-api {\n\t// handler doc\n\t@handler GreetHandler // handler comment\n\tget /from/:name(Request) returns (Response);\n}" + +func TestParseContent(t *testing.T) { + sp, err := ParseContent(testApi) + assert.Nil(t, err) + assert.Equal(t, spec.Doc{`// syntax doc`}, sp.Syntax.Doc) + assert.Equal(t, spec.Doc{`// syntax comment`}, sp.Syntax.Comment) + for _, tp := range sp.Types { + if tp.Name() == "Request" { + assert.Equal(t, []string{`// type doc`}, tp.Documents()) + } + } + for _, e := range sp.Service.Routes() { + if e.Handler == "GreetHandler" { + assert.Equal(t, spec.Doc{"// handler doc"}, e.HandlerDoc) + assert.Equal(t, spec.Doc{"// handler comment"}, e.HandlerComment) + } + } +} diff --git a/tools/goctl/api/spec/name.go b/tools/goctl/api/spec/name.go index eea0d558..37ec72f4 100644 --- a/tools/goctl/api/spec/name.go +++ b/tools/goctl/api/spec/name.go @@ -5,27 +5,87 @@ func (t PrimitiveType) Name() string { return t.RawName } +// Comments returns the comments of struct +func (t PrimitiveType) Comments() []string { + return nil +} + +// Documents returns the documents of struct +func (t PrimitiveType) Documents() []string { + return nil +} + // Name returns a structure string, such as User func (t DefineStruct) Name() string { return t.RawName } +// Comments returns the comments of struct +func (t DefineStruct) Comments() []string { + return nil +} + +// Documents returns the documents of struct +func (t DefineStruct) Documents() []string { + return t.Docs +} + // Name returns a map string, such as map[string]int func (t MapType) Name() string { return t.RawName } +// Comments returns the comments of struct +func (t MapType) Comments() []string { + return nil +} + +// Documents returns the documents of struct +func (t MapType) Documents() []string { + return nil +} + // Name returns a slice string, such as []int func (t ArrayType) Name() string { return t.RawName } +// Comments returns the comments of struct +func (t ArrayType) Comments() []string { + return nil +} + +// Documents returns the documents of struct +func (t ArrayType) Documents() []string { + return nil +} + // Name returns a pointer string, such as *User func (t PointerType) Name() string { return t.RawName } +// Comments returns the comments of struct +func (t PointerType) Comments() []string { + return nil +} + +// Documents returns the documents of struct +func (t PointerType) Documents() []string { + return nil +} + // Name returns a interface string, Its fixed value is interface{} func (t InterfaceType) Name() string { return t.RawName } + +// Comments returns the comments of struct +func (t InterfaceType) Comments() []string { + return nil +} + +// Documents returns the documents of struct +func (t InterfaceType) Documents() []string { + return nil +} diff --git a/tools/goctl/api/spec/spec.go b/tools/goctl/api/spec/spec.go index b1c8d01a..1399b6b0 100644 --- a/tools/goctl/api/spec/spec.go +++ b/tools/goctl/api/spec/spec.go @@ -12,6 +12,8 @@ type ( // ApiSyntax describes the syntax grammar ApiSyntax struct { Version string + Doc Doc + Comment Doc } // ApiSpec describes a api file @@ -25,7 +27,9 @@ type ( // Import describes api import Import struct { - Value string + Value string + Doc Doc + Comment Doc } // Group defines a set of routing information @@ -71,6 +75,10 @@ type ( Docs Doc Handler string AtDoc AtDoc + HandlerDoc Doc + HandlerComment Doc + Doc Doc + Comment Doc } // Service describes api service @@ -82,6 +90,8 @@ type ( // Type defines api type Type interface { Name() string + Comments() []string + Documents() []string } // DefineStruct describes api structure