json_schemer 2.0.0 → 2.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/.github/workflows/ci.yml +1 -1
- data/CHANGELOG.md +18 -1
- data/Gemfile.lock +10 -3
- data/README.md +192 -1
- data/json_schemer.gemspec +2 -0
- data/lib/json_schemer/content.rb +18 -0
- data/lib/json_schemer/draft201909/meta.rb +3 -18
- data/lib/json_schemer/draft202012/meta.rb +27 -24
- data/lib/json_schemer/draft202012/vocab/content.rb +10 -2
- data/lib/json_schemer/draft202012/vocab/core.rb +6 -0
- data/lib/json_schemer/draft202012/vocab/format_annotation.rb +1 -9
- data/lib/json_schemer/draft202012/vocab/format_assertion.rb +1 -7
- data/lib/json_schemer/draft202012/vocab.rb +3 -1
- data/lib/json_schemer/draft4/meta.rb +6 -0
- data/lib/json_schemer/draft6/meta.rb +11 -0
- data/lib/json_schemer/draft7/meta.rb +5 -0
- data/lib/json_schemer/draft7/vocab/validation.rb +4 -4
- data/lib/json_schemer/format.rb +113 -117
- data/lib/json_schemer/keyword.rb +4 -0
- data/lib/json_schemer/openapi30/meta.rb +6 -0
- data/lib/json_schemer/openapi31/meta.rb +8 -0
- data/lib/json_schemer/openapi31/vocab/base.rb +65 -27
- data/lib/json_schemer/output.rb +6 -5
- data/lib/json_schemer/result.rb +71 -10
- data/lib/json_schemer/schema.rb +57 -23
- data/lib/json_schemer/version.rb +1 -1
- data/lib/json_schemer.rb +20 -19
- metadata +31 -2
data/lib/json_schemer/schema.rb
CHANGED
@@ -10,7 +10,6 @@ module JSONSchemer
|
|
10
10
|
end
|
11
11
|
|
12
12
|
include Output
|
13
|
-
include Format::JSONPointer
|
14
13
|
|
15
14
|
DEFAULT_SCHEMA = Draft202012::BASE_URI.to_s.freeze
|
16
15
|
SCHEMA_KEYWORD_CLASS = Draft202012::Vocab::Core::Schema
|
@@ -21,6 +20,8 @@ module JSONSchemer
|
|
21
20
|
PROPERTIES_KEYWORD_CLASS = Draft202012::Vocab::Applicator::Properties
|
22
21
|
DEFAULT_BASE_URI = URI('json-schemer://schema').freeze
|
23
22
|
DEFAULT_FORMATS = {}.freeze
|
23
|
+
DEFAULT_CONTENT_ENCODINGS = {}.freeze
|
24
|
+
DEFAULT_CONTENT_MEDIA_TYPES = {}.freeze
|
24
25
|
DEFAULT_KEYWORDS = {}.freeze
|
25
26
|
DEFAULT_BEFORE_PROPERTY_VALIDATION = [].freeze
|
26
27
|
DEFAULT_AFTER_PROPERTY_VALIDATION = [].freeze
|
@@ -42,7 +43,7 @@ module JSONSchemer
|
|
42
43
|
|
43
44
|
attr_accessor :base_uri, :meta_schema, :keywords, :keyword_order
|
44
45
|
attr_reader :value, :parent, :root, :parsed
|
45
|
-
attr_reader :vocabulary, :format, :formats, :custom_keywords, :before_property_validation, :after_property_validation, :insert_property_defaults, :property_default_resolver
|
46
|
+
attr_reader :vocabulary, :format, :formats, :content_encodings, :content_media_types, :custom_keywords, :before_property_validation, :after_property_validation, :insert_property_defaults, :property_default_resolver
|
46
47
|
|
47
48
|
def initialize(
|
48
49
|
value,
|
@@ -54,6 +55,8 @@ module JSONSchemer
|
|
54
55
|
vocabulary: nil,
|
55
56
|
format: true,
|
56
57
|
formats: DEFAULT_FORMATS,
|
58
|
+
content_encodings: DEFAULT_CONTENT_ENCODINGS,
|
59
|
+
content_media_types: DEFAULT_CONTENT_MEDIA_TYPES,
|
57
60
|
keywords: DEFAULT_KEYWORDS,
|
58
61
|
before_property_validation: DEFAULT_BEFORE_PROPERTY_VALIDATION,
|
59
62
|
after_property_validation: DEFAULT_AFTER_PROPERTY_VALIDATION,
|
@@ -75,6 +78,8 @@ module JSONSchemer
|
|
75
78
|
@vocabulary = vocabulary
|
76
79
|
@format = format
|
77
80
|
@formats = formats
|
81
|
+
@content_encodings = content_encodings
|
82
|
+
@content_media_types = content_media_types
|
78
83
|
@custom_keywords = keywords
|
79
84
|
@before_property_validation = Array(before_property_validation)
|
80
85
|
@after_property_validation = Array(after_property_validation)
|
@@ -113,7 +118,7 @@ module JSONSchemer
|
|
113
118
|
end
|
114
119
|
|
115
120
|
def ref(value)
|
116
|
-
resolve_ref(URI.join(base_uri, value))
|
121
|
+
root.resolve_ref(URI.join(base_uri, value))
|
117
122
|
end
|
118
123
|
|
119
124
|
def validate_instance(instance, instance_location, keyword_location, context)
|
@@ -160,7 +165,7 @@ module JSONSchemer
|
|
160
165
|
|
161
166
|
def resolve_ref(uri)
|
162
167
|
pointer = ''
|
163
|
-
if valid_json_pointer?(uri.fragment)
|
168
|
+
if Format.valid_json_pointer?(uri.fragment)
|
164
169
|
pointer = URI.decode_www_form_component(uri.fragment)
|
165
170
|
uri.fragment = nil
|
166
171
|
end
|
@@ -183,6 +188,8 @@ module JSONSchemer
|
|
183
188
|
:meta_schema => meta_schema,
|
184
189
|
:format => format,
|
185
190
|
:formats => formats,
|
191
|
+
:content_encodings => content_encodings,
|
192
|
+
:content_media_types => content_media_types,
|
186
193
|
:keywords => custom_keywords,
|
187
194
|
:before_property_validation => before_property_validation,
|
188
195
|
:after_property_validation => after_property_validation,
|
@@ -288,6 +295,34 @@ module JSONSchemer
|
|
288
295
|
end
|
289
296
|
end
|
290
297
|
|
298
|
+
def error_key
|
299
|
+
'^'
|
300
|
+
end
|
301
|
+
|
302
|
+
def fetch_format(format, *args, &block)
|
303
|
+
if meta_schema == self
|
304
|
+
formats.fetch(format, *args, &block)
|
305
|
+
else
|
306
|
+
formats.fetch(format) { meta_schema.fetch_format(format, *args, &block) }
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def fetch_content_encoding(content_encoding, *args, &block)
|
311
|
+
if meta_schema == self
|
312
|
+
content_encodings.fetch(content_encoding, *args, &block)
|
313
|
+
else
|
314
|
+
content_encodings.fetch(content_encoding) { meta_schema.fetch_content_encoding(content_encoding, *args, &block) }
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def fetch_content_media_type(content_media_type, *args, &block)
|
319
|
+
if meta_schema == self
|
320
|
+
content_media_types.fetch(content_media_type, *args, &block)
|
321
|
+
else
|
322
|
+
content_media_types.fetch(content_media_type) { meta_schema.fetch_content_media_type(content_media_type, *args, &block) }
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
291
326
|
def id_keyword
|
292
327
|
@id_keyword ||= (keywords.key?('$id') ? '$id' : 'id')
|
293
328
|
end
|
@@ -329,28 +364,27 @@ module JSONSchemer
|
|
329
364
|
VOCABULARY_KEYWORD_CLASS.new(vocabulary, self, '$vocabulary')
|
330
365
|
end
|
331
366
|
|
332
|
-
|
367
|
+
keywords = meta_schema.keywords
|
368
|
+
exclusive_ref = value.is_a?(Hash) && value.key?('$ref') && keywords.fetch('$ref').exclusive?
|
369
|
+
|
370
|
+
if root == self && (!value.is_a?(Hash) || !value.key?(meta_schema.id_keyword) || exclusive_ref)
|
333
371
|
ID_KEYWORD_CLASS.new(base_uri, self, meta_schema.id_keyword)
|
334
372
|
end
|
335
373
|
|
336
|
-
if
|
337
|
-
|
338
|
-
|
339
|
-
if value.key?(
|
340
|
-
@parsed[
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
last
|
348
|
-
|
349
|
-
|
350
|
-
keyword_order.fetch(keyword_a, last) <=> keyword_order.fetch(keyword_b, last)
|
351
|
-
end.each do |keyword, value|
|
352
|
-
@parsed[keyword] ||= keywords.fetch(keyword, UNKNOWN_KEYWORD_CLASS).new(value, self, keyword)
|
353
|
-
end
|
374
|
+
if exclusive_ref
|
375
|
+
@parsed['$ref'] = keywords.fetch('$ref').new(value.fetch('$ref'), self, '$ref')
|
376
|
+
defs_keyword = meta_schema.defs_keyword
|
377
|
+
if value.key?(defs_keyword) && keywords.key?(defs_keyword)
|
378
|
+
@parsed[defs_keyword] = keywords.fetch(defs_keyword).new(value.fetch(defs_keyword), self, defs_keyword)
|
379
|
+
end
|
380
|
+
elsif value.is_a?(Hash)
|
381
|
+
keyword_order = meta_schema.keyword_order
|
382
|
+
last = keywords.size
|
383
|
+
|
384
|
+
value.sort do |(keyword_a, _value_a), (keyword_b, _value_b)|
|
385
|
+
keyword_order.fetch(keyword_a, last) <=> keyword_order.fetch(keyword_b, last)
|
386
|
+
end.each do |keyword, value|
|
387
|
+
@parsed[keyword] ||= keywords.fetch(keyword, UNKNOWN_KEYWORD_CLASS).new(value, self, keyword)
|
354
388
|
end
|
355
389
|
end
|
356
390
|
|
data/lib/json_schemer/version.rb
CHANGED
data/lib/json_schemer.rb
CHANGED
@@ -20,6 +20,7 @@ require 'json_schemer/format/json_pointer'
|
|
20
20
|
require 'json_schemer/format/uri_template'
|
21
21
|
require 'json_schemer/format/email'
|
22
22
|
require 'json_schemer/format'
|
23
|
+
require 'json_schemer/content'
|
23
24
|
require 'json_schemer/errors'
|
24
25
|
require 'json_schemer/cached_resolver'
|
25
26
|
require 'json_schemer/ecma_regexp'
|
@@ -145,6 +146,9 @@ module JSONSchemer
|
|
145
146
|
@draft202012 ||= Schema.new(
|
146
147
|
Draft202012::SCHEMA,
|
147
148
|
:base_uri => Draft202012::BASE_URI,
|
149
|
+
:formats => Draft202012::FORMATS,
|
150
|
+
:content_encodings => Draft202012::CONTENT_ENCODINGS,
|
151
|
+
:content_media_types => Draft202012::CONTENT_MEDIA_TYPES,
|
148
152
|
:ref_resolver => Draft202012::Meta::SCHEMAS.to_proc,
|
149
153
|
:regexp_resolver => 'ecma'
|
150
154
|
)
|
@@ -154,6 +158,9 @@ module JSONSchemer
|
|
154
158
|
@draft201909 ||= Schema.new(
|
155
159
|
Draft201909::SCHEMA,
|
156
160
|
:base_uri => Draft201909::BASE_URI,
|
161
|
+
:formats => Draft201909::FORMATS,
|
162
|
+
:content_encodings => Draft201909::CONTENT_ENCODINGS,
|
163
|
+
:content_media_types => Draft201909::CONTENT_MEDIA_TYPES,
|
157
164
|
:ref_resolver => Draft201909::Meta::SCHEMAS.to_proc,
|
158
165
|
:regexp_resolver => 'ecma'
|
159
166
|
)
|
@@ -164,6 +171,9 @@ module JSONSchemer
|
|
164
171
|
Draft7::SCHEMA,
|
165
172
|
:vocabulary => { 'json-schemer://draft7' => true },
|
166
173
|
:base_uri => Draft7::BASE_URI,
|
174
|
+
:formats => Draft7::FORMATS,
|
175
|
+
:content_encodings => Draft7::CONTENT_ENCODINGS,
|
176
|
+
:content_media_types => Draft7::CONTENT_MEDIA_TYPES,
|
167
177
|
:regexp_resolver => 'ecma'
|
168
178
|
)
|
169
179
|
end
|
@@ -173,6 +183,9 @@ module JSONSchemer
|
|
173
183
|
Draft6::SCHEMA,
|
174
184
|
:vocabulary => { 'json-schemer://draft6' => true },
|
175
185
|
:base_uri => Draft6::BASE_URI,
|
186
|
+
:formats => Draft6::FORMATS,
|
187
|
+
:content_encodings => Draft6::CONTENT_ENCODINGS,
|
188
|
+
:content_media_types => Draft6::CONTENT_MEDIA_TYPES,
|
176
189
|
:regexp_resolver => 'ecma'
|
177
190
|
)
|
178
191
|
end
|
@@ -182,6 +195,9 @@ module JSONSchemer
|
|
182
195
|
Draft4::SCHEMA,
|
183
196
|
:vocabulary => { 'json-schemer://draft4' => true },
|
184
197
|
:base_uri => Draft4::BASE_URI,
|
198
|
+
:formats => Draft4::FORMATS,
|
199
|
+
:content_encodings => Draft4::CONTENT_ENCODINGS,
|
200
|
+
:content_media_types => Draft4::CONTENT_MEDIA_TYPES,
|
185
201
|
:regexp_resolver => 'ecma'
|
186
202
|
)
|
187
203
|
end
|
@@ -190,16 +206,9 @@ module JSONSchemer
|
|
190
206
|
@openapi31 ||= Schema.new(
|
191
207
|
OpenAPI31::SCHEMA,
|
192
208
|
:base_uri => OpenAPI31::BASE_URI,
|
209
|
+
:formats => OpenAPI31::FORMATS,
|
193
210
|
:ref_resolver => OpenAPI31::Meta::SCHEMAS.to_proc,
|
194
|
-
:regexp_resolver => 'ecma'
|
195
|
-
# https://spec.openapis.org/oas/latest.html#data-types
|
196
|
-
:formats => {
|
197
|
-
'int32' => proc { |instance, _value| instance.is_a?(Integer) && instance.bit_length <= 32 },
|
198
|
-
'int64' => proc { |instance, _value| instance.is_a?(Integer) && instance.bit_length <= 64 },
|
199
|
-
'float' => proc { |instance, _value| instance.is_a?(Float) },
|
200
|
-
'double' => proc { |instance, _value| instance.is_a?(Float) },
|
201
|
-
'password' => proc { |_instance, _value| true }
|
202
|
-
}
|
211
|
+
:regexp_resolver => 'ecma'
|
203
212
|
)
|
204
213
|
end
|
205
214
|
|
@@ -211,17 +220,9 @@ module JSONSchemer
|
|
211
220
|
'json-schemer://openapi30' => true
|
212
221
|
},
|
213
222
|
:base_uri => OpenAPI30::BASE_URI,
|
223
|
+
:formats => OpenAPI30::FORMATS,
|
214
224
|
:ref_resolver => OpenAPI30::Meta::SCHEMAS.to_proc,
|
215
|
-
:regexp_resolver => 'ecma'
|
216
|
-
:formats => {
|
217
|
-
'int32' => proc { |instance, _value| instance.is_a?(Integer) && instance.bit_length <= 32 },
|
218
|
-
'int64' => proc { |instance, _value| instance.is_a?(Integer) && instance.bit_length <= 64 },
|
219
|
-
'float' => proc { |instance, _value| instance.is_a?(Float) },
|
220
|
-
'double' => proc { |instance, _value| instance.is_a?(Float) },
|
221
|
-
'byte' => proc { |instance, _value| Format.decode_content_encoding(instance, 'base64').first },
|
222
|
-
'binary' => proc { |instance, _value| instance.is_a?(String) && instance.encoding == Encoding::ASCII_8BIT },
|
223
|
-
'password' => proc { |_instance, _value| true }
|
224
|
-
}
|
225
|
+
:regexp_resolver => 'ecma'
|
225
226
|
)
|
226
227
|
end
|
227
228
|
|
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: 2.
|
4
|
+
version: 2.1.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: 2023-
|
11
|
+
date: 2023-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,34 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.22'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: i18n
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: i18n-debug
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
69
97
|
- !ruby/object:Gem::Dependency
|
70
98
|
name: hana
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -132,6 +160,7 @@ files:
|
|
132
160
|
- json_schemer.gemspec
|
133
161
|
- lib/json_schemer.rb
|
134
162
|
- lib/json_schemer/cached_resolver.rb
|
163
|
+
- lib/json_schemer/content.rb
|
135
164
|
- lib/json_schemer/draft201909/meta.rb
|
136
165
|
- lib/json_schemer/draft201909/vocab.rb
|
137
166
|
- lib/json_schemer/draft201909/vocab/applicator.rb
|