diff --git a/cmd/gf/internal/cmd/genctrl/genctrl.go b/cmd/gf/internal/cmd/genctrl/genctrl.go index d7d4b4bdf..d6788620a 100644 --- a/cmd/gf/internal/cmd/genctrl/genctrl.go +++ b/cmd/gf/internal/cmd/genctrl/genctrl.go @@ -9,15 +9,13 @@ package genctrl import ( "context" + "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog" "github.com/gogf/gf/v2/container/gset" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gfile" "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/text/gregex" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gtag" - - "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog" ) const ( @@ -38,7 +36,6 @@ gf gen ctrl ) const ( - PatternApiDefinition = `type[\s\(]+(\w+)Req\s+struct\s+{([\s\S]+?)}` PatternCtrlDefinition = `func\s+\(.+?\)\s+\w+\(.+?\*(\w+)\.(\w+)Req\)\s+\(.+?\*(\w+)\.(\w+)Res,\s+\w+\s+error\)\s+{` ) @@ -146,7 +143,11 @@ func (c CGenCtrl) generateByWatchFile(watchFile, sdkPath string, sdkStdVersion, } // watch file should have api definitions. if gfile.Exists(watchFile) { - if !gregex.IsMatchString(PatternApiDefinition, gfile.GetContents(watchFile)) { + structsInfo, err := c.getStructsNameInSrc(watchFile) + if err != nil { + return err + } + if len(structsInfo) == 0 { return nil } } diff --git a/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go b/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go index 40d0d1fd5..21021d798 100644 --- a/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go +++ b/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go @@ -7,6 +7,12 @@ package genctrl import ( + "bytes" + "go/ast" + "go/parser" + "go/printer" + "go/token" + "github.com/gogf/gf/cmd/gf/v2/internal/utility/utils" "github.com/gogf/gf/v2/os/gfile" "github.com/gogf/gf/v2/text/gregex" @@ -14,10 +20,7 @@ import ( ) func (c CGenCtrl) getApiItemsInSrc(apiModuleFolderPath string) (items []apiItem, err error) { - var ( - fileContent string - importPath string - ) + var importPath string // The second level folders: versions. apiVersionFolderPaths, err := gfile.ScanDir(apiModuleFolderPath, "*", false) if err != nil { @@ -37,20 +40,13 @@ func (c CGenCtrl) getApiItemsInSrc(apiModuleFolderPath string) (items []apiItem, if gfile.IsDir(apiFileFolderPath) { continue } - fileContent = gfile.GetContents(apiFileFolderPath) - matches, err := gregex.MatchAllString(PatternApiDefinition, fileContent) + structsInfo, err := c.getStructsNameInSrc(apiFileFolderPath) if err != nil { return nil, err } - for _, match := range matches { - var ( - methodName = match[1] - structBody = match[2] - ) - // ignore struct name that match a request, but has no g.Meta in its body. - if !gstr.Contains(structBody, `g.Meta`) { - continue - } + for _, methodName := range structsInfo { + // remove end "Req" + methodName = gstr.TrimRightStr(methodName, "Req", 1) item := apiItem{ Import: gstr.Trim(importPath, `"`), FileName: gfile.Name(apiFileFolderPath), @@ -143,3 +139,41 @@ func (c CGenCtrl) getApiItemsInDst(dstFolder string) (items []apiItem, err error } return } + +// getStructsNameInSrc retrieves all struct names +// that end in "Req" and have "g.Meta" in their body. +func (c CGenCtrl) getStructsNameInSrc(filePath string) (structsName []string, err error) { + var ( + fileContent = gfile.GetContents(filePath) + fileSet = token.NewFileSet() + ) + + node, err := parser.ParseFile(fileSet, "", fileContent, parser.ParseComments) + if err != nil { + return + } + + ast.Inspect(node, func(n ast.Node) bool { + if typeSpec, ok := n.(*ast.TypeSpec); ok { + methodName := typeSpec.Name.Name + if !gstr.HasSuffix(methodName, "Req") { + // ignore struct name that do not end in "Req" + return true + } + if structType, ok := typeSpec.Type.(*ast.StructType); ok { + var buf bytes.Buffer + if err := printer.Fprint(&buf, fileSet, structType); err != nil { + return false + } + // ignore struct name that match a request, but has no g.Meta in its body. + if !gstr.Contains(buf.String(), `g.Meta`) { + return true + } + structsName = append(structsName, methodName) + } + } + return true + }) + + return +}