/
main.go
266 lines (233 loc) · 5.23 KB
/
main.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
package main
import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"os"
"reflect"
"strings"
"github.com/tidwall/gjson"
)
var (
recursiveFlag = flag.Bool("r", false, "if r is set , output struct will be in closure format. Append to the end when use simplified format")
jsonContent = ""
)
type Task struct {
name string
content map[string]interface{}
}
var (
taskList []Task = make([]Task, 0)
)
func main() {
parseArgs()
handleParse()
handleGoGenerate()
}
func parseArgs() {
flag.Parse()
hasChannel := false
info, _ := os.Stdin.Stat()
if info.Size() > 0 {
hasChannel = true
bts, _ := ioutil.ReadAll(os.Stdin)
jsonContent = string(bts[:])
}
if len(os.Args) < 2 && !hasChannel {
flag.Usage()
os.Exit(0)
}
if !hasChannel {
if !*recursiveFlag {
jsonContent = os.Args[1]
} else {
if len(os.Args) < 3 && !hasChannel {
flag.Usage()
os.Exit(0)
}
jsonContent = os.Args[2]
}
}
}
func handleParse() {
m, ok := gjson.Parse(jsonContent).Value().(map[string]interface{})
if !ok {
fmt.Println("json file parse error , please check the file format")
os.Exit(0)
}
taskList = append(taskList, Task{"JsonObject", m})
}
func handleGoGenerate() {
var structBuffer bytes.Buffer
for {
if len(taskList) == 0 {
break
}
task := taskList[0]
taskList = taskList[1:]
content, _ := HandleTask(task)
structBuffer.WriteString(content)
}
fmt.Println(structBuffer.String())
return
}
func HandleTask(task Task) (res string, err error) {
buffer := bytes.Buffer{}
buffer.WriteString(fmt.Sprintf(`type %s struct {
`, task.name))
defer func() {
buffer.WriteString("}\n")
res = buffer.String()
}()
for key, val := range task.content {
line, err := getStructLineString(key, val, task)
if err != nil {
panic(err.Error())
}
buffer.WriteString(line)
}
return buffer.String(), nil
}
func getStructLineString(key string, val interface{}, task Task) (line string, err error) {
// write variable name
oldKey := key
var lineBuffer bytes.Buffer
switch len(key) {
case 0:
return "", nil
case 1:
key = strings.ToUpper(key)
default:
key = strings.ToUpper(key[0:1]) + key[1:]
}
lineBuffer.WriteString(fmt.Sprintf("\t%s\t", key))
// handle json value `null`
if val == nil {
val = struct{}{}
}
var (
tp = reflect.TypeOf(val)
typeStr string
parseValue = task.content[oldKey]
)
//recursive handle function
type TaskType string
const (
TaskSlice TaskType = "slice"
TaskMap TaskType = "map"
)
handleRecursiveTask := func(task Task, tp TaskType) (res string, err error) {
bf := bytes.Buffer{}
bf.WriteString(fmt.Sprintf("\t%s\t", key))
switch tp {
case TaskSlice:
bf.WriteString("[]struct{\n")
case TaskMap:
bf.WriteString("struct{\n")
default:
panic("wrong task type ")
}
defer func() {
bf.WriteString("\t}\t")
bf.WriteString(fmt.Sprintf("`json:\"%s\"`\n", oldKey))
res = bf.String()
}()
for key, val := range task.content {
line, err := getStructLineString(key, val, task)
if err != nil {
panic(err)
}
bf.WriteString("\t" + line)
}
return bf.String(), nil
}
for tp.Kind() == reflect.Slice {
mps, ok := parseValue.([]interface{})
if !ok {
return "", fmt.Errorf("wrong value type : %s ", val)
}
if len(mps) == 0 {
break
}
// 判断[]内类型是否相同,不相同则为[]interface{}
baseType := reflect.TypeOf(mps[0])
isStandardArray := true
for _, mp := range mps {
if reflect.TypeOf(mp) != baseType {
isStandardArray = false
break
}
}
// 数组内类型不一样,go文件中生成[]interface{}
typeStr += "[]"
if !isStandardArray {
tp = reflect.TypeOf(struct{}{})
} else if baseType.Kind() == reflect.Slice {
parseValue = mps[0]
continue
} else if baseType.Kind() == reflect.Map {
name := key + "Item"
typeStr += name
unionMap := getUnionFieldMap(mps)
if *recursiveFlag {
return handleRecursiveTask(Task{name, unionMap}, TaskSlice)
}
taskList = append(taskList, Task{name, unionMap})
goto Output
} else {
parseValue = mps[0]
tp = reflect.TypeOf(parseValue)
}
}
// 输出类型
switch tp.Kind() {
case reflect.Bool:
typeStr += "bool"
case reflect.String:
typeStr += "string"
case reflect.Int:
typeStr += "int"
case reflect.Float32:
typeStr += "float32"
case reflect.Float64:
typeStr += "float64"
case reflect.Struct: // 支持null值
typeStr += "interface{}"
case reflect.Map:
typeStr += key + "Item"
mp, ok := parseValue.(map[string]interface{})
if !ok {
return "", fmt.Errorf("wrong value type : %s ", val)
}
if *recursiveFlag {
return handleRecursiveTask(Task{typeStr, mp}, TaskMap)
} else {
taskList = append(taskList, Task{typeStr, mp})
}
default:
return "", fmt.Errorf("wrong value type : %s ", val)
}
Output:
lineBuffer.WriteString(typeStr + "\t")
// write tag
tagStr := fmt.Sprintf("`json:\"%s\"`\n", oldKey)
lineBuffer.WriteString(tagStr)
return lineBuffer.String(), nil
}
func getUnionFieldMap(mps []interface{}) (unionMap map[string]interface{}) {
unionMap = make(map[string]interface{})
for _, v := range mps {
v, ok := v.(map[string]interface{})
if !ok {
continue
}
for key, field := range v {
if _, ok := unionMap[key]; ok {
continue
}
unionMap[key] = field
}
}
return
}