mirror of
https://github.com/xinliangnote/go-gin-api.git
synced 2024-04-21 12:31:46 +00:00
119 lines
2.7 KiB
Go
119 lines
2.7 KiB
Go
package pkg
|
|
|
|
import (
|
|
"go/ast"
|
|
"go/build"
|
|
"go/parser"
|
|
"go/token"
|
|
"log"
|
|
"strings"
|
|
|
|
"github.com/jinzhu/gorm"
|
|
)
|
|
|
|
// The Parser is used to parse a directory and expose information about the structs defined in the files of this directory.
|
|
type Parser struct {
|
|
dir string
|
|
pkg *build.Package
|
|
parsedFiles []*ast.File
|
|
}
|
|
|
|
// NewParser create a new parser instance.
|
|
func NewParser(dir string) *Parser {
|
|
return &Parser{
|
|
dir: dir,
|
|
}
|
|
}
|
|
|
|
// getPackage parse dir get go file and package
|
|
func (p *Parser) getPackage() {
|
|
pkg, err := build.Default.ImportDir(p.dir, build.ImportComment)
|
|
if err != nil {
|
|
log.Fatalf("cannot process directory %s: %s", p.dir, err)
|
|
}
|
|
p.pkg = pkg
|
|
|
|
}
|
|
|
|
// parseGoFiles parse go file
|
|
func (p *Parser) parseGoFiles() {
|
|
var parsedFiles []*ast.File
|
|
fs := token.NewFileSet()
|
|
for _, file := range p.pkg.GoFiles {
|
|
file = p.dir + "/" + file
|
|
parsedFile, err := parser.ParseFile(fs, file, nil, 0)
|
|
if err != nil {
|
|
log.Fatalf("parsing package: %s: %s\n", file, err)
|
|
}
|
|
parsedFiles = append(parsedFiles, parsedFile)
|
|
}
|
|
p.parsedFiles = parsedFiles
|
|
}
|
|
|
|
// parseTypes parse type of struct
|
|
func (p *Parser) parseTypes(file *ast.File) (ret []structConfig) {
|
|
ast.Inspect(file, func(n ast.Node) bool {
|
|
decl, ok := n.(*ast.GenDecl)
|
|
if !ok || decl.Tok != token.TYPE {
|
|
return true
|
|
}
|
|
|
|
for _, spec := range decl.Specs {
|
|
var (
|
|
data structConfig
|
|
)
|
|
typeSpec, _ok := spec.(*ast.TypeSpec)
|
|
if !_ok {
|
|
continue
|
|
}
|
|
// We only care about struct declaration (for now)
|
|
var structType *ast.StructType
|
|
if structType, ok = typeSpec.Type.(*ast.StructType); !ok {
|
|
continue
|
|
}
|
|
|
|
data.StructName = typeSpec.Name.Name
|
|
for _, v := range structType.Fields.List {
|
|
var (
|
|
optionField fieldConfig
|
|
)
|
|
|
|
if t, _ok := v.Type.(*ast.Ident); _ok {
|
|
optionField.FieldType = t.String()
|
|
} else {
|
|
if v.Tag != nil {
|
|
if strings.Contains(v.Tag.Value, "gorm") && strings.Contains(v.Tag.Value, "time") {
|
|
optionField.FieldType = "time.Time"
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(v.Names) > 0 {
|
|
optionField.FieldName = v.Names[0].String()
|
|
optionField.ColumnName = gorm.ToDBName(optionField.FieldName)
|
|
optionField.HumpName = SQLColumnToHumpStyle(optionField.ColumnName)
|
|
}
|
|
|
|
data.OptionFields = append(data.OptionFields, optionField)
|
|
}
|
|
|
|
ret = append(ret, data)
|
|
}
|
|
return true
|
|
})
|
|
return
|
|
}
|
|
|
|
// Parse should be called before any type querying for the parser. It takes the directory to be parsed and extracts all the structs defined in this directory.
|
|
func (p *Parser) Parse() (ret []structConfig) {
|
|
var (
|
|
data []structConfig
|
|
)
|
|
p.getPackage()
|
|
p.parseGoFiles()
|
|
for _, f := range p.parsedFiles {
|
|
data = append(data, p.parseTypes(f)...)
|
|
}
|
|
return data
|
|
}
|