github.com/clubpay/ronykit/kit@v0.14.4-0.20240515065620-d0dace45cbc7/utils/transform.go (about) 1 package utils 2 3 import ( 4 "strings" 5 ) 6 7 /* 8 Creation Time: 2020 - Apr - 09 9 Created by: (ehsan) 10 Maintainers: 11 1. Ehsan N. Moosa (E2) 12 Auditor: Ehsan N. Moosa (E2) 13 */ 14 15 var uppercaseAcronym = map[string]string{ 16 "ID": "id", 17 "HTML": "html", 18 "RPC": "rpc", 19 } 20 21 // Converts a string to CamelCase 22 func toCamelInitCase(s string, initCase bool) string { 23 s = strings.TrimSpace(s) 24 if s == "" { 25 return s 26 } 27 if a, ok := uppercaseAcronym[s]; ok { 28 s = a 29 } 30 31 n := strings.Builder{} 32 n.Grow(len(s)) 33 capNext := initCase 34 for i, v := range []byte(s) { 35 vIsCap := v >= 'A' && v <= 'Z' 36 vIsLow := v >= 'a' && v <= 'z' 37 if capNext { 38 if vIsLow { 39 v += 'A' 40 v -= 'a' 41 } 42 } else if i == 0 { 43 if vIsCap { 44 v += 'a' 45 v -= 'A' 46 } 47 } 48 if vIsCap || vIsLow { 49 n.WriteByte(v) 50 capNext = false 51 } else if vIsNum := v >= '0' && v <= '9'; vIsNum { 52 n.WriteByte(v) 53 capNext = true 54 } else { 55 capNext = v == '_' || v == ' ' || v == '-' || v == '.' 56 } 57 } 58 59 return n.String() 60 } 61 62 // ToCamel converts a string to CamelCase 63 func ToCamel(s string) string { 64 return toCamelInitCase(s, true) 65 } 66 67 // ToLowerCamel converts a string to lowerCamelCase 68 func ToLowerCamel(s string) string { 69 return toCamelInitCase(s, false) 70 } 71 72 // ToSnake converts a string to snake_case 73 func ToSnake(s string) string { 74 return ToDelimited(s, '_') 75 } 76 77 func ToSnakeWithIgnore(s string, ignore uint8) string { 78 return ToScreamingDelimited(s, '_', ignore, false) 79 } 80 81 // ToScreamingSnake converts a string to SCREAMING_SNAKE_CASE 82 func ToScreamingSnake(s string) string { 83 return ToScreamingDelimited(s, '_', 0, true) 84 } 85 86 // ToKebab converts a string to kebab-case 87 func ToKebab(s string) string { 88 return ToDelimited(s, '-') 89 } 90 91 // ToScreamingKebab converts a string to SCREAMING-KEBAB-CASE 92 func ToScreamingKebab(s string) string { 93 return ToScreamingDelimited(s, '-', 0, true) 94 } 95 96 // ToDelimited converts a string to delimited.snake.case 97 // (in this case `delimiter = '.'`) 98 func ToDelimited(s string, delimiter uint8) string { 99 return ToScreamingDelimited(s, delimiter, 0, false) 100 } 101 102 // ToScreamingDelimited converts a string to SCREAMING.DELIMITED.SNAKE.CASE 103 // (in this case `delimiter = '.'; screaming = true`) 104 // or delimited.snake.case 105 // (in this case `delimiter = '.'; screaming = false`) 106 func ToScreamingDelimited(s string, delimiter uint8, ignore uint8, screaming bool) string { //nolint:gocognit,gocyclo 107 n := strings.Builder{} 108 n.Grow(len(s) + 2) // nominal 2 bytes of extra space for inserted delimiters 109 start := true 110 spaces := 0 111 for i, v := range []byte(s) { 112 if v == ' ' { 113 spaces++ 114 115 continue 116 } else if start { 117 start = false 118 spaces = 0 119 } else { 120 for ; spaces > 0; spaces-- { 121 if ignore == ' ' { 122 n.WriteByte(' ') 123 } else { 124 n.WriteByte(delimiter) 125 } 126 } 127 } 128 129 vIsCap := v >= 'A' && v <= 'Z' 130 vIsLow := v >= 'a' && v <= 'z' 131 if vIsLow && screaming { 132 v += 'A' 133 v -= 'a' 134 } else if vIsCap && !screaming { 135 v += 'a' 136 v -= 'A' 137 } 138 139 // treat acronyms as words, eg. for JSONData -> ToJSON is a whole word 140 //nolint:nestif 141 if i+1 < len(s) { 142 next := s[i+1] 143 vIsNum := v >= '0' && v <= '9' 144 nextIsCap := next >= 'A' && next <= 'Z' 145 nextIsLow := next >= 'a' && next <= 'z' 146 nextIsNum := next >= '0' && next <= '9' 147 // add underscore if next letter case type is changed 148 if (vIsCap && (nextIsLow || nextIsNum)) || 149 (vIsLow && (nextIsCap || nextIsNum)) || 150 (vIsNum && (nextIsCap || nextIsLow)) { 151 if prevIgnore := ignore > 0 && i > 0 && s[i-1] == ignore; !prevIgnore { 152 if vIsCap && nextIsLow { 153 if prevIsCap := i > 0 && s[i-1] >= 'A' && s[i-1] <= 'Z'; prevIsCap { 154 n.WriteByte(delimiter) 155 } 156 } 157 n.WriteByte(v) 158 if vIsLow || vIsNum || nextIsNum { 159 n.WriteByte(delimiter) 160 } 161 162 continue 163 } 164 } 165 } 166 167 if (v == ' ' || v == '_' || v == '-') && v != ignore { 168 // replace space/underscore/hyphen with delimiter 169 n.WriteByte(delimiter) 170 } else { 171 n.WriteByte(v) 172 } 173 } 174 175 return n.String() 176 }