fix(goctl)/new parser (#3834)
Co-authored-by: keson <keson@kesondeMacBook-Pro.local>
This commit is contained in:
@@ -192,7 +192,10 @@ func Test_genPublicModel(t *testing.T) {
|
||||
code, err := g.genModelCustom(*tables[0], false)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, strings.Contains(code, "package model"))
|
||||
assert.True(t, strings.Contains(code, "TestUserModel interface {\n\t\ttestUserModel\n\t}\n"))
|
||||
assert.True(t, strings.Contains(code, ` TestUserModel interface {
|
||||
testUserModel
|
||||
withSession(session sqlx.Session) TestUserModel
|
||||
}`))
|
||||
assert.True(t, strings.Contains(code, "customTestUserModel struct {\n\t\t*defaultTestUserModel\n\t}\n"))
|
||||
assert.True(t, strings.Contains(code, "func NewTestUserModel(conn sqlx.SqlConn) TestUserModel {"))
|
||||
}
|
||||
|
||||
@@ -12,6 +12,11 @@ import (
|
||||
"github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/token"
|
||||
)
|
||||
|
||||
const (
|
||||
atServerGroupKey = "group:"
|
||||
atServerPrefixKey = "prefix:"
|
||||
)
|
||||
|
||||
// API is the parsed api file.
|
||||
type API struct {
|
||||
Filename string
|
||||
@@ -127,10 +132,13 @@ func (api *API) checkServiceStmt() error {
|
||||
} else {
|
||||
serviceName[name] = name
|
||||
}
|
||||
var group = api.getAtServerValue(v.AtServerStmt, "prefix")
|
||||
var (
|
||||
prefix = api.getAtServerValue(v.AtServerStmt, atServerPrefixKey)
|
||||
group = api.getAtServerValue(v.AtServerStmt, atServerGroupKey)
|
||||
)
|
||||
for _, item := range v.Routes {
|
||||
handlerChecker.check(item.AtHandler.Name)
|
||||
path := fmt.Sprintf("[%s]:%s", group, item.Route.Format(""))
|
||||
handlerChecker.checkNodeWithPrefix(group, item.AtHandler.Name)
|
||||
path := fmt.Sprintf("[%s]:%s", prefix, item.Route.Format(""))
|
||||
pathChecker.check(ast.NewTokenNode(token.Token{
|
||||
Text: path,
|
||||
Position: item.Route.Pos(),
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/ast"
|
||||
"github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/placeholder"
|
||||
)
|
||||
@@ -21,6 +23,17 @@ func (b *filterBuilder) check(nodes ...*ast.TokenNode) {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *filterBuilder) checkNodeWithPrefix(prefix string, nodes ...*ast.TokenNode) {
|
||||
for _, node := range nodes {
|
||||
joinText:=fmt.Sprintf("%s/%s",prefix,node.Token.Text)
|
||||
if _, ok := b.m[joinText]; ok {
|
||||
b.errorManager.add(ast.DuplicateStmtError(node.Pos(), "duplicate "+b.checkExprName))
|
||||
} else {
|
||||
b.m[joinText] = placeholder.PlaceHolder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *filterBuilder) error() error {
|
||||
return b.errorManager.error()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"}),
|
||||
|
||||
@@ -93,6 +93,12 @@ type (
|
||||
NestDemoResp2 {
|
||||
*Nest `json:"nest"`
|
||||
}
|
||||
RootReq{
|
||||
|
||||
}
|
||||
RootResp{
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
@server (
|
||||
@@ -124,6 +130,23 @@ service example {
|
||||
prefix: /v1/v2
|
||||
timeout: 100ms
|
||||
)
|
||||
service example {
|
||||
@doc (
|
||||
desc: "path demo"
|
||||
)
|
||||
@handler postPath
|
||||
post /example/path (PostPathReq) returns (PostPathResp)
|
||||
|
||||
@handler root
|
||||
post / (RootReq) returns (RootResp)
|
||||
}
|
||||
|
||||
@server (
|
||||
group: path2
|
||||
middleware: Path
|
||||
prefix: /v1/v3
|
||||
timeout: 100ms
|
||||
)
|
||||
service example {
|
||||
@doc (
|
||||
desc: "path demo"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/token"
|
||||
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -650,7 +651,7 @@ func NewScanner(filename string, src interface{}) (*Scanner, error) {
|
||||
}
|
||||
|
||||
func readData(filename string, src interface{}) ([]byte, error) {
|
||||
if strings.HasSuffix(filename, ".api") {
|
||||
if strings.HasSuffix(filename, ".api") &&pathx.FileExists(filename){
|
||||
data, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user