jsi 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +6 -1
- data/CHANGELOG.md +15 -0
- data/README.md +19 -18
- data/jsi.gemspec +2 -3
- data/lib/jsi/base/mutability.rb +44 -0
- data/lib/jsi/base/node.rb +199 -34
- data/lib/jsi/base.rb +412 -228
- data/lib/jsi/jsi_coder.rb +18 -16
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +57 -23
- data/lib/jsi/metaschema_node.rb +138 -107
- data/lib/jsi/ptr.rb +59 -37
- data/lib/jsi/schema/application/child_application/draft04.rb +0 -1
- data/lib/jsi/schema/application/child_application/draft06.rb +0 -1
- data/lib/jsi/schema/application/child_application/draft07.rb +0 -1
- data/lib/jsi/schema/application/child_application.rb +0 -25
- data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -1
- data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -1
- data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -1
- data/lib/jsi/schema/application/inplace_application/ref.rb +1 -1
- data/lib/jsi/schema/application/inplace_application/someof.rb +1 -1
- data/lib/jsi/schema/application/inplace_application.rb +0 -27
- data/lib/jsi/schema/draft04.rb +0 -1
- data/lib/jsi/schema/draft06.rb +0 -1
- data/lib/jsi/schema/draft07.rb +0 -1
- data/lib/jsi/schema/ref.rb +44 -18
- data/lib/jsi/schema/schema_ancestor_node.rb +65 -56
- data/lib/jsi/schema/validation/contains.rb +1 -1
- data/lib/jsi/schema/validation/draft04/minmax.rb +2 -0
- data/lib/jsi/schema/validation/draft04.rb +0 -2
- data/lib/jsi/schema/validation/draft06.rb +0 -2
- data/lib/jsi/schema/validation/draft07.rb +0 -2
- data/lib/jsi/schema/validation/items.rb +3 -3
- data/lib/jsi/schema/validation/pattern.rb +1 -1
- data/lib/jsi/schema/validation/properties.rb +4 -4
- data/lib/jsi/schema/validation/ref.rb +1 -1
- data/lib/jsi/schema/validation.rb +0 -2
- data/lib/jsi/schema.rb +405 -194
- data/lib/jsi/schema_classes.rb +196 -127
- data/lib/jsi/schema_registry.rb +66 -17
- data/lib/jsi/schema_set.rb +76 -30
- data/lib/jsi/simple_wrap.rb +2 -7
- data/lib/jsi/util/private/attr_struct.rb +28 -14
- data/lib/jsi/util/private/memo_map.rb +75 -0
- data/lib/jsi/util/private.rb +73 -92
- data/lib/jsi/util/typelike.rb +28 -28
- data/lib/jsi/util.rb +120 -36
- data/lib/jsi/validation/error.rb +4 -0
- data/lib/jsi/validation/result.rb +18 -32
- data/lib/jsi/version.rb +1 -1
- data/lib/jsi.rb +67 -25
- data/lib/schemas/json-schema.org/draft-04/schema.rb +159 -4
- data/lib/schemas/json-schema.org/draft-06/schema.rb +161 -4
- data/lib/schemas/json-schema.org/draft-07/schema.rb +188 -4
- metadata +19 -5
- data/lib/jsi/metaschema.rb +0 -6
- data/lib/jsi/schema/validation/core.rb +0 -39
data/lib/jsi/base.rb
CHANGED
@@ -1,40 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module JSI
|
4
|
-
# JSI::Base
|
4
|
+
# A JSI::Base instance represents a node in a JSON document (its {#jsi_document}) at a particular
|
5
|
+
# location (its {#jsi_ptr}), described by any number of JSON Schemas (its {#jsi_schemas}).
|
5
6
|
#
|
6
|
-
#
|
7
|
-
#
|
7
|
+
# JSI::Base is an abstract base class. The subclasses used to instantiate JSIs are dynamically created as
|
8
|
+
# needed for a given instance.
|
8
9
|
#
|
9
|
-
#
|
10
|
+
# These subclasses are generally intended to be ignored by applications using this library - the purpose
|
11
|
+
# they serve is to include modules relevant to the instance. The modules these classes include are:
|
10
12
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# the JSI::Base class itself is not intended to be instantiated.
|
13
|
+
# - the {Schema#jsi_schema_module} of each schema which describes the instance
|
14
|
+
# - {Base::HashNode}, {Base::ArrayNode}, or {Base::StringNode} if the instance is
|
15
|
+
# a hash/object, array, or string
|
16
|
+
# - Modules defining accessor methods for property names described by the schemas
|
16
17
|
class Base
|
17
18
|
autoload :ArrayNode, 'jsi/base/node'
|
18
19
|
autoload :HashNode, 'jsi/base/node'
|
20
|
+
autoload :StringNode, 'jsi/base/node'
|
21
|
+
autoload(:Mutable, 'jsi/base/mutability')
|
22
|
+
autoload(:Immutable, 'jsi/base/mutability')
|
19
23
|
|
20
24
|
include Schema::SchemaAncestorNode
|
21
|
-
include Util::Memoize
|
22
25
|
|
23
|
-
#
|
24
|
-
|
26
|
+
# An exception raised when attempting to access a child of a node which cannot have children.
|
27
|
+
# A complex node can have children, a simple node cannot.
|
28
|
+
class SimpleNodeChildError < StandardError
|
25
29
|
end
|
26
30
|
|
27
31
|
class << self
|
28
|
-
#
|
29
|
-
# is the constant JSI::SchemaClasses::<self.schema_classes_const_name> defined?
|
30
|
-
# (if so, we will prefer to use something more human-readable than that ugly mess.)
|
31
|
-
def in_schema_classes
|
32
|
-
# #name sets @in_schema_classes
|
33
|
-
name
|
34
|
-
@in_schema_classes
|
35
|
-
end
|
36
|
-
|
37
|
-
# a string indicating a class name if one is defined, as well as the schema module name
|
32
|
+
# A string indicating the schema module name
|
38
33
|
# and/or schema URI of each schema the class represents.
|
39
34
|
# @return [String]
|
40
35
|
def inspect
|
@@ -42,11 +37,11 @@ module JSI
|
|
42
37
|
super
|
43
38
|
else
|
44
39
|
schema_names = jsi_class_schemas.map do |schema|
|
45
|
-
|
46
|
-
if
|
47
|
-
"#{
|
48
|
-
elsif
|
49
|
-
|
40
|
+
mod_name = schema.jsi_schema_module.name_from_ancestor
|
41
|
+
if mod_name && schema.schema_absolute_uri
|
42
|
+
"#{mod_name} <#{schema.schema_absolute_uri}>"
|
43
|
+
elsif mod_name
|
44
|
+
mod_name
|
50
45
|
elsif schema.schema_uri
|
51
46
|
schema.schema_uri.to_s
|
52
47
|
else
|
@@ -54,61 +49,51 @@ module JSI
|
|
54
49
|
end
|
55
50
|
end
|
56
51
|
|
57
|
-
if
|
58
|
-
|
59
|
-
"#{name} (0 schemas)"
|
60
|
-
else
|
61
|
-
"#{name} (#{schema_names.join(', ')})"
|
62
|
-
end
|
52
|
+
if schema_names.empty?
|
53
|
+
"(JSI Schema Class for 0 schemas#{jsi_class_includes.map { |n| " + #{n}" }})"
|
63
54
|
else
|
64
|
-
|
65
|
-
"(JSI Schema Class for 0 schemas)"
|
66
|
-
else
|
67
|
-
"(JSI Schema Class: #{schema_names.join(', ')})"
|
68
|
-
end
|
55
|
+
-"(JSI Schema Class: #{(schema_names + jsi_class_includes.map(&:name)).join(' + ')})"
|
69
56
|
end
|
70
57
|
end
|
71
58
|
end
|
72
59
|
|
73
|
-
|
74
|
-
|
75
|
-
# @private
|
76
|
-
# see {.name}
|
77
|
-
def schema_classes_const_name
|
78
|
-
if respond_to?(:jsi_class_schemas)
|
79
|
-
schema_names = jsi_class_schemas.map do |schema|
|
80
|
-
named_ancestor_schema, tokens = schema.jsi_schema_module.send(:named_ancestor_schema_tokens)
|
81
|
-
if named_ancestor_schema
|
82
|
-
[named_ancestor_schema.jsi_schema_module.name, *tokens].join('_')
|
83
|
-
elsif schema.schema_uri
|
84
|
-
schema.schema_uri.to_s
|
85
|
-
else
|
86
|
-
nil
|
87
|
-
end
|
88
|
-
end
|
89
|
-
if !schema_names.any?(&:nil?) && !schema_names.empty?
|
90
|
-
schema_names.sort.map { |n| 'X' + n.to_s.gsub(/[^\w]/, '_') }.join('')
|
91
|
-
end
|
92
|
-
end
|
60
|
+
def to_s
|
61
|
+
inspect
|
93
62
|
end
|
94
63
|
|
95
|
-
#
|
96
|
-
# this class represents
|
64
|
+
# A constant name of this class. This is generated from any schema module name or URI of each schema
|
65
|
+
# this class represents, or random characters.
|
97
66
|
#
|
98
67
|
# this generated name is not too pretty but can be more helpful than an anonymous class, especially
|
99
68
|
# in error messages.
|
100
69
|
#
|
101
70
|
# @return [String]
|
102
71
|
def name
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
72
|
+
return super if instance_variable_defined?(:@tried_to_name)
|
73
|
+
@tried_to_name = true
|
74
|
+
return super unless respond_to?(:jsi_class_schemas)
|
75
|
+
alnum = proc { |id| (id % 36**4).to_s(36).rjust(4, '0').upcase }
|
76
|
+
schema_names = jsi_class_schemas.map do |schema|
|
77
|
+
named_ancestor_schema, tokens = schema.jsi_schema_module.send(:named_ancestor_schema_tokens)
|
78
|
+
if named_ancestor_schema
|
79
|
+
[named_ancestor_schema.jsi_schema_module.name, *tokens].join('_')
|
80
|
+
elsif schema.schema_uri
|
81
|
+
schema.schema_uri.to_s
|
107
82
|
else
|
108
|
-
|
109
|
-
@in_schema_classes = true
|
83
|
+
[alnum[schema.jsi_root_node.__id__], *schema.jsi_ptr.tokens].join('_')
|
110
84
|
end
|
111
85
|
end
|
86
|
+
includes_names = jsi_class_includes.map { |m| m.name.sub(/\AJSI::Base::/, '').gsub(Util::RUBY_REJECT_NAME_RE, '_') }
|
87
|
+
if schema_names.any?
|
88
|
+
parts = schema_names.compact.sort.map { |n| 'X' + n.to_s }
|
89
|
+
parts += includes_names
|
90
|
+
const_name = Util.const_name_from_parts(parts, join: '__')
|
91
|
+
const_name += "__" + alnum[__id__] if SchemaClasses.const_defined?(const_name)
|
92
|
+
else
|
93
|
+
const_name = (['X' + alnum[__id__]] + includes_names).join('__')
|
94
|
+
end
|
95
|
+
# collisions are technically possible though vanishingly unlikely
|
96
|
+
SchemaClasses.const_set(const_name, self) unless SchemaClasses.const_defined?(const_name)
|
112
97
|
super
|
113
98
|
end
|
114
99
|
end
|
@@ -117,37 +102,46 @@ module JSI
|
|
117
102
|
#
|
118
103
|
# this is a private api - users should look elsewhere to instantiate JSIs, in particular:
|
119
104
|
#
|
120
|
-
# - {JSI.new_schema} and {Schema::
|
105
|
+
# - {JSI.new_schema} and {Schema::MetaSchema#new_schema} to instantiate schemas
|
121
106
|
# - {Schema#new_jsi} to instantiate schema instances
|
122
107
|
#
|
123
108
|
# @api private
|
124
109
|
# @param jsi_document [Object] the document containing the instance
|
125
110
|
# @param jsi_ptr [JSI::Ptr] a pointer pointing to the JSI's instance in the document
|
126
|
-
# @param jsi_root_node [JSI::Base] the JSI of the root of the document containing this JSI
|
127
111
|
# @param jsi_schema_base_uri [Addressable::URI] see {SchemaSet#new_jsi} param uri
|
128
|
-
# @param jsi_schema_resource_ancestors [Array<JSI::Base
|
112
|
+
# @param jsi_schema_resource_ancestors [Array<JSI::Base + JSI::Schema>]
|
113
|
+
# @param jsi_root_node [JSI::Base] the JSI of the root of the document containing this JSI
|
129
114
|
def initialize(jsi_document,
|
130
115
|
jsi_ptr: Ptr[],
|
131
|
-
|
116
|
+
jsi_indicated_schemas: ,
|
132
117
|
jsi_schema_base_uri: nil,
|
133
|
-
jsi_schema_resource_ancestors: Util::EMPTY_ARY
|
118
|
+
jsi_schema_resource_ancestors: Util::EMPTY_ARY,
|
119
|
+
jsi_schema_registry: ,
|
120
|
+
jsi_content_to_immutable: ,
|
121
|
+
jsi_root_node: nil
|
134
122
|
)
|
135
|
-
raise(Bug, "no #jsi_schemas") unless respond_to?(:jsi_schemas)
|
136
|
-
|
137
|
-
jsi_initialize_memos
|
123
|
+
#chkbug raise(Bug, "no #jsi_schemas") unless respond_to?(:jsi_schemas)
|
138
124
|
|
139
125
|
self.jsi_document = jsi_document
|
140
126
|
self.jsi_ptr = jsi_ptr
|
127
|
+
self.jsi_indicated_schemas = jsi_indicated_schemas
|
128
|
+
self.jsi_schema_base_uri = jsi_schema_base_uri
|
129
|
+
self.jsi_schema_resource_ancestors = jsi_schema_resource_ancestors
|
130
|
+
self.jsi_schema_registry = jsi_schema_registry
|
131
|
+
@jsi_content_to_immutable = jsi_content_to_immutable
|
141
132
|
if @jsi_ptr.root?
|
142
|
-
raise(Bug, "jsi_root_node specified for root JSI") if jsi_root_node
|
133
|
+
#chkbug raise(Bug, "jsi_root_node specified for root JSI") if jsi_root_node
|
143
134
|
@jsi_root_node = self
|
144
135
|
else
|
145
|
-
raise(Bug, "jsi_root_node is not JSI::Base") if !jsi_root_node.is_a?(JSI::Base)
|
146
|
-
raise(Bug, "jsi_root_node ptr is not root") if !jsi_root_node.jsi_ptr.root?
|
136
|
+
#chkbug raise(Bug, "jsi_root_node is not JSI::Base") if !jsi_root_node.is_a?(JSI::Base)
|
137
|
+
#chkbug raise(Bug, "jsi_root_node ptr is not root") if !jsi_root_node.jsi_ptr.root?
|
147
138
|
@jsi_root_node = jsi_root_node
|
148
139
|
end
|
149
|
-
|
150
|
-
|
140
|
+
|
141
|
+
jsi_memomaps_initialize
|
142
|
+
jsi_mutability_initialize
|
143
|
+
|
144
|
+
super()
|
151
145
|
|
152
146
|
if jsi_instance.is_a?(JSI::Base)
|
153
147
|
raise(TypeError, "a JSI::Base instance must not be another JSI::Base. received: #{jsi_instance.pretty_inspect.chomp}")
|
@@ -155,7 +149,9 @@ module JSI
|
|
155
149
|
end
|
156
150
|
|
157
151
|
# @!method jsi_schemas
|
158
|
-
#
|
152
|
+
# The set of schemas that describe this instance.
|
153
|
+
# These are the applicator schemas that apply to this instance, the result of inplace application
|
154
|
+
# of our {#jsi_indicated_schemas}.
|
159
155
|
# @return [JSI::SchemaSet]
|
160
156
|
# note: defined on subclasses by JSI::SchemaClasses.class_for_schemas
|
161
157
|
|
@@ -167,38 +163,66 @@ module JSI
|
|
167
163
|
# @return [JSI::Ptr]
|
168
164
|
attr_reader :jsi_ptr
|
169
165
|
|
166
|
+
# Comes from the param `to_immutable` of {SchemaSet#new_jsi} (or other `new_jsi` /
|
167
|
+
# `new_schema` / `new_schema_module` method).
|
168
|
+
# Immutable JSIs use this when instantiating a modified copy so its instance is also immutable.
|
169
|
+
# @return [#call, nil]
|
170
|
+
attr_reader(:jsi_content_to_immutable)
|
171
|
+
|
170
172
|
# the JSI at the root of this JSI's document
|
171
173
|
# @return [JSI::Base]
|
172
174
|
attr_reader :jsi_root_node
|
173
175
|
|
174
176
|
# the content of this node in our {#jsi_document} at our {#jsi_ptr}. the same as {#jsi_instance}.
|
175
177
|
def jsi_node_content
|
176
|
-
|
177
|
-
content
|
178
|
+
# stub method for doc, overridden by Mutable/Immutable
|
178
179
|
end
|
179
180
|
|
180
|
-
#
|
181
|
-
|
181
|
+
# The JSON schema instance this JSI represents - the underlying JSON data used to instantiate this JSI.
|
182
|
+
# The same as {#jsi_node_content} - 'node content' is usually preferable terminology, to avoid
|
183
|
+
# ambiguity in the heavily overloaded term 'instance'.
|
184
|
+
def jsi_instance
|
185
|
+
jsi_node_content
|
186
|
+
end
|
182
187
|
|
183
|
-
#
|
188
|
+
# the schemas indicated as describing this instance, prior to inplace application.
|
189
|
+
#
|
190
|
+
# this is different from {#jsi_schemas}, which are the inplace applicator schemas
|
191
|
+
# which describe this instance. for most purposes, `#jsi_schemas` is more relevant.
|
192
|
+
#
|
193
|
+
# `jsi_indicated_schemas` does not include inplace applicator schemas, such as the
|
194
|
+
# subschemas of `allOf`, whereas `#jsi_schemas` does.
|
184
195
|
#
|
185
|
-
#
|
196
|
+
# this does include indicated schemas which do not apply themselves, such as `$ref`
|
197
|
+
# schemas (on json schema drafts up to 7) - these are not included on `#jsi_schemas`.
|
186
198
|
#
|
199
|
+
# @return [JSI::SchemaSet]
|
200
|
+
attr_reader :jsi_indicated_schemas
|
201
|
+
|
202
|
+
# yields a JSI of each node at or below this one in this JSI's document.
|
203
|
+
#
|
204
|
+
# @param propertyNames [Boolean] Whether to also yield each object property
|
205
|
+
# name (Hash key) of any descendent which is a hash/object.
|
206
|
+
# These are described by `propertyNames` subshemas of that object's schemas.
|
207
|
+
# They are not actual descendents of this node.
|
208
|
+
# See {HashNode#jsi_each_propertyName}.
|
187
209
|
# @yield [JSI::Base] each descendent node, starting with self
|
188
210
|
# @return [nil, Enumerator] an Enumerator if invoked without a block; otherwise nil
|
189
|
-
def jsi_each_descendent_node(&block)
|
190
|
-
return to_enum(__method__) unless block
|
211
|
+
def jsi_each_descendent_node(propertyNames: false, &block)
|
212
|
+
return to_enum(__method__, propertyNames: propertyNames) unless block
|
191
213
|
|
192
214
|
yield self
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
elsif respond_to?(:to_ary)
|
198
|
-
each_index do |i|
|
199
|
-
self[i, as_jsi: true].jsi_each_descendent_node(&block)
|
215
|
+
|
216
|
+
if propertyNames && is_a?(HashNode)
|
217
|
+
jsi_each_propertyName do |propertyName|
|
218
|
+
propertyName.jsi_each_descendent_node(propertyNames: propertyNames, &block)
|
200
219
|
end
|
201
220
|
end
|
221
|
+
|
222
|
+
jsi_each_child_token do |token|
|
223
|
+
jsi_child_node(token).jsi_each_descendent_node(propertyNames: propertyNames, &block)
|
224
|
+
end
|
225
|
+
|
202
226
|
nil
|
203
227
|
end
|
204
228
|
|
@@ -212,21 +236,17 @@ module JSI
|
|
212
236
|
# @return [JSI::Base] modified copy of self containing only the selected nodes
|
213
237
|
def jsi_select_descendents_node_first(&block)
|
214
238
|
jsi_modified_copy do |instance|
|
215
|
-
if
|
239
|
+
if jsi_array? || jsi_hash?
|
216
240
|
res = instance.class.new
|
217
|
-
|
218
|
-
v =
|
241
|
+
jsi_each_child_token do |token|
|
242
|
+
v = jsi_child_node(token)
|
219
243
|
if yield(v)
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
each_index do |i|
|
227
|
-
e = self[i, as_jsi: true]
|
228
|
-
if yield(e)
|
229
|
-
res << e.jsi_select_descendents_node_first(&block).jsi_node_content
|
244
|
+
res_v = v.jsi_select_descendents_node_first(&block).jsi_node_content
|
245
|
+
if jsi_array?
|
246
|
+
res << res_v
|
247
|
+
else
|
248
|
+
res[token] = res_v
|
249
|
+
end
|
230
250
|
end
|
231
251
|
end
|
232
252
|
res
|
@@ -236,9 +256,6 @@ module JSI
|
|
236
256
|
end
|
237
257
|
end
|
238
258
|
|
239
|
-
# @deprecated after v0.6
|
240
|
-
alias_method :jsi_select_children_node_first, :jsi_select_descendents_node_first
|
241
|
-
|
242
259
|
# recursively selects descendent nodes of this JSI, returning a modified copy of self containing only
|
243
260
|
# descendent nodes for which the given block had a true-ish result.
|
244
261
|
#
|
@@ -249,21 +266,17 @@ module JSI
|
|
249
266
|
# @return [JSI::Base] modified copy of self containing only the selected nodes
|
250
267
|
def jsi_select_descendents_leaf_first(&block)
|
251
268
|
jsi_modified_copy do |instance|
|
252
|
-
if
|
269
|
+
if jsi_array? || jsi_hash?
|
253
270
|
res = instance.class.new
|
254
|
-
|
255
|
-
v =
|
271
|
+
jsi_each_child_token do |token|
|
272
|
+
v = jsi_child_node(token).jsi_select_descendents_leaf_first(&block)
|
256
273
|
if yield(v)
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
each_index do |i|
|
264
|
-
e = self[i, as_jsi: true].jsi_select_descendents_leaf_first(&block)
|
265
|
-
if yield(e)
|
266
|
-
res << e.jsi_node_content
|
274
|
+
res_v = v.jsi_node_content
|
275
|
+
if jsi_array?
|
276
|
+
res << res_v
|
277
|
+
else
|
278
|
+
res[token] = res_v
|
279
|
+
end
|
267
280
|
end
|
268
281
|
end
|
269
282
|
res
|
@@ -273,9 +286,6 @@ module JSI
|
|
273
286
|
end
|
274
287
|
end
|
275
288
|
|
276
|
-
# @deprecated after v0.6
|
277
|
-
alias_method :jsi_select_children_leaf_first, :jsi_select_descendents_leaf_first
|
278
|
-
|
279
289
|
# an array of JSI instances above this one in the document.
|
280
290
|
#
|
281
291
|
# @return [Array<JSI::Base>]
|
@@ -284,9 +294,9 @@ module JSI
|
|
284
294
|
|
285
295
|
jsi_ptr.tokens.map do |token|
|
286
296
|
parent.tap do
|
287
|
-
parent = parent
|
297
|
+
parent = parent.jsi_child_node(token)
|
288
298
|
end
|
289
|
-
end.reverse
|
299
|
+
end.reverse!.freeze
|
290
300
|
end
|
291
301
|
|
292
302
|
# the immediate parent of this JSI. nil if there is no parent.
|
@@ -305,7 +315,7 @@ module JSI
|
|
305
315
|
ancestors << ancestor
|
306
316
|
|
307
317
|
jsi_ptr.tokens.each do |token|
|
308
|
-
ancestor = ancestor
|
318
|
+
ancestor = ancestor.jsi_child_node(token)
|
309
319
|
ancestors << ancestor
|
310
320
|
end
|
311
321
|
ancestors.reverse!.freeze
|
@@ -320,19 +330,140 @@ module JSI
|
|
320
330
|
descendent
|
321
331
|
end
|
322
332
|
|
333
|
+
# A shorthand alias for {#jsi_descendent_node}.
|
334
|
+
#
|
335
|
+
# Note that, though more convenient to type, using an operator whose meaning may not be intuitive
|
336
|
+
# to a reader could impair readability of code.
|
337
|
+
#
|
338
|
+
# examples:
|
339
|
+
#
|
340
|
+
# my_jsi / ['foo', 'bar']
|
341
|
+
# my_jsi / %w(foo bar)
|
342
|
+
# my_schema / JSI::Ptr['additionalProperties']
|
343
|
+
# my_schema / %w(properties foo items additionalProperties)
|
344
|
+
#
|
345
|
+
# @param (see #jsi_descendent_node)
|
346
|
+
# @return (see #jsi_descendent_node)
|
347
|
+
def /(ptr)
|
348
|
+
jsi_descendent_node(ptr)
|
349
|
+
end
|
350
|
+
|
351
|
+
# yields each token (array index or hash key) identifying a child node.
|
352
|
+
# yields nothing if this node is not complex or has no children.
|
353
|
+
#
|
354
|
+
# @yield [String, Integer] each child token
|
355
|
+
# @return [nil, Enumerator] an Enumerator if invoked without a block; otherwise nil
|
356
|
+
def jsi_each_child_token
|
357
|
+
# note: overridden by Base::HashNode, Base::ArrayNode
|
358
|
+
return to_enum(__method__) { 0 } unless block_given?
|
359
|
+
nil
|
360
|
+
end
|
361
|
+
|
362
|
+
# Does the given token identify a child of this node?
|
363
|
+
#
|
364
|
+
# In other words, is the given token an array index or hash key of the instance?
|
365
|
+
#
|
366
|
+
# Always false if this is not a complex node.
|
367
|
+
#
|
368
|
+
# @param token [String, Integer]
|
369
|
+
# @return [Boolean]
|
370
|
+
def jsi_child_token_in_range?(token)
|
371
|
+
# note: overridden by Base::HashNode, Base::ArrayNode
|
372
|
+
false
|
373
|
+
end
|
374
|
+
|
375
|
+
# The child of the {#jsi_node_content} identified by the given token,
|
376
|
+
# or `nil` if the token does not identify an existing child.
|
377
|
+
#
|
378
|
+
# In other words, the element of the instance array at the given index,
|
379
|
+
# or the value of the instance hash/object for the given key.
|
380
|
+
#
|
381
|
+
# @return [Object, nil]
|
382
|
+
# @raise [SimpleNodeChildError] if this node is not complex (its instance is not array or hash)
|
383
|
+
def jsi_node_content_child(token)
|
384
|
+
# note: overridden by Base::HashNode, Base::ArrayNode
|
385
|
+
jsi_simple_node_child_error(token)
|
386
|
+
end
|
387
|
+
|
388
|
+
# A child JSI node, or the child of our {#jsi_instance}, identified by the given token.
|
389
|
+
# The token must identify an existing child; behavior if the child does not exist is undefined.
|
390
|
+
#
|
391
|
+
# @param token (see Base#[])
|
392
|
+
# @param as_jsi (see Base#[])
|
393
|
+
# @return [JSI::Base, Object]
|
394
|
+
def jsi_child(token, as_jsi: )
|
395
|
+
child_content = jsi_node_content_child(token)
|
396
|
+
|
397
|
+
child_indicated_schemas = @child_indicated_schemas_map[token: token, content: jsi_node_content]
|
398
|
+
child_applied_schemas = @child_applied_schemas_map[token: token, child_indicated_schemas: child_indicated_schemas, child_content: child_content]
|
399
|
+
|
400
|
+
jsi_child_as_jsi(child_content, child_applied_schemas, as_jsi) do
|
401
|
+
@child_node_map[
|
402
|
+
token: token,
|
403
|
+
child_indicated_schemas: child_indicated_schemas,
|
404
|
+
child_applied_schemas: child_applied_schemas,
|
405
|
+
includes: SchemaClasses.includes_for(child_content),
|
406
|
+
]
|
407
|
+
end
|
408
|
+
end
|
409
|
+
private :jsi_child # internals for #[] but idk, could be public
|
410
|
+
|
411
|
+
# @param token (see Base#[])
|
412
|
+
# @return [JSI::Base]
|
413
|
+
protected def jsi_child_node(token)
|
414
|
+
jsi_child(token, as_jsi: true)
|
415
|
+
end
|
416
|
+
|
417
|
+
# A default value for a child of this node identified by the given token, if schemas describing
|
418
|
+
# that child define a default value.
|
419
|
+
#
|
420
|
+
# If no schema describes a default value for the child (or in the unusual case that multiple
|
421
|
+
# schemas define different defaults), the result is `nil`.
|
422
|
+
#
|
423
|
+
# See also the `use_default` param of {Base#[]}.
|
424
|
+
#
|
425
|
+
# @param token (see Base#[])
|
426
|
+
# @param as_jsi (see Base#[])
|
427
|
+
# @return [JSI::Base, nil]
|
428
|
+
def jsi_default_child(token, as_jsi: )
|
429
|
+
child_content = jsi_node_content_child(token)
|
430
|
+
|
431
|
+
child_indicated_schemas = @child_indicated_schemas_map[token: token, content: jsi_node_content]
|
432
|
+
child_applied_schemas = @child_applied_schemas_map[token: token, child_indicated_schemas: child_indicated_schemas, child_content: child_content]
|
433
|
+
|
434
|
+
defaults = Set.new
|
435
|
+
child_applied_schemas.each do |child_schema|
|
436
|
+
if child_schema.keyword?('default')
|
437
|
+
defaults << child_schema.jsi_node_content['default']
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
if defaults.size == 1
|
442
|
+
# use the default value
|
443
|
+
jsi_child_as_jsi(defaults.first, child_applied_schemas, as_jsi) do
|
444
|
+
jsi_modified_copy do |i|
|
445
|
+
i.dup.tap { |i_dup| i_dup[token] = defaults.first }
|
446
|
+
end.jsi_child_node(token)
|
447
|
+
end
|
448
|
+
else
|
449
|
+
child_content
|
450
|
+
end
|
451
|
+
end
|
452
|
+
private :jsi_default_child # internals for #[] but idk, could be public
|
453
|
+
|
323
454
|
# subscripts to return a child value identified by the given token.
|
324
455
|
#
|
325
456
|
# @param token [String, Integer, Object] an array index or hash key (JSON object property name)
|
326
457
|
# of the instance identifying the child value
|
327
|
-
# @param as_jsi [:auto, true, false]
|
458
|
+
# @param as_jsi [:auto, true, false] (default is `:auto`)
|
459
|
+
# Whether to return the child as a JSI. One of:
|
328
460
|
#
|
329
|
-
# -
|
461
|
+
# - `:auto`: By default a JSI will be returned when either:
|
330
462
|
#
|
331
463
|
# - the result is a complex value (responds to #to_ary or #to_hash)
|
332
464
|
# - the result is a schema (including true/false schemas)
|
333
465
|
#
|
334
|
-
#
|
335
|
-
# simple type (anything unresponsive to #to_ary / #to_hash).
|
466
|
+
# The plain content is returned when it is a simple type.
|
336
467
|
#
|
337
468
|
# - true: the result value will always be returned as a JSI. the {#jsi_schemas} of the result may be
|
338
469
|
# empty if no schemas describe the instance.
|
@@ -342,8 +473,9 @@ module JSI
|
|
342
473
|
# is not a hash key or array index of the instance and no default value applies.
|
343
474
|
# (one exception is when this JSI's instance is a Hash with a default or default_proc, which has
|
344
475
|
# unspecified behavior.)
|
345
|
-
# @param use_default [true, false]
|
346
|
-
#
|
476
|
+
# @param use_default [true, false] (default is `false`)
|
477
|
+
# Whether to return a schema default value when the token refers to a child that is not in the document.
|
478
|
+
# If the token is not an array index or hash key of the instance, and one schema for the child
|
347
479
|
# instance specifies a default value, that default is returned.
|
348
480
|
#
|
349
481
|
# if the result with the default value is a JSI (per the `as_jsi` param), that JSI is not a child of
|
@@ -354,52 +486,23 @@ module JSI
|
|
354
486
|
# defaults are specified across those schemas), nil is returned.
|
355
487
|
# (one exception is when this JSI's instance is a Hash with a default or default_proc, which has
|
356
488
|
# unspecified behavior.)
|
357
|
-
# @return [JSI::Base, Object] the child value identified by the subscript token
|
358
|
-
def [](token, as_jsi:
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
elsif respond_to?(:to_ary)
|
363
|
-
token_in_range = jsi_node_content_ary_pubsend(:each_index).include?(token)
|
364
|
-
value = jsi_node_content_ary_pubsend(:[], token)
|
365
|
-
else
|
366
|
-
raise(CannotSubscriptError, "cannot subscript (using token: #{token.inspect}) from instance: #{jsi_instance.pretty_inspect.chomp}")
|
367
|
-
end
|
368
|
-
|
369
|
-
begin
|
370
|
-
subinstance_schemas = jsi_subinstance_schemas_memos[token: token, instance: jsi_node_content, subinstance: value]
|
489
|
+
# @return [JSI::Base, Object, nil] the child value identified by the subscript token
|
490
|
+
def [](token, as_jsi: jsi_child_as_jsi_default, use_default: jsi_child_use_default_default)
|
491
|
+
# note: overridden by Base::HashNode, Base::ArrayNode
|
492
|
+
jsi_simple_node_child_error(token)
|
493
|
+
end
|
371
494
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
includes: SchemaClasses.includes_for(value),
|
378
|
-
]
|
379
|
-
end
|
380
|
-
else
|
381
|
-
if use_default
|
382
|
-
defaults = Set.new
|
383
|
-
subinstance_schemas.each do |subinstance_schema|
|
384
|
-
if subinstance_schema.keyword?('default')
|
385
|
-
defaults << subinstance_schema.jsi_node_content['default']
|
386
|
-
end
|
387
|
-
end
|
388
|
-
end
|
495
|
+
# The default value for the param `as_jsi` of {#[]}, controlling whether a child is returned as a JSI instance.
|
496
|
+
# @return [:auto, true, false] a valid value of the `as_jsi` param of {#[]}
|
497
|
+
def jsi_child_as_jsi_default
|
498
|
+
:auto
|
499
|
+
end
|
389
500
|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
# I kind of want to just return nil here. the preferred mechanism for
|
396
|
-
# a JSI's default value should be its schema. but returning nil ignores
|
397
|
-
# any value returned by Hash#default/#default_proc. there's no compelling
|
398
|
-
# reason not to support both, so I'll return that.
|
399
|
-
value
|
400
|
-
end
|
401
|
-
end
|
402
|
-
end
|
501
|
+
# The default value for the param `use_default` of {#[]}, controlling whether a schema default value is
|
502
|
+
# returned when a token refers to a child that is not in the document.
|
503
|
+
# @return [true, false] a valid value of the `use_default` param of {#[]}
|
504
|
+
def jsi_child_use_default_default
|
505
|
+
false
|
403
506
|
end
|
404
507
|
|
405
508
|
# assigns the subscript of the instance identified by the given token to the given value.
|
@@ -408,8 +511,8 @@ module JSI
|
|
408
511
|
# @param token [String, Integer, Object] token identifying the subscript to assign
|
409
512
|
# @param value [JSI::Base, Object] the value to be assigned
|
410
513
|
def []=(token, value)
|
411
|
-
unless
|
412
|
-
|
514
|
+
unless jsi_array? || jsi_hash?
|
515
|
+
jsi_simple_node_child_error(token)
|
413
516
|
end
|
414
517
|
if value.is_a?(Base)
|
415
518
|
self[token] = value.jsi_instance
|
@@ -424,6 +527,26 @@ module JSI
|
|
424
527
|
Util.ensure_module_set(jsi_schemas.map(&:jsi_schema_module))
|
425
528
|
end
|
426
529
|
|
530
|
+
# Is this JSI described by the given schema (or schema module)?
|
531
|
+
#
|
532
|
+
# @param schema [Schema, SchemaModule]
|
533
|
+
# @return [Boolean]
|
534
|
+
def described_by?(schema)
|
535
|
+
if schema.is_a?(Schema)
|
536
|
+
jsi_schemas.include?(schema)
|
537
|
+
elsif schema.is_a?(SchemaModule)
|
538
|
+
jsi_schema_modules.include?(schema)
|
539
|
+
else
|
540
|
+
raise(TypeError, "expected a Schema or Schema Module; got: #{schema.pretty_inspect.chomp}")
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
# Is this a JSI Schema?
|
545
|
+
# @return [Boolean]
|
546
|
+
def jsi_is_schema?
|
547
|
+
false
|
548
|
+
end
|
549
|
+
|
427
550
|
# yields the content of this JSI's instance. the block must result in
|
428
551
|
# a modified copy of the yielded instance (not modified in place, which would alter this JSI
|
429
552
|
# as well) which will be used to instantiate and return a new JSI with the modified content.
|
@@ -435,30 +558,58 @@ module JSI
|
|
435
558
|
# in a nondestructively modified copy of this.
|
436
559
|
# @return [JSI::Base subclass] the modified copy of self
|
437
560
|
def jsi_modified_copy(&block)
|
438
|
-
if @jsi_ptr.root?
|
439
561
|
modified_document = @jsi_ptr.modified_document_copy(@jsi_document, &block)
|
440
|
-
|
441
|
-
uri: jsi_schema_base_uri,
|
562
|
+
modified_jsi_root_node = @jsi_root_node.jsi_indicated_schemas.new_jsi(modified_document,
|
563
|
+
uri: @jsi_root_node.jsi_schema_base_uri,
|
564
|
+
register: false, # default is already false but this is a place to be explicit
|
565
|
+
schema_registry: jsi_schema_registry,
|
566
|
+
mutable: jsi_mutable?,
|
567
|
+
to_immutable: jsi_content_to_immutable,
|
442
568
|
)
|
443
|
-
else
|
444
|
-
modified_jsi_root_node = @jsi_root_node.jsi_modified_copy do |root|
|
445
|
-
@jsi_ptr.modified_document_copy(root, &block)
|
446
|
-
end
|
447
569
|
modified_jsi_root_node.jsi_descendent_node(@jsi_ptr)
|
448
|
-
|
570
|
+
end
|
571
|
+
|
572
|
+
# Is the instance an array?
|
573
|
+
#
|
574
|
+
# An array is typically an instance of the Array class but may be an object that supports
|
575
|
+
# [implicit conversion](https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html)
|
576
|
+
# with a `#to_ary` method.
|
577
|
+
#
|
578
|
+
# @return [Boolean]
|
579
|
+
def jsi_array?
|
580
|
+
# note: overridden by Base::ArrayNode
|
581
|
+
false
|
582
|
+
end
|
583
|
+
|
584
|
+
# Is the instance a ruby Hash (JSON object)?
|
585
|
+
#
|
586
|
+
# This is typically an instance of the Hash class but may be an object that supports
|
587
|
+
# [implicit conversion](https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html)
|
588
|
+
# with a `#to_hash` method.
|
589
|
+
#
|
590
|
+
# @return [Boolean]
|
591
|
+
def jsi_hash?
|
592
|
+
# note: overridden by Base::HashNode
|
593
|
+
false
|
594
|
+
end
|
595
|
+
|
596
|
+
# Is this JSI mutable?
|
597
|
+
# @return [Boolean]
|
598
|
+
def jsi_mutable?
|
599
|
+
# note: overridden by Base::Mutable / Immutable
|
449
600
|
end
|
450
601
|
|
451
602
|
# validates this JSI's instance against its schemas
|
452
603
|
#
|
453
604
|
# @return [JSI::Validation::FullResult]
|
454
605
|
def jsi_validate
|
455
|
-
|
606
|
+
jsi_indicated_schemas.instance_validate(self)
|
456
607
|
end
|
457
608
|
|
458
609
|
# whether this JSI's instance is valid against all of its schemas
|
459
610
|
# @return [Boolean]
|
460
611
|
def jsi_valid?
|
461
|
-
|
612
|
+
jsi_indicated_schemas.instance_valid?(self)
|
462
613
|
end
|
463
614
|
|
464
615
|
# queries this JSI using the [JMESPath Ruby](https://rubygems.org/gems/jmespath) gem.
|
@@ -485,21 +636,21 @@ module JSI
|
|
485
636
|
# a string representing this JSI, indicating any named schemas and inspecting its instance
|
486
637
|
# @return [String]
|
487
638
|
def inspect
|
488
|
-
"\#<#{jsi_object_group_text.join(' ')} #{jsi_instance.inspect}>"
|
639
|
+
-"\#<#{jsi_object_group_text.join(' ')} #{jsi_instance.inspect}>"
|
489
640
|
end
|
490
641
|
|
491
|
-
|
642
|
+
def to_s
|
643
|
+
inspect
|
644
|
+
end
|
492
645
|
|
493
646
|
# pretty-prints a representation of this JSI to the given printer
|
494
647
|
# @return [void]
|
495
648
|
def pretty_print(q)
|
496
649
|
q.text '#<'
|
497
650
|
q.text jsi_object_group_text.join(' ')
|
498
|
-
q.
|
499
|
-
q.nest(2) {
|
651
|
+
q.group(2) {
|
500
652
|
q.breakable ' '
|
501
653
|
q.pp jsi_instance
|
502
|
-
}
|
503
654
|
}
|
504
655
|
q.breakable ''
|
505
656
|
q.text '>'
|
@@ -512,82 +663,115 @@ module JSI
|
|
512
663
|
if schema_names.empty?
|
513
664
|
class_txt = "JSI"
|
514
665
|
else
|
515
|
-
class_txt = "JSI (#{schema_names.join(', ')})"
|
666
|
+
class_txt = -"JSI (#{schema_names.join(', ')})"
|
516
667
|
end
|
517
668
|
|
518
669
|
if (is_a?(ArrayNode) || is_a?(HashNode)) && ![Array, Hash].include?(jsi_node_content.class)
|
519
670
|
if jsi_node_content.respond_to?(:jsi_object_group_text)
|
520
671
|
content_txt = jsi_node_content.jsi_object_group_text
|
521
672
|
else
|
522
|
-
content_txt =
|
673
|
+
content_txt = jsi_node_content.class.to_s
|
523
674
|
end
|
524
675
|
else
|
525
|
-
content_txt =
|
676
|
+
content_txt = nil
|
526
677
|
end
|
527
678
|
|
528
679
|
[
|
529
680
|
class_txt,
|
530
|
-
is_a?(
|
681
|
+
is_a?(Schema::MetaSchema) ? "Meta-Schema" : is_a?(Schema) ? "Schema" : nil,
|
531
682
|
*content_txt,
|
532
|
-
].compact
|
683
|
+
].compact.freeze
|
533
684
|
end
|
534
685
|
|
535
|
-
#
|
536
|
-
#
|
537
|
-
def as_json(
|
538
|
-
Util.as_json(jsi_instance,
|
686
|
+
# A structure coerced to JSONifiable types from the instance content.
|
687
|
+
# Calls {Util.as_json} with the instance and any given options.
|
688
|
+
def as_json(options = {})
|
689
|
+
Util.as_json(jsi_instance, **options)
|
539
690
|
end
|
540
691
|
|
541
|
-
#
|
692
|
+
# A JSON encoded string of the instance content.
|
693
|
+
# Calls {Util.to_json} with the instance and any given options.
|
694
|
+
# @return [String]
|
695
|
+
def to_json(options = {})
|
696
|
+
Util.to_json(jsi_instance, **options)
|
697
|
+
end
|
698
|
+
|
699
|
+
# see {Util::Private::FingerprintHash}
|
700
|
+
# @api private
|
542
701
|
def jsi_fingerprint
|
543
702
|
{
|
544
|
-
class:
|
703
|
+
class: JSI::Base,
|
704
|
+
jsi_schemas: jsi_schemas,
|
545
705
|
jsi_document: jsi_document,
|
546
706
|
jsi_ptr: jsi_ptr,
|
547
707
|
# for instances in documents with schemas:
|
548
708
|
jsi_resource_ancestor_uri: jsi_resource_ancestor_uri,
|
549
|
-
#
|
550
|
-
|
551
|
-
}
|
709
|
+
# different registries mean references may resolve to different resources so must not be equal
|
710
|
+
jsi_schema_registry: jsi_schema_registry,
|
711
|
+
}.freeze
|
552
712
|
end
|
553
|
-
include Util::FingerprintHash
|
554
713
|
|
555
714
|
private
|
556
715
|
|
557
|
-
def
|
558
|
-
jsi_memomap(
|
559
|
-
|
560
|
-
|
716
|
+
def jsi_memomaps_initialize
|
717
|
+
@child_indicated_schemas_map = jsi_memomap(key_by: proc { |i| i[:token] }, &method(:jsi_child_indicated_schemas_compute))
|
718
|
+
@child_applied_schemas_map = jsi_memomap(key_by: proc { |i| i[:token] }, &method(:jsi_child_applied_schemas_compute))
|
719
|
+
@child_node_map = jsi_memomap(key_by: proc { |i| i[:token] }, &method(:jsi_child_node_compute))
|
561
720
|
end
|
562
721
|
|
563
|
-
def
|
564
|
-
|
565
|
-
|
722
|
+
def jsi_indicated_schemas=(jsi_indicated_schemas)
|
723
|
+
#chkbug raise(Bug) unless jsi_indicated_schemas.is_a?(SchemaSet)
|
724
|
+
@jsi_indicated_schemas = jsi_indicated_schemas
|
725
|
+
end
|
726
|
+
|
727
|
+
def jsi_child_node_compute(token: , child_indicated_schemas: , child_applied_schemas: , includes: )
|
728
|
+
jsi_class = JSI::SchemaClasses.class_for_schemas(child_applied_schemas,
|
729
|
+
includes: includes,
|
730
|
+
mutable: jsi_mutable?,
|
731
|
+
)
|
566
732
|
jsi_class.new(@jsi_document,
|
567
733
|
jsi_ptr: @jsi_ptr[token],
|
568
|
-
|
734
|
+
jsi_indicated_schemas: child_indicated_schemas,
|
569
735
|
jsi_schema_base_uri: jsi_resource_ancestor_uri,
|
570
736
|
jsi_schema_resource_ancestors: is_a?(Schema) ? jsi_subschema_resource_ancestors : jsi_schema_resource_ancestors,
|
737
|
+
jsi_schema_registry: jsi_schema_registry,
|
738
|
+
jsi_content_to_immutable: @jsi_content_to_immutable,
|
739
|
+
jsi_root_node: @jsi_root_node,
|
571
740
|
)
|
572
|
-
end
|
573
741
|
end
|
574
742
|
|
575
|
-
def
|
743
|
+
def jsi_child_indicated_schemas_compute(token: , content: )
|
744
|
+
jsi_schemas.child_applicator_schemas(token, content)
|
745
|
+
end
|
746
|
+
|
747
|
+
def jsi_child_applied_schemas_compute(token: , child_indicated_schemas: , child_content: )
|
748
|
+
child_indicated_schemas.inplace_applicator_schemas(child_content)
|
749
|
+
end
|
750
|
+
|
751
|
+
def jsi_child_as_jsi(child_content, child_schemas, as_jsi)
|
576
752
|
if [true, false].include?(as_jsi)
|
577
|
-
|
753
|
+
child_as_jsi = as_jsi
|
578
754
|
elsif as_jsi == :auto
|
579
|
-
|
580
|
-
|
581
|
-
|
755
|
+
child_is_complex = child_content.respond_to?(:to_hash) || child_content.respond_to?(:to_ary)
|
756
|
+
child_is_schema = child_schemas.any?(&:describes_schema?)
|
757
|
+
child_as_jsi = child_is_complex || child_is_schema
|
582
758
|
else
|
583
759
|
raise(ArgumentError, "as_jsi must be one of: :auto, true, false")
|
584
760
|
end
|
585
761
|
|
586
|
-
if
|
762
|
+
if child_as_jsi
|
587
763
|
yield
|
588
764
|
else
|
589
|
-
|
765
|
+
child_content
|
590
766
|
end
|
591
767
|
end
|
768
|
+
|
769
|
+
def jsi_simple_node_child_error(token)
|
770
|
+
raise(SimpleNodeChildError, [
|
771
|
+
"cannot access a child of this JSI node because this node is not complex",
|
772
|
+
"using token: #{token.inspect}",
|
773
|
+
"instance: #{jsi_instance.pretty_inspect.chomp}",
|
774
|
+
].join("\n"))
|
775
|
+
end
|
592
776
|
end
|
593
777
|
end
|