1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package strs
import (
"encoding/json"
"strconv"
"strings"
)
func AppendUniqueFold(values []string, extra ...string) []string {
seen := make(map[string]struct{}, len(values)+len(extra))
out := make([]string, 0, len(values)+len(extra))
add := func(value string) {
value = strings.TrimSpace(value)
if value == "" {
return
}
key := strings.ToLower(value)
if _, ok := seen[key]; ok {
return
}
seen[key] = struct{}{}
out = append(out, value)
}
for _, value := range values {
add(value)
}
for _, value := range extra {
add(value)
}
return out
}
func Pluralize(kind string) string {
name := strings.ToLower(strings.TrimSpace(kind))
switch {
case name == "":
return ""
case strings.HasSuffix(name, "y"):
return strings.TrimSuffix(name, "y") + "ies"
case strings.HasSuffix(name, "s"), strings.HasSuffix(name, "x"),
strings.HasSuffix(name, "ch"), strings.HasSuffix(name, "sh"):
return name + "es"
default:
return name + "s"
}
}
func AnySlice(in []string) []any {
out := make([]any, len(in))
for i, s := range in {
out[i] = s
}
return out
}
func AnyMap(in map[string]string) map[string]any {
out := make(map[string]any, len(in))
for k, v := range in {
out[k] = v
}
return out
}
func LastSegment(value string) string {
value = strings.TrimSpace(value)
if index := strings.LastIndex(value, "/"); index >= 0 {
value = value[index+1:]
}
return strings.TrimSpace(value)
}
func LeadingInt(v string) (int, error) {
end := strings.IndexFunc(v, func(r rune) bool { return r < '0' || r > '9' })
if end < 0 {
end = len(v)
}
return strconv.Atoi(v[:end])
}
func SplitNUL(b []byte) []string {
fields := strings.Split(string(b), "\x00")
if n := len(fields); n > 0 && fields[n-1] == "" {
return fields[:n-1]
}
return fields
}
func Lookup(data map[string]any, keys ...string) string {
for _, key := range keys {
value, ok := data[key]
if !ok {
continue
}
switch typed := value.(type) {
case string:
if strings.TrimSpace(typed) != "" {
return strings.TrimSpace(typed)
}
case []byte:
if strings.TrimSpace(string(typed)) != "" {
return strings.TrimSpace(string(typed))
}
case json.Number:
if typed.String() != "" {
return typed.String()
}
}
}
return ""
}