json_skooma 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +22 -0
- data/LICENSE.txt +21 -0
- data/README.md +107 -0
- data/data/draft-2019-09/README.md +60 -0
- data/data/draft-2019-09/hyper-schema.json +26 -0
- data/data/draft-2019-09/links.json +91 -0
- data/data/draft-2019-09/meta/applicator.json +56 -0
- data/data/draft-2019-09/meta/content.json +17 -0
- data/data/draft-2019-09/meta/core.json +57 -0
- data/data/draft-2019-09/meta/format.json +14 -0
- data/data/draft-2019-09/meta/hyper-schema.json +29 -0
- data/data/draft-2019-09/meta/meta-data.json +37 -0
- data/data/draft-2019-09/meta/validation.json +98 -0
- data/data/draft-2019-09/output/hyper-schema.json +62 -0
- data/data/draft-2019-09/output/schema.json +86 -0
- data/data/draft-2019-09/output/verbose-example.json +130 -0
- data/data/draft-2019-09/schema.json +42 -0
- data/data/draft-2020-12/README.md +89 -0
- data/data/draft-2020-12/adr/README.md +15 -0
- data/data/draft-2020-12/archive/hyper-schema.json +28 -0
- data/data/draft-2020-12/archive/links.json +93 -0
- data/data/draft-2020-12/archive/meta/hyper-schema.json +30 -0
- data/data/draft-2020-12/hyper-schema.json +27 -0
- data/data/draft-2020-12/links.json +85 -0
- data/data/draft-2020-12/meta/applicator.json +48 -0
- data/data/draft-2020-12/meta/content.json +17 -0
- data/data/draft-2020-12/meta/core.json +51 -0
- data/data/draft-2020-12/meta/format-annotation.json +14 -0
- data/data/draft-2020-12/meta/format-assertion.json +14 -0
- data/data/draft-2020-12/meta/hyper-schema.json +29 -0
- data/data/draft-2020-12/meta/meta-data.json +37 -0
- data/data/draft-2020-12/meta/unevaluated.json +15 -0
- data/data/draft-2020-12/meta/validation.json +98 -0
- data/data/draft-2020-12/output/hyper-schema.json +62 -0
- data/data/draft-2020-12/output/schema.json +96 -0
- data/data/draft-2020-12/output/verbose-example.json +130 -0
- data/data/draft-2020-12/schema.json +58 -0
- data/lib/json_skooma/dialects/draft201909.rb +137 -0
- data/lib/json_skooma/dialects/draft202012.rb +146 -0
- data/lib/json_skooma/formatters.rb +135 -0
- data/lib/json_skooma/inflector.rb +13 -0
- data/lib/json_skooma/json_node.rb +100 -0
- data/lib/json_skooma/json_pointer.rb +79 -0
- data/lib/json_skooma/json_schema.rb +176 -0
- data/lib/json_skooma/keywords/applicator/additional_properties.rb +37 -0
- data/lib/json_skooma/keywords/applicator/all_of.rb +25 -0
- data/lib/json_skooma/keywords/applicator/any_of.rb +26 -0
- data/lib/json_skooma/keywords/applicator/contains.rb +31 -0
- data/lib/json_skooma/keywords/applicator/dependent_schemas.rb +35 -0
- data/lib/json_skooma/keywords/applicator/else.rb +22 -0
- data/lib/json_skooma/keywords/applicator/if.rb +17 -0
- data/lib/json_skooma/keywords/applicator/items.rb +36 -0
- data/lib/json_skooma/keywords/applicator/not.rb +19 -0
- data/lib/json_skooma/keywords/applicator/one_of.rb +35 -0
- data/lib/json_skooma/keywords/applicator/pattern_properties.rb +46 -0
- data/lib/json_skooma/keywords/applicator/prefix_items.rb +31 -0
- data/lib/json_skooma/keywords/applicator/properties.rb +34 -0
- data/lib/json_skooma/keywords/applicator/property_names.rb +25 -0
- data/lib/json_skooma/keywords/applicator/then.rb +22 -0
- data/lib/json_skooma/keywords/base.rb +74 -0
- data/lib/json_skooma/keywords/base_annotation.rb +12 -0
- data/lib/json_skooma/keywords/content/content_encoding.rb +12 -0
- data/lib/json_skooma/keywords/content/content_media_type.rb +12 -0
- data/lib/json_skooma/keywords/content/content_schema.rb +19 -0
- data/lib/json_skooma/keywords/core/anchor.rb +22 -0
- data/lib/json_skooma/keywords/core/comment.rb +12 -0
- data/lib/json_skooma/keywords/core/defs.rb +13 -0
- data/lib/json_skooma/keywords/core/dynamic_anchor.rb +22 -0
- data/lib/json_skooma/keywords/core/dynamic_ref.rb +67 -0
- data/lib/json_skooma/keywords/core/id.rb +28 -0
- data/lib/json_skooma/keywords/core/ref.rb +35 -0
- data/lib/json_skooma/keywords/core/schema.rb +26 -0
- data/lib/json_skooma/keywords/core/vocabulary.rb +34 -0
- data/lib/json_skooma/keywords/draft_2019_09/additional_items.rb +40 -0
- data/lib/json_skooma/keywords/draft_2019_09/items.rb +41 -0
- data/lib/json_skooma/keywords/draft_2019_09/recursive_anchor.rb +12 -0
- data/lib/json_skooma/keywords/draft_2019_09/recursive_ref.rb +46 -0
- data/lib/json_skooma/keywords/draft_2019_09/unevaluated_items.rb +56 -0
- data/lib/json_skooma/keywords/format_annotation/format.rb +27 -0
- data/lib/json_skooma/keywords/meta_data/default.rb +11 -0
- data/lib/json_skooma/keywords/meta_data/deprecated.rb +11 -0
- data/lib/json_skooma/keywords/meta_data/description.rb +11 -0
- data/lib/json_skooma/keywords/meta_data/examples.rb +11 -0
- data/lib/json_skooma/keywords/meta_data/read_only.rb +11 -0
- data/lib/json_skooma/keywords/meta_data/title.rb +11 -0
- data/lib/json_skooma/keywords/meta_data/write_only.rb +11 -0
- data/lib/json_skooma/keywords/unevaluated/unevaluated_items.rb +59 -0
- data/lib/json_skooma/keywords/unevaluated/unevaluated_properties.rb +43 -0
- data/lib/json_skooma/keywords/unknown.rb +21 -0
- data/lib/json_skooma/keywords/validation/const.rb +17 -0
- data/lib/json_skooma/keywords/validation/dependent_required.rb +24 -0
- data/lib/json_skooma/keywords/validation/enum.rb +19 -0
- data/lib/json_skooma/keywords/validation/exclusive_maximum.rb +18 -0
- data/lib/json_skooma/keywords/validation/exclusive_minimum.rb +18 -0
- data/lib/json_skooma/keywords/validation/max_contains.rb +24 -0
- data/lib/json_skooma/keywords/validation/max_items.rb +18 -0
- data/lib/json_skooma/keywords/validation/max_length.rb +18 -0
- data/lib/json_skooma/keywords/validation/max_properties.rb +18 -0
- data/lib/json_skooma/keywords/validation/maximum.rb +18 -0
- data/lib/json_skooma/keywords/validation/min_contains.rb +31 -0
- data/lib/json_skooma/keywords/validation/min_items.rb +18 -0
- data/lib/json_skooma/keywords/validation/min_length.rb +18 -0
- data/lib/json_skooma/keywords/validation/min_properties.rb +18 -0
- data/lib/json_skooma/keywords/validation/minimum.rb +18 -0
- data/lib/json_skooma/keywords/validation/multiple_of.rb +20 -0
- data/lib/json_skooma/keywords/validation/pattern.rb +23 -0
- data/lib/json_skooma/keywords/validation/required.rb +19 -0
- data/lib/json_skooma/keywords/validation/type.rb +26 -0
- data/lib/json_skooma/keywords/validation/unique_items.rb +20 -0
- data/lib/json_skooma/keywords/value_schemas.rb +87 -0
- data/lib/json_skooma/memoizable.rb +21 -0
- data/lib/json_skooma/metaschema.rb +32 -0
- data/lib/json_skooma/registry.rb +130 -0
- data/lib/json_skooma/result.rb +125 -0
- data/lib/json_skooma/sources.rb +55 -0
- data/lib/json_skooma/validators/base.rb +31 -0
- data/lib/json_skooma/validators/date.rb +18 -0
- data/lib/json_skooma/validators/date_time.rb +24 -0
- data/lib/json_skooma/validators/duration.rb +25 -0
- data/lib/json_skooma/validators/email.rb +36 -0
- data/lib/json_skooma/validators/hostname.rb +17 -0
- data/lib/json_skooma/validators/idn_email.rb +30 -0
- data/lib/json_skooma/validators/idn_hostname.rb +15 -0
- data/lib/json_skooma/validators/ipv4.rb +20 -0
- data/lib/json_skooma/validators/ipv6.rb +16 -0
- data/lib/json_skooma/validators/iri.rb +47 -0
- data/lib/json_skooma/validators/iri_reference.rb +15 -0
- data/lib/json_skooma/validators/json_pointer.rb +19 -0
- data/lib/json_skooma/validators/regex.rb +15 -0
- data/lib/json_skooma/validators/relative_json_pointer.rb +18 -0
- data/lib/json_skooma/validators/time.rb +32 -0
- data/lib/json_skooma/validators/uri.rb +60 -0
- data/lib/json_skooma/validators/uri_reference.rb +15 -0
- data/lib/json_skooma/validators/uri_template.rb +26 -0
- data/lib/json_skooma/validators/uuid.rb +15 -0
- data/lib/json_skooma/validators.rb +17 -0
- data/lib/json_skooma/version.rb +5 -0
- data/lib/json_skooma/vocabulary.rb +12 -0
- data/lib/json_skooma.rb +39 -0
- metadata +244 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Applicator
|
6
|
+
class PrefixItems < Base
|
7
|
+
self.key = "prefixItems"
|
8
|
+
self.instance_types = "array"
|
9
|
+
self.value_schema = :array_of_schemas
|
10
|
+
|
11
|
+
def evaluate(instance, result)
|
12
|
+
annotation = nil
|
13
|
+
error = []
|
14
|
+
instance.take(json.length).each_with_index do |item, index|
|
15
|
+
annotation = index
|
16
|
+
result.call(item, index.to_s) do |subresult|
|
17
|
+
unless json[index].evaluate(item, subresult).passed?
|
18
|
+
error << index
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
return result.failure(error) unless error.empty?
|
23
|
+
return if annotation.nil?
|
24
|
+
|
25
|
+
annotation = true if annotation == instance.length - 1
|
26
|
+
result.annotate(annotation)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Applicator
|
6
|
+
class Properties < Base
|
7
|
+
self.key = "properties"
|
8
|
+
self.instance_types = "object"
|
9
|
+
self.value_schema = :object_of_schemas
|
10
|
+
|
11
|
+
def evaluate(instance, result)
|
12
|
+
annotation = []
|
13
|
+
err_names = []
|
14
|
+
instance.each do |name, item|
|
15
|
+
next unless json.value.key?(name)
|
16
|
+
|
17
|
+
result.call(item, name) do |subresult|
|
18
|
+
json[name].evaluate(item, subresult)
|
19
|
+
if subresult.passed?
|
20
|
+
annotation << name
|
21
|
+
else
|
22
|
+
err_names << name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
return result.annotate(annotation) if err_names.empty?
|
28
|
+
|
29
|
+
result.failure("Properties #{err_names} are invalid")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Applicator
|
6
|
+
class PropertyNames < Base
|
7
|
+
self.key = "propertyNames"
|
8
|
+
self.instance_types = "object"
|
9
|
+
self.value_schema = :schema
|
10
|
+
|
11
|
+
def evaluate(instance, result)
|
12
|
+
error = []
|
13
|
+
instance.each do |name,|
|
14
|
+
next if json.evaluate(JSONNode.new(name, key: name, parent: instance), result).passed?
|
15
|
+
|
16
|
+
error << name
|
17
|
+
result.success
|
18
|
+
end
|
19
|
+
|
20
|
+
result.failure(error) if error.any?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Applicator
|
6
|
+
class Then < Base
|
7
|
+
self.key = "then"
|
8
|
+
self.value_schema = :schema
|
9
|
+
self.depends_on = %w[if]
|
10
|
+
|
11
|
+
def evaluate(instance, result)
|
12
|
+
condition = result.sibling(instance, "if")
|
13
|
+
if condition&.valid?
|
14
|
+
json.evaluate(instance, result)
|
15
|
+
else
|
16
|
+
result.discard
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
class Base
|
6
|
+
attr_reader :json, :parent_schema
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_accessor :static, :depends_on, :schema_value_class
|
10
|
+
attr_writer :key
|
11
|
+
attr_reader :instance_types
|
12
|
+
|
13
|
+
def key
|
14
|
+
@key or raise "Key must be defined"
|
15
|
+
end
|
16
|
+
|
17
|
+
def instance_types=(value)
|
18
|
+
@instance_types = Array(value)
|
19
|
+
end
|
20
|
+
|
21
|
+
def value_schema=(schema_keys)
|
22
|
+
Array(schema_keys).each do |k|
|
23
|
+
prepend ValueSchemas[k]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_defaults
|
28
|
+
@instance_types = %w[boolean object array string number null]
|
29
|
+
@static = false
|
30
|
+
@depends_on = []
|
31
|
+
end
|
32
|
+
|
33
|
+
def inherited(subclass)
|
34
|
+
subclass.set_defaults
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(parent_schema, value)
|
39
|
+
@parent_schema = parent_schema
|
40
|
+
@json = wrap_value(value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def key
|
44
|
+
self.class.key
|
45
|
+
end
|
46
|
+
|
47
|
+
def static
|
48
|
+
self.class.static
|
49
|
+
end
|
50
|
+
|
51
|
+
def instance_types
|
52
|
+
self.class.instance_types
|
53
|
+
end
|
54
|
+
|
55
|
+
def evaluate(instance, result)
|
56
|
+
end
|
57
|
+
|
58
|
+
def each_schema(&block)
|
59
|
+
end
|
60
|
+
|
61
|
+
def resolve
|
62
|
+
each_schema do |schema|
|
63
|
+
schema.resolve_references if schema.respond_to?(:resolve_references)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def wrap_value(value)
|
70
|
+
JSONNode.new(value, key: key, parent: parent_schema)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Content
|
6
|
+
class ContentSchema < BaseAnnotation
|
7
|
+
self.key = "contentSchema"
|
8
|
+
self.instance_types = %w[string]
|
9
|
+
self.depends_on = %w[contentMediaType]
|
10
|
+
|
11
|
+
def evaluate(instance, result)
|
12
|
+
return super if result.sibling(instance, "contentMediaType")
|
13
|
+
|
14
|
+
result.discard
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Core
|
6
|
+
class Anchor < Base
|
7
|
+
self.key = "$anchor"
|
8
|
+
self.static = true
|
9
|
+
|
10
|
+
def initialize(parent_schema, value)
|
11
|
+
super
|
12
|
+
|
13
|
+
base_uri = parent_schema.base_uri
|
14
|
+
raise Error, "No base URI for `$anchor` value `#{value}`" if base_uri.nil?
|
15
|
+
|
16
|
+
uri = base_uri.dup.tap { |u| u.fragment = value }
|
17
|
+
parent_schema.registry.add_schema(uri, parent_schema, cache_id: parent_schema.cache_id)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Core
|
6
|
+
class DynamicAnchor < Base
|
7
|
+
self.key = "$dynamicAnchor"
|
8
|
+
self.static = true
|
9
|
+
|
10
|
+
def initialize(parent_schema, value)
|
11
|
+
super
|
12
|
+
|
13
|
+
base_uri = parent_schema.base_uri
|
14
|
+
raise Error, "No base URI for `$dynamicAnchor` value `#{value}`" if base_uri.nil?
|
15
|
+
|
16
|
+
uri = base_uri.dup.tap { |u| u.fragment = value }
|
17
|
+
parent_schema.registry.add_schema(uri, parent_schema, cache_id: parent_schema.cache_id)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Core
|
6
|
+
class DynamicRef < Base
|
7
|
+
self.key = "$dynamicRef"
|
8
|
+
|
9
|
+
def initialize(parent_schema, value)
|
10
|
+
super
|
11
|
+
@fragment = URI.parse(value).fragment
|
12
|
+
@dynamic = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def resolve
|
16
|
+
uri = URI.parse(json)
|
17
|
+
if uri.relative?
|
18
|
+
base_uri = parent_schema.base_uri
|
19
|
+
if base_uri.nil?
|
20
|
+
raise "No base URI against which to resolve the `$dynamicRef` value `#{uri}`"
|
21
|
+
end
|
22
|
+
|
23
|
+
uri = base_uri + uri
|
24
|
+
end
|
25
|
+
@ref_schema = parent_schema.registry.schema(
|
26
|
+
uri,
|
27
|
+
metaschema_uri: parent_schema.metaschema_uri,
|
28
|
+
cache_id: parent_schema.cache_id
|
29
|
+
)
|
30
|
+
dynamic_anchor = @ref_schema["$dynamicAnchor"]
|
31
|
+
@dynamic = dynamic_anchor == @fragment
|
32
|
+
end
|
33
|
+
|
34
|
+
def evaluate(instance, result)
|
35
|
+
ref_schema = @ref_schema
|
36
|
+
if @dynamic
|
37
|
+
target = result
|
38
|
+
checked_uris = Set.new
|
39
|
+
while target
|
40
|
+
base_uri = target.schema.base_uri
|
41
|
+
if base_uri && !checked_uris.include?(base_uri)
|
42
|
+
checked_uris << base_uri
|
43
|
+
target_uri = base_uri.dup.tap { |u| u.fragment = @fragment }
|
44
|
+
|
45
|
+
begin
|
46
|
+
found_schema = parent_schema.registry.schema(
|
47
|
+
target_uri,
|
48
|
+
cache_id: parent_schema.cache_id
|
49
|
+
)
|
50
|
+
dynamic_anchor = found_schema["$dynamicAnchor"]
|
51
|
+
ref_schema = found_schema if dynamic_anchor == @fragment
|
52
|
+
rescue RegistryError, Hana::Pointer::FormatError
|
53
|
+
# do nothing
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
target = target.parent
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
ref_schema.evaluate(instance, result)
|
62
|
+
result.ref_schema = ref_schema
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Core
|
6
|
+
class Id < Base
|
7
|
+
self.key = "$id"
|
8
|
+
self.static = true
|
9
|
+
|
10
|
+
def initialize(parent_schema, value)
|
11
|
+
super
|
12
|
+
|
13
|
+
uri = URI.parse(value)
|
14
|
+
if uri.relative?
|
15
|
+
base_uri = parent_schema.base_uri
|
16
|
+
if base_uri
|
17
|
+
uri = base_uri + uri
|
18
|
+
else
|
19
|
+
raise "No base URI against which to resolve the `$id` value `#{value}`"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
parent_schema.uri = uri
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Core
|
6
|
+
class Ref < Base
|
7
|
+
self.key = "$ref"
|
8
|
+
|
9
|
+
def resolve
|
10
|
+
uri = resolve_uri
|
11
|
+
@ref_schema = parent_schema.registry.schema(
|
12
|
+
uri,
|
13
|
+
metaschema_uri: parent_schema.metaschema_uri,
|
14
|
+
cache_id: parent_schema.cache_id
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
def evaluate(instance, result)
|
19
|
+
@ref_schema.evaluate(instance, result)
|
20
|
+
result.ref_schema = @ref_schema
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def resolve_uri
|
26
|
+
uri = URI.parse(json)
|
27
|
+
return uri if uri.absolute?
|
28
|
+
return parent_schema.base_uri + uri if parent_schema.base_uri
|
29
|
+
|
30
|
+
raise Error, "No base URI against which to resolve the `$ref` value `#{uri}`"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Core
|
6
|
+
class Schema < Base
|
7
|
+
self.key = "$schema"
|
8
|
+
self.static = true
|
9
|
+
|
10
|
+
def initialize(parent_schema, value)
|
11
|
+
super
|
12
|
+
|
13
|
+
# todo: validate URI.validate(require_scheme=True, require_normalized=True)
|
14
|
+
uri = URI.parse(value)
|
15
|
+
parent_schema.metaschema_uri = uri
|
16
|
+
|
17
|
+
if parent_schema.is_a?(Metaschema)
|
18
|
+
metaschema = parent_schema.registry.metaschema(uri)
|
19
|
+
parent_schema.core_vocabulary ||= metaschema.core_vocabulary
|
20
|
+
parent_schema.default_vocabularies ||= metaschema.default_vocabularies
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Core
|
6
|
+
class Vocabulary < Base
|
7
|
+
self.key = "$vocabulary"
|
8
|
+
self.static = true
|
9
|
+
|
10
|
+
def initialize(parent_schema, value)
|
11
|
+
super
|
12
|
+
|
13
|
+
return unless parent_schema.is_a?(Metaschema)
|
14
|
+
|
15
|
+
core_vocab_uri = parent_schema.core_vocabulary&.uri.to_s
|
16
|
+
if core_vocab_uri.empty? || !value[core_vocab_uri]
|
17
|
+
raise Error, "The `$vocabulary` keyword must list the core vocabulary with a value of true"
|
18
|
+
end
|
19
|
+
|
20
|
+
value.each do |vocabulary_uri, vocabulary_required|
|
21
|
+
uri = URI.parse(vocabulary_uri)
|
22
|
+
|
23
|
+
vocabulary = parent_schema.registry.vocabulary(uri)
|
24
|
+
parent_schema.kw_classes.merge!(vocabulary.kw_classes)
|
25
|
+
rescue RegistryError
|
26
|
+
if vocabulary_required
|
27
|
+
raise Error, "The metaschema requires an unrecognized vocabulary #{vocabulary_uri}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Draft201909
|
6
|
+
class AdditionalItems < Base
|
7
|
+
self.key = "additionalItems"
|
8
|
+
self.instance_types = "array"
|
9
|
+
self.value_schema = :schema
|
10
|
+
self.depends_on = %w[items]
|
11
|
+
|
12
|
+
def evaluate(instance, result)
|
13
|
+
items = result.sibling(instance, "items")
|
14
|
+
return result.discard unless items&.annotation.is_a?(Integer)
|
15
|
+
|
16
|
+
annotation = nil
|
17
|
+
error = []
|
18
|
+
|
19
|
+
instance.each_with_index do |item, index|
|
20
|
+
next if items.annotation >= index
|
21
|
+
|
22
|
+
if json.evaluate(item, result).passed?
|
23
|
+
annotation = true
|
24
|
+
else
|
25
|
+
error << index
|
26
|
+
# reset to passed for the next iteration
|
27
|
+
result.success
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
if error.any?
|
32
|
+
result.failure(error)
|
33
|
+
else
|
34
|
+
result.annotate(annotation)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Draft201909
|
6
|
+
class Items < Base
|
7
|
+
self.key = "items"
|
8
|
+
self.instance_types = %w[array]
|
9
|
+
self.value_schema = [:schema, :array_of_schemas]
|
10
|
+
|
11
|
+
def evaluate(instance, result)
|
12
|
+
return if instance.empty?
|
13
|
+
|
14
|
+
if json.type == "boolean"
|
15
|
+
json.evaluate(instance, result)
|
16
|
+
elsif json.is_a?(JSONSchema)
|
17
|
+
instance.each do |item|
|
18
|
+
json.evaluate(item, result)
|
19
|
+
end
|
20
|
+
result.annotate(true) if result.passed?
|
21
|
+
elsif json.type == "array"
|
22
|
+
annotation = nil
|
23
|
+
error = []
|
24
|
+
|
25
|
+
instance.take(json.length).each_with_index do |item, index|
|
26
|
+
annotation = index
|
27
|
+
result.call(item, index.to_s) do |subresult|
|
28
|
+
unless json[index].evaluate(item, subresult).passed?
|
29
|
+
error << index
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return result.failure(error) unless error.empty?
|
34
|
+
|
35
|
+
result.annotate(annotation)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONSkooma
|
4
|
+
module Keywords
|
5
|
+
module Draft201909
|
6
|
+
class RecursiveRef < Base
|
7
|
+
self.key = "$recursiveRef"
|
8
|
+
|
9
|
+
def initialize(parent_schema, value)
|
10
|
+
super
|
11
|
+
raise "`$recursiveRef` may only take the value `#`" if value != "#"
|
12
|
+
end
|
13
|
+
|
14
|
+
def resolve
|
15
|
+
base_uri = parent_schema.base_uri
|
16
|
+
if base_uri.nil?
|
17
|
+
raise "No base URI against which to resolve the `$recursiveRef`"
|
18
|
+
end
|
19
|
+
|
20
|
+
@ref_schema = parent_schema.registry.schema(
|
21
|
+
base_uri,
|
22
|
+
metaschema_uri: parent_schema.metaschema_uri,
|
23
|
+
cache_id: parent_schema.cache_id
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def evaluate(instance, result)
|
28
|
+
ref_schema = @ref_schema
|
29
|
+
recursive_anchor = ref_schema["$recursiveAnchor"]
|
30
|
+
if recursive_anchor&.value
|
31
|
+
target = result
|
32
|
+
while target
|
33
|
+
base_anchor = target.schema["$recursiveAnchor"]
|
34
|
+
if base_anchor&.value
|
35
|
+
ref_schema = target.schema
|
36
|
+
end
|
37
|
+
target = target.parent
|
38
|
+
end
|
39
|
+
end
|
40
|
+
ref_schema.evaluate(instance, result)
|
41
|
+
result.ref_schema = ref_schema
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|