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