json-schema 2.8.1 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +55 -11
- data/lib/json-schema/attribute.rb +15 -16
- data/lib/json-schema/attributes/additionalitems.rb +1 -0
- data/lib/json-schema/attributes/additionalproperties.rb +4 -7
- data/lib/json-schema/attributes/allof.rb +33 -6
- data/lib/json-schema/attributes/anyof.rb +4 -4
- data/lib/json-schema/attributes/const.rb +15 -0
- data/lib/json-schema/attributes/dependencies.rb +1 -0
- data/lib/json-schema/attributes/disallow.rb +2 -1
- data/lib/json-schema/attributes/divisibleby.rb +1 -1
- data/lib/json-schema/attributes/enum.rb +3 -3
- data/lib/json-schema/attributes/extends.rb +10 -8
- data/lib/json-schema/attributes/format.rb +2 -1
- data/lib/json-schema/attributes/formats/custom.rb +5 -7
- data/lib/json-schema/attributes/formats/date.rb +2 -1
- data/lib/json-schema/attributes/formats/date_time.rb +4 -3
- data/lib/json-schema/attributes/formats/date_time_v4.rb +2 -1
- data/lib/json-schema/attributes/formats/ip.rb +3 -3
- data/lib/json-schema/attributes/formats/time.rb +1 -1
- data/lib/json-schema/attributes/formats/uri.rb +2 -1
- data/lib/json-schema/attributes/items.rb +1 -0
- data/lib/json-schema/attributes/limit.rb +2 -2
- data/lib/json-schema/attributes/limits/numeric.rb +1 -1
- data/lib/json-schema/attributes/maxdecimal.rb +2 -2
- data/lib/json-schema/attributes/not.rb +2 -2
- data/lib/json-schema/attributes/oneof.rb +9 -11
- data/lib/json-schema/attributes/pattern.rb +1 -1
- data/lib/json-schema/attributes/patternproperties.rb +2 -1
- data/lib/json-schema/attributes/properties.rb +10 -10
- data/lib/json-schema/attributes/properties_v4.rb +2 -2
- data/lib/json-schema/attributes/propertynames.rb +23 -0
- data/lib/json-schema/attributes/ref.rb +19 -18
- data/lib/json-schema/attributes/required.rb +6 -5
- data/lib/json-schema/attributes/type.rb +11 -10
- data/lib/json-schema/attributes/type_v4.rb +3 -3
- data/lib/json-schema/attributes/uniqueitems.rb +1 -1
- data/lib/json-schema/errors/validation_error.rb +10 -10
- data/lib/json-schema/schema/reader.rb +4 -2
- data/lib/json-schema/schema/validator.rb +4 -4
- data/lib/json-schema/schema.rb +13 -14
- data/lib/json-schema/util/array_set.rb +2 -4
- data/lib/json-schema/util/uri.rb +100 -77
- data/lib/json-schema/util/uuid.rb +204 -226
- data/lib/json-schema/validator.rb +173 -156
- data/lib/json-schema/validators/draft1.rb +21 -23
- data/lib/json-schema/validators/draft2.rb +22 -24
- data/lib/json-schema/validators/draft3.rb +26 -28
- data/lib/json-schema/validators/draft4.rb +34 -36
- data/lib/json-schema/validators/draft6.rb +36 -36
- data/lib/json-schema/validators/hyper-draft1.rb +2 -3
- data/lib/json-schema/validators/hyper-draft2.rb +2 -3
- data/lib/json-schema/validators/hyper-draft3.rb +2 -3
- data/lib/json-schema/validators/hyper-draft4.rb +2 -3
- data/lib/json-schema/validators/hyper-draft6.rb +2 -3
- data/lib/json-schema.rb +3 -3
- data/resources/draft-06.json +12 -12
- metadata +60 -32
|
@@ -3,8 +3,10 @@ require 'pathname'
|
|
|
3
3
|
require 'bigdecimal'
|
|
4
4
|
require 'digest/sha1'
|
|
5
5
|
require 'date'
|
|
6
|
-
require '
|
|
6
|
+
require 'timeout'
|
|
7
|
+
require 'stringio'
|
|
7
8
|
require 'yaml'
|
|
9
|
+
require 'delegate'
|
|
8
10
|
|
|
9
11
|
require 'json-schema/schema/reader'
|
|
10
12
|
require 'json-schema/errors/schema_error'
|
|
@@ -14,21 +16,22 @@ require 'json-schema/errors/json_parse_error'
|
|
|
14
16
|
require 'json-schema/util/uri'
|
|
15
17
|
|
|
16
18
|
module JSON
|
|
17
|
-
|
|
18
19
|
class Validator
|
|
19
|
-
|
|
20
20
|
@@schemas = {}
|
|
21
21
|
@@cache_schemas = true
|
|
22
22
|
@@default_opts = {
|
|
23
|
-
:
|
|
24
|
-
:
|
|
25
|
-
:
|
|
26
|
-
:
|
|
27
|
-
:
|
|
28
|
-
:
|
|
29
|
-
:
|
|
30
|
-
:
|
|
31
|
-
:
|
|
23
|
+
list: false,
|
|
24
|
+
version: nil,
|
|
25
|
+
validate_schema: false,
|
|
26
|
+
record_errors: false,
|
|
27
|
+
errors_as_objects: false,
|
|
28
|
+
insert_defaults: false,
|
|
29
|
+
clear_cache: false,
|
|
30
|
+
strict: false,
|
|
31
|
+
allPropertiesRequired: false,
|
|
32
|
+
noAdditionalProperties: false,
|
|
33
|
+
parse_data: true,
|
|
34
|
+
parse_integer: true,
|
|
32
35
|
}
|
|
33
36
|
@@validators = {}
|
|
34
37
|
@@default_validator = nil
|
|
@@ -37,32 +40,31 @@ module JSON
|
|
|
37
40
|
@@serializer = nil
|
|
38
41
|
@@mutex = Mutex.new
|
|
39
42
|
|
|
40
|
-
def initialize(schema_data,
|
|
43
|
+
def initialize(schema_data, opts = {})
|
|
41
44
|
@options = @@default_opts.clone.merge(opts)
|
|
42
|
-
@errors = []
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
@options[:version] = validator
|
|
46
|
+
configured_validator = self.class.validator_for_name(@options[:version])
|
|
46
47
|
@options[:schema_reader] ||= self.class.schema_reader
|
|
47
48
|
|
|
48
|
-
@validation_options = @options[:record_errors] ? {:
|
|
49
|
+
@validation_options = @options[:record_errors] ? { record_errors: true } : {}
|
|
49
50
|
@validation_options[:insert_defaults] = true if @options[:insert_defaults]
|
|
50
|
-
|
|
51
|
+
if @options[:strict] == true
|
|
52
|
+
@validation_options[:allPropertiesRequired] = true
|
|
53
|
+
@validation_options[:noAdditionalProperties] = true
|
|
54
|
+
else
|
|
55
|
+
@validation_options[:allPropertiesRequired] = true if @options[:allPropertiesRequired]
|
|
56
|
+
@validation_options[:noAdditionalProperties] = true if @options[:noAdditionalProperties]
|
|
57
|
+
end
|
|
51
58
|
@validation_options[:clear_cache] = true if !@@cache_schemas || @options[:clear_cache]
|
|
52
59
|
|
|
53
|
-
@@mutex.synchronize { @base_schema = initialize_schema(schema_data) }
|
|
54
|
-
@original_data = data
|
|
55
|
-
@data = initialize_data(data)
|
|
60
|
+
@@mutex.synchronize { @base_schema = initialize_schema(schema_data, configured_validator) }
|
|
56
61
|
@@mutex.synchronize { build_schemas(@base_schema) }
|
|
57
62
|
|
|
58
63
|
# validate the schema, if requested
|
|
59
64
|
if @options[:validate_schema]
|
|
60
|
-
if @base_schema.schema["$schema"]
|
|
61
|
-
base_validator = self.class.validator_for_name(@base_schema.schema["$schema"])
|
|
62
|
-
end
|
|
63
|
-
metaschema = base_validator ? base_validator.metaschema : validator.metaschema
|
|
64
65
|
# Don't clear the cache during metaschema validation!
|
|
65
|
-
self.class.
|
|
66
|
+
meta_validator = self.class.new(@base_schema.validator.metaschema, { clear_cache: false })
|
|
67
|
+
meta_validator.validate(@base_schema.schema)
|
|
66
68
|
end
|
|
67
69
|
|
|
68
70
|
# If the :fragment option is set, try and validate against the fragment
|
|
@@ -73,52 +75,74 @@ module JSON
|
|
|
73
75
|
|
|
74
76
|
def schema_from_fragment(base_schema, fragment)
|
|
75
77
|
schema_uri = base_schema.uri
|
|
76
|
-
fragments = fragment.split(
|
|
78
|
+
fragments = fragment.split('/').map { |f| f.gsub('~0', '~').gsub('~1', '/') }
|
|
77
79
|
|
|
78
80
|
# ensure the first element was a hash, per the fragment spec
|
|
79
|
-
if fragments.shift !=
|
|
80
|
-
raise JSON::Schema::SchemaError
|
|
81
|
+
if fragments.shift != '#'
|
|
82
|
+
raise JSON::Schema::SchemaError, 'Invalid fragment syntax in :fragment option'
|
|
81
83
|
end
|
|
82
84
|
|
|
85
|
+
schema_fragment = base_schema.schema
|
|
83
86
|
fragments.each do |f|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
elsif base_schema.is_a?(Hash)
|
|
90
|
-
if !base_schema.has_key?(f)
|
|
91
|
-
raise JSON::Schema::SchemaError.new("Invalid fragment resolution for :fragment option")
|
|
92
|
-
end
|
|
93
|
-
base_schema = JSON::Schema.new(base_schema[f],schema_uri,@options[:version])
|
|
94
|
-
elsif base_schema.is_a?(Array)
|
|
95
|
-
if base_schema[f.to_i].nil?
|
|
96
|
-
raise JSON::Schema::SchemaError.new("Invalid fragment resolution for :fragment option")
|
|
97
|
-
end
|
|
98
|
-
base_schema = JSON::Schema.new(base_schema[f.to_i],schema_uri,@options[:version])
|
|
99
|
-
else
|
|
100
|
-
raise JSON::Schema::SchemaError.new("Invalid schema encountered when resolving :fragment option")
|
|
87
|
+
case schema_fragment
|
|
88
|
+
when Hash
|
|
89
|
+
schema_fragment = schema_fragment[f]
|
|
90
|
+
when Array
|
|
91
|
+
schema_fragment = schema_fragment[f.to_i]
|
|
101
92
|
end
|
|
102
93
|
end
|
|
103
94
|
|
|
95
|
+
unless schema_fragment.is_a?(Hash)
|
|
96
|
+
raise JSON::Schema::SchemaError, 'Invalid fragment resolution for :fragment option'
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
schema = JSON::Schema.new(schema_fragment, schema_uri, base_schema.validator)
|
|
100
|
+
|
|
104
101
|
if @options[:list]
|
|
105
|
-
|
|
106
|
-
elsif
|
|
107
|
-
JSON::Schema.new(
|
|
102
|
+
schema.to_array_schema
|
|
103
|
+
elsif schema.is_a?(Hash)
|
|
104
|
+
JSON::Schema.new(schema, schema_uri, @options[:version])
|
|
108
105
|
else
|
|
109
|
-
|
|
106
|
+
schema
|
|
110
107
|
end
|
|
111
108
|
end
|
|
112
109
|
|
|
110
|
+
class ErrorRecorder < SimpleDelegator
|
|
111
|
+
def initialize(sub)
|
|
112
|
+
@errors = []
|
|
113
|
+
|
|
114
|
+
super
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def validation_error(error)
|
|
118
|
+
@errors.push(error)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def validation_errors
|
|
122
|
+
@errors
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def with_errors
|
|
126
|
+
self
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def with_errors
|
|
131
|
+
ErrorRecorder.new(self)
|
|
132
|
+
end
|
|
133
|
+
|
|
113
134
|
# Run a simple true/false validation of data against a schema
|
|
114
|
-
def validate
|
|
115
|
-
|
|
135
|
+
def validate(data)
|
|
136
|
+
original_data = data
|
|
137
|
+
data = initialize_data(data)
|
|
138
|
+
error_recorder = with_errors
|
|
139
|
+
@base_schema.validate(data, [], error_recorder, @validation_options)
|
|
116
140
|
|
|
117
141
|
if @options[:record_errors]
|
|
118
142
|
if @options[:errors_as_objects]
|
|
119
|
-
|
|
143
|
+
error_recorder.validation_errors.map { |e| e.to_hash }
|
|
120
144
|
else
|
|
121
|
-
|
|
145
|
+
error_recorder.validation_errors.map { |e| e.to_string }
|
|
122
146
|
end
|
|
123
147
|
else
|
|
124
148
|
true
|
|
@@ -128,7 +152,7 @@ module JSON
|
|
|
128
152
|
self.class.clear_cache
|
|
129
153
|
end
|
|
130
154
|
if @validation_options[:insert_defaults]
|
|
131
|
-
self.class.merge_missing_values(
|
|
155
|
+
self.class.merge_missing_values(data, original_data)
|
|
132
156
|
end
|
|
133
157
|
end
|
|
134
158
|
|
|
@@ -149,13 +173,13 @@ module JSON
|
|
|
149
173
|
schema = parent_schema.schema
|
|
150
174
|
|
|
151
175
|
# Build ref schemas if they exist
|
|
152
|
-
if schema[
|
|
153
|
-
load_ref_schema(parent_schema, schema[
|
|
176
|
+
if schema['$ref']
|
|
177
|
+
load_ref_schema(parent_schema, schema['$ref'])
|
|
154
178
|
end
|
|
155
179
|
|
|
156
|
-
case schema[
|
|
180
|
+
case schema['extends']
|
|
157
181
|
when String
|
|
158
|
-
load_ref_schema(parent_schema, schema[
|
|
182
|
+
load_ref_schema(parent_schema, schema['extends'])
|
|
159
183
|
when Array
|
|
160
184
|
schema['extends'].each do |type|
|
|
161
185
|
handle_schema(parent_schema, type)
|
|
@@ -163,12 +187,12 @@ module JSON
|
|
|
163
187
|
end
|
|
164
188
|
|
|
165
189
|
# Check for schemas in union types
|
|
166
|
-
[
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
190
|
+
%w[type disallow].each do |key|
|
|
191
|
+
next unless schema[key].is_a?(Array)
|
|
192
|
+
|
|
193
|
+
schema[key].each do |type|
|
|
194
|
+
if type.is_a?(Hash)
|
|
195
|
+
handle_schema(parent_schema, type)
|
|
172
196
|
end
|
|
173
197
|
end
|
|
174
198
|
end
|
|
@@ -177,7 +201,8 @@ module JSON
|
|
|
177
201
|
# are themselves schemas.
|
|
178
202
|
%w[definitions properties patternProperties].each do |key|
|
|
179
203
|
next unless value = schema[key]
|
|
180
|
-
|
|
204
|
+
|
|
205
|
+
value.each do |_k, inner_schema|
|
|
181
206
|
handle_schema(parent_schema, inner_schema)
|
|
182
207
|
end
|
|
183
208
|
end
|
|
@@ -185,20 +210,22 @@ module JSON
|
|
|
185
210
|
# Schema properties whose values are themselves schemas.
|
|
186
211
|
%w[additionalProperties additionalItems dependencies extends].each do |key|
|
|
187
212
|
next unless schema[key].is_a?(Hash)
|
|
213
|
+
|
|
188
214
|
handle_schema(parent_schema, schema[key])
|
|
189
215
|
end
|
|
190
216
|
|
|
191
217
|
# Schema properties whose values may be an array of schemas.
|
|
192
218
|
%w[allOf anyOf oneOf not].each do |key|
|
|
193
219
|
next unless value = schema[key]
|
|
220
|
+
|
|
194
221
|
Array(value).each do |inner_schema|
|
|
195
222
|
handle_schema(parent_schema, inner_schema)
|
|
196
223
|
end
|
|
197
224
|
end
|
|
198
225
|
|
|
199
226
|
# Items are always schemas
|
|
200
|
-
if schema[
|
|
201
|
-
items = schema[
|
|
227
|
+
if schema['items']
|
|
228
|
+
items = schema['items'].clone
|
|
202
229
|
items = [items] unless items.is_a?(Array)
|
|
203
230
|
|
|
204
231
|
items.each do |item|
|
|
@@ -207,10 +234,9 @@ module JSON
|
|
|
207
234
|
end
|
|
208
235
|
|
|
209
236
|
# Convert enum to a ArraySet
|
|
210
|
-
if schema[
|
|
211
|
-
schema[
|
|
237
|
+
if schema['enum'].is_a?(Array)
|
|
238
|
+
schema['enum'] = ArraySet.new(schema['enum'])
|
|
212
239
|
end
|
|
213
|
-
|
|
214
240
|
end
|
|
215
241
|
|
|
216
242
|
# Either load a reference schema or create a new schema
|
|
@@ -225,66 +251,55 @@ module JSON
|
|
|
225
251
|
end
|
|
226
252
|
end
|
|
227
253
|
|
|
228
|
-
def validation_error(error)
|
|
229
|
-
@errors.push(error)
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
def validation_errors
|
|
233
|
-
@errors
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
|
|
237
254
|
class << self
|
|
238
|
-
def validate(schema, data,opts={})
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
return false
|
|
243
|
-
end
|
|
255
|
+
def validate(schema, data, opts = {})
|
|
256
|
+
validate!(schema, data, opts)
|
|
257
|
+
rescue JSON::Schema::ValidationError, JSON::Schema::SchemaError
|
|
258
|
+
false
|
|
244
259
|
end
|
|
245
260
|
|
|
246
|
-
def validate_json(schema, data, opts={})
|
|
247
|
-
validate(schema, data, opts.merge(:
|
|
261
|
+
def validate_json(schema, data, opts = {})
|
|
262
|
+
validate(schema, data, opts.merge(json: true))
|
|
248
263
|
end
|
|
249
264
|
|
|
250
|
-
def validate_uri(schema, data, opts={})
|
|
251
|
-
validate(schema, data, opts.merge(:
|
|
265
|
+
def validate_uri(schema, data, opts = {})
|
|
266
|
+
validate(schema, data, opts.merge(uri: true))
|
|
252
267
|
end
|
|
253
268
|
|
|
254
|
-
def validate!(schema, data,opts={})
|
|
255
|
-
validator = new(schema,
|
|
256
|
-
validator.validate
|
|
269
|
+
def validate!(schema, data, opts = {})
|
|
270
|
+
validator = new(schema, opts)
|
|
271
|
+
validator.validate(data)
|
|
257
272
|
end
|
|
258
273
|
|
|
259
|
-
def validate2(schema, data, opts={})
|
|
260
|
-
warn
|
|
274
|
+
def validate2(schema, data, opts = {})
|
|
275
|
+
warn '[DEPRECATION NOTICE] JSON::Validator#validate2 has been replaced by JSON::Validator#validate! and will be removed in version >= 3. Please use the #validate! method instead.'
|
|
261
276
|
validate!(schema, data, opts)
|
|
262
277
|
end
|
|
263
278
|
|
|
264
|
-
def validate_json!(schema, data, opts={})
|
|
265
|
-
validate!(schema, data, opts.merge(:
|
|
279
|
+
def validate_json!(schema, data, opts = {})
|
|
280
|
+
validate!(schema, data, opts.merge(json: true))
|
|
266
281
|
end
|
|
267
282
|
|
|
268
|
-
def validate_uri!(schema, data, opts={})
|
|
269
|
-
validate!(schema, data, opts.merge(:
|
|
283
|
+
def validate_uri!(schema, data, opts = {})
|
|
284
|
+
validate!(schema, data, opts.merge(uri: true))
|
|
270
285
|
end
|
|
271
286
|
|
|
272
|
-
def fully_validate(schema, data, opts={})
|
|
273
|
-
validate!(schema, data, opts.merge(:
|
|
287
|
+
def fully_validate(schema, data, opts = {})
|
|
288
|
+
validate!(schema, data, opts.merge(record_errors: true))
|
|
274
289
|
end
|
|
275
290
|
|
|
276
|
-
def fully_validate_schema(schema, opts={})
|
|
291
|
+
def fully_validate_schema(schema, opts = {})
|
|
277
292
|
data = schema
|
|
278
293
|
schema = validator_for_name(opts[:version]).metaschema
|
|
279
294
|
fully_validate(schema, data, opts)
|
|
280
295
|
end
|
|
281
296
|
|
|
282
|
-
def fully_validate_json(schema, data, opts={})
|
|
283
|
-
fully_validate(schema, data, opts.merge(:
|
|
297
|
+
def fully_validate_json(schema, data, opts = {})
|
|
298
|
+
fully_validate(schema, data, opts.merge(json: true))
|
|
284
299
|
end
|
|
285
300
|
|
|
286
|
-
def fully_validate_uri(schema, data, opts={})
|
|
287
|
-
fully_validate(schema, data, opts.merge(:
|
|
301
|
+
def fully_validate_uri(schema, data, opts = {})
|
|
302
|
+
fully_validate(schema, data, opts.merge(uri: true))
|
|
288
303
|
end
|
|
289
304
|
|
|
290
305
|
def schema_reader
|
|
@@ -297,7 +312,6 @@ module JSON
|
|
|
297
312
|
|
|
298
313
|
def clear_cache
|
|
299
314
|
@@schemas = {}
|
|
300
|
-
JSON::Util::URI.clear_cache
|
|
301
315
|
end
|
|
302
316
|
|
|
303
317
|
def schemas
|
|
@@ -324,8 +338,8 @@ module JSON
|
|
|
324
338
|
end
|
|
325
339
|
|
|
326
340
|
def cache_schemas=(val)
|
|
327
|
-
warn
|
|
328
|
-
@@cache_schemas = val == true
|
|
341
|
+
warn '[DEPRECATION NOTICE] Schema caching is now a validation option. Schemas will still be cached if this is set to true, but this method will be removed in version >= 3. Please use the :clear_cache validation option instead.'
|
|
342
|
+
@@cache_schemas = val == true
|
|
329
343
|
end
|
|
330
344
|
|
|
331
345
|
def validators
|
|
@@ -336,32 +350,34 @@ module JSON
|
|
|
336
350
|
@@default_validator
|
|
337
351
|
end
|
|
338
352
|
|
|
339
|
-
def validator_for_uri(schema_uri, raise_not_found=true)
|
|
353
|
+
def validator_for_uri(schema_uri, raise_not_found = true)
|
|
340
354
|
return default_validator unless schema_uri
|
|
355
|
+
|
|
341
356
|
u = JSON::Util::URI.parse(schema_uri)
|
|
342
357
|
validator = validators["#{u.scheme}://#{u.host}#{u.path}"]
|
|
343
358
|
if validator.nil? && raise_not_found
|
|
344
|
-
raise JSON::Schema::SchemaError
|
|
359
|
+
raise JSON::Schema::SchemaError, "Schema not found: #{schema_uri}"
|
|
345
360
|
else
|
|
346
361
|
validator
|
|
347
362
|
end
|
|
348
363
|
end
|
|
349
364
|
|
|
350
|
-
def validator_for_name(schema_name, raise_not_found=true)
|
|
365
|
+
def validator_for_name(schema_name, raise_not_found = true)
|
|
351
366
|
return default_validator unless schema_name
|
|
367
|
+
|
|
352
368
|
schema_name = schema_name.to_s
|
|
353
369
|
validator = validators.values.detect do |v|
|
|
354
370
|
Array(v.names).include?(schema_name)
|
|
355
371
|
end
|
|
356
372
|
if validator.nil? && raise_not_found
|
|
357
|
-
raise JSON::Schema::SchemaError
|
|
373
|
+
raise JSON::Schema::SchemaError, 'The requested JSON schema version is not supported'
|
|
358
374
|
else
|
|
359
375
|
validator
|
|
360
376
|
end
|
|
361
377
|
end
|
|
362
378
|
|
|
363
379
|
def validator_for(schema_uri)
|
|
364
|
-
warn
|
|
380
|
+
warn '[DEPRECATION NOTICE] JSON::Validator#validator_for has been replaced by JSON::Validator#validator_for_uri and will be removed in version >= 3. Please use the #validator_for_uri method instead.'
|
|
365
381
|
validator_for_uri(schema_uri)
|
|
366
382
|
end
|
|
367
383
|
|
|
@@ -373,7 +389,7 @@ module JSON
|
|
|
373
389
|
@@default_validator = v
|
|
374
390
|
end
|
|
375
391
|
|
|
376
|
-
def register_format_validator(format, validation_proc, versions = (@@validators.flat_map{ |
|
|
392
|
+
def register_format_validator(format, validation_proc, versions = (@@validators.flat_map { |_k, v| v.names.first } + [nil]))
|
|
377
393
|
custom_format_validator = JSON::Schema::CustomFormat.new(validation_proc)
|
|
378
394
|
versions.each do |version|
|
|
379
395
|
validator = validator_for_name(version)
|
|
@@ -381,14 +397,14 @@ module JSON
|
|
|
381
397
|
end
|
|
382
398
|
end
|
|
383
399
|
|
|
384
|
-
def deregister_format_validator(format, versions = (@@validators.flat_map{ |
|
|
400
|
+
def deregister_format_validator(format, versions = (@@validators.flat_map { |_k, v| v.names.first } + [nil]))
|
|
385
401
|
versions.each do |version|
|
|
386
402
|
validator = validator_for_name(version)
|
|
387
403
|
validator.formats[format.to_s] = validator.default_formats[format.to_s]
|
|
388
404
|
end
|
|
389
405
|
end
|
|
390
406
|
|
|
391
|
-
def restore_default_formats(versions = (@@validators.flat_map{ |
|
|
407
|
+
def restore_default_formats(versions = (@@validators.flat_map { |_k, v| v.names.first } + [nil]))
|
|
392
408
|
versions.each do |version|
|
|
393
409
|
validator = validator_for_name(version)
|
|
394
410
|
validator.formats = validator.default_formats.clone
|
|
@@ -405,14 +421,14 @@ module JSON
|
|
|
405
421
|
|
|
406
422
|
def json_backend=(backend)
|
|
407
423
|
if defined?(MultiJson)
|
|
408
|
-
backend = backend == 'json'
|
|
424
|
+
backend = 'json_gem' if backend == 'json'
|
|
409
425
|
MultiJson.respond_to?(:use) ? MultiJson.use(backend) : MultiJson.engine = backend
|
|
410
426
|
else
|
|
411
427
|
backend = backend.to_s
|
|
412
428
|
if @@available_json_backends.include?(backend)
|
|
413
429
|
@@json_backend = backend
|
|
414
430
|
else
|
|
415
|
-
raise JSON::Schema::JsonParseError
|
|
431
|
+
raise JSON::Schema::JsonParseError, "The JSON backend '#{backend}' could not be found."
|
|
416
432
|
end
|
|
417
433
|
end
|
|
418
434
|
end
|
|
@@ -422,26 +438,26 @@ module JSON
|
|
|
422
438
|
begin
|
|
423
439
|
MultiJson.respond_to?(:adapter) ? MultiJson.load(s) : MultiJson.decode(s)
|
|
424
440
|
rescue MultiJson::ParseError => e
|
|
425
|
-
raise JSON::Schema::JsonParseError
|
|
441
|
+
raise JSON::Schema::JsonParseError, e.message
|
|
426
442
|
end
|
|
427
443
|
else
|
|
428
444
|
case @@json_backend.to_s
|
|
429
445
|
when 'json'
|
|
430
446
|
begin
|
|
431
|
-
JSON.parse(s, :
|
|
447
|
+
JSON.parse(s, quirks_mode: true)
|
|
432
448
|
rescue JSON::ParserError => e
|
|
433
|
-
raise JSON::Schema::JsonParseError
|
|
449
|
+
raise JSON::Schema::JsonParseError, e.message
|
|
434
450
|
end
|
|
435
451
|
when 'yajl'
|
|
436
452
|
begin
|
|
437
453
|
json = StringIO.new(s)
|
|
438
454
|
parser = Yajl::Parser.new
|
|
439
|
-
parser.parse(json) or raise
|
|
455
|
+
parser.parse(json) or raise(JSON::Schema::JsonParseError, 'The JSON could not be parsed by yajl')
|
|
440
456
|
rescue Yajl::ParseError => e
|
|
441
|
-
raise JSON::Schema::JsonParseError
|
|
457
|
+
raise JSON::Schema::JsonParseError, e.message
|
|
442
458
|
end
|
|
443
459
|
else
|
|
444
|
-
raise JSON::Schema::JsonParseError
|
|
460
|
+
raise JSON::Schema::JsonParseError, "No supported JSON parsers found. The following parsers are suported:\n * yajl-ruby\n * json"
|
|
445
461
|
end
|
|
446
462
|
end
|
|
447
463
|
end
|
|
@@ -465,8 +481,8 @@ module JSON
|
|
|
465
481
|
end
|
|
466
482
|
end
|
|
467
483
|
|
|
468
|
-
|
|
469
|
-
if Gem::Specification
|
|
484
|
+
unless defined?(MultiJson)
|
|
485
|
+
if Gem::Specification.find_all_by_name('json').any?
|
|
470
486
|
require 'json'
|
|
471
487
|
@@available_json_backends << 'json'
|
|
472
488
|
@@json_backend = 'json'
|
|
@@ -480,34 +496,33 @@ module JSON
|
|
|
480
496
|
end
|
|
481
497
|
end
|
|
482
498
|
|
|
483
|
-
|
|
484
|
-
if Gem::Specification::find_all_by_name('yajl-ruby').any?
|
|
499
|
+
if Gem::Specification.find_all_by_name('yajl-ruby').any?
|
|
485
500
|
require 'yajl'
|
|
486
501
|
@@available_json_backends << 'yajl'
|
|
487
502
|
@@json_backend = 'yajl'
|
|
488
503
|
end
|
|
489
504
|
|
|
490
|
-
if @@json_backend == 'yajl'
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
505
|
+
@@serializer = if @@json_backend == 'yajl'
|
|
506
|
+
->(o) { Yajl::Encoder.encode(o) }
|
|
507
|
+
elsif @@json_backend == 'json'
|
|
508
|
+
->(o) { JSON.dump(o) }
|
|
509
|
+
else
|
|
510
|
+
->(o) { YAML.dump(o) }
|
|
511
|
+
end
|
|
497
512
|
end
|
|
498
513
|
end
|
|
499
514
|
|
|
500
515
|
private
|
|
501
516
|
|
|
502
|
-
if Gem::Specification
|
|
517
|
+
if Gem::Specification.find_all_by_name('uuidtools').any?
|
|
503
518
|
require 'uuidtools'
|
|
504
|
-
@@fake_uuid_generator =
|
|
519
|
+
@@fake_uuid_generator = ->(s) { UUIDTools::UUID.sha1_create(UUIDTools::UUID_URL_NAMESPACE, s).to_s }
|
|
505
520
|
else
|
|
506
521
|
require 'json-schema/util/uuid'
|
|
507
|
-
@@fake_uuid_generator =
|
|
522
|
+
@@fake_uuid_generator = ->(s) { JSON::Util::UUID.create_v5(s, JSON::Util::UUID::Nil).to_s }
|
|
508
523
|
end
|
|
509
524
|
|
|
510
|
-
def serialize
|
|
525
|
+
def serialize(schema)
|
|
511
526
|
if defined?(MultiJson)
|
|
512
527
|
MultiJson.respond_to?(:dump) ? MultiJson.dump(schema) : MultiJson.encode(schema)
|
|
513
528
|
else
|
|
@@ -515,16 +530,16 @@ module JSON
|
|
|
515
530
|
end
|
|
516
531
|
end
|
|
517
532
|
|
|
518
|
-
def fake_uuid
|
|
533
|
+
def fake_uuid(schema)
|
|
519
534
|
@@fake_uuid_generator.call(schema)
|
|
520
535
|
end
|
|
521
536
|
|
|
522
|
-
def initialize_schema(schema)
|
|
537
|
+
def initialize_schema(schema, default_validator)
|
|
523
538
|
if schema.is_a?(String)
|
|
524
539
|
begin
|
|
525
540
|
# Build a fake URI for this
|
|
526
541
|
schema_uri = JSON::Util::URI.parse(fake_uuid(schema))
|
|
527
|
-
schema = JSON::Schema.new(
|
|
542
|
+
schema = JSON::Schema.new(JSON::Validator.parse(schema), schema_uri, default_validator)
|
|
528
543
|
if @options[:list] && @options[:fragment].nil?
|
|
529
544
|
schema = schema.to_array_schema
|
|
530
545
|
end
|
|
@@ -532,7 +547,15 @@ module JSON
|
|
|
532
547
|
rescue JSON::Schema::JsonParseError
|
|
533
548
|
# Build a uri for it
|
|
534
549
|
schema_uri = Util::URI.normalized_uri(schema)
|
|
535
|
-
if
|
|
550
|
+
if self.class.schema_loaded?(schema_uri)
|
|
551
|
+
schema = self.class.schema_for_uri(schema_uri)
|
|
552
|
+
if @options[:list] && @options[:fragment].nil?
|
|
553
|
+
schema = schema.to_array_schema
|
|
554
|
+
schema.uri = JSON::Util::URI.parse(fake_uuid(serialize(schema.schema)))
|
|
555
|
+
self.class.add_schema(schema)
|
|
556
|
+
end
|
|
557
|
+
schema
|
|
558
|
+
else
|
|
536
559
|
schema = @options[:schema_reader].read(schema_uri)
|
|
537
560
|
schema = JSON::Schema.stringify(schema)
|
|
538
561
|
|
|
@@ -541,26 +564,18 @@ module JSON
|
|
|
541
564
|
end
|
|
542
565
|
|
|
543
566
|
self.class.add_schema(schema)
|
|
544
|
-
else
|
|
545
|
-
schema = self.class.schema_for_uri(schema_uri)
|
|
546
|
-
if @options[:list] && @options[:fragment].nil?
|
|
547
|
-
schema = schema.to_array_schema
|
|
548
|
-
schema.uri = JSON::Util::URI.parse(fake_uuid(serialize(schema.schema)))
|
|
549
|
-
self.class.add_schema(schema)
|
|
550
|
-
end
|
|
551
|
-
schema
|
|
552
567
|
end
|
|
553
568
|
end
|
|
554
569
|
elsif schema.is_a?(Hash)
|
|
555
570
|
schema_uri = JSON::Util::URI.parse(fake_uuid(serialize(schema)))
|
|
556
571
|
schema = JSON::Schema.stringify(schema)
|
|
557
|
-
schema = JSON::Schema.new(schema, schema_uri,
|
|
572
|
+
schema = JSON::Schema.new(schema, schema_uri, default_validator)
|
|
558
573
|
if @options[:list] && @options[:fragment].nil?
|
|
559
574
|
schema = schema.to_array_schema
|
|
560
575
|
end
|
|
561
576
|
self.class.add_schema(schema)
|
|
562
577
|
else
|
|
563
|
-
raise JSON::Schema::SchemaParseError,
|
|
578
|
+
raise JSON::Schema::SchemaParseError, 'Invalid schema - must be either a string or a hash'
|
|
564
579
|
end
|
|
565
580
|
|
|
566
581
|
schema
|
|
@@ -575,7 +590,9 @@ module JSON
|
|
|
575
590
|
data = self.class.parse(custom_open(json_uri))
|
|
576
591
|
elsif data.is_a?(String)
|
|
577
592
|
begin
|
|
578
|
-
|
|
593
|
+
# Check if the string is valid integer
|
|
594
|
+
strict_convert = data.match?(/\A[+-]?\d+\z/) && !@options[:parse_integer]
|
|
595
|
+
data = self.class.parse(data) unless strict_convert
|
|
579
596
|
rescue JSON::Schema::JsonParseError
|
|
580
597
|
begin
|
|
581
598
|
json_uri = Util::URI.normalized_uri(data)
|
|
@@ -593,7 +610,7 @@ module JSON
|
|
|
593
610
|
uri = Util::URI.normalized_uri(uri) if uri.is_a?(String)
|
|
594
611
|
if uri.absolute? && Util::URI::SUPPORTED_PROTOCOLS.include?(uri.scheme)
|
|
595
612
|
begin
|
|
596
|
-
open(uri.to_s).read
|
|
613
|
+
URI.open(uri.to_s).read
|
|
597
614
|
rescue OpenURI::HTTPError, Timeout::Error => e
|
|
598
615
|
raise JSON::Schema::JsonLoadError, e.message
|
|
599
616
|
end
|