-
Notifications
You must be signed in to change notification settings - Fork 64
/
Copy pathcode_gen.go
237 lines (218 loc) · 7.48 KB
/
code_gen.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
package codetemplete
import (
"SamWaf/utils"
"bytes"
"fmt"
"html"
"os"
"path/filepath"
"reflect"
"strings"
"text/template"
"unicode"
)
// getStructFields 拉平解析结构体的字段信息,支持嵌套结构体
func GetStructFields(t interface{}) []map[string]string {
var fields []map[string]string
typ := reflect.TypeOf(t)
// 确保输入的是结构体
if typ.Kind() == reflect.Struct {
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
// 如果字段是嵌套结构体,递归解析子模型
if field.Type.Kind() == reflect.Struct && field.Type.String() != "time.Time" {
//fmt.Printf("field.Type.String():" + field.Type.String())
subFields := GetStructFields(reflect.New(field.Type).Elem().Interface())
fields = append(fields, subFields...)
} else {
// 普通字段
if field.Name == "wall" || field.Name == "ext" || field.Name == "loc" {
continue
}
fields = append(fields, map[string]string{
"Name": field.Name,
"Type": field.Type.String(),
"Tag": string(field.Tag),
})
}
}
}
return fields
}
func initFunc() template.FuncMap {
return template.FuncMap{
"lower": func(s string) string {
return string(bytes.ToLower([]byte(s)))
},
"pascalCase": func(s string) string {
// 将字符串转换为首字母大写格式(PascalCase)
words := strings.Fields(s) // 按空格分割单词
for i := range words {
// 对每个单词的首字母进行大写
words[i] = strings.Title(words[i])
}
// 连接成一个字符串并返回
return strings.Join(words, "")
},
"unescapeHtml": func(s string) string {
return html.UnescapeString(s)
},
"addForm": func(s string) string {
return strings.ReplaceAll(s, "json:", "form:")
},
"snakeCase": func(s string) string {
// 将字符串转换为小写并替换大写字母为下划线连接的小写字母
var result []rune
for i, r := range s {
// 如果是大写字母且不是第一个字符,前面加下划线
if unicode.IsUpper(r) {
if i > 0 {
result = append(result, '_')
}
// 转换为小写
result = append(result, unicode.ToLower(r))
} else {
result = append(result, r)
}
}
return string(result)
},
"removeQuotes": func(s string) string {
// 去掉字符串中的引号
return strings.ReplaceAll(s, `"`, "")
},
}
}
// renderTemplateAndSave 用于渲染模板并保存到指定路径
// templatePath:模板文件的路径
// renderData:传递给模板的数据
// outputPath 路径
// outputPathTemplate:输出文件的保存文件模板
// isDefaultDelim 是否默认模板分隔符
func renderTemplateAndSave(templatePath string, renderData map[string]interface{}, outputPath string, outputPathTemplate string, isDefaultDelim bool) error {
// 读取模板文件
templateContent, err := os.ReadFile(templatePath)
if err != nil {
return fmt.Errorf("读取模板文件失败: %v", err)
}
// 如果 isDefaultDelim 为 false,使用自定义分隔符
var tmpl *template.Template
if isDefaultDelim {
// 使用默认分隔符
tmpl, err = template.New("apiTemplate").Funcs(initFunc()).Parse(string(templateContent))
} else {
// 使用自定义分隔符,防止与 Vue 模板冲突
tmpl, err = template.New("vueTemplate").Delims("[[", "]]").Funcs(initFunc()).Parse(string(templateContent))
}
if err != nil {
return fmt.Errorf("解析模板失败: %v", err)
}
// 渲染模板
var renderedCode bytes.Buffer
if isDefaultDelim {
err = tmpl.Execute(&renderedCode, renderData)
if err != nil {
return fmt.Errorf("渲染模板失败: %v", err)
}
} else {
err = tmpl.ExecuteTemplate(&renderedCode, "vueTemplate", renderData)
if err != nil {
return fmt.Errorf("渲染模板失败: %v", err)
}
}
// 解码HTML实体字符
//decodedCode := html.UnescapeString(renderedCode.String())
/*fmt.Println("Before Rendered Code:")
fmt.Println(renderedCode)
fmt.Println("Decoded Rendered Code:")
fmt.Println(decodedCode)*/
// 渲染输出路径
utils.CheckPathAndCreate(outputPath)
outputPathTemplateParsed, err := template.New("outputPath").Funcs(initFunc()).Parse(outputPathTemplate)
if err != nil {
return fmt.Errorf("解析输出路径模板失败: %v", err)
}
var outputPathBuffer bytes.Buffer
err = outputPathTemplateParsed.Execute(&outputPathBuffer, renderData)
if err != nil {
return fmt.Errorf("渲染输出路径失败: %v", err)
}
// 输出到指定文件
outputPathFinal := filepath.Join(outputPath, outputPathBuffer.String())
err = os.WriteFile(outputPathFinal, renderedCode.Bytes(), 0644)
if err != nil {
return fmt.Errorf("写入输出文件失败: %v", err)
}
fmt.Printf("代码生成成功,已保存到 %s\n", outputPathFinal)
return nil
}
func CodeGeneration(entityName string, fields []map[string]string, uniFields []map[string]string) {
fmt.Printf("%v\n", fields)
fmt.Printf("%v\n", uniFields)
// 打印当前工作目录
/* currentDir, err := os.Getwd()
fmt.Println(currentDir)*/
// 生成api
err := renderTemplateAndSave("./tpl/waf_api.txt", map[string]interface{}{
"EntityName": entityName, // 需要替换的实体名称
"Fields": fields,
"UniFields": uniFields, //唯一识别的字段
}, "./output/"+entityName+"/api/", "waf_{{.EntityName | lower}}_api.go", true)
if err != nil {
fmt.Printf("生成代码失败: %v\n", err)
}
// 生成service
err = renderTemplateAndSave("./tpl/waf_service.txt", map[string]interface{}{
"EntityName": entityName, // 需要替换的实体名称
"Fields": fields,
"UniFields": uniFields, //唯一识别的字段
}, "./output/"+entityName+"/service/", "waf_{{.EntityName | lower}}_service.go", true)
if err != nil {
fmt.Printf("生成代码失败: %v\n", err)
}
// 生成req
err = renderTemplateAndSave("./tpl/waf_req.txt", map[string]interface{}{
"EntityName": entityName, // 需要替换的实体名称
"Fields": fields,
"UniFields": uniFields, //唯一识别的字段
}, "./output/"+entityName+"/request/", "waf_{{.EntityName | lower}}_req.go", true)
if err != nil {
fmt.Printf("生成代码失败: %v\n", err)
}
// 生成router
err = renderTemplateAndSave("./tpl/waf_router.txt", map[string]interface{}{
"EntityName": entityName, // 需要替换的实体名称
"Fields": fields,
"UniFields": uniFields, //唯一识别的字段
}, "./output/"+entityName+"/router/", "waf_{{.EntityName | lower}}_router.go", true)
if err != nil {
fmt.Printf("生成代码失败: %v\n", err)
}
// 生成vue
err = renderTemplateAndSave("./tpl/index_vue.txt", map[string]interface{}{
"EntityName": entityName, // 需要替换的实体名称
"Fields": fields,
"UniFields": uniFields, //唯一识别的字段
}, "./output/"+entityName+"/vue/", "index.vue", false)
if err != nil {
fmt.Printf("生成代码失败: %v\n", err)
}
// 生成js api
err = renderTemplateAndSave("./tpl/index_jsapi.txt", map[string]interface{}{
"EntityName": entityName, // 需要替换的实体名称
"Fields": fields,
"UniFields": uniFields, //唯一识别的字段
}, "./output/"+entityName+"/vue/", "{{.EntityName | snakeCase}}.ts", true)
if err != nil {
fmt.Printf("生成代码失败: %v\n", err)
}
// 生成语言文件
err = renderTemplateAndSave("./tpl/index_zh_en.txt", map[string]interface{}{
"EntityName": entityName, // 需要替换的实体名称
"Fields": fields,
"UniFields": uniFields, //唯一识别的字段
}, "./output/"+entityName+"/vue/", "{{.EntityName | snakeCase}}_zh_en.ts", false)
if err != nil {
fmt.Printf("生成代码失败: %v\n", err)
}
}