123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- 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
- }
|