mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 15:42:25 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			364 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			364 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2015 go-swagger maintainers
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //    http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| package swag
 | |
| 
 | |
| import (
 | |
| 	"reflect"
 | |
| 	"strings"
 | |
| 	"unicode"
 | |
| 	"unicode/utf8"
 | |
| )
 | |
| 
 | |
| // GoNamePrefixFunc sets an optional rule to prefix go names
 | |
| // which do not start with a letter.
 | |
| //
 | |
| // The prefix function is assumed to return a string that starts with an upper case letter.
 | |
| //
 | |
| // e.g. to help convert "123" into "{prefix}123"
 | |
| //
 | |
| // The default is to prefix with "X"
 | |
| var GoNamePrefixFunc func(string) string
 | |
| 
 | |
| func prefixFunc(name, in string) string {
 | |
| 	if GoNamePrefixFunc == nil {
 | |
| 		return "X" + in
 | |
| 	}
 | |
| 
 | |
| 	return GoNamePrefixFunc(name) + in
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	// collectionFormatComma = "csv"
 | |
| 	collectionFormatSpace = "ssv"
 | |
| 	collectionFormatTab   = "tsv"
 | |
| 	collectionFormatPipe  = "pipes"
 | |
| 	collectionFormatMulti = "multi"
 | |
| )
 | |
| 
 | |
| // JoinByFormat joins a string array by a known format (e.g. swagger's collectionFormat attribute):
 | |
| //
 | |
| //	ssv: space separated value
 | |
| //	tsv: tab separated value
 | |
| //	pipes: pipe (|) separated value
 | |
| //	csv: comma separated value (default)
 | |
| func JoinByFormat(data []string, format string) []string {
 | |
| 	if len(data) == 0 {
 | |
| 		return data
 | |
| 	}
 | |
| 	var sep string
 | |
| 	switch format {
 | |
| 	case collectionFormatSpace:
 | |
| 		sep = " "
 | |
| 	case collectionFormatTab:
 | |
| 		sep = "\t"
 | |
| 	case collectionFormatPipe:
 | |
| 		sep = "|"
 | |
| 	case collectionFormatMulti:
 | |
| 		return data
 | |
| 	default:
 | |
| 		sep = ","
 | |
| 	}
 | |
| 	return []string{strings.Join(data, sep)}
 | |
| }
 | |
| 
 | |
| // SplitByFormat splits a string by a known format:
 | |
| //
 | |
| //	ssv: space separated value
 | |
| //	tsv: tab separated value
 | |
| //	pipes: pipe (|) separated value
 | |
| //	csv: comma separated value (default)
 | |
| func SplitByFormat(data, format string) []string {
 | |
| 	if data == "" {
 | |
| 		return nil
 | |
| 	}
 | |
| 	var sep string
 | |
| 	switch format {
 | |
| 	case collectionFormatSpace:
 | |
| 		sep = " "
 | |
| 	case collectionFormatTab:
 | |
| 		sep = "\t"
 | |
| 	case collectionFormatPipe:
 | |
| 		sep = "|"
 | |
| 	case collectionFormatMulti:
 | |
| 		return nil
 | |
| 	default:
 | |
| 		sep = ","
 | |
| 	}
 | |
| 	var result []string
 | |
| 	for _, s := range strings.Split(data, sep) {
 | |
| 		if ts := strings.TrimSpace(s); ts != "" {
 | |
| 			result = append(result, ts)
 | |
| 		}
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // Removes leading whitespaces
 | |
| func trim(str string) string {
 | |
| 	return strings.TrimSpace(str)
 | |
| }
 | |
| 
 | |
| // Shortcut to strings.ToUpper()
 | |
| func upper(str string) string {
 | |
| 	return strings.ToUpper(trim(str))
 | |
| }
 | |
| 
 | |
| // Shortcut to strings.ToLower()
 | |
| func lower(str string) string {
 | |
| 	return strings.ToLower(trim(str))
 | |
| }
 | |
| 
 | |
| // Camelize an uppercased word
 | |
| func Camelize(word string) string {
 | |
| 	camelized := poolOfBuffers.BorrowBuffer(len(word))
 | |
| 	defer func() {
 | |
| 		poolOfBuffers.RedeemBuffer(camelized)
 | |
| 	}()
 | |
| 
 | |
| 	for pos, ru := range []rune(word) {
 | |
| 		if pos > 0 {
 | |
| 			camelized.WriteRune(unicode.ToLower(ru))
 | |
| 		} else {
 | |
| 			camelized.WriteRune(unicode.ToUpper(ru))
 | |
| 		}
 | |
| 	}
 | |
| 	return camelized.String()
 | |
| }
 | |
| 
 | |
| // ToFileName lowercases and underscores a go type name
 | |
| func ToFileName(name string) string {
 | |
| 	in := split(name)
 | |
| 	out := make([]string, 0, len(in))
 | |
| 
 | |
| 	for _, w := range in {
 | |
| 		out = append(out, lower(w))
 | |
| 	}
 | |
| 
 | |
| 	return strings.Join(out, "_")
 | |
| }
 | |
| 
 | |
| // ToCommandName lowercases and underscores a go type name
 | |
| func ToCommandName(name string) string {
 | |
| 	in := split(name)
 | |
| 	out := make([]string, 0, len(in))
 | |
| 
 | |
| 	for _, w := range in {
 | |
| 		out = append(out, lower(w))
 | |
| 	}
 | |
| 	return strings.Join(out, "-")
 | |
| }
 | |
| 
 | |
| // ToHumanNameLower represents a code name as a human series of words
 | |
| func ToHumanNameLower(name string) string {
 | |
| 	s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck)
 | |
| 	in := s.split(name)
 | |
| 	poolOfSplitters.RedeemSplitter(s)
 | |
| 	out := make([]string, 0, len(*in))
 | |
| 
 | |
| 	for _, w := range *in {
 | |
| 		if !w.IsInitialism() {
 | |
| 			out = append(out, lower(w.GetOriginal()))
 | |
| 		} else {
 | |
| 			out = append(out, trim(w.GetOriginal()))
 | |
| 		}
 | |
| 	}
 | |
| 	poolOfLexems.RedeemLexems(in)
 | |
| 
 | |
| 	return strings.Join(out, " ")
 | |
| }
 | |
| 
 | |
| // ToHumanNameTitle represents a code name as a human series of words with the first letters titleized
 | |
| func ToHumanNameTitle(name string) string {
 | |
| 	s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck)
 | |
| 	in := s.split(name)
 | |
| 	poolOfSplitters.RedeemSplitter(s)
 | |
| 
 | |
| 	out := make([]string, 0, len(*in))
 | |
| 	for _, w := range *in {
 | |
| 		original := trim(w.GetOriginal())
 | |
| 		if !w.IsInitialism() {
 | |
| 			out = append(out, Camelize(original))
 | |
| 		} else {
 | |
| 			out = append(out, original)
 | |
| 		}
 | |
| 	}
 | |
| 	poolOfLexems.RedeemLexems(in)
 | |
| 
 | |
| 	return strings.Join(out, " ")
 | |
| }
 | |
| 
 | |
| // ToJSONName camelcases a name which can be underscored or pascal cased
 | |
| func ToJSONName(name string) string {
 | |
| 	in := split(name)
 | |
| 	out := make([]string, 0, len(in))
 | |
| 
 | |
| 	for i, w := range in {
 | |
| 		if i == 0 {
 | |
| 			out = append(out, lower(w))
 | |
| 			continue
 | |
| 		}
 | |
| 		out = append(out, Camelize(trim(w)))
 | |
| 	}
 | |
| 	return strings.Join(out, "")
 | |
| }
 | |
| 
 | |
| // ToVarName camelcases a name which can be underscored or pascal cased
 | |
| func ToVarName(name string) string {
 | |
| 	res := ToGoName(name)
 | |
| 	if isInitialism(res) {
 | |
| 		return lower(res)
 | |
| 	}
 | |
| 	if len(res) <= 1 {
 | |
| 		return lower(res)
 | |
| 	}
 | |
| 	return lower(res[:1]) + res[1:]
 | |
| }
 | |
| 
 | |
| // ToGoName translates a swagger name which can be underscored or camel cased to a name that golint likes
 | |
| func ToGoName(name string) string {
 | |
| 	s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck)
 | |
| 	lexems := s.split(name)
 | |
| 	poolOfSplitters.RedeemSplitter(s)
 | |
| 	defer func() {
 | |
| 		poolOfLexems.RedeemLexems(lexems)
 | |
| 	}()
 | |
| 	lexemes := *lexems
 | |
| 
 | |
| 	if len(lexemes) == 0 {
 | |
| 		return ""
 | |
| 	}
 | |
| 
 | |
| 	result := poolOfBuffers.BorrowBuffer(len(name))
 | |
| 	defer func() {
 | |
| 		poolOfBuffers.RedeemBuffer(result)
 | |
| 	}()
 | |
| 
 | |
| 	// check if not starting with a letter, upper case
 | |
| 	firstPart := lexemes[0].GetUnsafeGoName()
 | |
| 	if lexemes[0].IsInitialism() {
 | |
| 		firstPart = upper(firstPart)
 | |
| 	}
 | |
| 
 | |
| 	if c := firstPart[0]; c < utf8.RuneSelf {
 | |
| 		// ASCII
 | |
| 		switch {
 | |
| 		case 'A' <= c && c <= 'Z':
 | |
| 			result.WriteString(firstPart)
 | |
| 		case 'a' <= c && c <= 'z':
 | |
| 			result.WriteByte(c - 'a' + 'A')
 | |
| 			result.WriteString(firstPart[1:])
 | |
| 		default:
 | |
| 			result.WriteString(prefixFunc(name, firstPart))
 | |
| 			// NOTE: no longer check if prefixFunc returns a string that starts with uppercase:
 | |
| 			// assume this is always the case
 | |
| 		}
 | |
| 	} else {
 | |
| 		// unicode
 | |
| 		firstRune, _ := utf8.DecodeRuneInString(firstPart)
 | |
| 		switch {
 | |
| 		case !unicode.IsLetter(firstRune):
 | |
| 			result.WriteString(prefixFunc(name, firstPart))
 | |
| 		case !unicode.IsUpper(firstRune):
 | |
| 			result.WriteString(prefixFunc(name, firstPart))
 | |
| 			/*
 | |
| 				result.WriteRune(unicode.ToUpper(firstRune))
 | |
| 				result.WriteString(firstPart[offset:])
 | |
| 			*/
 | |
| 		default:
 | |
| 			result.WriteString(firstPart)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for _, lexem := range lexemes[1:] {
 | |
| 		goName := lexem.GetUnsafeGoName()
 | |
| 
 | |
| 		// to support old behavior
 | |
| 		if lexem.IsInitialism() {
 | |
| 			goName = upper(goName)
 | |
| 		}
 | |
| 		result.WriteString(goName)
 | |
| 	}
 | |
| 
 | |
| 	return result.String()
 | |
| }
 | |
| 
 | |
| // ContainsStrings searches a slice of strings for a case-sensitive match
 | |
| func ContainsStrings(coll []string, item string) bool {
 | |
| 	for _, a := range coll {
 | |
| 		if a == item {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // ContainsStringsCI searches a slice of strings for a case-insensitive match
 | |
| func ContainsStringsCI(coll []string, item string) bool {
 | |
| 	for _, a := range coll {
 | |
| 		if strings.EqualFold(a, item) {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| type zeroable interface {
 | |
| 	IsZero() bool
 | |
| }
 | |
| 
 | |
| // IsZero returns true when the value passed into the function is a zero value.
 | |
| // This allows for safer checking of interface values.
 | |
| func IsZero(data interface{}) bool {
 | |
| 	v := reflect.ValueOf(data)
 | |
| 	// check for nil data
 | |
| 	switch v.Kind() { //nolint:exhaustive
 | |
| 	case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
 | |
| 		if v.IsNil() {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// check for things that have an IsZero method instead
 | |
| 	if vv, ok := data.(zeroable); ok {
 | |
| 		return vv.IsZero()
 | |
| 	}
 | |
| 
 | |
| 	// continue with slightly more complex reflection
 | |
| 	switch v.Kind() { //nolint:exhaustive
 | |
| 	case reflect.String:
 | |
| 		return v.Len() == 0
 | |
| 	case reflect.Bool:
 | |
| 		return !v.Bool()
 | |
| 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | |
| 		return v.Int() == 0
 | |
| 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 | |
| 		return v.Uint() == 0
 | |
| 	case reflect.Float32, reflect.Float64:
 | |
| 		return v.Float() == 0
 | |
| 	case reflect.Struct, reflect.Array:
 | |
| 		return reflect.DeepEqual(data, reflect.Zero(v.Type()).Interface())
 | |
| 	case reflect.Invalid:
 | |
| 		return true
 | |
| 	default:
 | |
| 		return false
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // CommandLineOptionsGroup represents a group of user-defined command line options
 | |
| type CommandLineOptionsGroup struct {
 | |
| 	ShortDescription string
 | |
| 	LongDescription  string
 | |
| 	Options          interface{}
 | |
| }
 |