...
1 package jsonschema
2
3 import (
4 "bytes"
5 "context"
6 "encoding/json"
7 "fmt"
8
9 jptr "github.com/qri-io/jsonpointer"
10 )
11
12 var notSupported = map[string]bool{
13
14 "$vocabulary": true,
15
16
17 "contentEncoding": true,
18 "contentMediaType": true,
19 "contentSchema": true,
20 "deprecated": true,
21
22
23 "definitions": true,
24 "dependencies": true,
25 }
26
27 var (
28 keywordRegistry = map[string]KeyMaker{}
29 keywordOrder = map[string]int{}
30 keywordInsertOrder = map[string]int{}
31 )
32
33
34 func IsRegisteredKeyword(prop string) bool {
35 _, ok := keywordRegistry[prop]
36 return ok
37 }
38
39
40 func GetKeyword(prop string) Keyword {
41 if !IsRegisteredKeyword(prop) {
42 return NewVoid()
43 }
44 return keywordRegistry[prop]()
45 }
46
47
48
49 func GetKeywordOrder(prop string) int {
50 if order, ok := keywordOrder[prop]; ok {
51 return order
52 }
53 return 1
54 }
55
56
57
58 func GetKeywordInsertOrder(prop string) int {
59 if order, ok := keywordInsertOrder[prop]; ok {
60 return order
61 }
62
63 return 1000
64 }
65
66
67 func SetKeywordOrder(prop string, order int) {
68 keywordOrder[prop] = order
69 }
70
71
72
73 func IsNotSupportedKeyword(prop string) bool {
74 _, ok := notSupported[prop]
75 return ok
76 }
77
78
79 func IsRegistryLoaded() bool {
80 return keywordRegistry != nil && len(keywordRegistry) > 0
81 }
82
83
84 func RegisterKeyword(prop string, maker KeyMaker) {
85 keywordRegistry[prop] = maker
86 keywordInsertOrder[prop] = len(keywordInsertOrder)
87 }
88
89
90
91
92 var MaxKeywordErrStringLen = 20
93
94
95
96 type Keyword interface {
97
98
99 ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{})
100
101
102
103
104
105 Register(uri string, registry *SchemaRegistry)
106
107
108
109
110
111
112
113
114
115
116 Resolve(pointer jptr.Pointer, uri string) *Schema
117 }
118
119
120
121
122 type KeyMaker func() Keyword
123
124
125
126 type KeyError struct {
127
128
129 PropertyPath string `json:"propertyPath,omitempty"`
130
131 InvalidValue interface{} `json:"invalidValue,omitempty"`
132
133 Message string `json:"message"`
134 }
135
136
137 func (v KeyError) Error() string {
138 if v.PropertyPath != "" && v.InvalidValue != nil {
139 return fmt.Sprintf("%s: %s %s", v.PropertyPath, InvalidValueString(v.InvalidValue), v.Message)
140 } else if v.PropertyPath != "" {
141 return fmt.Sprintf("%s: %s", v.PropertyPath, v.Message)
142 }
143 return v.Message
144 }
145
146
147 func InvalidValueString(data interface{}) string {
148 bt, err := json.Marshal(data)
149 if err != nil {
150 return ""
151 }
152 bt = bytes.Replace(bt, []byte{'\n', '\r'}, []byte{' '}, -1)
153 if MaxKeywordErrStringLen != -1 && len(bt) > MaxKeywordErrStringLen {
154 bt = append(bt[:MaxKeywordErrStringLen], []byte("...")...)
155 }
156 return string(bt)
157 }
158
View as plain text