module JSI
class MetaschemaNode < Base
autoload :BootstrapSchema, 'jsi/metaschema_node/bootstrap_schema'
def initialize(
jsi_document,
jsi_ptr: Ptr[],
schema_implementation_modules: ,
metaschema_root_ptr: Ptr[],
root_schema_ptr: Ptr[],
jsi_schema_base_uri: nil,
jsi_schema_registry: nil,
jsi_root_node: nil
)
super(jsi_document,
jsi_ptr: jsi_ptr,
jsi_indicated_schemas: SchemaSet[],
jsi_schema_base_uri: jsi_schema_base_uri,
jsi_schema_registry: jsi_schema_registry,
jsi_root_node: jsi_root_node,
)
@schema_implementation_modules = Util.ensure_module_set(schema_implementation_modules)
@metaschema_root_ptr = metaschema_root_ptr
@root_schema_ptr = root_schema_ptr
if jsi_ptr.root? && jsi_schema_base_uri
raise(NotImplementedError, "unsupported jsi_schema_base_uri on metaschema document root")
end
jsi_node_content = self.jsi_node_content
extends = Set[]
instance_for_schemas = jsi_document
bootstrap_schema_class = JSI::SchemaClasses.bootstrap_schema_class(schema_implementation_modules)
root_bootstrap_schema = bootstrap_schema_class.new(
jsi_document,
jsi_ptr: root_schema_ptr,
jsi_schema_base_uri: nil, )
our_bootstrap_indicated_schemas = jsi_ptr.tokens.inject(SchemaSet[root_bootstrap_schema]) do |bootstrap_indicated_schemas, tok|
bootstrap_schemas = bootstrap_indicated_schemas.inplace_applicator_schemas(instance_for_schemas)
child_indicated_schemas = bootstrap_schemas.child_applicator_schemas(tok, instance_for_schemas)
instance_for_schemas = instance_for_schemas[tok]
child_indicated_schemas
end
@indicated_schemas_map = jsi_memomap { bootstrap_schemas_to_msn(our_bootstrap_indicated_schemas) }
our_bootstrap_schemas = our_bootstrap_indicated_schemas.inplace_applicator_schemas(instance_for_schemas)
our_bootstrap_schemas.each do |bootstrap_schema|
if bootstrap_schema.jsi_ptr == metaschema_root_ptr
extend Schema
schema_implementation_modules.each do |schema_implementation_module|
extend schema_implementation_module
end
extends += schema_implementation_modules
end
if bootstrap_schema.jsi_ptr == jsi_ptr
extend Metaschema
extends << Metaschema
end
end
@jsi_schemas = bootstrap_schemas_to_msn(our_bootstrap_schemas)
if is_a?(Metaschema)
describes_schema!(schema_implementation_modules)
end
extends_for_instance = JSI::SchemaClasses.includes_for(jsi_node_content)
extends.merge(extends_for_instance)
extends.freeze
conflicting_modules = Set[self.class] + extends + @jsi_schemas.map(&:jsi_schema_module)
reader_modules = @jsi_schemas.map do |schema|
JSI::SchemaClasses.schema_property_reader_module(schema, conflicting_modules: conflicting_modules)
end
readers = reader_modules.map(&:jsi_property_readers).inject(Set[], &:merge).freeze
define_singleton_method(:jsi_property_readers) { readers }
reader_modules.each { |reader_module| extend reader_module }
extends_for_instance.each do |m|
extend m
end
@jsi_schemas.each do |schema|
extend schema.jsi_schema_module
end
end
attr_reader :schema_implementation_modules
attr_reader :metaschema_root_ptr
attr_reader :root_schema_ptr
attr_reader :jsi_schemas
def jsi_indicated_schemas
@indicated_schemas_map[]
end
def jsi_child(token, as_jsi: )
child_node = @root_descendent_node_map[ptr: jsi_ptr[token]]
jsi_child_as_jsi(jsi_node_content_child(token), child_node.jsi_schemas, as_jsi) do
child_node
end
end
private :jsi_child
def jsi_default_child(token, as_jsi: )
jsi_node_content_child(token)
end
private :jsi_default_child
def jsi_modified_copy(&block)
if jsi_ptr.root?
modified_document = jsi_ptr.modified_document_copy(jsi_document, &block)
MetaschemaNode.new(modified_document, **our_initialize_params)
else
modified_jsi_root_node = jsi_root_node.jsi_modified_copy do |root|
jsi_ptr.modified_document_copy(root, &block)
end
modified_jsi_root_node.jsi_descendent_node(jsi_ptr)
end
end
def jsi_object_group_text
if jsi_schemas && jsi_schemas.any?
class_n_schemas = -"#{self.class} (#{jsi_schemas.map { |s| s.jsi_schema_module.name_from_ancestor || s.jsi_ptr.uri }.join(' ')})"
else
class_n_schemas = self.class.to_s
end
[
class_n_schemas,
is_a?(Metaschema) ? "Metaschema" : is_a?(Schema) ? "Schema" : nil,
*(jsi_node_content.respond_to?(:jsi_object_group_text) ? jsi_node_content.jsi_object_group_text : nil),
].compact
end
def jsi_fingerprint
{class: self.class, jsi_document: jsi_document}.merge(our_initialize_params)
end
protected
attr_reader :root_descendent_node_map
private
def jsi_memomaps_initialize
if jsi_ptr.root?
@root_descendent_node_map = jsi_memomap(key_by: proc { |i| i[:ptr] }, &method(:jsi_root_descendent_node_compute))
else
@root_descendent_node_map = @jsi_root_node.root_descendent_node_map
end
end
def our_initialize_params
{
jsi_ptr: jsi_ptr,
schema_implementation_modules: schema_implementation_modules,
metaschema_root_ptr: metaschema_root_ptr,
root_schema_ptr: root_schema_ptr,
jsi_schema_base_uri: jsi_schema_base_uri,
jsi_schema_registry: jsi_schema_registry,
}
end
def new_node(**params)
MetaschemaNode.new(jsi_document, jsi_root_node: jsi_root_node, **our_initialize_params, **params)
end
def jsi_root_descendent_node_compute(ptr: )
if ptr.root?
self
else
new_node(
jsi_ptr: ptr,
jsi_schema_base_uri: jsi_resource_ancestor_uri,
)
end
end
def bootstrap_schemas_to_msn(bootstrap_schemas)
SchemaSet.new(bootstrap_schemas) do |bootstrap_schema|
if bootstrap_schema.jsi_ptr == jsi_ptr
self
elsif bootstrap_schema.jsi_ptr.root?
@jsi_root_node
else
new_node(
jsi_ptr: bootstrap_schema.jsi_ptr,
jsi_schema_base_uri: bootstrap_schema.jsi_schema_base_uri,
)
end
end
end
end
end