json_schemer 2.1.1 → 2.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/.github/workflows/ci.yml +1 -1
- data/CHANGELOG.md +20 -0
- data/Gemfile.lock +11 -4
- data/README.md +16 -1
- data/json_schemer.gemspec +3 -0
- data/lib/json_schemer/configuration.rb +32 -0
- data/lib/json_schemer/draft202012/vocab/applicator.rb +1 -1
- data/lib/json_schemer/draft202012/vocab/unevaluated.rb +18 -8
- data/lib/json_schemer/format.rb +5 -6
- data/lib/json_schemer/keyword.rb +3 -0
- data/lib/json_schemer/openapi.rb +2 -4
- data/lib/json_schemer/openapi30/meta.rb +1 -1
- data/lib/json_schemer/result.rb +14 -2
- data/lib/json_schemer/schema.rb +60 -59
- data/lib/json_schemer/version.rb +1 -1
- data/lib/json_schemer.rb +46 -22
- metadata +46 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4013d2026a3ac04ca50649b4cf6437ea2ee477ed1e9d350942cfa7e56ead0828
|
4
|
+
data.tar.gz: 810f08388b21cc68d849181a87a820982c2fc7a577c402d5e05699b0c8d07507
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4c5bb6fe5e6d4e0ccfd8abd28a0c12ae23254e74c807ba94278680bf7b706970276cef14f26eaf488f9c46ebd8d418b5aef90bf4abd886b9fd1d7513bb6d27a
|
7
|
+
data.tar.gz: 19a0c839189ba44d6688c389fa38b3f0b1ccc9986643471e2df4d50c347c5ce22ec3fa170002fc000fc877e05080842b57cc01351f46ff1e876ba972880e6584
|
data/.github/workflows/ci.yml
CHANGED
@@ -6,7 +6,7 @@ jobs:
|
|
6
6
|
fail-fast: false
|
7
7
|
matrix:
|
8
8
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
9
|
-
ruby: [2.5, 2.6, 2.7, 3.0, 3.1, 3.2, head, jruby, jruby-head, truffleruby, truffleruby-head]
|
9
|
+
ruby: [2.5, 2.6, 2.7, 3.0, 3.1, 3.2, 3.3, head, jruby, jruby-head, truffleruby, truffleruby-head]
|
10
10
|
exclude:
|
11
11
|
- os: windows-latest
|
12
12
|
ruby: truffleruby
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [2.2.0] - XXXX-XX-XX
|
4
|
+
|
5
|
+
## Bug Fixes
|
6
|
+
|
7
|
+
- Support symbol keys when accessing original instance: https://github.com/davishmcclurg/json_schemer/commit/d52c130e9967919c6cf1c9dbc3f0babfb8b01cf8
|
8
|
+
- Support custom keywords in nested schemas: https://github.com/davishmcclurg/json_schemer/commit/93c85a5006981347c7e9a4c11b73c6bdb65d8ba2
|
9
|
+
- Stringify instance location for custom keywords: https://github.com/davishmcclurg/json_schemer/commit/513c99130b9e7986b09881e7efd3fb7143744754
|
10
|
+
- Reduce unhelpful error output in `unevaluated` keywords: https://github.com/davishmcclurg/json_schemer/pull/164
|
11
|
+
- Handle parse errors during schema validation: https://github.com/davishmcclurg/json_schemer/pull/171
|
12
|
+
- Follow refs when finding default property values: https://github.com/davishmcclurg/json_schemer/pull/175
|
13
|
+
|
14
|
+
## Features
|
15
|
+
|
16
|
+
- Global configuration with `Configuration` object: https://github.com/davishmcclurg/json_schemer/pull/170
|
17
|
+
- Symbol key property defaults with `insert_property_defaults: :symbol`: https://github.com/davishmcclurg/json_schemer/commit/a72473dc84199107ddedc8998950e5b82273232a
|
18
|
+
- Consistent schema type support for schema validation methods: https://github.com/davishmcclurg/json_schemer/commit/bbcd0cea20cbaa61cf2bdae5f53840861cae54b8
|
19
|
+
- Validation option support for schema validation methods: https://github.com/davishmcclurg/json_schemer/commit/2eeef77de522f127619b7d0faa51e0d7e40977ad
|
20
|
+
|
21
|
+
[2.2.0]: https://github.com/davishmcclurg/json_schemer/releases/tag/v2.2.0
|
22
|
+
|
3
23
|
## [2.1.1] - 2023-11-28
|
4
24
|
|
5
25
|
### Bug Fixes
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
json_schemer (2.
|
4
|
+
json_schemer (2.2.0)
|
5
|
+
base64
|
6
|
+
bigdecimal
|
5
7
|
hana (~> 1.3)
|
6
8
|
regexp_parser (~> 2.0)
|
7
9
|
simpleidn (~> 0.2)
|
@@ -9,7 +11,11 @@ PATH
|
|
9
11
|
GEM
|
10
12
|
remote: https://rubygems.org/
|
11
13
|
specs:
|
14
|
+
base64 (0.2.0)
|
15
|
+
bigdecimal (3.1.6)
|
16
|
+
bigdecimal (3.1.6-java)
|
12
17
|
concurrent-ruby (1.2.2)
|
18
|
+
csv (3.2.8)
|
13
19
|
docile (1.4.0)
|
14
20
|
hana (1.3.7)
|
15
21
|
i18n (1.14.1)
|
@@ -17,8 +23,8 @@ GEM
|
|
17
23
|
i18n-debug (1.2.0)
|
18
24
|
i18n (< 2)
|
19
25
|
minitest (5.15.0)
|
20
|
-
rake (13.0
|
21
|
-
regexp_parser (2.
|
26
|
+
rake (13.1.0)
|
27
|
+
regexp_parser (2.9.0)
|
22
28
|
simplecov (0.22.0)
|
23
29
|
docile (~> 1.1)
|
24
30
|
simplecov-html (~> 0.11)
|
@@ -38,6 +44,7 @@ PLATFORMS
|
|
38
44
|
|
39
45
|
DEPENDENCIES
|
40
46
|
bundler (~> 2.0)
|
47
|
+
csv
|
41
48
|
i18n
|
42
49
|
i18n-debug
|
43
50
|
json_schemer!
|
@@ -46,4 +53,4 @@ DEPENDENCIES
|
|
46
53
|
simplecov (~> 0.22)
|
47
54
|
|
48
55
|
BUNDLED WITH
|
49
|
-
2.3.
|
56
|
+
2.3.27
|
data/README.md
CHANGED
@@ -212,7 +212,8 @@ JSONSchemer.schema(
|
|
212
212
|
},
|
213
213
|
|
214
214
|
# insert default property values during validation
|
215
|
-
#
|
215
|
+
# string keys by default (use `:symbol` to insert symbol keys)
|
216
|
+
# true/false/:symbol
|
216
217
|
# default: false
|
217
218
|
insert_property_defaults: true,
|
218
219
|
|
@@ -256,6 +257,20 @@ JSONSchemer.schema(
|
|
256
257
|
)
|
257
258
|
```
|
258
259
|
|
260
|
+
## Global Configuration
|
261
|
+
|
262
|
+
Configuration options can be set globally by modifying `JSONSchemer.configuration`. Global options are applied to any new schemas at creation time (global configuration changes are not reflected in existing schemas). They can be overridden with the regular keyword arguments described [above](#options).
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
# configuration block
|
266
|
+
JSONSchemer.configure do |config|
|
267
|
+
config.regexp_resolver = 'ecma'
|
268
|
+
end
|
269
|
+
|
270
|
+
# configuration accessors
|
271
|
+
JSONSchemer.configuration.insert_property_defaults = true
|
272
|
+
```
|
273
|
+
|
259
274
|
## Custom Error Messages
|
260
275
|
|
261
276
|
Error messages can be customized using the `x-error` keyword and/or [I18n](https://github.com/ruby-i18n/i18n) translations. `x-error` takes precedence if both are defined.
|
data/json_schemer.gemspec
CHANGED
@@ -26,9 +26,12 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_development_dependency "rake", "~> 13.0"
|
27
27
|
spec.add_development_dependency "minitest", "~> 5.0"
|
28
28
|
spec.add_development_dependency "simplecov", "~> 0.22"
|
29
|
+
spec.add_development_dependency "csv"
|
29
30
|
spec.add_development_dependency "i18n"
|
30
31
|
spec.add_development_dependency "i18n-debug"
|
31
32
|
|
33
|
+
spec.add_runtime_dependency "base64"
|
34
|
+
spec.add_runtime_dependency "bigdecimal"
|
32
35
|
spec.add_runtime_dependency "hana", "~> 1.3"
|
33
36
|
spec.add_runtime_dependency "regexp_parser", "~> 2.0"
|
34
37
|
spec.add_runtime_dependency "simpleidn", "~> 0.2"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSchemer
|
4
|
+
Configuration = Struct.new(
|
5
|
+
:base_uri, :meta_schema, :vocabulary, :format, :formats, :content_encodings, :content_media_types, :keywords,
|
6
|
+
:before_property_validation, :after_property_validation, :insert_property_defaults, :property_default_resolver,
|
7
|
+
:ref_resolver, :regexp_resolver, :output_format, :resolve_enumerators, :access_mode,
|
8
|
+
keyword_init: true
|
9
|
+
) do
|
10
|
+
def initialize(
|
11
|
+
base_uri: URI('json-schemer://schema'),
|
12
|
+
meta_schema: Draft202012::BASE_URI.to_s,
|
13
|
+
vocabulary: nil,
|
14
|
+
format: true,
|
15
|
+
formats: {},
|
16
|
+
content_encodings: {},
|
17
|
+
content_media_types: {},
|
18
|
+
keywords: {},
|
19
|
+
before_property_validation: [],
|
20
|
+
after_property_validation: [],
|
21
|
+
insert_property_defaults: false,
|
22
|
+
property_default_resolver: nil,
|
23
|
+
ref_resolver: proc { |uri| raise UnknownRef, uri.to_s },
|
24
|
+
regexp_resolver: 'ruby',
|
25
|
+
output_format: 'classic',
|
26
|
+
resolve_enumerators: false,
|
27
|
+
access_mode: nil
|
28
|
+
)
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -300,7 +300,7 @@ module JSONSchemer
|
|
300
300
|
end
|
301
301
|
|
302
302
|
def false_schema_error(formatted_instance_location:, **)
|
303
|
-
"object property at #{formatted_instance_location} is
|
303
|
+
"object property at #{formatted_instance_location} is a disallowed additional property"
|
304
304
|
end
|
305
305
|
|
306
306
|
def parse
|
@@ -8,6 +8,10 @@ module JSONSchemer
|
|
8
8
|
"array items at #{formatted_instance_location} do not match `unevaluatedItems` schema"
|
9
9
|
end
|
10
10
|
|
11
|
+
def false_schema_error(formatted_instance_location:, **)
|
12
|
+
"array item at #{formatted_instance_location} is a disallowed unevaluated item"
|
13
|
+
end
|
14
|
+
|
11
15
|
def parse
|
12
16
|
subschema(value)
|
13
17
|
end
|
@@ -18,7 +22,7 @@ module JSONSchemer
|
|
18
22
|
unevaluated_items = instance.size.times.to_set
|
19
23
|
|
20
24
|
context.adjacent_results.each_value do |adjacent_result|
|
21
|
-
collect_unevaluated_items(adjacent_result,
|
25
|
+
collect_unevaluated_items(adjacent_result, unevaluated_items)
|
22
26
|
end
|
23
27
|
|
24
28
|
nested = unevaluated_items.map do |index|
|
@@ -30,8 +34,7 @@ module JSONSchemer
|
|
30
34
|
|
31
35
|
private
|
32
36
|
|
33
|
-
def collect_unevaluated_items(result,
|
34
|
-
return unless result.valid && result.instance_location == instance_location
|
37
|
+
def collect_unevaluated_items(result, unevaluated_items)
|
35
38
|
case result.source
|
36
39
|
when Applicator::PrefixItems
|
37
40
|
unevaluated_items.subtract(0..result.annotation)
|
@@ -41,7 +44,9 @@ module JSONSchemer
|
|
41
44
|
unevaluated_items.subtract(result.annotation)
|
42
45
|
end
|
43
46
|
result.nested&.each do |subresult|
|
44
|
-
|
47
|
+
if subresult.valid && subresult.instance_location == result.instance_location
|
48
|
+
collect_unevaluated_items(subresult, unevaluated_items)
|
49
|
+
end
|
45
50
|
end
|
46
51
|
end
|
47
52
|
end
|
@@ -51,6 +56,10 @@ module JSONSchemer
|
|
51
56
|
"object properties at #{formatted_instance_location} do not match `unevaluatedProperties` schema"
|
52
57
|
end
|
53
58
|
|
59
|
+
def false_schema_error(formatted_instance_location:, **)
|
60
|
+
"object property at #{formatted_instance_location} is a disallowed unevaluated property"
|
61
|
+
end
|
62
|
+
|
54
63
|
def parse
|
55
64
|
subschema(value)
|
56
65
|
end
|
@@ -61,7 +70,7 @@ module JSONSchemer
|
|
61
70
|
evaluated_keys = Set[]
|
62
71
|
|
63
72
|
context.adjacent_results.each_value do |adjacent_result|
|
64
|
-
collect_evaluated_keys(adjacent_result,
|
73
|
+
collect_evaluated_keys(adjacent_result, evaluated_keys)
|
65
74
|
end
|
66
75
|
|
67
76
|
evaluated = instance.reject do |key, _value|
|
@@ -77,14 +86,15 @@ module JSONSchemer
|
|
77
86
|
|
78
87
|
private
|
79
88
|
|
80
|
-
def collect_evaluated_keys(result,
|
81
|
-
return unless result.valid && result.instance_location == instance_location
|
89
|
+
def collect_evaluated_keys(result, evaluated_keys)
|
82
90
|
case result.source
|
83
91
|
when Applicator::Properties, Applicator::PatternProperties, Applicator::AdditionalProperties, UnevaluatedProperties
|
84
92
|
evaluated_keys.merge(result.annotation)
|
85
93
|
end
|
86
94
|
result.nested&.each do |subresult|
|
87
|
-
|
95
|
+
if subresult.valid && subresult.instance_location == result.instance_location
|
96
|
+
collect_evaluated_keys(subresult, evaluated_keys)
|
97
|
+
end
|
88
98
|
end
|
89
99
|
end
|
90
100
|
end
|
data/lib/json_schemer/format.rb
CHANGED
@@ -76,8 +76,8 @@ module JSONSchemer
|
|
76
76
|
IRI_ESCAPE_REGEX = /[^[:ascii:]]/
|
77
77
|
UUID_REGEX = /\A\h{8}-\h{4}-\h{4}-[89AB]\h{3}-\h{12}\z/i
|
78
78
|
NIL_UUID = '00000000-0000-0000-0000-000000000000'
|
79
|
-
|
80
|
-
out[-byte.chr] = -sprintf('%%%02X', byte)
|
79
|
+
BINARY_TO_PERCENT_ENCODED = 256.times.each_with_object({}) do |byte, out|
|
80
|
+
out[-byte.chr(Encoding::BINARY)] = -sprintf('%%%02X', byte)
|
81
81
|
end.freeze
|
82
82
|
|
83
83
|
class << self
|
@@ -88,10 +88,9 @@ module JSONSchemer
|
|
88
88
|
include URITemplate
|
89
89
|
|
90
90
|
def percent_encode(data, regexp)
|
91
|
-
|
92
|
-
|
93
|
-
data.
|
94
|
-
data.force_encoding(Encoding::US_ASCII)
|
91
|
+
binary = data.b
|
92
|
+
binary.gsub!(regexp, BINARY_TO_PERCENT_ENCODED)
|
93
|
+
binary.force_encoding(data.encoding)
|
95
94
|
end
|
96
95
|
|
97
96
|
def valid_date_time?(data)
|
data/lib/json_schemer/keyword.rb
CHANGED
@@ -45,8 +45,11 @@ module JSONSchemer
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def subschema(value, keyword = nil, **options)
|
48
|
+
options[:configuration] ||= schema.configuration
|
48
49
|
options[:base_uri] ||= schema.base_uri
|
49
50
|
options[:meta_schema] ||= schema.meta_schema
|
51
|
+
options[:ref_resolver] ||= schema.ref_resolver
|
52
|
+
options[:regexp_resolver] ||= schema.regexp_resolver
|
50
53
|
Schema.new(value, self, root, keyword, **options)
|
51
54
|
end
|
52
55
|
end
|
data/lib/json_schemer/openapi.rb
CHANGED
@@ -8,16 +8,14 @@ module JSONSchemer
|
|
8
8
|
case version
|
9
9
|
when /\A3\.1\.\d+\z/
|
10
10
|
@document_schema = JSONSchemer.openapi31_document
|
11
|
-
|
11
|
+
meta_schema = document.fetch('jsonSchemaDialect') { OpenAPI31::BASE_URI.to_s }
|
12
12
|
when /\A3\.0\.\d+\z/
|
13
13
|
@document_schema = JSONSchemer.openapi30_document
|
14
|
-
|
14
|
+
meta_schema = OpenAPI30::BASE_URI.to_s
|
15
15
|
else
|
16
16
|
raise UnsupportedOpenAPIVersion, version
|
17
17
|
end
|
18
18
|
|
19
|
-
meta_schema = META_SCHEMAS_BY_BASE_URI_STR[json_schema_dialect] || raise(UnsupportedMetaSchema, json_schema_dialect)
|
20
|
-
|
21
19
|
@schema = JSONSchemer.schema(@document, :meta_schema => meta_schema, **options)
|
22
20
|
end
|
23
21
|
|
@@ -5,7 +5,7 @@ module JSONSchemer
|
|
5
5
|
# https://spec.openapis.org/oas/v3.0.3#data-types
|
6
6
|
FORMATS = OpenAPI31::FORMATS.merge(
|
7
7
|
'byte' => proc { |instance, _value| ContentEncoding::BASE64.call(instance).first },
|
8
|
-
'binary' => proc { |instance, _value| instance.is_a?(String) && instance.encoding == Encoding::
|
8
|
+
'binary' => proc { |instance, _value| instance.is_a?(String) && instance.encoding == Encoding::BINARY },
|
9
9
|
'date' => Format::DATE
|
10
10
|
)
|
11
11
|
SCHEMA = {
|
data/lib/json_schemer/result.rb
CHANGED
@@ -201,8 +201,8 @@ module JSONSchemer
|
|
201
201
|
|
202
202
|
if result.source.is_a?(Schema::PROPERTIES_KEYWORD_CLASS) && result.instance.is_a?(Hash)
|
203
203
|
result.source.parsed.each do |property, schema|
|
204
|
-
next if result.instance.key?(property)
|
205
|
-
default = schema
|
204
|
+
next if result.instance.key?(property)
|
205
|
+
next unless default = default_keyword_instance(schema)
|
206
206
|
instance_location = Location.join(result.instance_location, property)
|
207
207
|
keyword_location = Location.join(Location.join(result.keyword_location, property), default.keyword)
|
208
208
|
default_result = default.validate(nil, instance_location, keyword_location, nil)
|
@@ -225,5 +225,17 @@ module JSONSchemer
|
|
225
225
|
|
226
226
|
inserted
|
227
227
|
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
def default_keyword_instance(schema)
|
232
|
+
schema.parsed.fetch('default') do
|
233
|
+
schema.parsed.find do |_keyword, keyword_instance|
|
234
|
+
next unless keyword_instance.respond_to?(:ref_schema)
|
235
|
+
next unless default = default_keyword_instance(keyword_instance.ref_schema)
|
236
|
+
break default
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
228
240
|
end
|
229
241
|
end
|
data/lib/json_schemer/schema.rb
CHANGED
@@ -4,28 +4,26 @@ module JSONSchemer
|
|
4
4
|
Context = Struct.new(:instance, :dynamic_scope, :adjacent_results, :short_circuit, :access_mode) do
|
5
5
|
def original_instance(instance_location)
|
6
6
|
Hana::Pointer.parse(Location.resolve(instance_location)).reduce(instance) do |obj, token|
|
7
|
-
obj.
|
7
|
+
if obj.is_a?(Array)
|
8
|
+
obj.fetch(token.to_i)
|
9
|
+
elsif !obj.key?(token) && obj.key?(token.to_sym)
|
10
|
+
obj.fetch(token.to_sym)
|
11
|
+
else
|
12
|
+
obj.fetch(token)
|
13
|
+
end
|
8
14
|
end
|
9
15
|
end
|
10
16
|
end
|
11
17
|
|
12
18
|
include Output
|
13
19
|
|
14
|
-
DEFAULT_SCHEMA = Draft202012::BASE_URI.to_s.freeze
|
15
20
|
SCHEMA_KEYWORD_CLASS = Draft202012::Vocab::Core::Schema
|
16
21
|
VOCABULARY_KEYWORD_CLASS = Draft202012::Vocab::Core::Vocabulary
|
17
22
|
ID_KEYWORD_CLASS = Draft202012::Vocab::Core::Id
|
18
23
|
UNKNOWN_KEYWORD_CLASS = Draft202012::Vocab::Core::UnknownKeyword
|
19
24
|
NOT_KEYWORD_CLASS = Draft202012::Vocab::Applicator::Not
|
20
25
|
PROPERTIES_KEYWORD_CLASS = Draft202012::Vocab::Applicator::Properties
|
21
|
-
|
22
|
-
DEFAULT_FORMATS = {}.freeze
|
23
|
-
DEFAULT_CONTENT_ENCODINGS = {}.freeze
|
24
|
-
DEFAULT_CONTENT_MEDIA_TYPES = {}.freeze
|
25
|
-
DEFAULT_KEYWORDS = {}.freeze
|
26
|
-
DEFAULT_BEFORE_PROPERTY_VALIDATION = [].freeze
|
27
|
-
DEFAULT_AFTER_PROPERTY_VALIDATION = [].freeze
|
28
|
-
DEFAULT_REF_RESOLVER = proc { |uri| raise UnknownRef, uri.to_s }
|
26
|
+
|
29
27
|
NET_HTTP_REF_RESOLVER = proc { |uri| JSON.parse(Net::HTTP.get(uri)) }
|
30
28
|
RUBY_REGEXP_RESOLVER = proc { |pattern| Regexp.new(pattern) }
|
31
29
|
ECMA_REGEXP_RESOLVER = proc { |pattern| Regexp.new(EcmaRegexp.ruby_equivalent(pattern)) }
|
@@ -40,39 +38,44 @@ module JSONSchemer
|
|
40
38
|
false
|
41
39
|
end
|
42
40
|
end
|
41
|
+
SYMBOL_PROPERTY_DEFAULT_RESOLVER = proc do |instance, property, results_with_tree_validity|
|
42
|
+
DEFAULT_PROPERTY_DEFAULT_RESOLVER.call(instance, property.to_sym, results_with_tree_validity)
|
43
|
+
end
|
43
44
|
|
44
45
|
attr_accessor :base_uri, :meta_schema, :keywords, :keyword_order
|
45
|
-
attr_reader :value, :parent, :root, :parsed
|
46
|
-
attr_reader :vocabulary, :format, :formats, :content_encodings, :content_media_types, :custom_keywords, :before_property_validation, :after_property_validation, :insert_property_defaults
|
46
|
+
attr_reader :value, :parent, :root, :configuration, :parsed
|
47
|
+
attr_reader :vocabulary, :format, :formats, :content_encodings, :content_media_types, :custom_keywords, :before_property_validation, :after_property_validation, :insert_property_defaults
|
47
48
|
|
48
49
|
def initialize(
|
49
50
|
value,
|
50
51
|
parent = nil,
|
51
52
|
root = self,
|
52
53
|
keyword = nil,
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
54
|
+
configuration: JSONSchemer.configuration,
|
55
|
+
base_uri: configuration.base_uri,
|
56
|
+
meta_schema: configuration.meta_schema,
|
57
|
+
vocabulary: configuration.vocabulary,
|
58
|
+
format: configuration.format,
|
59
|
+
formats: configuration.formats,
|
60
|
+
content_encodings: configuration.content_encodings,
|
61
|
+
content_media_types: configuration.content_media_types,
|
62
|
+
keywords: configuration.keywords,
|
63
|
+
before_property_validation: configuration.before_property_validation,
|
64
|
+
after_property_validation: configuration.after_property_validation,
|
65
|
+
insert_property_defaults: configuration.insert_property_defaults,
|
66
|
+
property_default_resolver: configuration.property_default_resolver,
|
67
|
+
ref_resolver: configuration.ref_resolver,
|
68
|
+
regexp_resolver: configuration.regexp_resolver,
|
69
|
+
output_format: configuration.output_format,
|
70
|
+
resolve_enumerators: configuration.resolve_enumerators,
|
71
|
+
access_mode: configuration.access_mode
|
70
72
|
)
|
71
73
|
@value = deep_stringify_keys(value)
|
72
74
|
@parent = parent
|
73
75
|
@root = root
|
74
76
|
@keyword = keyword
|
75
77
|
@schema = self
|
78
|
+
@configuration = configuration
|
76
79
|
@base_uri = base_uri
|
77
80
|
@meta_schema = meta_schema
|
78
81
|
@vocabulary = vocabulary
|
@@ -109,12 +112,12 @@ module JSONSchemer
|
|
109
112
|
output
|
110
113
|
end
|
111
114
|
|
112
|
-
def valid_schema?
|
113
|
-
meta_schema.valid?(value)
|
115
|
+
def valid_schema?(**options)
|
116
|
+
meta_schema.valid?(value, **options)
|
114
117
|
end
|
115
118
|
|
116
|
-
def validate_schema
|
117
|
-
meta_schema.validate(value)
|
119
|
+
def validate_schema(**options)
|
120
|
+
meta_schema.validate(value, **options)
|
118
121
|
end
|
119
122
|
|
120
123
|
def ref(value)
|
@@ -142,10 +145,11 @@ module JSONSchemer
|
|
142
145
|
adjacent_results[keyword_instance.class] = keyword_result
|
143
146
|
end
|
144
147
|
|
145
|
-
if custom_keywords.any?
|
146
|
-
|
148
|
+
if root.custom_keywords.any?
|
149
|
+
resolved_instance_location = Location.resolve(instance_location)
|
150
|
+
root.custom_keywords.each do |custom_keyword, callable|
|
147
151
|
if value.key?(custom_keyword)
|
148
|
-
[*callable.call(instance, value,
|
152
|
+
[*callable.call(instance, value, resolved_instance_location)].each do |custom_keyword_result|
|
149
153
|
custom_keyword_valid = custom_keyword_result == true
|
150
154
|
valid &&= custom_keyword_valid
|
151
155
|
type = custom_keyword_result.is_a?(String) ? custom_keyword_result : custom_keyword
|
@@ -184,16 +188,9 @@ module JSONSchemer
|
|
184
188
|
uri.fragment = nil
|
185
189
|
remote_schema = JSONSchemer.schema(
|
186
190
|
ref_resolver.call(uri) || raise(InvalidRefResolution, uri.to_s),
|
191
|
+
:configuration => configuration,
|
187
192
|
:base_uri => uri,
|
188
193
|
:meta_schema => meta_schema,
|
189
|
-
:format => format,
|
190
|
-
:formats => formats,
|
191
|
-
:content_encodings => content_encodings,
|
192
|
-
:content_media_types => content_media_types,
|
193
|
-
:keywords => custom_keywords,
|
194
|
-
:before_property_validation => before_property_validation,
|
195
|
-
:after_property_validation => after_property_validation,
|
196
|
-
:property_default_resolver => property_default_resolver,
|
197
194
|
:ref_resolver => ref_resolver,
|
198
195
|
:regexp_resolver => regexp_resolver
|
199
196
|
)
|
@@ -342,6 +339,21 @@ module JSONSchemer
|
|
342
339
|
end
|
343
340
|
end
|
344
341
|
|
342
|
+
def ref_resolver
|
343
|
+
@ref_resolver ||= @original_ref_resolver == 'net/http' ? CachedResolver.new(&NET_HTTP_REF_RESOLVER) : @original_ref_resolver
|
344
|
+
end
|
345
|
+
|
346
|
+
def regexp_resolver
|
347
|
+
@regexp_resolver ||= case @original_regexp_resolver
|
348
|
+
when 'ecma'
|
349
|
+
CachedResolver.new(&ECMA_REGEXP_RESOLVER)
|
350
|
+
when 'ruby'
|
351
|
+
CachedResolver.new(&RUBY_REGEXP_RESOLVER)
|
352
|
+
else
|
353
|
+
@original_regexp_resolver
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
345
357
|
def inspect
|
346
358
|
"#<#{self.class.name} @value=#{@value.inspect} @parent=#{@parent.inspect} @keyword=#{@keyword.inspect}>"
|
347
359
|
end
|
@@ -353,8 +365,8 @@ module JSONSchemer
|
|
353
365
|
|
354
366
|
if value.is_a?(Hash) && value.key?('$schema')
|
355
367
|
@parsed['$schema'] = SCHEMA_KEYWORD_CLASS.new(value.fetch('$schema'), self, '$schema')
|
356
|
-
elsif
|
357
|
-
SCHEMA_KEYWORD_CLASS.new(
|
368
|
+
elsif meta_schema.is_a?(String)
|
369
|
+
SCHEMA_KEYWORD_CLASS.new(meta_schema, self, '$schema')
|
358
370
|
end
|
359
371
|
|
360
372
|
if value.is_a?(Hash) && value.key?('$vocabulary')
|
@@ -394,19 +406,8 @@ module JSONSchemer
|
|
394
406
|
@root_keyword_location ||= Location.root
|
395
407
|
end
|
396
408
|
|
397
|
-
def
|
398
|
-
@
|
399
|
-
end
|
400
|
-
|
401
|
-
def regexp_resolver
|
402
|
-
@regexp_resolver ||= case @original_regexp_resolver
|
403
|
-
when 'ecma'
|
404
|
-
CachedResolver.new(&ECMA_REGEXP_RESOLVER)
|
405
|
-
when 'ruby'
|
406
|
-
CachedResolver.new(&RUBY_REGEXP_RESOLVER)
|
407
|
-
else
|
408
|
-
@original_regexp_resolver
|
409
|
-
end
|
409
|
+
def property_default_resolver
|
410
|
+
@property_default_resolver ||= insert_property_defaults == :symbol ? SYMBOL_PROPERTY_DEFAULT_RESOLVER : DEFAULT_PROPERTY_DEFAULT_RESOLVER
|
410
411
|
end
|
411
412
|
|
412
413
|
def resolve_enumerators!(output)
|
data/lib/json_schemer/version.rb
CHANGED
data/lib/json_schemer.rb
CHANGED
@@ -59,10 +59,10 @@ require 'json_schemer/openapi30/meta'
|
|
59
59
|
require 'json_schemer/openapi30/vocab/base'
|
60
60
|
require 'json_schemer/openapi30/vocab'
|
61
61
|
require 'json_schemer/openapi'
|
62
|
+
require 'json_schemer/configuration'
|
62
63
|
require 'json_schemer/schema'
|
63
64
|
|
64
65
|
module JSONSchemer
|
65
|
-
class UnsupportedMetaSchema < StandardError; end
|
66
66
|
class UnsupportedOpenAPIVersion < StandardError; end
|
67
67
|
class UnknownRef < StandardError; end
|
68
68
|
class UnknownFormat < StandardError; end
|
@@ -113,33 +113,19 @@ module JSONSchemer
|
|
113
113
|
end
|
114
114
|
|
115
115
|
class << self
|
116
|
-
def schema(schema,
|
117
|
-
|
118
|
-
|
119
|
-
schema = JSON.parse(schema)
|
120
|
-
when Pathname
|
121
|
-
base_uri = URI.parse(File.join('file:', URI::DEFAULT_PARSER.escape(schema.realpath.to_s)))
|
122
|
-
options[:base_uri] = base_uri
|
123
|
-
schema = if options.key?(:ref_resolver)
|
124
|
-
FILE_URI_REF_RESOLVER.call(base_uri)
|
125
|
-
else
|
126
|
-
ref_resolver = CachedResolver.new(&FILE_URI_REF_RESOLVER)
|
127
|
-
options[:ref_resolver] = ref_resolver
|
128
|
-
ref_resolver.call(base_uri)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
unless meta_schema.is_a?(Schema)
|
132
|
-
meta_schema = META_SCHEMAS_BY_BASE_URI_STR[meta_schema] || raise(UnsupportedMetaSchema, meta_schema)
|
133
|
-
end
|
134
|
-
Schema.new(schema, :meta_schema => meta_schema, **options)
|
116
|
+
def schema(schema, **options)
|
117
|
+
schema = resolve(schema, options)
|
118
|
+
Schema.new(schema, **options)
|
135
119
|
end
|
136
120
|
|
137
121
|
def valid_schema?(schema, **options)
|
138
|
-
schema(schema,
|
122
|
+
schema = resolve(schema, options)
|
123
|
+
meta_schema(schema, options).valid?(schema, **options.slice(:output_format, :resolve_enumerators, :access_mode))
|
139
124
|
end
|
140
125
|
|
141
126
|
def validate_schema(schema, **options)
|
142
|
-
schema(schema,
|
127
|
+
schema = resolve(schema, options)
|
128
|
+
meta_schema(schema, options).validate(schema, **options.slice(:output_format, :resolve_enumerators, :access_mode))
|
143
129
|
end
|
144
130
|
|
145
131
|
def draft202012
|
@@ -245,6 +231,44 @@ module JSONSchemer
|
|
245
231
|
def openapi(document, **options)
|
246
232
|
OpenAPI.new(document, **options)
|
247
233
|
end
|
234
|
+
|
235
|
+
def configuration
|
236
|
+
@configuration ||= Configuration.new
|
237
|
+
end
|
238
|
+
|
239
|
+
def configure
|
240
|
+
yield configuration
|
241
|
+
end
|
242
|
+
|
243
|
+
private
|
244
|
+
|
245
|
+
def resolve(schema, options)
|
246
|
+
case schema
|
247
|
+
when String
|
248
|
+
JSON.parse(schema)
|
249
|
+
when Pathname
|
250
|
+
base_uri = URI.parse(File.join('file:', URI::DEFAULT_PARSER.escape(schema.realpath.to_s)))
|
251
|
+
options[:base_uri] = base_uri
|
252
|
+
if options.key?(:ref_resolver)
|
253
|
+
FILE_URI_REF_RESOLVER.call(base_uri)
|
254
|
+
else
|
255
|
+
ref_resolver = CachedResolver.new(&FILE_URI_REF_RESOLVER)
|
256
|
+
options[:ref_resolver] = ref_resolver
|
257
|
+
ref_resolver.call(base_uri)
|
258
|
+
end
|
259
|
+
else
|
260
|
+
schema
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def meta_schema(schema, options)
|
265
|
+
parseable_schema = {}
|
266
|
+
if schema.is_a?(Hash)
|
267
|
+
meta_schema = schema['$schema'] || schema[:'$schema']
|
268
|
+
parseable_schema['$schema'] = meta_schema if meta_schema.is_a?(String)
|
269
|
+
end
|
270
|
+
schema(parseable_schema, **options).meta_schema
|
271
|
+
end
|
248
272
|
end
|
249
273
|
|
250
274
|
META_SCHEMA_CALLABLES_BY_BASE_URI_STR = {
|
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.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:
|
11
|
+
date: 2024-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.22'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: csv
|
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'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: i18n
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +108,34 @@ dependencies:
|
|
94
108
|
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: base64
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: bigdecimal
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
97
139
|
- !ruby/object:Gem::Dependency
|
98
140
|
name: hana
|
99
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -160,6 +202,7 @@ files:
|
|
160
202
|
- json_schemer.gemspec
|
161
203
|
- lib/json_schemer.rb
|
162
204
|
- lib/json_schemer/cached_resolver.rb
|
205
|
+
- lib/json_schemer/configuration.rb
|
163
206
|
- lib/json_schemer/content.rb
|
164
207
|
- lib/json_schemer/draft201909/meta.rb
|
165
208
|
- lib/json_schemer/draft201909/vocab.rb
|
@@ -225,7 +268,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
225
268
|
- !ruby/object:Gem::Version
|
226
269
|
version: '0'
|
227
270
|
requirements: []
|
228
|
-
rubygems_version: 3.
|
271
|
+
rubygems_version: 3.5.3
|
229
272
|
signing_key:
|
230
273
|
specification_version: 4
|
231
274
|
summary: JSON Schema validator. Supports drafts 4, 6, 7, 2019-09, 2020-12, OpenAPI
|