jsi-dev 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +3 -4
- data/CHANGELOG.md +19 -0
- data/LICENSE.md +2 -3
- data/README.md +87 -43
- data/docs/{glossary.md → Glossary.md} +84 -52
- data/jsi.gemspec +1 -1
- data/lib/jsi/base/mutability.rb +48 -0
- data/lib/jsi/base/node.rb +66 -52
- data/lib/jsi/base.rb +592 -176
- data/lib/jsi/jsi_coder.rb +4 -2
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +118 -59
- data/lib/jsi/metaschema_node.rb +244 -154
- data/lib/jsi/ptr.rb +45 -17
- data/lib/jsi/ref.rb +197 -0
- data/lib/jsi/registry.rb +311 -0
- data/lib/jsi/schema/cxt/child_application.rb +35 -0
- data/lib/jsi/schema/cxt/inplace_application.rb +37 -0
- data/lib/jsi/schema/cxt.rb +80 -0
- data/lib/jsi/schema/dialect.rb +137 -0
- data/lib/jsi/schema/draft04.rb +113 -5
- data/lib/jsi/schema/draft06.rb +123 -5
- data/lib/jsi/schema/draft07.rb +157 -5
- data/lib/jsi/schema/draft202012.rb +303 -0
- data/lib/jsi/schema/dynamic_anchor_map.rb +63 -0
- data/lib/jsi/schema/element.rb +69 -0
- data/lib/jsi/schema/elements/anchor.rb +13 -0
- data/lib/jsi/schema/elements/array_validation.rb +82 -0
- data/lib/jsi/schema/elements/comment.rb +10 -0
- data/lib/jsi/schema/{validation → elements}/const.rb +11 -7
- data/lib/jsi/schema/elements/contains.rb +59 -0
- data/lib/jsi/schema/elements/contains_minmax.rb +91 -0
- data/lib/jsi/schema/elements/content_encoding.rb +10 -0
- data/lib/jsi/schema/elements/content_media_type.rb +10 -0
- data/lib/jsi/schema/elements/content_schema.rb +16 -0
- data/lib/jsi/schema/elements/default.rb +11 -0
- data/lib/jsi/schema/elements/definitions.rb +19 -0
- data/lib/jsi/schema/elements/dependencies.rb +99 -0
- data/lib/jsi/schema/elements/dependent_required.rb +49 -0
- data/lib/jsi/schema/elements/dependent_schemas.rb +69 -0
- data/lib/jsi/schema/elements/dynamic_ref.rb +69 -0
- data/lib/jsi/schema/elements/enum.rb +26 -0
- data/lib/jsi/schema/elements/examples.rb +10 -0
- data/lib/jsi/schema/elements/format.rb +10 -0
- data/lib/jsi/schema/elements/id.rb +30 -0
- data/lib/jsi/schema/elements/if_then_else.rb +82 -0
- data/lib/jsi/schema/elements/info_bool.rb +10 -0
- data/lib/jsi/schema/elements/info_string.rb +10 -0
- data/lib/jsi/schema/elements/items.rb +93 -0
- data/lib/jsi/schema/elements/items_prefixed.rb +96 -0
- data/lib/jsi/schema/elements/not.rb +31 -0
- data/lib/jsi/schema/elements/numeric.rb +137 -0
- data/lib/jsi/schema/elements/numeric_draft04.rb +77 -0
- data/lib/jsi/schema/elements/object_validation.rb +55 -0
- data/lib/jsi/schema/elements/pattern.rb +35 -0
- data/lib/jsi/schema/elements/properties.rb +145 -0
- data/lib/jsi/schema/elements/property_names.rb +48 -0
- data/lib/jsi/schema/elements/ref.rb +62 -0
- data/lib/jsi/schema/elements/required.rb +34 -0
- data/lib/jsi/schema/elements/self.rb +24 -0
- data/lib/jsi/schema/elements/some_of.rb +180 -0
- data/lib/jsi/schema/elements/string_validation.rb +57 -0
- data/lib/jsi/schema/elements/type.rb +43 -0
- data/lib/jsi/schema/elements/unevaluated_items.rb +54 -0
- data/lib/jsi/schema/elements/unevaluated_properties.rb +54 -0
- data/lib/jsi/schema/elements/xschema.rb +10 -0
- data/lib/jsi/schema/elements/xvocabulary.rb +10 -0
- data/lib/jsi/schema/elements.rb +101 -0
- data/lib/jsi/schema/issue.rb +3 -4
- data/lib/jsi/schema/schema_ancestor_node.rb +105 -52
- data/lib/jsi/schema/vocabulary.rb +36 -0
- data/lib/jsi/schema.rb +598 -383
- data/lib/jsi/schema_classes.rb +195 -141
- data/lib/jsi/schema_set.rb +85 -128
- data/lib/jsi/set.rb +23 -0
- data/lib/jsi/simple_wrap.rb +14 -17
- data/lib/jsi/struct.rb +57 -0
- data/lib/jsi/uri.rb +40 -0
- data/lib/jsi/util/private/memo_map.rb +9 -13
- data/lib/jsi/util/private.rb +59 -31
- data/lib/jsi/util/typelike.rb +19 -60
- data/lib/jsi/util.rb +53 -34
- data/lib/jsi/validation/error.rb +45 -2
- data/lib/jsi/validation/result.rb +121 -90
- data/lib/jsi/validation.rb +1 -6
- data/lib/jsi/version.rb +1 -1
- data/lib/jsi.rb +170 -36
- data/lib/schemas/json-schema.org/draft/2020-12/schema.rb +62 -0
- data/lib/schemas/json-schema.org/draft-04/schema.rb +60 -109
- data/lib/schemas/json-schema.org/draft-06/schema.rb +53 -108
- data/lib/schemas/json-schema.org/draft-07/schema.rb +63 -127
- data/readme.rb +4 -4
- data/{resources}/schemas/2020-12_strict.json +19 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/applicator.json +48 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/content.json +17 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/core.json +51 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-annotation.json +14 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-assertion.json +14 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/meta-data.json +37 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/unevaluated.json +15 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/validation.json +98 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/schema.json +58 -0
- metadata +73 -52
- data/lib/jsi/metaschema.rb +0 -6
- data/lib/jsi/schema/application/child_application/contains.rb +0 -25
- data/lib/jsi/schema/application/child_application/draft04.rb +0 -21
- data/lib/jsi/schema/application/child_application/draft06.rb +0 -28
- data/lib/jsi/schema/application/child_application/draft07.rb +0 -28
- data/lib/jsi/schema/application/child_application/items.rb +0 -18
- data/lib/jsi/schema/application/child_application/properties.rb +0 -25
- data/lib/jsi/schema/application/child_application.rb +0 -13
- data/lib/jsi/schema/application/draft04.rb +0 -8
- data/lib/jsi/schema/application/draft06.rb +0 -8
- data/lib/jsi/schema/application/draft07.rb +0 -8
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +0 -28
- data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -25
- data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -26
- data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -32
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +0 -20
- data/lib/jsi/schema/application/inplace_application/ref.rb +0 -18
- data/lib/jsi/schema/application/inplace_application/someof.rb +0 -44
- data/lib/jsi/schema/application/inplace_application.rb +0 -14
- data/lib/jsi/schema/application.rb +0 -12
- data/lib/jsi/schema/ref.rb +0 -183
- data/lib/jsi/schema/validation/array.rb +0 -69
- data/lib/jsi/schema/validation/contains.rb +0 -25
- data/lib/jsi/schema/validation/dependencies.rb +0 -49
- data/lib/jsi/schema/validation/draft04/minmax.rb +0 -91
- data/lib/jsi/schema/validation/draft04.rb +0 -110
- data/lib/jsi/schema/validation/draft06.rb +0 -120
- data/lib/jsi/schema/validation/draft07.rb +0 -157
- data/lib/jsi/schema/validation/enum.rb +0 -25
- data/lib/jsi/schema/validation/ifthenelse.rb +0 -46
- data/lib/jsi/schema/validation/items.rb +0 -54
- data/lib/jsi/schema/validation/not.rb +0 -20
- data/lib/jsi/schema/validation/numeric.rb +0 -121
- data/lib/jsi/schema/validation/object.rb +0 -45
- data/lib/jsi/schema/validation/pattern.rb +0 -34
- data/lib/jsi/schema/validation/properties.rb +0 -101
- data/lib/jsi/schema/validation/property_names.rb +0 -32
- data/lib/jsi/schema/validation/ref.rb +0 -40
- data/lib/jsi/schema/validation/required.rb +0 -27
- data/lib/jsi/schema/validation/someof.rb +0 -90
- data/lib/jsi/schema/validation/string.rb +0 -47
- data/lib/jsi/schema/validation/type.rb +0 -49
- data/lib/jsi/schema/validation.rb +0 -49
- data/lib/jsi/schema_registry.rb +0 -190
- data/lib/jsi/util/private/attr_struct.rb +0 -130
data/lib/jsi/base.rb
CHANGED
|
@@ -10,52 +10,157 @@ module JSI
|
|
|
10
10
|
# These subclasses are generally intended to be ignored by applications using this library - the purpose
|
|
11
11
|
# they serve is to include modules relevant to the instance. The modules these classes include are:
|
|
12
12
|
#
|
|
13
|
-
# - the {Schema
|
|
13
|
+
# - the {SchemaModule JSI Schema Module} of each schema which describes the instance
|
|
14
14
|
# - {Base::HashNode}, {Base::ArrayNode}, or {Base::StringNode} if the instance is
|
|
15
15
|
# a hash/object, array, or string
|
|
16
|
+
# - {Base::Immutable} or {Base::Mutable}
|
|
16
17
|
# - Modules defining accessor methods for property names described by the schemas
|
|
17
18
|
class Base
|
|
18
19
|
autoload :ArrayNode, 'jsi/base/node'
|
|
19
20
|
autoload :HashNode, 'jsi/base/node'
|
|
20
21
|
autoload :StringNode, 'jsi/base/node'
|
|
22
|
+
autoload(:Mutable, 'jsi/base/mutability')
|
|
23
|
+
autoload(:Immutable, 'jsi/base/mutability')
|
|
21
24
|
|
|
22
25
|
include Schema::SchemaAncestorNode
|
|
26
|
+
include(Util::Pretty)
|
|
23
27
|
|
|
24
28
|
# An exception raised when attempting to access a child of a node which cannot have children.
|
|
25
29
|
# A complex node can have children, a simple node cannot.
|
|
26
30
|
class SimpleNodeChildError < StandardError
|
|
27
31
|
end
|
|
28
32
|
|
|
33
|
+
class ChildNotPresent < StandardError
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
conf_attrs = {
|
|
37
|
+
root_uri: {fingerprint: true },
|
|
38
|
+
registry: {fingerprint: true },
|
|
39
|
+
application_collect_evaluated_validate: {fingerprint: false},
|
|
40
|
+
reinstantiate_nonschemas: {fingerprint: false},
|
|
41
|
+
after_initialize: {fingerprint: false},
|
|
42
|
+
child_as_jsi: {fingerprint: false},
|
|
43
|
+
child_use_default: {fingerprint: false},
|
|
44
|
+
to_immutable: {fingerprint: false},
|
|
45
|
+
}.freeze
|
|
46
|
+
Conf = Struct.subclass(*conf_attrs.keys)
|
|
47
|
+
Conf::ATTRS = conf_attrs
|
|
48
|
+
|
|
49
|
+
# Configuration, shared across all nodes of a document. A JSI's {Base#jsi_conf}.
|
|
50
|
+
#
|
|
51
|
+
# Configuration parameters are set from `**conf_kw` params passed to {SchemaSet#new_jsi #new_jsi},
|
|
52
|
+
# {Schema::MetaSchema#new_schema #new_schema} and related methods.
|
|
53
|
+
#
|
|
54
|
+
# @!attribute root_uri
|
|
55
|
+
# A URI identifying the document root resource.
|
|
56
|
+
# References (e.g. a schema `$ref`) can resolve the resource with this URI.
|
|
57
|
+
#
|
|
58
|
+
# It is rare that this needs to be specified. Most resources that would be
|
|
59
|
+
# referenced are schemas that use the `$id` keyword to specify their URI.
|
|
60
|
+
# However, there are cases when a resource may be referenced using a retrieval URI
|
|
61
|
+
# that does not match the resource's `$id`, and `root_uri` enables resolution.
|
|
62
|
+
# @return [URI, nil]
|
|
63
|
+
# @!attribute registry
|
|
64
|
+
# The registry from which references are resolved.
|
|
65
|
+
# For schemas (or documents containing schemas), this is mainly used with `$ref` values.
|
|
66
|
+
# It is unused in instances that do not contain schemas.
|
|
67
|
+
#
|
|
68
|
+
# Default: {JSI.registry}
|
|
69
|
+
# @return [Registry, nil]
|
|
70
|
+
# @!attribute application_collect_evaluated_validate
|
|
71
|
+
# Shall schema application perform validation when collecting child evaluation
|
|
72
|
+
# (for `unevaluatedProperties`, `unevaluatedItems`)?
|
|
73
|
+
#
|
|
74
|
+
# A child should not be considered evaluated by a schema when it fails to validate[^1].
|
|
75
|
+
# This means that `unevaluatedItems` or `unevaluatedProperties` should
|
|
76
|
+
# only apply to a child if no other applicator schema validates the child.
|
|
77
|
+
# The computational cost of this validation is significant, however, and may be unacceptable for performance.
|
|
78
|
+
#
|
|
79
|
+
# Set to `true`, child evaluation will perform validation, and `unevaluated*` will applicate
|
|
80
|
+
# correctly, at some cost in CPU time.
|
|
81
|
+
#
|
|
82
|
+
# Set to `false`, a child will be considered evaluated when a child applicator schema applies to it,
|
|
83
|
+
# regardless of validity, which will result in an `unevaluated*` schema incorrectly failing to
|
|
84
|
+
# applicate when the child is not valid.
|
|
85
|
+
#
|
|
86
|
+
# The default is false. It is expected that application of `unevaluated*` schemas to such children
|
|
87
|
+
# is not typically relied on, so validation is not typically worth the cost of its computation.
|
|
88
|
+
#
|
|
89
|
+
# [^1]: (ref: the JSON Schema spec states, "Schema objects that produce a false assertion result MUST
|
|
90
|
+
# NOT produce any annotation results, whether from their own keywords or from keywords in subschemas.")
|
|
91
|
+
#
|
|
92
|
+
# Default: false
|
|
93
|
+
# @return [Boolean]
|
|
94
|
+
# @!attribute reinstantiate_nonschemas
|
|
95
|
+
# _private, not officially supported_. whether Schema#resource_root_subschema reinstantiates.
|
|
96
|
+
# @!attribute after_initialize
|
|
97
|
+
# _EXPERIMENTAL_ - a callback that is called with each JSI node in the document after the node is initialized.
|
|
98
|
+
# @return [#call, nil]
|
|
99
|
+
# @!attribute child_as_jsi
|
|
100
|
+
# Default value for {Base#jsi_as_child_default_as_jsi}.
|
|
101
|
+
# @return [Boolean]
|
|
102
|
+
# @!attribute child_use_default
|
|
103
|
+
# Default value for {Base#jsi_child_use_default_default}.
|
|
104
|
+
# @return [Boolean]
|
|
105
|
+
# @!attribute to_immutable
|
|
106
|
+
# A callable that transforms given instance content to an immutable (i.e. deeply frozen) object equal to it.
|
|
107
|
+
#
|
|
108
|
+
# Used when instantiating immutable JSIs and modified copies of them, so their content is immutable.
|
|
109
|
+
#
|
|
110
|
+
# If the instantiated JSI will be mutable, this is not used.
|
|
111
|
+
#
|
|
112
|
+
# Though not recommended, this may be nil with immutable JSIs if the instance content is otherwise
|
|
113
|
+
# guaranteed to be immutable, as well as any modified copies of the instance.
|
|
114
|
+
#
|
|
115
|
+
# Default: {DEFAULT_CONTENT_TO_IMMUTABLE}
|
|
116
|
+
# @return [#call, nil]
|
|
117
|
+
class Conf
|
|
118
|
+
def initialize(
|
|
119
|
+
root_uri: nil,
|
|
120
|
+
registry: JSI.registry,
|
|
121
|
+
application_collect_evaluated_validate: false,
|
|
122
|
+
child_as_jsi: false,
|
|
123
|
+
child_use_default: false,
|
|
124
|
+
to_immutable: DEFAULT_CONTENT_TO_IMMUTABLE,
|
|
125
|
+
**kw
|
|
126
|
+
)
|
|
127
|
+
super(
|
|
128
|
+
root_uri: Util.uri(root_uri, nnil: false, yabs: true),
|
|
129
|
+
registry: registry,
|
|
130
|
+
application_collect_evaluated_validate: application_collect_evaluated_validate,
|
|
131
|
+
child_as_jsi: child_as_jsi,
|
|
132
|
+
child_use_default: child_use_default,
|
|
133
|
+
to_immutable: to_immutable,
|
|
134
|
+
**kw,
|
|
135
|
+
)
|
|
136
|
+
freeze
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# @private
|
|
140
|
+
# @return [Hash]
|
|
141
|
+
def for_fingerprint
|
|
142
|
+
to_h.select { |k, _| self.class::ATTRS.fetch(k).fetch(:fingerprint) }.freeze
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
29
146
|
class << self
|
|
30
147
|
# A string indicating the schema module name
|
|
31
148
|
# and/or schema URI of each schema the class represents.
|
|
32
149
|
# @return [String]
|
|
33
150
|
def inspect
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if mod_name && schema.schema_absolute_uri
|
|
40
|
-
"#{mod_name} <#{schema.schema_absolute_uri}>"
|
|
41
|
-
elsif mod_name
|
|
42
|
-
mod_name
|
|
43
|
-
elsif schema.schema_uri
|
|
44
|
-
schema.schema_uri.to_s
|
|
45
|
-
else
|
|
46
|
-
schema.jsi_ptr.uri.to_s
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
if schema_names.empty?
|
|
51
|
-
"(JSI Schema Class for 0 schemas)"
|
|
52
|
-
else
|
|
53
|
-
-"(JSI Schema Class: #{schema_names.join(' + ')})"
|
|
54
|
-
end
|
|
151
|
+
return super unless respond_to?(:jsi_class_schemas)
|
|
152
|
+
schema_names = jsi_class_schemas.map do |schema|
|
|
153
|
+
mod_name = schema.jsi_schema_module_name_from_ancestor
|
|
154
|
+
next "#{mod_name} <#{schema.jsi_resource_uri}>" if mod_name && schema.jsi_resource_uri
|
|
155
|
+
mod_name || "<#{schema.schema_uri || schema.jsi_ptr.uri}>"
|
|
55
156
|
end
|
|
157
|
+
"(#{[superclass, *schema_names, *jsi_class_includes].join(' + ')})"
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def to_s
|
|
161
|
+
inspect
|
|
56
162
|
end
|
|
57
163
|
|
|
58
|
-
alias_method :to_s, :inspect
|
|
59
164
|
# A constant name of this class. This is generated from any schema module name or URI of each schema
|
|
60
165
|
# this class represents, or random characters.
|
|
61
166
|
#
|
|
@@ -69,9 +174,9 @@ module JSI
|
|
|
69
174
|
return super unless respond_to?(:jsi_class_schemas)
|
|
70
175
|
alnum = proc { |id| (id % 36**4).to_s(36).rjust(4, '0').upcase }
|
|
71
176
|
schema_names = jsi_class_schemas.map do |schema|
|
|
72
|
-
|
|
73
|
-
if
|
|
74
|
-
[
|
|
177
|
+
named_ancestor, tokens = schema.jsi_schema_module.send(:named_ancestor_tokens)
|
|
178
|
+
if named_ancestor
|
|
179
|
+
[named_ancestor.jsi_schema_module_connection.name, *tokens].join('_')
|
|
75
180
|
elsif schema.schema_uri
|
|
76
181
|
schema.schema_uri.to_s
|
|
77
182
|
else
|
|
@@ -97,43 +202,53 @@ module JSI
|
|
|
97
202
|
#
|
|
98
203
|
# this is a private api - users should look elsewhere to instantiate JSIs, in particular:
|
|
99
204
|
#
|
|
100
|
-
# - {JSI.new_schema} and {Schema::
|
|
205
|
+
# - {JSI.new_schema} and {Schema::MetaSchema#new_schema} to instantiate schemas
|
|
101
206
|
# - {Schema#new_jsi} to instantiate schema instances
|
|
102
207
|
#
|
|
103
208
|
# @api private
|
|
104
209
|
# @param jsi_document [Object] the document containing the instance
|
|
105
210
|
# @param jsi_ptr [JSI::Ptr] a pointer pointing to the JSI's instance in the document
|
|
106
|
-
# @param
|
|
211
|
+
# @param jsi_base_uri [URI, nil] see {SchemaSet#new_jsi} param `base_uri`
|
|
107
212
|
# @param jsi_schema_resource_ancestors [Array<JSI::Base + JSI::Schema>]
|
|
108
|
-
# @param
|
|
109
|
-
|
|
213
|
+
# @param jsi_schema_dynamic_anchor_map [Schema::DynamicAnchorMap]
|
|
214
|
+
# @param jsi_dynamic_root_map map of (ptr, dynamic_anchor_map) → (Base root node), shared across dynamic root nodes
|
|
215
|
+
# @param jsi_conf [Base::Conf]
|
|
216
|
+
# @param jsi_root_node [JSI::Base, nil]
|
|
217
|
+
def initialize(
|
|
218
|
+
jsi_document: ,
|
|
110
219
|
jsi_ptr: Ptr[],
|
|
111
220
|
jsi_indicated_schemas: ,
|
|
112
|
-
|
|
221
|
+
jsi_base_uri: nil,
|
|
113
222
|
jsi_schema_resource_ancestors: Util::EMPTY_ARY,
|
|
114
|
-
|
|
223
|
+
jsi_schema_dynamic_anchor_map: Schema::DynamicAnchorMap::EMPTY,
|
|
224
|
+
jsi_dynamic_root_map: nil,
|
|
225
|
+
jsi_conf: nil,
|
|
115
226
|
jsi_root_node: nil
|
|
116
227
|
)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
228
|
+
#chkbug fail(Bug, "no #jsi_schemas") unless respond_to?(:jsi_schemas)
|
|
229
|
+
|
|
230
|
+
#chkbug fail(Bug) if !jsi_root_node ^ jsi_conf
|
|
231
|
+
@jsi_conf = jsi_conf = jsi_conf || jsi_root_node.jsi_conf
|
|
232
|
+
@jsi_document = jsi_document
|
|
233
|
+
#chkbug fail(Bug) unless jsi_ptr.is_a?(Ptr)
|
|
234
|
+
#chkbug fail(Bug) unless jsi_ptr.resolve_against(jsi_document).equal?(jsi_ptr)
|
|
235
|
+
@jsi_ptr = jsi_ptr
|
|
236
|
+
#chkbug fail(Bug) unless jsi_indicated_schemas.is_a?(SchemaSet)
|
|
237
|
+
@jsi_indicated_schemas = jsi_indicated_schemas
|
|
238
|
+
self.jsi_base_uri = jsi_base_uri
|
|
125
239
|
self.jsi_schema_resource_ancestors = jsi_schema_resource_ancestors
|
|
126
|
-
self.
|
|
127
|
-
if
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
end
|
|
135
|
-
|
|
240
|
+
self.jsi_schema_dynamic_anchor_map = jsi_schema_dynamic_anchor_map
|
|
241
|
+
#chkbug fail(Bug) if jsi_root_node && jsi_dynamic_root_map
|
|
242
|
+
@jsi_dynamic_root_map = jsi_dynamic_root_map || (jsi_root_node ? jsi_root_node.jsi_dynamic_root_map : jsi_memomap(&method(:jsi_dynamic_root_compute)))
|
|
243
|
+
@jsi_root_node = jsi_root_node || self
|
|
244
|
+
@root_rel_ptr = @jsi_ptr.relative_to(@jsi_root_node.jsi_ptr)
|
|
245
|
+
|
|
246
|
+
# @memos does not freeze if/when the node freezes
|
|
247
|
+
@memos = {}
|
|
136
248
|
jsi_memomaps_initialize
|
|
249
|
+
jsi_mutability_initialize
|
|
250
|
+
|
|
251
|
+
super()
|
|
137
252
|
|
|
138
253
|
if jsi_instance.is_a?(JSI::Base)
|
|
139
254
|
raise(TypeError, "a JSI::Base instance must not be another JSI::Base. received: #{jsi_instance.pretty_inspect.chomp}")
|
|
@@ -142,7 +257,7 @@ module JSI
|
|
|
142
257
|
|
|
143
258
|
# @!method jsi_schemas
|
|
144
259
|
# The set of schemas that describe this instance.
|
|
145
|
-
# These are the applicator schemas that apply to this instance, the result of
|
|
260
|
+
# These are the applicator schemas that apply to this instance, the result of in-place application
|
|
146
261
|
# of our {#jsi_indicated_schemas}.
|
|
147
262
|
# @return [JSI::SchemaSet]
|
|
148
263
|
# note: defined on subclasses by JSI::SchemaClasses.class_for_schemas
|
|
@@ -155,25 +270,41 @@ module JSI
|
|
|
155
270
|
# @return [JSI::Ptr]
|
|
156
271
|
attr_reader :jsi_ptr
|
|
157
272
|
|
|
158
|
-
#
|
|
273
|
+
# See {SchemaSet#new_jsi} param `registry`
|
|
274
|
+
# @return [Registry, nil]
|
|
275
|
+
def jsi_registry
|
|
276
|
+
jsi_conf.registry
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
attr_reader(:jsi_dynamic_root_map)
|
|
280
|
+
protected(:jsi_dynamic_root_map)
|
|
281
|
+
|
|
282
|
+
# @return [Base::Conf]
|
|
283
|
+
attr_reader(:jsi_conf)
|
|
284
|
+
|
|
285
|
+
# The root ancestor of this node. This is typically the document root, though
|
|
286
|
+
# it can be a different resource root when dynamic scope is overridden.
|
|
159
287
|
# @return [JSI::Base]
|
|
160
288
|
attr_reader :jsi_root_node
|
|
161
289
|
|
|
162
290
|
# the content of this node in our {#jsi_document} at our {#jsi_ptr}. the same as {#jsi_instance}.
|
|
163
291
|
def jsi_node_content
|
|
164
|
-
|
|
165
|
-
content
|
|
292
|
+
# stub method for doc, overridden by Mutable/Immutable
|
|
166
293
|
end
|
|
167
294
|
|
|
168
|
-
#
|
|
169
|
-
|
|
295
|
+
# The JSON schema instance this JSI represents - the underlying JSON data used to instantiate this JSI.
|
|
296
|
+
# The same as {#jsi_node_content} - 'node content' is usually preferable terminology, to avoid
|
|
297
|
+
# ambiguity in the heavily overloaded term 'instance'.
|
|
298
|
+
def jsi_instance
|
|
299
|
+
jsi_node_content
|
|
300
|
+
end
|
|
170
301
|
|
|
171
|
-
#
|
|
302
|
+
# The schemas indicated as describing this instance, prior to in-place application.
|
|
172
303
|
#
|
|
173
|
-
#
|
|
304
|
+
# This is different from {#jsi_schemas}, which are the in-place applicator schemas
|
|
174
305
|
# which describe this instance. for most purposes, `#jsi_schemas` is more relevant.
|
|
175
306
|
#
|
|
176
|
-
# `jsi_indicated_schemas` does not include
|
|
307
|
+
# `jsi_indicated_schemas` does not include in-place applicator schemas, such as the
|
|
177
308
|
# subschemas of `allOf`, whereas `#jsi_schemas` does.
|
|
178
309
|
#
|
|
179
310
|
# this does include indicated schemas which do not apply themselves, such as `$ref`
|
|
@@ -192,7 +323,22 @@ module JSI
|
|
|
192
323
|
# @yield [JSI::Base] each descendent node, starting with self
|
|
193
324
|
# @return [nil, Enumerator] an Enumerator if invoked without a block; otherwise nil
|
|
194
325
|
def jsi_each_descendent_node(propertyNames: false, &block)
|
|
195
|
-
|
|
326
|
+
unless block
|
|
327
|
+
return to_enum(__method__, propertyNames: propertyNames) do
|
|
328
|
+
# size
|
|
329
|
+
Util.ycomb do |rec|
|
|
330
|
+
proc do |node|
|
|
331
|
+
if node.respond_to?(:to_hash)
|
|
332
|
+
node.to_hash.inject(1) { |c, (k, child)| c + rec[child] + (propertyNames ? rec[k] : 0) }
|
|
333
|
+
elsif node.respond_to?(:to_ary)
|
|
334
|
+
node.to_ary.inject(1) { |c, child| c + rec[child] }
|
|
335
|
+
else
|
|
336
|
+
1
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end[jsi_node_content]
|
|
340
|
+
end
|
|
341
|
+
end
|
|
196
342
|
|
|
197
343
|
yield self
|
|
198
344
|
|
|
@@ -203,12 +349,38 @@ module JSI
|
|
|
203
349
|
end
|
|
204
350
|
|
|
205
351
|
jsi_each_child_token do |token|
|
|
206
|
-
|
|
352
|
+
jsi_child_node(token).jsi_each_descendent_node(propertyNames: propertyNames, &block)
|
|
207
353
|
end
|
|
208
354
|
|
|
209
355
|
nil
|
|
210
356
|
end
|
|
211
357
|
|
|
358
|
+
# yields each descendent of this node that is a JSI Schema
|
|
359
|
+
# @yield [Base + Schema]
|
|
360
|
+
# @return [nil, Enumerator] an Enumerator if invoked without a block; otherwise nil
|
|
361
|
+
def jsi_each_descendent_schema(&block)
|
|
362
|
+
return(to_enum(__method__)) unless block_given?
|
|
363
|
+
|
|
364
|
+
# note: this never yields self; if self is a Schema, Schema#jsi_each_descendent_schema overrides this method
|
|
365
|
+
jsi_each_child_token do |token|
|
|
366
|
+
jsi_child_node(token).jsi_each_descendent_schema(&block)
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
# yields each descendent of this node within the same resource that is a Schema
|
|
371
|
+
# @yield [Schema]
|
|
372
|
+
def jsi_each_descendent_schema_same_resource(&block)
|
|
373
|
+
return(to_enum(__method__)) unless block_given?
|
|
374
|
+
|
|
375
|
+
jsi_each_child_token do |token|
|
|
376
|
+
child = jsi_child_node(token)
|
|
377
|
+
if !child.jsi_is_resource_root?
|
|
378
|
+
# note: if child is a Schema, Schema#jsi_each_descendent_schema_same_resource overrides Base
|
|
379
|
+
child.jsi_each_descendent_schema_same_resource(&block)
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
212
384
|
# recursively selects descendent nodes of this JSI, returning a modified copy of self containing only
|
|
213
385
|
# descendent nodes for which the given block had a true-ish result.
|
|
214
386
|
#
|
|
@@ -222,7 +394,7 @@ module JSI
|
|
|
222
394
|
if jsi_array? || jsi_hash?
|
|
223
395
|
res = instance.class.new
|
|
224
396
|
jsi_each_child_token do |token|
|
|
225
|
-
v =
|
|
397
|
+
v = jsi_child_node(token)
|
|
226
398
|
if yield(v)
|
|
227
399
|
res_v = v.jsi_select_descendents_node_first(&block).jsi_node_content
|
|
228
400
|
if jsi_array?
|
|
@@ -252,7 +424,7 @@ module JSI
|
|
|
252
424
|
if jsi_array? || jsi_hash?
|
|
253
425
|
res = instance.class.new
|
|
254
426
|
jsi_each_child_token do |token|
|
|
255
|
-
v =
|
|
427
|
+
v = jsi_child_node(token).jsi_select_descendents_leaf_first(&block)
|
|
256
428
|
if yield(v)
|
|
257
429
|
res_v = v.jsi_node_content
|
|
258
430
|
if jsi_array?
|
|
@@ -269,24 +441,24 @@ module JSI
|
|
|
269
441
|
end
|
|
270
442
|
end
|
|
271
443
|
|
|
272
|
-
#
|
|
444
|
+
# JSI nodes above this one in the document.
|
|
273
445
|
#
|
|
274
446
|
# @return [Array<JSI::Base>]
|
|
275
447
|
def jsi_parent_nodes
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
parent
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
448
|
+
parent_nodes = []
|
|
449
|
+
ptr = @root_rel_ptr
|
|
450
|
+
while !ptr.root?
|
|
451
|
+
ptr = ptr.parent
|
|
452
|
+
parent_nodes.push(jsi_root_node.jsi_descendent_node(ptr))
|
|
453
|
+
end
|
|
454
|
+
parent_nodes.freeze
|
|
283
455
|
end
|
|
284
456
|
|
|
285
457
|
# the immediate parent of this JSI. nil if there is no parent.
|
|
286
458
|
#
|
|
287
459
|
# @return [JSI::Base, nil]
|
|
288
460
|
def jsi_parent_node
|
|
289
|
-
|
|
461
|
+
@root_rel_ptr.root? ? nil : jsi_root_node.jsi_descendent_node(@root_rel_ptr.parent)
|
|
290
462
|
end
|
|
291
463
|
|
|
292
464
|
# ancestor JSI instances from this node up to the root. this node itself is always its own first ancestor.
|
|
@@ -297,8 +469,8 @@ module JSI
|
|
|
297
469
|
ancestor = jsi_root_node
|
|
298
470
|
ancestors << ancestor
|
|
299
471
|
|
|
300
|
-
|
|
301
|
-
ancestor = ancestor
|
|
472
|
+
@root_rel_ptr.tokens.each do |token|
|
|
473
|
+
ancestor = ancestor.jsi_child_node(token)
|
|
302
474
|
ancestors << ancestor
|
|
303
475
|
end
|
|
304
476
|
ancestors.reverse!.freeze
|
|
@@ -309,11 +481,11 @@ module JSI
|
|
|
309
481
|
# @param ptr [JSI::Ptr, #to_ary]
|
|
310
482
|
# @return [JSI::Base]
|
|
311
483
|
def jsi_descendent_node(ptr)
|
|
312
|
-
|
|
313
|
-
|
|
484
|
+
tokens = Ptr.ary_ptr(ptr).resolve_against(jsi_node_content).tokens
|
|
485
|
+
tokens.inject(self, &:jsi_child_node)
|
|
314
486
|
end
|
|
315
487
|
|
|
316
|
-
#
|
|
488
|
+
# The descendent node at the given {Ptr}, token array, or pointer string.
|
|
317
489
|
#
|
|
318
490
|
# Note that, though more convenient to type, using an operator whose meaning may not be intuitive
|
|
319
491
|
# to a reader could impair readability of code.
|
|
@@ -322,13 +494,14 @@ module JSI
|
|
|
322
494
|
#
|
|
323
495
|
# my_jsi / ['foo', 'bar']
|
|
324
496
|
# my_jsi / %w(foo bar)
|
|
497
|
+
# my_jsi / '/foo/bar'
|
|
325
498
|
# my_schema / JSI::Ptr['additionalProperties']
|
|
326
499
|
# my_schema / %w(properties foo items additionalProperties)
|
|
327
500
|
#
|
|
328
|
-
# @param
|
|
501
|
+
# @param ptr [JSI::Ptr, #to_ary, #to_str]
|
|
329
502
|
# @return (see #jsi_descendent_node)
|
|
330
503
|
def /(ptr)
|
|
331
|
-
jsi_descendent_node(ptr)
|
|
504
|
+
jsi_descendent_node(ptr.respond_to?(:to_str) ? Ptr.from_pointer(ptr) : ptr)
|
|
332
505
|
end
|
|
333
506
|
|
|
334
507
|
# yields each token (array index or hash key) identifying a child node.
|
|
@@ -350,11 +523,20 @@ module JSI
|
|
|
350
523
|
#
|
|
351
524
|
# @param token [String, Integer]
|
|
352
525
|
# @return [Boolean]
|
|
353
|
-
def
|
|
526
|
+
def jsi_child_token_present?(token)
|
|
354
527
|
# note: overridden by Base::HashNode, Base::ArrayNode
|
|
355
528
|
false
|
|
356
529
|
end
|
|
357
530
|
|
|
531
|
+
# @api private
|
|
532
|
+
# @return [nil]
|
|
533
|
+
def jsi_child_ensure_present(token)
|
|
534
|
+
if !jsi_child_token_present?(token)
|
|
535
|
+
raise(ChildNotPresent, -"token does not identify a child that is present: #{token.inspect}\nself = #{pretty_inspect.chomp}")
|
|
536
|
+
end
|
|
537
|
+
nil
|
|
538
|
+
end
|
|
539
|
+
|
|
358
540
|
# The child of the {#jsi_node_content} identified by the given token,
|
|
359
541
|
# or `nil` if the token does not identify an existing child.
|
|
360
542
|
#
|
|
@@ -369,27 +551,37 @@ module JSI
|
|
|
369
551
|
end
|
|
370
552
|
|
|
371
553
|
# A child JSI node, or the child of our {#jsi_instance}, identified by the given token.
|
|
372
|
-
# The token must identify an existing child; behavior if the child does not exist is undefined.
|
|
373
554
|
#
|
|
374
555
|
# @param token (see Base#[])
|
|
375
556
|
# @param as_jsi (see Base#[])
|
|
376
557
|
# @return [JSI::Base, Object]
|
|
558
|
+
# @raise [Base::ChildNotPresent]
|
|
377
559
|
def jsi_child(token, as_jsi: )
|
|
560
|
+
jsi_child_as_jsi(jsi_child_node(token), as_jsi)
|
|
561
|
+
end
|
|
562
|
+
private :jsi_child # internals for #[] but idk, could be public
|
|
563
|
+
|
|
564
|
+
# @param token An array index or Hash/object property name identifying a present child of this node
|
|
565
|
+
# @return [JSI::Base]
|
|
566
|
+
# @raise [Base::ChildNotPresent]
|
|
567
|
+
def jsi_child_node(token)
|
|
568
|
+
@child_node_by_token_map[token: token]
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
private def jsi_child_node_by_token_compute(token: )
|
|
572
|
+
jsi_child_ensure_present(token)
|
|
573
|
+
|
|
378
574
|
child_content = jsi_node_content_child(token)
|
|
379
575
|
|
|
380
576
|
child_indicated_schemas = @child_indicated_schemas_map[token: token, content: jsi_node_content]
|
|
381
577
|
child_applied_schemas = @child_applied_schemas_map[token: token, child_indicated_schemas: child_indicated_schemas, child_content: child_content]
|
|
382
|
-
|
|
383
|
-
jsi_child_as_jsi(child_content, child_applied_schemas, as_jsi) do
|
|
384
|
-
@child_node_map[
|
|
578
|
+
@child_node_map[
|
|
385
579
|
token: token,
|
|
386
580
|
child_indicated_schemas: child_indicated_schemas,
|
|
387
581
|
child_applied_schemas: child_applied_schemas,
|
|
388
582
|
includes: SchemaClasses.includes_for(child_content),
|
|
389
|
-
|
|
390
|
-
end
|
|
583
|
+
]
|
|
391
584
|
end
|
|
392
|
-
private :jsi_child # internals for #[] but idk, could be public
|
|
393
585
|
|
|
394
586
|
# A default value for a child of this node identified by the given token, if schemas describing
|
|
395
587
|
# that child define a default value.
|
|
@@ -410,41 +602,42 @@ module JSI
|
|
|
410
602
|
|
|
411
603
|
defaults = Set.new
|
|
412
604
|
child_applied_schemas.each do |child_schema|
|
|
413
|
-
|
|
414
|
-
defaults << child_schema.jsi_node_content['default']
|
|
415
|
-
end
|
|
605
|
+
defaults.merge(child_schema.dialect_invoke_each(:default))
|
|
416
606
|
end
|
|
417
607
|
|
|
418
608
|
if defaults.size == 1
|
|
419
609
|
# use the default value
|
|
420
|
-
|
|
610
|
+
default_child_node =
|
|
421
611
|
jsi_modified_copy do |i|
|
|
422
612
|
i.dup.tap { |i_dup| i_dup[token] = defaults.first }
|
|
423
|
-
end
|
|
424
|
-
|
|
613
|
+
end.jsi_child_node(token)
|
|
614
|
+
jsi_child_as_jsi(default_child_node, as_jsi)
|
|
425
615
|
else
|
|
426
616
|
child_content
|
|
427
617
|
end
|
|
428
618
|
end
|
|
429
619
|
private :jsi_default_child # internals for #[] but idk, could be public
|
|
430
620
|
|
|
431
|
-
#
|
|
621
|
+
# Returns a child or children identified by param `token`.
|
|
622
|
+
#
|
|
623
|
+
# @param token [String, Integer, Range, Object] Identifies the child or children to return.
|
|
624
|
+
# Typically an array index or hash key (JSON object property name) of the instance.
|
|
625
|
+
#
|
|
626
|
+
# For an array instance, this may also be a Range (in which case an Array of children is returned)
|
|
627
|
+
# or a negative index; these behave as Array#[] does.
|
|
628
|
+
# @param as_jsi [:auto, true, false] (default is `:auto` or {Base::Conf#child_as_jsi conf child_as_jsi})
|
|
432
629
|
#
|
|
433
|
-
# @param token [String, Integer, Object] an array index or hash key (JSON object property name)
|
|
434
|
-
# of the instance identifying the child value
|
|
435
|
-
# @param as_jsi [:auto, true, false] (default is `:auto`)
|
|
436
630
|
# Whether to return the child as a JSI. One of:
|
|
437
631
|
#
|
|
438
632
|
# - `:auto`: By default a JSI will be returned when either:
|
|
439
633
|
#
|
|
440
|
-
# - the
|
|
441
|
-
# - the
|
|
634
|
+
# - the child is an array or hash
|
|
635
|
+
# - the child is a schema (including true/false schemas)
|
|
442
636
|
#
|
|
443
637
|
# The plain content is returned when it is a simple type.
|
|
444
638
|
#
|
|
445
|
-
# - true: the result
|
|
446
|
-
#
|
|
447
|
-
# - false: the result value will always be the plain instance.
|
|
639
|
+
# - true: the result will always be returned as a JSI.
|
|
640
|
+
# - false: the result will always be the node's content.
|
|
448
641
|
#
|
|
449
642
|
# note that nil is returned (regardless of as_jsi) when there is no value to return because the token
|
|
450
643
|
# is not a hash key or array index of the instance and no default value applies.
|
|
@@ -461,15 +654,26 @@ module JSI
|
|
|
461
654
|
#
|
|
462
655
|
# if the child instance's schemas do not indicate a single default value (that is, if zero or multiple
|
|
463
656
|
# defaults are specified across those schemas), nil is returned.
|
|
464
|
-
#
|
|
465
|
-
# unspecified behavior.)
|
|
466
|
-
# @return [JSI::Base, Object, nil] the child value identified by the subscript token
|
|
657
|
+
# @return [Base, Object, Array, nil] the child or children identified by `token`
|
|
467
658
|
def [](token, as_jsi: jsi_child_as_jsi_default, use_default: jsi_child_use_default_default)
|
|
659
|
+
raise(BlockGivenError) if block_given?
|
|
468
660
|
# note: overridden by Base::HashNode, Base::ArrayNode
|
|
469
661
|
jsi_simple_node_child_error(token)
|
|
470
662
|
end
|
|
471
663
|
|
|
664
|
+
# When accessing this node as a child (from a parent's {#[]} or a property reader), should the result
|
|
665
|
+
# by default be a JSI node (this node), or its node content?
|
|
666
|
+
# This default may be overridden using the `as_jsi` parameter calling the parent's {#[]}.
|
|
667
|
+
# {Base::Conf Configurable} using {Base::Conf#child_as_jsi `child_as_jsi`}.
|
|
668
|
+
# @return [Boolean]
|
|
669
|
+
def jsi_as_child_default_as_jsi
|
|
670
|
+
# base default is false, for simple types. overridden by complex types (HashNode, ArrayNode), Schema, and others.
|
|
671
|
+
jsi_conf.child_as_jsi
|
|
672
|
+
end
|
|
673
|
+
|
|
472
674
|
# The default value for the param `as_jsi` of {#[]}, controlling whether a child is returned as a JSI instance.
|
|
675
|
+
# @deprecated after v0.8. This is the parent node's preference whether its children are returned as JSIs, but it
|
|
676
|
+
# is better for a child to indicate whether it should be a JSI by overriding {#jsi_as_child_default_as_jsi}.
|
|
473
677
|
# @return [:auto, true, false] a valid value of the `as_jsi` param of {#[]}
|
|
474
678
|
def jsi_child_as_jsi_default
|
|
475
679
|
:auto
|
|
@@ -477,33 +681,28 @@ module JSI
|
|
|
477
681
|
|
|
478
682
|
# The default value for the param `use_default` of {#[]}, controlling whether a schema default value is
|
|
479
683
|
# returned when a token refers to a child that is not in the document.
|
|
684
|
+
# {Base::Conf Configurable} using {Base::Conf#child_use_default `child_use_default`}.
|
|
480
685
|
# @return [true, false] a valid value of the `use_default` param of {#[]}
|
|
481
686
|
def jsi_child_use_default_default
|
|
482
|
-
|
|
687
|
+
jsi_conf.child_use_default
|
|
483
688
|
end
|
|
484
689
|
|
|
485
|
-
#
|
|
486
|
-
#
|
|
690
|
+
# Assigns a child identified by the given token to the given value.
|
|
691
|
+
# If the given value is a JSI node, its content is used; its {#jsi_schemas} are not.
|
|
487
692
|
#
|
|
488
|
-
# @param token [String, Integer, Object] token identifying the
|
|
693
|
+
# @param token [String, Integer, Object] token identifying the child to assign
|
|
489
694
|
# @param value [JSI::Base, Object] the value to be assigned
|
|
490
695
|
def []=(token, value)
|
|
491
696
|
unless jsi_array? || jsi_hash?
|
|
492
697
|
jsi_simple_node_child_error(token)
|
|
493
698
|
end
|
|
494
699
|
if value.is_a?(Base)
|
|
495
|
-
self[token] = value.
|
|
700
|
+
self[token] = value.jsi_node_content
|
|
496
701
|
else
|
|
497
|
-
|
|
702
|
+
jsi_node_content[token] = value
|
|
498
703
|
end
|
|
499
704
|
end
|
|
500
705
|
|
|
501
|
-
# the set of JSI schema modules corresponding to the schemas that describe this JSI
|
|
502
|
-
# @return [Set<Module>]
|
|
503
|
-
def jsi_schema_modules
|
|
504
|
-
Util.ensure_module_set(jsi_schemas.map(&:jsi_schema_module))
|
|
505
|
-
end
|
|
506
|
-
|
|
507
706
|
# Is this JSI described by the given schema (or schema module)?
|
|
508
707
|
#
|
|
509
708
|
# @param schema [Schema, SchemaModule]
|
|
@@ -512,12 +711,18 @@ module JSI
|
|
|
512
711
|
if schema.is_a?(Schema)
|
|
513
712
|
jsi_schemas.include?(schema)
|
|
514
713
|
elsif schema.is_a?(SchemaModule)
|
|
515
|
-
|
|
714
|
+
jsi_schemas.include?(schema.schema)
|
|
516
715
|
else
|
|
517
716
|
raise(TypeError, "expected a Schema or Schema Module; got: #{schema.pretty_inspect.chomp}")
|
|
518
717
|
end
|
|
519
718
|
end
|
|
520
719
|
|
|
720
|
+
# Is this a JSI Schema?
|
|
721
|
+
# @return [Boolean]
|
|
722
|
+
def jsi_is_schema?
|
|
723
|
+
false
|
|
724
|
+
end
|
|
725
|
+
|
|
521
726
|
# yields the content of this JSI's instance. the block must result in
|
|
522
727
|
# a modified copy of the yielded instance (not modified in place, which would alter this JSI
|
|
523
728
|
# as well) which will be used to instantiate and return a new JSI with the modified content.
|
|
@@ -527,15 +732,37 @@ module JSI
|
|
|
527
732
|
#
|
|
528
733
|
# @yield [Object] this JSI's instance. the block should result
|
|
529
734
|
# in a nondestructively modified copy of this.
|
|
530
|
-
# @return [
|
|
531
|
-
def jsi_modified_copy(&block)
|
|
735
|
+
# @return [Base] the modified copy of self
|
|
736
|
+
def jsi_modified_copy(**conf_kw, &block)
|
|
532
737
|
modified_document = @jsi_ptr.modified_document_copy(@jsi_document, &block)
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
738
|
+
|
|
739
|
+
conf = jsi_conf.merge(**conf_kw)
|
|
740
|
+
|
|
741
|
+
modified_document = conf.to_immutable.call(modified_document) if !jsi_mutable? && conf.to_immutable
|
|
742
|
+
|
|
743
|
+
root_content = jsi_root_node.jsi_ptr.evaluate(modified_document)
|
|
744
|
+
|
|
745
|
+
root_applied_schemas = SchemaSet.build do |y|
|
|
746
|
+
c = y.method(:yield) # TODO drop c, just pass y, when all supported Enumerator::Yielder.method_defined?(:to_proc)
|
|
747
|
+
jsi_root_node.jsi_indicated_schemas.each do |is|
|
|
748
|
+
is.each_inplace_applicator_schema(root_content, &c)
|
|
749
|
+
end
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
root_class = JSI::SchemaClasses.class_for_schemas(root_applied_schemas,
|
|
753
|
+
includes: SchemaClasses.includes_for(root_content),
|
|
754
|
+
mutable: jsi_mutable?,
|
|
537
755
|
)
|
|
538
|
-
modified_jsi_root_node.
|
|
756
|
+
modified_jsi_root_node = root_class.new(
|
|
757
|
+
jsi_document: modified_document,
|
|
758
|
+
jsi_ptr: jsi_root_node.jsi_ptr,
|
|
759
|
+
jsi_indicated_schemas: jsi_root_node.jsi_indicated_schemas,
|
|
760
|
+
jsi_base_uri: jsi_root_node.jsi_base_uri,
|
|
761
|
+
jsi_schema_dynamic_anchor_map: jsi_root_node.jsi_schema_dynamic_anchor_map,
|
|
762
|
+
jsi_conf: conf,
|
|
763
|
+
).send(:jsi_initialized)
|
|
764
|
+
|
|
765
|
+
modified_jsi_root_node.jsi_descendent_node(@root_rel_ptr)
|
|
539
766
|
end
|
|
540
767
|
|
|
541
768
|
# Is the instance an array?
|
|
@@ -562,9 +789,15 @@ module JSI
|
|
|
562
789
|
false
|
|
563
790
|
end
|
|
564
791
|
|
|
792
|
+
# Is this JSI mutable?
|
|
793
|
+
# @return [Boolean]
|
|
794
|
+
def jsi_mutable?
|
|
795
|
+
# note: overridden by Base::Mutable / Immutable
|
|
796
|
+
end
|
|
797
|
+
|
|
565
798
|
# validates this JSI's instance against its schemas
|
|
566
799
|
#
|
|
567
|
-
# @return [JSI::Validation::
|
|
800
|
+
# @return [JSI::Validation::Result::Full]
|
|
568
801
|
def jsi_validate
|
|
569
802
|
jsi_indicated_schemas.instance_validate(self)
|
|
570
803
|
end
|
|
@@ -575,6 +808,15 @@ module JSI
|
|
|
575
808
|
jsi_indicated_schemas.instance_valid?(self)
|
|
576
809
|
end
|
|
577
810
|
|
|
811
|
+
# Asserts that this JSI is valid against its schemas.
|
|
812
|
+
# {JSI::Invalid} is raised if it is not.
|
|
813
|
+
#
|
|
814
|
+
# @raise [Invalid]
|
|
815
|
+
# @return [nil]
|
|
816
|
+
def jsi_valid!
|
|
817
|
+
jsi_validate.valid!
|
|
818
|
+
end
|
|
819
|
+
|
|
578
820
|
# queries this JSI using the [JMESPath Ruby](https://rubygems.org/gems/jmespath) gem.
|
|
579
821
|
# see [https://jmespath.org/](https://jmespath.org/) to learn the JMESPath query language.
|
|
580
822
|
#
|
|
@@ -592,41 +834,161 @@ module JSI
|
|
|
592
834
|
JMESPath.search(expression, self, **runtime_options)
|
|
593
835
|
end
|
|
594
836
|
|
|
595
|
-
|
|
596
|
-
|
|
837
|
+
# The nearest ancestor (including this node) that is a resource root.
|
|
838
|
+
#
|
|
839
|
+
# A resource root is a schema with an absolute URI, or the {#jsi_root_node document's root node}
|
|
840
|
+
# (which might not be a schema and might not have an absolute URI).
|
|
841
|
+
# @return [Base]
|
|
842
|
+
def jsi_resource_root
|
|
843
|
+
super || jsi_root_node
|
|
597
844
|
end
|
|
598
845
|
|
|
599
|
-
#
|
|
600
|
-
# @return [
|
|
601
|
-
def
|
|
602
|
-
|
|
846
|
+
# @private
|
|
847
|
+
# @return [URI, nil]
|
|
848
|
+
def jsi_root_uri
|
|
849
|
+
jsi_conf.root_uri
|
|
603
850
|
end
|
|
604
851
|
|
|
605
|
-
|
|
852
|
+
# @private
|
|
853
|
+
# @return [SchemaModule::Connection]
|
|
854
|
+
def jsi_schema_module_connection
|
|
855
|
+
raise(BlockGivenError) if block_given?
|
|
856
|
+
@memos.fetch(:schema_module_connection) do
|
|
857
|
+
if is_a?(Schema)
|
|
858
|
+
raise(TypeError, "mutable schema may not have a schema module: #{self}") if jsi_mutable?
|
|
859
|
+
module_class = SchemaModule
|
|
860
|
+
else
|
|
861
|
+
raise(TypeError, "mutable JSI may not have a SchemaModule::Connection: #{self}") if jsi_mutable?
|
|
862
|
+
module_class = SchemaModule::Connection
|
|
863
|
+
end
|
|
864
|
+
@memos[:schema_module_connection] = module_class.new(self)
|
|
865
|
+
end
|
|
866
|
+
end
|
|
606
867
|
|
|
607
|
-
#
|
|
868
|
+
# @private experimental
|
|
869
|
+
# a callback to be overridden (remember to call super), called with our #jsi_schema_module_connection when that is created
|
|
870
|
+
# @param mod [SchemaModule::Connection]
|
|
608
871
|
# @return [void]
|
|
872
|
+
def jsi_schema_module_connection_created(mod)
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
# @private
|
|
876
|
+
# @return [Boolean]
|
|
877
|
+
def jsi_schema_module_connection_defined?
|
|
878
|
+
@memos.key?(:schema_module_connection)
|
|
879
|
+
end
|
|
880
|
+
|
|
881
|
+
# @param dynamic_anchor_map [Schema::DynamicAnchorMap]
|
|
882
|
+
# @return [Base]
|
|
883
|
+
private def jsi_dynamic_root_descendent(dynamic_anchor_map)
|
|
884
|
+
root = jsi_dynamic_root_map[
|
|
885
|
+
ptr: jsi_resource_root.jsi_ptr,
|
|
886
|
+
dynamic_anchor_map: dynamic_anchor_map,
|
|
887
|
+
]
|
|
888
|
+
root.jsi_descendent_node(jsi_ptr.relative_to(jsi_resource_root.jsi_ptr))
|
|
889
|
+
end
|
|
890
|
+
|
|
891
|
+
# This instantiates a new root node (its #jsi_root_node is itself).
|
|
892
|
+
# When the resource at `ptr` is not the document root, the new root node has the
|
|
893
|
+
# unusual property that its jsi_ptr is not the root ptr; it is the given `ptr`.
|
|
894
|
+
# (Calling this a 'root node' is questionable, but that is the name we use.)
|
|
895
|
+
# From the new root node, no JSI node represents locations in the document above it.
|
|
896
|
+
# @param ptr [Ptr]
|
|
897
|
+
# @param dynamic_anchor_map [Schema::DynamicAnchorMap]
|
|
898
|
+
# @return [Base]
|
|
899
|
+
private def jsi_dynamic_root_compute(ptr: , dynamic_anchor_map: )
|
|
900
|
+
# self is always the originally instantiated root node (with jsi_ptr = Ptr[])
|
|
901
|
+
resource_root = jsi_descendent_node(ptr)
|
|
902
|
+
if resource_root.jsi_schema_dynamic_anchor_map == dynamic_anchor_map
|
|
903
|
+
return resource_root
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
resource_root.jsi_dynamic_root_instantiate(
|
|
907
|
+
jsi_document: resource_root.jsi_document,
|
|
908
|
+
jsi_ptr: ptr,
|
|
909
|
+
jsi_base_uri: resource_root.jsi_base_uri,
|
|
910
|
+
#jsi_schema_resource_ancestors: none (new root),
|
|
911
|
+
jsi_schema_dynamic_anchor_map: dynamic_anchor_map,
|
|
912
|
+
jsi_dynamic_root_map: jsi_dynamic_root_map,
|
|
913
|
+
jsi_conf: resource_root.jsi_conf,
|
|
914
|
+
)
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
protected def jsi_dynamic_root_instantiate(**kw)
|
|
918
|
+
# self is a resource root being instantiated with overridden dynamic scope
|
|
919
|
+
self.class.new(
|
|
920
|
+
jsi_indicated_schemas: jsi_indicated_schemas,
|
|
921
|
+
**kw,
|
|
922
|
+
).send(:jsi_initialized)
|
|
923
|
+
end
|
|
924
|
+
|
|
925
|
+
# A JSI whose node content is a duplicate of this JSI's (using its #dup).
|
|
926
|
+
#
|
|
927
|
+
# Note that immutable JSIs are not made mutable with #dup.
|
|
928
|
+
# The content's #dup may return an unfrozen copy, but instantiating a modified
|
|
929
|
+
# copy of this JSI involves transforming the content to immutable again
|
|
930
|
+
# (using {Base::Conf conf} {Base::Conf#to_immutable to_immutable}).
|
|
931
|
+
# @return [Base]
|
|
932
|
+
def dup
|
|
933
|
+
jsi_modified_copy(&:dup)
|
|
934
|
+
end
|
|
935
|
+
|
|
936
|
+
# Prints a string indicating this JSI's schemas, briefly, and its content.
|
|
937
|
+
#
|
|
938
|
+
# If described by a schema with a named schema module, that is shown.
|
|
939
|
+
# The number of schemas describing this JSI is indicated.
|
|
940
|
+
#
|
|
941
|
+
# If this JSI is a simple type, the node's content is inspected; if complex, its children are inspected.
|
|
609
942
|
def pretty_print(q)
|
|
610
|
-
q
|
|
611
|
-
q.text jsi_object_group_text.join(' ')
|
|
612
|
-
q.group_sub {
|
|
613
|
-
q.nest(2) {
|
|
614
|
-
q.breakable ' '
|
|
943
|
+
jsi_pp_object_group(q, jsi_object_group_text) do
|
|
615
944
|
q.pp jsi_instance
|
|
616
|
-
|
|
617
|
-
}
|
|
618
|
-
q.breakable ''
|
|
619
|
-
q.text '>'
|
|
945
|
+
end
|
|
620
946
|
end
|
|
621
947
|
|
|
622
948
|
# @private
|
|
623
949
|
# @return [Array<String>]
|
|
624
950
|
def jsi_object_group_text
|
|
625
|
-
|
|
951
|
+
jsi_schemas = self.jsi_schemas || Util::EMPTY_SET # for debug during MSN initialize, may not be set yet
|
|
952
|
+
schemas_priorities = jsi_schemas.each_with_index.map do |schema, i|
|
|
953
|
+
priority = [
|
|
954
|
+
schema.describes_schema? ? 0 : 1,
|
|
955
|
+
|
|
956
|
+
schema.jsi_schema_module_name ?
|
|
957
|
+
0
|
|
958
|
+
: schema.jsi_schema_module_name_from_ancestor ?
|
|
959
|
+
1
|
|
960
|
+
: schema.jsi_resource_uri ?
|
|
961
|
+
2
|
|
962
|
+
: schema.schema_uri ?
|
|
963
|
+
3
|
|
964
|
+
: 5,
|
|
965
|
+
|
|
966
|
+
!schema.respond_to?(:to_hash) ?
|
|
967
|
+
# boolean
|
|
968
|
+
9
|
|
969
|
+
: schema.empty? ?
|
|
970
|
+
8
|
|
971
|
+
: schema.all? { |k, _| k == '$ref' || k == '$dynamicRef' } ?
|
|
972
|
+
7
|
|
973
|
+
: 5,
|
|
974
|
+
]
|
|
975
|
+
[priority, i, schema]
|
|
976
|
+
end.sort
|
|
977
|
+
|
|
978
|
+
schema_names = []
|
|
979
|
+
schemas_priorities.each do |(priority, _idx, schema)|
|
|
980
|
+
if priority[0] == 0 || (priority == schemas_priorities.first.first && schema_names.size < 2)
|
|
981
|
+
name = schema.jsi_schema_identifier(required: priority[0] == 0)
|
|
982
|
+
schema_names << name if name
|
|
983
|
+
end
|
|
984
|
+
end
|
|
985
|
+
|
|
626
986
|
if schema_names.empty?
|
|
627
|
-
|
|
987
|
+
schemas_txt = -"*#{self.jsi_schemas ? jsi_schemas.size : '?'}"
|
|
988
|
+
elsif schema_names.size == jsi_schemas.size
|
|
989
|
+
schemas_txt = -" (#{schema_names.join(' + ')})"
|
|
628
990
|
else
|
|
629
|
-
|
|
991
|
+
schemas_txt = -" (#{schema_names.join(' + ')} + #{jsi_schemas.size - schema_names.size})"
|
|
630
992
|
end
|
|
631
993
|
|
|
632
994
|
if (is_a?(ArrayNode) || is_a?(HashNode)) && ![Array, Hash].include?(jsi_node_content.class)
|
|
@@ -640,10 +1002,11 @@ module JSI
|
|
|
640
1002
|
end
|
|
641
1003
|
|
|
642
1004
|
[
|
|
643
|
-
|
|
644
|
-
is_a?(
|
|
1005
|
+
-"JSI#{is_a?(MetaSchemaNode) ? ":MSN" : ""}#{schemas_txt}",
|
|
1006
|
+
is_a?(Schema::MetaSchema) ? "Meta-Schema" : is_a?(Schema) ? "Schema" : nil,
|
|
1007
|
+
is_a?(Schema) && !jsi_schema_dynamic_anchor_map.empty? ? jsi_schema_dynamic_anchor_map.anchor_schemas_identifier : nil,
|
|
645
1008
|
*content_txt,
|
|
646
|
-
].compact
|
|
1009
|
+
].compact.freeze
|
|
647
1010
|
end
|
|
648
1011
|
|
|
649
1012
|
# A structure coerced to JSONifiable types from the instance content.
|
|
@@ -656,74 +1019,116 @@ module JSI
|
|
|
656
1019
|
# Calls {Util.to_json} with the instance and any given options.
|
|
657
1020
|
# @return [String]
|
|
658
1021
|
def to_json(options = {})
|
|
659
|
-
Util.to_json(jsi_instance,
|
|
1022
|
+
Util.to_json(jsi_instance, options)
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
# Psych/YAML .dump calls this method; dumping a JSI as YAML will dump its instance.
|
|
1026
|
+
# @param coder [Psych::Coder]
|
|
1027
|
+
def encode_with(coder)
|
|
1028
|
+
coder.represent_object(nil, jsi_node_content)
|
|
1029
|
+
nil
|
|
660
1030
|
end
|
|
661
1031
|
|
|
662
1032
|
# see {Util::Private::FingerprintHash}
|
|
663
1033
|
# @api private
|
|
664
1034
|
def jsi_fingerprint
|
|
665
1035
|
{
|
|
666
|
-
class:
|
|
1036
|
+
class: JSI::Base,
|
|
1037
|
+
jsi_schemas: jsi_schemas,
|
|
667
1038
|
jsi_document: jsi_document,
|
|
668
1039
|
jsi_ptr: jsi_ptr,
|
|
669
1040
|
# for instances in documents with schemas:
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
1041
|
+
jsi_base_uri: jsi_base_uri,
|
|
1042
|
+
jsi_root_uri: jsi_conf.root_uri,
|
|
1043
|
+
# different dynamic anchor map means dynamic references may resolve to different resources so must not be equal
|
|
1044
|
+
jsi_schema_dynamic_anchor_map: jsi_schema_dynamic_anchor_map,
|
|
1045
|
+
**jsi_conf.for_fingerprint,
|
|
1046
|
+
}.freeze
|
|
1047
|
+
end
|
|
1048
|
+
|
|
1049
|
+
# @private
|
|
1050
|
+
def jsi_next_schema_dynamic_anchor_map
|
|
1051
|
+
jsi_schema_dynamic_anchor_map
|
|
674
1052
|
end
|
|
675
|
-
include Util::FingerprintHash
|
|
676
1053
|
|
|
677
1054
|
private
|
|
678
1055
|
|
|
679
|
-
|
|
680
|
-
@child_indicated_schemas_map = jsi_memomap(key_by: proc { |i| i[:token] }, &method(:jsi_child_indicated_schemas_compute))
|
|
681
|
-
@child_applied_schemas_map = jsi_memomap(key_by: proc { |i| i[:token] }, &method(:jsi_child_applied_schemas_compute))
|
|
682
|
-
@child_node_map = jsi_memomap(key_by: proc { |i| i[:token] }, &method(:jsi_child_node_compute))
|
|
683
|
-
end
|
|
1056
|
+
BY_TOKEN = proc { |i| i[:token] }
|
|
684
1057
|
|
|
685
|
-
def
|
|
686
|
-
|
|
687
|
-
@
|
|
1058
|
+
def jsi_memomaps_initialize
|
|
1059
|
+
@child_indicated_schemas_map = jsi_memomap(key_by: BY_TOKEN, &method(:jsi_child_indicated_schemas_compute))
|
|
1060
|
+
@child_applied_schemas_map = jsi_memomap(key_by: BY_TOKEN, &method(:jsi_child_applied_schemas_compute))
|
|
688
1061
|
end
|
|
689
1062
|
|
|
690
1063
|
def jsi_child_node_compute(token: , child_indicated_schemas: , child_applied_schemas: , includes: )
|
|
691
1064
|
jsi_class = JSI::SchemaClasses.class_for_schemas(child_applied_schemas,
|
|
692
1065
|
includes: includes,
|
|
1066
|
+
mutable: jsi_mutable?,
|
|
693
1067
|
)
|
|
694
|
-
jsi_class.new(
|
|
1068
|
+
jsi_class.new(
|
|
1069
|
+
jsi_document: @jsi_document,
|
|
695
1070
|
jsi_ptr: @jsi_ptr[token],
|
|
696
1071
|
jsi_indicated_schemas: child_indicated_schemas,
|
|
697
|
-
|
|
1072
|
+
jsi_base_uri: jsi_next_base_uri,
|
|
698
1073
|
jsi_schema_resource_ancestors: is_a?(Schema) ? jsi_subschema_resource_ancestors : jsi_schema_resource_ancestors,
|
|
699
|
-
|
|
1074
|
+
jsi_schema_dynamic_anchor_map: jsi_child_dynamic_anchor_map(token: token, child_schemas: child_applied_schemas),
|
|
700
1075
|
jsi_root_node: @jsi_root_node,
|
|
701
|
-
)
|
|
1076
|
+
).send(:jsi_initialized)
|
|
1077
|
+
end
|
|
1078
|
+
|
|
1079
|
+
def jsi_child_dynamic_anchor_map(token: , child_schemas: )
|
|
1080
|
+
metaschema = child_schemas.detect(&:describes_schema?)
|
|
1081
|
+
# note: no memoized dialect.bootstrap_schema; this is only used once.
|
|
1082
|
+
if metaschema && MetaSchemaNode::BootstrapSchema.new(dialect: metaschema.dialect, jsi_document: jsi_document, jsi_ptr: jsi_ptr[token], jsi_base_uri: jsi_next_base_uri).jsi_is_resource_root?
|
|
1083
|
+
# if the child is a resource root, compute dynamic scope for it
|
|
1084
|
+
# TODO if without_node removes the child, that probably means the child is equal to a descendent
|
|
1085
|
+
# of another dynamic_root. not sure if this should find/return that child - one one hand
|
|
1086
|
+
# instantiating multiple equal nodes via different dynamic scopes isn't ideal; on the other
|
|
1087
|
+
# hand having child_node return a node with a different jsi_root_node may also be problematic.
|
|
1088
|
+
jsi_next_schema_dynamic_anchor_map.without_node(self, ptr: jsi_ptr[token])
|
|
1089
|
+
else
|
|
1090
|
+
# child is not a resource, has the same dynamic scope as self
|
|
1091
|
+
jsi_schema_dynamic_anchor_map
|
|
1092
|
+
end
|
|
702
1093
|
end
|
|
703
1094
|
|
|
704
1095
|
def jsi_child_indicated_schemas_compute(token: , content: )
|
|
705
|
-
jsi_schemas.
|
|
1096
|
+
if jsi_schemas.any?(&:application_requires_evaluated)
|
|
1097
|
+
# if application_requires_evaluated, in-place application needs to collect token evaluation
|
|
1098
|
+
# recursively to inform child application, so must be recomputed.
|
|
1099
|
+
jsi_indicated_schemas.each_yield_set do |is, y|
|
|
1100
|
+
is.each_inplace_child_applicator_schema(token, content,
|
|
1101
|
+
collect_evaluated_validate: jsi_conf.application_collect_evaluated_validate,
|
|
1102
|
+
&y
|
|
1103
|
+
)
|
|
1104
|
+
end
|
|
1105
|
+
else
|
|
1106
|
+
# if token evaluation does not need to be collected, use our already-computed #jsi_schemas.
|
|
1107
|
+
jsi_schemas.each_yield_set do |s, y|
|
|
1108
|
+
s.each_child_applicator_schema(token, content, &y)
|
|
1109
|
+
end
|
|
1110
|
+
end
|
|
706
1111
|
end
|
|
707
1112
|
|
|
708
1113
|
def jsi_child_applied_schemas_compute(token: , child_indicated_schemas: , child_content: )
|
|
709
|
-
child_indicated_schemas.
|
|
1114
|
+
child_indicated_schemas.each_yield_set do |cis, y|
|
|
1115
|
+
cis.each_inplace_applicator_schema(child_content, &y)
|
|
1116
|
+
end
|
|
710
1117
|
end
|
|
711
1118
|
|
|
712
|
-
def jsi_child_as_jsi(
|
|
1119
|
+
def jsi_child_as_jsi(child_node, as_jsi)
|
|
713
1120
|
if [true, false].include?(as_jsi)
|
|
714
1121
|
child_as_jsi = as_jsi
|
|
715
1122
|
elsif as_jsi == :auto
|
|
716
|
-
|
|
717
|
-
child_is_schema = child_schemas.any?(&:describes_schema?)
|
|
718
|
-
child_as_jsi = child_is_complex || child_is_schema
|
|
1123
|
+
child_as_jsi = child_node.jsi_as_child_default_as_jsi
|
|
719
1124
|
else
|
|
720
1125
|
raise(ArgumentError, "as_jsi must be one of: :auto, true, false")
|
|
721
1126
|
end
|
|
722
1127
|
|
|
723
1128
|
if child_as_jsi
|
|
724
|
-
|
|
1129
|
+
child_node
|
|
725
1130
|
else
|
|
726
|
-
|
|
1131
|
+
child_node.jsi_node_content
|
|
727
1132
|
end
|
|
728
1133
|
end
|
|
729
1134
|
|
|
@@ -734,5 +1139,16 @@ module JSI
|
|
|
734
1139
|
"instance: #{jsi_instance.pretty_inspect.chomp}",
|
|
735
1140
|
].join("\n"))
|
|
736
1141
|
end
|
|
1142
|
+
|
|
1143
|
+
# Note that #initialize does not invoke the jsi_conf.after_initialize callback, because
|
|
1144
|
+
# the node is not finished initializing when #initialize returns; other included modules
|
|
1145
|
+
# or subclasses with #initialize methods calling super still need to finish.
|
|
1146
|
+
# Places where Base is directly instantiated must call #jsi_initialized.
|
|
1147
|
+
# @return [self]
|
|
1148
|
+
def jsi_initialized
|
|
1149
|
+
#chkbug fail if defined?(super) # this should be the last jsi_initialized in class ancestry
|
|
1150
|
+
jsi_conf.after_initialize.call(self) if jsi_conf.after_initialize
|
|
1151
|
+
self
|
|
1152
|
+
end
|
|
737
1153
|
end
|
|
738
1154
|
end
|