1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package strfmt
16
17 import (
18 "encoding"
19 stderrors "errors"
20 "fmt"
21 "reflect"
22 "strings"
23 "sync"
24 "time"
25
26 "github.com/go-openapi/errors"
27 "github.com/mitchellh/mapstructure"
28 )
29
30
31 var Default = NewSeededFormats(nil, nil)
32
33
34 type Validator func(string) bool
35
36
37
38
39
40 type Format interface {
41 String() string
42 encoding.TextMarshaler
43 encoding.TextUnmarshaler
44 }
45
46
47 type Registry interface {
48 Add(string, Format, Validator) bool
49 DelByName(string) bool
50 GetType(string) (reflect.Type, bool)
51 ContainsName(string) bool
52 Validates(string, string) bool
53 Parse(string, string) (interface{}, error)
54 MapStructureHookFunc() mapstructure.DecodeHookFunc
55 }
56
57 type knownFormat struct {
58 Name string
59 OrigName string
60 Type reflect.Type
61 Validator Validator
62 }
63
64
65 type NameNormalizer func(string) string
66
67
68 func DefaultNameNormalizer(name string) string {
69 return strings.ReplaceAll(name, "-", "")
70 }
71
72 type defaultFormats struct {
73 sync.Mutex
74 data []knownFormat
75 normalizeName NameNormalizer
76 }
77
78
79 func NewFormats() Registry {
80
81 return NewSeededFormats(Default.(*defaultFormats).data, nil)
82 }
83
84
85 func NewSeededFormats(seeds []knownFormat, normalizer NameNormalizer) Registry {
86 if normalizer == nil {
87 normalizer = DefaultNameNormalizer
88 }
89
90 d := append([]knownFormat(nil), seeds...)
91 return &defaultFormats{
92 data: d,
93 normalizeName: normalizer,
94 }
95 }
96
97
98 func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc {
99 return func(from reflect.Type, to reflect.Type, obj interface{}) (interface{}, error) {
100 if from.Kind() != reflect.String {
101 return obj, nil
102 }
103 data, ok := obj.(string)
104 if !ok {
105 return nil, fmt.Errorf("failed to cast %+v to string", obj)
106 }
107
108 for _, v := range f.data {
109 tpe, _ := f.GetType(v.Name)
110 if to == tpe {
111 switch v.Name {
112 case "date":
113 d, err := time.ParseInLocation(RFC3339FullDate, data, DefaultTimeLocation)
114 if err != nil {
115 return nil, err
116 }
117 return Date(d), nil
118 case "datetime":
119 input := data
120 if len(input) == 0 {
121 return nil, stderrors.New("empty string is an invalid datetime format")
122 }
123 return ParseDateTime(input)
124 case "duration":
125 dur, err := ParseDuration(data)
126 if err != nil {
127 return nil, err
128 }
129 return Duration(dur), nil
130 case "uri":
131 return URI(data), nil
132 case "email":
133 return Email(data), nil
134 case "uuid":
135 return UUID(data), nil
136 case "uuid3":
137 return UUID3(data), nil
138 case "uuid4":
139 return UUID4(data), nil
140 case "uuid5":
141 return UUID5(data), nil
142 case "hostname":
143 return Hostname(data), nil
144 case "ipv4":
145 return IPv4(data), nil
146 case "ipv6":
147 return IPv6(data), nil
148 case "cidr":
149 return CIDR(data), nil
150 case "mac":
151 return MAC(data), nil
152 case "isbn":
153 return ISBN(data), nil
154 case "isbn10":
155 return ISBN10(data), nil
156 case "isbn13":
157 return ISBN13(data), nil
158 case "creditcard":
159 return CreditCard(data), nil
160 case "ssn":
161 return SSN(data), nil
162 case "hexcolor":
163 return HexColor(data), nil
164 case "rgbcolor":
165 return RGBColor(data), nil
166 case "byte":
167 return Base64(data), nil
168 case "password":
169 return Password(data), nil
170 case "ulid":
171 ulid, err := ParseULID(data)
172 if err != nil {
173 return nil, err
174 }
175 return ulid, nil
176 default:
177 return nil, errors.InvalidTypeName(v.Name)
178 }
179 }
180 }
181 return data, nil
182 }
183 }
184
185
186 func (f *defaultFormats) Add(name string, strfmt Format, validator Validator) bool {
187 f.Lock()
188 defer f.Unlock()
189
190 nme := f.normalizeName(name)
191
192 tpe := reflect.TypeOf(strfmt)
193 if tpe.Kind() == reflect.Ptr {
194 tpe = tpe.Elem()
195 }
196
197 for i := range f.data {
198 v := &f.data[i]
199 if v.Name == nme {
200 v.Type = tpe
201 v.Validator = validator
202 return false
203 }
204 }
205
206
207 f.data = append(f.data, knownFormat{Name: nme, OrigName: name, Type: tpe, Validator: validator})
208 return true
209 }
210
211
212 func (f *defaultFormats) GetType(name string) (reflect.Type, bool) {
213 f.Lock()
214 defer f.Unlock()
215 nme := f.normalizeName(name)
216 for _, v := range f.data {
217 if v.Name == nme {
218 return v.Type, true
219 }
220 }
221 return nil, false
222 }
223
224
225 func (f *defaultFormats) DelByName(name string) bool {
226 f.Lock()
227 defer f.Unlock()
228
229 nme := f.normalizeName(name)
230
231 for i, v := range f.data {
232 if v.Name == nme {
233 f.data[i] = knownFormat{}
234 f.data = append(f.data[:i], f.data[i+1:]...)
235 return true
236 }
237 }
238 return false
239 }
240
241
242 func (f *defaultFormats) DelByFormat(strfmt Format) bool {
243 f.Lock()
244 defer f.Unlock()
245
246 tpe := reflect.TypeOf(strfmt)
247 if tpe.Kind() == reflect.Ptr {
248 tpe = tpe.Elem()
249 }
250
251 for i, v := range f.data {
252 if v.Type == tpe {
253 f.data[i] = knownFormat{}
254 f.data = append(f.data[:i], f.data[i+1:]...)
255 return true
256 }
257 }
258 return false
259 }
260
261
262 func (f *defaultFormats) ContainsName(name string) bool {
263 f.Lock()
264 defer f.Unlock()
265 nme := f.normalizeName(name)
266 for _, v := range f.data {
267 if v.Name == nme {
268 return true
269 }
270 }
271 return false
272 }
273
274
275 func (f *defaultFormats) ContainsFormat(strfmt Format) bool {
276 f.Lock()
277 defer f.Unlock()
278 tpe := reflect.TypeOf(strfmt)
279 if tpe.Kind() == reflect.Ptr {
280 tpe = tpe.Elem()
281 }
282
283 for _, v := range f.data {
284 if v.Type == tpe {
285 return true
286 }
287 }
288 return false
289 }
290
291
292
293
294
295 func (f *defaultFormats) Validates(name, data string) bool {
296 f.Lock()
297 defer f.Unlock()
298 nme := f.normalizeName(name)
299 for _, v := range f.data {
300 if v.Name == nme {
301 return v.Validator(data)
302 }
303 }
304 return false
305 }
306
307
308
309
310 func (f *defaultFormats) Parse(name, data string) (interface{}, error) {
311 f.Lock()
312 defer f.Unlock()
313 nme := f.normalizeName(name)
314 for _, v := range f.data {
315 if v.Name == nme {
316 nw := reflect.New(v.Type).Interface()
317 if dec, ok := nw.(encoding.TextUnmarshaler); ok {
318 if err := dec.UnmarshalText([]byte(data)); err != nil {
319 return nil, err
320 }
321 return nw, nil
322 }
323 return nil, errors.InvalidTypeName(name)
324 }
325 }
326 return nil, errors.InvalidTypeName(name)
327 }
328
View as plain text