json_schemer 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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