1
2
3
4 package object
5
6 import (
7 "fmt"
8 "regexp"
9 "strings"
10
11 "k8s.io/apimachinery/pkg/util/validation/field"
12 )
13
14
15
16 func NestedField(obj map[string]interface{}, fields ...interface{}) (interface{}, bool, error) {
17 var val interface{} = obj
18
19 for i, field := range fields {
20 if val == nil {
21 return nil, false, nil
22 }
23 switch typedField := field.(type) {
24 case string:
25 if m, ok := val.(map[string]interface{}); ok {
26 val, ok = m[typedField]
27 if !ok {
28
29 return nil, false, nil
30 }
31 } else {
32 return nil, false, InvalidType(fields[:i+1], val, "map[string]interface{}")
33 }
34 case int:
35 if s, ok := val.([]interface{}); ok {
36 if typedField >= len(s) {
37
38 return nil, false, nil
39 }
40 val = s[typedField]
41 } else {
42 return nil, false, InvalidType(fields[:i+1], val, "[]interface{}")
43 }
44 default:
45 return nil, false, InvalidType(fields[:i+1], val, "string or int")
46 }
47 }
48 return val, true, nil
49 }
50
51
52
53 func InvalidType(fieldPath []interface{}, value interface{}, validTypes string) *field.Error {
54 return Invalid(fieldPath, value,
55 fmt.Sprintf("found type %T, expected %s", value, validTypes))
56 }
57
58
59
60 func Invalid(fieldPath []interface{}, value interface{}, detail string) *field.Error {
61 return &field.Error{
62 Type: field.ErrorTypeInvalid,
63 Field: FieldPath(fieldPath),
64 BadValue: value,
65 Detail: detail,
66 }
67 }
68
69
70
71 func NotFound(fieldPath []interface{}, value interface{}) *field.Error {
72 return &field.Error{
73 Type: field.ErrorTypeNotFound,
74 Field: FieldPath(fieldPath),
75 BadValue: value,
76 Detail: "",
77 }
78 }
79
80
81
82
83
84
85
86 func FieldPath(fieldPath []interface{}) string {
87 var sb strings.Builder
88 for _, field := range fieldPath {
89 switch typedField := field.(type) {
90 case string:
91 if isSimpleString(typedField) {
92 _, _ = fmt.Fprintf(&sb, ".%s", typedField)
93 } else {
94 _, _ = fmt.Fprintf(&sb, "[%q]", typedField)
95 }
96 case int:
97 _, _ = fmt.Fprintf(&sb, "[%d]", typedField)
98 default:
99
100 _, _ = fmt.Fprintf(&sb, "[%#v]", typedField)
101 }
102 }
103 return sb.String()
104 }
105
106 var simpleStringRegex = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$`)
107
108
109
110
111
112 func isSimpleString(s string) bool {
113 return simpleStringRegex.FindString(s) != ""
114 }
115
View as plain text