github.com/oam-dev/kubevela@v1.9.11/references/cuegen/tag.go (about) 1 /* 2 Copyright 2023 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cuegen 18 19 import ( 20 "reflect" 21 "strings" 22 ) 23 24 type tagOptions struct { 25 // basic 26 Name string 27 Inline bool 28 Optional bool 29 30 // extended 31 Default *string // nil means no default value 32 Enum []string 33 } 34 35 // TODO(iyear): be customizable 36 const ( 37 basicTag = "json" // same as json tag 38 extTag = "cue" // format: cue:"key1:value1;key2:value2;boolValue1;boolValue2" 39 ) 40 41 func (g *Generator) parseTag(tag string) *tagOptions { 42 if tag == "" { 43 return &tagOptions{} 44 } 45 46 name, opts := parseTag(reflect.StructTag(tag).Get(basicTag)) 47 ext := parseExtTag(reflect.StructTag(tag).Get(extTag)) 48 49 return &tagOptions{ 50 Name: name, 51 Inline: opts.Has("inline"), 52 Optional: opts.Has("omitempty"), 53 54 Default: ext.GetX("default"), 55 Enum: unescapeSplit(ext.Get("enum"), ","), 56 } 57 } 58 59 type basicTagOptions string 60 61 func parseTag(tag string) (string, basicTagOptions) { 62 tag, opt, _ := strings.Cut(tag, ",") 63 return tag, basicTagOptions(opt) 64 } 65 66 func (o basicTagOptions) Has(opt string) bool { 67 if len(o) == 0 { 68 return false 69 } 70 s := string(o) 71 for s != "" { 72 var name string 73 name, s, _ = strings.Cut(s, ",") 74 if name == opt { 75 return true 76 } 77 } 78 return false 79 } 80 81 func parseExtTag(str string) extTagOptions { 82 settings := map[string]string{} 83 if str == "" { 84 return settings 85 } 86 87 pairs := unescapeSplit(str, ";") 88 for _, pair := range pairs { 89 switch kv := unescapeSplit(pair, ":"); len(kv) { 90 case 1: 91 settings[kv[0]] = "" 92 case 2: 93 settings[kv[0]] = kv[1] 94 default: 95 // ignore invalid pair 96 } 97 } 98 99 return settings 100 } 101 102 func unescapeSplit(str string, sep string) []string { 103 if str == "" { 104 return []string{} 105 } 106 107 ss := strings.Split(str, sep) 108 for i := 0; i < len(ss); i++ { 109 j := i 110 if len(ss[j]) > 0 { 111 for { 112 if ss[j][len(ss[j])-1] == '\\' && i+1 < len(ss) { 113 i++ 114 ss[j] = ss[j][0:len(ss[j])-1] + sep + ss[i] 115 ss[i] = "" 116 } else { 117 break 118 } 119 } 120 } 121 } 122 123 // filter empty strings 124 res := make([]string, 0, len(ss)) 125 for _, s := range ss { 126 if s != "" { 127 res = append(res, s) 128 } 129 } 130 return res 131 } 132 133 type extTagOptions map[string]string 134 135 // GetX returns the value of the key if it exists, otherwise nil. 136 func (e extTagOptions) GetX(key string) *string { 137 if v, ok := e[key]; ok { 138 return &v 139 } 140 return nil 141 } 142 143 // Get returns the value of the key if it exists, otherwise "". 144 func (e extTagOptions) Get(key string) string { 145 return e[key] 146 }