diff --git a/tools/goctl/pkg/parser/api/parser/parser.go b/tools/goctl/pkg/parser/api/parser/parser.go index 5876697e4b129..5cbc29432bb72 100644 --- a/tools/goctl/pkg/parser/api/parser/parser.go +++ b/tools/goctl/pkg/parser/api/parser/parser.go @@ -385,6 +385,9 @@ func (p *Parser) parsePathExpr() *ast.PathExpr { } values = append(values, p.curTok) + if p.peekTokenIs(token.LPAREN, token.Returns, token.AT_DOC, token.AT_HANDLER, token.SEMICOLON, token.RBRACE){ + break + } if p.notExpectPeekTokenGotComment(p.curTokenNode().PeekFirstLeadingComment(), token.COLON, token.IDENT, token.INT) { return nil } diff --git a/tools/goctl/pkg/parser/api/parser/parser_test.go b/tools/goctl/pkg/parser/api/parser/parser_test.go index 9fac7a5f6e05e..c37b03a751e5b 100644 --- a/tools/goctl/pkg/parser/api/parser/parser_test.go +++ b/tools/goctl/pkg/parser/api/parser/parser_test.go @@ -521,6 +521,19 @@ func TestParser_Parse_service(t *testing.T) { LBrace: ast.NewTokenNode(token.Token{Type: token.LBRACE, Text: "{"}), RBrace: ast.NewTokenNode(token.Token{Type: token.RBRACE, Text: "}"}), Routes: []*ast.ServiceItemStmt{ + { + AtHandler: &ast.AtHandlerStmt{ + AtHandler: ast.NewTokenNode(token.Token{Type: token.AT_HANDLER, Text: "@handler"}), + Name: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "root"}), + }, + Route: &ast.RouteStmt{ + Method: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "get"}), + Path: &ast.PathExpr{Value: ast.NewTokenNode(token.Token{ + Type: token.PATH, + Text: "/", + })}, + }, + }, { AtHandler: &ast.AtHandlerStmt{ AtHandler: ast.NewTokenNode(token.Token{Type: token.AT_HANDLER, Text: "@handler"}), @@ -557,6 +570,93 @@ func TestParser_Parse_service(t *testing.T) { LBrace: ast.NewTokenNode(token.Token{Type: token.LBRACE, Text: "{"}), RBrace: ast.NewTokenNode(token.Token{Type: token.RBRACE, Text: "}"}), Routes: []*ast.ServiceItemStmt{ + { + AtDoc: &ast.AtDocLiteralStmt{ + AtDoc: ast.NewTokenNode(token.Token{Type: token.AT_DOC, Text: "@doc"}), + Value: ast.NewTokenNode(token.Token{Type: token.STRING, Text: `"bar"`}), + }, + AtHandler: &ast.AtHandlerStmt{ + AtHandler: ast.NewTokenNode(token.Token{Type: token.AT_HANDLER, Text: "@handler"}), + Name: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "root"}), + }, + Route: &ast.RouteStmt{ + Method: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "get"}), + Path: &ast.PathExpr{ + Value: ast.NewTokenNode(token.Token{ + Type: token.PATH, + Text: "/", + }), + }, + Request: &ast.BodyStmt{ + LParen: ast.NewTokenNode(token.Token{Type: token.LPAREN, Text: "("}), + Body: &ast.BodyExpr{ + Value: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "Foo"}), + }, + RParen: ast.NewTokenNode(token.Token{Type: token.RPAREN, Text: ")"}), + }, + }, + }, + { + AtDoc: &ast.AtDocLiteralStmt{ + AtDoc: ast.NewTokenNode(token.Token{Type: token.AT_DOC, Text: "@doc"}), + Value: ast.NewTokenNode(token.Token{Type: token.STRING, Text: `"bar"`}), + }, + AtHandler: &ast.AtHandlerStmt{ + AtHandler: ast.NewTokenNode(token.Token{Type: token.AT_HANDLER, Text: "@handler"}), + Name: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "root2"}), + }, + Route: &ast.RouteStmt{ + Method: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "get"}), + Path: &ast.PathExpr{ + Value: ast.NewTokenNode(token.Token{ + Type: token.PATH, + Text: "/", + }), + }, + Returns: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "returns"}), + Response: &ast.BodyStmt{ + LParen: ast.NewTokenNode(token.Token{Type: token.LPAREN, Text: "("}), + Body: &ast.BodyExpr{ + Value: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "Foo"}), + }, + RParen: ast.NewTokenNode(token.Token{Type: token.RPAREN, Text: ")"}), + }, + }, + }, + { + AtDoc: &ast.AtDocLiteralStmt{ + AtDoc: ast.NewTokenNode(token.Token{Type: token.AT_DOC, Text: "@doc"}), + Value: ast.NewTokenNode(token.Token{Type: token.STRING, Text: `"bar"`}), + }, + AtHandler: &ast.AtHandlerStmt{ + AtHandler: ast.NewTokenNode(token.Token{Type: token.AT_HANDLER, Text: "@handler"}), + Name: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "root3"}), + }, + Route: &ast.RouteStmt{ + Method: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "get"}), + Path: &ast.PathExpr{ + Value: ast.NewTokenNode(token.Token{ + Type: token.PATH, + Text: "/", + }), + }, + Request: &ast.BodyStmt{ + LParen: ast.NewTokenNode(token.Token{Type: token.LPAREN, Text: "("}), + Body: &ast.BodyExpr{ + Value: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "Foo"}), + }, + RParen: ast.NewTokenNode(token.Token{Type: token.RPAREN, Text: ")"}), + }, + Returns: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "returns"}), + Response: &ast.BodyStmt{ + LParen: ast.NewTokenNode(token.Token{Type: token.LPAREN, Text: "("}), + Body: &ast.BodyExpr{ + Value: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "Bar"}), + }, + RParen: ast.NewTokenNode(token.Token{Type: token.RPAREN, Text: ")"}), + }, + }, + }, { AtDoc: &ast.AtDocLiteralStmt{ AtDoc: ast.NewTokenNode(token.Token{Type: token.AT_DOC, Text: "@doc"}), diff --git a/tools/goctl/pkg/parser/api/parser/testdata/example.api b/tools/goctl/pkg/parser/api/parser/testdata/example.api index ff76d6bc8d89a..97ff1dd81d92c 100644 --- a/tools/goctl/pkg/parser/api/parser/testdata/example.api +++ b/tools/goctl/pkg/parser/api/parser/testdata/example.api @@ -93,6 +93,12 @@ type ( NestDemoResp2 { *Nest `json:"nest"` } + RootReq{ + + } + RootResp{ + + } ) @server ( @@ -130,6 +136,9 @@ service example { ) @handler postPath post /example/path (PostPathReq) returns (PostPathResp) + + @handler root + post / (RootReq) returns (RootResp) } @server ( diff --git a/tools/goctl/pkg/parser/api/parser/testdata/service_test.api b/tools/goctl/pkg/parser/api/parser/testdata/service_test.api index f967e7312c61e..7d9323d3cb3a3 100644 --- a/tools/goctl/pkg/parser/api/parser/testdata/service_test.api +++ b/tools/goctl/pkg/parser/api/parser/testdata/service_test.api @@ -1,4 +1,7 @@ service foo { + @handler root + get / + @handler bar get /ping @@ -7,6 +10,18 @@ service foo { } service bar { + @doc "bar" + @handler root + get / (Foo) + + @doc "bar" + @handler root2 + get / returns (Foo) + + @doc "bar" + @handler root3 + get / (Foo) returns (Bar) + @doc "bar" @handler foo get /foo/:bar (Foo)