package templ import ( "bufio" "bytes" "embed" "errors" "fmt" "log" "os" "path/filepath" "regexp" "strings" "text/template" "git.ymnuktech.ru/ymnuk/yt-gen-app/structs" uuid "github.com/satori/go.uuid" ) //go:embed tmpl/* var Content embed.FS var funcMap = template.FuncMap{ //"includeTemplPart": IncludeTemplPart, "fieldName": FieldName, "fieldChildName": FieldChildName, "fieldNamePrepare": FieldNamePrepare, "fieldNameLowerPrepare": FieldNameLowerPrepare, "fieldJsonNameStr": FieldJsonNameStr, "fieldType": FieldType, "fieldTypeStr": FieldTypeStr, "fieldStringToType": FieldStringToType, //"fieldDbTableType": FieldDbTableType, "fieldTypeDB": FieldTypeDB, "fieldTypeDBStr": FieldTypeDBStr, "fieldTypeParentTable": FieldTypeParentTable, "hasFieldType": HasFieldType, "fieldDescript": FieldDescript, "configParamName": ConfigParamName, "configParamType": ConfigParamType, "configParamTag": ConfigParamTag, "packageName": PackageName, "methodNameGetId": MethodNameGetId, "methodSummary": MethodSummary, "methodComment": MethodComment, "getModelName": GetModelName, "getModelNameAngular": GetModelNameAngular, "displayMethodNamePost": DisplayMethodNamePost, "methodNamePost": MethodNamePost, "displayMethodNameGet": DisplayMethodNameGet, "methodNameGet": MethodNameGet, "isMethod": IsMethod, "roles": Roles, "removeFirstChar": RemoveFirstChar, "angularRestName": AngularRestName, "angularFilename": AngularFilename, "getFieldsByModelID": GetFieldsByModelID, "getFksByModelID": GetFksByModelID, "getFksByModelID2": GetFksByModelID2, "fieldToVisField": FieldToVisField, "fieldToVisField2": FieldToVisField2, "fieldJsonDescriptionStrClear": FieldJsonDescriptionStrClear, "backendFsPath": BackendFsPath, "parseRestPath": ParseRestPath, "parseRestPathForName": ParseRestPathForName, "parseRestPathParams": ParseRestPathParams, "fieldInTableByName": FieldInTableByName, "escapeChars": EscapeChars, } func EscapeChars(value string) string { value = strings.ReplaceAll(value, "/", "\\/") return value } func IncludeTemplPart(templName string, data interface{}) string { var err error var tmpl *template.Template if tmpl, err = ReadTmplFile(templName); err != nil { panic(err) } var out []byte if out, err = ExecuteTmplFile(tmpl, data); err != nil { panic(err) } /*arr:=strings.Split(string(out)) var newArr []string for*/ return string(out) } func IsMethod(arr map[string][]string, method string) bool { if arr == nil { return false } _, ok := arr[method] return ok } func Roles(arr map[string][]string, method string) []string { if arr == nil { return nil } return arr[method] } func FieldNamePrepare(value string) string { value = strings.Trim(value, " ") if value == "" { //log.SetFlags(log.Llongfile) log.Fatal("Should be set name for field") } asRunes := []rune(value) asRunes[0] = []rune(strings.ToUpper(string([]rune(value)[0])))[0] value = string(asRunes) i := strings.Index(value, "_") for i != -1 { asRunes := []rune(value) if i >= len(value) { break } asRunes[i+1] = []rune(strings.ToUpper(string(asRunes[i+1])))[0] asRunes = append(asRunes[:i], asRunes[i+1:]...) value = string(asRunes) i = strings.Index(value, "_") } var regexpForReplace = regexp.MustCompile(`([Ii][Dd]$)`) value = regexpForReplace.ReplaceAllString(value, "ID") return value } func FieldNameLowerPrepare(value string) string { var regexpForReplace = regexp.MustCompile(`([A-Z])`) value = strings.ToLower(regexpForReplace.ReplaceAllString(value, "_$1")) if []rune(value)[0] == '_' { value = string([]rune(value)[1:]) } value = strings.ReplaceAll(value, "i_d", "id") return value } func FieldName(field *structs.Field) string { if field == nil { log.Fatal("Field is null") } field.Name = strings.Trim(field.Name, " ") if field.Name == "" { log.Fatal("Should be set name for field") } field.Name = FieldNamePrepare(field.Name) return field.Name } func FieldChildName(field *structs.Field) string { return FieldName(field) } // Возвращает имя в БД func FieldDBName(field *structs.Field) (res string) { res = strings.Trim(field.Name, " ") if res == "" { log.Fatal("Shoudl be set name for field") } //res = strings.ToLower(res) res = FieldNameLowerPrepare(res) return } func FieldTypeParentTable(field *structs.Field) string { return FieldType(&structs.Field{Type: field.TypeParentTable}) } func FieldTypeStr(value string) string { value = strings.ToLower(strings.Trim(value, " ")) if value == "" { return value } switch value { case "text": return "*string" case "string": return "*string" case "int": return "*int" case "bigint": return "*int64" case "double": return "*float64" case "float": return "*float32" case "uuid": return "*uuid.UUID" case "date": return "*time.Time" case "time": return "*time.Time" case "bool": return "*bool" case "any": return "[]byte" default: fkTmp := &structs.Field{ Name: value, } return FieldName(fkTmp) //log.Fatalf("Unknow format %s", field.Type) } } func FieldType(field *structs.Field) string { if field == nil { log.Fatal("field is empty") } field.Type = strings.ToLower(strings.Trim(field.Type, " ")) value := FieldTypeStr(field.Type) if value == "" { field.Type = "text" value = "text" } return value //return "" } func FieldDbTableType(field *structs.Field) string { return FieldNamePrepare(FieldDBName(&structs.Field{ Name: field.Type, })) } func HasFieldType(fields []structs.Field, typeName string) (has bool) { for _, field := range fields { if (field.Type == "date" || field.Type == "time") && (typeName == "date" || typeName == "time") { return true } if field.Type == typeName || field.TypeParentTable == typeName { return true } } return false } func FieldTypeDBStr(value string, length *int) string { switch value { case "text": return "TEXT" case "string": tmp := "VARCHAR" if length != nil && *length == 0 { tmp += fmt.Sprintf("(%d)", *length) } else { tmp += "(255)" } //return "TEXT" return tmp case "int": return "INT" case "bigint": return "BIGINT" case "uuid": return "UUID" case "float": return "FLOAT" case "double": return "DOUBLE" case "date": return "DATE" case "time": return "timestamp" case "bool": return "int" default: log.Fatalf("Unknow format %s", value) } return "" } func FieldTypeDB(field *structs.Field) string { field.Type = strings.ToLower(strings.Trim(field.Type, " ")) return FieldTypeDBStr(field.Type, field.Length) } // Генерирование описания таблиц в БД func FieldDescript(field *structs.Field, fieldId bool) (str string) { str = "`" if fieldId { str = fmt.Sprintf("`gorm:\"column:%s;type:%s", FieldDBName(field), FieldTypeDB(field)) field.Description = strings.Trim(field.Description, " ") if field.Description != "" { str += fmt.Sprintf(";comment:%s", field.Description) } str += "\"" } if fieldId { str = fmt.Sprintf("%s json:\"%sId,omitempty\"`", str, FieldJsonName(field)) } else { str = fmt.Sprintf("%s json:\"%s,omitempty\"`", str, FieldJsonName(field)) } return } // Вернуть название параметра func ConfigParamName(field *structs.ParamConfig) string { if field == nil { log.Fatal("Field is null") } field.Name = strings.Trim(field.Name, " ") if field.Name == "" { log.Fatal("Should be set name for field") } return FieldNamePrepare(field.Name) } // Вернуть тип параметра func ConfigParamType(field *structs.ParamConfig) string { if field == nil { log.Fatal("Param should be set") } field.Type = strings.Trim(field.Type, " ") if field.Type == "" { log.Fatal("Param type should be set") } switch field.Type { case "string": return "string" default: log.Fatal("Unknow type") } return "" } // Вернуть строку для тэгирования параметров func ConfigParamTag(field *structs.ParamConfig) string { if field == nil { log.Fatal("Param should be set") } if field == nil { log.Fatal("Field is null") } field.Name = strings.Trim(field.Name, " ") if field.Name == "" { log.Fatal("Shoudl be set name for field") } tag := fmt.Sprintf("`arg:\"--%s,env:%s\"", strings.ReplaceAll(strings.ToLower(field.Name), "_", "-"), strings.ReplaceAll(strings.ToUpper(field.Name), "-", "_")) field.Help = strings.Trim(field.Help, " ") if field.Help != "" { tag += fmt.Sprintf(" help:\"%s\"", field.Help) } tag += "`" return tag } func WriteTmplFile(filename string, outname string) error { fmt.Printf("Generate: %s\n", outname) if buff, err := Content.ReadFile(filename); err != nil { return err } else { if err = os.WriteFile(outname, buff, 0755); err != nil { return err } } return nil } // Чтение шаблона и его подготовка func ReadTmplFile(filename string) (tmpl *template.Template, err error) { var ( buff []byte ) if buff, err = Content.ReadFile(filename); err != nil { return } var ( tmp string //tmpl *template.Template ) if tmp, err = RandomHex(4); err != nil { return } if _, ok := funcMap["includeTemplPart"]; !ok { funcMap["includeTemplPart"] = IncludeTemplPart } tmpl, err = template.New(tmp).Funcs(funcMap).Parse(string(buff)) return } // Запись файла на диск func WriteFile(outname string, data []byte) (err error) { err = os.WriteFile(outname, data, 0755) return } // Выполнить шаблон func ExecuteTmplFile(tmpl *template.Template, data interface{}) (out []byte, err error) { var b bytes.Buffer w := bufio.NewWriter(&b) if err = tmpl.Execute(w, data); err != nil { return } w.Flush() out = b.Bytes() return } // Использование шаблона func PrepareTmplFile(filename string, data interface{}, outname string) (err error) { dir := filepath.Dir(outname) if err = MkdirIsNotExists(dir); err != nil { return err } fmt.Printf("Generate: %s\n", outname) /*var b bytes.Buffer w := bufio.NewWriter(&b)*/ var tmpl *template.Template if tmpl, err = ReadTmplFile(filename); err != nil { return } /*if err = tmpl.Execute(w, data); err != nil { return err } w.Flush()*/ var out []byte if out, err = ExecuteTmplFile(tmpl, data); err != nil { return } return WriteFile(outname, out) } // Подготовка файла, если его нет на диске func PrepareTmplIsNotExists(filename string, data interface{}, outname string) (err error) { if err = MkdirIsNotExists(filepath.Dir(outname)); err != nil { return } if _, err := os.Stat(outname); errors.Is(err, os.ErrNotExist) { return PrepareTmplFile(filename, data, outname) } return nil } func MkdirIsNotExists(pathdir string) (err error) { if _, err = os.Stat(pathdir); os.IsNotExist(err) { if err = os.MkdirAll(pathdir, 0775); err != nil { return } } err = nil return } func AngularRestName(tmp string) string { value := tmp value = strings.Trim(value, " ") if value == "" { return "Unknow" } value = strings.ReplaceAll(ParseRestPathForName(value), "/", "_") value = FieldNamePrepare(value) /*var regexpForReplace = regexp.MustCompile(`_([a-z])`) value = strings.ToUpper(regexpForReplace.ReplaceAllString(value, `$1`)) asRunes := []rune(value) asRunes[0] = []rune(strings.ToUpper(string([]rune(value)[0])))[0] value = string(asRunes)*/ return value } func AngularFilename(value string) string { value = strings.Trim(value, " ") if value == "" { return "unknow" } value = strings.ReplaceAll(ParseRestPathForName(value), "/", "-") if []rune(value)[0] == '-' { value = string([]rune(value)[1:]) } return value } func RemoveFirstChar(value string) string { value = strings.Trim(value, " ") if value == "" { return "" } runes := []rune(value) if runes[0] == '-' || runes[0] == '/' || runes[0] == '\\' || runes[0] == '_' || runes[0] == '*' { value = string(runes[1:]) } else { value = string(runes) } return value } func GetFieldsByModelID(project *structs.Project, id uuid.UUID) []structs.Field { tmpSrc := FindSourceDataInDBByID(project, id) if tmpSrc != nil { return tmpSrc.Fields } tmpInterface := FindSourceDataInInterfaceByID(project, id) if tmpInterface != nil { return tmpInterface.Fields } return nil } func GetFksByModelID(project *structs.Project, id uuid.UUID) []structs.Field { tmpSrc := FindSourceDataInDBByID(project, id) if tmpSrc != nil { return tmpSrc.FkFields } return nil } func GetFksByModelID2(project *structs.Project, id uuid.UUID) []structs.FK { tmpSrc := FindSourceDataInDBByID(project, id) if tmpSrc != nil { return tmpSrc.FKs } return nil } func GetFieldsByModelName(project *structs.Project, name string) []structs.Field { tmpSrc := FindSourceDataInDBByName(project, name) if tmpSrc != nil { return tmpSrc.Fields } tmpInterface := FindSourceDataInInterfaceByName(project, name) if tmpInterface != nil { return tmpInterface.Fields } return nil } func FieldToVisField(field structs.Field) (res structs.VisField) { res.Name = field.Name res.ID = field.ID // fmt.Println(res) return } func FieldToVisField2(field structs.FK) (res structs.VisField) { res.Name = field.Name res.ID = field.TableID // fmt.Println(res) return } func FieldJsonDescriptionStrClear(value string) string { return strings.ReplaceAll(strings.ReplaceAll(value, "\"", ""), "\\", "") }