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.
@@ -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
- if root == self && (!value.is_a?(Hash) || !value.key?(meta_schema.id_keyword))
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 value.is_a?(Hash)
337
- keywords = meta_schema.keywords
338
-
339
- if value.key?('$ref') && keywords.fetch('$ref').exclusive?
340
- @parsed['$ref'] = keywords.fetch('$ref').new(value.fetch('$ref'), self, '$ref')
341
- defs_keyword = meta_schema.defs_keyword
342
- if value.key?(defs_keyword) && keywords.key?(defs_keyword)
343
- @parsed[defs_keyword] = keywords.fetch(defs_keyword).new(value.fetch(defs_keyword), self, defs_keyword)
344
- end
345
- else
346
- keyword_order = meta_schema.keyword_order
347
- last = keywords.size
348
-
349
- value.sort do |(keyword_a, _value_a), (keyword_b, _value_b)|
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
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module JSONSchemer
3
- VERSION = '2.0.0'
3
+ VERSION = '2.1.0'
4
4
  end
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.0.0
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-08-20 00:00:00.000000000 Z
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