json_schemer 0.1.10 → 0.2.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/Gemfile.lock +2 -2
- data/lib/json_schemer.rb +13 -1
- data/lib/json_schemer/format.rb +0 -6
- data/lib/json_schemer/schema/base.rb +81 -55
- data/lib/json_schemer/schema/draft4.rb +2 -2
- data/lib/json_schemer/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99e547dd87197c33f01403e652c5ddecdb1dc39df0e63071a588135a94100960
|
4
|
+
data.tar.gz: d2b6d281eaa5d6d228ef5a90ea1d8ddbd22574f72d638c83d3fe48b1fd50825c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a506748ca559c13ae0c05204011be6bd5650c8982ef2fdd4e4874bc094664201a7d5856f1cceea5b5773956c74cb4d7e1a68c9b1c8165e3c1ce40d48fcef6ed
|
7
|
+
data.tar.gz: ae1eaa5e38b44e88244ab51782184f397050ce07d0ace89ef450777d4be4a7c1c2003b7d8e66df7c9f1a373b2ef1b1a27c0b8c5d26d03cbabe01645f3ecf6894
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
json_schemer (0.
|
4
|
+
json_schemer (0.2.0)
|
5
5
|
ecma-re-validator (~> 0.2.0)
|
6
6
|
hana (~> 1.3.3)
|
7
7
|
regexp_parser (~> 1.2.0)
|
@@ -12,7 +12,7 @@ GEM
|
|
12
12
|
specs:
|
13
13
|
ecma-re-validator (0.2.0)
|
14
14
|
regexp_parser (~> 1.2)
|
15
|
-
hana (1.3.
|
15
|
+
hana (1.3.5)
|
16
16
|
minitest (5.11.1)
|
17
17
|
rake (10.5.0)
|
18
18
|
regexp_parser (1.2.0)
|
data/lib/json_schemer.rb
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'base64'
|
4
|
+
require 'json'
|
5
|
+
require 'net/http'
|
6
|
+
require 'pathname'
|
7
|
+
require 'time'
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
require 'ecma-re-validator'
|
11
|
+
require 'hana'
|
12
|
+
require 'ipaddr'
|
13
|
+
require 'uri_template'
|
14
|
+
|
3
15
|
require 'json_schemer/version'
|
4
16
|
require 'json_schemer/format'
|
5
17
|
require 'json_schemer/cached_ref_resolver'
|
@@ -7,11 +19,11 @@ require 'json_schemer/schema/base'
|
|
7
19
|
require 'json_schemer/schema/draft4'
|
8
20
|
require 'json_schemer/schema/draft6'
|
9
21
|
require 'json_schemer/schema/draft7'
|
10
|
-
require 'pathname'
|
11
22
|
|
12
23
|
module JSONSchemer
|
13
24
|
class UnsupportedMetaSchema < StandardError; end
|
14
25
|
class UnknownRef < StandardError; end
|
26
|
+
class InvalidRefResolution < StandardError; end
|
15
27
|
class InvalidFileURI < StandardError; end
|
16
28
|
class InvalidSymbolKey < StandardError; end
|
17
29
|
|
data/lib/json_schemer/format.rb
CHANGED
@@ -1,12 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'base64'
|
4
|
-
require 'hana'
|
5
|
-
require 'json'
|
6
|
-
require 'net/http'
|
7
|
-
require 'time'
|
8
|
-
require 'uri'
|
9
|
-
|
10
3
|
module JSONSchemer
|
11
4
|
module Schema
|
12
5
|
class Base
|
@@ -25,8 +18,8 @@ module JSONSchemer
|
|
25
18
|
end
|
26
19
|
|
27
20
|
ID_KEYWORD = '$id'
|
28
|
-
DEFAULT_REF_RESOLVER = proc { |uri| raise UnknownRef, uri.to_s }
|
29
|
-
NET_HTTP_REF_RESOLVER = proc { |uri| JSON.parse(Net::HTTP.get(uri)) }
|
21
|
+
DEFAULT_REF_RESOLVER = proc { |uri| raise UnknownRef, uri.to_s }
|
22
|
+
NET_HTTP_REF_RESOLVER = proc { |uri| JSON.parse(Net::HTTP.get(uri)) }
|
30
23
|
BOOLEANS = Set[true, false].freeze
|
31
24
|
|
32
25
|
RUBY_REGEX_ANCHORS_TO_ECMA_262 = {
|
@@ -43,7 +36,7 @@ module JSONSchemer
|
|
43
36
|
keywords: nil,
|
44
37
|
ref_resolver: DEFAULT_REF_RESOLVER
|
45
38
|
)
|
46
|
-
raise InvalidSymbolKey, 'schemas must use string keys' if schema.is_a?(Hash) && schema.first.first.is_a?(
|
39
|
+
raise InvalidSymbolKey, 'schemas must use string keys' if schema.is_a?(Hash) && !schema.first.first.is_a?(String)
|
47
40
|
@root = schema
|
48
41
|
@format = format
|
49
42
|
@formats = formats
|
@@ -65,18 +58,17 @@ module JSONSchemer
|
|
65
58
|
validate_instance(instance).none?
|
66
59
|
end
|
67
60
|
|
68
|
-
def validate_instance(instance)
|
61
|
+
def validate_instance(instance, &block)
|
69
62
|
return enum_for(:validate_instance, instance) unless block_given?
|
70
63
|
|
71
64
|
schema = instance.schema
|
72
65
|
|
73
|
-
return if schema == true
|
74
66
|
if schema == false
|
75
67
|
yield error(instance, 'schema')
|
76
68
|
return
|
77
69
|
end
|
78
70
|
|
79
|
-
return if schema.empty?
|
71
|
+
return if schema == true || schema.empty?
|
80
72
|
|
81
73
|
type = schema['type']
|
82
74
|
enum = schema['enum']
|
@@ -94,12 +86,12 @@ module JSONSchemer
|
|
94
86
|
instance.parent_uri = join_uri(instance.parent_uri, id)
|
95
87
|
|
96
88
|
if ref
|
97
|
-
validate_ref(instance, ref, &
|
89
|
+
validate_ref(instance, ref, &block)
|
98
90
|
return
|
99
91
|
end
|
100
92
|
|
101
93
|
if format? && custom_format?(format)
|
102
|
-
validate_custom_format(instance, formats.fetch(format), &
|
94
|
+
validate_custom_format(instance, formats.fetch(format), &block)
|
103
95
|
end
|
104
96
|
|
105
97
|
if keywords
|
@@ -107,7 +99,7 @@ module JSONSchemer
|
|
107
99
|
if schema.key?(keyword)
|
108
100
|
result = callable.call(data, schema, instance.pointer)
|
109
101
|
if result.is_a?(Array)
|
110
|
-
result.each
|
102
|
+
result.each(&block)
|
111
103
|
elsif !result
|
112
104
|
yield error(instance, keyword)
|
113
105
|
end
|
@@ -120,25 +112,50 @@ module JSONSchemer
|
|
120
112
|
yield error(instance, 'enum') if enum && !enum.include?(data)
|
121
113
|
yield error(instance, 'const') if schema.key?('const') && schema['const'] != data
|
122
114
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
115
|
+
if all_of
|
116
|
+
all_of.each_with_index do |subschema, index|
|
117
|
+
validate_instance(instance.merge(schema: subschema, schema_pointer: "#{instance.schema_pointer}/allOf/#{index}"), &block)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
if any_of
|
122
|
+
subschemas = any_of.lazy.with_index.map do |subschema, index|
|
123
|
+
validate_instance(instance.merge(schema: subschema, schema_pointer: "#{instance.schema_pointer}/anyOf/#{index}"))
|
124
|
+
end
|
125
|
+
subschemas.each { |subschema| subschema.each(&block) } unless subschemas.any?(&:none?)
|
126
|
+
end
|
127
|
+
|
128
|
+
if one_of
|
129
|
+
subschemas = one_of.map.with_index do |subschema, index|
|
130
|
+
validate_instance(instance.merge(schema: subschema, schema_pointer: "#{instance.schema_pointer}/oneOf/#{index}"))
|
131
|
+
end
|
132
|
+
valid_subschema_count = subschemas.count(&:none?)
|
133
|
+
if valid_subschema_count > 1
|
134
|
+
yield error(instance, 'oneOf')
|
135
|
+
elsif valid_subschema_count == 0
|
136
|
+
subschemas.each { |subschema| subschema.each(&block) }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
unless not_schema.nil?
|
141
|
+
subinstance = instance.merge(schema: not_schema, schema_pointer: "#{instance.schema_pointer}/not")
|
142
|
+
yield error(subinstance, 'not') if valid_instance?(subinstance)
|
143
|
+
end
|
127
144
|
|
128
145
|
if if_schema && valid_instance?(instance.merge(schema: if_schema))
|
129
|
-
|
146
|
+
validate_instance(instance.merge(schema: then_schema, schema_pointer: "#{instance.schema_pointer}/then"), &block) unless then_schema.nil?
|
130
147
|
elsif if_schema
|
131
|
-
|
148
|
+
validate_instance(instance.merge(schema: else_schema, schema_pointer: "#{instance.schema_pointer}/else"), &block) unless else_schema.nil?
|
132
149
|
end
|
133
150
|
|
134
151
|
case type
|
135
152
|
when nil
|
136
|
-
validate_class(instance, &
|
153
|
+
validate_class(instance, &block)
|
137
154
|
when String
|
138
|
-
validate_type(instance, type, &
|
155
|
+
validate_type(instance, type, &block)
|
139
156
|
when Array
|
140
157
|
if valid_type = type.find { |subtype| valid_instance?(instance.merge(schema: { 'type' => subtype })) }
|
141
|
-
validate_type(instance, valid_type, &
|
158
|
+
validate_type(instance, valid_type, &block)
|
142
159
|
else
|
143
160
|
yield error(instance, 'type')
|
144
161
|
end
|
@@ -179,8 +196,8 @@ module JSONSchemer
|
|
179
196
|
)
|
180
197
|
end
|
181
198
|
|
182
|
-
def error(instance, type)
|
183
|
-
{
|
199
|
+
def error(instance, type, details = nil)
|
200
|
+
error = {
|
184
201
|
'data' => instance.data,
|
185
202
|
'data_pointer' => instance.data_pointer,
|
186
203
|
'schema' => instance.schema,
|
@@ -188,43 +205,45 @@ module JSONSchemer
|
|
188
205
|
'root_schema' => root,
|
189
206
|
'type' => type,
|
190
207
|
}
|
208
|
+
error['details'] = details if details
|
209
|
+
error
|
191
210
|
end
|
192
211
|
|
193
|
-
def validate_class(instance)
|
212
|
+
def validate_class(instance, &block)
|
194
213
|
case instance.data
|
195
214
|
when Integer
|
196
|
-
validate_integer(instance, &
|
215
|
+
validate_integer(instance, &block)
|
197
216
|
when Numeric
|
198
|
-
validate_number(instance, &
|
217
|
+
validate_number(instance, &block)
|
199
218
|
when String
|
200
|
-
validate_string(instance, &
|
219
|
+
validate_string(instance, &block)
|
201
220
|
when Array
|
202
|
-
validate_array(instance, &
|
221
|
+
validate_array(instance, &block)
|
203
222
|
when Hash
|
204
|
-
validate_object(instance, &
|
223
|
+
validate_object(instance, &block)
|
205
224
|
end
|
206
225
|
end
|
207
226
|
|
208
|
-
def validate_type(instance, type)
|
227
|
+
def validate_type(instance, type, &block)
|
209
228
|
case type
|
210
229
|
when 'null'
|
211
230
|
yield error(instance, 'null') unless instance.data.nil?
|
212
231
|
when 'boolean'
|
213
232
|
yield error(instance, 'boolean') unless BOOLEANS.include?(instance.data)
|
214
233
|
when 'number'
|
215
|
-
validate_number(instance, &
|
234
|
+
validate_number(instance, &block)
|
216
235
|
when 'integer'
|
217
|
-
validate_integer(instance, &
|
236
|
+
validate_integer(instance, &block)
|
218
237
|
when 'string'
|
219
|
-
validate_string(instance, &
|
238
|
+
validate_string(instance, &block)
|
220
239
|
when 'array'
|
221
|
-
validate_array(instance, &
|
240
|
+
validate_array(instance, &block)
|
222
241
|
when 'object'
|
223
|
-
validate_object(instance, &
|
242
|
+
validate_object(instance, &block)
|
224
243
|
end
|
225
244
|
end
|
226
245
|
|
227
|
-
def validate_ref(instance, ref)
|
246
|
+
def validate_ref(instance, ref, &block)
|
228
247
|
ref_uri = join_uri(instance.parent_uri, ref)
|
229
248
|
|
230
249
|
if valid_json_pointer?(ref_uri.fragment)
|
@@ -235,16 +254,16 @@ module JSONSchemer
|
|
235
254
|
schema_pointer: ref_uri.fragment,
|
236
255
|
parent_uri: pointer_uri(root, ref_pointer)
|
237
256
|
)
|
238
|
-
validate_instance(subinstance, &
|
257
|
+
validate_instance(subinstance, &block)
|
239
258
|
else
|
240
|
-
ref_root =
|
259
|
+
ref_root = resolve_ref(ref_uri)
|
241
260
|
ref_object = child(ref_root)
|
242
261
|
subinstance = instance.merge(
|
243
262
|
schema: ref_pointer.eval(ref_root),
|
244
263
|
schema_pointer: ref_uri.fragment,
|
245
264
|
parent_uri: pointer_uri(ref_root, ref_pointer)
|
246
265
|
)
|
247
|
-
ref_object.validate_instance(subinstance, &
|
266
|
+
ref_object.validate_instance(subinstance, &block)
|
248
267
|
end
|
249
268
|
elsif id = ids[ref_uri.to_s]
|
250
269
|
subinstance = instance.merge(
|
@@ -252,9 +271,9 @@ module JSONSchemer
|
|
252
271
|
schema_pointer: id.fetch(:pointer),
|
253
272
|
parent_uri: ref_uri
|
254
273
|
)
|
255
|
-
validate_instance(subinstance, &
|
274
|
+
validate_instance(subinstance, &block)
|
256
275
|
else
|
257
|
-
ref_root =
|
276
|
+
ref_root = resolve_ref(ref_uri)
|
258
277
|
ref_object = child(ref_root)
|
259
278
|
id = ref_object.ids[ref_uri.to_s] || { schema: ref_root, pointer: '' }
|
260
279
|
subinstance = instance.merge(
|
@@ -262,7 +281,7 @@ module JSONSchemer
|
|
262
281
|
schema_pointer: id.fetch(:pointer),
|
263
282
|
parent_uri: ref_uri
|
264
283
|
)
|
265
|
-
ref_object.validate_instance(subinstance, &
|
284
|
+
ref_object.validate_instance(subinstance, &block)
|
266
285
|
end
|
267
286
|
end
|
268
287
|
|
@@ -278,7 +297,7 @@ module JSONSchemer
|
|
278
297
|
yield error(instance, 'exclusiveMinimum') if instance.data <= exclusive_minimum
|
279
298
|
end
|
280
299
|
|
281
|
-
def validate_numeric(instance)
|
300
|
+
def validate_numeric(instance, &block)
|
282
301
|
schema = instance.schema
|
283
302
|
data = instance.data
|
284
303
|
|
@@ -291,8 +310,8 @@ module JSONSchemer
|
|
291
310
|
yield error(instance, 'maximum') if maximum && data > maximum
|
292
311
|
yield error(instance, 'minimum') if minimum && data < minimum
|
293
312
|
|
294
|
-
validate_exclusive_maximum(instance, exclusive_maximum, maximum, &
|
295
|
-
validate_exclusive_minimum(instance, exclusive_minimum, minimum, &
|
313
|
+
validate_exclusive_maximum(instance, exclusive_maximum, maximum, &block) if exclusive_maximum
|
314
|
+
validate_exclusive_minimum(instance, exclusive_minimum, minimum, &block) if exclusive_minimum
|
296
315
|
|
297
316
|
if multiple_of
|
298
317
|
quotient = data / multiple_of.to_f
|
@@ -300,16 +319,16 @@ module JSONSchemer
|
|
300
319
|
end
|
301
320
|
end
|
302
321
|
|
303
|
-
def validate_number(instance)
|
322
|
+
def validate_number(instance, &block)
|
304
323
|
unless instance.data.is_a?(Numeric)
|
305
324
|
yield error(instance, 'number')
|
306
325
|
return
|
307
326
|
end
|
308
327
|
|
309
|
-
validate_numeric(instance, &
|
328
|
+
validate_numeric(instance, &block)
|
310
329
|
end
|
311
330
|
|
312
|
-
def validate_integer(instance)
|
331
|
+
def validate_integer(instance, &block)
|
313
332
|
data = instance.data
|
314
333
|
|
315
334
|
if !data.is_a?(Numeric) || (!data.is_a?(Integer) && data.floor != data)
|
@@ -317,10 +336,10 @@ module JSONSchemer
|
|
317
336
|
return
|
318
337
|
end
|
319
338
|
|
320
|
-
validate_numeric(instance, &
|
339
|
+
validate_numeric(instance, &block)
|
321
340
|
end
|
322
341
|
|
323
|
-
def validate_string(instance)
|
342
|
+
def validate_string(instance, &block)
|
324
343
|
data = instance.data
|
325
344
|
|
326
345
|
unless data.is_a?(String)
|
@@ -453,7 +472,10 @@ module JSONSchemer
|
|
453
472
|
|
454
473
|
yield error(instance, 'maxProperties') if max_properties && data.size > max_properties
|
455
474
|
yield error(instance, 'minProperties') if min_properties && data.size < min_properties
|
456
|
-
|
475
|
+
if required
|
476
|
+
missing_keys = required - data.keys
|
477
|
+
yield error(instance, 'required', 'missing_keys' => missing_keys) if missing_keys.any?
|
478
|
+
end
|
457
479
|
|
458
480
|
regex_pattern_properties = nil
|
459
481
|
data.each do |key, value|
|
@@ -570,6 +592,10 @@ module JSONSchemer
|
|
570
592
|
end
|
571
593
|
ids
|
572
594
|
end
|
595
|
+
|
596
|
+
def resolve_ref(uri)
|
597
|
+
ref_resolver.call(uri) || raise(InvalidRefResolution, uri.to_s)
|
598
|
+
end
|
573
599
|
end
|
574
600
|
end
|
575
601
|
end
|
@@ -32,13 +32,13 @@ module JSONSchemer
|
|
32
32
|
yield error(instance, 'exclusiveMinimum') if exclusive_minimum && instance.data <= minimum
|
33
33
|
end
|
34
34
|
|
35
|
-
def validate_integer(instance)
|
35
|
+
def validate_integer(instance, &block)
|
36
36
|
if !instance.data.is_a?(Integer)
|
37
37
|
yield error(instance, 'integer')
|
38
38
|
return
|
39
39
|
end
|
40
40
|
|
41
|
-
validate_numeric(instance, &
|
41
|
+
validate_numeric(instance, &block)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
data/lib/json_schemer/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json_schemer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Harsha
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -153,7 +153,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
153
|
- !ruby/object:Gem::Version
|
154
154
|
version: '0'
|
155
155
|
requirements: []
|
156
|
-
|
156
|
+
rubyforge_project:
|
157
|
+
rubygems_version: 2.7.6
|
157
158
|
signing_key:
|
158
159
|
specification_version: 4
|
159
160
|
summary: JSON Schema validator. Supports drafts 4, 6, and 7.
|