jsi 0.8.2 → 0.9.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/.yardopts +3 -2
- data/CHANGELOG.md +8 -3
- data/LICENSE.md +2 -3
- data/README.md +68 -31
- data/docs/Glossary.md +313 -0
- data/jsi.gemspec +1 -0
- data/lib/jsi/base/mutability.rb +4 -0
- data/lib/jsi/base/node.rb +63 -24
- data/lib/jsi/base.rb +556 -173
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +106 -56
- data/lib/jsi/metaschema_node.rb +227 -160
- data/lib/jsi/ptr.rb +32 -15
- 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 +103 -50
- data/lib/jsi/schema/vocabulary.rb +36 -0
- data/lib/jsi/schema.rb +519 -337
- data/lib/jsi/schema_classes.rb +168 -124
- data/lib/jsi/schema_set.rb +67 -126
- data/lib/jsi/set.rb +23 -0
- data/lib/jsi/simple_wrap.rb +13 -16
- 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 +57 -12
- data/lib/jsi/util/typelike.rb +19 -64
- data/lib/jsi/util.rb +52 -34
- data/lib/jsi/validation/error.rb +41 -2
- data/lib/jsi/validation/result.rb +118 -71
- data/lib/jsi/validation.rb +1 -6
- data/lib/jsi/version.rb +1 -1
- data/lib/jsi.rb +158 -41
- data/lib/schemas/json-schema.org/draft/2020-12/schema.rb +67 -0
- data/lib/schemas/json-schema.org/draft-04/schema.rb +63 -106
- data/lib/schemas/json-schema.org/draft-06/schema.rb +56 -105
- data/lib/schemas/json-schema.org/draft-07/schema.rb +67 -124
- data/readme.rb +3 -3
- 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 +69 -47
- 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 -186
- 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 -93
- 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 -200
- data/lib/jsi/util/private/attr_struct.rb +0 -141
data/lib/jsi/schema.rb
CHANGED
|
@@ -11,125 +11,50 @@ module JSI
|
|
|
11
11
|
# The content of an instance which is a JSI::Schema (referred to in this context as schema_content) is
|
|
12
12
|
# typically a Hash (JSON object) or a boolean.
|
|
13
13
|
module Schema
|
|
14
|
-
autoload
|
|
15
|
-
autoload
|
|
14
|
+
autoload(:Element, 'jsi/schema/element')
|
|
15
|
+
autoload(:Vocabulary, 'jsi/schema/vocabulary')
|
|
16
|
+
autoload(:Dialect, 'jsi/schema/dialect')
|
|
17
|
+
autoload(:Cxt, 'jsi/schema/cxt')
|
|
18
|
+
|
|
19
|
+
autoload(:Elements, 'jsi/schema/elements')
|
|
16
20
|
|
|
17
21
|
autoload :Issue, 'jsi/schema/issue'
|
|
18
|
-
autoload
|
|
22
|
+
autoload(:DynamicAnchorMap, 'jsi/schema/dynamic_anchor_map')
|
|
19
23
|
|
|
20
24
|
autoload :SchemaAncestorNode, 'jsi/schema/schema_ancestor_node'
|
|
21
25
|
|
|
22
26
|
autoload :Draft04, 'jsi/schema/draft04'
|
|
23
27
|
autoload :Draft06, 'jsi/schema/draft06'
|
|
24
28
|
autoload :Draft07, 'jsi/schema/draft07'
|
|
25
|
-
|
|
26
|
-
class Error < StandardError
|
|
27
|
-
end
|
|
29
|
+
autoload(:Draft202012, 'jsi/schema/draft202012')
|
|
28
30
|
|
|
29
31
|
# an exception raised when a thing is expected to be a JSI::Schema, but is not
|
|
30
|
-
class NotASchemaError <
|
|
32
|
+
class NotASchemaError < TypeError
|
|
31
33
|
end
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
class ReferenceError < StandardError
|
|
35
|
+
class NotAMetaSchemaError < TypeError
|
|
35
36
|
end
|
|
36
37
|
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# extends any schema which uses the keyword 'id' to identify its canonical URI
|
|
51
|
-
module OldId
|
|
52
|
-
# the contents of an `id` keyword whose value is a string, or nil
|
|
53
|
-
# @return [#to_str, nil]
|
|
54
|
-
def id
|
|
55
|
-
if keyword?('id') && schema_content['id'].respond_to?(:to_str)
|
|
56
|
-
schema_content['id']
|
|
57
|
-
else
|
|
58
|
-
nil
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# extends any schema which defines an anchor as a URI fragment in the schema id
|
|
64
|
-
module IdWithAnchor
|
|
65
|
-
# a URI for the schema's id, unless the id defines an anchor in its
|
|
66
|
-
# fragment. nil if the schema defines no id.
|
|
67
|
-
# @return [Addressable::URI, nil]
|
|
68
|
-
def id_without_fragment
|
|
69
|
-
if id
|
|
70
|
-
id_uri = Util.uri(id)
|
|
71
|
-
if id_uri.merge(fragment: nil).empty?
|
|
72
|
-
# fragment-only id is just an anchor
|
|
73
|
-
# e.g. #foo
|
|
74
|
-
nil
|
|
75
|
-
elsif id_uri.fragment == nil
|
|
76
|
-
# no fragment
|
|
77
|
-
# e.g. http://localhost:1234/bar
|
|
78
|
-
id_uri
|
|
79
|
-
elsif id_uri.fragment == ''
|
|
80
|
-
# empty fragment
|
|
81
|
-
# e.g. http://json-schema.org/draft-07/schema#
|
|
82
|
-
id_uri.merge(fragment: nil).freeze
|
|
83
|
-
elsif jsi_schema_base_uri && jsi_schema_base_uri.join(id_uri).merge(fragment: nil) == jsi_schema_base_uri
|
|
84
|
-
# the id, resolved against the base uri, consists of the base uri plus an anchor fragment.
|
|
85
|
-
# so there's no non-fragment id.
|
|
86
|
-
# e.g. base uri is http://localhost:1234/bar
|
|
87
|
-
# and id is http://localhost:1234/bar#foo
|
|
88
|
-
nil
|
|
89
|
-
else
|
|
90
|
-
# e.g. http://localhost:1234/bar#foo
|
|
91
|
-
id_uri.merge(fragment: nil).freeze
|
|
92
|
-
end
|
|
93
|
-
else
|
|
94
|
-
nil
|
|
95
|
-
end
|
|
38
|
+
# @deprecated alias after v0.8
|
|
39
|
+
# an exception raised when we are unable to resolve a schema reference
|
|
40
|
+
ReferenceError = ResolutionError
|
|
41
|
+
|
|
42
|
+
# A reference to a schema identified by a given URI.
|
|
43
|
+
# {#resolve} will return a Schema, and param `referrer` must be a Schema.
|
|
44
|
+
class Ref < Ref
|
|
45
|
+
# @param ref_schema [Schema] deprecated; use `referrer`
|
|
46
|
+
def initialize(ref, ref_schema: nil, **kw)
|
|
47
|
+
super(ref, referrer: ref_schema, **kw)
|
|
96
48
|
end
|
|
97
49
|
|
|
98
|
-
# an anchor defined by a non-empty fragment in the id uri
|
|
99
|
-
# @return [String]
|
|
100
|
-
def anchor
|
|
101
|
-
if id
|
|
102
|
-
id_uri = Util.uri(id)
|
|
103
|
-
if id_uri.fragment == ''
|
|
104
|
-
nil
|
|
105
|
-
else
|
|
106
|
-
id_uri.fragment
|
|
107
|
-
end
|
|
108
|
-
else
|
|
109
|
-
nil
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
# @private
|
|
115
|
-
module IntegerAllows0Fraction
|
|
116
|
-
# is `value` an integer?
|
|
117
|
-
# @private
|
|
118
|
-
# @param value
|
|
119
50
|
# @return [Boolean]
|
|
120
|
-
def
|
|
121
|
-
|
|
51
|
+
def resolve_schema?
|
|
52
|
+
true
|
|
122
53
|
end
|
|
123
|
-
end
|
|
124
54
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
# @private
|
|
129
|
-
# @param value
|
|
130
|
-
# @return [Boolean]
|
|
131
|
-
def internal_integer?(value)
|
|
132
|
-
value.is_a?(Integer)
|
|
55
|
+
# @deprecated after v0.8
|
|
56
|
+
def deref_schema
|
|
57
|
+
resolve
|
|
133
58
|
end
|
|
134
59
|
end
|
|
135
60
|
|
|
@@ -144,86 +69,80 @@ module JSI
|
|
|
144
69
|
#
|
|
145
70
|
# A schema is indicated as describing other schemas using the {Schema#describes_schema!} method.
|
|
146
71
|
module MetaSchema
|
|
147
|
-
# @return [
|
|
148
|
-
attr_reader(:
|
|
72
|
+
# @return [Schema::Dialect]
|
|
73
|
+
attr_reader(:described_dialect)
|
|
149
74
|
|
|
150
75
|
# Instantiates the given schema content as a JSI Schema.
|
|
151
76
|
#
|
|
152
|
-
# By default, the schema will be registered with the {JSI.
|
|
153
|
-
# This can be controlled by
|
|
77
|
+
# By default, the schema will be registered with the {JSI.registry}.
|
|
78
|
+
# This can be controlled by the `register` param and {Base::Conf#registry `registry`} {Base::Conf configuration}.
|
|
154
79
|
#
|
|
155
80
|
# By default, the `schema_content` will have any Symbol keys of Hashes replaced with Strings
|
|
156
81
|
# (recursively through the document). This is controlled by the param `stringify_symbol_keys`.
|
|
157
82
|
#
|
|
158
83
|
# Schemas instantiated with `new_schema` are immutable, their content transformed using
|
|
159
|
-
# the `to_immutable`
|
|
160
|
-
#
|
|
161
|
-
# @param schema_content an object to be instantiated as a JSI Schema - typically a Hash
|
|
162
|
-
# @param uri [#to_str, Addressable::URI] The retrieval URI of the schema document.
|
|
163
|
-
# If specified, the root schema will be identified by this URI, in addition
|
|
164
|
-
# to any absolute URI declared with an id keyword, for resolution in the `schema_registry`.
|
|
165
|
-
#
|
|
166
|
-
# It is rare that this needs to be specified. Most schemas, if they use absolute URIs, will
|
|
167
|
-
# use the `$id` keyword (`id` in draft 4) to specify this. A different retrieval URI is useful
|
|
168
|
-
# in unusual cases:
|
|
84
|
+
# the {Base::Conf configured} {Base::Conf#to_immutable `to_immutable`}.
|
|
169
85
|
#
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
# - Another schema refers with `$ref` to the schema being instantiated by this retrieval URI,
|
|
173
|
-
# rather than an id declared in the schema - the schema is resolvable by this URI in the
|
|
174
|
-
# `schema_registry`.
|
|
175
|
-
# @param register [Boolean] Whether the instantiated schema and any subschemas with absolute URIs
|
|
176
|
-
# will be registered in the schema registry indicated by param `schema_registry`.
|
|
177
|
-
# @param schema_registry [SchemaRegistry, nil] The registry this schema will use.
|
|
86
|
+
# Parameters are passed to {SchemaSet#new_jsi} and are documented there, but some have
|
|
87
|
+
# different defaults for new_schema.
|
|
178
88
|
#
|
|
179
|
-
#
|
|
180
|
-
#
|
|
181
|
-
#
|
|
182
|
-
# @param stringify_symbol_keys
|
|
183
|
-
#
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
# @yield If a block is given, it is evaluated in the context of the schema's JSI schema module
|
|
187
|
-
# using [Module#module_exec](https://ruby-doc.org/core/Module.html#method-i-module_exec).
|
|
188
|
-
# @return [JSI::Base subclass + JSI::Schema] a JSI which is a {JSI::Schema} whose content comes from
|
|
189
|
-
# the given `schema_content` and whose schemas are this schema's inplace applicators.
|
|
89
|
+
# @param schema_content an object to be instantiated as a JSI Schema - typically a Hash
|
|
90
|
+
# @param base_uri
|
|
91
|
+
# @param register
|
|
92
|
+
# @param stringify_symbol_keys
|
|
93
|
+
# @param conf_kw (see SchemaSet#new_jsi)
|
|
94
|
+
# @return [Base + Schema] A JSI which is a {Schema} whose content comes from
|
|
95
|
+
# the given `schema_content` and whose schemas are this meta-schema's in-place applicators.
|
|
190
96
|
def new_schema(schema_content,
|
|
191
|
-
|
|
97
|
+
base_uri: nil,
|
|
192
98
|
register: true,
|
|
193
|
-
schema_registry: JSI.schema_registry,
|
|
194
99
|
stringify_symbol_keys: true,
|
|
195
|
-
|
|
196
|
-
&block
|
|
100
|
+
**conf_kw
|
|
197
101
|
)
|
|
198
|
-
|
|
199
|
-
|
|
102
|
+
raise(BlockGivenError) if block_given?
|
|
103
|
+
new_jsi(schema_content,
|
|
104
|
+
base_uri: base_uri,
|
|
200
105
|
register: register,
|
|
201
|
-
schema_registry: schema_registry,
|
|
202
106
|
stringify_symbol_keys: stringify_symbol_keys,
|
|
203
|
-
|
|
107
|
+
**conf_kw,
|
|
204
108
|
mutable: false,
|
|
205
109
|
)
|
|
206
|
-
|
|
207
|
-
schema_jsi.jsi_schema_module_exec(&block) if block
|
|
208
|
-
|
|
209
|
-
schema_jsi
|
|
210
110
|
end
|
|
211
111
|
|
|
212
112
|
# Instantiates the given schema content as a JSI Schema, passing all params to
|
|
213
113
|
# {Schema::MetaSchema#new_schema}, and returns its {Schema#jsi_schema_module JSI Schema Module}.
|
|
214
114
|
#
|
|
115
|
+
# @yield If a block is given, it is evaluated in the context of the schema module
|
|
116
|
+
# using [Module#module_exec](https://ruby-doc.org/core/Module.html#method-i-module_exec).
|
|
215
117
|
# @return [JSI::SchemaModule] the JSI Schema Module of the instantiated schema
|
|
216
118
|
def new_schema_module(schema_content, **kw, &block)
|
|
217
|
-
new_schema(schema_content, **kw
|
|
119
|
+
schema_jsi = new_schema(schema_content, **kw)
|
|
120
|
+
schema_jsi.jsi_schema_module_exec(&block) if block
|
|
121
|
+
schema_jsi.jsi_schema_module
|
|
218
122
|
end
|
|
219
123
|
end
|
|
220
124
|
|
|
221
|
-
|
|
125
|
+
# @private
|
|
126
|
+
module ExtendedInitialize
|
|
222
127
|
def extended(o)
|
|
223
128
|
super
|
|
224
129
|
o.send(:jsi_schema_initialize)
|
|
225
130
|
end
|
|
131
|
+
|
|
132
|
+
def included(m)
|
|
133
|
+
super
|
|
134
|
+
return if m.is_a?(Class)
|
|
135
|
+
|
|
136
|
+
# if a module (m) includes Schema, and an object (o) is extended with m,
|
|
137
|
+
# then o should have #jsi_schema_initialize called, but Schema.extended is not called,
|
|
138
|
+
# so m needs its own .extended method to call jsi_schema_initialize.
|
|
139
|
+
# note: extending m with ExtendedInitialize for .extended, rather than m.define_singleton_method(:extended),
|
|
140
|
+
# avoids possibly clobbering an existing singleton .extended method the module has defined.
|
|
141
|
+
m.extend(ExtendedInitialize)
|
|
142
|
+
end
|
|
226
143
|
end
|
|
144
|
+
|
|
145
|
+
extend(ExtendedInitialize)
|
|
227
146
|
end
|
|
228
147
|
|
|
229
148
|
class << self
|
|
@@ -251,8 +170,9 @@ module JSI
|
|
|
251
170
|
#
|
|
252
171
|
# The meta-schema that describes the schema must be indicated:
|
|
253
172
|
#
|
|
254
|
-
# - If the schema object has a `$schema` property, that URI is resolved using the
|
|
255
|
-
#
|
|
173
|
+
# - If the schema object has a `$schema` property, that URI is resolved using the
|
|
174
|
+
# {Base::Conf configured} {Base::Conf#registry `registry`} (by default {JSI.registry JSI.registry}),
|
|
175
|
+
# and that meta-schema is used. For example:
|
|
256
176
|
#
|
|
257
177
|
# ```ruby
|
|
258
178
|
# JSI.new_schema({
|
|
@@ -283,45 +203,44 @@ module JSI
|
|
|
283
203
|
# specifying a `default_metaschema` is to call `new_schema` on the
|
|
284
204
|
# {Schema::MetaSchema#new_schema meta-schema} or its
|
|
285
205
|
# {SchemaModule::MetaSchemaModule#new_schema schema module}, e.g.
|
|
286
|
-
# `JSI::JSONSchemaDraft07.new_schema(my_schema_content)`
|
|
206
|
+
# `JSI::JSONSchemaDraft07.new_schema(my_schema_content)`. This will ignore any `$schema` keyword
|
|
207
|
+
# that may be present.
|
|
287
208
|
#
|
|
288
209
|
# Schemas instantiated with `new_schema` are immutable, their content transformed using
|
|
289
|
-
# the `to_immutable`
|
|
210
|
+
# the {Base::Conf configured} {Base::Conf#to_immutable `to_immutable`}.
|
|
211
|
+
#
|
|
212
|
+
# Most parameters are passed to {SchemaSet#new_jsi} and are documented there, but some have
|
|
213
|
+
# different defaults for JSI.new_schema.
|
|
290
214
|
#
|
|
291
215
|
# @param schema_content (see Schema::MetaSchema#new_schema)
|
|
292
216
|
# @param default_metaschema [Schema::MetaSchema, SchemaModule::MetaSchemaModule, #to_str]
|
|
293
217
|
# Indicates the meta-schema to use if the given `schema_content` does not have a `$schema` property.
|
|
294
218
|
# This may be a meta-schema or a meta-schema's schema module (e.g. `JSI::JSONSchemaDraft07`),
|
|
295
219
|
# or a URI (as would be in a `$schema` keyword).
|
|
296
|
-
# @param
|
|
297
|
-
# @param register
|
|
298
|
-
# @param
|
|
299
|
-
# @param
|
|
300
|
-
# @
|
|
301
|
-
#
|
|
302
|
-
# @return [JSI::Base subclass + JSI::Schema] a JSI which is a {JSI::Schema} whose content comes from
|
|
303
|
-
# the given `schema_content` and whose schemas are inplace applicators of the indicated meta-schema
|
|
220
|
+
# @param base_uri
|
|
221
|
+
# @param register
|
|
222
|
+
# @param stringify_symbol_keys
|
|
223
|
+
# @param conf_kw (see SchemaSet#new_jsi)
|
|
224
|
+
# @return [Base + Schema] A JSI which is a {Schema} whose content comes from
|
|
225
|
+
# the given `schema_content` and whose schemas are in-place applicators of the indicated meta-schema.
|
|
304
226
|
def new_schema(schema_content,
|
|
305
227
|
default_metaschema: nil,
|
|
306
|
-
|
|
307
|
-
# would remove repetition, but yard doesn't display delegated defaults with its (see X) directive.
|
|
308
|
-
uri: nil,
|
|
228
|
+
base_uri: nil,
|
|
309
229
|
register: true,
|
|
310
|
-
schema_registry: JSI.schema_registry,
|
|
311
230
|
stringify_symbol_keys: true,
|
|
312
|
-
|
|
313
|
-
&block
|
|
231
|
+
**conf_kw
|
|
314
232
|
)
|
|
233
|
+
raise(BlockGivenError) if block_given?
|
|
315
234
|
new_schema_params = {
|
|
316
|
-
|
|
235
|
+
base_uri: base_uri,
|
|
317
236
|
register: register,
|
|
318
|
-
schema_registry: schema_registry,
|
|
319
237
|
stringify_symbol_keys: stringify_symbol_keys,
|
|
320
|
-
|
|
238
|
+
**conf_kw,
|
|
321
239
|
}
|
|
240
|
+
conf = Base::Conf.new(**conf_kw) # some redundancy instantiating this - not passed to MetaSchema#new_schema, just used in this method
|
|
322
241
|
default_metaschema_new_schema = -> {
|
|
323
242
|
default_metaschema = if default_metaschema
|
|
324
|
-
Schema.ensure_metaschema(default_metaschema, name: "default_metaschema")
|
|
243
|
+
Schema.ensure_metaschema(default_metaschema, name: "default_metaschema", registry: conf.registry)
|
|
325
244
|
elsif self.default_metaschema
|
|
326
245
|
self.default_metaschema
|
|
327
246
|
else
|
|
@@ -336,7 +255,7 @@ module JSI
|
|
|
336
255
|
"instantiating schema_content: #{schema_content.pretty_inspect.chomp}",
|
|
337
256
|
].join("\n"))
|
|
338
257
|
end
|
|
339
|
-
default_metaschema.new_schema(schema_content, **new_schema_params
|
|
258
|
+
default_metaschema.new_schema(schema_content, **new_schema_params)
|
|
340
259
|
}
|
|
341
260
|
if schema_content.is_a?(Schema)
|
|
342
261
|
raise(TypeError, [
|
|
@@ -354,8 +273,8 @@ module JSI
|
|
|
354
273
|
unless id.respond_to?(:to_str)
|
|
355
274
|
raise(ArgumentError, "given schema_content keyword `$schema` is not a string")
|
|
356
275
|
end
|
|
357
|
-
metaschema = Schema.ensure_metaschema(id, name: '$schema',
|
|
358
|
-
metaschema.new_schema(schema_content, **new_schema_params
|
|
276
|
+
metaschema = Schema.ensure_metaschema(id, name: '$schema', registry: conf.registry)
|
|
277
|
+
metaschema.new_schema(schema_content, **new_schema_params)
|
|
359
278
|
else
|
|
360
279
|
default_metaschema_new_schema.call
|
|
361
280
|
end
|
|
@@ -372,11 +291,10 @@ module JSI
|
|
|
372
291
|
# ensure the given object is a JSI Schema
|
|
373
292
|
#
|
|
374
293
|
# @param schema [Object] the thing the caller wishes to ensure is a Schema
|
|
375
|
-
# @
|
|
376
|
-
# if the schema param is not a schema
|
|
294
|
+
# @yieldreturn [#to_s, #to_ary] first line(s) of the error message, overriding the default
|
|
377
295
|
# @raise [NotASchemaError] if the schema param is not a schema
|
|
378
296
|
# @return [Schema] the given schema
|
|
379
|
-
def ensure_schema(schema,
|
|
297
|
+
def ensure_schema(schema, reinstantiate_as: nil)
|
|
380
298
|
if schema.is_a?(Schema)
|
|
381
299
|
schema
|
|
382
300
|
else
|
|
@@ -384,27 +302,33 @@ module JSI
|
|
|
384
302
|
# TODO warn; behavior is undefined and I hate this implementation
|
|
385
303
|
|
|
386
304
|
result_schema_indicated_schemas = SchemaSet.new(schema.jsi_indicated_schemas + reinstantiate_as)
|
|
387
|
-
result_schema_applied_schemas = result_schema_indicated_schemas.
|
|
305
|
+
result_schema_applied_schemas = result_schema_indicated_schemas.each_yield_set do |is, y|
|
|
306
|
+
is.each_inplace_applicator_schema(schema.jsi_node_content, &y)
|
|
307
|
+
end
|
|
388
308
|
|
|
389
309
|
result_schema_class = JSI::SchemaClasses.class_for_schemas(result_schema_applied_schemas,
|
|
390
310
|
includes: SchemaClasses.includes_for(schema.jsi_node_content),
|
|
391
311
|
mutable: schema.jsi_mutable?,
|
|
392
312
|
)
|
|
393
313
|
|
|
394
|
-
result_schema_class.new(
|
|
314
|
+
result_schema_class.new(
|
|
315
|
+
jsi_document: schema.jsi_document,
|
|
395
316
|
jsi_ptr: schema.jsi_ptr,
|
|
396
317
|
jsi_indicated_schemas: result_schema_indicated_schemas,
|
|
397
|
-
|
|
318
|
+
jsi_base_uri: schema.jsi_base_uri,
|
|
398
319
|
jsi_schema_resource_ancestors: schema.jsi_schema_resource_ancestors,
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
jsi_root_node: schema.
|
|
402
|
-
)
|
|
320
|
+
jsi_schema_dynamic_anchor_map: schema.jsi_schema_dynamic_anchor_map,
|
|
321
|
+
jsi_conf: schema.equal?(schema.jsi_root_node) ? schema.jsi_conf : nil,
|
|
322
|
+
jsi_root_node: schema.equal?(schema.jsi_root_node) ? nil : schema.jsi_root_node, # bad
|
|
323
|
+
).send(:jsi_initialized)
|
|
403
324
|
else
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
325
|
+
msg = []
|
|
326
|
+
msg.concat([*(block_given? ? yield : "indicated object is not a schema:")])
|
|
327
|
+
msg << schema.pretty_inspect.chomp
|
|
328
|
+
if schema.is_a?(Base)
|
|
329
|
+
msg << "its schemas (which should include a Meta-Schema): #{schema.jsi_schemas.pretty_inspect.chomp}"
|
|
330
|
+
end
|
|
331
|
+
raise(NotASchemaError, msg.compact.join("\n"))
|
|
408
332
|
end
|
|
409
333
|
end
|
|
410
334
|
end
|
|
@@ -415,11 +339,11 @@ module JSI
|
|
|
415
339
|
# @param metaschema [Schema::MetaSchema, SchemaModule::MetaSchemaModule, #to_str]
|
|
416
340
|
# @raise [TypeError] if the param does not indicate a meta-schema
|
|
417
341
|
# @return [Base + Schema + Schema::MetaSchema]
|
|
418
|
-
def ensure_metaschema(metaschema, name: nil,
|
|
342
|
+
def ensure_metaschema(metaschema, name: nil, registry: JSI.registry)
|
|
419
343
|
if metaschema.respond_to?(:to_str)
|
|
420
|
-
schema = Schema::Ref.new(metaschema,
|
|
344
|
+
schema = Schema::Ref.new(metaschema, registry: registry).resolve
|
|
421
345
|
if !schema.describes_schema?
|
|
422
|
-
raise(
|
|
346
|
+
raise(NotAMetaSchemaError, [name, "URI indicates a schema that is not a meta-schema: #{metaschema.pretty_inspect.chomp}"].compact.join(" "))
|
|
423
347
|
end
|
|
424
348
|
schema
|
|
425
349
|
elsif metaschema.is_a?(SchemaModule::MetaSchemaModule)
|
|
@@ -427,7 +351,7 @@ module JSI
|
|
|
427
351
|
elsif metaschema.is_a?(Schema::MetaSchema)
|
|
428
352
|
metaschema
|
|
429
353
|
else
|
|
430
|
-
raise(
|
|
354
|
+
raise(NotAMetaSchemaError, "#{name || "param"} does not indicate a meta-schema: #{metaschema.pretty_inspect.chomp}")
|
|
431
355
|
end
|
|
432
356
|
end
|
|
433
357
|
end
|
|
@@ -444,6 +368,12 @@ module JSI
|
|
|
444
368
|
end
|
|
445
369
|
end
|
|
446
370
|
|
|
371
|
+
# @!method dialect
|
|
372
|
+
# The dialect of this schema
|
|
373
|
+
# @return [Schema::Dialect]
|
|
374
|
+
# note: defined on a meta-schema's schema module by Schema#describes_schema!
|
|
375
|
+
|
|
376
|
+
|
|
447
377
|
# the underlying JSON data used to instantiate this JSI::Schema.
|
|
448
378
|
# this is an alias for {Base#jsi_node_content}, named for clarity in the context of working with
|
|
449
379
|
# a schema.
|
|
@@ -458,83 +388,93 @@ module JSI
|
|
|
458
388
|
schema_content.respond_to?(:to_hash) && schema_content.key?(keyword)
|
|
459
389
|
end
|
|
460
390
|
|
|
461
|
-
#
|
|
462
|
-
# @return [
|
|
391
|
+
# Does this schema contain the given keyword with the given value?
|
|
392
|
+
# @return [Boolean]
|
|
393
|
+
def keyword_value?(keyword, value)
|
|
394
|
+
keyword?(keyword) && schema_content[keyword] == value
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# the string contents of an `$id`/`id` keyword, or nil
|
|
398
|
+
# @return [#to_str, nil]
|
|
399
|
+
def id
|
|
400
|
+
dialect_invoke_each(:id).first
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
# @return [Enumerable<String>]
|
|
404
|
+
def anchors
|
|
405
|
+
anchors = Set[]
|
|
406
|
+
anchors.merge(dialect_invoke_each(:anchor))
|
|
407
|
+
anchors.merge(dialect_invoke_each(:dynamicAnchor))
|
|
408
|
+
anchors.freeze
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
# the URI of this schema, from an `$id` keyword, resolved against our `#jsi_base_uri`
|
|
412
|
+
# @deprecated after v0.8 - use `#jsi_resource_uri`
|
|
413
|
+
# @return [URI, nil]
|
|
463
414
|
def schema_absolute_uri
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
415
|
+
jsi_resource_uri
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# @deprecated after v0.8 - use `#jsi_resource_uris`
|
|
419
|
+
# @return [Enumerable<URI>]
|
|
420
|
+
def schema_absolute_uris
|
|
421
|
+
jsi_resource_uris
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# @yield [URI]
|
|
425
|
+
private def jsi_each_resource_uri_compute
|
|
426
|
+
dialect_invoke_each(:id_without_fragment) do |id_without_fragment|
|
|
427
|
+
if jsi_base_uri
|
|
428
|
+
yield(jsi_base_uri.join(id_without_fragment))
|
|
467
429
|
elsif id_without_fragment.absolute?
|
|
468
|
-
id_without_fragment
|
|
469
|
-
else
|
|
470
|
-
# TODO warn / schema_error
|
|
471
|
-
nil
|
|
430
|
+
yield(id_without_fragment)
|
|
472
431
|
end
|
|
473
432
|
end
|
|
433
|
+
super
|
|
474
434
|
end
|
|
475
435
|
|
|
476
436
|
# a nonrelative URI which refers to this schema.
|
|
477
437
|
# `nil` if no ancestor of this schema defines an id.
|
|
478
438
|
# see {#schema_uris} for all URIs known to refer to this schema.
|
|
479
|
-
# @return [
|
|
439
|
+
# @return [URI, nil]
|
|
480
440
|
def schema_uri
|
|
481
441
|
schema_uris.first
|
|
482
442
|
end
|
|
483
443
|
|
|
484
444
|
# nonrelative URIs (that is, absolute, but possibly with a fragment) which refer to this schema
|
|
485
|
-
# @return [Array<
|
|
445
|
+
# @return [Array<URI>]
|
|
486
446
|
def schema_uris
|
|
487
|
-
@schema_uris_map[]
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
private def schema_uris_compute(**_) # TODO remove **_ eventually (keyword argument compatibility)
|
|
491
|
-
each_schema_uri.to_a
|
|
447
|
+
@schema_uris_map[schema_content: schema_content]
|
|
492
448
|
end
|
|
493
449
|
|
|
494
|
-
#
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
def each_schema_uri
|
|
498
|
-
return to_enum(__method__) unless block_given?
|
|
499
|
-
|
|
500
|
-
yield schema_absolute_uri if schema_absolute_uri
|
|
501
|
-
|
|
502
|
-
ancestor_schemas = jsi_subschema_resource_ancestors.reverse_each.select do |resource|
|
|
503
|
-
resource.schema_absolute_uri
|
|
504
|
-
end
|
|
450
|
+
# @yield [URI]
|
|
451
|
+
private def schema_uris_compute(&block)
|
|
452
|
+
jsi_resource_uris.each(&block)
|
|
505
453
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
yield(ancestor_schema.schema_absolute_uri.merge(fragment: anchor).freeze)
|
|
511
|
-
else
|
|
512
|
-
anchored = false
|
|
454
|
+
if jsi_resource_root
|
|
455
|
+
anchors.each do |anchor|
|
|
456
|
+
jsi_resource_root.jsi_resource_uris.each do |uri|
|
|
457
|
+
yield(uri.merge(fragment: anchor))
|
|
513
458
|
end
|
|
514
459
|
end
|
|
460
|
+
end
|
|
515
461
|
|
|
462
|
+
jsi_subschema_resource_ancestors.reverse_each do |ancestor_schema|
|
|
516
463
|
relative_ptr = jsi_ptr.relative_to(ancestor_schema.jsi_ptr)
|
|
517
|
-
|
|
464
|
+
ancestor_schema.jsi_resource_uris.each do |uri|
|
|
465
|
+
yield(uri.merge(fragment: relative_ptr.fragment))
|
|
466
|
+
end
|
|
518
467
|
end
|
|
519
468
|
|
|
520
469
|
nil
|
|
521
470
|
end
|
|
522
471
|
|
|
523
|
-
#
|
|
524
|
-
#
|
|
525
|
-
#
|
|
526
|
-
# some functionality is also defined on the module itself (its singleton class, not for its instances):
|
|
527
|
-
#
|
|
528
|
-
# - the module is extended with {JSI::SchemaModule}, which defines .new_jsi to instantiate instances
|
|
529
|
-
# of this schema (see {#new_jsi}).
|
|
530
|
-
# - properties described by this schema's metaschema are defined as methods to get subschemas' schema
|
|
531
|
-
# modules, so for example `schema.jsi_schema_module.items` returns the same module
|
|
532
|
-
# as `schema.items.jsi_schema_module`.
|
|
533
|
-
# - method .schema which returns this schema.
|
|
472
|
+
# The {SchemaModule JSI Schema Module} for this schema.
|
|
473
|
+
# JSI instances described by this schema are instances of this module.
|
|
534
474
|
#
|
|
535
475
|
# @return [SchemaModule]
|
|
536
476
|
def jsi_schema_module
|
|
537
|
-
|
|
477
|
+
jsi_schema_module_connection
|
|
538
478
|
end
|
|
539
479
|
|
|
540
480
|
# Evaluates the given block in the context of this schema's JSI schema module.
|
|
@@ -547,28 +487,40 @@ module JSI
|
|
|
547
487
|
jsi_schema_module.module_exec(*a, **kw, &block)
|
|
548
488
|
end
|
|
549
489
|
|
|
490
|
+
# @return [String, nil]
|
|
491
|
+
def jsi_schema_module_name
|
|
492
|
+
# don't hit #jsi_schema_module - avoid creating module, avoid erroring for MSN::BootstrapSchema
|
|
493
|
+
@memos[:schema_module_connection] && @memos[:schema_module_connection].name
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
# @return [String, nil]
|
|
497
|
+
def jsi_schema_module_name_from_ancestor
|
|
498
|
+
is_a?(Base) ? jsi_schema_module.name_from_ancestor : nil
|
|
499
|
+
end
|
|
500
|
+
|
|
550
501
|
# Instantiates a new JSI whose content comes from the given `instance` param.
|
|
551
|
-
# This schema indicates the schemas of the JSI - its schemas are
|
|
502
|
+
# This schema indicates the schemas of the JSI - its schemas are in-place
|
|
552
503
|
# applicators of this schema which apply to the given instance.
|
|
553
504
|
#
|
|
554
|
-
#
|
|
555
|
-
#
|
|
556
|
-
#
|
|
505
|
+
# All parameters are passed to {SchemaSet#new_jsi}.
|
|
506
|
+
#
|
|
507
|
+
# @return [Base] a JSI whose content comes from the given instance and whose schemas are
|
|
508
|
+
# in-place applicators of this schema.
|
|
557
509
|
def new_jsi(instance, **kw)
|
|
510
|
+
raise(BlockGivenError) if block_given?
|
|
558
511
|
SchemaSet[self].new_jsi(instance, **kw)
|
|
559
512
|
end
|
|
560
513
|
|
|
561
|
-
# @param
|
|
514
|
+
# @param ref [#to_str] ref URI
|
|
562
515
|
# @return [Schema::Ref]
|
|
563
|
-
def schema_ref(
|
|
564
|
-
|
|
565
|
-
@schema_ref_map[keyword: keyword, value: schema_content[keyword]]
|
|
516
|
+
def schema_ref(ref = schema_content["$ref"])
|
|
517
|
+
@schema_ref_map[ref]
|
|
566
518
|
end
|
|
567
519
|
|
|
568
520
|
# Does this schema itself describe a schema? I.e. is this schema a meta-schema?
|
|
569
521
|
# @return [Boolean]
|
|
570
522
|
def describes_schema?
|
|
571
|
-
|
|
523
|
+
is_a?(Schema::MetaSchema)
|
|
572
524
|
end
|
|
573
525
|
|
|
574
526
|
# Is this a JSI Schema?
|
|
@@ -580,30 +532,36 @@ module JSI
|
|
|
580
532
|
# Indicates that this schema describes schemas, i.e. it is a meta-schema.
|
|
581
533
|
# this schema is extended with {Schema::MetaSchema} and its {#jsi_schema_module} is extended
|
|
582
534
|
# with {SchemaModule::MetaSchemaModule}, and the JSI Schema Module will include
|
|
583
|
-
# JSI::Schema
|
|
535
|
+
# JSI::Schema.
|
|
584
536
|
#
|
|
585
|
-
# @param
|
|
586
|
-
# the schema to extend schemas described by this schema.
|
|
537
|
+
# @param dialect [Schema::Dialect, nil] dialect may be passed, or inferred from `$vocabulary`
|
|
587
538
|
# @return [void]
|
|
588
|
-
def describes_schema!(
|
|
589
|
-
|
|
539
|
+
def describes_schema!(dialect = nil)
|
|
540
|
+
# TODO rm bridge code hax
|
|
541
|
+
dialect = dialect.first::DIALECT if dialect.is_a?(Array) && dialect.size == 1
|
|
542
|
+
|
|
543
|
+
if !dialect
|
|
544
|
+
raise(ArgumentError, "no dialect given and no $vocabulary hash/object") if !schema_content['$vocabulary'].respond_to?(:to_hash)
|
|
545
|
+
dialect = Schema::Dialect.from_xvocabulary(schema_content['$vocabulary'], registry: jsi_registry)
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
raise(TypeError) if !dialect.is_a?(Schema::Dialect)
|
|
590
549
|
|
|
591
|
-
if
|
|
592
|
-
# this schema
|
|
550
|
+
if jsi_schema_module <= Schema
|
|
551
|
+
# this schema has already had describes_schema! called on it.
|
|
593
552
|
# this is to be avoided, but is not particularly a problem.
|
|
594
|
-
# it is a bug if it was called different times with different
|
|
595
|
-
|
|
596
|
-
raise(ArgumentError, "this schema already describes a schema with different
|
|
553
|
+
# it is a bug if it was called different times with different dialect, though.
|
|
554
|
+
if @described_dialect != dialect
|
|
555
|
+
raise(ArgumentError, "this schema already describes a schema with different dialect")
|
|
597
556
|
end
|
|
598
557
|
else
|
|
599
558
|
jsi_schema_module.include(Schema)
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
end
|
|
559
|
+
jsi_schema_module.send(:define_method, :dialect) { dialect }
|
|
560
|
+
proc { |metaschema| jsi_schema_module.send(:define_method, :metaschema) { metaschema } }[self]
|
|
603
561
|
jsi_schema_module.extend(SchemaModule::MetaSchemaModule)
|
|
604
562
|
end
|
|
605
563
|
|
|
606
|
-
@
|
|
564
|
+
@described_dialect = dialect
|
|
607
565
|
extend(Schema::MetaSchema)
|
|
608
566
|
|
|
609
567
|
nil
|
|
@@ -617,15 +575,21 @@ module JSI
|
|
|
617
575
|
# If no ancestor schema has an absolute uri, the schema_resource_root is the {Base#jsi_root_node document's root node}.
|
|
618
576
|
# In this case, the resource root may or may not be a schema itself.
|
|
619
577
|
#
|
|
578
|
+
# @deprecated after v0.8
|
|
620
579
|
# @return [JSI::Base] resource containing this schema
|
|
621
580
|
def schema_resource_root
|
|
622
|
-
|
|
581
|
+
jsi_resource_root
|
|
623
582
|
end
|
|
624
583
|
|
|
625
584
|
# is this schema the root of a schema resource?
|
|
626
585
|
# @return [Boolean]
|
|
586
|
+
def jsi_is_resource_root?
|
|
587
|
+
super || jsi_resource_uris.any?
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
# @deprecated after v0.8
|
|
627
591
|
def schema_resource_root?
|
|
628
|
-
|
|
592
|
+
jsi_is_resource_root?
|
|
629
593
|
end
|
|
630
594
|
|
|
631
595
|
# a subschema of this Schema
|
|
@@ -633,78 +597,202 @@ module JSI
|
|
|
633
597
|
# @param subptr [JSI::Ptr, #to_ary] a relative pointer, or array of tokens, pointing to the subschema
|
|
634
598
|
# @return [JSI::Schema] the subschema at the location indicated by subptr. self if subptr is empty.
|
|
635
599
|
def subschema(subptr)
|
|
636
|
-
|
|
637
|
-
Schema.ensure_schema(jsi_descendent_node(subptr), msg: [
|
|
638
|
-
"subschema is not a schema at pointer: #{subptr.pointer}"
|
|
639
|
-
])
|
|
600
|
+
Schema.ensure_schema(jsi_descendent_node(subptr)) { "subschema is not a schema at pointer: #{Ptr.ary_ptr(subptr).pointer}" }
|
|
640
601
|
end
|
|
641
602
|
|
|
642
|
-
#
|
|
603
|
+
# A schema in the same schema resource as this one (see {Schema::SchemaAncestorNode#jsi_resource_root}) at the given
|
|
643
604
|
# pointer relative to the root of the schema resource.
|
|
644
605
|
#
|
|
645
606
|
# @param ptr [JSI::Ptr, #to_ary] a pointer to a schema from our schema resource root
|
|
646
607
|
# @return [JSI::Schema] the schema pointed to by ptr
|
|
647
608
|
def resource_root_subschema(ptr)
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
reinstantiate_as: jsi_schemas.select(&:describes_schema?)
|
|
609
|
+
Schema.ensure_schema(jsi_resource_root.jsi_descendent_node(ptr),
|
|
610
|
+
reinstantiate_as: jsi_conf.reinstantiate_nonschemas && jsi_schemas.select(&:describes_schema?),
|
|
651
611
|
)
|
|
652
612
|
end
|
|
653
613
|
|
|
654
|
-
#
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
614
|
+
# @yield [Schema]
|
|
615
|
+
def jsi_each_descendent_schema(&block)
|
|
616
|
+
return(to_enum(__method__)) unless block_given?
|
|
617
|
+
|
|
618
|
+
yield(self)
|
|
619
|
+
dialect_invoke_each(:subschema) { |ptr| subschema(ptr).jsi_each_descendent_schema(&block) }
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
# yields each descendent of this node (including itself) within the same resource that is a Schema
|
|
623
|
+
# @yield [Schema]
|
|
624
|
+
def jsi_each_descendent_schema_same_resource(&block)
|
|
625
|
+
return(to_enum(__method__)) unless block_given?
|
|
626
|
+
|
|
627
|
+
yield(self)
|
|
628
|
+
dialect_invoke_each(:subschema) do |ptr|
|
|
629
|
+
desc = subschema(ptr)
|
|
630
|
+
if !desc.jsi_is_resource_root?
|
|
631
|
+
desc.jsi_each_descendent_schema_same_resource(&block)
|
|
632
|
+
end
|
|
633
|
+
end
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
# @yield [Ptr]
|
|
637
|
+
def each_immediate_subschema_ptr
|
|
638
|
+
return(to_enum(__method__)) unless block_given?
|
|
639
|
+
|
|
640
|
+
dialect_invoke_each(:subschema) { |ptr| yield(Ptr.ary_ptr(ptr)) }
|
|
663
641
|
end
|
|
664
642
|
|
|
665
|
-
#
|
|
643
|
+
# @private
|
|
644
|
+
# @yield each in-place applicator schema and params yielded from action :inplace_applicate
|
|
645
|
+
def each_immediate_inplace_applicator_schema(
|
|
646
|
+
instance: ,
|
|
647
|
+
visited_refs: ,
|
|
648
|
+
collect_evaluated: ,
|
|
649
|
+
&block
|
|
650
|
+
)
|
|
651
|
+
# if collect_evaluated, applicators must validate the instance to set `evaluated`
|
|
652
|
+
if collect_evaluated || @inplace_application_requires_instance
|
|
653
|
+
dialect_invoke_each(:inplace_applicate, Cxt::InplaceApplication::WithInstance,
|
|
654
|
+
instance: instance,
|
|
655
|
+
visited_refs: visited_refs,
|
|
656
|
+
collect_evaluated: collect_evaluated,
|
|
657
|
+
&block
|
|
658
|
+
)
|
|
659
|
+
else
|
|
660
|
+
# memoize: if the instance is not used by any in-place applicator present in this schema,
|
|
661
|
+
# the schema can do in-place application once instead of for every instance,
|
|
662
|
+
# for a very substantial performance gain.
|
|
663
|
+
#
|
|
664
|
+
# :inplace_applicate yields (schema, **keywords)
|
|
665
|
+
# so @memos[:immediate_inplace_applicators] is a 2D Array of tuples (schema, keywords)
|
|
666
|
+
@memos[:immediate_inplace_applicators] ||= begin
|
|
667
|
+
immediate_inplace_applicators = []
|
|
668
|
+
dialect_invoke_each(:inplace_applicate, Cxt::InplaceApplication,
|
|
669
|
+
visited_refs: visited_refs,
|
|
670
|
+
) do |s, **kw|
|
|
671
|
+
immediate_inplace_applicators.push([s, kw])
|
|
672
|
+
end
|
|
673
|
+
immediate_inplace_applicators.freeze
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
@memos[:immediate_inplace_applicators].each do |(s, kw)|
|
|
677
|
+
yield(s, **kw)
|
|
678
|
+
end
|
|
679
|
+
nil
|
|
680
|
+
end
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
# Yields each in-place applicator schema which applies to the given instance.
|
|
666
684
|
#
|
|
667
|
-
# @param instance
|
|
685
|
+
# @param instance [Object] the instance to check any applicators against
|
|
668
686
|
# @param visited_refs [Enumerable<JSI::Schema::Ref>]
|
|
669
687
|
# @yield [JSI::Schema]
|
|
670
|
-
# @return [nil
|
|
688
|
+
# @return [nil]
|
|
671
689
|
def each_inplace_applicator_schema(
|
|
672
690
|
instance,
|
|
673
691
|
visited_refs: Util::EMPTY_ARY,
|
|
674
692
|
&block
|
|
675
693
|
)
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
694
|
+
each_immediate_inplace_applicator_schema(
|
|
695
|
+
instance: instance,
|
|
696
|
+
visited_refs: visited_refs,
|
|
697
|
+
collect_evaluated: false, # child application is not invoked so no evaluated children to collect
|
|
698
|
+
) do |schema, ref: nil, applicate: true|
|
|
699
|
+
if schema.equal?(self) && !ref
|
|
700
|
+
yield(self)
|
|
701
|
+
elsif applicate
|
|
702
|
+
schema.each_inplace_applicator_schema(
|
|
703
|
+
instance,
|
|
704
|
+
visited_refs: Util.add_visited_ref(visited_refs, ref),
|
|
705
|
+
&block
|
|
706
|
+
)
|
|
707
|
+
end
|
|
680
708
|
end
|
|
681
|
-
|
|
682
|
-
nil
|
|
683
|
-
end
|
|
684
|
-
|
|
685
|
-
# a set of child applicator subschemas of this schema which apply to the child of the given instance
|
|
686
|
-
# on the given token.
|
|
687
|
-
#
|
|
688
|
-
# @param token [Object] the array index or object property name for the child instance
|
|
689
|
-
# @param instance [Object] the instance to check any child applicators against
|
|
690
|
-
# @return [JSI::SchemaSet] child applicator subschemas of this schema for the given token
|
|
691
|
-
# of the instance
|
|
692
|
-
def child_applicator_schemas(token, instance)
|
|
693
|
-
SchemaSet.new(each_child_applicator_schema(token, instance))
|
|
694
709
|
end
|
|
695
710
|
|
|
696
711
|
# yields each child applicator subschema (from properties, items, etc.) which applies to the child of
|
|
697
712
|
# the given instance on the given token.
|
|
698
713
|
#
|
|
699
|
-
# @param
|
|
714
|
+
# @param token [Object] the array index or object property name for the child instance
|
|
715
|
+
# @param instance [Object] the instance to check any child applicators against
|
|
700
716
|
# @yield [JSI::Schema]
|
|
701
717
|
# @return [nil, Enumerator] an Enumerator if invoked without a block; otherwise nil
|
|
702
718
|
def each_child_applicator_schema(token, instance, &block)
|
|
703
|
-
|
|
719
|
+
dialect_invoke_each(:child_applicate,
|
|
720
|
+
Cxt::ChildApplication,
|
|
721
|
+
instance: instance,
|
|
722
|
+
token: token,
|
|
723
|
+
collect_evaluated: false,
|
|
724
|
+
collect_evaluated_validate: false,
|
|
725
|
+
evaluated: false,
|
|
726
|
+
&block
|
|
727
|
+
)
|
|
728
|
+
end
|
|
729
|
+
|
|
730
|
+
# For each in-place applicator schema that applies to the given instance, yields each child applicator
|
|
731
|
+
# of that schema that applies to the child of the instance on the given token.
|
|
732
|
+
#
|
|
733
|
+
# This method handles collection of whether the child was evaluated by any applicator
|
|
734
|
+
# when that evaluation is needed by either this schema or the caller (per param `collect_evaluated`).
|
|
735
|
+
# This is relevant to schemas containing `unevaluatedProperties` or `unevaluatedItems`.
|
|
736
|
+
#
|
|
737
|
+
# @param token [Object] array index or hash/object property name
|
|
738
|
+
# @param instance [Object]
|
|
739
|
+
# @param collect_evaluated [Boolean] Does the caller need this method to collect successful child evaluation?
|
|
740
|
+
# Note: this method will still collect child evaluation if this schema needs it; this only needs to be
|
|
741
|
+
# passed true when called by an in-place applicator schema that needs it (i.e. contains `unevaluated*`).
|
|
742
|
+
# @param collect_evaluated_validate [Boolean] See {Base::Conf#application_collect_evaluated_validate}
|
|
743
|
+
# @yield [Schema]
|
|
744
|
+
# @return [Boolean] if `collect_evaluated` is true, whether the child was successfully evaluated
|
|
745
|
+
# by a child applicator schema. if `collect_evaluated` is false, undefined/void.
|
|
746
|
+
def each_inplace_child_applicator_schema(
|
|
747
|
+
token,
|
|
748
|
+
instance,
|
|
749
|
+
visited_refs: Util::EMPTY_ARY,
|
|
750
|
+
collect_evaluated: false,
|
|
751
|
+
collect_evaluated_validate: false,
|
|
752
|
+
&block
|
|
753
|
+
)
|
|
754
|
+
collect_evaluated ||= application_requires_evaluated
|
|
755
|
+
inplace_child_evaluated = false
|
|
756
|
+
applicate_self = false
|
|
704
757
|
|
|
705
|
-
|
|
758
|
+
each_immediate_inplace_applicator_schema(
|
|
759
|
+
instance: instance,
|
|
760
|
+
visited_refs: visited_refs,
|
|
761
|
+
collect_evaluated: collect_evaluated,
|
|
762
|
+
) do |schema, ref: nil, applicate: true|
|
|
763
|
+
if schema.equal?(self) && !ref
|
|
764
|
+
applicate_self = true
|
|
765
|
+
elsif applicate || (collect_evaluated && !inplace_child_evaluated)
|
|
766
|
+
schema_evaluated = schema.each_inplace_child_applicator_schema(
|
|
767
|
+
token,
|
|
768
|
+
instance,
|
|
769
|
+
visited_refs: Util.add_visited_ref(visited_refs, ref),
|
|
770
|
+
collect_evaluated: collect_evaluated && !inplace_child_evaluated,
|
|
771
|
+
collect_evaluated_validate: collect_evaluated_validate,
|
|
772
|
+
# the `if` keyword needs to yield to here because it does affect `evaluated`,
|
|
773
|
+
# but it does not applicate itself/its applicators, so does not yield to the given block.
|
|
774
|
+
&(applicate ? block : proc { })
|
|
775
|
+
)
|
|
776
|
+
inplace_child_evaluated ||= collect_evaluated && schema_evaluated && (!collect_evaluated_validate || schema.instance_valid?(instance))
|
|
777
|
+
end
|
|
778
|
+
end
|
|
706
779
|
|
|
707
|
-
|
|
780
|
+
if applicate_self
|
|
781
|
+
child_application = dialect.invoke(:child_applicate, Cxt::ChildApplication.new(
|
|
782
|
+
schema: self,
|
|
783
|
+
abort: false,
|
|
784
|
+
token: token,
|
|
785
|
+
instance: instance,
|
|
786
|
+
collect_evaluated: collect_evaluated,
|
|
787
|
+
collect_evaluated_validate: collect_evaluated_validate,
|
|
788
|
+
evaluated: inplace_child_evaluated,
|
|
789
|
+
block: block,
|
|
790
|
+
))
|
|
791
|
+
|
|
792
|
+
child_application.evaluated
|
|
793
|
+
else
|
|
794
|
+
inplace_child_evaluated
|
|
795
|
+
end
|
|
708
796
|
end
|
|
709
797
|
|
|
710
798
|
# any object property names this schema indicates may be present on its instances.
|
|
@@ -712,24 +800,13 @@ module JSI
|
|
|
712
800
|
# array of "required" property keys.
|
|
713
801
|
# @return [Set]
|
|
714
802
|
def described_object_property_names
|
|
715
|
-
@described_object_property_names_map[]
|
|
716
|
-
end
|
|
717
|
-
|
|
718
|
-
private def described_object_property_names_compute(**_) # TODO remove **_ eventually (keyword argument compatibility)
|
|
719
|
-
Set.new.tap do |property_names|
|
|
720
|
-
if schema_content.respond_to?(:to_hash) && schema_content['properties'].respond_to?(:to_hash)
|
|
721
|
-
property_names.merge(schema_content['properties'].keys)
|
|
722
|
-
end
|
|
723
|
-
if schema_content.respond_to?(:to_hash) && schema_content['required'].respond_to?(:to_ary)
|
|
724
|
-
property_names.merge(schema_content['required'].to_ary)
|
|
725
|
-
end
|
|
726
|
-
end.freeze
|
|
803
|
+
@described_object_property_names_map[schema_content: schema_content]
|
|
727
804
|
end
|
|
728
805
|
|
|
729
|
-
#
|
|
806
|
+
# Validates the given instance against this schema, returning a result with each validation error.
|
|
730
807
|
#
|
|
731
808
|
# @param instance [Object] the instance to validate against this schema
|
|
732
|
-
# @return [JSI::Validation::Result]
|
|
809
|
+
# @return [JSI::Validation::Result::Full]
|
|
733
810
|
def instance_validate(instance)
|
|
734
811
|
if instance.is_a?(SchemaAncestorNode)
|
|
735
812
|
instance_ptr = instance.jsi_ptr
|
|
@@ -751,6 +828,15 @@ module JSI
|
|
|
751
828
|
internal_validate_instance(Ptr[], instance, validate_only: true).valid?
|
|
752
829
|
end
|
|
753
830
|
|
|
831
|
+
# Asserts that the given instance is valid against this schema.
|
|
832
|
+
# {JSI::Invalid} is raised if it is not.
|
|
833
|
+
#
|
|
834
|
+
# @raise [Invalid]
|
|
835
|
+
# @return [nil]
|
|
836
|
+
def instance_valid!(instance)
|
|
837
|
+
instance_validate(instance).valid!
|
|
838
|
+
end
|
|
839
|
+
|
|
754
840
|
# validates the given instance against this schema
|
|
755
841
|
#
|
|
756
842
|
# @private
|
|
@@ -766,13 +852,14 @@ module JSI
|
|
|
766
852
|
validate_only: false
|
|
767
853
|
)
|
|
768
854
|
if validate_only
|
|
769
|
-
result = JSI::Validation::
|
|
855
|
+
result = JSI::Validation::Result::Valid.new
|
|
770
856
|
else
|
|
771
|
-
result = JSI::Validation::
|
|
857
|
+
result = JSI::Validation::Result::Full.new
|
|
772
858
|
end
|
|
773
859
|
result_builder = result.class::Builder.new(
|
|
774
860
|
result: result,
|
|
775
861
|
schema: self,
|
|
862
|
+
abort: false,
|
|
776
863
|
instance_ptr: instance_ptr,
|
|
777
864
|
instance_document: instance_document,
|
|
778
865
|
validate_only: validate_only,
|
|
@@ -780,43 +867,138 @@ module JSI
|
|
|
780
867
|
)
|
|
781
868
|
|
|
782
869
|
catch(:jsi_validation_result) do
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
# it's fine for them to behave the same as boolean schemas in later drafts.
|
|
786
|
-
# I don't care about draft 4 to implement a different structuring for that.
|
|
787
|
-
if schema_content == true
|
|
788
|
-
# noop
|
|
789
|
-
elsif schema_content == false
|
|
790
|
-
result_builder.validate(false, 'instance is not valid against `false` schema')
|
|
791
|
-
elsif schema_content.respond_to?(:to_hash)
|
|
792
|
-
internal_validate_keywords(result_builder)
|
|
793
|
-
else
|
|
794
|
-
result_builder.schema_error('schema is not a boolean or a JSON object')
|
|
795
|
-
end
|
|
870
|
+
dialect.invoke(:validate, result_builder)
|
|
871
|
+
|
|
796
872
|
result
|
|
797
873
|
end.freeze
|
|
798
874
|
end
|
|
799
875
|
|
|
876
|
+
# See {Base#jsi_as_child_default_as_jsi}. true for Schema, including boolean schemas.
|
|
877
|
+
def jsi_as_child_default_as_jsi
|
|
878
|
+
true
|
|
879
|
+
end
|
|
880
|
+
|
|
881
|
+
# @param action_name [Symbol]
|
|
882
|
+
# @param cxt_class [Class]
|
|
883
|
+
# @yield
|
|
884
|
+
def dialect_invoke_each(
|
|
885
|
+
action_name,
|
|
886
|
+
cxt_class = Cxt::Block,
|
|
887
|
+
**cxt_param,
|
|
888
|
+
&block
|
|
889
|
+
)
|
|
890
|
+
return(to_enum(__method__, action_name, cxt_class, **cxt_param)) unless block_given?
|
|
891
|
+
|
|
892
|
+
cxt = cxt_class.new(
|
|
893
|
+
schema: self,
|
|
894
|
+
abort: false,
|
|
895
|
+
block: block,
|
|
896
|
+
**cxt_param,
|
|
897
|
+
)
|
|
898
|
+
dialect.invoke(action_name, cxt)
|
|
899
|
+
|
|
900
|
+
nil
|
|
901
|
+
end
|
|
902
|
+
|
|
800
903
|
# schema resources which are ancestors of any subschemas below this schema.
|
|
801
904
|
# this may include this schema if this is a schema resource root.
|
|
802
905
|
# @api private
|
|
803
906
|
# @return [Array<JSI::Schema>]
|
|
804
907
|
def jsi_subschema_resource_ancestors
|
|
805
|
-
if
|
|
908
|
+
if jsi_is_resource_root?
|
|
806
909
|
jsi_schema_resource_ancestors.dup.push(self).freeze
|
|
807
910
|
else
|
|
808
911
|
jsi_schema_resource_ancestors
|
|
809
912
|
end
|
|
810
913
|
end
|
|
811
914
|
|
|
915
|
+
# @private
|
|
916
|
+
def jsi_next_schema_dynamic_anchor_map
|
|
917
|
+
return @memos[:next_schema_dynamic_anchor_map] if @memos.key?(:next_schema_dynamic_anchor_map)
|
|
918
|
+
|
|
919
|
+
if !dialect.elements.any? { |e| e.invokes?(:dynamicAnchor) }
|
|
920
|
+
return @memos[:next_schema_dynamic_anchor_map] = jsi_schema_dynamic_anchor_map
|
|
921
|
+
end
|
|
922
|
+
if !jsi_resource_root.is_a?(Schema)
|
|
923
|
+
# if the resource root is not a schema, then this schema does not add to dynamic_anchor_map.
|
|
924
|
+
# we could treat self as the anchor root, but that complicates DynamicAnchorMap#without_node.
|
|
925
|
+
return @memos[:next_schema_dynamic_anchor_map] = jsi_schema_dynamic_anchor_map
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
map = jsi_schema_dynamic_anchor_map
|
|
929
|
+
|
|
930
|
+
anchor_root = jsi_resource_root
|
|
931
|
+
descendent_schemas = [[anchor_root, Util::EMPTY_ARY]]
|
|
932
|
+
|
|
933
|
+
while !descendent_schemas.empty?
|
|
934
|
+
descendent_schema, ptrs = *descendent_schemas.shift
|
|
935
|
+
|
|
936
|
+
descendent_schema.dialect_invoke_each(:dynamicAnchor) do |anchor|
|
|
937
|
+
next if map.key?(anchor)
|
|
938
|
+
map = map.merge({
|
|
939
|
+
anchor => [anchor_root.jsi_with_schema_dynamic_anchor_map(Schema::DynamicAnchorMap::EMPTY), ptrs].freeze,
|
|
940
|
+
}).freeze
|
|
941
|
+
end
|
|
942
|
+
|
|
943
|
+
descendent_schema.each_immediate_subschema_ptr do |subptr|
|
|
944
|
+
# we want a schema at subptr to
|
|
945
|
+
# - check if it is a schema resource root
|
|
946
|
+
# - check for $dynamicAnchor
|
|
947
|
+
# can't use #subschema here (it would need to pass this method's result to instantiate the subschema);
|
|
948
|
+
# a minimal bootstrap schema is used instead.
|
|
949
|
+
# note: not using dialect.bootstrap_schema. this bootstrap is only used once, skip memoization.
|
|
950
|
+
descendent_subschema = MetaSchemaNode::BootstrapSchema.new(
|
|
951
|
+
dialect: dialect,
|
|
952
|
+
jsi_document: jsi_document,
|
|
953
|
+
jsi_ptr: descendent_schema.jsi_ptr + subptr,
|
|
954
|
+
# note: same as anchor_root.jsi_next_base_uri since we don't cross resource boundaries.
|
|
955
|
+
jsi_base_uri: descendent_schema.jsi_next_base_uri,
|
|
956
|
+
)
|
|
957
|
+
if !descendent_subschema.jsi_is_resource_root?
|
|
958
|
+
descendent_schemas.push([descendent_subschema, ptrs.dup.push(subptr).freeze])
|
|
959
|
+
end
|
|
960
|
+
end
|
|
961
|
+
end
|
|
962
|
+
|
|
963
|
+
@memos[:next_schema_dynamic_anchor_map] = map
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
# @private pending stronger stability of dynamic scope
|
|
967
|
+
def with_dynamic_scope_from(node)
|
|
968
|
+
node = node.jsi_node if node.is_a?(SchemaModule::Connection)
|
|
969
|
+
jsi_with_schema_dynamic_anchor_map(node.jsi_next_schema_dynamic_anchor_map)
|
|
970
|
+
end
|
|
971
|
+
|
|
972
|
+
# Does application require collection of evaluated children?
|
|
973
|
+
# (i.e. does the schema contain `unevaluatedItems` / `unevaluatedProperties`?)
|
|
974
|
+
# @private
|
|
975
|
+
# @return [Boolean]
|
|
976
|
+
attr_reader(:application_requires_evaluated)
|
|
977
|
+
|
|
978
|
+
# @private
|
|
979
|
+
# @return [#to_s, nil]
|
|
980
|
+
def jsi_schema_identifier(required: false)
|
|
981
|
+
name = jsi_schema_module_name_from_ancestor
|
|
982
|
+
return name if name
|
|
983
|
+
return schema_uri || (required ? jsi_ptr.uri : nil) if jsi_schema_dynamic_anchor_map.empty?
|
|
984
|
+
-"#{schema_uri || jsi_ptr.uri}#{jsi_schema_dynamic_anchor_map.anchor_schemas_identifier}"
|
|
985
|
+
end
|
|
986
|
+
|
|
812
987
|
private
|
|
813
988
|
|
|
989
|
+
KEY_BY_NONE = proc { nil }
|
|
990
|
+
|
|
814
991
|
def jsi_schema_initialize
|
|
815
|
-
|
|
816
|
-
|
|
992
|
+
# guard against being called twice on MetaSchemaNode, first from extend(Schema) then extend(jsi_schema_module) that includes Schema.
|
|
993
|
+
# both extends need to initialize for edge case of draft4's boolean schema that is not described by meta-schema.
|
|
994
|
+
instance_variable_defined?(:@jsi_schema_initialized) ? return : (@jsi_schema_initialized = true)
|
|
995
|
+
@schema_ref_map = Hash.new { |h, ref| h[ref] = Schema::Ref.new(ref, referrer: self) }
|
|
996
|
+
@schema_uris_map = jsi_memomap(key_by: KEY_BY_NONE) { to_enum(:schema_uris_compute).to_a.freeze }
|
|
997
|
+
@described_object_property_names_map = jsi_memomap(key_by: KEY_BY_NONE) do
|
|
998
|
+
Set.new(dialect_invoke_each(:described_object_property_names)).freeze
|
|
817
999
|
end
|
|
818
|
-
@
|
|
819
|
-
@
|
|
1000
|
+
@application_requires_evaluated = dialect_invoke_each(:application_requires_evaluated).any?
|
|
1001
|
+
@inplace_application_requires_instance = dialect_invoke_each(:inplace_application_requires_instance).any?
|
|
820
1002
|
end
|
|
821
1003
|
end
|
|
822
1004
|
end
|