jsi-dev 0.0.0.pre.commonmarker
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 +7 -0
- data/.yardopts +8 -0
- data/CHANGELOG.md +101 -0
- data/LICENSE.md +613 -0
- data/README.md +303 -0
- data/docs/glossary.md +281 -0
- data/jsi.gemspec +30 -0
- data/lib/jsi/base/node.rb +373 -0
- data/lib/jsi/base.rb +738 -0
- data/lib/jsi/jsi_coder.rb +92 -0
- data/lib/jsi/metaschema.rb +6 -0
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +126 -0
- data/lib/jsi/metaschema_node.rb +262 -0
- data/lib/jsi/ptr.rb +314 -0
- data/lib/jsi/schema/application/child_application/contains.rb +25 -0
- data/lib/jsi/schema/application/child_application/draft04.rb +21 -0
- data/lib/jsi/schema/application/child_application/draft06.rb +28 -0
- data/lib/jsi/schema/application/child_application/draft07.rb +28 -0
- data/lib/jsi/schema/application/child_application/items.rb +18 -0
- data/lib/jsi/schema/application/child_application/properties.rb +25 -0
- data/lib/jsi/schema/application/child_application.rb +13 -0
- data/lib/jsi/schema/application/draft04.rb +8 -0
- data/lib/jsi/schema/application/draft06.rb +8 -0
- data/lib/jsi/schema/application/draft07.rb +8 -0
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +28 -0
- data/lib/jsi/schema/application/inplace_application/draft04.rb +25 -0
- data/lib/jsi/schema/application/inplace_application/draft06.rb +26 -0
- data/lib/jsi/schema/application/inplace_application/draft07.rb +32 -0
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +20 -0
- data/lib/jsi/schema/application/inplace_application/ref.rb +18 -0
- data/lib/jsi/schema/application/inplace_application/someof.rb +44 -0
- data/lib/jsi/schema/application/inplace_application.rb +14 -0
- data/lib/jsi/schema/application.rb +12 -0
- data/lib/jsi/schema/draft04.rb +13 -0
- data/lib/jsi/schema/draft06.rb +13 -0
- data/lib/jsi/schema/draft07.rb +13 -0
- data/lib/jsi/schema/issue.rb +36 -0
- data/lib/jsi/schema/ref.rb +183 -0
- data/lib/jsi/schema/schema_ancestor_node.rb +122 -0
- data/lib/jsi/schema/validation/array.rb +69 -0
- data/lib/jsi/schema/validation/const.rb +20 -0
- data/lib/jsi/schema/validation/contains.rb +25 -0
- data/lib/jsi/schema/validation/dependencies.rb +49 -0
- data/lib/jsi/schema/validation/draft04/minmax.rb +91 -0
- data/lib/jsi/schema/validation/draft04.rb +110 -0
- data/lib/jsi/schema/validation/draft06.rb +120 -0
- data/lib/jsi/schema/validation/draft07.rb +157 -0
- data/lib/jsi/schema/validation/enum.rb +25 -0
- data/lib/jsi/schema/validation/ifthenelse.rb +46 -0
- data/lib/jsi/schema/validation/items.rb +54 -0
- data/lib/jsi/schema/validation/not.rb +20 -0
- data/lib/jsi/schema/validation/numeric.rb +121 -0
- data/lib/jsi/schema/validation/object.rb +45 -0
- data/lib/jsi/schema/validation/pattern.rb +34 -0
- data/lib/jsi/schema/validation/properties.rb +101 -0
- data/lib/jsi/schema/validation/property_names.rb +32 -0
- data/lib/jsi/schema/validation/ref.rb +40 -0
- data/lib/jsi/schema/validation/required.rb +27 -0
- data/lib/jsi/schema/validation/someof.rb +90 -0
- data/lib/jsi/schema/validation/string.rb +47 -0
- data/lib/jsi/schema/validation/type.rb +49 -0
- data/lib/jsi/schema/validation.rb +49 -0
- data/lib/jsi/schema.rb +792 -0
- data/lib/jsi/schema_classes.rb +357 -0
- data/lib/jsi/schema_registry.rb +190 -0
- data/lib/jsi/schema_set.rb +219 -0
- data/lib/jsi/simple_wrap.rb +26 -0
- data/lib/jsi/util/private/attr_struct.rb +130 -0
- data/lib/jsi/util/private/memo_map.rb +75 -0
- data/lib/jsi/util/private.rb +202 -0
- data/lib/jsi/util/typelike.rb +225 -0
- data/lib/jsi/util.rb +227 -0
- data/lib/jsi/validation/error.rb +34 -0
- data/lib/jsi/validation/result.rb +212 -0
- data/lib/jsi/validation.rb +15 -0
- data/lib/jsi/version.rb +5 -0
- data/lib/jsi.rb +105 -0
- data/lib/schemas/json-schema.org/draft-04/schema.rb +169 -0
- data/lib/schemas/json-schema.org/draft-06/schema.rb +171 -0
- data/lib/schemas/json-schema.org/draft-07/schema.rb +198 -0
- data/readme.rb +138 -0
- data/{resources}/schemas/json-schema.org/draft-04/schema.json +149 -0
- data/{resources}/schemas/json-schema.org/draft-06/schema.json +154 -0
- data/{resources}/schemas/json-schema.org/draft-07/schema.json +168 -0
- metadata +155 -0
@@ -0,0 +1,44 @@
|
|
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
|
@@ -0,0 +1,14 @@
|
|
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
|
@@ -0,0 +1,12 @@
|
|
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
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema
|
5
|
+
Issue = Util::AttrStruct[*%w(
|
6
|
+
level
|
7
|
+
message
|
8
|
+
keyword
|
9
|
+
schema
|
10
|
+
)]
|
11
|
+
|
12
|
+
# an issue or problem with a schema.
|
13
|
+
#
|
14
|
+
# when the `level` is `:error`, the schema is invalid according to its specification,
|
15
|
+
# violating some "MUST" or "MUST NOT".
|
16
|
+
#
|
17
|
+
# when the `level` is `:warning`, the issue does not mean the schema is invalid, but contains something
|
18
|
+
# that does not make sense. for example, specifying `additionalItems` without an adjacent `items` has
|
19
|
+
# no effect (in specifications which define `additionalItems`), but is not an invalid schema.
|
20
|
+
#
|
21
|
+
# @!attribute level
|
22
|
+
# :error or :warning
|
23
|
+
# @return [Symbol]
|
24
|
+
# @!attribute message
|
25
|
+
# a message describing the issue
|
26
|
+
# @return [String]
|
27
|
+
# @!attribute keyword
|
28
|
+
# the keyword of the schema that has an issue
|
29
|
+
# @return [String]
|
30
|
+
# @!attribute schema
|
31
|
+
# the schema that has an issue
|
32
|
+
# @return [JSI::Schema]
|
33
|
+
class Issue
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,183 @@
|
|
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
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
# a node in a document which may contain a schema somewhere within is extended with SchemaAncestorNode, for
|
5
|
+
# tracking things necessary for a schema to function correctly
|
6
|
+
module Schema::SchemaAncestorNode
|
7
|
+
if Util::LAST_ARGUMENT_AS_KEYWORD_PARAMETERS
|
8
|
+
def initialize(*)
|
9
|
+
super
|
10
|
+
jsi_schema_ancestor_node_initialize
|
11
|
+
end
|
12
|
+
else
|
13
|
+
def initialize(*, **)
|
14
|
+
super
|
15
|
+
jsi_schema_ancestor_node_initialize
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# the base URI used to resolve the ids of schemas at or below this JSI.
|
20
|
+
# this is always an absolute URI (with no fragment).
|
21
|
+
# this may be the absolute schema URI of a parent schema or the URI from which the document was retrieved.
|
22
|
+
# @api private
|
23
|
+
# @return [Addressable::URI, nil]
|
24
|
+
attr_reader :jsi_schema_base_uri
|
25
|
+
|
26
|
+
# resources which are ancestors of this JSI in the document. this does not include self.
|
27
|
+
# @api private
|
28
|
+
# @return [Array<JSI::Schema>]
|
29
|
+
attr_reader :jsi_schema_resource_ancestors
|
30
|
+
|
31
|
+
# See {SchemaSet#new_jsi} param `schema_registry`
|
32
|
+
# @return [SchemaRegistry]
|
33
|
+
attr_reader(:jsi_schema_registry)
|
34
|
+
|
35
|
+
# the URI of the resource containing this node.
|
36
|
+
# this is always an absolute URI (with no fragment).
|
37
|
+
# if this node is a schema with an id, this is its absolute URI; otherwise a parent resource's URI,
|
38
|
+
# or nil if not contained by a resource with a URI.
|
39
|
+
# @return [Addressable::URI, nil]
|
40
|
+
def jsi_resource_ancestor_uri
|
41
|
+
(is_a?(Schema) && schema_absolute_uri) || jsi_schema_base_uri
|
42
|
+
end
|
43
|
+
|
44
|
+
# The schema at or below this node with the given anchor.
|
45
|
+
# If no schema has that anchor (or multiple schemas do, incorrectly), nil.
|
46
|
+
#
|
47
|
+
# @return [JSI::Schema, nil]
|
48
|
+
def jsi_anchor_subschema(anchor)
|
49
|
+
subschemas = @anchor_subschemas_map[anchor: anchor]
|
50
|
+
if subschemas.size == 1
|
51
|
+
subschemas.first
|
52
|
+
else
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# All schemas at or below this node with the given anchor.
|
58
|
+
#
|
59
|
+
# @return [Set<JSI::Schema>]
|
60
|
+
def jsi_anchor_subschemas(anchor)
|
61
|
+
@anchor_subschemas_map[anchor: anchor]
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def jsi_schema_ancestor_node_initialize
|
67
|
+
@anchor_subschemas_map = jsi_memomap(&method(:jsi_anchor_subschemas_compute))
|
68
|
+
end
|
69
|
+
|
70
|
+
attr_writer :jsi_document
|
71
|
+
|
72
|
+
def jsi_ptr=(jsi_ptr)
|
73
|
+
#chkbug raise(Bug, "jsi_ptr not #{Ptr}: #{jsi_ptr}") unless jsi_ptr.is_a?(Ptr)
|
74
|
+
@jsi_ptr = jsi_ptr
|
75
|
+
end
|
76
|
+
|
77
|
+
def jsi_schema_base_uri=(jsi_schema_base_uri)
|
78
|
+
#chkbug raise(Bug) if jsi_schema_base_uri && !jsi_schema_base_uri.is_a?(Addressable::URI)
|
79
|
+
#chkbug raise(Bug) if jsi_schema_base_uri && !jsi_schema_base_uri.absolute?
|
80
|
+
#chkbug raise(Bug) if jsi_schema_base_uri && jsi_schema_base_uri.fragment
|
81
|
+
|
82
|
+
@jsi_schema_base_uri = jsi_schema_base_uri
|
83
|
+
end
|
84
|
+
|
85
|
+
def jsi_schema_resource_ancestors=(jsi_schema_resource_ancestors)
|
86
|
+
#chkbug raise(Bug) unless jsi_schema_resource_ancestors.respond_to?(:to_ary)
|
87
|
+
#chkbug jsi_schema_resource_ancestors.each { |a| Schema.ensure_schema(a) }
|
88
|
+
#chkbug # sanity check the ancestors are in order
|
89
|
+
#chkbug last_anc_ptr = nil
|
90
|
+
#chkbug jsi_schema_resource_ancestors.each do |anc|
|
91
|
+
#chkbug if last_anc_ptr.nil?
|
92
|
+
#chkbug # pass
|
93
|
+
#chkbug elsif last_anc_ptr == anc.jsi_ptr
|
94
|
+
#chkbug raise(Bug, "duplicate ancestors in #{jsi_schema_resource_ancestors.pretty_inspect}")
|
95
|
+
#chkbug elsif !last_anc_ptr.contains?(anc.jsi_ptr)
|
96
|
+
#chkbug raise(Bug, "ancestor ptr #{anc.jsi_ptr} not contained by previous: #{last_anc_ptr} in #{jsi_schema_resource_ancestors.pretty_inspect}")
|
97
|
+
#chkbug end
|
98
|
+
#chkbug if anc.jsi_ptr == jsi_ptr
|
99
|
+
#chkbug raise(Bug, "ancestor is self")
|
100
|
+
#chkbug elsif !anc.jsi_ptr.contains?(jsi_ptr)
|
101
|
+
#chkbug raise(Bug, "ancestor does not contain self")
|
102
|
+
#chkbug end
|
103
|
+
#chkbug last_anc_ptr = anc.jsi_ptr
|
104
|
+
#chkbug end
|
105
|
+
|
106
|
+
@jsi_schema_resource_ancestors = jsi_schema_resource_ancestors
|
107
|
+
end
|
108
|
+
|
109
|
+
attr_writer(:jsi_schema_registry)
|
110
|
+
|
111
|
+
def jsi_anchor_subschemas_compute(anchor: )
|
112
|
+
jsi_each_descendent_node.select do |node|
|
113
|
+
node.is_a?(Schema) && node.respond_to?(:anchor) && node.anchor == anchor
|
114
|
+
end.to_set.freeze
|
115
|
+
end
|
116
|
+
|
117
|
+
# @return [Util::MemoMap]
|
118
|
+
def jsi_memomap(**options, &block)
|
119
|
+
Util::MemoMap::Mutable.new(**options, &block)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,69 @@
|
|
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
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Validation::Const
|
5
|
+
# @private
|
6
|
+
def internal_validate_const(result_builder)
|
7
|
+
if keyword?('const')
|
8
|
+
value = schema_content['const']
|
9
|
+
# The value of this keyword MAY be of any type, including null.
|
10
|
+
# An instance validates successfully against this keyword if its value is equal to the value of
|
11
|
+
# the keyword.
|
12
|
+
result_builder.validate(
|
13
|
+
result_builder.instance == value,
|
14
|
+
'instance is not equal to `const` value',
|
15
|
+
keyword: 'const',
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
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
|
@@ -0,0 +1,49 @@
|
|
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
|