github.com/bytedance/go-tagexpr@v2.7.5-0.20210114074101-de5b8743ad85+incompatible/binding/tag_names.go (about) 1 package binding 2 3 import ( 4 "net/textproto" 5 "reflect" 6 "sort" 7 "strings" 8 9 "github.com/henrylee2cn/goutil" 10 ) 11 12 const ( 13 tagRequired = "required" 14 tagRequired2 = "req" 15 defaultTagPath = "path" 16 defaultTagQuery = "query" 17 defaultTagHeader = "header" 18 defaultTagCookie = "cookie" 19 defaultTagRawbody = "raw_body" 20 defaultTagForm = "form" 21 defaultTagValidator = "vd" 22 tagProtobuf = "protobuf" 23 tagJSON = "json" 24 tagDefault = "default" 25 ) 26 27 // Config the struct tag naming and so on 28 type Config struct { 29 // LooseZeroMode if set to true, 30 // the empty string request parameter is bound to the zero value of parameter. 31 // NOTE: Suitable for these parameter types: query/header/cookie/form . 32 LooseZeroMode bool 33 // PathParam use 'path' by default when empty 34 PathParam string 35 // Query use 'query' by default when empty 36 Query string 37 // Header use 'header' by default when empty 38 Header string 39 // Cookie use 'cookie' by default when empty 40 Cookie string 41 // RawBody use 'raw' by default when empty 42 RawBody string 43 // FormBody use 'form' by default when empty 44 FormBody string 45 // Validator use 'vd' by default when empty 46 Validator string 47 // protobufBody use 'protobuf' by default when empty 48 protobufBody string 49 // jsonBody use 'json' by default when empty 50 jsonBody string 51 // defaultVal use 'default' by default when empty 52 defaultVal string 53 54 list []string 55 } 56 57 func (t *Config) init() { 58 t.list = []string{ 59 goutil.InitAndGetString(&t.PathParam, defaultTagPath), 60 goutil.InitAndGetString(&t.Query, defaultTagQuery), 61 goutil.InitAndGetString(&t.Header, defaultTagHeader), 62 goutil.InitAndGetString(&t.Cookie, defaultTagCookie), 63 goutil.InitAndGetString(&t.RawBody, defaultTagRawbody), 64 goutil.InitAndGetString(&t.FormBody, defaultTagForm), 65 goutil.InitAndGetString(&t.Validator, defaultTagValidator), 66 goutil.InitAndGetString(&t.protobufBody, tagProtobuf), 67 goutil.InitAndGetString(&t.jsonBody, tagJSON), 68 goutil.InitAndGetString(&t.defaultVal, tagDefault), 69 } 70 } 71 72 func (t *Config) parse(field reflect.StructField) tagKVs { 73 tag := field.Tag 74 fieldName := field.Name 75 76 kvs := make(tagKVs, 0, len(t.list)) 77 s := string(tag) 78 79 for _, name := range t.list { 80 value, ok := tag.Lookup(name) 81 if !ok { 82 continue 83 } 84 if name != t.defaultVal && value != "-" { 85 value = strings.Replace(strings.TrimSpace(value), " ", "", -1) 86 value = strings.Replace(value, "\t", "", -1) 87 if name == t.RawBody { 88 info := newTagInfo(value, false) 89 if info.required || info.paramName == tagRequired { 90 value = "," + tagRequired 91 } 92 } else if value == "" { 93 value = fieldName 94 } else if value == ","+tagRequired { 95 value = fieldName + value 96 } 97 } 98 kvs = append(kvs, &tagKV{name: name, value: value, pos: strings.Index(s, name)}) 99 } 100 sort.Sort(kvs) 101 return kvs 102 } 103 104 type tagKV struct { 105 name string 106 value string 107 pos int 108 } 109 110 type tagInfo struct { 111 paramIn in 112 paramName string 113 required bool 114 namePath string 115 116 requiredError, typeError, cannotError, contentTypeError error 117 } 118 119 func (t *tagKV) toInfo(isHeader bool) *tagInfo { 120 return newTagInfo(t.value, isHeader) 121 } 122 123 func newTagInfo(value string, isHeader bool) *tagInfo { 124 info := new(tagInfo) 125 for i, v := range strings.Split(value, ",") { 126 v = strings.TrimSpace(v) 127 if i == 0 { 128 info.paramName = v 129 } else { 130 if v == tagRequired || v == tagRequired2 { 131 info.required = true 132 } 133 } 134 } 135 if isHeader { 136 info.paramName = textproto.CanonicalMIMEHeaderKey(info.paramName) 137 } 138 return info 139 } 140 141 type tagKVs []*tagKV 142 143 // Len is the number of elements in the collection. 144 func (a tagKVs) Len() int { 145 return len(a) 146 } 147 148 // Less reports whether the element with 149 // index i should sort before the element with index j. 150 func (a tagKVs) Less(i, j int) bool { 151 return a[i].pos < a[j].pos 152 } 153 154 // Swap swaps the elements with indexes i and j. 155 func (a tagKVs) Swap(i, j int) { 156 a[i], a[j] = a[j], a[i] 157 } 158 159 func (a tagKVs) lookup(name string) (string, bool) { 160 for _, v := range a { 161 if v.name == name { 162 return v.value, true 163 } 164 } 165 return "", false 166 }