parser.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package pkg
  2. import (
  3. "go/ast"
  4. "go/build"
  5. "go/parser"
  6. "go/token"
  7. "log"
  8. "strings"
  9. "github.com/jinzhu/gorm"
  10. )
  11. // The Parser is used to parse a directory and expose information about the structs defined in the files of this directory.
  12. type Parser struct {
  13. dir string
  14. pkg *build.Package
  15. parsedFiles []*ast.File
  16. }
  17. // NewParser create a new parser instance.
  18. func NewParser(dir string) *Parser {
  19. return &Parser{
  20. dir: dir,
  21. }
  22. }
  23. // getPackage parse dir get go file and package
  24. func (p *Parser) getPackage() {
  25. pkg, err := build.Default.ImportDir(p.dir, build.ImportComment)
  26. if err != nil {
  27. log.Fatalf("cannot process directory %s: %s", p.dir, err)
  28. }
  29. p.pkg = pkg
  30. }
  31. // parseGoFiles parse go file
  32. func (p *Parser) parseGoFiles() {
  33. var parsedFiles []*ast.File
  34. fs := token.NewFileSet()
  35. for _, file := range p.pkg.GoFiles {
  36. file = p.dir + "/" + file
  37. parsedFile, err := parser.ParseFile(fs, file, nil, 0)
  38. if err != nil {
  39. log.Fatalf("parsing package: %s: %s\n", file, err)
  40. }
  41. parsedFiles = append(parsedFiles, parsedFile)
  42. }
  43. p.parsedFiles = parsedFiles
  44. }
  45. // parseTypes parse type of struct
  46. func (p *Parser) parseTypes(file *ast.File) (ret []structConfig) {
  47. ast.Inspect(file, func(n ast.Node) bool {
  48. decl, ok := n.(*ast.GenDecl)
  49. if !ok || decl.Tok != token.TYPE {
  50. return true
  51. }
  52. for _, spec := range decl.Specs {
  53. var (
  54. data structConfig
  55. )
  56. typeSpec, _ok := spec.(*ast.TypeSpec)
  57. if !_ok {
  58. continue
  59. }
  60. // We only care about struct declaration (for now)
  61. var structType *ast.StructType
  62. if structType, ok = typeSpec.Type.(*ast.StructType); !ok {
  63. continue
  64. }
  65. data.StructName = typeSpec.Name.Name
  66. for _, v := range structType.Fields.List {
  67. var (
  68. optionField fieldConfig
  69. )
  70. if t, _ok := v.Type.(*ast.Ident); _ok {
  71. optionField.FieldType = t.String()
  72. } else {
  73. if v.Tag != nil {
  74. if strings.Contains(v.Tag.Value, "gorm") && strings.Contains(v.Tag.Value, "time") {
  75. optionField.FieldType = "time.Time"
  76. }
  77. }
  78. }
  79. if len(v.Names) > 0 {
  80. optionField.FieldName = v.Names[0].String()
  81. optionField.ColumnName = gorm.ToDBName(optionField.FieldName)
  82. optionField.HumpName = SQLColumnToHumpStyle(optionField.ColumnName)
  83. }
  84. data.OptionFields = append(data.OptionFields, optionField)
  85. }
  86. ret = append(ret, data)
  87. }
  88. return true
  89. })
  90. return
  91. }
  92. // 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.
  93. func (p *Parser) Parse() (ret []structConfig) {
  94. var (
  95. data []structConfig
  96. )
  97. p.getPackage()
  98. p.parseGoFiles()
  99. for _, f := range p.parsedFiles {
  100. data = append(data, p.parseTypes(f)...)
  101. }
  102. return data
  103. }