fix(goctl): allow duplicate_path_expression under different prefix (#4626)

This commit is contained in:
youzipi
2025-02-07 16:37:11 +08:00
committed by GitHub
parent 396393b336
commit e347d3f8f8
6 changed files with 171 additions and 78 deletions

View File

@@ -14,69 +14,97 @@ import (
)
func Test_Parse(t *testing.T) {
t.Run("valid", func(t *testing.T) {
apiSpec, err := Parse("./testdata/example.api", nil)
assert.Nil(t, err)
ast := assert.New(t)
ast.Equal(spec.Info{
Title: "type title here",
Desc: "type desc here",
Version: "type version here",
Author: "type author here",
Email: "type email here",
Properties: map[string]string{
"title": "type title here",
"desc": "type desc here",
"version": "type version here",
"author": "type author here",
"email": "type email here",
},
}, apiSpec.Info)
ast.True(func() bool {
for _, group := range apiSpec.Service.Groups {
value, ok := group.Annotation.Properties["summary"]
if ok {
return value == "test"
}
}
return false
}())
})
t.Run(
"valid", func(t *testing.T) {
apiSpec, err := Parse("./testdata/example.api", nil)
assert.Nil(t, err)
ast := assert.New(t)
ast.Equal(
spec.Info{
Title: "type title here",
Desc: "type desc here",
Version: "type version here",
Author: "type author here",
Email: "type email here",
Properties: map[string]string{
"title": "type title here",
"desc": "type desc here",
"version": "type version here",
"author": "type author here",
"email": "type email here",
},
}, apiSpec.Info,
)
ast.True(
func() bool {
for _, group := range apiSpec.Service.Groups {
value, ok := group.Annotation.Properties["summary"]
if ok {
return value == "test"
}
}
return false
}(),
)
},
)
t.Run("invalid", func(t *testing.T) {
data, err := os.ReadFile("./testdata/invalid.api")
assert.NoError(t, err)
splits := bytes.Split(data, []byte("-----"))
var testFile []string
for idx, split := range splits {
replacer := strings.NewReplacer(" ", "", "\t", "", "\n", "", "\r", "", "\f", "")
r := replacer.Replace(string(split))
if len(r) == 0 {
continue
}
filename := filepath.Join(t.TempDir(), fmt.Sprintf("invalid%d.api", idx))
err := os.WriteFile(filename, split, 0666)
t.Run(
"invalid", func(t *testing.T) {
data, err := os.ReadFile("./testdata/invalid.api")
assert.NoError(t, err)
testFile = append(testFile, filename)
}
for _, v := range testFile {
_, err := Parse(v, nil)
splits := bytes.Split(data, []byte("-----"))
var testFile []string
for idx, split := range splits {
replacer := strings.NewReplacer(" ", "", "\t", "", "\n", "", "\r", "", "\f", "")
r := replacer.Replace(string(split))
if len(r) == 0 {
continue
}
filename := filepath.Join(t.TempDir(), fmt.Sprintf("invalid%d.api", idx))
err := os.WriteFile(filename, split, 0666)
assert.NoError(t, err)
testFile = append(testFile, filename)
}
for _, v := range testFile {
_, err := Parse(v, nil)
assertx.Error(t, err)
}
},
)
t.Run(
"circleImport", func(t *testing.T) {
_, err := Parse("./testdata/base.api", nil)
assertx.Error(t, err)
}
})
},
)
t.Run("circleImport", func(t *testing.T) {
_, err := Parse("./testdata/base.api", nil)
assertx.Error(t, err)
})
t.Run(
"link_import", func(t *testing.T) {
_, err := Parse("./testdata/link_import.api", nil)
assert.Nil(t, err)
},
)
t.Run("link_import", func(t *testing.T) {
_, err := Parse("./testdata/link_import.api", nil)
assert.Nil(t, err)
})
t.Run(
"duplicate_types", func(t *testing.T) {
_, err := Parse("./testdata/duplicate_type.api", nil)
assertx.Error(t, err)
},
)
t.Run("duplicate_types", func(t *testing.T) {
_, err := Parse("./testdata/duplicate_type.api", nil)
assertx.Error(t, err)
})
t.Run(
"duplicate_path_expression", func(t *testing.T) {
_, err := Parse("./testdata/duplicate_path_expression.api", nil)
assertx.Error(t, err)
},
)
t.Run(
"duplicate_path_expression_different_prefix", func(t *testing.T) {
_, err := Parse("./testdata/duplicate_path_expression_different_prefix.api", nil)
assert.Nil(t, err)
},
)
}

View File

@@ -13,8 +13,8 @@ import (
)
const (
atServerGroupKey = "group:"
atServerPrefixKey = "prefix:"
atServerGroupKey = "group"
atServerPrefixKey = "prefix"
)
// API is the parsed api file.
@@ -38,18 +38,24 @@ func convert2API(a *ast.AST, importSet map[string]lang.PlaceholderType, is *impo
syntax, ok := one.(*ast.SyntaxStmt)
if !ok {
syntax = &ast.SyntaxStmt{
Syntax: ast.NewTokenNode(token.Token{
Type: token.IDENT,
Text: token.Syntax,
}),
Assign: ast.NewTokenNode(token.Token{
Type: token.ASSIGN,
Text: "=",
}),
Value: ast.NewTokenNode(token.Token{
Type: token.STRING,
Text: `"v1"`,
}),
Syntax: ast.NewTokenNode(
token.Token{
Type: token.IDENT,
Text: token.Syntax,
},
),
Assign: ast.NewTokenNode(
token.Token{
Type: token.ASSIGN,
Text: "=",
},
),
Value: ast.NewTokenNode(
token.Token{
Type: token.STRING,
Text: `"v1"`,
},
),
}
}
@@ -133,10 +139,14 @@ func (api *API) checkServiceStmt() error {
for _, item := range v.Routes {
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(),
}))
pathChecker.check(
ast.NewTokenNode(
token.Token{
Text: path,
Position: item.Route.Pos(),
},
),
)
}
}
return f.error()
@@ -237,7 +247,8 @@ func (api *API) getAtServerValue(atServer *ast.AtServerStmt, key string) string
func (api *API) mergeAPI(in *API) error {
if api.Syntax.Value.Format() != in.Syntax.Value.Format() {
return ast.SyntaxError(in.Syntax.Value.Pos(),
return ast.SyntaxError(
in.Syntax.Value.Pos(),
"multiple syntax value expression, expected <%s>, got <%s>",
api.Syntax.Value.Format(),
in.Syntax.Value.Format(),

View File

@@ -0,0 +1,21 @@
syntax = "v1"
@server (
group: path2
middleware: Path
prefix: /v1/v3
timeout: 100ms
)
service example {
@doc (
desc: "path demo"
)
@handler getPath1
get / (string) returns (string)
@doc (
desc: "path demo"
)
@handler getPath2
get / (string) returns (string)
}

View File

@@ -0,0 +1,2 @@
import "duplicate_path_expression_different_prefix__prefix_1.api"
import "duplicate_path_expression_different_prefix__prefix_2.api"

View File

@@ -0,0 +1,16 @@
syntax = "v1"
@server (
group: group2
middleware: Path
prefix: /v1/group2
timeout: 100ms
)
service example {
@doc (
desc: "path demo"
)
@handler getPath2
get / (string) returns (string)
}

View File

@@ -0,0 +1,15 @@
syntax = "v1"
@server (
group: group1
middleware: Path
prefix: /v1/group1
timeout: 100ms
)
service example {
@doc (
desc: "path demo"
)
@handler getPath1
get / (string) returns (string)
}