1 // Copyright 2015 go-swagger maintainers
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
26 // commonInitialisms are common acronyms that are kept as whole uppercased words.
27 var commonInitialisms *indexOfInitialisms
29 // initialisms is a slice of sorted initialisms
30 var initialisms []string
34 var isInitialism func(string) bool
37 splitRex1 *regexp.Regexp
38 splitRex2 *regexp.Regexp
39 splitReplacer *strings.Replacer
43 // Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769
44 var configuredInitialisms = map[string]bool{
86 // a thread-safe index of initialisms
87 commonInitialisms = newIndexOfInitialisms().load(configuredInitialisms)
90 isInitialism = commonInitialisms.isInitialism
94 initialisms = commonInitialisms.sorted()
98 //collectionFormatComma = "csv"
99 collectionFormatSpace = "ssv"
100 collectionFormatTab = "tsv"
101 collectionFormatPipe = "pipes"
102 collectionFormatMulti = "multi"
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 {
116 case collectionFormatSpace:
118 case collectionFormatTab:
120 case collectionFormatPipe:
122 case collectionFormatMulti:
127 return []string{strings.Join(data, sep)}
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)
136 func SplitByFormat(data, format string) []string {
142 case collectionFormatSpace:
144 case collectionFormatTab:
146 case collectionFormatPipe:
148 case collectionFormatMulti:
154 for _, s := range strings.Split(data, sep) {
155 if ts := strings.TrimSpace(s); ts != "" {
156 result = append(result, ts)
162 type byInitialism []string
164 func (s byInitialism) Len() int {
167 func (s byInitialism) Swap(i, j int) {
168 s[i], s[j] = s[j], s[i]
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])
175 return strings.Compare(s[i], s[j]) > 0
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
182 splitRex1 = regexp.MustCompile(`(\p{Lu})`)
183 splitRex2 = regexp.MustCompile(`(\pL|\pM|\pN|\p{Pc})+`)
184 splitReplacer = strings.NewReplacer(
198 // Convert dash and underscore to spaces
199 str = splitReplacer.Replace(str)
201 // Split when uppercase is found (needed for Snake)
202 str = splitRex1.ReplaceAllString(str, " $1")
204 for _, k := range initialisms {
205 str = strings.Replace(str, splitRex1.ReplaceAllString(k, " $1"), " "+k, -1)
207 // Get the final list of words
208 //words = rex2.FindAllString(str, -1)
209 return splitRex2.FindAllString(str, -1)
212 // Removes leading whitespaces
213 func trim(str string) string {
214 return strings.Trim(str, " ")
217 // Shortcut to strings.ToUpper()
218 func upper(str string) string {
219 return strings.ToUpper(trim(str))
222 // Shortcut to strings.ToLower()
223 func lower(str string) string {
224 return strings.ToLower(trim(str))
227 // Camelize an uppercased word
228 func Camelize(word string) (camelized string) {
229 for pos, ru := range []rune(word) {
231 camelized += string(unicode.ToLower(ru))
233 camelized += string(unicode.ToUpper(ru))
239 // ToFileName lowercases and underscores a go type name
240 func ToFileName(name string) string {
242 out := make([]string, 0, len(in))
244 for _, w := range in {
245 out = append(out, lower(w))
248 return strings.Join(out, "_")
251 // ToCommandName lowercases and underscores a go type name
252 func ToCommandName(name string) string {
254 out := make([]string, 0, len(in))
256 for _, w := range in {
257 out = append(out, lower(w))
259 return strings.Join(out, "-")
262 // ToHumanNameLower represents a code name as a human series of words
263 func ToHumanNameLower(name string) string {
265 out := make([]string, 0, len(in))
267 for _, w := range in {
268 if !isInitialism(upper(w)) {
269 out = append(out, lower(w))
274 return strings.Join(out, " ")
277 // ToHumanNameTitle represents a code name as a human series of words with the first letters titleized
278 func ToHumanNameTitle(name string) string {
280 out := make([]string, 0, len(in))
282 for _, w := range in {
284 if !isInitialism(uw) {
285 out = append(out, Camelize(w))
290 return strings.Join(out, " ")
293 // ToJSONName camelcases a name which can be underscored or pascal cased
294 func ToJSONName(name string) string {
296 out := make([]string, 0, len(in))
298 for i, w := range in {
300 out = append(out, lower(w))
303 out = append(out, Camelize(w))
305 return strings.Join(out, "")
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) {
317 return lower(res[:1]) + res[1:]
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 {
323 out := make([]string, 0, len(in))
325 for _, w := range in {
327 mod := int(math.Min(float64(len(uw)), 2))
328 if !isInitialism(uw) && !isInitialism(uw[:len(uw)-mod]) {
331 out = append(out, uw)
334 result := strings.Join(out, "")
336 if !unicode.IsUpper([]rune(result)[0]) {
337 result = "X" + result
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 {
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) {
363 type zeroable interface {
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 {
374 // continue with slightly more complex reflection
375 v := reflect.ValueOf(data)
381 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
383 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
385 case reflect.Float32, reflect.Float64:
386 return v.Float() == 0
387 case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
389 case reflect.Struct, reflect.Array:
390 return reflect.DeepEqual(data, reflect.Zero(v.Type()).Interface())
391 case reflect.Invalid:
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))
404 initialisms = commonInitialisms.sorted()
407 // CommandLineOptionsGroup represents a group of user-defined command line options
408 type CommandLineOptionsGroup struct {
409 ShortDescription string
410 LongDescription string