github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/codegen/identifier.go (about) 1 package codegen 2 3 import ( 4 "strings" 5 "unicode" 6 "unicode/utf8" 7 ) 8 9 // https://github.com/golang/lint/blob/master/lint.go#L720 10 var commonInitialisms = map[string]bool{ 11 "ACL": true, 12 "API": true, 13 "ASCII": true, 14 "CPU": true, 15 "CSS": true, 16 "DNS": true, 17 "EOF": true, 18 "GUID": true, 19 "HTML": true, 20 "HTTP": true, 21 "HTTPS": true, 22 "ID": true, 23 "IP": true, 24 "JSON": true, 25 "LHS": true, 26 "QPS": true, 27 "RAM": true, 28 "RHS": true, 29 "RPC": true, 30 "SLA": true, 31 "SMTP": true, 32 "SQL": true, 33 "SSH": true, 34 "TCP": true, 35 "TLS": true, 36 "TTL": true, 37 "UDP": true, 38 "UI": true, 39 "UID": true, 40 "UUID": true, 41 "URI": true, 42 "URL": true, 43 "UTF8": true, 44 "VM": true, 45 "XML": true, 46 "XMPP": true, 47 "XSRF": true, 48 "XSS": true, 49 } 50 51 func SplitToWords(s string) (entries []string) { 52 if !utf8.ValidString(s) { 53 return []string{s} 54 } 55 entries = []string{} 56 var runes [][]rune 57 lastClass := 0 58 class := 0 59 60 // split into fields based on class of unicode character 61 for _, r := range s { 62 switch true { 63 case unicode.IsSpace(r): 64 class = 1 65 case unicode.IsLower(r): 66 class = 2 67 case unicode.IsUpper(r): 68 class = 3 69 case unicode.IsDigit(r): 70 class = 4 71 default: 72 class = 5 73 } 74 if class == lastClass { 75 runes[len(runes)-1] = append(runes[len(runes)-1], r) 76 } else { 77 runes = append(runes, []rune{r}) 78 } 79 lastClass = class 80 } 81 82 // handle upper case -> lower case sequences, e.g. 83 // "PDFL", "oader" -> "PDF", "Loader" 84 for i := 0; i < len(runes)-1; i++ { 85 if unicode.IsUpper(runes[i][0]) && unicode.IsLower(runes[i+1][0]) { 86 runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...) 87 runes[i] = runes[i][:len(runes[i])-1] 88 } 89 } 90 91 // construct []string from results 92 // 93 for _, s := range runes { 94 if len(s) > 0 && (unicode.IsDigit(s[0]) || unicode.IsLetter(s[0])) { 95 entries = append(entries, string(s)) 96 } 97 } 98 99 return 100 } 101 102 type RewordsReducer func(result string, word string, index int) string 103 104 func Rewords(s string, reducer RewordsReducer) string { 105 words := SplitToWords(s) 106 107 var result = "" 108 109 for idx, word := range words { 110 result = reducer(result, word, idx) 111 } 112 113 return result 114 } 115 116 func ToUpperFirst(s string) string { 117 runes := []rune(s) 118 runes[0] = unicode.ToUpper(runes[0]) 119 return string(runes) 120 } 121 122 func ToCamelCase(s string) string { 123 upperString := strings.ToUpper(s) 124 if commonInitialisms[upperString] { 125 return upperString 126 } 127 return ToUpperFirst(strings.ToLower(upperString)) 128 } 129 130 func ToUpperCamelCase(s string) string { 131 return Rewords(s, func(result string, word string, idx int) string { 132 return result + ToCamelCase(word) 133 }) 134 } 135 136 func ToLowerCamelCase(s string) string { 137 return Rewords(s, func(result string, word string, idx int) string { 138 if idx == 0 { 139 return result + strings.ToLower(word) 140 } 141 return result + ToCamelCase(word) 142 }) 143 } 144 145 func ToUpperSnakeCase(s string) string { 146 return Rewords(s, func(result string, word string, idx int) string { 147 newWord := strings.ToUpper(word) 148 if idx == 0 || (len(newWord) == 1 && unicode.IsDigit(rune(newWord[0]))) { 149 return result + newWord 150 } 151 return result + "_" + newWord 152 }) 153 } 154 155 func ToLowerSnakeCase(s string) string { 156 return strings.ToLower(ToUpperSnakeCase(s)) 157 } 158 159 func ToLowerLinkCase(s string) string { 160 return strings.Replace(ToLowerSnakeCase(s), "_", "-", -1) 161 }