// helpers — конвертация имён, форматирование, plan-модификаторы. package main import ( "fmt" "go/format" "os" "strings" "unicode" ) 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) } 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) } func paramType(p Param) string { switch strings.ToLower(p.Type) { case "bool": return "types.Bool" case "int", "int64", "number": return "types.Int64" default: return "types.String" } } func paramDefaultExpr(p 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) } } func paramFormat(p 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) } } func paramParse(p 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" } } func paramDescription(p 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) } func outputParamType(p OutputParam) string { switch strings.ToLower(p.Type) { case "map": return "types.Map" case "list": return "types.List" default: return "types.String" } } func outputParamIsMap(p OutputParam) bool { return strings.EqualFold(strings.TrimSpace(p.Type), "map") } func outputParamIsList(p OutputParam) bool { return strings.EqualFold(strings.TrimSpace(p.Type), "list") } func outputParamSensitive(p OutputParam) bool { return p.Sensitive } func ensureGoIdent(s string) string { if s == "" { return "R" } first := rune(s[0]) if unicode.IsLetter(first) || first == '_' { return s } return "R" + s } 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 } func planModifierType(p Param) string { switch strings.ToLower(strings.TrimSpace(p.Type)) { case "bool": return "Bool" case "int", "int64", "number": return "Int64" default: return "String" } } func planModifierExpr(p 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()" } }