lutaml-model 0.8.19 → 0.8.23

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.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/dependent-tests.yml +1 -1
  3. data/.github/workflows/rake.yml +1 -0
  4. data/.rubocop.yml +1 -1
  5. data/.rubocop_todo.yml +133 -72
  6. data/bench/bench_common.rb +8 -5
  7. data/bench/bench_niso.rb +1 -2
  8. data/bench/gate_config.rb +4 -1
  9. data/benchmark/serialization_benchmark.rb +4 -4
  10. data/docs/_guides/value-transformations.adoc +27 -0
  11. data/docs/_guides/xml-mapping.adoc +31 -0
  12. data/lib/compat/opal/generate_boot.rb +3 -1
  13. data/lib/compat/opal/lutaml_model_boot.rb +10 -7
  14. data/lib/compat/opal/moxml_boot.rb +6 -1
  15. data/lib/lutaml/hash_format/format.rb +29 -0
  16. data/lib/lutaml/hash_format.rb +5 -27
  17. data/lib/lutaml/json/adapter/oj_adapter.rb +7 -0
  18. data/lib/lutaml/json/adapter/standard_adapter.rb +17 -5
  19. data/lib/lutaml/json/format.rb +61 -0
  20. data/lib/lutaml/json/generator_options.rb +62 -0
  21. data/lib/lutaml/json.rb +4 -59
  22. data/lib/lutaml/jsonl/adapter/standard_adapter.rb +1 -1
  23. data/lib/lutaml/jsonl/format.rb +22 -0
  24. data/lib/lutaml/jsonl.rb +5 -19
  25. data/lib/lutaml/jsonld/adapter.rb +12 -4
  26. data/lib/lutaml/key_value/adapter/json/oj_adapter.rb +7 -0
  27. data/lib/lutaml/key_value/adapter/json/standard_adapter.rb +17 -5
  28. data/lib/lutaml/key_value/adapter/jsonl/standard_adapter.rb +1 -1
  29. data/lib/lutaml/key_value/format.rb +26 -0
  30. data/lib/lutaml/key_value/transform.rb +4 -1
  31. data/lib/lutaml/key_value/transformation/value_serializer.rb +0 -2
  32. data/lib/lutaml/key_value.rb +4 -21
  33. data/lib/lutaml/model/attribute.rb +38 -4
  34. data/lib/lutaml/model/collection.rb +7 -2
  35. data/lib/lutaml/model/compiled_rule.rb +1 -1
  36. data/lib/lutaml/model/config.rb +2 -2
  37. data/lib/lutaml/model/consolidation_map.rb +2 -2
  38. data/lib/lutaml/model/consolidation_rule/dispatch_block.rb +2 -2
  39. data/lib/lutaml/model/errors.rb +2 -2
  40. data/lib/lutaml/model/global_context.rb +4 -2
  41. data/lib/lutaml/model/mapping/mapping_rule.rb +4 -1
  42. data/lib/lutaml/model/mapping/model_mapping.rb +2 -2
  43. data/lib/lutaml/model/runtime_compatibility.rb +2 -2
  44. data/lib/lutaml/model/schema/class_loader.rb +2 -1
  45. data/lib/lutaml/model/schema/decorators/definition_collection.rb +4 -4
  46. data/lib/lutaml/model/schema/definitions/namespace.rb +2 -1
  47. data/lib/lutaml/model/schema/file_writer.rb +5 -2
  48. data/lib/lutaml/model/schema/renderers/base.rb +4 -3
  49. data/lib/lutaml/model/schema/renderers/mappings.rb +9 -3
  50. data/lib/lutaml/model/schema/renderers/member_decls.rb +9 -3
  51. data/lib/lutaml/model/schema/renderers/model.rb +18 -6
  52. data/lib/lutaml/model/schema/renderers/required_files_calculator.rb +2 -1
  53. data/lib/lutaml/model/schema/renderers.rb +2 -1
  54. data/lib/lutaml/model/schema/rnc_compiler/source_resolver.rb +6 -2
  55. data/lib/lutaml/model/schema/rnc_compiler.rb +3 -1
  56. data/lib/lutaml/model/schema/rng_compiler/element_visitor.rb +35 -15
  57. data/lib/lutaml/model/schema/rng_compiler/value_type_resolver.rb +4 -2
  58. data/lib/lutaml/model/schema/rng_compiler.rb +10 -5
  59. data/lib/lutaml/model/schema/xml_compiler/element_order.rb +2 -1
  60. data/lib/lutaml/model/schema/xml_compiler/spec_builder/complex_types.rb +4 -2
  61. data/lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb +39 -13
  62. data/lib/lutaml/model/schema/xml_compiler/spec_builder.rb +29 -10
  63. data/lib/lutaml/model/schema/xml_compiler/supported_data_types.rb +2 -2
  64. data/lib/lutaml/model/schema/xml_compiler.rb +10 -5
  65. data/lib/lutaml/model/sequence.rb +4 -4
  66. data/lib/lutaml/model/serialization_adapter.rb +1 -1
  67. data/lib/lutaml/model/serialize/attribute_definition.rb +1 -0
  68. data/lib/lutaml/model/serialize/format_conversion.rb +40 -9
  69. data/lib/lutaml/model/serialize/initialization.rb +9 -1
  70. data/lib/lutaml/model/serialize/model_import.rb +1 -0
  71. data/lib/lutaml/model/serialize.rb +22 -3
  72. data/lib/lutaml/model/transformation.rb +5 -0
  73. data/lib/lutaml/model/type/uninitialized_class_guard.rb +1 -1
  74. data/lib/lutaml/model/type.rb +9 -0
  75. data/lib/lutaml/model/type_registry.rb +2 -2
  76. data/lib/lutaml/model/uninitialized_class.rb +1 -1
  77. data/lib/lutaml/model/union.rb +5 -2
  78. data/lib/lutaml/model/utils.rb +2 -2
  79. data/lib/lutaml/model/value_policy.rb +27 -0
  80. data/lib/lutaml/model/version.rb +1 -1
  81. data/lib/lutaml/model.rb +17 -16
  82. data/lib/lutaml/rdf/mapping.rb +2 -2
  83. data/lib/lutaml/rdf/namespace_set.rb +2 -2
  84. data/lib/lutaml/rdf/transform.rb +2 -2
  85. data/lib/lutaml/toml/format.rb +48 -0
  86. data/lib/lutaml/toml.rb +5 -46
  87. data/lib/lutaml/xml/adapter/base_adapter.rb +2 -2
  88. data/lib/lutaml/xml/builder/base.rb +2 -2
  89. data/lib/lutaml/xml/format.rb +331 -0
  90. data/lib/lutaml/xml/mapping.rb +26 -2
  91. data/lib/lutaml/xml/mapping_rule.rb +62 -3
  92. data/lib/lutaml/xml/model_transform.rb +183 -55
  93. data/lib/lutaml/xml/namespace_collector.rb +3 -3
  94. data/lib/lutaml/xml/parse_session.rb +59 -0
  95. data/lib/lutaml/xml/parsed_namespace_set.rb +2 -2
  96. data/lib/lutaml/xml/schema/builder.rb +5 -5
  97. data/lib/lutaml/xml/schema/xsd/schema_location_mapping.rb +2 -2
  98. data/lib/lutaml/xml/schema/xsd.rb +0 -2
  99. data/lib/lutaml/xml/schema/xsd_schema.rb +2 -1
  100. data/lib/lutaml/xml/serialization/format_conversion.rb +3 -3
  101. data/lib/lutaml/xml/transformation/element_builder.rb +2 -1
  102. data/lib/lutaml/xml/transformation/ordered_applier.rb +2 -1
  103. data/lib/lutaml/xml/transformation.rb +29 -0
  104. data/lib/lutaml/xml/xml_element.rb +2 -0
  105. data/lib/lutaml/xml.rb +4 -328
  106. data/lib/lutaml/yaml/format.rb +30 -0
  107. data/lib/lutaml/yaml.rb +5 -28
  108. data/lib/lutaml/yamls/adapter/mapping.rb +2 -2
  109. data/lib/lutaml/yamls/format.rb +22 -0
  110. data/lib/lutaml/yamls.rb +5 -19
  111. data/lib/tasks/benchmark_runner.rb +2 -2
  112. data/lutaml-model.gemspec +1 -1
  113. data/spec/lutaml/json/adapter/standard_adapter_spec.rb +159 -0
  114. data/spec/lutaml/jsonld/adapter_spec.rb +19 -0
  115. data/spec/lutaml/model/attribute_apply_value_map_spec.rb +26 -13
  116. data/spec/lutaml/model/attribute_spec.rb +8 -3
  117. data/spec/lutaml/model/collection_spec.rb +1 -1
  118. data/spec/lutaml/model/collection_state_nesting_spec.rb +44 -0
  119. data/spec/lutaml/model/custom_bibtex_adapter_spec.rb +2 -2
  120. data/spec/lutaml/model/custom_from_empty_values_spec.rb +74 -0
  121. data/spec/lutaml/model/custom_vobject_adapter_spec.rb +8 -8
  122. data/spec/lutaml/model/defaults_spec.rb +45 -0
  123. data/spec/lutaml/model/generator_defaults_spec.rb +101 -0
  124. data/spec/lutaml/model/json_spec.rb +1 -2
  125. data/spec/lutaml/model/json_state_nesting_spec.rb +82 -0
  126. data/spec/lutaml/model/serialize/builder_spec.rb +6 -3
  127. data/spec/lutaml/model/store_spec.rb +3 -1
  128. data/spec/lutaml/model/transform_apply_value_map_spec.rb +6 -3
  129. data/spec/lutaml/model/union_attribute_spec.rb +4 -2
  130. data/spec/lutaml/model/value_policy_spec.rb +82 -0
  131. data/spec/lutaml/require_load_order_spec.rb +25 -0
  132. data/spec/lutaml/xml/attribute_element_namespace_disjoint_spec.rb +88 -0
  133. data/spec/lutaml/xml/attribute_namespace_disjointness_spec.rb +125 -0
  134. data/spec/lutaml/xml/out_of_namespace_parsing_spec.rb +123 -0
  135. data/spec/lutaml/xml/schema/rnc_compiler_spec.rb +17 -6
  136. data/spec/lutaml/xml/schema/rng_compiler_spec.rb +15 -6
  137. data/spec/lutaml/xml/shared_element_rules_spec.rb +64 -0
  138. data/spec/lutaml/xml/w3c_types_spec.rb +3 -6
  139. metadata +26 -4
data/lib/lutaml/model.rb CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  module Lutaml
4
4
  # Autoload top-level modules (outside Model namespace)
5
- autoload :KeyValue, "#{__dir__}/key_value"
6
- autoload :Json, "#{__dir__}/json"
7
- autoload :Yaml, "#{__dir__}/yaml"
8
- autoload :Toml, "#{__dir__}/toml"
9
- autoload :HashFormat, "#{__dir__}/hash_format"
10
- autoload :Jsonl, "#{__dir__}/jsonl"
11
- autoload :Yamls, "#{__dir__}/yamls"
12
- autoload :Xml, "#{__dir__}/xml"
5
+ autoload :KeyValue, "#{__dir__}/key_value/format"
6
+ autoload :Json, "#{__dir__}/json/format"
7
+ autoload :Yaml, "#{__dir__}/yaml/format"
8
+ autoload :Toml, "#{__dir__}/toml/format"
9
+ autoload :HashFormat, "#{__dir__}/hash_format/format"
10
+ autoload :Jsonl, "#{__dir__}/jsonl/format"
11
+ autoload :Yamls, "#{__dir__}/yamls/format"
12
+ autoload :Xml, "#{__dir__}/xml/format"
13
13
  autoload :JsonLd, "#{__dir__}/jsonld"
14
14
  autoload :YamlLd, "#{__dir__}/yamlld"
15
15
  autoload :Turtle, "#{__dir__}/turtle"
@@ -72,6 +72,7 @@ module Lutaml
72
72
  autoload :CollectionHandler, "#{__dir__}/model/collection_handler"
73
73
  autoload :AttributeValidator, "#{__dir__}/model/attribute_validator"
74
74
  autoload :Attribute, "#{__dir__}/model/attribute"
75
+ autoload :ValuePolicy, "#{__dir__}/model/value_policy"
75
76
  autoload :JsonAdapter, "#{__dir__}/model/json_adapter"
76
77
  autoload :SchemaLocation, "#{__dir__}/model/schema_location"
77
78
  autoload :Validation, "#{__dir__}/model/validation"
@@ -258,14 +259,14 @@ end
258
259
 
259
260
  # Format files register DSL methods - use require to ensure proper loading order
260
261
  # These files set up FormatRegistry and detect/configure adapters
261
- require "#{__dir__}/key_value"
262
- require "#{__dir__}/json"
263
- require "#{__dir__}/yaml"
264
- require "#{__dir__}/toml"
265
- require "#{__dir__}/hash_format"
266
- require "#{__dir__}/jsonl"
267
- require "#{__dir__}/yamls"
268
- require "#{__dir__}/xml"
262
+ require "#{__dir__}/key_value/format"
263
+ require "#{__dir__}/json/format"
264
+ require "#{__dir__}/yaml/format"
265
+ require "#{__dir__}/toml/format"
266
+ require "#{__dir__}/hash_format/format"
267
+ require "#{__dir__}/jsonl/format"
268
+ require "#{__dir__}/yamls/format"
269
+ require "#{__dir__}/xml/format"
269
270
 
270
271
  # Optional formats: require "lutaml/jsonld" or "lutaml/turtle" to enable.
271
272
  # These are not eagerly loaded because they depend on optional gems
@@ -19,8 +19,8 @@ module Lutaml
19
19
  @namespace_set = Lutaml::Rdf::NamespaceSet.new(*namespace_classes)
20
20
  end
21
21
 
22
- def subject(&)
23
- @rdf_subject = Proc.new(&) if block_given?
22
+ def subject(&block)
23
+ @rdf_subject = Proc.new(&block) if block
24
24
  end
25
25
 
26
26
  def type(value)
@@ -38,8 +38,8 @@ module Lutaml
38
38
  nil
39
39
  end
40
40
 
41
- def each(&)
42
- @by_prefix.each_value(&)
41
+ def each(&block)
42
+ @by_prefix.each_value(&block)
43
43
  end
44
44
 
45
45
  def size
@@ -17,9 +17,9 @@ module Lutaml
17
17
  mapping.rdf_type.map { |t| resolve_single_type_uri(mapping, t) }
18
18
  end
19
19
 
20
- def each_member(instance, member_rule, &)
20
+ def each_member(instance, member_rule, &block)
21
21
  collection = Array(instance.public_send(member_rule.attr_name))
22
- collection.each(&)
22
+ collection.each(&block)
23
23
  end
24
24
 
25
25
  def member_mapping_for(member, format)
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Internal TOML format implementation. Loaded from lib/lutaml/toml.rb
4
+ # (the public entrypoint) and from lib/lutaml/model.rb (so the model
5
+ # entrypoint triggers the registration side effects).
6
+ # No require_relative "model" here — keeps the require graph acyclic.
7
+
8
+ require "lutaml/model/runtime_compatibility"
9
+ require_relative "../key_value/format"
10
+ require_relative "adapter"
11
+
12
+ module Lutaml
13
+ module Toml
14
+ class Error < StandardError; end
15
+
16
+ # Convenience aliases for common classes at the module level
17
+ # Allows Lutaml::Toml::Mapping to resolve to Lutaml::Toml::Adapter::Mapping
18
+ def self.const_missing(name)
19
+ if Adapter.const_defined?(name, false)
20
+ Adapter.const_get(name, false)
21
+ else
22
+ super
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ Lutaml::Model::FormatRegistry.register(
29
+ :toml,
30
+ mapping_class: Lutaml::Toml::Adapter::Mapping,
31
+ adapter_class: nil,
32
+ transformer: Lutaml::Toml::Adapter::Transform,
33
+ key_value: true,
34
+ adapter_options: if Lutaml::Model.opal?
35
+ nil
36
+ else
37
+ {
38
+ available: %i[tomlib toml_rb],
39
+ default: Lutaml::Model::RuntimeCompatibility.windows? ? :toml_rb : :tomlib,
40
+ }
41
+ end,
42
+ )
43
+
44
+ require_relative "type/serializers"
45
+ Lutaml::Toml::Type::Serializers.register_all!
46
+
47
+ # Auto-detection is now handled lazily by AdapterResolver on first use.
48
+ # No eager adapter selection at require time.
data/lib/lutaml/toml.rb CHANGED
@@ -1,48 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # TOML format module
4
- # Provides Lutaml::Toml namespace for TOML serialization
5
-
6
- require "lutaml/model/runtime_compatibility"
7
- require_relative "key_value"
8
- require_relative "toml/adapter"
9
-
10
- module Lutaml
11
- module Toml
12
- class Error < StandardError; end
13
-
14
- # Convenience aliases for common classes at the module level
15
- # Allows Lutaml::Toml::Mapping to resolve to Lutaml::Toml::Adapter::Mapping
16
- def self.const_missing(name)
17
- if Adapter.const_defined?(name, false)
18
- Adapter.const_get(name, false)
19
- else
20
- super
21
- end
22
- end
23
- end
24
- end
25
-
26
- # Register TOML format with the format registry
27
- Lutaml::Model::FormatRegistry.register(
28
- :toml,
29
- mapping_class: Lutaml::Toml::Adapter::Mapping,
30
- adapter_class: nil,
31
- transformer: Lutaml::Toml::Adapter::Transform,
32
- key_value: true,
33
- adapter_options: if Lutaml::Model.opal?
34
- nil
35
- else
36
- {
37
- available: %i[tomlib toml_rb],
38
- default: Lutaml::Model::RuntimeCompatibility.windows? ? :toml_rb : :tomlib,
39
- }
40
- end,
41
- )
42
-
43
- # Register TOML type serializers
44
- require_relative "toml/type/serializers"
45
- Lutaml::Toml::Type::Serializers.register_all!
46
-
47
- # Auto-detection is now handled lazily by AdapterResolver on first use.
48
- # No eager adapter selection at require time.
3
+ # Public TOML format entrypoint. Loads the base model and the internal
4
+ # implementation. The internal file does not require the model back,
5
+ # which keeps the require graph acyclic.
6
+ require_relative "model"
7
+ require_relative "toml/format"
@@ -215,8 +215,8 @@ module Lutaml
215
215
 
216
216
  private
217
217
 
218
- def attribute_values(element, &)
219
- element.attributes.each_value(&)
218
+ def attribute_values(element, &block)
219
+ element.attributes.each_value(&block)
220
220
  end
221
221
 
222
222
  def schema_location_attribute?(attr)
@@ -180,9 +180,9 @@ module Lutaml
180
180
  result
181
181
  end
182
182
 
183
- def method_missing(method_name, *args, &)
183
+ def method_missing(method_name, *args, &block)
184
184
  attrs = args.first.is_a?(Hash) ? args.first : {}
185
- create_and_add_element(method_name.to_s, attributes: attrs, &)
185
+ create_and_add_element(method_name.to_s, attributes: attrs, &block)
186
186
  end
187
187
 
188
188
  def respond_to_missing?(_method_name, _include_private = false)
@@ -0,0 +1,331 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Lutaml::Xml - XML serialization module for LutaML
4
+ #
5
+ # This module provides XML-specific serialization functionality.
6
+ # It requires lutaml/model to be loaded first for base classes.
7
+
8
+ # Ensure base model is loaded
9
+
10
+ # XML requires moxml for parsing
11
+ require "moxml"
12
+
13
+ # Under Opal, moxml's autoloads don't fire (Opal ignores autoload).
14
+ # Pull in the eager-load boot that ships at lib/compat/opal/moxml_boot.rb
15
+ # so Moxml::Adapter::{Oga,Rexml} etc. are actually defined. Without
16
+ # this, `Config.adapter = :oga` later fails with
17
+ # `NameError: uninitialized constant Moxml::Adapter::Oga`.
18
+ if Lutaml::Model.opal?
19
+ require "moxml_boot"
20
+ end
21
+
22
+ module Lutaml
23
+ module Xml
24
+ # Error module for XML-specific errors
25
+ module Error
26
+ autoload :XmlError, "#{__dir__}/error/xml_error"
27
+ autoload :InvalidNamespaceError,
28
+ "#{__dir__}/error/invalid_namespace_error"
29
+ autoload :InvalidXsdTypeError,
30
+ "#{__dir__}/error/invalid_xsd_type_error"
31
+ autoload :XmlConfigurationError,
32
+ "#{__dir__}/error/xml_configuration_error"
33
+ autoload :NamespaceMismatchError,
34
+ "#{__dir__}/error/namespace_mismatch_error"
35
+ autoload :SchemaValidationError,
36
+ "#{__dir__}/error/schema_validation_error"
37
+ end
38
+
39
+ # XML Configuration modules
40
+ autoload :Configurable, "#{__dir__}/configurable"
41
+ autoload :NamespaceTypeResolver, "#{__dir__}/namespace_type_resolver"
42
+
43
+ # XML Type modules
44
+ module Type
45
+ autoload :ValueXmlMapping, "#{__dir__}/type/value_xml_mapping"
46
+ autoload :Configurable, "#{__dir__}/type/configurable"
47
+ end
48
+
49
+ # XML Serialization modules
50
+ autoload :Serialization, "#{__dir__}/serialization"
51
+
52
+ # XML Schema modules
53
+ autoload :Schema, "#{__dir__}/schema"
54
+
55
+ # Detect available XML adapter.
56
+ # Delegates to moxml, which is the authority on XML adapter
57
+ # availability and platform constraints.
58
+ #
59
+ # @return [Symbol] adapter type name
60
+ def self.detect_xml_adapter
61
+ Moxml::Config.runtime_default_adapter
62
+ end
63
+
64
+ # Get the current XML adapter
65
+ #
66
+ # Provides unified access to the configured XML adapter.
67
+ # This is a convenience method for consistent adapter access across
68
+ # Model and Type classes.
69
+ #
70
+ # @return [Object] the configured XML adapter instance
71
+ #
72
+ # @example Using the adapter
73
+ # adapter = Lutaml::Xml.adapter
74
+ # doc = adapter.parse(xml_string)
75
+ #
76
+ def self.adapter
77
+ Lutaml::Model::Config.adapter_for(:xml)
78
+ end
79
+
80
+ # Get the current XML adapter type
81
+ #
82
+ # @return [Symbol] the configured XML adapter type (:nokogiri, :ox, etc.)
83
+ def self.adapter_type
84
+ Lutaml::Model::Config.xml_adapter_type
85
+ end
86
+
87
+ # Autoload core classes
88
+ autoload :Location, "#{__dir__}/schema_location"
89
+ autoload :SchemaLocation, "#{__dir__}/schema_location"
90
+ autoload :Namespace, "#{__dir__}/namespace"
91
+ autoload :Mapping, "#{__dir__}/mapping"
92
+ autoload :MappingRule, "#{__dir__}/mapping_rule"
93
+ autoload :Listener, "#{__dir__}/listener"
94
+ autoload :Document, "#{__dir__}/document"
95
+ autoload :Transformation, "#{__dir__}/transformation"
96
+ autoload :CustomMethodWrapper,
97
+ "#{__dir__}/transformation/custom_method_wrapper"
98
+ autoload :Transform, "#{__dir__}/transform"
99
+ autoload :XsdValidator, "#{__dir__}/xsd_validator"
100
+ autoload :Adapter, "#{__dir__}/adapter"
101
+ autoload :XmlElement, "#{__dir__}/xml_element"
102
+ autoload :AdapterElement, "#{__dir__}/adapter_element"
103
+ autoload :XmlAttribute, "#{__dir__}/xml_attribute"
104
+ autoload :Decisions, "#{__dir__}/decisions"
105
+ autoload :DeclarationPlan, "#{__dir__}/declaration_plan"
106
+ autoload :DeclarationPlanner, "#{__dir__}/declaration_planner"
107
+ autoload :NamespaceCollector, "#{__dir__}/namespace_collector"
108
+ autoload :NamespaceResolver, "#{__dir__}/namespace_resolver"
109
+ autoload :NamespaceDeclaration, "#{__dir__}/namespace_declaration"
110
+ autoload :NamespaceClassRegistry, "#{__dir__}/namespace_class_registry"
111
+ autoload :BlankNamespace, "#{__dir__}/blank_namespace"
112
+ autoload :EncodingNormalizer, "#{__dir__}/encoding_normalizer"
113
+ autoload :W3c, "#{__dir__}/w3c"
114
+ autoload :NamespaceResolutionStrategy,
115
+ "#{__dir__}/namespace_resolution_strategy"
116
+ autoload :NamespaceInheritanceStrategy,
117
+ "#{__dir__}/namespace_inheritance_strategy"
118
+ autoload :QualifiedInheritanceStrategy,
119
+ "#{__dir__}/qualified_inheritance_strategy"
120
+ autoload :UnqualifiedInheritanceStrategy,
121
+ "#{__dir__}/unqualified_inheritance_strategy"
122
+ autoload :DataModel, "#{__dir__}/data_model"
123
+ autoload :TransformationBuilder, "#{__dir__}/transformation_builder"
124
+ autoload :AdapterLoader, "#{__dir__}/adapter_loader"
125
+ autoload :Element, "#{__dir__}/element"
126
+ autoload :ModelTransform, "#{__dir__}/model_transform"
127
+ autoload :ParseSession, "#{__dir__}/parse_session"
128
+ autoload :TypeNamespaceResolver, "#{__dir__}/type_namespace_resolver"
129
+ autoload :NamespaceNeeds, "#{__dir__}/namespace_needs"
130
+ autoload :NamespaceUsage, "#{__dir__}/namespace_usage"
131
+ autoload :NamespaceDeclarationData,
132
+ "#{__dir__}/namespace_declaration_data"
133
+ autoload :ParsedNamespaceDeclaration,
134
+ "#{__dir__}/parsed_namespace_declaration"
135
+ autoload :ParsedNamespaceSet, "#{__dir__}/parsed_namespace_set"
136
+ autoload :DeclarationHandler, "#{__dir__}/declaration_handler"
137
+ autoload :PolymorphicValueHandler,
138
+ "#{__dir__}/polymorphic_value_handler"
139
+ autoload :AttributeNamespaceResolver,
140
+ "#{__dir__}/attribute_namespace_resolver"
141
+ autoload :BlankNamespaceHandler, "#{__dir__}/blank_namespace_handler"
142
+ autoload :DeclarationPlanQuery, "#{__dir__}/declaration_plan_query"
143
+ autoload :DocTypeExtractor, "#{__dir__}/doctype_extractor"
144
+ autoload :NamespaceDeclarationBuilder,
145
+ "#{__dir__}/namespace_declaration_builder"
146
+ autoload :ElementPrefixResolver, "#{__dir__}/element_prefix_resolver"
147
+ autoload :FormatChooser, "#{__dir__}/format_chooser"
148
+ autoload :HoistingAlgorithm, "#{__dir__}/hoisting_algorithm"
149
+ autoload :NamespaceInheritanceResolver,
150
+ "#{__dir__}/namespace_inheritance_resolver"
151
+ autoload :NamespaceScopeConfig, "#{__dir__}/namespace_scope_config"
152
+ autoload :Builder, "#{__dir__}/builder"
153
+ autoload :TypeNamespace, "#{__dir__}/type_namespace"
154
+ autoload :TransformationSupport, "#{__dir__}/transformation_support"
155
+ autoload :SharedDsl, "#{__dir__}/shared_dsl"
156
+
157
+ autoload :Oga, "#{__dir__}/oga"
158
+ autoload :Rexml, "#{__dir__}/rexml"
159
+ Lutaml::Model::RuntimeCompatibility.autoload_native(
160
+ self,
161
+ NokogiriElement: "#{__dir__}/nokogiri/element",
162
+ Nokogiri: "#{__dir__}/nokogiri",
163
+ Ox: "#{__dir__}/ox",
164
+ )
165
+ end
166
+ end
167
+
168
+ # Register XML format with the model's format registry
169
+ Lutaml::Model::FormatRegistry.register(
170
+ :xml,
171
+ mapping_class: Lutaml::Xml::Mapping,
172
+ adapter_class: nil,
173
+ transformer: Lutaml::Xml::Transform,
174
+ adapter_loader: Lutaml::Xml::AdapterLoader,
175
+ castable_type: Lutaml::Xml::XmlElement,
176
+ key_value: false,
177
+ error_types: %w[
178
+ Moxml::ParseError
179
+ Nokogiri::XML::SyntaxError
180
+ Ox::ParseError
181
+ REXML::ParseException
182
+ ],
183
+ adapter_options: if Lutaml::Model.opal?
184
+ # Both Oga (vendored opal-oga fork, pure-Ruby lexer)
185
+ # and REXML (bundled stdlib gem, pure Ruby) work
186
+ # under Opal. Oga is the default because moxml's CI
187
+ # verifies it most thoroughly; REXML is selectable
188
+ # for callers that prefer a stdlib-only stack.
189
+ {
190
+ available: %i[oga rexml],
191
+ default: :oga,
192
+ }
193
+ else
194
+ {
195
+ available: %i[nokogiri ox oga rexml],
196
+ default: :nokogiri,
197
+ }
198
+ end,
199
+ )
200
+
201
+ # Register XML transformation builder
202
+ Lutaml::Model::TransformationRegistry.register_builder(
203
+ :xml, Lutaml::Xml::TransformationBuilder
204
+ )
205
+
206
+ # Extend Type::Value with XML configuration (namespace, xsd_type, xml block)
207
+ Lutaml::Model::Type::Value.include(Lutaml::Xml::Type::Configurable)
208
+
209
+ # Prepend XML-specific serialization hooks into Serialize::ClassMethods
210
+ # Uses prepend so XML's hook overrides (pre_deserialize_hook, validate_document, etc.)
211
+ # take priority over core's no-op defaults.
212
+ Lutaml::Model::Serialize::ClassMethods.prepend(
213
+ Lutaml::Xml::Serialization::FormatConversion,
214
+ )
215
+
216
+ # Prepend XML-specific ModelImport overrides (root?, ensure_format_mapping_imports!, etc.)
217
+ Lutaml::Model::Serialize::ModelImport.prepend(
218
+ Lutaml::Xml::Serialization::ModelImportExt,
219
+ )
220
+
221
+ # Prepend XML-specific instance methods (import_declaration_plan, validate_root_mapping!, etc.)
222
+ Lutaml::Model::Serialize.prepend(
223
+ Lutaml::Xml::Serialization::InstanceMethods,
224
+ )
225
+
226
+ # Opal does not propagate methods prepended into an already-included module
227
+ # to classes that included it before the prepend. Serializable includes
228
+ # Serialize during model boot, so make the XML instance API available on the
229
+ # concrete base class as well.
230
+ #
231
+ # Anonymous model classes (Class.new { include Serialize }) extend
232
+ # Serialize::ClassMethods rather than inheriting from Serializable, so the
233
+ # ModelImportExt override (root?) must land on ClassMethods too. The other
234
+ # two (FormatConversion, InstanceMethods) are already prepended unconditionally
235
+ # above, so Opal's no-double-prepend rule means we don't repeat them here.
236
+ if Lutaml::Model.opal?
237
+ Lutaml::Model::Serializable.singleton_class.prepend(
238
+ Lutaml::Xml::Serialization::ModelImportExt,
239
+ )
240
+
241
+ Lutaml::Model::Serializable.prepend(
242
+ Lutaml::Xml::Serialization::InstanceMethods,
243
+ )
244
+
245
+ Lutaml::Model::Serialize::ClassMethods.prepend(
246
+ Lutaml::Xml::Serialization::ModelImportExt,
247
+ )
248
+ end
249
+
250
+ # Register XML-specific attribute override warning names
251
+ Lutaml::Model::Attribute.format_specific_warn_names.push(:element_order,
252
+ :schema_location, :encoding, :doctype, :ordered?, :mixed?)
253
+
254
+ # Prepend XML-specific Collection overrides (unwrapped collection handling for XML)
255
+ require_relative "serialization/collection_ext"
256
+ Lutaml::Model::Collection.singleton_class.prepend(
257
+ Lutaml::Xml::Serialization::CollectionExt,
258
+ )
259
+
260
+ # Register XML type serializers
261
+ require_relative "type/serializers"
262
+ Lutaml::Xml::Type::Serializers.register_all!
263
+
264
+ # Register XML schema methods
265
+ Lutaml::Model::Schema.register_method(:to_xsd) do |klass, options = {}|
266
+ if Lutaml::Model.opal?
267
+ raise NotImplementedError,
268
+ "XSD schema generation is not available under Opal."
269
+ end
270
+
271
+ Lutaml::Xml::Schema::XsdSchema.generate(klass, options)
272
+ end
273
+
274
+ Lutaml::Model::Schema.register_method(:to_relaxng) do |klass, options = {}|
275
+ if Lutaml::Model.opal?
276
+ raise NotImplementedError,
277
+ "RELAX NG schema generation requires Nokogiri, " \
278
+ "which is not available under Opal."
279
+ end
280
+
281
+ Lutaml::Xml::Schema::RelaxngSchema.generate(klass, options)
282
+ end
283
+
284
+ Lutaml::Model::Schema.register_method(:from_xml) do |xml, options = {}|
285
+ if Lutaml::Model.opal?
286
+ raise NotImplementedError,
287
+ "XML schema compilation is not available under Opal."
288
+ end
289
+
290
+ Lutaml::Model::Schema::XmlCompiler.to_models(xml, options)
291
+ end
292
+
293
+ Lutaml::Model::Schema.register_method(:from_relaxng) do |rng, options = {}|
294
+ if Lutaml::Model::RuntimeCompatibility.opal?
295
+ raise NotImplementedError,
296
+ "RELAX NG schema compilation is not available under Opal."
297
+ end
298
+
299
+ Lutaml::Model::Schema::RngCompiler.to_models(rng, options)
300
+ end
301
+
302
+ Lutaml::Model::Schema.register_method(:from_rnc) do |rnc, options = {}|
303
+ if Lutaml::Model::RuntimeCompatibility.opal?
304
+ raise NotImplementedError,
305
+ "RNC schema compilation is not available under Opal."
306
+ end
307
+
308
+ Lutaml::Model::Schema::RncCompiler.to_models(rnc, options)
309
+ end
310
+
311
+ # Register XML namespace registry with GlobalContext
312
+ Lutaml::Model::GlobalContext.register_format_registry(
313
+ :xml, Lutaml::Xml::NamespaceClassRegistry.new
314
+ )
315
+
316
+ # Eagerly load W3C namespace definitions (has registration side effects)
317
+ require_relative "w3c"
318
+
319
+ # Auto-detection is now handled lazily by AdapterResolver on first use.
320
+ # No eager adapter selection at require time — libraries can configure
321
+ # their preferred adapter before any XML operations occur.
322
+
323
+ # Namespace identifier validation:
324
+ # - URIs (http://..., urn:...) are valid namespace names per W3C XML
325
+ # Namespaces (RFC 3986). URNs are first-class identifiers (RFC 8141).
326
+ # - Non-URI identifiers (e.g., FPIs like "-//OASIS//...") are also
327
+ # accepted for compatibility, though not spec-compliant.
328
+ # Use lenient mode to support FPIs and non-standard identifiers.
329
+ Moxml.configure do |config|
330
+ config.namespace_validation_mode = :lenient
331
+ end
@@ -818,10 +818,10 @@ module Lutaml
818
818
  # @param group_class [Class] the GroupClass to instantiate (optional, resolved from Organization)
819
819
  # @yield Builder block with gather/dispatch_by or map_element/map_content
820
820
  # @return [ConsolidationMap]
821
- def consolidate_map(by:, to:, group_class: nil, &)
821
+ def consolidate_map(by:, to:, group_class: nil, &block)
822
822
  builder = ::Lutaml::Model::ConsolidationMap::Builder.new(by, to,
823
823
  group_class)
824
- builder.instance_eval(&)
824
+ builder.instance_eval(&block)
825
825
  @consolidation_maps << builder.build
826
826
  end
827
827
 
@@ -1071,6 +1071,30 @@ module Lutaml
1071
1071
  result
1072
1072
  end
1073
1073
 
1074
+ # lutaml-model#765: plain element rules grouped by target attribute
1075
+ # name, for spelling-tolerance mapping (several element names feeding
1076
+ # one attribute). Cached per register so the parse hot path only pays
1077
+ # a hash lookup. Grouping uses rule-level properties only — the
1078
+ # transform applies the collection-attribute filter.
1079
+ #
1080
+ # @return [Hash{Symbol, String => Array<MappingRule>}]
1081
+ def plain_element_rules_by_attr(register_id = nil)
1082
+ reg_key = register_id || :default
1083
+ @plain_element_rules_by_attr ||= {}
1084
+ @plain_element_rules_by_attr[reg_key] ||= begin
1085
+ grouped = {}
1086
+ mappings(reg_key).each do |r|
1087
+ next if r.attribute? || r.raw_mapping? || r.content_mapping? ||
1088
+ r.cdata || r.has_custom_method_for_deserialization? ||
1089
+ (r.transform.is_a?(Hash) && !r.transform.empty?) ||
1090
+ r.transform.is_a?(Class)
1091
+
1092
+ (grouped[r.to] ||= []) << r
1093
+ end
1094
+ grouped
1095
+ end
1096
+ end
1097
+
1074
1098
  def importable_mappings
1075
1099
  @importable_mappings ||= []
1076
1100
  end