jsi 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +3 -2
- data/CHANGELOG.md +9 -0
- data/LICENSE.md +2 -3
- data/README.md +68 -31
- data/docs/Glossary.md +313 -0
- data/jsi.gemspec +1 -0
- data/lib/jsi/base/mutability.rb +4 -0
- data/lib/jsi/base/node.rb +63 -24
- data/lib/jsi/base.rb +556 -173
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +106 -56
- data/lib/jsi/metaschema_node.rb +227 -160
- data/lib/jsi/ptr.rb +32 -15
- data/lib/jsi/ref.rb +197 -0
- data/lib/jsi/registry.rb +311 -0
- data/lib/jsi/schema/cxt/child_application.rb +35 -0
- data/lib/jsi/schema/cxt/inplace_application.rb +37 -0
- data/lib/jsi/schema/cxt.rb +80 -0
- data/lib/jsi/schema/dialect.rb +137 -0
- data/lib/jsi/schema/draft04.rb +113 -5
- data/lib/jsi/schema/draft06.rb +123 -5
- data/lib/jsi/schema/draft07.rb +157 -5
- data/lib/jsi/schema/draft202012.rb +303 -0
- data/lib/jsi/schema/dynamic_anchor_map.rb +63 -0
- data/lib/jsi/schema/element.rb +69 -0
- data/lib/jsi/schema/elements/anchor.rb +13 -0
- data/lib/jsi/schema/elements/array_validation.rb +82 -0
- data/lib/jsi/schema/elements/comment.rb +10 -0
- data/lib/jsi/schema/{validation → elements}/const.rb +11 -7
- data/lib/jsi/schema/elements/contains.rb +59 -0
- data/lib/jsi/schema/elements/contains_minmax.rb +91 -0
- data/lib/jsi/schema/elements/content_encoding.rb +10 -0
- data/lib/jsi/schema/elements/content_media_type.rb +10 -0
- data/lib/jsi/schema/elements/content_schema.rb +16 -0
- data/lib/jsi/schema/elements/default.rb +11 -0
- data/lib/jsi/schema/elements/definitions.rb +19 -0
- data/lib/jsi/schema/elements/dependencies.rb +99 -0
- data/lib/jsi/schema/elements/dependent_required.rb +49 -0
- data/lib/jsi/schema/elements/dependent_schemas.rb +69 -0
- data/lib/jsi/schema/elements/dynamic_ref.rb +69 -0
- data/lib/jsi/schema/elements/enum.rb +26 -0
- data/lib/jsi/schema/elements/examples.rb +10 -0
- data/lib/jsi/schema/elements/format.rb +10 -0
- data/lib/jsi/schema/elements/id.rb +30 -0
- data/lib/jsi/schema/elements/if_then_else.rb +82 -0
- data/lib/jsi/schema/elements/info_bool.rb +10 -0
- data/lib/jsi/schema/elements/info_string.rb +10 -0
- data/lib/jsi/schema/elements/items.rb +93 -0
- data/lib/jsi/schema/elements/items_prefixed.rb +96 -0
- data/lib/jsi/schema/elements/not.rb +31 -0
- data/lib/jsi/schema/elements/numeric.rb +137 -0
- data/lib/jsi/schema/elements/numeric_draft04.rb +77 -0
- data/lib/jsi/schema/elements/object_validation.rb +55 -0
- data/lib/jsi/schema/elements/pattern.rb +35 -0
- data/lib/jsi/schema/elements/properties.rb +145 -0
- data/lib/jsi/schema/elements/property_names.rb +48 -0
- data/lib/jsi/schema/elements/ref.rb +62 -0
- data/lib/jsi/schema/elements/required.rb +34 -0
- data/lib/jsi/schema/elements/self.rb +24 -0
- data/lib/jsi/schema/elements/some_of.rb +180 -0
- data/lib/jsi/schema/elements/string_validation.rb +57 -0
- data/lib/jsi/schema/elements/type.rb +43 -0
- data/lib/jsi/schema/elements/unevaluated_items.rb +54 -0
- data/lib/jsi/schema/elements/unevaluated_properties.rb +54 -0
- data/lib/jsi/schema/elements/xschema.rb +10 -0
- data/lib/jsi/schema/elements/xvocabulary.rb +10 -0
- data/lib/jsi/schema/elements.rb +101 -0
- data/lib/jsi/schema/issue.rb +3 -4
- data/lib/jsi/schema/schema_ancestor_node.rb +103 -50
- data/lib/jsi/schema/vocabulary.rb +36 -0
- data/lib/jsi/schema.rb +520 -338
- data/lib/jsi/schema_classes.rb +168 -124
- data/lib/jsi/schema_set.rb +67 -126
- data/lib/jsi/set.rb +23 -0
- data/lib/jsi/simple_wrap.rb +13 -16
- data/lib/jsi/struct.rb +57 -0
- data/lib/jsi/uri.rb +40 -0
- data/lib/jsi/util/private/memo_map.rb +9 -13
- data/lib/jsi/util/private.rb +57 -12
- data/lib/jsi/util/typelike.rb +19 -64
- data/lib/jsi/util.rb +52 -34
- data/lib/jsi/validation/error.rb +41 -2
- data/lib/jsi/validation/result.rb +118 -71
- data/lib/jsi/validation.rb +1 -6
- data/lib/jsi/version.rb +1 -1
- data/lib/jsi.rb +158 -41
- data/lib/schemas/json-schema.org/draft/2020-12/schema.rb +67 -0
- data/lib/schemas/json-schema.org/draft-04/schema.rb +63 -106
- data/lib/schemas/json-schema.org/draft-06/schema.rb +56 -105
- data/lib/schemas/json-schema.org/draft-07/schema.rb +67 -124
- data/readme.rb +3 -3
- data/{resources}/schemas/2020-12_strict.json +19 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/applicator.json +48 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/content.json +17 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/core.json +51 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-annotation.json +14 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-assertion.json +14 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/meta-data.json +37 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/unevaluated.json +15 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/validation.json +98 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/schema.json +58 -0
- metadata +70 -48
- data/lib/jsi/schema/application/child_application/contains.rb +0 -25
- data/lib/jsi/schema/application/child_application/draft04.rb +0 -21
- data/lib/jsi/schema/application/child_application/draft06.rb +0 -28
- data/lib/jsi/schema/application/child_application/draft07.rb +0 -28
- data/lib/jsi/schema/application/child_application/items.rb +0 -18
- data/lib/jsi/schema/application/child_application/properties.rb +0 -25
- data/lib/jsi/schema/application/child_application.rb +0 -13
- data/lib/jsi/schema/application/draft04.rb +0 -8
- data/lib/jsi/schema/application/draft06.rb +0 -8
- data/lib/jsi/schema/application/draft07.rb +0 -8
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +0 -28
- data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -25
- data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -26
- data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -32
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +0 -20
- data/lib/jsi/schema/application/inplace_application/ref.rb +0 -18
- data/lib/jsi/schema/application/inplace_application/someof.rb +0 -44
- data/lib/jsi/schema/application/inplace_application.rb +0 -14
- data/lib/jsi/schema/application.rb +0 -12
- data/lib/jsi/schema/ref.rb +0 -186
- data/lib/jsi/schema/validation/array.rb +0 -69
- data/lib/jsi/schema/validation/contains.rb +0 -25
- data/lib/jsi/schema/validation/dependencies.rb +0 -49
- data/lib/jsi/schema/validation/draft04/minmax.rb +0 -93
- data/lib/jsi/schema/validation/draft04.rb +0 -110
- data/lib/jsi/schema/validation/draft06.rb +0 -120
- data/lib/jsi/schema/validation/draft07.rb +0 -157
- data/lib/jsi/schema/validation/enum.rb +0 -25
- data/lib/jsi/schema/validation/ifthenelse.rb +0 -46
- data/lib/jsi/schema/validation/items.rb +0 -54
- data/lib/jsi/schema/validation/not.rb +0 -20
- data/lib/jsi/schema/validation/numeric.rb +0 -121
- data/lib/jsi/schema/validation/object.rb +0 -45
- data/lib/jsi/schema/validation/pattern.rb +0 -34
- data/lib/jsi/schema/validation/properties.rb +0 -101
- data/lib/jsi/schema/validation/property_names.rb +0 -32
- data/lib/jsi/schema/validation/ref.rb +0 -40
- data/lib/jsi/schema/validation/required.rb +0 -27
- data/lib/jsi/schema/validation/someof.rb +0 -90
- data/lib/jsi/schema/validation/string.rb +0 -47
- data/lib/jsi/schema/validation/type.rb +0 -49
- data/lib/jsi/schema/validation.rb +0 -49
- data/lib/jsi/schema_registry.rb +0 -200
- data/lib/jsi/util/private/attr_struct.rb +0 -141
data/lib/jsi/metaschema_node.rb
CHANGED
|
@@ -1,117 +1,189 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module JSI
|
|
4
|
-
# A MetaSchemaNode is a JSI instance representing a node in a document that contains a meta-schema
|
|
5
|
-
#
|
|
6
|
-
# the schema describing the root of the document is pointed to by root_schema_ptr.
|
|
4
|
+
# A MetaSchemaNode is a JSI instance representing a node in a document that contains a meta-schema,
|
|
5
|
+
# or contains a schema describing a meta-schema (e.g. a meta-schema vocabulary schema).
|
|
7
6
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
7
|
+
# A meta-schema typically has the unique property that it is an instance of itself.
|
|
8
|
+
# It may also be an instance of a number of other schemas, each of which
|
|
9
|
+
# may be an instance of the meta-schema, itself, and/or other schemas.
|
|
11
10
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
11
|
+
# This is not a configuration of schemas/instances that normal JSI::Base instantiation can accommodate.
|
|
12
|
+
# MetaSchemaNode instead bootstraps each node on initialization, computing and instantiating
|
|
13
|
+
# the schemas that describe it (other MetaSchemaNode instances) and their schema modules.
|
|
14
|
+
# This results in a node that is a meta-schema being an instance of its own schema module
|
|
15
|
+
# (as well as JSI::Schema and JSI::Schema::MetaSchema), and a node that is a schema being an instance of
|
|
16
|
+
# the meta-schema's schema module (and thereby JSI::Schema).
|
|
18
17
|
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
18
|
+
# The meta-schema may be anywhere in a document, though it is rare to put it anywhere but at the root.
|
|
19
|
+
# The root of the meta-schema is referenced by the {MetaSchemaNode::Conf configured}
|
|
20
|
+
# {MetaSchemaNode::Conf#metaschema_root_ref `metaschema_root_ref`}.
|
|
21
|
+
# The schema describing the root of the document is referenced by the configured
|
|
22
|
+
# {MetaSchemaNode::Conf#root_schema_ref `root_schema_ref`}.
|
|
23
23
|
class MetaSchemaNode < Base
|
|
24
24
|
autoload :BootstrapSchema, 'jsi/metaschema_node/bootstrap_schema'
|
|
25
25
|
|
|
26
|
+
# @private - experimental
|
|
27
|
+
# `self` is a MetaSchemaNode
|
|
28
|
+
# @param node [MetaSchemaNode, MetaSchemaNode::BootstrapSchema]
|
|
29
|
+
# @return [Boolean] is `node` a meta-schema?
|
|
30
|
+
DEFAULT_IS_METASCHEMA = proc do |node|
|
|
31
|
+
node.jsi_document.equal?(@bootstrap_metaschema.jsi_document) && node.jsi_ptr == @bootstrap_metaschema.jsi_ptr
|
|
32
|
+
end
|
|
33
|
+
private_constant(:DEFAULT_IS_METASCHEMA)
|
|
34
|
+
|
|
26
35
|
include(Base::Immutable)
|
|
27
36
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
conf_attrs = {
|
|
38
|
+
dialect: {fingerprint: true },
|
|
39
|
+
metaschema_root_ref: {fingerprint: true },
|
|
40
|
+
root_schema_ref: {fingerprint: true },
|
|
41
|
+
bootstrap_registry: {fingerprint: true },
|
|
42
|
+
is_metaschema: {fingerprint: true },
|
|
43
|
+
}.freeze
|
|
44
|
+
Conf = Base::Conf.subclass(*conf_attrs.keys)
|
|
45
|
+
class Conf end
|
|
46
|
+
Conf::ATTRS = Base::Conf::ATTRS.merge(conf_attrs)
|
|
47
|
+
|
|
48
|
+
# {Base::Conf} with additional configuration for MetaSchemaNode.
|
|
49
|
+
#
|
|
50
|
+
# @!attribute dialect
|
|
51
|
+
# @return [Schema::Dialect]
|
|
52
|
+
# @!attribute metaschema_root_ref
|
|
53
|
+
# URI reference to the root of the meta-schema.
|
|
54
|
+
#
|
|
55
|
+
# Default: `"#"` resolves to the root of the `jsi_document`.
|
|
56
|
+
# @return [Addressable::URI]
|
|
57
|
+
# @!attribute root_schema_ref
|
|
58
|
+
# URI reference to the schema describing the root of the jsi_document.
|
|
59
|
+
# When schemas of the meta-schema are in multiple documents, this describes the roots of all instantiated documents.
|
|
60
|
+
#
|
|
61
|
+
# Default: `metaschema_root_ref` value, i.e. the document root is a schema.
|
|
62
|
+
# @return [Addressable::URI]
|
|
63
|
+
# @!attribute bootstrap_registry
|
|
64
|
+
# Default: nil
|
|
65
|
+
# @return [Registry, nil]
|
|
66
|
+
class Conf < Base::Conf
|
|
67
|
+
def initialize(
|
|
68
|
+
dialect: ,
|
|
69
|
+
metaschema_root_ref: '#',
|
|
70
|
+
root_schema_ref: metaschema_root_ref,
|
|
71
|
+
registry: nil, # overrides Base::Conf default value JSI.registry
|
|
72
|
+
is_metaschema: DEFAULT_IS_METASCHEMA,
|
|
73
|
+
**kw
|
|
74
|
+
)
|
|
75
|
+
super(
|
|
76
|
+
dialect: dialect,
|
|
77
|
+
metaschema_root_ref: Util.uri(metaschema_root_ref, nnil: true),
|
|
78
|
+
root_schema_ref: Util.uri(root_schema_ref, nnil: true),
|
|
79
|
+
registry: registry,
|
|
80
|
+
is_metaschema: is_metaschema,
|
|
81
|
+
**kw,
|
|
82
|
+
)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# See {JSI.new_metaschema_node} to instantiate.
|
|
87
|
+
#
|
|
88
|
+
# Note: when instantiating MetaSchemaNode directly, the caller must invoke #jsi_initialize_finish.
|
|
89
|
+
# @api private
|
|
38
90
|
def initialize(
|
|
39
|
-
|
|
40
|
-
jsi_ptr: Ptr[],
|
|
41
|
-
schema_implementation_modules: ,
|
|
42
|
-
metaschema_root_ptr: Ptr[],
|
|
43
|
-
root_schema_ptr: Ptr[],
|
|
44
|
-
jsi_schema_base_uri: nil,
|
|
45
|
-
jsi_schema_registry: nil,
|
|
46
|
-
jsi_content_to_immutable: DEFAULT_CONTENT_TO_IMMUTABLE,
|
|
47
|
-
jsi_root_node: nil
|
|
91
|
+
**kw
|
|
48
92
|
)
|
|
49
|
-
super(
|
|
50
|
-
jsi_ptr: jsi_ptr,
|
|
93
|
+
super(
|
|
51
94
|
jsi_indicated_schemas: SchemaSet[],
|
|
52
|
-
|
|
53
|
-
jsi_schema_registry: jsi_schema_registry,
|
|
54
|
-
jsi_content_to_immutable: jsi_content_to_immutable,
|
|
55
|
-
jsi_root_node: jsi_root_node,
|
|
95
|
+
**kw,
|
|
56
96
|
)
|
|
57
97
|
|
|
58
|
-
@
|
|
59
|
-
@
|
|
60
|
-
@
|
|
98
|
+
@initialize_finish_started = false
|
|
99
|
+
@initialize_finished = false
|
|
100
|
+
@to_initialize_finish = []
|
|
61
101
|
|
|
62
|
-
if jsi_ptr.root? &&
|
|
63
|
-
raise(NotImplementedError, "unsupported
|
|
102
|
+
if jsi_ptr.root? && jsi_base_uri
|
|
103
|
+
raise(NotImplementedError, "unsupported jsi_base_uri on meta-schema document root")
|
|
64
104
|
end
|
|
65
105
|
|
|
66
|
-
#chkbug
|
|
106
|
+
#chkbug fail(Bug, 'MetaSchemaNode instance must be frozen') unless jsi_node_content.frozen?
|
|
107
|
+
|
|
108
|
+
bootstrap_schema_from_ref = proc do |ref_uri|
|
|
109
|
+
ref_uri_nofrag = ref_uri.merge(fragment: nil)
|
|
110
|
+
|
|
111
|
+
if ref_uri_nofrag.empty?
|
|
112
|
+
ptr = Ptr.from_fragment(ref_uri.fragment).resolve_against(jsi_document) # anchor not supported
|
|
113
|
+
if jsi_conf.root_schema_ref == jsi_conf.metaschema_root_ref
|
|
114
|
+
# root is a schema
|
|
115
|
+
jsi_conf.dialect.bootstrap_schema(
|
|
116
|
+
jsi_document: jsi_document,
|
|
117
|
+
jsi_base_uri: nil, # not supported
|
|
118
|
+
jsi_registry: jsi_conf.bootstrap_registry,
|
|
119
|
+
).resource_root_subschema(ptr)
|
|
120
|
+
else
|
|
121
|
+
jsi_conf.dialect.bootstrap_schema(
|
|
122
|
+
jsi_document: jsi_document,
|
|
123
|
+
jsi_ptr: ptr,
|
|
124
|
+
jsi_base_uri: nil, # not supported
|
|
125
|
+
jsi_registry: jsi_conf.bootstrap_registry,
|
|
126
|
+
)
|
|
127
|
+
end
|
|
128
|
+
else
|
|
129
|
+
# if not fragment-only, ref must be registered in the bootstrap_registry
|
|
130
|
+
ref = Schema::Ref.new(ref_uri, registry: jsi_conf.bootstrap_registry)
|
|
131
|
+
ref.resolve
|
|
132
|
+
end
|
|
133
|
+
end
|
|
67
134
|
|
|
68
|
-
|
|
135
|
+
@bootstrap_metaschema = bootstrap_schema_from_ref[jsi_conf.metaschema_root_ref]
|
|
69
136
|
|
|
70
137
|
instance_for_schemas = jsi_document
|
|
71
|
-
|
|
72
|
-
root_bootstrap_schema = bootstrap_schema_class.new(
|
|
73
|
-
jsi_document,
|
|
74
|
-
jsi_ptr: root_schema_ptr,
|
|
75
|
-
jsi_schema_base_uri: nil, # supplying jsi_schema_base_uri on root bootstrap schema is not supported
|
|
76
|
-
)
|
|
138
|
+
root_bootstrap_schema = bootstrap_schema_from_ref[jsi_conf.root_schema_ref]
|
|
77
139
|
our_bootstrap_indicated_schemas = jsi_ptr.tokens.inject(SchemaSet[root_bootstrap_schema]) do |bootstrap_indicated_schemas, tok|
|
|
78
|
-
|
|
79
|
-
|
|
140
|
+
child_indicated_schemas = bootstrap_indicated_schemas.each_yield_set do |is, y|
|
|
141
|
+
is.each_inplace_child_applicator_schema(tok, instance_for_schemas,
|
|
142
|
+
collect_evaluated_validate: jsi_conf.application_collect_evaluated_validate,
|
|
143
|
+
&y
|
|
144
|
+
)
|
|
145
|
+
end
|
|
80
146
|
instance_for_schemas = instance_for_schemas[tok]
|
|
81
147
|
child_indicated_schemas
|
|
82
148
|
end
|
|
83
|
-
@indicated_schemas_map = jsi_memomap
|
|
149
|
+
@indicated_schemas_map = jsi_memomap do
|
|
150
|
+
SchemaSet.new(our_bootstrap_indicated_schemas) { |s| bootstrap_schema_to_msn(s) }
|
|
151
|
+
end
|
|
84
152
|
|
|
85
|
-
|
|
153
|
+
@bootstrap_schemas = our_bootstrap_indicated_schemas.each_yield_set do |is, y|
|
|
154
|
+
is.each_inplace_applicator_schema(instance_for_schemas, &y) # note: instance_for_schemas == jsi_node_content now
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
@jsi_schemas = @bootstrap_schemas
|
|
86
158
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if bootstrap_schema.jsi_ptr == metaschema_root_ptr
|
|
159
|
+
@bootstrap_schemas.each do |bootstrap_schema|
|
|
160
|
+
if instance_exec(bootstrap_schema, &jsi_conf.is_metaschema)
|
|
90
161
|
# this is described by the meta-schema, i.e. this is a schema
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
162
|
+
define_singleton_method(:dialect) { jsi_conf.dialect }
|
|
163
|
+
extend(Schema)
|
|
164
|
+
|
|
165
|
+
if jsi_registry && jsi_resource_uris.any? { |uri| !jsi_registry.registered?(uri) }
|
|
166
|
+
jsi_registry.register_immediate(self)
|
|
94
167
|
end
|
|
95
|
-
extends += schema_implementation_modules
|
|
96
|
-
end
|
|
97
|
-
if bootstrap_schema.jsi_ptr == jsi_ptr
|
|
98
|
-
# this is the meta-schema (it is described by itself)
|
|
99
|
-
describes_self = true
|
|
100
168
|
end
|
|
101
169
|
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# @api private
|
|
173
|
+
def jsi_initialize_finish
|
|
174
|
+
return self if @initialize_finish_started
|
|
175
|
+
@initialize_finish_started = true
|
|
102
176
|
|
|
103
|
-
@jsi_schemas =
|
|
177
|
+
@jsi_schemas = SchemaSet.new(@bootstrap_schemas) { |s| bootstrap_schema_to_msn(s) }
|
|
104
178
|
|
|
105
179
|
# note: jsi_schemas must already be set for jsi_schema_module to be used/extended
|
|
106
|
-
if
|
|
107
|
-
describes_schema!(
|
|
180
|
+
if instance_exec(self, &jsi_conf.is_metaschema)
|
|
181
|
+
describes_schema!(jsi_conf.dialect)
|
|
108
182
|
end
|
|
109
183
|
|
|
110
184
|
extends_for_instance = JSI::SchemaClasses.includes_for(jsi_node_content)
|
|
111
|
-
extends.merge(extends_for_instance)
|
|
112
|
-
extends.freeze
|
|
113
185
|
|
|
114
|
-
conflicting_modules = Set[self.class] +
|
|
186
|
+
conflicting_modules = Set[self.class] + extends_for_instance + @jsi_schemas.map(&:jsi_schema_module)
|
|
115
187
|
reader_modules = @jsi_schemas.map do |schema|
|
|
116
188
|
JSI::SchemaClasses.schema_property_reader_module(schema, conflicting_modules: conflicting_modules)
|
|
117
189
|
end
|
|
@@ -128,19 +200,15 @@ module JSI
|
|
|
128
200
|
@jsi_schemas.each do |schema|
|
|
129
201
|
extend schema.jsi_schema_module
|
|
130
202
|
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# Set of modules to apply to schemas that are instances of (described by) the meta-schema
|
|
134
|
-
# @return [Set<Module>]
|
|
135
|
-
attr_reader :schema_implementation_modules
|
|
136
203
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
204
|
+
@initialize_finished = true
|
|
205
|
+
while !@to_initialize_finish.empty?
|
|
206
|
+
node = @to_initialize_finish.shift
|
|
207
|
+
node.jsi_initialize_finish
|
|
208
|
+
end
|
|
140
209
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
attr_reader :root_schema_ptr
|
|
210
|
+
jsi_initialized
|
|
211
|
+
end
|
|
144
212
|
|
|
145
213
|
# JSI Schemas describing this MetaSchemaNode
|
|
146
214
|
# @return [JSI::SchemaSet]
|
|
@@ -152,15 +220,10 @@ module JSI
|
|
|
152
220
|
@indicated_schemas_map[]
|
|
153
221
|
end
|
|
154
222
|
|
|
155
|
-
# see {Base#
|
|
156
|
-
def
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
jsi_child_as_jsi(child_node.jsi_node_content, child_node.jsi_schemas, as_jsi) do
|
|
160
|
-
child_node
|
|
161
|
-
end
|
|
223
|
+
# see {Base#jsi_child_node}
|
|
224
|
+
def jsi_child_node(token)
|
|
225
|
+
root_descendent_node(jsi_ptr[token])
|
|
162
226
|
end
|
|
163
|
-
private :jsi_child
|
|
164
227
|
|
|
165
228
|
# See {Base#jsi_default_child}
|
|
166
229
|
def jsi_default_child(token, as_jsi: )
|
|
@@ -168,42 +231,24 @@ module JSI
|
|
|
168
231
|
end
|
|
169
232
|
private :jsi_default_child # internals for #[] but idk, could be public
|
|
170
233
|
|
|
171
|
-
#
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
modified_document = jsi_ptr.modified_document_copy(jsi_document, &block)
|
|
178
|
-
modified_document = jsi_content_to_immutable.call(modified_document) if jsi_content_to_immutable
|
|
179
|
-
MetaSchemaNode.new(modified_document, **our_initialize_params)
|
|
180
|
-
else
|
|
181
|
-
modified_jsi_root_node = jsi_root_node.jsi_modified_copy do |root|
|
|
182
|
-
jsi_ptr.modified_document_copy(root, &block)
|
|
183
|
-
end
|
|
184
|
-
modified_jsi_root_node.jsi_descendent_node(jsi_ptr)
|
|
185
|
-
end
|
|
234
|
+
# @raise [NotImplementedError] not implemented for MetaSchemaNode
|
|
235
|
+
def jsi_modified_copy(**)
|
|
236
|
+
# this had an implementation previously (see git history). but for 2020-12, support for multiple
|
|
237
|
+
# mutually-descriptive schemas as well as dynamic scope makes instantiating a modified copy that
|
|
238
|
+
# preserves self-descriptive/mutually-descriptive relationships generally infeasible.
|
|
239
|
+
raise(NotImplementedError)
|
|
186
240
|
end
|
|
187
241
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
class_n_schemas = -"#{self.class} (#{jsi_schemas.map { |s| s.jsi_schema_module.name_from_ancestor || s.jsi_ptr.uri }.join(' ')})"
|
|
193
|
-
else
|
|
194
|
-
class_n_schemas = self.class.to_s
|
|
195
|
-
end
|
|
196
|
-
[
|
|
197
|
-
class_n_schemas,
|
|
198
|
-
is_a?(Schema::MetaSchema) ? "Meta-Schema" : is_a?(Schema) ? "Schema" : nil,
|
|
199
|
-
*(jsi_node_content.respond_to?(:jsi_object_group_text) ? jsi_node_content.jsi_object_group_text : nil),
|
|
200
|
-
].compact.freeze
|
|
242
|
+
protected def jsi_dynamic_root_instantiate(**kw)
|
|
243
|
+
# self is a resource root being instantiated with overridden dynamic scope
|
|
244
|
+
#chkbug fail unless jsi_ptr.root? # jsi_schema_resource_ancestors not tracked
|
|
245
|
+
to_initialize_finish(MetaSchemaNode.new(**kw))
|
|
201
246
|
end
|
|
202
247
|
|
|
203
248
|
# see {Util::Private::FingerprintHash}
|
|
204
249
|
# @api private
|
|
205
250
|
def jsi_fingerprint
|
|
206
|
-
|
|
251
|
+
jsi_fingerprint_no_schemas
|
|
207
252
|
end
|
|
208
253
|
|
|
209
254
|
protected
|
|
@@ -213,61 +258,83 @@ module JSI
|
|
|
213
258
|
private
|
|
214
259
|
|
|
215
260
|
def jsi_memomaps_initialize
|
|
216
|
-
if
|
|
261
|
+
if equal?(@jsi_root_node)
|
|
217
262
|
@root_descendent_node_map = jsi_memomap(&method(:jsi_root_descendent_node_compute))
|
|
218
263
|
else
|
|
219
264
|
@root_descendent_node_map = @jsi_root_node.root_descendent_node_map
|
|
220
265
|
end
|
|
221
266
|
end
|
|
222
267
|
|
|
223
|
-
# note: does not include jsi_root_node
|
|
224
|
-
def our_initialize_params
|
|
225
|
-
{
|
|
226
|
-
jsi_ptr: jsi_ptr,
|
|
227
|
-
schema_implementation_modules: schema_implementation_modules,
|
|
228
|
-
metaschema_root_ptr: metaschema_root_ptr,
|
|
229
|
-
root_schema_ptr: root_schema_ptr,
|
|
230
|
-
jsi_schema_base_uri: jsi_schema_base_uri,
|
|
231
|
-
jsi_schema_registry: jsi_schema_registry,
|
|
232
|
-
jsi_content_to_immutable: jsi_content_to_immutable,
|
|
233
|
-
}.freeze
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
# note: not for root node
|
|
237
|
-
def new_node(**params)
|
|
238
|
-
MetaSchemaNode.new(jsi_document, jsi_root_node: jsi_root_node, **our_initialize_params, **params)
|
|
239
|
-
end
|
|
240
|
-
|
|
241
268
|
def jsi_root_descendent_node_compute(ptr: )
|
|
242
|
-
#
|
|
269
|
+
# note: self is jsi_root_node
|
|
270
|
+
#chkbug fail(Bug) unless equal?(jsi_root_node)
|
|
243
271
|
if ptr.root?
|
|
244
272
|
self
|
|
245
273
|
else
|
|
246
|
-
|
|
274
|
+
MetaSchemaNode.new(
|
|
275
|
+
jsi_document: jsi_document,
|
|
247
276
|
jsi_ptr: ptr,
|
|
248
|
-
|
|
277
|
+
jsi_base_uri: jsi_next_base_uri,
|
|
278
|
+
jsi_schema_resource_ancestors: is_a?(Schema) ? jsi_subschema_resource_ancestors : Util::EMPTY_ARY,
|
|
279
|
+
# since MSN only supports document root as jsi_resource_root, and jsi_next_schema_dynamic_anchor_map
|
|
280
|
+
# is only passed to descendents that are resource roots, that is not used here.
|
|
281
|
+
jsi_schema_dynamic_anchor_map: jsi_schema_dynamic_anchor_map,
|
|
282
|
+
jsi_root_node: jsi_root_node,
|
|
249
283
|
)
|
|
250
284
|
end
|
|
251
285
|
end
|
|
252
286
|
|
|
253
|
-
# @param
|
|
254
|
-
# @return [
|
|
255
|
-
def
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
287
|
+
# @param ptr [Ptr]
|
|
288
|
+
# @return [MetaSchemaNode]
|
|
289
|
+
protected def root_descendent_node(ptr)
|
|
290
|
+
to_initialize_finish(@root_descendent_node_map[
|
|
291
|
+
ptr: ptr.resolve_against(jsi_document),
|
|
292
|
+
])
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def to_initialize_finish(node)
|
|
296
|
+
if @initialize_finished
|
|
297
|
+
node.jsi_initialize_finish
|
|
298
|
+
else
|
|
299
|
+
@to_initialize_finish.push(node)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
node
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# @param bootstrap_schema [MetaSchemaNode::BootstrapSchema]
|
|
306
|
+
# @return [MetaSchemaNode]
|
|
307
|
+
def bootstrap_schema_to_msn(bootstrap_schema)
|
|
308
|
+
dynamic_anchor_map = Schema::DynamicAnchorMap::EMPTY
|
|
309
|
+
bootstrap_schema.jsi_schema_dynamic_anchor_map.each do |anchor, (bootstrap_anchor_root, anchor_ptrs)|
|
|
310
|
+
msn_anchor_root = bootstrap_schema_to_msn(bootstrap_anchor_root)
|
|
311
|
+
dynamic_anchor_map = dynamic_anchor_map.merge({
|
|
312
|
+
anchor => [msn_anchor_root, anchor_ptrs].freeze,
|
|
313
|
+
}).freeze
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
if bootstrap_schema.jsi_document.equal?(jsi_document)
|
|
317
|
+
root_descendent_node(bootstrap_schema.jsi_ptr).jsi_with_schema_dynamic_anchor_map(dynamic_anchor_map)
|
|
318
|
+
else
|
|
319
|
+
jsi_registry || raise(ResolutionError, "no jsi_registry")
|
|
320
|
+
bootstrap_resource = bootstrap_schema.jsi_resource_root
|
|
321
|
+
resource_uri = bootstrap_resource.jsi_resource_uri || raise(ResolutionError, "no URI: #{bootstrap_resource}")
|
|
322
|
+
if jsi_registry.registered?(resource_uri)
|
|
323
|
+
resource = jsi_registry.find(resource_uri)
|
|
324
|
+
relative_ptr = bootstrap_schema.jsi_ptr.relative_to(bootstrap_resource.jsi_ptr)
|
|
325
|
+
resource.jsi_descendent_node(relative_ptr).jsi_with_schema_dynamic_anchor_map(dynamic_anchor_map)
|
|
261
326
|
else
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
327
|
+
root = to_initialize_finish(MetaSchemaNode.new(
|
|
328
|
+
jsi_document: bootstrap_schema.jsi_document,
|
|
329
|
+
jsi_ptr: Ptr[],
|
|
330
|
+
jsi_base_uri: nil,
|
|
331
|
+
# this seems like the best dynamic_anchor_map to pass
|
|
332
|
+
jsi_schema_dynamic_anchor_map: dynamic_anchor_map.without_node(nil, document: bootstrap_schema.jsi_document, ptr: Ptr[], registry: jsi_registry),
|
|
333
|
+
jsi_conf: jsi_conf,
|
|
334
|
+
))
|
|
335
|
+
root.jsi_descendent_node(bootstrap_schema.jsi_ptr).jsi_with_schema_dynamic_anchor_map(dynamic_anchor_map)
|
|
266
336
|
end
|
|
267
337
|
end
|
|
268
338
|
end
|
|
269
339
|
end
|
|
270
|
-
|
|
271
|
-
# @deprecated after v0.7.0, alias of {MetaSchemaNode}
|
|
272
|
-
MetaschemaNode = MetaSchemaNode
|
|
273
340
|
end
|
data/lib/jsi/ptr.rb
CHANGED
|
@@ -13,7 +13,7 @@ module JSI
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
# raised when a pointer refers to a path in a document that could not be resolved
|
|
16
|
-
class ResolutionError <
|
|
16
|
+
class ResolutionError < JSI::ResolutionError
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
POS_INT_RE = /\A[1-9]\d*\z/
|
|
@@ -61,9 +61,9 @@ module JSI
|
|
|
61
61
|
# => JSI::Ptr["foo bar"]
|
|
62
62
|
#
|
|
63
63
|
# Note: A fragment does not include a leading '#'. The string "#/foo" is a URI containing the
|
|
64
|
-
# fragment "/foo", which should be parsed by `
|
|
64
|
+
# fragment "/foo", which should be parsed by `JSI::URI` before passing to this method, e.g.:
|
|
65
65
|
#
|
|
66
|
-
# JSI::Ptr.from_fragment(
|
|
66
|
+
# JSI::Ptr.from_fragment(JSI::URI["#/foo"].fragment)
|
|
67
67
|
# => JSI::Ptr["foo"]
|
|
68
68
|
#
|
|
69
69
|
# @param fragment [String] a fragment containing a pointer
|
|
@@ -71,7 +71,7 @@ module JSI
|
|
|
71
71
|
# @raise [JSI::Ptr::PointerSyntaxError] when the fragment does not contain a pointer with
|
|
72
72
|
# valid pointer syntax
|
|
73
73
|
def self.from_fragment(fragment)
|
|
74
|
-
from_pointer(
|
|
74
|
+
from_pointer(URI.unescape(fragment))
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
# parse a pointer string and instantiate as a JSI::Ptr
|
|
@@ -129,6 +129,24 @@ module JSI
|
|
|
129
129
|
res
|
|
130
130
|
end
|
|
131
131
|
|
|
132
|
+
# Resolves each token of this pointer in `document`, in particular resolving strings indicating
|
|
133
|
+
# array indices to integers.
|
|
134
|
+
# @param document [Object]
|
|
135
|
+
# @return [Ptr]
|
|
136
|
+
def resolve_against(document)
|
|
137
|
+
return(self) if tokens.empty?
|
|
138
|
+
node = document
|
|
139
|
+
resolved_tokens = nil
|
|
140
|
+
tokens.each_with_index do |token, i|
|
|
141
|
+
resolved_token, node = node_subscript_token_child(node, token)
|
|
142
|
+
next if resolved_token.equal?(token)
|
|
143
|
+
resolved_tokens ||= tokens.dup
|
|
144
|
+
resolved_tokens[i] = resolved_token
|
|
145
|
+
end
|
|
146
|
+
return(self) if !resolved_tokens
|
|
147
|
+
Ptr.new(resolved_tokens.freeze)
|
|
148
|
+
end
|
|
149
|
+
|
|
132
150
|
# the pointer string representation of this pointer
|
|
133
151
|
# @return [String]
|
|
134
152
|
def pointer
|
|
@@ -138,13 +156,13 @@ module JSI
|
|
|
138
156
|
# the fragment string representation of this pointer
|
|
139
157
|
# @return [String]
|
|
140
158
|
def fragment
|
|
141
|
-
|
|
159
|
+
URI.escape(pointer).freeze
|
|
142
160
|
end
|
|
143
161
|
|
|
144
162
|
# a URI consisting of a fragment containing this pointer's fragment string representation
|
|
145
|
-
# @return [
|
|
163
|
+
# @return [URI]
|
|
146
164
|
def uri
|
|
147
|
-
|
|
165
|
+
URI.new(fragment: fragment).freeze
|
|
148
166
|
end
|
|
149
167
|
|
|
150
168
|
# whether this pointer is empty, i.e. it has no tokens
|
|
@@ -175,11 +193,6 @@ module JSI
|
|
|
175
193
|
tokens == other_ptr.tokens[0...tokens.size]
|
|
176
194
|
end
|
|
177
195
|
|
|
178
|
-
# @deprecated
|
|
179
|
-
def contains?(other_ptr)
|
|
180
|
-
ancestor_of?(other_ptr)
|
|
181
|
-
end
|
|
182
|
-
|
|
183
196
|
# part of this pointer relative to the given ancestor_ptr
|
|
184
197
|
# @return [JSI::Ptr]
|
|
185
198
|
# @raise [JSI::Ptr::Error] if the given ancestor_ptr is not an ancestor of this pointer
|
|
@@ -196,6 +209,7 @@ module JSI
|
|
|
196
209
|
# @return [JSI::Ptr]
|
|
197
210
|
def +(ptr)
|
|
198
211
|
if ptr.is_a?(Ptr)
|
|
212
|
+
return(ptr) if tokens.empty?
|
|
199
213
|
ptr_tokens = ptr.tokens
|
|
200
214
|
elsif ptr.respond_to?(:to_ary)
|
|
201
215
|
ptr_tokens = ptr
|
|
@@ -210,10 +224,12 @@ module JSI
|
|
|
210
224
|
# @return [JSI::Ptr]
|
|
211
225
|
# @raise [ArgumentError] if n is not between 0 and the size of our tokens
|
|
212
226
|
def take(n)
|
|
227
|
+
return(EMPTY) if n == 0
|
|
228
|
+
return(self) if n == tokens.size
|
|
213
229
|
unless n.is_a?(Integer) && n >= 0 && n <= tokens.size
|
|
214
230
|
raise(ArgumentError, "n not in range (0..#{tokens.size}): #{n.inspect}")
|
|
215
231
|
end
|
|
216
|
-
|
|
232
|
+
Ptr.new(tokens.take(n).freeze)
|
|
217
233
|
end
|
|
218
234
|
|
|
219
235
|
# appends the given token to this pointer's tokens and returns the result
|
|
@@ -249,13 +265,13 @@ module JSI
|
|
|
249
265
|
cdr = tokens.size == 1 ? EMPTY : Ptr.new(tokens[1..-1].freeze)
|
|
250
266
|
token, document_child = node_subscript_token_child(document, car)
|
|
251
267
|
modified_document_child = cdr.modified_document_copy(document_child, &block)
|
|
252
|
-
if modified_document_child.
|
|
268
|
+
if modified_document_child.equal?(document_child)
|
|
253
269
|
document
|
|
254
270
|
else
|
|
255
271
|
modified_document = document.respond_to?(:[]=) ? document.dup :
|
|
256
272
|
document.respond_to?(:to_hash) ? document.to_hash.dup :
|
|
257
273
|
document.respond_to?(:to_ary) ? document.to_ary.dup :
|
|
258
|
-
|
|
274
|
+
fail(Bug) # not possible; node_subscript_token_child would have raised
|
|
259
275
|
modified_document[token] = modified_document_child
|
|
260
276
|
modified_document
|
|
261
277
|
end
|
|
@@ -284,6 +300,7 @@ module JSI
|
|
|
284
300
|
private
|
|
285
301
|
|
|
286
302
|
def node_subscript_token_child(value, token, *a, **kw)
|
|
303
|
+
token = token.jsi_node_content if token.is_a?(Schema::SchemaAncestorNode)
|
|
287
304
|
if value.respond_to?(:to_ary)
|
|
288
305
|
if token.is_a?(String) && (token == '0' || token =~ POS_INT_RE)
|
|
289
306
|
token = token.to_i
|