-
Notifications
You must be signed in to change notification settings - Fork 17
/
yaml2go.go
153 lines (133 loc) · 3.68 KB
/
yaml2go.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
149
150
151
152
153
package yaml2go
import (
"fmt"
"go/format"
"gopkg.in/yaml.v2"
"reflect"
"strings"
)
// New creates Yaml2Go object
func New() Yaml2Go {
return Yaml2Go{}
}
type line struct {
structName string
line string
}
// Yaml2Go to store converted result
type Yaml2Go struct {
Visited map[line]bool
StructMap map[string]string
}
// NewStruct creates new entry in StructMap result
func (yg *Yaml2Go) NewStruct(structName string, parent string) string {
// If struct already present with the same name
// rename struct to ParentStructname
if _, ok := yg.StructMap[structName]; ok {
structName = goKeyFormat(parent) + structName
}
yg.AppendResult(structName, fmt.Sprintf("// %s\n", structName))
l := fmt.Sprintf("type %s struct {\n", structName)
yg.Visited[line{structName, l}] = true
yg.StructMap[structName] += l
return structName
}
// AppendResult add lines to the result
func (yg *Yaml2Go) AppendResult(structName string, l string) {
if _, ok := yg.Visited[line{structName, l}]; !ok {
yg.StructMap[structName] += l
}
yg.Visited[line{structName, l}] = true
}
// removeUnderscores and camelize string
func goKeyFormat(key string) string {
var st string
strList := strings.Split(key, "_")
for _, str := range strList {
st += strings.Title(str)
}
if len(st) == 0 {
st = key
}
return st
}
// Convert transforms map[string]interface{} to go struct
func (yg *Yaml2Go) Convert(structName string, data []byte) (string, error) {
yg.Visited = make(map[line]bool)
yg.StructMap = make(map[string]string)
// Unmarshal to map[string]interface{}
var obj map[string]interface{}
err := yaml.Unmarshal(data, &obj)
if err != nil {
return "", err
}
yg.NewStruct("Yaml2Go", "")
for k, v := range obj {
yg.Structify(structName, k, v, false)
}
yg.AppendResult("Yaml2Go", "}\n")
var result string
for _, value := range yg.StructMap {
result += fmt.Sprintf("%s\n", value)
}
// Convert result into go format
goFormat, err := format.Source([]byte(result))
if err != nil {
return "", err
}
return string(goFormat), nil
}
// Structify transforms map key values to struct fields
// structName : parent struct name
// k, v : fields in the struct
func (yg *Yaml2Go) Structify(structName, k string, v interface{}, arrayElem bool) {
if reflect.TypeOf(v) == nil || len(k) == 0 {
yg.AppendResult(structName, fmt.Sprintf("%s interface{} `yaml:\"%s\"`\n", goKeyFormat(k), k))
return
}
switch reflect.TypeOf(v).Kind() {
// If yaml object
case reflect.Map:
switch val := v.(type) {
case map[interface{}]interface{}:
key := goKeyFormat(k)
newKey := key
if !arrayElem {
// Create new structure
newKey = yg.NewStruct(key, structName)
yg.AppendResult(structName, fmt.Sprintf("%s %s `yaml:\"%s\"`\n", key, newKey, k))
}
// If array of yaml objects
for k1, v1 := range val {
if _, ok := k1.(string); ok {
yg.Structify(newKey, k1.(string), v1, false)
}
}
if !arrayElem {
yg.AppendResult(newKey, "}\n")
}
}
// If array
case reflect.Slice:
val := v.([]interface{})
if len(val) == 0 {
return
}
switch val[0].(type) {
case string, int, bool, float64:
yg.AppendResult(structName, fmt.Sprintf("%s []%s `yaml:\"%s\"`\n", goKeyFormat(k), reflect.TypeOf(val[0]), k))
// if nested object
case map[interface{}]interface{}:
key := goKeyFormat(k)
// Create new structure
newKey := yg.NewStruct(key, structName)
yg.AppendResult(structName, fmt.Sprintf("%s []%s `yaml:\"%s\"`\n", key, newKey, k))
for _, v1 := range val {
yg.Structify(newKey, key, v1, true)
}
yg.AppendResult(newKey, "}\n")
}
default:
yg.AppendResult(structName, fmt.Sprintf("%s %s `yaml:\"%s\"`\n", goKeyFormat(k), reflect.TypeOf(v).String(), k))
}
}