-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstr.go
More file actions
247 lines (214 loc) · 5.91 KB
/
Copy pathstr.go
File metadata and controls
247 lines (214 loc) · 5.91 KB
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
package vaddie
import (
"fmt"
"net/mail"
"regexp"
"strings"
"unicode"
"unicode/utf8"
)
// StrEmpty validates our value is empty.
func StrEmpty() ValidateValue[string] {
return func(value string) error {
length := len(value)
if length != 0 {
return &ValidationError{
Message: "not empty",
Help: fmt.Sprintf("%d > 0", length),
}
}
return nil
}
}
// StrSpace validates our value is entirely made up of unicode space characters.
func StrSpace() ValidateValue[string] {
return func(value string) error {
for _, v := range value {
if !unicode.IsSpace(v) {
return &ValidationError{
Message: "not entirely whitespace",
Help: fmt.Sprintf("%q has printable character %q", value, v),
}
}
}
return nil
}
}
// StrMin validates our value is at least a minimum length.
func StrMin(minLength int) ValidateValue[string] {
return func(value string) error {
length := len(value)
if length < minLength {
return &ValidationError{
Message: "too short",
Help: fmt.Sprintf("%d < %d", length, minLength),
}
}
return nil
}
}
// StrMax validates our value is no more then a maximum length.
func StrMax(maxLength int) ValidateValue[string] {
return func(value string) error {
length := len(value)
if length > maxLength {
return &ValidationError{
Message: "too long",
Help: fmt.Sprintf("%d > %d", length, maxLength),
}
}
return nil
}
}
// StrUnicodeMin validates our value is at least a minimum length of unicode characters.
// This properly compares strings that include things such as emojis and CJK symbols.
func StrUnicodeMin(minLength int) ValidateValue[string] {
return func(value string) error {
length := utf8.RuneCountInString(value)
if length < minLength {
return &ValidationError{
Message: "unicode length too short",
Help: fmt.Sprintf("%d < %d", length, minLength),
}
}
return nil
}
}
// StrUnicodeMax validates our value is no more then a maximum length of unicode characters.
// This properly compares strings that include things such as emojis and CJK symbols.
func StrUnicodeMax(maxLength int) ValidateValue[string] {
return func(value string) error {
length := utf8.RuneCountInString(value)
if length > maxLength {
return &ValidationError{
Message: "unicode length too long",
Help: fmt.Sprintf("%d > %d", length, maxLength),
}
}
return nil
}
}
// StrLetters validates every rune is a letter.
func StrLetters() ValidateValue[string] {
return func(value string) error {
for i, v := range value {
if !unicode.IsLetter(v) {
return &ValidationError{
Message: "non-letter rune",
Help: fmt.Sprintf("%q at index %d", v, i),
}
}
}
return nil
}
}
// StrAscii validates every rune is an ascii value.
func StrAscii() ValidateValue[string] {
return func(value string) error {
for i, v := range value {
if v > unicode.MaxASCII {
return &ValidationError{
Message: "non-ascii rune",
Help: fmt.Sprintf("%q at index %d", v, i),
}
}
}
return nil
}
}
// StrHasPrefix validates our string has the provided prefix.
func StrHasPrefix(prefix string) ValidateValue[string] {
return func(value string) error {
if !strings.HasPrefix(value, prefix) {
return &ValidationError{
Message: "does not have prefix",
Help: fmt.Sprintf("%q does not have expected prefix %q", value, prefix),
}
}
return nil
}
}
// StrHasSuffix validates our string has the provided suffix.
func StrHasSuffix(suffix string) ValidateValue[string] {
return func(value string) error {
if !strings.HasSuffix(value, suffix) {
return &ValidationError{
Message: "does not have suffix",
Help: fmt.Sprintf("%q does not have expected suffix %q", value, suffix),
}
}
return nil
}
}
// StrContains validates our string contains the provided substring.
func StrContains(substr string) ValidateValue[string] {
return func(value string) error {
if !strings.Contains(value, substr) {
return &ValidationError{
Message: "does not have substr",
Help: fmt.Sprintf("%q does not have expected substr %q", value, substr),
}
}
return nil
}
}
// StrContainsAny validates whether any Unicode code points in chars are within value.
func StrContainsAny(chars string) ValidateValue[string] {
return func(value string) error {
if !strings.ContainsAny(value, chars) {
return &ValidationError{
Message: "does not have chars",
Help: fmt.Sprintf("%q does not have any of the chars %q", value, chars),
}
}
return nil
}
}
// StrMatch validates whether the value is matched by the provided regex.
// The regex is compiled once, if the regex is invalid every validation will fail but
// not panic.
// Use [StrRegexp] if you want to handle compiling the regexp yourself.
func StrMatch(reg string) ValidateValue[string] {
rg, err := regexp.Compile(reg)
return func(value string) error {
if err != nil {
return &ValidationError{
Message: "regex did not compile",
Help: fmt.Sprintf("%q is invalid", reg),
}
}
if !rg.MatchString(value) {
return &ValidationError{
Message: "does not match regex",
Help: fmt.Sprintf("%q does not match", value),
}
}
return nil
}
}
// StrRegexp validates whether the value is matched by the provided regex.
// Use [StrMatch] if you want vaddie to manage compiling the regexp.
func StrRegexp(rg *regexp.Regexp) ValidateValue[string] {
return func(value string) error {
if !rg.MatchString(value) {
return &ValidationError{
Message: "does not match regex",
Help: fmt.Sprintf("%q does not match", value),
}
}
return nil
}
}
// StrEmail validates whether the value is a valid email address according to RFC 5322.
func StrEmail() ValidateValue[string] {
return func(value string) error {
_, err := mail.ParseAddress(value)
if err != nil {
return &ValidationError{
Message: "is not an email",
Help: fmt.Sprintf("%q not a valid email", value),
}
}
return nil
}
}