From 801a6ddc089e5868c7396a40f38c8cd79918b0ca Mon Sep 17 00:00:00 2001 From: oldme Date: Wed, 10 Apr 2024 11:30:21 +0800 Subject: [PATCH 1/5] AST --- cmd/gf/internal/cmd/genctrl/genctrl.go | 9 ++-- .../internal/cmd/genctrl/genctrl_calculate.go | 20 ++++---- cmd/gf/internal/utility/utils/utils.go | 48 +++++++++++++++++++ 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/cmd/gf/internal/cmd/genctrl/genctrl.go b/cmd/gf/internal/cmd/genctrl/genctrl.go index d7d4b4bdf6a..8d61b988f63 100644 --- a/cmd/gf/internal/cmd/genctrl/genctrl.go +++ b/cmd/gf/internal/cmd/genctrl/genctrl.go @@ -9,11 +9,11 @@ package genctrl import ( "context" + "github.com/gogf/gf/cmd/gf/v2/internal/utility/utils" "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" @@ -38,7 +38,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 +145,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 := utils.GetStructs(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 40d0d1fd540..0bdd3a2b6d2 100644 --- a/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go +++ b/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go @@ -14,10 +14,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 +34,21 @@ 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 := utils.GetStructs(apiFileFolderPath) if err != nil { return nil, err } - for _, match := range matches { - var ( - methodName = match[1] - structBody = match[2] - ) + for methodName, structBody := range structsInfo { + // ignore struct name that do not end in "Req" + if !gstr.HasSuffix(methodName, "Req") { + continue + } // ignore struct name that match a request, but has no g.Meta in its body. if !gstr.Contains(structBody, `g.Meta`) { continue } + // remove end "Req" + methodName = gstr.TrimRightStr(methodName, "Req", 1) item := apiItem{ Import: gstr.Trim(importPath, `"`), FileName: gfile.Name(apiFileFolderPath), diff --git a/cmd/gf/internal/utility/utils/utils.go b/cmd/gf/internal/utility/utils/utils.go index 66625079ade..46bc60d510f 100644 --- a/cmd/gf/internal/utility/utils/utils.go +++ b/cmd/gf/internal/utility/utils/utils.go @@ -7,8 +7,13 @@ package utils import ( + "bytes" "context" "fmt" + "go/ast" + "go/parser" + "go/printer" + "go/token" "golang.org/x/tools/imports" @@ -136,3 +141,46 @@ func GetModPath() string { } return "" } + +func GetStructs(filePath string) (structsInfo map[string]string, err error) { + var ( + fileContent = gfile.GetContents(filePath) + fileSet = token.NewFileSet() + typeSpecList []*ast.TypeSpec + ) + structsInfo = make(map[string]string) + + node, err := parser.ParseFile(fileSet, "", fileContent, parser.ParseComments) + if err != nil { + return + } + + // Extract and store type declarations + for _, decl := range node.Decls { + genDecl, isGenDecl := decl.(*ast.GenDecl) + if !isGenDecl { + continue + } + for _, spec := range genDecl.Specs { + if typeSpec, isTypeSpec := spec.(*ast.TypeSpec); isTypeSpec { + typeSpecList = append(typeSpecList, typeSpec) + } + } + } + + for _, typeSpec := range typeSpecList { + structType, isStruct := typeSpec.Type.(*ast.StructType) + if !isStruct { + continue + } + + var buf bytes.Buffer + if err := printer.Fprint(&buf, fileSet, structType); err != nil { + return nil, err + } + + structsInfo[typeSpec.Name.Name] = buf.String() + } + + return +} From 4c876752a0cfad846deecf32a57235f76e5a1080 Mon Sep 17 00:00:00 2001 From: oldme Date: Wed, 10 Apr 2024 14:16:52 +0800 Subject: [PATCH 2/5] up --- cmd/gf/internal/utility/utils/utils.go | 64 +++++++++++++++----------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/cmd/gf/internal/utility/utils/utils.go b/cmd/gf/internal/utility/utils/utils.go index 46bc60d510f..32aed02317a 100644 --- a/cmd/gf/internal/utility/utils/utils.go +++ b/cmd/gf/internal/utility/utils/utils.go @@ -144,9 +144,8 @@ func GetModPath() string { func GetStructs(filePath string) (structsInfo map[string]string, err error) { var ( - fileContent = gfile.GetContents(filePath) - fileSet = token.NewFileSet() - typeSpecList []*ast.TypeSpec + fileContent = gfile.GetContents(filePath) + fileSet = token.NewFileSet() ) structsInfo = make(map[string]string) @@ -155,32 +154,45 @@ func GetStructs(filePath string) (structsInfo map[string]string, err error) { return } - // Extract and store type declarations - for _, decl := range node.Decls { - genDecl, isGenDecl := decl.(*ast.GenDecl) - if !isGenDecl { - continue - } - for _, spec := range genDecl.Specs { - if typeSpec, isTypeSpec := spec.(*ast.TypeSpec); isTypeSpec { - typeSpecList = append(typeSpecList, typeSpec) + ast.Inspect(node, func(n ast.Node) bool { + if typeSpec, ok := n.(*ast.TypeSpec); ok { + if structType, ok := typeSpec.Type.(*ast.StructType); ok { + var buf bytes.Buffer + if err := printer.Fprint(&buf, fileSet, structType); err != nil { + return false + } + structsInfo[typeSpec.Name.Name] = buf.String() } } - } - - for _, typeSpec := range typeSpecList { - structType, isStruct := typeSpec.Type.(*ast.StructType) - if !isStruct { - continue - } - - var buf bytes.Buffer - if err := printer.Fprint(&buf, fileSet, structType); err != nil { - return nil, err - } + return true + }) - structsInfo[typeSpec.Name.Name] = buf.String() - } + // Extract and store type declarations + // for _, decl := range node.Decls { + // genDecl, isGenDecl := decl.(*ast.GenDecl) + // if !isGenDecl { + // continue + // } + // for _, spec := range genDecl.Specs { + // if typeSpec, isTypeSpec := spec.(*ast.TypeSpec); isTypeSpec { + // typeSpecList = append(typeSpecList, typeSpec) + // } + // } + // } + // + // for _, typeSpec := range typeSpecList { + // structType, isStruct := typeSpec.Type.(*ast.StructType) + // if !isStruct { + // continue + // } + // + // var buf bytes.Buffer + // if err := printer.Fprint(&buf, fileSet, structType); err != nil { + // return nil, err + // } + // + // structsInfo[typeSpec.Name.Name] = buf.String() + // } return } From 5f835de60f5217dd8065159c587c777970ff9d4f Mon Sep 17 00:00:00 2001 From: oldme Date: Wed, 10 Apr 2024 14:31:58 +0800 Subject: [PATCH 3/5] up --- cmd/gf/internal/utility/utils/utils.go | 27 -------------------------- 1 file changed, 27 deletions(-) diff --git a/cmd/gf/internal/utility/utils/utils.go b/cmd/gf/internal/utility/utils/utils.go index 32aed02317a..f1988b346a3 100644 --- a/cmd/gf/internal/utility/utils/utils.go +++ b/cmd/gf/internal/utility/utils/utils.go @@ -167,32 +167,5 @@ func GetStructs(filePath string) (structsInfo map[string]string, err error) { return true }) - // Extract and store type declarations - // for _, decl := range node.Decls { - // genDecl, isGenDecl := decl.(*ast.GenDecl) - // if !isGenDecl { - // continue - // } - // for _, spec := range genDecl.Specs { - // if typeSpec, isTypeSpec := spec.(*ast.TypeSpec); isTypeSpec { - // typeSpecList = append(typeSpecList, typeSpec) - // } - // } - // } - // - // for _, typeSpec := range typeSpecList { - // structType, isStruct := typeSpec.Type.(*ast.StructType) - // if !isStruct { - // continue - // } - // - // var buf bytes.Buffer - // if err := printer.Fprint(&buf, fileSet, structType); err != nil { - // return nil, err - // } - // - // structsInfo[typeSpec.Name.Name] = buf.String() - // } - return } From 1b616ade4bee0c82ef1d43982430bcce02f90b4e Mon Sep 17 00:00:00 2001 From: oldme Date: Wed, 10 Apr 2024 16:17:02 +0800 Subject: [PATCH 4/5] up --- .../internal/cmd/cmd_z_unit_gen_ctrl_test.go | 9 +- cmd/gf/internal/cmd/genctrl/genctrl.go | 4 +- .../internal/cmd/genctrl/genctrl_calculate.go | 3 +- cmd/gf/internal/utility/ast/ast.go | 82 +++++++++++++++++++ cmd/gf/internal/utility/utils/utils.go | 33 -------- 5 files changed, 94 insertions(+), 37 deletions(-) create mode 100644 cmd/gf/internal/utility/ast/ast.go diff --git a/cmd/gf/internal/cmd/cmd_z_unit_gen_ctrl_test.go b/cmd/gf/internal/cmd/cmd_z_unit_gen_ctrl_test.go index 99e2935e96c..e1158067b5b 100644 --- a/cmd/gf/internal/cmd/cmd_z_unit_gen_ctrl_test.go +++ b/cmd/gf/internal/cmd/cmd_z_unit_gen_ctrl_test.go @@ -11,6 +11,7 @@ import ( "testing" "github.com/gogf/gf/cmd/gf/v2/internal/cmd/genctrl" + "github.com/gogf/gf/cmd/gf/v2/internal/utility/ast" "github.com/gogf/gf/v2/os/gfile" "github.com/gogf/gf/v2/test/gtest" "github.com/gogf/gf/v2/util/guid" @@ -51,7 +52,13 @@ func Test_Gen_Ctrl_Default(t *testing.T) { genApiExpect = apiFolder + filepath.FromSlash("/article/article_expect.go") ) defer gfile.Remove(genApi) - t.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect)) + + // compare apiInterface and apiInterfaceExpect + genApiMap, err := ast.GetInterfaces(genApi) + t.AssertNil(err) + genApiExpectMap, err := ast.GetInterfaces(genApiExpect) + t.AssertNil(err) + t.Assert(genApiMap, genApiExpectMap) // files files, err := gfile.ScanDir(path, "*.go", true) diff --git a/cmd/gf/internal/cmd/genctrl/genctrl.go b/cmd/gf/internal/cmd/genctrl/genctrl.go index 8d61b988f63..d09ce026f02 100644 --- a/cmd/gf/internal/cmd/genctrl/genctrl.go +++ b/cmd/gf/internal/cmd/genctrl/genctrl.go @@ -9,7 +9,7 @@ package genctrl import ( "context" - "github.com/gogf/gf/cmd/gf/v2/internal/utility/utils" + "github.com/gogf/gf/cmd/gf/v2/internal/utility/ast" "github.com/gogf/gf/v2/container/gset" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gfile" @@ -145,7 +145,7 @@ func (c CGenCtrl) generateByWatchFile(watchFile, sdkPath string, sdkStdVersion, } // watch file should have api definitions. if gfile.Exists(watchFile) { - structsInfo, err := utils.GetStructs(watchFile) + structsInfo, err := ast.GetStructs(watchFile) if err != nil { return err } diff --git a/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go b/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go index 0bdd3a2b6d2..c9b3df50964 100644 --- a/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go +++ b/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go @@ -7,6 +7,7 @@ package genctrl import ( + "github.com/gogf/gf/cmd/gf/v2/internal/utility/ast" "github.com/gogf/gf/cmd/gf/v2/internal/utility/utils" "github.com/gogf/gf/v2/os/gfile" "github.com/gogf/gf/v2/text/gregex" @@ -34,7 +35,7 @@ func (c CGenCtrl) getApiItemsInSrc(apiModuleFolderPath string) (items []apiItem, if gfile.IsDir(apiFileFolderPath) { continue } - structsInfo, err := utils.GetStructs(apiFileFolderPath) + structsInfo, err := ast.GetStructs(apiFileFolderPath) if err != nil { return nil, err } diff --git a/cmd/gf/internal/utility/ast/ast.go b/cmd/gf/internal/utility/ast/ast.go new file mode 100644 index 00000000000..711a4a0ff59 --- /dev/null +++ b/cmd/gf/internal/utility/ast/ast.go @@ -0,0 +1,82 @@ +// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package ast + +import ( + "bytes" + "go/ast" + "go/parser" + "go/printer" + "go/token" + "sort" + + "github.com/gogf/gf/v2/os/gfile" +) + +// GetStructs retrieves and returns all struct definitions from given file. +// The key of the returned map is the struct name, and the value is the struct definition. +// The struct definition is the string content of the struct definition in the file. +func GetStructs(filePath string) (structsInfo map[string]string, err error) { + var ( + fileContent = gfile.GetContents(filePath) + fileSet = token.NewFileSet() + ) + structsInfo = make(map[string]string) + + 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 { + if structType, ok := typeSpec.Type.(*ast.StructType); ok { + var buf bytes.Buffer + if err := printer.Fprint(&buf, fileSet, structType); err != nil { + return false + } + structsInfo[typeSpec.Name.Name] = buf.String() + } + } + return true + }) + + return +} + +// GetInterfaces retrieves and returns all interface definitions from given file. +// The key of the returned map is the interface name, and the value is the list of method names. +// The method names are sorted in ascending order. +func GetInterfaces(filePath string) (interfacesInfo map[string][]string, err error) { + fileSet := token.NewFileSet() + + node, err := parser.ParseFile(fileSet, filePath, nil, parser.ParseComments) + if err != nil { + return nil, err + } + + interfacesInfo = make(map[string][]string) + ast.Inspect(node, func(n ast.Node) bool { + switch t := n.(type) { + case *ast.TypeSpec: + if interfaceType, ok := t.Type.(*ast.InterfaceType); ok { + for _, field := range interfaceType.Methods.List { + interfacesInfo[t.Name.Name] = append(interfacesInfo[t.Name.Name], field.Names[0].Name) + } + } + } + return true + }) + + // Sort the methods in each interface. + for k, v := range interfacesInfo { + sort.Strings(v) + interfacesInfo[k] = v + } + + return interfacesInfo, nil +} diff --git a/cmd/gf/internal/utility/utils/utils.go b/cmd/gf/internal/utility/utils/utils.go index f1988b346a3..66625079ade 100644 --- a/cmd/gf/internal/utility/utils/utils.go +++ b/cmd/gf/internal/utility/utils/utils.go @@ -7,13 +7,8 @@ package utils import ( - "bytes" "context" "fmt" - "go/ast" - "go/parser" - "go/printer" - "go/token" "golang.org/x/tools/imports" @@ -141,31 +136,3 @@ func GetModPath() string { } return "" } - -func GetStructs(filePath string) (structsInfo map[string]string, err error) { - var ( - fileContent = gfile.GetContents(filePath) - fileSet = token.NewFileSet() - ) - structsInfo = make(map[string]string) - - 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 { - if structType, ok := typeSpec.Type.(*ast.StructType); ok { - var buf bytes.Buffer - if err := printer.Fprint(&buf, fileSet, structType); err != nil { - return false - } - structsInfo[typeSpec.Name.Name] = buf.String() - } - } - return true - }) - - return -} From 12c560f69cd3768a4f2f4d23690a29dca6812774 Mon Sep 17 00:00:00 2001 From: oldme Date: Thu, 11 Apr 2024 15:39:20 +0800 Subject: [PATCH 5/5] up --- .../internal/cmd/cmd_z_unit_gen_ctrl_test.go | 9 +- cmd/gf/internal/cmd/genctrl/genctrl.go | 6 +- .../internal/cmd/genctrl/genctrl_calculate.go | 57 ++++++++++--- cmd/gf/internal/utility/ast/ast.go | 82 ------------------- 4 files changed, 49 insertions(+), 105 deletions(-) delete mode 100644 cmd/gf/internal/utility/ast/ast.go diff --git a/cmd/gf/internal/cmd/cmd_z_unit_gen_ctrl_test.go b/cmd/gf/internal/cmd/cmd_z_unit_gen_ctrl_test.go index e1158067b5b..99e2935e96c 100644 --- a/cmd/gf/internal/cmd/cmd_z_unit_gen_ctrl_test.go +++ b/cmd/gf/internal/cmd/cmd_z_unit_gen_ctrl_test.go @@ -11,7 +11,6 @@ import ( "testing" "github.com/gogf/gf/cmd/gf/v2/internal/cmd/genctrl" - "github.com/gogf/gf/cmd/gf/v2/internal/utility/ast" "github.com/gogf/gf/v2/os/gfile" "github.com/gogf/gf/v2/test/gtest" "github.com/gogf/gf/v2/util/guid" @@ -52,13 +51,7 @@ func Test_Gen_Ctrl_Default(t *testing.T) { genApiExpect = apiFolder + filepath.FromSlash("/article/article_expect.go") ) defer gfile.Remove(genApi) - - // compare apiInterface and apiInterfaceExpect - genApiMap, err := ast.GetInterfaces(genApi) - t.AssertNil(err) - genApiExpectMap, err := ast.GetInterfaces(genApiExpect) - t.AssertNil(err) - t.Assert(genApiMap, genApiExpectMap) + t.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect)) // files files, err := gfile.ScanDir(path, "*.go", true) diff --git a/cmd/gf/internal/cmd/genctrl/genctrl.go b/cmd/gf/internal/cmd/genctrl/genctrl.go index d09ce026f02..d6788620aa2 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/ast" + "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/util/gconv" "github.com/gogf/gf/v2/util/gtag" - - "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog" ) const ( @@ -145,7 +143,7 @@ func (c CGenCtrl) generateByWatchFile(watchFile, sdkPath string, sdkStdVersion, } // watch file should have api definitions. if gfile.Exists(watchFile) { - structsInfo, err := ast.GetStructs(watchFile) + structsInfo, err := c.getStructsNameInSrc(watchFile) if err != nil { return err } diff --git a/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go b/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go index c9b3df50964..21021d79865 100644 --- a/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go +++ b/cmd/gf/internal/cmd/genctrl/genctrl_calculate.go @@ -7,7 +7,12 @@ package genctrl import ( - "github.com/gogf/gf/cmd/gf/v2/internal/utility/ast" + "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" @@ -35,19 +40,11 @@ func (c CGenCtrl) getApiItemsInSrc(apiModuleFolderPath string) (items []apiItem, if gfile.IsDir(apiFileFolderPath) { continue } - structsInfo, err := ast.GetStructs(apiFileFolderPath) + structsInfo, err := c.getStructsNameInSrc(apiFileFolderPath) if err != nil { return nil, err } - for methodName, structBody := range structsInfo { - // ignore struct name that do not end in "Req" - if !gstr.HasSuffix(methodName, "Req") { - continue - } - // 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{ @@ -142,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 +} diff --git a/cmd/gf/internal/utility/ast/ast.go b/cmd/gf/internal/utility/ast/ast.go deleted file mode 100644 index 711a4a0ff59..00000000000 --- a/cmd/gf/internal/utility/ast/ast.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package ast - -import ( - "bytes" - "go/ast" - "go/parser" - "go/printer" - "go/token" - "sort" - - "github.com/gogf/gf/v2/os/gfile" -) - -// GetStructs retrieves and returns all struct definitions from given file. -// The key of the returned map is the struct name, and the value is the struct definition. -// The struct definition is the string content of the struct definition in the file. -func GetStructs(filePath string) (structsInfo map[string]string, err error) { - var ( - fileContent = gfile.GetContents(filePath) - fileSet = token.NewFileSet() - ) - structsInfo = make(map[string]string) - - 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 { - if structType, ok := typeSpec.Type.(*ast.StructType); ok { - var buf bytes.Buffer - if err := printer.Fprint(&buf, fileSet, structType); err != nil { - return false - } - structsInfo[typeSpec.Name.Name] = buf.String() - } - } - return true - }) - - return -} - -// GetInterfaces retrieves and returns all interface definitions from given file. -// The key of the returned map is the interface name, and the value is the list of method names. -// The method names are sorted in ascending order. -func GetInterfaces(filePath string) (interfacesInfo map[string][]string, err error) { - fileSet := token.NewFileSet() - - node, err := parser.ParseFile(fileSet, filePath, nil, parser.ParseComments) - if err != nil { - return nil, err - } - - interfacesInfo = make(map[string][]string) - ast.Inspect(node, func(n ast.Node) bool { - switch t := n.(type) { - case *ast.TypeSpec: - if interfaceType, ok := t.Type.(*ast.InterfaceType); ok { - for _, field := range interfaceType.Methods.List { - interfacesInfo[t.Name.Name] = append(interfacesInfo[t.Name.Name], field.Names[0].Name) - } - } - } - return true - }) - - // Sort the methods in each interface. - for k, v := range interfacesInfo { - sort.Strings(v) - interfacesInfo[k] = v - } - - return interfacesInfo, nil -}