feat(templ): ✨ added templ to command line that reads go template and outputs code
This commit is contained in:
316
pkg/writers/template/string_helpers.go
Normal file
316
pkg/writers/template/string_helpers.go
Normal file
@@ -0,0 +1,316 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// ToUpper converts a string to uppercase
|
||||
func ToUpper(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
}
|
||||
|
||||
// ToLower converts a string to lowercase
|
||||
func ToLower(s string) string {
|
||||
return strings.ToLower(s)
|
||||
}
|
||||
|
||||
// ToCamelCase converts snake_case to camelCase
|
||||
// Examples: user_name → userName, http_request → httpRequest
|
||||
func ToCamelCase(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
parts := strings.Split(s, "_")
|
||||
for i, part := range parts {
|
||||
if i == 0 {
|
||||
parts[i] = strings.ToLower(part)
|
||||
} else {
|
||||
parts[i] = capitalize(part)
|
||||
}
|
||||
}
|
||||
return strings.Join(parts, "")
|
||||
}
|
||||
|
||||
// ToPascalCase converts snake_case to PascalCase
|
||||
// Examples: user_name → UserName, http_request → HTTPRequest
|
||||
func ToPascalCase(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
parts := strings.Split(s, "_")
|
||||
for i, part := range parts {
|
||||
parts[i] = capitalize(part)
|
||||
}
|
||||
return strings.Join(parts, "")
|
||||
}
|
||||
|
||||
// ToSnakeCase converts PascalCase/camelCase to snake_case
|
||||
// Examples: UserName → user_name, HTTPRequest → http_request
|
||||
func ToSnakeCase(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
var result strings.Builder
|
||||
var prevUpper bool
|
||||
var nextUpper bool
|
||||
|
||||
runes := []rune(s)
|
||||
for i, r := range runes {
|
||||
isUpper := unicode.IsUpper(r)
|
||||
|
||||
if i+1 < len(runes) {
|
||||
nextUpper = unicode.IsUpper(runes[i+1])
|
||||
} else {
|
||||
nextUpper = false
|
||||
}
|
||||
|
||||
if i > 0 && isUpper {
|
||||
// Add underscore before uppercase letter if:
|
||||
// 1. Previous char was lowercase, OR
|
||||
// 2. Next char is lowercase (end of acronym)
|
||||
if !prevUpper || (!nextUpper && i+1 < len(runes)) {
|
||||
result.WriteRune('_')
|
||||
}
|
||||
}
|
||||
|
||||
result.WriteRune(unicode.ToLower(r))
|
||||
prevUpper = isUpper
|
||||
}
|
||||
|
||||
return result.String()
|
||||
}
|
||||
|
||||
// ToKebabCase converts snake_case or PascalCase/camelCase to kebab-case
|
||||
// Examples: user_name → user-name, UserName → user-name
|
||||
func ToKebabCase(s string) string {
|
||||
// First convert to snake_case, then replace underscores with hyphens
|
||||
snakeCase := ToSnakeCase(s)
|
||||
return strings.ReplaceAll(snakeCase, "_", "-")
|
||||
}
|
||||
|
||||
// Title capitalizes the first letter of each word
|
||||
func Title(s string) string {
|
||||
caser := cases.Title(language.English)
|
||||
src := []byte(s)
|
||||
dest := []byte(s)
|
||||
_, _, _ = caser.Transform(dest, src, true)
|
||||
return string(dest)
|
||||
}
|
||||
|
||||
// Pluralize converts a singular word to plural
|
||||
// Basic implementation with common English rules
|
||||
func Pluralize(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Special cases
|
||||
irregular := map[string]string{
|
||||
"person": "people",
|
||||
"child": "children",
|
||||
"tooth": "teeth",
|
||||
"foot": "feet",
|
||||
"man": "men",
|
||||
"woman": "women",
|
||||
"mouse": "mice",
|
||||
"goose": "geese",
|
||||
"ox": "oxen",
|
||||
"datum": "data",
|
||||
"medium": "media",
|
||||
"analysis": "analyses",
|
||||
"crisis": "crises",
|
||||
"status": "statuses",
|
||||
}
|
||||
|
||||
if plural, ok := irregular[strings.ToLower(s)]; ok {
|
||||
return plural
|
||||
}
|
||||
|
||||
// Already plural (ends in 's' but not 'ss' or 'us')
|
||||
if strings.HasSuffix(s, "s") && !strings.HasSuffix(s, "ss") && !strings.HasSuffix(s, "us") {
|
||||
return s
|
||||
}
|
||||
|
||||
// Words ending in s, x, z, ch, sh
|
||||
if strings.HasSuffix(s, "s") || strings.HasSuffix(s, "x") ||
|
||||
strings.HasSuffix(s, "z") || strings.HasSuffix(s, "ch") ||
|
||||
strings.HasSuffix(s, "sh") {
|
||||
return s + "es"
|
||||
}
|
||||
|
||||
// Words ending in consonant + y
|
||||
if len(s) >= 2 && strings.HasSuffix(s, "y") {
|
||||
prevChar := s[len(s)-2]
|
||||
if !isVowel(prevChar) {
|
||||
return s[:len(s)-1] + "ies"
|
||||
}
|
||||
}
|
||||
|
||||
// Words ending in f or fe
|
||||
if strings.HasSuffix(s, "f") {
|
||||
return s[:len(s)-1] + "ves"
|
||||
}
|
||||
if strings.HasSuffix(s, "fe") {
|
||||
return s[:len(s)-2] + "ves"
|
||||
}
|
||||
|
||||
// Words ending in consonant + o
|
||||
if len(s) >= 2 && strings.HasSuffix(s, "o") {
|
||||
prevChar := s[len(s)-2]
|
||||
if !isVowel(prevChar) {
|
||||
return s + "es"
|
||||
}
|
||||
}
|
||||
|
||||
// Default: add 's'
|
||||
return s + "s"
|
||||
}
|
||||
|
||||
// Singularize converts a plural word to singular
|
||||
// Basic implementation with common English rules
|
||||
func Singularize(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Special cases
|
||||
irregular := map[string]string{
|
||||
"people": "person",
|
||||
"children": "child",
|
||||
"teeth": "tooth",
|
||||
"feet": "foot",
|
||||
"men": "man",
|
||||
"women": "woman",
|
||||
"mice": "mouse",
|
||||
"geese": "goose",
|
||||
"oxen": "ox",
|
||||
"data": "datum",
|
||||
"media": "medium",
|
||||
"analyses": "analysis",
|
||||
"crises": "crisis",
|
||||
"statuses": "status",
|
||||
}
|
||||
|
||||
if singular, ok := irregular[strings.ToLower(s)]; ok {
|
||||
return singular
|
||||
}
|
||||
|
||||
// Words ending in ies
|
||||
if strings.HasSuffix(s, "ies") && len(s) > 3 {
|
||||
return s[:len(s)-3] + "y"
|
||||
}
|
||||
|
||||
// Words ending in ves
|
||||
if strings.HasSuffix(s, "ves") {
|
||||
return s[:len(s)-3] + "f"
|
||||
}
|
||||
|
||||
// Words ending in ses, xes, zes, ches, shes
|
||||
if strings.HasSuffix(s, "ses") || strings.HasSuffix(s, "xes") ||
|
||||
strings.HasSuffix(s, "zes") || strings.HasSuffix(s, "ches") ||
|
||||
strings.HasSuffix(s, "shes") {
|
||||
return s[:len(s)-2]
|
||||
}
|
||||
|
||||
// Words ending in s (not ss)
|
||||
if strings.HasSuffix(s, "s") && !strings.HasSuffix(s, "ss") {
|
||||
return s[:len(s)-1]
|
||||
}
|
||||
|
||||
// Already singular
|
||||
return s
|
||||
}
|
||||
|
||||
// Trim trims whitespace from both ends
|
||||
func Trim(s string) string {
|
||||
return strings.TrimSpace(s)
|
||||
}
|
||||
|
||||
// TrimPrefix removes the prefix from the string if present
|
||||
func TrimPrefix(s, prefix string) string {
|
||||
return strings.TrimPrefix(s, prefix)
|
||||
}
|
||||
|
||||
// TrimSuffix removes the suffix from the string if present
|
||||
func TrimSuffix(s, suffix string) string {
|
||||
return strings.TrimSuffix(s, suffix)
|
||||
}
|
||||
|
||||
// Replace replaces occurrences of old with new (n times, or all if n < 0)
|
||||
func Replace(s, old, newstr string, n int) string {
|
||||
return strings.Replace(s, old, newstr, n)
|
||||
}
|
||||
|
||||
// StringContains checks if substr is within s
|
||||
func StringContains(s, substr string) bool {
|
||||
return strings.Contains(s, substr)
|
||||
}
|
||||
|
||||
// HasPrefix checks if string starts with prefix
|
||||
func HasPrefix(s, prefix string) bool {
|
||||
return strings.HasPrefix(s, prefix)
|
||||
}
|
||||
|
||||
// HasSuffix checks if string ends with suffix
|
||||
func HasSuffix(s, suffix string) bool {
|
||||
return strings.HasSuffix(s, suffix)
|
||||
}
|
||||
|
||||
// Split splits string by separator
|
||||
func Split(s, sep string) []string {
|
||||
return strings.Split(s, sep)
|
||||
}
|
||||
|
||||
// Join joins string slice with separator
|
||||
func Join(parts []string, sep string) string {
|
||||
return strings.Join(parts, sep)
|
||||
}
|
||||
|
||||
// capitalize capitalizes the first letter and handles common acronyms
|
||||
func capitalize(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
upper := strings.ToUpper(s)
|
||||
|
||||
// Handle common acronyms
|
||||
acronyms := map[string]bool{
|
||||
"ID": true,
|
||||
"UUID": true,
|
||||
"GUID": true,
|
||||
"URL": true,
|
||||
"URI": true,
|
||||
"HTTP": true,
|
||||
"HTTPS": true,
|
||||
"API": true,
|
||||
"JSON": true,
|
||||
"XML": true,
|
||||
"SQL": true,
|
||||
"HTML": true,
|
||||
"CSS": true,
|
||||
"RID": true,
|
||||
}
|
||||
|
||||
if acronyms[upper] {
|
||||
return upper
|
||||
}
|
||||
|
||||
// Capitalize first letter
|
||||
runes := []rune(s)
|
||||
runes[0] = unicode.ToUpper(runes[0])
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
// isVowel checks if a byte is a vowel
|
||||
func isVowel(c byte) bool {
|
||||
c = byte(unicode.ToLower(rune(c)))
|
||||
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'
|
||||
}
|
||||
Reference in New Issue
Block a user