-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathast.go
126 lines (108 loc) · 2.58 KB
/
ast.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package main
import (
"errors"
"fmt"
"go/ast"
"os"
"path/filepath"
"regexp"
"strings"
)
const (
intTypeRegex = `^[u]?int\d?`
floatTypeRegex = `^float\d?`
)
type mapper interface {
jsImport() string
object() string
mapStringTag(string) string
mapBoolTag(string) string
mapNumberTag(string) string
mapTimeStructTag(string) string
mapMixedFieldTag(string) string
}
func isIntegerType(field *ast.Field) bool {
if field == nil {
return false
}
match, err := regexp.MatchString(intTypeRegex, fmt.Sprint(field.Type))
if err != nil {
return false
}
return match
}
func isFloatType(field *ast.Field) bool {
if field == nil {
return false
}
match, err := regexp.MatchString(floatTypeRegex, fmt.Sprint(field.Type))
if err != nil {
return false
}
return match
}
func isTimeField(field *ast.Field) bool {
if field == nil {
return false
}
return fmt.Sprint(field.Type) == "&{time Time}"
}
func generator(m mapper, snakeCase bool, outputDir string) func(n ast.Node) bool {
return func(n ast.Node) bool {
t, ok := n.(*ast.TypeSpec)
if !ok {
return true
}
s, ok := t.Type.(*ast.StructType)
if !ok {
return true
}
schema := NewSchema(t.Name.Name)
// fmt.Println("DEBUG: processing type", t.Name.Name)
for _, field := range s.Fields.List {
if field.Tag == nil {
continue
}
start := strings.Index(field.Tag.Value, "validate:")
if start <= 0 {
continue
}
validateTag := field.Tag.Value[start:]
end := strings.LastIndex(validateTag, `"`)
if end != -1 {
validateTag = validateTag[:end]
}
fieldName := field.Names[0].Name
if fmt.Sprint(field.Type) == "string" {
schema.AddStringField(fieldName, m.mapStringTag(validateTag))
} else if fmt.Sprint(field.Type) == "bool" {
schema.AddBoolField(fieldName, m.mapBoolTag(validateTag))
} else if isIntegerType(field) || isFloatType(field) {
schema.AddNumberField(fieldName, m.mapNumberTag(validateTag))
} else if isTimeField(field) {
schema.AddTimeField(fieldName, m.mapTimeStructTag(validateTag))
} else {
// default to using a "mixed" field
schema.AddMixedField(fieldName, m.mapMixedFieldTag(validateTag))
}
}
if schema.IsEmpty() {
return false
}
if outputDir != "" {
err := os.Mkdir(filepath.Join(outputDir), 0o775)
if err != nil {
if !errors.Is(err, os.ErrExist) {
panic(err)
}
}
err = os.WriteFile(filepath.Join(outputDir, schema.Filename(snakeCase)), []byte(schema.ToJSFile(m)), os.FileMode(0o777))
if err != nil {
panic(err)
}
return false
}
fmt.Println(schema.ToJS(m))
return false
}
}