package generator import ( "regexp" "strings" ) var ( kebabRegex = regexp.MustCompile(`[-_]`) mdLinkRegex = regexp.MustCompile(`\[([^\]]+)\]\([^)]+\)`) ) // ToPascalCase converts kebab-case or snake_case to PascalCase func ToPascalCase(s string) string { parts := kebabRegex.Split(s, -1) for i, p := range parts { if len(p) > 0 { parts[i] = strings.ToUpper(p[:1]) + p[1:] } } return strings.Join(parts, "") } // ToCamelCase converts kebab-case or snake_case to camelCase func ToCamelCase(s string) string { p := ToPascalCase(s) if len(p) > 0 { return strings.ToLower(p[:1]) + p[1:] } return p } // StripWaPrefix removes the "wa-" prefix from component names func StripWaPrefix(s string) string { return strings.TrimPrefix(s, "wa-") } // ToGoType converts TypeScript type to Go type func ToGoType(tsType string) string { tsType = strings.TrimSpace(tsType) switch { case tsType == "boolean": return "bool" case tsType == "number": return "float64" case tsType == "string": return "string" case tsType == "string | undefined", tsType == "string | null": return "string" case tsType == "number | undefined", tsType == "number | null": return "float64" case tsType == "boolean | undefined", tsType == "boolean | null": return "bool" case strings.HasPrefix(tsType, "'") && strings.Contains(tsType, "|"): // Union of string literals -> string return "string" case strings.Contains(tsType, "|"): // Complex union, default to string return "string" default: return "string" } } // ToBuilderType returns the type used in builder methods (always non-pointer for fluent API) func ToBuilderType(tsType string) string { return ToGoType(tsType) } // IsBoolean checks if the TypeScript type is boolean func IsBoolean(tsType string) bool { return strings.Contains(tsType, "boolean") } // IsNumber checks if the TypeScript type is numeric func IsNumber(tsType string) bool { return tsType == "number" || strings.HasPrefix(tsType, "number") } // CleanDescription cleans markdown and truncates description func CleanDescription(s string) string { if s == "" { return "" } // Take first line lines := strings.Split(s, "\n") first := strings.TrimSpace(lines[0]) // Strip markdown links first = mdLinkRegex.ReplaceAllString(first, "$1") // Remove backticks first = strings.ReplaceAll(first, "`", "") // Truncate if len(first) > 120 { first = first[:117] + "..." } return first } // ExtractEnumValues extracts string literal values from a union type func ExtractEnumValues(tsType string) []string { if !strings.Contains(tsType, "'") { return nil } re := regexp.MustCompile(`'([^']+)'`) matches := re.FindAllStringSubmatch(tsType, -1) values := make([]string, 0, len(matches)) for _, m := range matches { if len(m) > 1 { values = append(values, m[1]) } } return values } // ToEventName converts wa-event-name to OnEventName func ToEventName(s string) string { s = strings.TrimPrefix(s, "wa-") return "On" + ToPascalCase(s) } // ToSlotName converts slot name to Go-friendly name func ToSlotName(s string) string { if s == "" { return "Default" } return ToPascalCase(s) } // EscapeGoString escapes a string for use in Go source code func EscapeGoString(s string) string { s = strings.ReplaceAll(s, "\\", "\\\\") s = strings.ReplaceAll(s, "\"", "\\\"") s = strings.ReplaceAll(s, "\n", "\\n") s = strings.ReplaceAll(s, "\t", "\\t") return s }