forked from rikeda71/foggo
/
fields.go
105 lines (90 loc) · 2.35 KB
/
fields.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package parser
import (
"fmt"
"go/ast"
"go/types"
"strings"
"github.com/ervitis/foggo/internal/generator"
"github.com/fatih/structtag"
)
const (
TagKey = "foggo"
IgnoreValue = "-"
)
// CollectFields is function to get fields of struct type and index of struct type from ast files
func CollectFields(structName string, astFiles []*ast.File) ([]*generator.StructField, int, error) {
for i, af := range astFiles {
for _, decl := range af.Decls {
genDecl, ok := decl.(*ast.GenDecl)
if !ok {
continue
}
for _, spec := range genDecl.Specs {
typeSpec, ok := spec.(*ast.TypeSpec)
if !ok {
continue
}
if structName != typeSpec.Name.Name {
continue
}
structType, ok := typeSpec.Type.(*ast.StructType)
if !ok {
continue
}
converted, err := convertToStructFieldsFromAstFields(structType.Fields.List)
if err != nil {
return nil, -1, err
}
return converted, i, nil
}
}
}
return nil, -1, fmt.Errorf("there is no suitable struct that matches given structName [structName=%s]", structName)
}
func convertToStructFieldsFromAstFields(fields []*ast.Field) ([]*generator.StructField, error) {
sfs := make([]*generator.StructField, len(fields))
for i, f := range fields {
sf, err := internalConvert(f)
if err != nil {
return nil, fmt.Errorf("convert internal type error in %dth field: %w", i, err)
}
sfs[i] = sf
}
return sfs, nil
}
func internalConvert(field *ast.Field) (*generator.StructField, error) {
tag, err := parseTag(field.Tag)
if err != nil {
return nil, err
}
ignore := tag != nil && tag.Name == IgnoreValue
fieldType := types.ExprString(field.Type)
var fieldName string
if len(field.Names) > 0 {
fieldName = field.Names[0].Name
} else {
// get Struct Name from 'package.Struct'
chunks := strings.Split(fieldType, ".")
fieldName = strings.TrimPrefix(chunks[len(chunks)-1], "*")
}
return &generator.StructField{
Name: fieldName,
Type: fieldType,
Ignore: ignore,
}, nil
}
func parseTag(tag *ast.BasicLit) (*structtag.Tag, error) {
// not set tag
if tag == nil {
return nil, nil
}
tags, err := structtag.Parse(strings.Replace(tag.Value, "`", "", -1))
if err != nil {
return nil, fmt.Errorf("parse tag error: %w", err)
}
val, err := tags.Get(TagKey)
if err != nil {
return nil, fmt.Errorf("get tag error: %w", err)
}
return val, nil
}