-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrules.go
More file actions
87 lines (78 loc) · 2.77 KB
/
Copy pathrules.go
File metadata and controls
87 lines (78 loc) · 2.77 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
package structs
import (
"fmt"
"reflect"
"strings"
)
// DefaultRules is the built-in rule set, keyed by the name used in a `rules:`
// tag. Pass it to New/ValidateStructFields, or build your own map (optionally extending this one)
// to register custom RuleFuncs.
var DefaultRules = map[string]RuleFunc{
"required": Required,
"oneof": OneOf,
}
// RuleFunc validates one field against one rule. It receives the lookup key
// (fieldName, already resolved by tag priority), the full input values, the field's default,
// its reflect.Value, and the rule's args.
// It returns a map of field name to error messages (empty when valid).
// the returned error is for internal failures, not validation failures.
type RuleFunc func(fieldName string, values map[string]any, defaultValue string, fieldValue reflect.Value, args []string) (map[string][]string, error)
// Required fails when a field has no non-empty input and no default and the
// field's current value is zero. Whitespace-only string inputs count as empty.
var Required RuleFunc = func(fieldName string, values map[string]any, defaultValue string, fieldValue reflect.Value, args []string) (map[string][]string, error) {
value, ok := values[fieldName]
if !ok && defaultValue == "" {
if fieldValue.IsValid() && !fieldValue.IsZero() {
//nolint:nilnil // nil, nil means no validation and internal errors
return nil, nil
}
errors := map[string][]string{
fieldName: {"required"},
}
return errors, nil
}
if valStr, ok := value.(string); ok {
value = strings.TrimSpace(valStr)
if value == "" {
value = defaultValue
}
if value == "" {
errors := map[string][]string{
fieldName: {"required"},
}
return errors, nil
}
}
//nolint:nilnil // nil, nil means no validation and internal errors
return nil, nil
}
// OneOf restricts a field to one of the values listed in the rule args, e.g.
// `rules:"oneof:json,yaml,toml"`. An empty/absent value passes (pair with
// `required` to force presence); the default value, when set, is what gets
// checked if no input was provided.
var OneOf RuleFunc = func(fieldName string, values map[string]any, defaultValue string, fieldValue reflect.Value, args []string) (map[string][]string, error) {
value := ""
if raw, ok := values[fieldName]; ok {
if s, isStr := raw.(string); isStr {
value = strings.TrimSpace(s)
} else if raw != nil {
value = fmt.Sprintf("%v", raw)
}
}
if value == "" {
value = defaultValue
}
if value == "" {
//nolint:nilnil // nil, nil means no validation and internal errors
return nil, nil
}
for _, allowed := range args {
if value == allowed {
//nolint:nilnil // nil, nil means no validation and internal errors
return nil, nil
}
}
return map[string][]string{
fieldName: {"must be one of: " + strings.Join(args, ", ")},
}, nil
}