Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / go-openapi / swag / util.go
1 // Copyright 2015 go-swagger maintainers
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 package swag
16
17 import (
18         "math"
19         "reflect"
20         "regexp"
21         "strings"
22         "sync"
23         "unicode"
24 )
25
26 // commonInitialisms are common acronyms that are kept as whole uppercased words.
27 var commonInitialisms *indexOfInitialisms
28
29 // initialisms is a slice of sorted initialisms
30 var initialisms []string
31
32 var once sync.Once
33
34 var isInitialism func(string) bool
35
36 var (
37         splitRex1     *regexp.Regexp
38         splitRex2     *regexp.Regexp
39         splitReplacer *strings.Replacer
40 )
41
42 func init() {
43         // Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769
44         var configuredInitialisms = map[string]bool{
45                 "ACL":   true,
46                 "API":   true,
47                 "ASCII": true,
48                 "CPU":   true,
49                 "CSS":   true,
50                 "DNS":   true,
51                 "EOF":   true,
52                 "GUID":  true,
53                 "HTML":  true,
54                 "HTTPS": true,
55                 "HTTP":  true,
56                 "ID":    true,
57                 "IP":    true,
58                 "JSON":  true,
59                 "LHS":   true,
60                 "OAI":   true,
61                 "QPS":   true,
62                 "RAM":   true,
63                 "RHS":   true,
64                 "RPC":   true,
65                 "SLA":   true,
66                 "SMTP":  true,
67                 "SQL":   true,
68                 "SSH":   true,
69                 "TCP":   true,
70                 "TLS":   true,
71                 "TTL":   true,
72                 "UDP":   true,
73                 "UI":    true,
74                 "UID":   true,
75                 "UUID":  true,
76                 "URI":   true,
77                 "URL":   true,
78                 "UTF8":  true,
79                 "VM":    true,
80                 "XML":   true,
81                 "XMPP":  true,
82                 "XSRF":  true,
83                 "XSS":   true,
84         }
85
86         // a thread-safe index of initialisms
87         commonInitialisms = newIndexOfInitialisms().load(configuredInitialisms)
88
89         // a test function
90         isInitialism = commonInitialisms.isInitialism
91 }
92
93 func ensureSorted() {
94         initialisms = commonInitialisms.sorted()
95 }
96
97 const (
98         //collectionFormatComma = "csv"
99         collectionFormatSpace = "ssv"
100         collectionFormatTab   = "tsv"
101         collectionFormatPipe  = "pipes"
102         collectionFormatMulti = "multi"
103 )
104
105 // JoinByFormat joins a string array by a known format (e.g. swagger's collectionFormat attribute):
106 //              ssv: space separated value
107 //              tsv: tab separated value
108 //              pipes: pipe (|) separated value
109 //              csv: comma separated value (default)
110 func JoinByFormat(data []string, format string) []string {
111         if len(data) == 0 {
112                 return data
113         }
114         var sep string
115         switch format {
116         case collectionFormatSpace:
117                 sep = " "
118         case collectionFormatTab:
119                 sep = "\t"
120         case collectionFormatPipe:
121                 sep = "|"
122         case collectionFormatMulti:
123                 return data
124         default:
125                 sep = ","
126         }
127         return []string{strings.Join(data, sep)}
128 }
129
130 // SplitByFormat splits a string by a known format:
131 //              ssv: space separated value
132 //              tsv: tab separated value
133 //              pipes: pipe (|) separated value
134 //              csv: comma separated value (default)
135 //
136 func SplitByFormat(data, format string) []string {
137         if data == "" {
138                 return nil
139         }
140         var sep string
141         switch format {
142         case collectionFormatSpace:
143                 sep = " "
144         case collectionFormatTab:
145                 sep = "\t"
146         case collectionFormatPipe:
147                 sep = "|"
148         case collectionFormatMulti:
149                 return nil
150         default:
151                 sep = ","
152         }
153         var result []string
154         for _, s := range strings.Split(data, sep) {
155                 if ts := strings.TrimSpace(s); ts != "" {
156                         result = append(result, ts)
157                 }
158         }
159         return result
160 }
161
162 type byInitialism []string
163
164 func (s byInitialism) Len() int {
165         return len(s)
166 }
167 func (s byInitialism) Swap(i, j int) {
168         s[i], s[j] = s[j], s[i]
169 }
170 func (s byInitialism) Less(i, j int) bool {
171         if len(s[i]) != len(s[j]) {
172                 return len(s[i]) < len(s[j])
173         }
174
175         return strings.Compare(s[i], s[j]) > 0
176 }
177
178 // Prepares strings by splitting by caps, spaces, dashes, and underscore
179 func split(str string) []string {
180         // check if consecutive single char things make up an initialism
181         once.Do(func() {
182                 splitRex1 = regexp.MustCompile(`(\p{Lu})`)
183                 splitRex2 = regexp.MustCompile(`(\pL|\pM|\pN|\p{Pc})+`)
184                 splitReplacer = strings.NewReplacer(
185                         "@", "At ",
186                         "&", "And ",
187                         "|", "Pipe ",
188                         "$", "Dollar ",
189                         "!", "Bang ",
190                         "-", " ",
191                         "_", " ",
192                 )
193                 ensureSorted()
194         })
195
196         str = trim(str)
197
198         // Convert dash and underscore to spaces
199         str = splitReplacer.Replace(str)
200
201         // Split when uppercase is found (needed for Snake)
202         str = splitRex1.ReplaceAllString(str, " $1")
203
204         for _, k := range initialisms {
205                 str = strings.Replace(str, splitRex1.ReplaceAllString(k, " $1"), " "+k, -1)
206         }
207         // Get the final list of words
208         //words = rex2.FindAllString(str, -1)
209         return splitRex2.FindAllString(str, -1)
210 }
211
212 // Removes leading whitespaces
213 func trim(str string) string {
214         return strings.Trim(str, " ")
215 }
216
217 // Shortcut to strings.ToUpper()
218 func upper(str string) string {
219         return strings.ToUpper(trim(str))
220 }
221
222 // Shortcut to strings.ToLower()
223 func lower(str string) string {
224         return strings.ToLower(trim(str))
225 }
226
227 // Camelize an uppercased word
228 func Camelize(word string) (camelized string) {
229         for pos, ru := range []rune(word) {
230                 if pos > 0 {
231                         camelized += string(unicode.ToLower(ru))
232                 } else {
233                         camelized += string(unicode.ToUpper(ru))
234                 }
235         }
236         return
237 }
238
239 // ToFileName lowercases and underscores a go type name
240 func ToFileName(name string) string {
241         in := split(name)
242         out := make([]string, 0, len(in))
243
244         for _, w := range in {
245                 out = append(out, lower(w))
246         }
247
248         return strings.Join(out, "_")
249 }
250
251 // ToCommandName lowercases and underscores a go type name
252 func ToCommandName(name string) string {
253         in := split(name)
254         out := make([]string, 0, len(in))
255
256         for _, w := range in {
257                 out = append(out, lower(w))
258         }
259         return strings.Join(out, "-")
260 }
261
262 // ToHumanNameLower represents a code name as a human series of words
263 func ToHumanNameLower(name string) string {
264         in := split(name)
265         out := make([]string, 0, len(in))
266
267         for _, w := range in {
268                 if !isInitialism(upper(w)) {
269                         out = append(out, lower(w))
270                 } else {
271                         out = append(out, w)
272                 }
273         }
274         return strings.Join(out, " ")
275 }
276
277 // ToHumanNameTitle represents a code name as a human series of words with the first letters titleized
278 func ToHumanNameTitle(name string) string {
279         in := split(name)
280         out := make([]string, 0, len(in))
281
282         for _, w := range in {
283                 uw := upper(w)
284                 if !isInitialism(uw) {
285                         out = append(out, Camelize(w))
286                 } else {
287                         out = append(out, w)
288                 }
289         }
290         return strings.Join(out, " ")
291 }
292
293 // ToJSONName camelcases a name which can be underscored or pascal cased
294 func ToJSONName(name string) string {
295         in := split(name)
296         out := make([]string, 0, len(in))
297
298         for i, w := range in {
299                 if i == 0 {
300                         out = append(out, lower(w))
301                         continue
302                 }
303                 out = append(out, Camelize(w))
304         }
305         return strings.Join(out, "")
306 }
307
308 // ToVarName camelcases a name which can be underscored or pascal cased
309 func ToVarName(name string) string {
310         res := ToGoName(name)
311         if isInitialism(res) {
312                 return lower(res)
313         }
314         if len(res) <= 1 {
315                 return lower(res)
316         }
317         return lower(res[:1]) + res[1:]
318 }
319
320 // ToGoName translates a swagger name which can be underscored or camel cased to a name that golint likes
321 func ToGoName(name string) string {
322         in := split(name)
323         out := make([]string, 0, len(in))
324
325         for _, w := range in {
326                 uw := upper(w)
327                 mod := int(math.Min(float64(len(uw)), 2))
328                 if !isInitialism(uw) && !isInitialism(uw[:len(uw)-mod]) {
329                         uw = Camelize(w)
330                 }
331                 out = append(out, uw)
332         }
333
334         result := strings.Join(out, "")
335         if len(result) > 0 {
336                 if !unicode.IsUpper([]rune(result)[0]) {
337                         result = "X" + result
338                 }
339         }
340         return result
341 }
342
343 // ContainsStrings searches a slice of strings for a case-sensitive match
344 func ContainsStrings(coll []string, item string) bool {
345         for _, a := range coll {
346                 if a == item {
347                         return true
348                 }
349         }
350         return false
351 }
352
353 // ContainsStringsCI searches a slice of strings for a case-insensitive match
354 func ContainsStringsCI(coll []string, item string) bool {
355         for _, a := range coll {
356                 if strings.EqualFold(a, item) {
357                         return true
358                 }
359         }
360         return false
361 }
362
363 type zeroable interface {
364         IsZero() bool
365 }
366
367 // IsZero returns true when the value passed into the function is a zero value.
368 // This allows for safer checking of interface values.
369 func IsZero(data interface{}) bool {
370         // check for things that have an IsZero method instead
371         if vv, ok := data.(zeroable); ok {
372                 return vv.IsZero()
373         }
374         // continue with slightly more complex reflection
375         v := reflect.ValueOf(data)
376         switch v.Kind() {
377         case reflect.String:
378                 return v.Len() == 0
379         case reflect.Bool:
380                 return !v.Bool()
381         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
382                 return v.Int() == 0
383         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
384                 return v.Uint() == 0
385         case reflect.Float32, reflect.Float64:
386                 return v.Float() == 0
387         case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
388                 return v.IsNil()
389         case reflect.Struct, reflect.Array:
390                 return reflect.DeepEqual(data, reflect.Zero(v.Type()).Interface())
391         case reflect.Invalid:
392                 return true
393         }
394         return false
395 }
396
397 // AddInitialisms add additional initialisms
398 func AddInitialisms(words ...string) {
399         for _, word := range words {
400                 //commonInitialisms[upper(word)] = true
401                 commonInitialisms.add(upper(word))
402         }
403         // sort again
404         initialisms = commonInitialisms.sorted()
405 }
406
407 // CommandLineOptionsGroup represents a group of user-defined command line options
408 type CommandLineOptionsGroup struct {
409         ShortDescription string
410         LongDescription  string
411         Options          interface{}
412 }