mirror of
https://gitee.com/samwaf/SamWaf.git
synced 2026-10-31 02:01:44 +08:00
238 lines
7.5 KiB
Go
238 lines
7.5 KiB
Go
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)
|
|
}
|
|
}
|