github.imxd.top/operator-framework/operator-sdk@v0.8.2/pkg/ansible/paramconv/paramconv.go (about) 1 // Copyright 2018 The Operator-SDK Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Based on https://github.com/iancoleman/strcase 16 17 package paramconv 18 19 import ( 20 "regexp" 21 "strings" 22 ) 23 24 var ( 25 numberSequence = regexp.MustCompile(`([a-zA-Z])(\d+)([a-zA-Z]?)`) 26 numberReplacement = []byte(`$1 $2 $3`) 27 wordMapping = map[string]string{ 28 "http": "HTTP", 29 "url": "URL", 30 "ip": "IP", 31 } 32 ) 33 34 func addWordBoundariesToNumbers(s string) string { 35 b := []byte(s) 36 b = numberSequence.ReplaceAll(b, numberReplacement) 37 return string(b) 38 } 39 40 func translateWord(word string, initCase bool) string { 41 if val, ok := wordMapping[word]; ok { 42 return val 43 } 44 if initCase { 45 return strings.Title(word) 46 } 47 return word 48 } 49 50 // Converts a string to CamelCase 51 func ToCamel(s string) string { 52 s = addWordBoundariesToNumbers(s) 53 s = strings.Trim(s, " ") 54 n := "" 55 bits := []string{} 56 for _, v := range s { 57 if v == '_' || v == ' ' || v == '-' { 58 bits = append(bits, n) 59 n = "" 60 } else { 61 n += string(v) 62 } 63 } 64 bits = append(bits, n) 65 66 ret := "" 67 for i, substr := range bits { 68 ret += translateWord(substr, i != 0) 69 } 70 return ret 71 } 72 73 // Converts a string to snake_case 74 func ToSnake(s string) string { 75 s = addWordBoundariesToNumbers(s) 76 s = strings.Trim(s, " ") 77 var prefix string 78 char1 := []rune(s)[0] 79 if char1 >= 'A' && char1 <= 'Z' { 80 prefix = "_" 81 } else { 82 prefix = "" 83 } 84 bits := []string{} 85 n := "" 86 real_i := -1 87 88 for i, v := range s { 89 real_i += 1 90 // treat acronyms as words, eg for JSONData -> JSON is a whole word 91 nextCaseIsChanged := false 92 if i+1 < len(s) { 93 next := s[i+1] 94 if (v >= 'A' && v <= 'Z' && next >= 'a' && next <= 'z') || (v >= 'a' && v <= 'z' && next >= 'A' && next <= 'Z') { 95 nextCaseIsChanged = true 96 } 97 } 98 99 if real_i > 0 && n[len(n)-1] != '_' && nextCaseIsChanged { 100 // add underscore if next letter case type is changed 101 if v >= 'A' && v <= 'Z' { 102 bits = append(bits, strings.ToLower(n)) 103 n = string(v) 104 real_i = 0 105 } else if v >= 'a' && v <= 'z' { 106 bits = append(bits, strings.ToLower(n+string(v))) 107 n = "" 108 real_i = -1 109 } 110 } else if v == ' ' || v == '_' || v == '-' { 111 // replace spaces/underscores with delimiters 112 bits = append(bits, strings.ToLower(n)) 113 n = "" 114 real_i = -1 115 } else { 116 n = n + string(v) 117 } 118 } 119 bits = append(bits, strings.ToLower(n)) 120 joined := strings.Join(bits, "_") 121 if _, ok := wordMapping[bits[0]]; !ok { 122 return prefix + joined 123 } 124 return joined 125 } 126 127 func convertParameter(fn func(string) string, v interface{}) interface{} { 128 switch v := v.(type) { 129 case map[string]interface{}: 130 ret := map[string]interface{}{} 131 for key, val := range v { 132 ret[fn(key)] = convertParameter(fn, val) 133 } 134 return ret 135 case []interface{}: 136 return convertArray(fn, v) 137 default: 138 return v 139 } 140 } 141 142 func convertArray(fn func(string) string, in []interface{}) []interface{} { 143 res := make([]interface{}, len(in)) 144 for i, v := range in { 145 res[i] = convertParameter(fn, v) 146 } 147 return res 148 } 149 150 func convertMapKeys(fn func(string) string, in map[string]interface{}) map[string]interface{} { 151 converted := map[string]interface{}{} 152 for key, val := range in { 153 converted[fn(key)] = convertParameter(fn, val) 154 } 155 return converted 156 } 157 158 func MapToSnake(in map[string]interface{}) map[string]interface{} { 159 return convertMapKeys(ToSnake, in) 160 } 161 162 func MapToCamel(in map[string]interface{}) map[string]interface{} { 163 return convertMapKeys(ToCamel, in) 164 }