From 3331954a7824523cbed9a771753f9b88d840afff Mon Sep 17 00:00:00 2001 From: kesonan Date: Mon, 29 Jan 2024 21:05:08 +0800 Subject: [PATCH] (goctl): fix unresolved type if linked api imported (#3881) --- tools/goctl/pkg/parser/api/parser/analyzer.go | 3 +++ .../goctl/pkg/parser/api/parser/analyzer_test.go | 4 ++++ tools/goctl/pkg/parser/api/parser/api.go | 15 ++++++--------- tools/goctl/pkg/parser/api/parser/filter.go | 9 ++++++--- .../parser/api/parser/testdata/base/request.api | 6 ++++++ .../parser/api/parser/testdata/base/response.api | 10 ++++++++++ .../parser/api/parser/testdata/link_import.api | 12 ++++++++++++ 7 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 tools/goctl/pkg/parser/api/parser/testdata/base/request.api create mode 100644 tools/goctl/pkg/parser/api/parser/testdata/base/response.api create mode 100644 tools/goctl/pkg/parser/api/parser/testdata/link_import.api diff --git a/tools/goctl/pkg/parser/api/parser/analyzer.go b/tools/goctl/pkg/parser/api/parser/analyzer.go index 236630e4..a08974a9 100644 --- a/tools/goctl/pkg/parser/api/parser/analyzer.go +++ b/tools/goctl/pkg/parser/api/parser/analyzer.go @@ -403,6 +403,9 @@ func Parse(filename string, src interface{}) (*spec.ApiSpec, error) { if err != nil { return nil, err } + if err := api.SelfCheck(); err != nil { + return nil, err + } var result = new(spec.ApiSpec) analyzer := Analyzer{ diff --git a/tools/goctl/pkg/parser/api/parser/analyzer_test.go b/tools/goctl/pkg/parser/api/parser/analyzer_test.go index de4193b6..5e01d0f4 100644 --- a/tools/goctl/pkg/parser/api/parser/analyzer_test.go +++ b/tools/goctl/pkg/parser/api/parser/analyzer_test.go @@ -42,4 +42,8 @@ func Test_Parse(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) + }) } diff --git a/tools/goctl/pkg/parser/api/parser/api.go b/tools/goctl/pkg/parser/api/parser/api.go index 6fc5584b..69d33b40 100644 --- a/tools/goctl/pkg/parser/api/parser/api.go +++ b/tools/goctl/pkg/parser/api/parser/api.go @@ -85,15 +85,12 @@ func convert2API(a *ast.AST, importSet map[string]lang.PlaceholderType, is *impo } } - if err := api.SelfCheck(); err != nil { - return nil, err - } return api, nil } func (api *API) checkImportStmt() error { f := newFilter() - b := f.addCheckItem("import value expression") + b := f.addCheckItem(api.Filename, "import value expression") for _, v := range api.importStmt { switch val := v.(type) { case *ast.ImportLiteralStmt: @@ -110,7 +107,7 @@ func (api *API) checkInfoStmt() error { return nil } f := newFilter() - b := f.addCheckItem("info key expression") + b := f.addCheckItem(api.Filename, "info key expression") for _, v := range api.info.Values { b.check(v.Key) } @@ -119,9 +116,9 @@ func (api *API) checkInfoStmt() error { func (api *API) checkServiceStmt() error { f := newFilter() - serviceNameChecker := f.addCheckItem("service name expression") - handlerChecker := f.addCheckItem("handler expression") - pathChecker := f.addCheckItem("path expression") + serviceNameChecker := f.addCheckItem(api.Filename, "service name expression") + handlerChecker := f.addCheckItem(api.Filename, "handler expression") + pathChecker := f.addCheckItem(api.Filename, "path expression") var serviceName = map[string]string{} for _, v := range api.ServiceStmts { name := strings.TrimSuffix(v.Name.Format(""), "-api") @@ -150,7 +147,7 @@ func (api *API) checkServiceStmt() error { func (api *API) checkTypeStmt() error { f := newFilter() - b := f.addCheckItem("type expression") + b := f.addCheckItem(api.Filename, "type expression") for _, v := range api.TypeStmt { switch val := v.(type) { case *ast.TypeLiteralStmt: diff --git a/tools/goctl/pkg/parser/api/parser/filter.go b/tools/goctl/pkg/parser/api/parser/filter.go index fd0ce0ae..b660f271 100644 --- a/tools/goctl/pkg/parser/api/parser/filter.go +++ b/tools/goctl/pkg/parser/api/parser/filter.go @@ -8,6 +8,7 @@ import ( ) type filterBuilder struct { + filename string m map[string]placeholder.Type checkExprName string errorManager *errorManager @@ -15,10 +16,11 @@ type filterBuilder struct { func (b *filterBuilder) check(nodes ...*ast.TokenNode) { for _, node := range nodes { - if _, ok := b.m[node.Token.Text]; ok { + fileNodeText := fmt.Sprintf("%s/%s", b.filename, node.Token.Text) + if _, ok := b.m[fileNodeText]; ok { b.errorManager.add(ast.DuplicateStmtError(node.Pos(), "duplicate "+b.checkExprName)) } else { - b.m[node.Token.Text] = placeholder.PlaceHolder + b.m[fileNodeText] = placeholder.PlaceHolder } } } @@ -46,8 +48,9 @@ func newFilter() *filter { return &filter{} } -func (f *filter) addCheckItem(checkExprName string) *filterBuilder { +func (f *filter) addCheckItem(filename, checkExprName string) *filterBuilder { b := &filterBuilder{ + filename: filename, m: make(map[string]placeholder.Type), checkExprName: checkExprName, errorManager: newErrorManager(), diff --git a/tools/goctl/pkg/parser/api/parser/testdata/base/request.api b/tools/goctl/pkg/parser/api/parser/testdata/base/request.api new file mode 100644 index 00000000..fc1f3ac9 --- /dev/null +++ b/tools/goctl/pkg/parser/api/parser/testdata/base/request.api @@ -0,0 +1,6 @@ +syntax = "v1" + +type Baz { + Foo string `json:"foo"` + Baz bool `json:"bar"` +} diff --git a/tools/goctl/pkg/parser/api/parser/testdata/base/response.api b/tools/goctl/pkg/parser/api/parser/testdata/base/response.api new file mode 100644 index 00000000..83091190 --- /dev/null +++ b/tools/goctl/pkg/parser/api/parser/testdata/base/response.api @@ -0,0 +1,10 @@ +syntax = "v1" + +import "request.api" +type Bar { + Foo int `json:"foo"` + Bar bool `json:"bar"` + Baz + Qux map[string]string `json:"qux"` +} + diff --git a/tools/goctl/pkg/parser/api/parser/testdata/link_import.api b/tools/goctl/pkg/parser/api/parser/testdata/link_import.api new file mode 100644 index 00000000..fb08003f --- /dev/null +++ b/tools/goctl/pkg/parser/api/parser/testdata/link_import.api @@ -0,0 +1,12 @@ +syntax = "v1" + +import "base/request.api" +import "base/response.api" + +type Foo {} + +service demo { + @handler handlerName + get /users/id/:userId (Baz) returns (Bar) +} +