-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathgenerator.go
148 lines (136 loc) · 3.49 KB
/
generator.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package main
import (
"bytes"
"flag"
"fmt"
"go/ast"
"go/format"
"go/parser"
"go/token"
"os"
"strings"
"text/template"
)
var bindingsFile = `package {{.packageName}}
/*
This is an autogenerated file by autobindings
*/
import(
"github.com/mholt/binding"
)
func ({{.variableName}} {{.structName}}) FieldMap() binding.FieldMap {
binding_fmap := binding.FieldMap{ {{$vname := .variableName}}{{range $field, $mapping := .mappings}}
&{{$vname}}.{{$field}}: "{{$mapping}}",{{end}}
}
{{ if .hasEmbeds }}
type FieldMap interface {
FieldMap() binding.FieldMap
}
var iface interface{}
{{$vname := .variableName}}
{{range $field, $type := .embeds}}
iface = {{$vname}}.{{$type}}
if m, ok := iface.(FieldMap); ok {
for k, v := range m.FieldMap() {
binding_fmap[k] = v
}
}
{{end}}
{{end}}
return binding_fmap
}
`
func main() {
prnt := flag.Bool("print", false, "Output In Console")
filename := flag.String("file", "", "Input file")
flag.Parse()
if *filename == "" {
fmt.Println("Usage : bindings {file_name}\nExample: bindings file.go")
return
}
generateFieldMap(*filename, *prnt)
}
func generateFieldMap(fileName string, printOnConsole bool) {
fset := token.NewFileSet() // positions are relative to fset
// Parse the file given in arguments
f, err := parser.ParseFile(fset, fileName, nil, parser.ParseComments)
if err != nil {
panic(err)
}
structMap := map[string]*ast.FieldList{}
// range over the structs and fill struct map
for _, d := range f.Scope.Objects {
ts, ok := d.Decl.(*ast.TypeSpec)
if !ok {
continue
}
switch ts.Type.(type) {
case *ast.StructType:
x, _ := ts.Type.(*ast.StructType)
structMap[ts.Name.String()] = x.Fields
}
}
// looping through each struct and creating a bindings file for it
packageName := f.Name
for structName, fields := range structMap {
variableName := strings.ToLower(string(structName[0]))
mappings := map[string]string{}
embeds := []ast.Expr{}
hasEmbeds := false
for _, field := range fields.List {
if len(field.Names) == 0 {
hasEmbeds = true
embeds = append(embeds, field.Type)
continue
}
name := field.Names[0].String()
// if tag for field doesn't exists, create one
if field.Tag == nil {
mappings[name] = name
} else if strings.Contains(field.Tag.Value, "json") {
tags := strings.Replace(field.Tag.Value, "`", "", -1)
for _, tag := range strings.Split(tags, " ") {
if strings.Contains(tag, "json") {
mapping := strings.Replace(tag, "json:\"", "", -1)
mapping = strings.Replace(mapping, "\"", "", -1)
if mapping == "-" {
continue
}
mappings[name] = mapping
}
}
} else {
// I will handle other cases later
mappings[name] = name
}
}
content := new(bytes.Buffer)
t := template.Must(template.New("bindings").Parse(bindingsFile))
err = t.Execute(content, map[string]interface{}{
"packageName": packageName,
"variableName": variableName,
"structName": structName,
"mappings": mappings,
"embeds": embeds,
"hasEmbeds": hasEmbeds})
if err != nil {
panic(err)
}
finalContent, err := format.Source(content.Bytes())
if err != nil {
panic(err)
}
if printOnConsole {
fmt.Println(string(finalContent))
return
}
// opening file for writing content
writer, err := os.Create(fmt.Sprintf("%s_bindings.go", strings.ToLower(structName)))
if err != nil {
fmt.Printf("Error opening file %v", err)
panic(err)
}
writer.WriteString(string(finalContent))
writer.Close()
}
}