From d6d8fc21d8e1eff27de7e3fbb0a54bfdae8bbe15 Mon Sep 17 00:00:00 2001 From: kingxt Date: Tue, 17 Nov 2020 18:08:55 +0800 Subject: [PATCH] type should not define nested (#212) * nest type should not supported * nest type should not supported * nest type should not supported * nest type should not supported * new test * new test --- tools/goctl/api/format/format.go | 45 ++++++++++++++++++++----- tools/goctl/api/format/format_test.go | 3 +- tools/goctl/api/gogen/gen_test.go | 32 ++++++++++++++++-- tools/goctl/api/parser/apifileparser.go | 24 +++++++++++-- tools/goctl/api/util/util.go | 13 ------- 5 files changed, 88 insertions(+), 29 deletions(-) diff --git a/tools/goctl/api/format/format.go b/tools/goctl/api/format/format.go index 645af2c5..0c8940a8 100644 --- a/tools/goctl/api/format/format.go +++ b/tools/goctl/api/format/format.go @@ -11,10 +11,18 @@ import ( "strings" "github.com/tal-tech/go-zero/core/errorx" + "github.com/tal-tech/go-zero/tools/goctl/api/parser" "github.com/tal-tech/go-zero/tools/goctl/api/util" "github.com/urfave/cli" ) +const ( + leftParenthesis = "(" + rightParenthesis = ")" + leftBrace = "{" + rightBrace = "}" +) + func GoFormatApi(c *cli.Context) error { useStdin := c.Bool("stdin") @@ -57,7 +65,10 @@ func ApiFormatByStdin() error { return err } - result := apiFormat(string(data)) + result, err := apiFormat(string(data)) + if err != nil { + return err + } _, err = fmt.Print(result) if err != nil { @@ -72,28 +83,44 @@ func ApiFormatByPath(apiFilePath string) error { return err } - result := apiFormat(string(data)) + result, err := apiFormat(string(data)) + if err != nil { + return err + } + if err := ioutil.WriteFile(apiFilePath, []byte(result), os.ModePerm); err != nil { return err } return nil } -func apiFormat(data string) string { +func apiFormat(data string) (string, error) { + _, err := parser.ParseApi(data) + if err != nil { + return "", err + } + var builder strings.Builder - scanner := bufio.NewScanner(strings.NewReader(data)) + s := bufio.NewScanner(strings.NewReader(data)) var tapCount = 0 - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) + for s.Scan() { + line := strings.TrimSpace(s.Text()) noCommentLine := util.RemoveComment(line) - if noCommentLine == ")" || noCommentLine == "}" { + if noCommentLine == rightParenthesis || noCommentLine == rightBrace { tapCount -= 1 } + if tapCount < 0 { + line = strings.TrimSuffix(line, rightBrace) + line = strings.TrimSpace(line) + if strings.HasSuffix(line, leftBrace) { + tapCount += 1 + } + } util.WriteIndent(&builder, tapCount) builder.WriteString(line + "\n") - if strings.HasSuffix(noCommentLine, "(") || strings.HasSuffix(noCommentLine, "{") { + if strings.HasSuffix(noCommentLine, leftParenthesis) || strings.HasSuffix(noCommentLine, leftBrace) { tapCount += 1 } } - return strings.TrimSpace(builder.String()) + return strings.TrimSpace(builder.String()), nil } diff --git a/tools/goctl/api/format/format_test.go b/tools/goctl/api/format/format_test.go index 77701c35..a0f9444a 100644 --- a/tools/goctl/api/format/format_test.go +++ b/tools/goctl/api/format/format_test.go @@ -41,6 +41,7 @@ service A-api { ) func TestInlineTypeNotExist(t *testing.T) { - r := apiFormat(notFormattedStr) + r, err := apiFormat(notFormattedStr) + assert.Nil(t, err) assert.Equal(t, r, formattedStr) } diff --git a/tools/goctl/api/gogen/gen_test.go b/tools/goctl/api/gogen/gen_test.go index 8f984daf..8f15408c 100644 --- a/tools/goctl/api/gogen/gen_test.go +++ b/tools/goctl/api/gogen/gen_test.go @@ -288,13 +288,16 @@ type Request { Name string ` + "`" + `path:"name,options=you|me"` + "`" + ` } -type XXX { -} +type XXX {} type ( Response { Message string ` + "`" + `json:"message"` + "`" + ` } + + A {} + + B struct {} ) service A-api { @@ -303,6 +306,19 @@ service A-api { } ` +const nestTypeApi = ` +type Request { + Name string ` + "`" + `path:"name,options=you|me"` + "`" + ` + XXX struct { + } +} + +service A-api { + @handler GreetHandler + get /greet/from/:name(Request) +} +` + func TestParser(t *testing.T) { filename := "greet.api" err := ioutil.WriteFile(filename, []byte(testApiTemplate), os.ModePerm) @@ -532,11 +548,21 @@ func TestNoStructApi(t *testing.T) { spec, err := parser.Parse() assert.Nil(t, err) - assert.Equal(t, len(spec.Types), 3) + assert.Equal(t, len(spec.Types), 5) validate(t, filename) } +func TestNestTypeApi(t *testing.T) { + filename := "greet.api" + err := ioutil.WriteFile(filename, []byte(nestTypeApi), os.ModePerm) + assert.Nil(t, err) + defer os.Remove(filename) + + _, err = parser.NewParser(filename) + assert.NotNil(t, err) +} + func validate(t *testing.T, api string) { dir := "_go" os.RemoveAll(dir) diff --git a/tools/goctl/api/parser/apifileparser.go b/tools/goctl/api/parser/apifileparser.go index 5d5db3e2..26320cf6 100644 --- a/tools/goctl/api/parser/apifileparser.go +++ b/tools/goctl/api/parser/apifileparser.go @@ -154,6 +154,7 @@ func (s *apiImportState) process(api *ApiStruct, token string) (apiFileState, er func (s *apiTypeState) process(api *ApiStruct, token string) (apiFileState, error) { var blockCount = 0 + var braceCount = 0 for { line, err := s.readLine() if err != nil { @@ -161,7 +162,7 @@ func (s *apiTypeState) process(api *ApiStruct, token string) (apiFileState, erro } line = token + line - if blockCount <= 1 { + if braceCount == 0 { line = mayInsertStructKeyword(line) } api.Type += newline + newline + line @@ -171,17 +172,31 @@ func (s *apiTypeState) process(api *ApiStruct, token string) (apiFileState, erro if strings.HasSuffix(line, leftBrace) { blockCount++ + braceCount++ } if strings.HasSuffix(line, string(leftParenthesis)) { blockCount++ } if strings.HasSuffix(line, string(rightBrace)) { blockCount-- + braceCount-- } if strings.HasSuffix(line, string(rightParenthesis)) { blockCount-- } + if braceCount >= 2 { + return nil, errors.New("nested type not supported: " + line) + } + if braceCount < 0 { + line = strings.TrimSuffix(line, string(rightBrace)) + line = strings.TrimSpace(line) + if strings.HasSuffix(line, leftBrace) { + blockCount++ + braceCount++ + } + } + if blockCount == 0 { return &apiRootState{s.baseState}, nil } @@ -223,12 +238,15 @@ func (s *apiServiceState) process(api *ApiStruct, token string) (apiFileState, e func mayInsertStructKeyword(line string) string { line = util.RemoveComment(line) - if !strings.HasSuffix(line, leftBrace) { + if !strings.HasSuffix(line, leftBrace) && !strings.HasSuffix(line, string(rightBrace)) { return line } fields := strings.Fields(line) - if stringx.Contains(fields, tokenStruct) || stringx.Contains(fields, tokenStruct+leftBrace) || len(fields) <= 1 { + if stringx.Contains(fields, tokenStruct) || + stringx.Contains(fields, tokenStruct+leftBrace) || + stringx.Contains(fields, tokenStruct+leftBrace+string(rightBrace)) || + len(fields) <= 1 { return line } diff --git a/tools/goctl/api/util/util.go b/tools/goctl/api/util/util.go index 12f8a994..2377ef5e 100644 --- a/tools/goctl/api/util/util.go +++ b/tools/goctl/api/util/util.go @@ -26,19 +26,6 @@ func MaybeCreateFile(dir, subdir, file string) (fp *os.File, created bool, err e return } -func ClearAndOpenFile(fpath string) (*os.File, error) { - f, err := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0600) - if err != nil { - return nil, err - } - - _, err = f.WriteString("") - if err != nil { - return nil, err - } - return f, nil -} - func WrapErr(err error, message string) error { return errors.New(message + ", " + err.Error()) }