From c55694d957517b459faadbd70faf6324a16054e3 Mon Sep 17 00:00:00 2001 From: chensy <1278651995@qq.com> Date: Sat, 12 Mar 2022 15:17:31 +0800 Subject: [PATCH] Support for referencing types in different API files using format (#1630) --- tools/goctl/api/format/format.go | 24 ++++++++++++++-------- tools/goctl/api/format/format_test.go | 8 ++++++-- tools/goctl/api/gogen/gen.go | 2 +- tools/goctl/api/parser/g4/ast/apiparser.go | 17 +++++++++++---- tools/goctl/api/parser/parser.go | 20 +++++++++++++++--- tools/goctl/goctl.go | 4 ++++ 6 files changed, 56 insertions(+), 19 deletions(-) diff --git a/tools/goctl/api/format/format.go b/tools/goctl/api/format/format.go index 79672952..02cbd222 100644 --- a/tools/goctl/api/format/format.go +++ b/tools/goctl/api/format/format.go @@ -28,10 +28,11 @@ const ( // GoFormatApi format api file func GoFormatApi(c *cli.Context) error { useStdin := c.Bool("stdin") + skipCheckDeclare := c.Bool("declare") var be errorx.BatchError if useStdin { - if err := apiFormatByStdin(); err != nil { + if err := apiFormatByStdin(skipCheckDeclare); err != nil { be.Add(err) } } else { @@ -47,7 +48,7 @@ func GoFormatApi(c *cli.Context) error { err = filepath.Walk(dir, func(path string, fi os.FileInfo, errBack error) (err error) { if strings.HasSuffix(path, ".api") { - if err := ApiFormatByPath(path); err != nil { + if err := ApiFormatByPath(path, skipCheckDeclare); err != nil { be.Add(util.WrapErr(err, fi.Name())) } } @@ -64,13 +65,13 @@ func GoFormatApi(c *cli.Context) error { return be.Err() } -func apiFormatByStdin() error { +func apiFormatByStdin(skipCheckDeclare bool) error { data, err := ioutil.ReadAll(os.Stdin) if err != nil { return err } - result, err := apiFormat(string(data)) + result, err := apiFormat(string(data), skipCheckDeclare) if err != nil { return err } @@ -80,7 +81,7 @@ func apiFormatByStdin() error { } // ApiFormatByPath format api from file path -func ApiFormatByPath(apiFilePath string) error { +func ApiFormatByPath(apiFilePath string, skipCheckDeclare bool) error { data, err := ioutil.ReadFile(apiFilePath) if err != nil { return err @@ -91,12 +92,12 @@ func ApiFormatByPath(apiFilePath string) error { return err } - result, err := apiFormat(string(data), abs) + result, err := apiFormat(string(data), skipCheckDeclare, abs) if err != nil { return err } - _, err = parser.ParseContent(result, abs) + _, err = parser.ParseContentWithParserSkipCheckTypeDeclaration(result, abs) if err != nil { return err } @@ -104,8 +105,13 @@ func ApiFormatByPath(apiFilePath string) error { return ioutil.WriteFile(apiFilePath, []byte(result), os.ModePerm) } -func apiFormat(data string, filename ...string) (string, error) { - _, err := parser.ParseContent(data, filename...) +func apiFormat(data string, skipCheckDeclare bool, filename ...string) (string, error) { + var err error + if skipCheckDeclare { + _, err = parser.ParseContentWithParserSkipCheckTypeDeclaration(data, filename...) + } else { + _, err = parser.ParseContent(data, filename...) + } if err != nil { return "", err } diff --git a/tools/goctl/api/format/format_test.go b/tools/goctl/api/format/format_test.go index b3d2c64c..57bda187 100644 --- a/tools/goctl/api/format/format_test.go +++ b/tools/goctl/api/format/format_test.go @@ -13,6 +13,7 @@ type Request struct { } type Response struct { Message string ` + "`" + `json:"message"` + "`" + ` + Students []Student ` + "`" + `json:"students"` + "`" + ` } service A-api { @server( @@ -26,7 +27,8 @@ handler: GreetHandler Name string ` + "`" + `path:"name,options=you|me"` + "`" + ` } type Response { - Message string ` + "`" + `json:"message"` + "`" + ` + Message string ` + "`" + `json:"message"` + "`" + ` + Students []Student ` + "`" + `json:"students"` + "`" + ` } service A-api { @server( @@ -37,7 +39,9 @@ service A-api { ) func TestFormat(t *testing.T) { - r, err := apiFormat(notFormattedStr) + r, err := apiFormat(notFormattedStr, true) assert.Nil(t, err) assert.Equal(t, formattedStr, r) + _, err = apiFormat(notFormattedStr, false) + assert.Errorf(t, err, " line 7:13 can not found declaration 'Student' in context") } diff --git a/tools/goctl/api/gogen/gen.go b/tools/goctl/api/gogen/gen.go index 5b767750..14b81fcd 100644 --- a/tools/goctl/api/gogen/gen.go +++ b/tools/goctl/api/gogen/gen.go @@ -86,7 +86,7 @@ func DoGenProject(apiFile, dir, style string) error { return err } - if err := apiformat.ApiFormatByPath(apiFile); err != nil { + if err := apiformat.ApiFormatByPath(apiFile, false); err != nil { return err } diff --git a/tools/goctl/api/parser/g4/ast/apiparser.go b/tools/goctl/api/parser/g4/ast/apiparser.go index 2cb0e21d..b19ba666 100644 --- a/tools/goctl/api/parser/g4/ast/apiparser.go +++ b/tools/goctl/api/parser/g4/ast/apiparser.go @@ -19,7 +19,8 @@ type ( debug bool log console.Console antlr.DefaultErrorListener - src string + src string + skipCheckTypeDeclaration bool } // ParserOption defines an function with argument Parser @@ -136,9 +137,11 @@ func (p *Parser) parse(filename, content string) (*Api, error) { apiAstList = append(apiAstList, nestedApi) } - err = p.checkTypeDeclaration(apiAstList) - if err != nil { - return nil, err + if !p.skipCheckTypeDeclaration { + err = p.checkTypeDeclaration(apiAstList) + if err != nil { + return nil, err + } } allApi := p.memberFill(apiAstList) @@ -483,3 +486,9 @@ func WithParserPrefix(prefix string) ParserOption { p.linePrefix = prefix } } + +func WithParserSkipCheckTypeDeclaration() ParserOption { + return func(p *Parser) { + p.skipCheckTypeDeclaration = true + } +} diff --git a/tools/goctl/api/parser/parser.go b/tools/goctl/api/parser/parser.go index 8469605b..dadfe952 100644 --- a/tools/goctl/api/parser/parser.go +++ b/tools/goctl/api/parser/parser.go @@ -33,9 +33,13 @@ func Parse(filename string) (*spec.ApiSpec, error) { return spec, nil } -// ParseContent parses the api content -func ParseContent(content string, filename ...string) (*spec.ApiSpec, error) { - astParser := ast.NewParser() +func parseContent(content string, skipCheckTypeDeclaration bool, filename ...string) (*spec.ApiSpec, error) { + var astParser *ast.Parser + if skipCheckTypeDeclaration { + astParser = ast.NewParser(ast.WithParserSkipCheckTypeDeclaration()) + } else { + astParser = ast.NewParser() + } ast, err := astParser.ParseContent(content, filename...) if err != nil { return nil, err @@ -51,6 +55,16 @@ func ParseContent(content string, filename ...string) (*spec.ApiSpec, error) { return spec, nil } +// ParseContent parses the api content +func ParseContent(content string, filename ...string) (*spec.ApiSpec, error) { + return parseContent(content, false, filename...) +} + +// ParseContentWithParserSkipCheckTypeDeclaration parses the api content with skip check type declaration +func ParseContentWithParserSkipCheckTypeDeclaration(content string, filename ...string) (*spec.ApiSpec, error) { + return parseContent(content, true, filename...) +} + func (p parser) convert2Spec() error { p.fillInfo() p.fillSyntax() diff --git a/tools/goctl/goctl.go b/tools/goctl/goctl.go index f472b37d..cccf38bd 100644 --- a/tools/goctl/goctl.go +++ b/tools/goctl/goctl.go @@ -160,6 +160,10 @@ var commands = []cli.Command{ Name: "stdin", Usage: "use stdin to input api doc content, press \"ctrl + d\" to send EOF", }, + cli.BoolFlag{ + Name: "declare", + Usage: "use to skip check api types already declare", + }, }, Action: format.GoFormatApi, },