// Package helpers — конвертация имён, форматирование, plan-модификаторы. package helpers import ( "fmt" "go/format" "os" "strings" "unicode" "resource-generator/internal/types" ) // ToCamel конвертирует snake_case → CamelCase. func ToCamel(s string) string { parts := strings.FieldsFunc(s, func(r rune) bool { return r == '_' || r == '-' }) for i, p := range parts { if len(p) == 0 { continue } parts[i] = strings.ToUpper(p[:1]) + p[1:] } out := strings.Join(parts, "") return EnsureGoIdent(out) } // ToSnake конвертирует CamelCase → snake_case. func ToSnake(s string) string { var out []rune for i, r := range s { if i > 0 && r >= 'A' && r <= 'Z' { out = append(out, '_') } out = append(out, rune(strings.ToLower(string(r))[0])) } return string(out) } // ParamType возвращает Go-тип для параметра (types.Bool/Int64/String). func ParamType(p types.Param) string { switch strings.ToLower(p.Type) { case "bool": return "types.Bool" case "int", "int64", "number": return "types.Int64" default: return "types.String" } } // ParamDefaultExpr возвращает выражение значения по умолчанию. func ParamDefaultExpr(p types.Param) string { if p.Default == "" { return "" } switch strings.ToLower(p.Type) { case "bool": val := strings.ToLower(p.Default) return fmt.Sprintf("booldefault.StaticBool(%s)", val) case "int", "int64", "number": return fmt.Sprintf("int64default.StaticInt64(%s)", p.Default) default: return fmt.Sprintf("stringdefault.StaticString(%q)", p.Default) } } // ParamFormat возвращает вызов Format* для форматирования значения параметра. func ParamFormat(p types.Param, varName string) string { switch strings.ToLower(p.Type) { case "bool": return fmt.Sprintf("resources_core.FormatBool(%s)", varName) case "int", "int64", "number": return fmt.Sprintf("resources_core.FormatInt64(%s)", varName) default: return fmt.Sprintf("resources_core.FormatString(%s)", varName) } } // ParamParse возвращает имя Parse*-функции для параметра. func ParamParse(p types.Param) string { switch strings.ToLower(p.Type) { case "bool": return "resources_core.ParseBool" case "int", "int64", "number": return "resources_core.ParseInt64" default: return "resources_core.ParseString" } } // ParamDescription формирует MarkdownDescription для параметра. func ParamDescription(p types.Param) string { var desc string if strings.TrimSpace(p.Descr) != "" { desc = strings.TrimSpace(p.Descr) } else if strings.TrimSpace(p.Man) != "" { desc = strings.TrimSpace(p.Man) } else if p.RefSvcId > 0 { desc = fmt.Sprintf("UI display_name for service_id=%d (mapped to UUID in core)", p.RefSvcId) } if p.CreateOnly { if desc == "" { desc = "Не изменяется после создания." } else { desc = desc + " Не изменяется после создания." } } if p.ForceNew { if desc == "" { desc = "Изменение требует пересоздания." } else { desc = desc + " Изменение требует пересоздания." } } if desc == "" { return "" } return fmt.Sprintf("%q", desc) } // OutputParamType возвращает Go-тип для выходного параметра (types.Map/List/String). func OutputParamType(p types.OutputParam) string { switch strings.ToLower(p.Type) { case "map": return "types.Map" case "list": return "types.List" default: return "types.String" } } // OutputParamIsMap возвращает true, если выходной параметр — map. func OutputParamIsMap(p types.OutputParam) bool { return strings.EqualFold(strings.TrimSpace(p.Type), "map") } // OutputParamIsList возвращает true, если выходной параметр — list. func OutputParamIsList(p types.OutputParam) bool { return strings.EqualFold(strings.TrimSpace(p.Type), "list") } // OutputParamSensitive возвращает true, если параметр секретный. func OutputParamSensitive(p types.OutputParam) bool { return p.Sensitive } // EnsureGoIdent проверяет, что строка начинается с буквы или _. func EnsureGoIdent(s string) string { if s == "" { return "R" } first := rune(s[0]) if unicode.IsLetter(first) || first == '_' { return s } return "R" + s } // FormatSourceOrWarn форматирует Go-код. При ошибке пишет warning в stderr. func FormatSourceOrWarn(filePath string, src []byte) []byte { formatted, err := format.Source(src) if err != nil { fmt.Fprintf(os.Stderr, "WARNING: gofmt failed for %s: %v — writing unformatted code\n", filePath, err) return src } return formatted } // PlanModifierType возвращает суффикс типа план-модификатора (Bool/Int64/String). func PlanModifierType(p types.Param) string { switch strings.ToLower(strings.TrimSpace(p.Type)) { case "bool": return "Bool" case "int", "int64", "number": return "Int64" default: return "String" } } // PlanModifierExpr возвращает выражение план-модификатора RequiresReplace. func PlanModifierExpr(p types.Param) string { switch strings.ToLower(strings.TrimSpace(p.Type)) { case "bool": return "boolplanmodifier.RequiresReplace()" case "int", "int64", "number": return "int64planmodifier.RequiresReplace()" default: return "stringplanmodifier.RequiresReplace()" } }