From b628bc00867e6d0cb23ffa988308d32969d71b01 Mon Sep 17 00:00:00 2001 From: kingxt Date: Tue, 22 Sep 2020 18:32:26 +0800 Subject: [PATCH] goctl support import api file (#94) * rebase upstream * rebase * trim no need line * trim no need line * trim no need line * update doc * remove update * remove no need * remove no need * goctl add jwt support * goctl add jwt support * goctl add jwt support * goctl support import * goctl support import Co-authored-by: kingxt --- tools/goctl/api/format/format.go | 24 ++++++--- tools/goctl/api/parser/parser.go | 41 +++++++++++++--- tools/goctl/api/parser/util.go | 84 ++++++++++++++++++++------------ 3 files changed, 105 insertions(+), 44 deletions(-) diff --git a/tools/goctl/api/format/format.go b/tools/goctl/api/format/format.go index f43d2230..eb9d1326 100644 --- a/tools/goctl/api/format/format.go +++ b/tools/goctl/api/format/format.go @@ -65,16 +65,16 @@ func ApiFormat(path string, printToConsole bool) error { return m }) - info, st, service, err := parser.MatchStruct(r) + apiStruct, err := parser.MatchStruct(r) if err != nil { return err } - info = strings.TrimSpace(info) - if len(service) == 0 || len(st) == 0 { + info := strings.TrimSpace(apiStruct.Info) + if len(apiStruct.Service) == 0 { return nil } - fs, err := format.Source([]byte(strings.TrimSpace(st))) + fs, err := format.Source([]byte(strings.TrimSpace(apiStruct.StructBody))) if err != nil { str := err.Error() lineNumber := strings.Index(str, ":") @@ -93,12 +93,24 @@ func ApiFormat(path string, printToConsole bool) error { return err } - result := strings.Join([]string{info, string(fs), service}, "\n\n") + var result string + if len(strings.TrimSpace(info)) > 0 { + result += strings.TrimSpace(info) + "\n\n" + } + if len(strings.TrimSpace(apiStruct.Imports)) > 0 { + result += strings.TrimSpace(apiStruct.Imports) + "\n\n" + } + if len(strings.TrimSpace(string(fs))) > 0 { + result += strings.TrimSpace(string(fs)) + "\n\n" + } + if len(strings.TrimSpace(apiStruct.Service)) > 0 { + result += strings.TrimSpace(apiStruct.Service) + "\n\n" + } + if printToConsole { _, err := fmt.Print(result) return err } - result = strings.TrimSpace(result) return ioutil.WriteFile(path, []byte(result), os.ModePerm) } diff --git a/tools/goctl/api/parser/parser.go b/tools/goctl/api/parser/parser.go index 04a4f527..d99ccf2b 100644 --- a/tools/goctl/api/parser/parser.go +++ b/tools/goctl/api/parser/parser.go @@ -6,36 +6,61 @@ import ( "fmt" "io" "io/ioutil" + "path/filepath" + "strings" "github.com/tal-tech/go-zero/tools/goctl/api/spec" + "github.com/tal-tech/go-zero/tools/goctl/util" ) type Parser struct { - r *bufio.Reader - st string + r *bufio.Reader + typeDef string } func NewParser(filename string) (*Parser, error) { + apiAbsPath, err := filepath.Abs(filename) + if err != nil { + return nil, err + } + api, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - info, body, service, err := MatchStruct(string(api)) + + apiStruct, err := MatchStruct(string(api)) if err != nil { return nil, err } + for _, item := range strings.Split(apiStruct.Imports, "\n") { + ip := strings.TrimSpace(item) + if len(ip) > 0 { + item := strings.TrimPrefix(item, "import") + item = strings.TrimSpace(item) + var path = item + if !util.FileExists(item) { + path = filepath.Join(filepath.Dir(apiAbsPath), item) + } + content, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + apiStruct.StructBody += "\n" + string(content) + } + } + var buffer = new(bytes.Buffer) - buffer.WriteString(info) - buffer.WriteString(service) + buffer.WriteString(apiStruct.Service) return &Parser{ - r: bufio.NewReader(buffer), - st: body, + r: bufio.NewReader(buffer), + typeDef: apiStruct.StructBody, }, nil } func (p *Parser) Parse() (api *spec.ApiSpec, err error) { api = new(spec.ApiSpec) - types, err := parseStructAst(p.st) + types, err := parseStructAst(p.typeDef) if err != nil { return nil, err } diff --git a/tools/goctl/api/parser/util.go b/tools/goctl/api/parser/util.go index 0d53fd70..dc1f55e9 100644 --- a/tools/goctl/api/parser/util.go +++ b/tools/goctl/api/parser/util.go @@ -3,19 +3,19 @@ package parser import ( "bufio" "errors" - "regexp" "strings" "github.com/tal-tech/go-zero/tools/goctl/api/spec" ) -// struct match -const typeRegex = `(?m)(?m)(^ *type\s+[a-zA-Z][a-zA-Z0-9_-]+\s+(((struct)\s*?\{[\w\W]*?[^\{]\})|([a-zA-Z][a-zA-Z0-9_-]+)))|(^ *type\s*?\([\w\W]+\}\s*\))` +var emptyType spec.Type -var ( - emptyStrcut = errors.New("struct body not found") - emptyType spec.Type -) +type ApiStruct struct { + Info string + StructBody string + Service string + Imports string +} func GetType(api *spec.ApiSpec, t string) spec.Type { for _, tp := range api.Types { @@ -69,32 +69,56 @@ func unread(r *bufio.Reader) error { return r.UnreadRune() } -func MatchStruct(api string) (info, structBody, service string, err error) { - r := regexp.MustCompile(typeRegex) - indexes := r.FindAllStringIndex(api, -1) - if len(indexes) == 0 { - return "", "", "", emptyStrcut - } - startIndexes := indexes[0] - endIndexes := indexes[len(indexes)-1] +func MatchStruct(api string) (*ApiStruct, error) { + var result ApiStruct + scanner := bufio.NewScanner(strings.NewReader(api)) + var parseInfo = false + var parseImport = false + var parseType = false + var parseSevice = false + var segment string + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + + if line == "@doc(" { + parseInfo = true + } + if line == ")" && parseInfo { + parseInfo = false + result.Info = segment + ")" + segment = "" + continue + } - info = api[:startIndexes[0]] - structBody = api[startIndexes[0]:endIndexes[len(endIndexes)-1]] - service = api[endIndexes[len(endIndexes)-1]:] + if strings.HasPrefix(line, "import") { + parseImport = true + } + if parseImport && (strings.HasPrefix(line, "type") || strings.HasPrefix(line, "@server") || + strings.HasPrefix(line, "service")) { + parseImport = false + result.Imports = segment + segment = line + "\n" + continue + } - firstIIndex := strings.Index(info, "i") - if firstIIndex > 0 { - info = info[firstIIndex:] + if strings.HasPrefix(line, "type") { + parseType = true + } + if strings.HasPrefix(line, "@server") || strings.HasPrefix(line, "service") { + if parseType { + parseType = false + result.StructBody = segment + segment = line + "\n" + continue + } + parseSevice = true + } + segment += scanner.Text() + "\n" } - lastServiceRightBraceIndex := strings.LastIndex(service, "}") + 1 - var firstServiceIndex int - for index, char := range service { - if !isSpace(char) && !isNewline(char) { - firstServiceIndex = index - break - } + if !parseSevice { + return nil, errors.New("no service defined") } - service = service[firstServiceIndex:lastServiceRightBraceIndex] - return + result.Service = segment + return &result, nil }