jsi-dev 0.0.8 → 0.0.9
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/.yardopts +3 -4
- data/CHANGELOG.md +19 -0
- data/LICENSE.md +2 -3
- data/README.md +87 -43
- data/docs/{glossary.md → Glossary.md} +84 -52
- data/jsi.gemspec +1 -1
- data/lib/jsi/base/mutability.rb +48 -0
- data/lib/jsi/base/node.rb +66 -52
- data/lib/jsi/base.rb +592 -176
- data/lib/jsi/jsi_coder.rb +4 -2
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +118 -59
- data/lib/jsi/metaschema_node.rb +244 -154
- data/lib/jsi/ptr.rb +45 -17
- data/lib/jsi/ref.rb +197 -0
- data/lib/jsi/registry.rb +311 -0
- data/lib/jsi/schema/cxt/child_application.rb +35 -0
- data/lib/jsi/schema/cxt/inplace_application.rb +37 -0
- data/lib/jsi/schema/cxt.rb +80 -0
- data/lib/jsi/schema/dialect.rb +137 -0
- data/lib/jsi/schema/draft04.rb +113 -5
- data/lib/jsi/schema/draft06.rb +123 -5
- data/lib/jsi/schema/draft07.rb +157 -5
- data/lib/jsi/schema/draft202012.rb +303 -0
- data/lib/jsi/schema/dynamic_anchor_map.rb +63 -0
- data/lib/jsi/schema/element.rb +69 -0
- data/lib/jsi/schema/elements/anchor.rb +13 -0
- data/lib/jsi/schema/elements/array_validation.rb +82 -0
- data/lib/jsi/schema/elements/comment.rb +10 -0
- data/lib/jsi/schema/{validation → elements}/const.rb +11 -7
- data/lib/jsi/schema/elements/contains.rb +59 -0
- data/lib/jsi/schema/elements/contains_minmax.rb +91 -0
- data/lib/jsi/schema/elements/content_encoding.rb +10 -0
- data/lib/jsi/schema/elements/content_media_type.rb +10 -0
- data/lib/jsi/schema/elements/content_schema.rb +16 -0
- data/lib/jsi/schema/elements/default.rb +11 -0
- data/lib/jsi/schema/elements/definitions.rb +19 -0
- data/lib/jsi/schema/elements/dependencies.rb +99 -0
- data/lib/jsi/schema/elements/dependent_required.rb +49 -0
- data/lib/jsi/schema/elements/dependent_schemas.rb +69 -0
- data/lib/jsi/schema/elements/dynamic_ref.rb +69 -0
- data/lib/jsi/schema/elements/enum.rb +26 -0
- data/lib/jsi/schema/elements/examples.rb +10 -0
- data/lib/jsi/schema/elements/format.rb +10 -0
- data/lib/jsi/schema/elements/id.rb +30 -0
- data/lib/jsi/schema/elements/if_then_else.rb +82 -0
- data/lib/jsi/schema/elements/info_bool.rb +10 -0
- data/lib/jsi/schema/elements/info_string.rb +10 -0
- data/lib/jsi/schema/elements/items.rb +93 -0
- data/lib/jsi/schema/elements/items_prefixed.rb +96 -0
- data/lib/jsi/schema/elements/not.rb +31 -0
- data/lib/jsi/schema/elements/numeric.rb +137 -0
- data/lib/jsi/schema/elements/numeric_draft04.rb +77 -0
- data/lib/jsi/schema/elements/object_validation.rb +55 -0
- data/lib/jsi/schema/elements/pattern.rb +35 -0
- data/lib/jsi/schema/elements/properties.rb +145 -0
- data/lib/jsi/schema/elements/property_names.rb +48 -0
- data/lib/jsi/schema/elements/ref.rb +62 -0
- data/lib/jsi/schema/elements/required.rb +34 -0
- data/lib/jsi/schema/elements/self.rb +24 -0
- data/lib/jsi/schema/elements/some_of.rb +180 -0
- data/lib/jsi/schema/elements/string_validation.rb +57 -0
- data/lib/jsi/schema/elements/type.rb +43 -0
- data/lib/jsi/schema/elements/unevaluated_items.rb +54 -0
- data/lib/jsi/schema/elements/unevaluated_properties.rb +54 -0
- data/lib/jsi/schema/elements/xschema.rb +10 -0
- data/lib/jsi/schema/elements/xvocabulary.rb +10 -0
- data/lib/jsi/schema/elements.rb +101 -0
- data/lib/jsi/schema/issue.rb +3 -4
- data/lib/jsi/schema/schema_ancestor_node.rb +105 -52
- data/lib/jsi/schema/vocabulary.rb +36 -0
- data/lib/jsi/schema.rb +598 -383
- data/lib/jsi/schema_classes.rb +195 -141
- data/lib/jsi/schema_set.rb +85 -128
- data/lib/jsi/set.rb +23 -0
- data/lib/jsi/simple_wrap.rb +14 -17
- data/lib/jsi/struct.rb +57 -0
- data/lib/jsi/uri.rb +40 -0
- data/lib/jsi/util/private/memo_map.rb +9 -13
- data/lib/jsi/util/private.rb +59 -31
- data/lib/jsi/util/typelike.rb +19 -60
- data/lib/jsi/util.rb +53 -34
- data/lib/jsi/validation/error.rb +45 -2
- data/lib/jsi/validation/result.rb +121 -90
- data/lib/jsi/validation.rb +1 -6
- data/lib/jsi/version.rb +1 -1
- data/lib/jsi.rb +170 -36
- data/lib/schemas/json-schema.org/draft/2020-12/schema.rb +62 -0
- data/lib/schemas/json-schema.org/draft-04/schema.rb +60 -109
- data/lib/schemas/json-schema.org/draft-06/schema.rb +53 -108
- data/lib/schemas/json-schema.org/draft-07/schema.rb +63 -127
- data/readme.rb +4 -4
- data/{resources}/schemas/2020-12_strict.json +19 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/applicator.json +48 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/content.json +17 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/core.json +51 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-annotation.json +14 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-assertion.json +14 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/meta-data.json +37 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/unevaluated.json +15 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/validation.json +98 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/schema.json +58 -0
- metadata +73 -52
- data/lib/jsi/metaschema.rb +0 -6
- data/lib/jsi/schema/application/child_application/contains.rb +0 -25
- data/lib/jsi/schema/application/child_application/draft04.rb +0 -21
- data/lib/jsi/schema/application/child_application/draft06.rb +0 -28
- data/lib/jsi/schema/application/child_application/draft07.rb +0 -28
- data/lib/jsi/schema/application/child_application/items.rb +0 -18
- data/lib/jsi/schema/application/child_application/properties.rb +0 -25
- data/lib/jsi/schema/application/child_application.rb +0 -13
- data/lib/jsi/schema/application/draft04.rb +0 -8
- data/lib/jsi/schema/application/draft06.rb +0 -8
- data/lib/jsi/schema/application/draft07.rb +0 -8
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +0 -28
- data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -25
- data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -26
- data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -32
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +0 -20
- data/lib/jsi/schema/application/inplace_application/ref.rb +0 -18
- data/lib/jsi/schema/application/inplace_application/someof.rb +0 -44
- data/lib/jsi/schema/application/inplace_application.rb +0 -14
- data/lib/jsi/schema/application.rb +0 -12
- data/lib/jsi/schema/ref.rb +0 -183
- data/lib/jsi/schema/validation/array.rb +0 -69
- data/lib/jsi/schema/validation/contains.rb +0 -25
- data/lib/jsi/schema/validation/dependencies.rb +0 -49
- data/lib/jsi/schema/validation/draft04/minmax.rb +0 -91
- data/lib/jsi/schema/validation/draft04.rb +0 -110
- data/lib/jsi/schema/validation/draft06.rb +0 -120
- data/lib/jsi/schema/validation/draft07.rb +0 -157
- data/lib/jsi/schema/validation/enum.rb +0 -25
- data/lib/jsi/schema/validation/ifthenelse.rb +0 -46
- data/lib/jsi/schema/validation/items.rb +0 -54
- data/lib/jsi/schema/validation/not.rb +0 -20
- data/lib/jsi/schema/validation/numeric.rb +0 -121
- data/lib/jsi/schema/validation/object.rb +0 -45
- data/lib/jsi/schema/validation/pattern.rb +0 -34
- data/lib/jsi/schema/validation/properties.rb +0 -101
- data/lib/jsi/schema/validation/property_names.rb +0 -32
- data/lib/jsi/schema/validation/ref.rb +0 -40
- data/lib/jsi/schema/validation/required.rb +0 -27
- data/lib/jsi/schema/validation/someof.rb +0 -90
- data/lib/jsi/schema/validation/string.rb +0 -47
- data/lib/jsi/schema/validation/type.rb +0 -49
- data/lib/jsi/schema/validation.rb +0 -49
- data/lib/jsi/schema_registry.rb +0 -190
- data/lib/jsi/util/private/attr_struct.rb +0 -130
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Application::ChildApplication
|
|
5
|
-
autoload :Draft04, 'jsi/schema/application/child_application/draft04'
|
|
6
|
-
autoload :Draft06, 'jsi/schema/application/child_application/draft06'
|
|
7
|
-
autoload :Draft07, 'jsi/schema/application/child_application/draft07'
|
|
8
|
-
|
|
9
|
-
autoload :Items, 'jsi/schema/application/child_application/items'
|
|
10
|
-
autoload :Contains, 'jsi/schema/application/child_application/contains'
|
|
11
|
-
autoload :Properties, 'jsi/schema/application/child_application/properties'
|
|
12
|
-
end
|
|
13
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Application::InplaceApplication::Dependencies
|
|
5
|
-
# @private
|
|
6
|
-
def internal_applicate_dependencies(instance, visited_refs, &block)
|
|
7
|
-
if keyword?('dependencies')
|
|
8
|
-
value = schema_content['dependencies']
|
|
9
|
-
# This keyword's value MUST be an object. Each property specifies a dependency. Each dependency
|
|
10
|
-
# value MUST be an array or a valid JSON Schema.
|
|
11
|
-
if value.respond_to?(:to_hash)
|
|
12
|
-
value.each_pair do |property_name, dependency|
|
|
13
|
-
if dependency.respond_to?(:to_ary)
|
|
14
|
-
# noop: array-form dependencies has no inplace applicator schema
|
|
15
|
-
else
|
|
16
|
-
# If the dependency value is a subschema, and the dependency key is a
|
|
17
|
-
# property in the instance, the entire instance must validate against
|
|
18
|
-
# the dependency value.
|
|
19
|
-
if instance.respond_to?(:to_hash) && instance.key?(property_name)
|
|
20
|
-
subschema(['dependencies', property_name]).each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Application::InplaceApplication::Draft04
|
|
5
|
-
include Schema::Application::InplaceApplication::Ref
|
|
6
|
-
include Schema::Application::InplaceApplication::Dependencies
|
|
7
|
-
include Schema::Application::InplaceApplication::SomeOf
|
|
8
|
-
|
|
9
|
-
# @private
|
|
10
|
-
def internal_inplace_applicate_keywords(instance, visited_refs, &block)
|
|
11
|
-
internal_applicate_ref(instance, visited_refs, throw_done: true, &block)
|
|
12
|
-
|
|
13
|
-
# self is the first applicator schema if $ref has not short-circuited it
|
|
14
|
-
yield self
|
|
15
|
-
|
|
16
|
-
# 5.4.5. dependencies
|
|
17
|
-
internal_applicate_dependencies(instance, visited_refs, &block)
|
|
18
|
-
|
|
19
|
-
# 5.5.3. allOf
|
|
20
|
-
# 5.5.4. anyOf
|
|
21
|
-
# 5.5.5. oneOf
|
|
22
|
-
internal_applicate_someOf(instance, visited_refs, &block)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Application::InplaceApplication::Draft06
|
|
5
|
-
include Schema::Application::InplaceApplication::Ref
|
|
6
|
-
include Schema::Application::InplaceApplication::Dependencies
|
|
7
|
-
include Schema::Application::InplaceApplication::SomeOf
|
|
8
|
-
|
|
9
|
-
# @private
|
|
10
|
-
def internal_inplace_applicate_keywords(instance, visited_refs, &block)
|
|
11
|
-
# json-schema 8. Schema references with $ref
|
|
12
|
-
internal_applicate_ref(instance, visited_refs, throw_done: true, &block)
|
|
13
|
-
|
|
14
|
-
# self is the first applicator schema if $ref has not short-circuited it
|
|
15
|
-
yield self
|
|
16
|
-
|
|
17
|
-
# json-schema-validation 6.21. dependencies
|
|
18
|
-
internal_applicate_dependencies(instance, visited_refs, &block)
|
|
19
|
-
|
|
20
|
-
# json-schema-validation 6.26. allOf
|
|
21
|
-
# json-schema-validation 6.27. anyOf
|
|
22
|
-
# json-schema-validation 6.28. oneOf
|
|
23
|
-
internal_applicate_someOf(instance, visited_refs, &block)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Application::InplaceApplication::Draft07
|
|
5
|
-
include Schema::Application::InplaceApplication::Ref
|
|
6
|
-
include Schema::Application::InplaceApplication::Dependencies
|
|
7
|
-
include Schema::Application::InplaceApplication::IfThenElse
|
|
8
|
-
include Schema::Application::InplaceApplication::SomeOf
|
|
9
|
-
|
|
10
|
-
# @private
|
|
11
|
-
def internal_inplace_applicate_keywords(instance, visited_refs, &block)
|
|
12
|
-
# json-schema 8. Schema references with $ref
|
|
13
|
-
internal_applicate_ref(instance, visited_refs, throw_done: true, &block)
|
|
14
|
-
|
|
15
|
-
# self is the first applicator schema if $ref has not short-circuited it
|
|
16
|
-
block.call(self)
|
|
17
|
-
|
|
18
|
-
# 6.5.7. dependencies
|
|
19
|
-
internal_applicate_dependencies(instance, visited_refs, &block)
|
|
20
|
-
|
|
21
|
-
# 6.6.1. if
|
|
22
|
-
# 6.6.2. then
|
|
23
|
-
# 6.6.3. else
|
|
24
|
-
internal_applicate_ifthenelse(instance, visited_refs, &block)
|
|
25
|
-
|
|
26
|
-
# 6.7.1. allOf
|
|
27
|
-
# 6.7.2. anyOf
|
|
28
|
-
# 6.7.3. oneOf
|
|
29
|
-
internal_applicate_someOf(instance, visited_refs, &block)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Application::InplaceApplication::IfThenElse
|
|
5
|
-
# @private
|
|
6
|
-
def internal_applicate_ifthenelse(instance, visited_refs, &block)
|
|
7
|
-
if keyword?('if')
|
|
8
|
-
if subschema(['if']).instance_valid?(instance)
|
|
9
|
-
if keyword?('then')
|
|
10
|
-
subschema(['then']).each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
|
11
|
-
end
|
|
12
|
-
else
|
|
13
|
-
if keyword?('else')
|
|
14
|
-
subschema(['else']).each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Application::InplaceApplication::Ref
|
|
5
|
-
# @private
|
|
6
|
-
def internal_applicate_ref(instance, visited_refs, throw_done: false, &block)
|
|
7
|
-
if keyword?('$ref') && schema_content['$ref'].respond_to?(:to_str)
|
|
8
|
-
ref = schema_ref
|
|
9
|
-
unless visited_refs.include?(ref)
|
|
10
|
-
ref.deref_schema.each_inplace_applicator_schema(instance, visited_refs: visited_refs + [ref], &block)
|
|
11
|
-
if throw_done
|
|
12
|
-
throw(:jsi_application_done)
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Application::InplaceApplication::SomeOf
|
|
5
|
-
# @private
|
|
6
|
-
def internal_applicate_someOf(instance, visited_refs, &block)
|
|
7
|
-
if keyword?('allOf') && schema_content['allOf'].respond_to?(:to_ary)
|
|
8
|
-
schema_content['allOf'].each_index do |i|
|
|
9
|
-
subschema(['allOf', i]).each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
if keyword?('anyOf') && schema_content['anyOf'].respond_to?(:to_ary)
|
|
13
|
-
anyOf = schema_content['anyOf'].each_index.map { |i| subschema(['anyOf', i]) }
|
|
14
|
-
validOf = anyOf.select { |schema| schema.instance_valid?(instance) }
|
|
15
|
-
if !validOf.empty?
|
|
16
|
-
applicators = validOf
|
|
17
|
-
else
|
|
18
|
-
# invalid application: if none of the anyOf were valid, we apply them all
|
|
19
|
-
applicators = anyOf
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
applicators.each do |applicator|
|
|
23
|
-
applicator.each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
if keyword?('oneOf') && schema_content['oneOf'].respond_to?(:to_ary)
|
|
27
|
-
oneOf_idxs = schema_content['oneOf'].each_index
|
|
28
|
-
subschema_idx_valid = Hash.new { |h, i| h[i] = subschema(['oneOf', i]).instance_valid?(instance) }
|
|
29
|
-
# count up to 2 `oneOf` subschemas which `instance` validates against
|
|
30
|
-
nvalid = oneOf_idxs.inject(0) { |n, i| n > 1 ? n : subschema_idx_valid[i] ? n + 1 : n }
|
|
31
|
-
if nvalid == 1
|
|
32
|
-
applicator_idxs = oneOf_idxs.select { |i| subschema_idx_valid[i] }
|
|
33
|
-
else
|
|
34
|
-
# invalid application: if none or multiple of the oneOf were valid, we apply them all
|
|
35
|
-
applicator_idxs = oneOf_idxs
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
applicator_idxs.each do |i|
|
|
39
|
-
subschema(['oneOf', i]).each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Application::InplaceApplication
|
|
5
|
-
autoload :Draft04, 'jsi/schema/application/inplace_application/draft04'
|
|
6
|
-
autoload :Draft06, 'jsi/schema/application/inplace_application/draft06'
|
|
7
|
-
autoload :Draft07, 'jsi/schema/application/inplace_application/draft07'
|
|
8
|
-
|
|
9
|
-
autoload :Ref, 'jsi/schema/application/inplace_application/ref'
|
|
10
|
-
autoload :SomeOf, 'jsi/schema/application/inplace_application/someof'
|
|
11
|
-
autoload :IfThenElse, 'jsi/schema/application/inplace_application/ifthenelse'
|
|
12
|
-
autoload :Dependencies, 'jsi/schema/application/inplace_application/dependencies'
|
|
13
|
-
end
|
|
14
|
-
end
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Application
|
|
5
|
-
autoload :InplaceApplication, 'jsi/schema/application/inplace_application'
|
|
6
|
-
autoload :ChildApplication, 'jsi/schema/application/child_application'
|
|
7
|
-
|
|
8
|
-
autoload :Draft04, 'jsi/schema/application/draft04'
|
|
9
|
-
autoload :Draft06, 'jsi/schema/application/draft06'
|
|
10
|
-
autoload :Draft07, 'jsi/schema/application/draft07'
|
|
11
|
-
end
|
|
12
|
-
end
|
data/lib/jsi/schema/ref.rb
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
# A JSI::Schema::Ref is a reference to a schema identified by a URI, typically from
|
|
5
|
-
# a `$ref` keyword of a schema.
|
|
6
|
-
class Schema::Ref
|
|
7
|
-
# @param ref [String] A reference URI - typically the `$ref` value of the ref_schema
|
|
8
|
-
# @param ref_schema [JSI::Schema] A schema from which the reference originated.
|
|
9
|
-
#
|
|
10
|
-
# If the ref URI consists of only a fragment, it is resolved from the `ref_schema`'s
|
|
11
|
-
# {Schema#schema_resource_root}. Otherwise the resource is found in the `ref_schema`'s
|
|
12
|
-
# {SchemaAncestorNode#jsi_schema_registry #jsi_schema_registry} (and any fragment is resolved from there).
|
|
13
|
-
# @param schema_registry [SchemaRegistry] The registry in which the resource this ref refers to will be found.
|
|
14
|
-
# This should only be specified in the absence of a `ref_schema`.
|
|
15
|
-
# If neither is specified, {JSI.schema_registry} is used.
|
|
16
|
-
def initialize(ref, ref_schema: nil, schema_registry: nil)
|
|
17
|
-
raise(ArgumentError, "ref is not a string") unless ref.respond_to?(:to_str)
|
|
18
|
-
@ref = ref
|
|
19
|
-
@ref_uri = Util.uri(ref)
|
|
20
|
-
@ref_schema = ref_schema ? Schema.ensure_schema(ref_schema) : nil
|
|
21
|
-
@schema_registry = schema_registry || (ref_schema ? ref_schema.jsi_schema_registry : JSI.schema_registry)
|
|
22
|
-
@deref_schema = nil
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# @return [String]
|
|
26
|
-
attr_reader :ref
|
|
27
|
-
|
|
28
|
-
# @return [Addressable::URI]
|
|
29
|
-
attr_reader :ref_uri
|
|
30
|
-
|
|
31
|
-
# @return [Schema, nil]
|
|
32
|
-
attr_reader :ref_schema
|
|
33
|
-
|
|
34
|
-
# @return [SchemaRegistry, nil]
|
|
35
|
-
attr_reader(:schema_registry)
|
|
36
|
-
|
|
37
|
-
# finds the schema this ref points to
|
|
38
|
-
# @return [JSI::Schema]
|
|
39
|
-
# @raise [JSI::Schema::NotASchemaError] when the thing this ref points to is not a schema
|
|
40
|
-
# @raise [JSI::Schema::ReferenceError] when this reference cannot be resolved
|
|
41
|
-
def deref_schema
|
|
42
|
-
return @deref_schema if @deref_schema
|
|
43
|
-
|
|
44
|
-
schema_resource_root = nil
|
|
45
|
-
check_schema_resource_root = -> {
|
|
46
|
-
unless schema_resource_root
|
|
47
|
-
raise(Schema::ReferenceError, [
|
|
48
|
-
"cannot find schema by ref: #{ref}",
|
|
49
|
-
("from: #{ref_schema.pretty_inspect.chomp}" if ref_schema),
|
|
50
|
-
].compact.join("\n"))
|
|
51
|
-
end
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
ref_uri_nofrag = ref_uri.merge(fragment: nil).freeze
|
|
55
|
-
|
|
56
|
-
if ref_uri_nofrag.empty?
|
|
57
|
-
unless ref_schema
|
|
58
|
-
raise(Schema::ReferenceError, [
|
|
59
|
-
"cannot find schema by ref: #{ref}",
|
|
60
|
-
"with no ref schema",
|
|
61
|
-
].join("\n"))
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# the URI only consists of a fragment (or is empty).
|
|
65
|
-
# for a fragment pointer, resolve using Schema#resource_root_subschema on the ref_schema.
|
|
66
|
-
# for a fragment anchor, bootstrap does not support anchors; otherwise use the ref_schema's schema_resource_root.
|
|
67
|
-
schema_resource_root = ref_schema.is_a?(MetaschemaNode::BootstrapSchema) ? nil : ref_schema.schema_resource_root
|
|
68
|
-
resolve_fragment_ptr = ref_schema.method(:resource_root_subschema)
|
|
69
|
-
else
|
|
70
|
-
# find the schema_resource_root from the non-fragment URI. we will resolve any fragment, either pointer or anchor, from there.
|
|
71
|
-
|
|
72
|
-
if ref_uri_nofrag.absolute?
|
|
73
|
-
ref_abs_uri = ref_uri_nofrag
|
|
74
|
-
elsif ref_schema && ref_schema.jsi_resource_ancestor_uri
|
|
75
|
-
ref_abs_uri = ref_schema.jsi_resource_ancestor_uri.join(ref_uri_nofrag).freeze
|
|
76
|
-
else
|
|
77
|
-
ref_abs_uri = nil
|
|
78
|
-
end
|
|
79
|
-
if ref_abs_uri
|
|
80
|
-
unless schema_registry
|
|
81
|
-
raise(Schema::ReferenceError, [
|
|
82
|
-
"could not resolve remote ref with no schema_registry specified",
|
|
83
|
-
"ref URI: #{ref_uri.to_s}",
|
|
84
|
-
("from: #{ref_schema.pretty_inspect.chomp}" if ref_schema),
|
|
85
|
-
].compact.join("\n"))
|
|
86
|
-
end
|
|
87
|
-
schema_resource_root = schema_registry.find(ref_abs_uri)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
unless schema_resource_root
|
|
91
|
-
# HAX for how google does refs and ids
|
|
92
|
-
if ref_schema && ref_schema.jsi_document.respond_to?(:to_hash) && ref_schema.jsi_document['schemas'].respond_to?(:to_hash)
|
|
93
|
-
ref_schema.jsi_document['schemas'].each do |k, v|
|
|
94
|
-
if Addressable::URI.parse(v['id']) == ref_uri_nofrag
|
|
95
|
-
schema_resource_root = ref_schema.resource_root_subschema(['schemas', k])
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
check_schema_resource_root.call
|
|
102
|
-
|
|
103
|
-
if schema_resource_root.is_a?(Schema)
|
|
104
|
-
resolve_fragment_ptr = schema_resource_root.method(:resource_root_subschema)
|
|
105
|
-
else
|
|
106
|
-
# Note: Schema#resource_root_subschema will reinstantiate nonschemas as schemas.
|
|
107
|
-
# not implemented for remote refs when the schema_resource_root is not a schema.
|
|
108
|
-
resolve_fragment_ptr = -> (ptr) { schema_resource_root.jsi_descendent_node(ptr) }
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
fragment = ref_uri.fragment
|
|
113
|
-
|
|
114
|
-
if fragment
|
|
115
|
-
begin
|
|
116
|
-
ptr_from_fragment = Ptr.from_fragment(fragment)
|
|
117
|
-
rescue Ptr::PointerSyntaxError
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
if ptr_from_fragment
|
|
122
|
-
begin
|
|
123
|
-
result_schema = resolve_fragment_ptr.call(ptr_from_fragment)
|
|
124
|
-
rescue Ptr::ResolutionError
|
|
125
|
-
raise(Schema::ReferenceError, [
|
|
126
|
-
"could not resolve pointer: #{ptr_from_fragment.pointer.inspect}",
|
|
127
|
-
("from: #{ref_schema.pretty_inspect.chomp}" if ref_schema),
|
|
128
|
-
("in schema resource root: #{schema_resource_root.pretty_inspect.chomp}" if schema_resource_root),
|
|
129
|
-
].compact.join("\n"))
|
|
130
|
-
end
|
|
131
|
-
elsif fragment.nil?
|
|
132
|
-
check_schema_resource_root.call
|
|
133
|
-
result_schema = schema_resource_root
|
|
134
|
-
else
|
|
135
|
-
check_schema_resource_root.call
|
|
136
|
-
|
|
137
|
-
# find an anchor that resembles the fragment
|
|
138
|
-
result_schemas = schema_resource_root.jsi_anchor_subschemas(fragment)
|
|
139
|
-
|
|
140
|
-
if result_schemas.size == 1
|
|
141
|
-
result_schema = result_schemas.first
|
|
142
|
-
elsif result_schemas.size == 0
|
|
143
|
-
raise(Schema::ReferenceError, [
|
|
144
|
-
"could not find schema by fragment: #{fragment.inspect}",
|
|
145
|
-
"in schema resource root: #{schema_resource_root.pretty_inspect.chomp}",
|
|
146
|
-
].join("\n"))
|
|
147
|
-
else
|
|
148
|
-
raise(Schema::ReferenceError, [
|
|
149
|
-
"found multiple schemas for plain name fragment #{fragment.inspect}:",
|
|
150
|
-
*result_schemas.map { |s| s.pretty_inspect.chomp },
|
|
151
|
-
].join("\n"))
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
Schema.ensure_schema(result_schema, msg: "object identified by uri #{ref} is not a schema:")
|
|
156
|
-
return @deref_schema = result_schema
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
# @return [String]
|
|
160
|
-
def inspect
|
|
161
|
-
-%Q(\#<#{self.class.name} #{ref}>)
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
alias_method :to_s, :inspect
|
|
165
|
-
|
|
166
|
-
# pretty-prints a representation of self to the given printer
|
|
167
|
-
# @return [void]
|
|
168
|
-
def pretty_print(q)
|
|
169
|
-
q.text '#<'
|
|
170
|
-
q.text self.class.name
|
|
171
|
-
q.text ' '
|
|
172
|
-
q.text ref
|
|
173
|
-
q.text '>'
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
# see {Util::Private::FingerprintHash}
|
|
177
|
-
# @api private
|
|
178
|
-
def jsi_fingerprint
|
|
179
|
-
{class: self.class, ref: ref, ref_schema: ref_schema}
|
|
180
|
-
end
|
|
181
|
-
include Util::FingerprintHash
|
|
182
|
-
end
|
|
183
|
-
end
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Validation::ArrayLength
|
|
5
|
-
# @private
|
|
6
|
-
def internal_validate_maxItems(result_builder)
|
|
7
|
-
if keyword?('maxItems')
|
|
8
|
-
value = schema_content['maxItems']
|
|
9
|
-
# The value of this keyword MUST be a non-negative integer.
|
|
10
|
-
if internal_integer?(value) && value >= 0
|
|
11
|
-
if result_builder.instance.respond_to?(:to_ary)
|
|
12
|
-
# An array instance is valid against "maxItems" if its size is less than, or equal to, the value of this keyword.
|
|
13
|
-
result_builder.validate(
|
|
14
|
-
result_builder.instance.to_ary.size <= value,
|
|
15
|
-
'instance array size is greater than `maxItems` value',
|
|
16
|
-
keyword: 'maxItems',
|
|
17
|
-
)
|
|
18
|
-
end
|
|
19
|
-
else
|
|
20
|
-
result_builder.schema_error('`maxItems` is not a non-negative integer', 'maxItems')
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# @private
|
|
26
|
-
def internal_validate_minItems(result_builder)
|
|
27
|
-
if keyword?('minItems')
|
|
28
|
-
value = schema_content['minItems']
|
|
29
|
-
# The value of this keyword MUST be a non-negative integer.
|
|
30
|
-
if internal_integer?(value) && value >= 0
|
|
31
|
-
if result_builder.instance.respond_to?(:to_ary)
|
|
32
|
-
# An array instance is valid against "minItems" if its size is greater than, or equal to, the value of this keyword.
|
|
33
|
-
result_builder.validate(
|
|
34
|
-
result_builder.instance.to_ary.size >= value,
|
|
35
|
-
'instance array size is less than `minItems` value',
|
|
36
|
-
keyword: 'minItems',
|
|
37
|
-
)
|
|
38
|
-
end
|
|
39
|
-
else
|
|
40
|
-
result_builder.schema_error('`minItems` is not a non-negative integer', 'minItems')
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
module Schema::Validation::UniqueItems
|
|
46
|
-
# @private
|
|
47
|
-
def internal_validate_uniqueItems(result_builder)
|
|
48
|
-
if keyword?('uniqueItems')
|
|
49
|
-
value = schema_content['uniqueItems']
|
|
50
|
-
# The value of this keyword MUST be a boolean.
|
|
51
|
-
if value == false
|
|
52
|
-
# If this keyword has boolean value false, the instance validates successfully.
|
|
53
|
-
# (noop)
|
|
54
|
-
elsif value == true
|
|
55
|
-
if result_builder.instance.respond_to?(:to_ary)
|
|
56
|
-
# If it has boolean value true, the instance validates successfully if all of its elements are unique.
|
|
57
|
-
result_builder.validate(
|
|
58
|
-
result_builder.instance.uniq.size == result_builder.instance.size,
|
|
59
|
-
"instance array items' uniqueness does not match `uniqueItems` value",
|
|
60
|
-
keyword: 'uniqueItems',
|
|
61
|
-
)
|
|
62
|
-
end
|
|
63
|
-
else
|
|
64
|
-
result_builder.schema_error('`uniqueItems` is not a boolean', 'uniqueItems')
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Validation::Contains
|
|
5
|
-
# @private
|
|
6
|
-
def internal_validate_contains(result_builder)
|
|
7
|
-
if keyword?('contains')
|
|
8
|
-
# An array instance is valid against "contains" if at least one of its elements is valid against
|
|
9
|
-
# the given schema.
|
|
10
|
-
if result_builder.instance.respond_to?(:to_ary)
|
|
11
|
-
results = {}
|
|
12
|
-
result_builder.instance.each_index do |i|
|
|
13
|
-
results[i] = result_builder.child_subschema_validate(i, ['contains'])
|
|
14
|
-
end
|
|
15
|
-
result_builder.validate(
|
|
16
|
-
results.values.any?(&:valid?),
|
|
17
|
-
'instance array does not contain any items valid against `contains` schema value',
|
|
18
|
-
keyword: 'contains',
|
|
19
|
-
results: results.values,
|
|
20
|
-
)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JSI
|
|
4
|
-
module Schema::Validation::Dependencies
|
|
5
|
-
# @private
|
|
6
|
-
def internal_validate_dependencies(result_builder)
|
|
7
|
-
if keyword?('dependencies')
|
|
8
|
-
value = schema_content['dependencies']
|
|
9
|
-
# This keyword's value MUST be an object. Each property specifies a dependency. Each dependency
|
|
10
|
-
# value MUST be an array or a valid JSON Schema.
|
|
11
|
-
if value.respond_to?(:to_hash)
|
|
12
|
-
value.each_pair do |property_name, dependency|
|
|
13
|
-
if dependency.respond_to?(:to_ary)
|
|
14
|
-
# If the dependency value is an array, each element in the array, if
|
|
15
|
-
# any, MUST be a string, and MUST be unique. If the dependency key is
|
|
16
|
-
# a property in the instance, each of the items in the dependency value
|
|
17
|
-
# must be a property that exists in the instance.
|
|
18
|
-
if result_builder.instance.respond_to?(:to_hash) && result_builder.instance.key?(property_name)
|
|
19
|
-
missing_required = dependency.reject { |name| result_builder.instance.key?(name) }
|
|
20
|
-
# TODO include property_name / missing dependent required property names in the validation error
|
|
21
|
-
result_builder.validate(
|
|
22
|
-
missing_required.empty?,
|
|
23
|
-
'instance object does not contain all dependent required property names specified by `dependencies` value',
|
|
24
|
-
keyword: 'dependencies',
|
|
25
|
-
)
|
|
26
|
-
end
|
|
27
|
-
else
|
|
28
|
-
# If the dependency value is a subschema, and the dependency key is a
|
|
29
|
-
# property in the instance, the entire instance must validate against
|
|
30
|
-
# the dependency value.
|
|
31
|
-
if result_builder.instance.respond_to?(:to_hash) && result_builder.instance.key?(property_name)
|
|
32
|
-
dependency_result = result_builder.inplace_subschema_validate(['dependencies', property_name])
|
|
33
|
-
# TODO include property_name in the validation error
|
|
34
|
-
result_builder.validate(
|
|
35
|
-
dependency_result.valid?,
|
|
36
|
-
'instance object is not valid against the schema corresponding to a matched property name specified by `dependencies` value',
|
|
37
|
-
keyword: 'dependencies',
|
|
38
|
-
results: [dependency_result],
|
|
39
|
-
)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
else
|
|
44
|
-
result_builder.schema_error('`dependencies` is not an object', 'dependencies')
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|