This repository has been archived by the owner on Jul 24, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
val_all.go
172 lines (145 loc) · 3.64 KB
/
val_all.go
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
package jsonschema
import (
"encoding/json"
"fmt"
"strings"
)
type allOf struct {
EmbeddedSchemas
}
// TODO: though it isn't covered by tests, this is isn't right because if the JSON
// used to create allOf.EmbeddedSchemas is an object or a single schema it will
// still be unmarshaled into allOf.EmbeddedSchemas. allOf should only recognize an
// array of schemas, not an object or a single schema.
//
// This (and similar validators) need custom UnmarshalJSON methods.
func (a allOf) Validate(keypath []string, v interface{}) (valErrs []ValidationError) {
for _, s := range a.EmbeddedSchemas {
valErrs = append(valErrs, s.Validate(keypath, v)...)
}
return
}
type anyOf struct {
EmbeddedSchemas
}
func (a anyOf) Validate(keypath []string, v interface{}) []ValidationError {
for _, s := range a.EmbeddedSchemas {
if s.Validate(keypath, v) == nil {
return nil
}
}
return []ValidationError{
{keypath, "Validation failed for each schema in 'anyOf'."}}
}
type enum []interface{}
func (a enum) Validate(keypath []string, v interface{}) []ValidationError {
for _, b := range a {
if DeepEqual(v, b) {
return nil
}
}
return []ValidationError{
{keypath, fmt.Sprintf("Enum error. The data must be equal to one of these values %v.", a)}}
}
type not struct {
EmbeddedSchemas
}
func (n not) Validate(keypath []string, v interface{}) []ValidationError {
s, ok := n.EmbeddedSchemas[""]
if !ok {
return nil
}
if s.Validate(keypath, v) == nil {
return []ValidationError{{keypath, "The 'not' schema didn't raise an error."}}
}
return nil
}
type oneOf struct {
EmbeddedSchemas
}
func (a oneOf) Validate(keypath []string, v interface{}) []ValidationError {
var succeeded int
for _, s := range a.EmbeddedSchemas {
if s.Validate(keypath, v) == nil {
succeeded++
}
}
if succeeded != 1 {
return []ValidationError{{keypath,
fmt.Sprintf("Validation passed for %d schemas in 'oneOf'.", succeeded)}}
}
return nil
}
// A dummy schema used if we don't recognize a schema key. We unmarshal the key's contents anyway
// because it might contain embedded schemas referenced elsewhere in the document.
//
// NOTE: this is the only validator that is hardcoded instead of being listed in validatorMap.
type other struct {
EmbeddedSchemas
}
func (o other) Validate(keypath []string, v interface{}) []ValidationError {
return nil
}
type ref string
func (r ref) Validate(keypath []string, v interface{}) []ValidationError {
return nil
}
type typeValidator map[string]bool
func (t *typeValidator) UnmarshalJSON(b []byte) error {
*t = make(typeValidator)
var s string
var l []string
// The value of the "type" keyword can be a string or an array.
if err := json.Unmarshal(b, &s); err != nil {
err = json.Unmarshal(b, &l)
if err != nil {
return err
}
} else {
l = []string{s}
}
for _, val := range l {
(*t)[val] = true
}
return nil
}
func (t typeValidator) Validate(keypath []string, v interface{}) []ValidationError {
if _, ok := t["any"]; ok {
return nil
}
var s string
switch x := v.(type) {
case string:
s = "string"
case bool:
s = "boolean"
case nil:
s = "null"
case []interface{}:
s = "array"
case map[string]interface{}:
s = "object"
case json.Number:
if strings.Contains(x.String(), ".") {
s = "number"
} else {
s = "integer"
}
case float64:
s = "number"
}
_, ok := t[s]
// The "number" type includes the "integer" type.
if !ok && s == "integer" {
_, ok = t["number"]
}
if !ok {
types := make([]string, 0, len(t))
for key := range t {
types = append(types, key)
}
return []ValidationError{{keypath,
fmt.Sprintf("Value must be one of these types: %s. Got %s", types, s)}}
}
return nil
}