lutaml-model 0.8.37 → 0.8.38

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.
@@ -12,6 +12,16 @@ module Lutaml
12
12
  # - Used by model's serialization pipeline via Transform.for(:xml)
13
13
  #
14
14
  class ModelTransform < ::Lutaml::Model::Transform
15
+ require "cgi" unless Lutaml::Model.opal?
16
+
17
+ # Per (model class, register): compiled records for the mapping
18
+ # rules — attribute, derived/valid flags, and #765 group-skip —
19
+ # keyed on the mapping's finalize version so late changes rebuild.
20
+ # The loop body used to re-derive these per parsed instance.
21
+ # Concurrent::Map has no compare_by_identity; class identity is
22
+ # the key semantic here.
23
+ RULE_RECORDS = Concurrent::Map.new # rubocop:disable Lint/HashCompareByIdentity
24
+
15
25
  # Namespaced rule name -> [local_name, rule_uri]. Pure string
16
26
  # splitting, deterministic per spelling, shared across parses.
17
27
  # Concurrent::Map under threaded MRI, plain Hash under Opal.
@@ -36,7 +46,19 @@ module Lutaml
36
46
 
37
47
  instance_is_serialize = model_class.include?(::Lutaml::Model::Serialize)
38
48
  if instance_is_serialize
49
+ # TODO.max-perf/17: the same child element was being re-hydrated
50
+ # per matching rule (593k instantiations for 12k elements on the
51
+ # ISO-13849 profile). Memoize one instance per (element, class)
52
+ # for the whole parse; the memo travels in the propagated
53
+ # deserialization options.
54
+ memo = options[:__lutaml_child_memo] ||= {}
55
+ memo_key = [data.object_id, model_class.object_id]
56
+ if (existing = memo[memo_key])
57
+ return existing
58
+ end
59
+
39
60
  instance = model_class.allocate_for_deserialization(child_register)
61
+ memo[memo_key] = instance
40
62
  else
41
63
  instance = model_class.new
42
64
  register_accessor_methods_for(instance, child_register)
@@ -281,24 +303,33 @@ module Lutaml
281
303
  effective_register,
282
304
  )
283
305
 
306
+ serializable = instance.class.include?(Lutaml::Model::Serialize)
307
+ records = if serializable
308
+ compiled_rule_records(instance.class, effective_register,
309
+ grouped_plain_rules)
310
+ end
284
311
  mappings.each do |rule|
285
- # Performance: Cache rule properties accessed multiple times
286
- rule.name
312
+ record = records&.[](rule)
287
313
  rule_to = rule.to
288
- rule_namespace_set = rule.namespace_set?
289
- rule_namespace_set ? rule.namespace_param : nil
290
314
 
291
- attr = attribute_for_rule(rule)
292
- next if attr&.derived?
315
+ if record
316
+ attr = record.attr
317
+ next if record.derived
318
+ next if record.group_skip
293
319
 
294
- if (group = grouped_plain_rules[rule_to]) &&
295
- group.size > 1 && attr&.collection? && !group.first.equal?(rule)
296
- next
297
- end
320
+ raise "Attribute '#{rule_to}' not found in #{context}" unless record.valid
321
+ else
322
+ attr = attribute_for_rule(rule)
323
+ next if attr&.derived?
298
324
 
299
- raise "Attribute '#{rule_to}' not found in #{context}" unless valid_rule?(
300
- rule, attr
301
- )
325
+ group = grouped_plain_rules[rule_to]
326
+ next if group && group.size > 1 && attr&.collection? &&
327
+ !group.first.equal?(rule)
328
+
329
+ raise "Attribute '#{rule_to}' not found in #{context}" unless valid_rule?(
330
+ rule, attr
331
+ )
332
+ end
302
333
 
303
334
  # Performance: Use pre-computed frozen Hash for static namespace overrides.
304
335
  # Falls back to per-element hash only for the dynamic namespace_uri case.
@@ -371,6 +402,9 @@ module Lutaml
371
402
  value = apply_value_map(value, from_map, attr)
372
403
  value = normalize_xml_value(value, rule, attr, new_opts,
373
404
  effective_register)
405
+ value = decode_html_entities_value(value, decode_html_entities_for(
406
+ instance, effective_register
407
+ ))
374
408
  value = rule.transform_value(attr, value, :from, :xml)
375
409
  # An over-count is normally left for `.validate` to report. A mapped
376
410
  # PORO has no `.validate`, so deferring there would discard the
@@ -379,7 +413,8 @@ module Lutaml
379
413
  !rule.content_mapping?
380
414
  attr.valid_collection!(value, context)
381
415
  end
382
- rule.deserialize(instance, value, attributes, context)
416
+ rule.deserialize(instance, value, attributes, context,
417
+ options[:context])
383
418
 
384
419
  instance.value_set_for(rule_to)
385
420
  end
@@ -512,11 +547,13 @@ _effective_register)
512
547
  # its result array entirely on that path.
513
548
  if rule_names.size == 1
514
549
  rn = rule_names[0]
515
- converted = convert_rule_name_to_attribute_name(doc, rn)
550
+ converted = convert_rule_name_to_attribute_name(doc, rn,
551
+ session: session)
516
552
  value = doc.root.find_attribute_value(converted || rn)
517
553
  else
518
554
  attribute_names = rule_names.map do |rn|
519
- converted = convert_rule_name_to_attribute_name(doc, rn)
555
+ converted = convert_rule_name_to_attribute_name(doc, rn,
556
+ session: session)
520
557
  converted || rn
521
558
  end
522
559
 
@@ -545,7 +582,7 @@ _effective_register)
545
582
  # @param doc [XmlElement] the parsed XML document root
546
583
  # @param rule_name [String] the rule name (e.g., "urn:...:ext", "http://.../ns:val", "my-ns:val")
547
584
  # @return [String, nil] the attribute name to look up, or nil if no conversion needed
548
- def convert_rule_name_to_attribute_name(doc, rule_name)
585
+ def convert_rule_name_to_attribute_name(doc, rule_name, session: nil)
549
586
  return nil unless rule_name.include?(":")
550
587
 
551
588
  # URI-vs-prefix detection works on the whole rule name: the
@@ -564,13 +601,27 @@ _effective_register)
564
601
  # match, and unprefixed_name is not called per attribute
565
602
  # (it splits prefixed names and allocates).
566
603
  local_name = rule_name[(last_colon_index + 1)..]
567
- doc.root.attributes.each_value.find do |attr|
568
- ns = attr.namespace
569
- next false if ns.nil? || ns.length > last_colon_index
570
- next false unless rule_name.start_with?(ns) && rule_name[ns.length] == ":"
604
+ if session
605
+ candidates = session.element_local_attribute_index(doc.root)[local_name]
606
+ # No candidate carries this local name: nothing in the
607
+ # element can match, the scan is skipped entirely.
608
+ matched = candidates&.find do |attr|
609
+ ns = attr.namespace
610
+ next false if ns.nil? || ns.length > last_colon_index
611
+ next false unless rule_name.start_with?(ns) && rule_name[ns.length] == ":"
612
+
613
+ attr.unprefixed_name == local_name
614
+ end
615
+ else
616
+ matched = doc.root.attributes.each_value.find do |attr|
617
+ ns = attr.namespace
618
+ next false if ns.nil? || ns.length > last_colon_index
619
+ next false unless rule_name.start_with?(ns) && rule_name[ns.length] == ":"
571
620
 
572
- attr.unprefixed_name == local_name
573
- end&.name
621
+ attr.unprefixed_name == local_name
622
+ end
623
+ end
624
+ matched&.name
574
625
  else
575
626
  # Simple prefix format: look up the actual prefix from document's namespace declarations
576
627
  # The namespace_part is the namespace URI declared in the document (e.g., "my-ns").
@@ -594,39 +645,46 @@ _effective_register)
594
645
  # @return [String, nil] the attribute value or nil
595
646
  def find_attribute_by_local_name(doc, rule_names,
596
647
  flexible_local: false, session: nil)
597
- root_index = session&.root_local_attribute_index
598
-
599
- rule_names.each do |rn|
600
- next unless rn.include?(":")
601
-
602
- # Splitting a namespaced rule name is pure string work repeated
603
- # per element; memoized per spelling (bounded by the model's
604
- # distinct rule names).
605
- parts = NAMESPACED_NAME_PARTS[rn]
606
- unless parts
607
- last_colon_index = rn.rindex(":")
608
- parts = [rn[(last_colon_index + 1)..], rn[0...last_colon_index]]
609
- NAMESPACED_NAME_PARTS[rn] = parts
610
- end
611
- local_name, rule_uri = parts
648
+ root_index = session&.element_local_attribute_index(doc.root)
612
649
 
613
- candidates = root_index&.[](local_name)
614
- matched_attr = if candidates
615
- candidates.find do |attr|
616
- local_name_match?(attr, local_name, rule_uri,
617
- flexible_local)
618
- end
619
- else
620
- doc.root.attributes.each_value.find do |attr|
621
- local_name_match?(attr, local_name, rule_uri,
622
- flexible_local)
623
- end
624
- end
625
- return matched_attr&.value if matched_attr
650
+ rule_names.each do |rule_name|
651
+ next unless rule_name.include?(":")
652
+
653
+ resolved = match_attribute_by_local_name(
654
+ doc, rule_name, root_index, flexible_local
655
+ )
656
+ return resolved if resolved
626
657
  end
627
658
  nil
628
659
  end
629
660
 
661
+ def match_attribute_by_local_name(doc, rule_name, root_index, flexible_local)
662
+ # Splitting a namespaced rule name is pure string work repeated
663
+ # per element; memoized per spelling (bounded by the model's
664
+ # distinct rule names).
665
+ parts = NAMESPACED_NAME_PARTS[rule_name]
666
+ unless parts
667
+ last_colon_index = rule_name.rindex(":")
668
+ parts = [rule_name[(last_colon_index + 1)..], rule_name[0...last_colon_index]]
669
+ NAMESPACED_NAME_PARTS[rule_name] = parts
670
+ end
671
+ local_name, rule_uri = parts
672
+
673
+ candidates = root_index&.[](local_name)
674
+ matched_attr = if candidates
675
+ candidates.find do |attr|
676
+ local_name_match?(attr, local_name, rule_uri,
677
+ flexible_local)
678
+ end
679
+ else
680
+ doc.root.attributes.each_value.find do |attr|
681
+ local_name_match?(attr, local_name, rule_uri,
682
+ flexible_local)
683
+ end
684
+ end
685
+ matched_attr&.value
686
+ end
687
+
630
688
  # Namespace discipline of the lenient local-name fallback
631
689
  # (#744/#758/#790): sole claimants bind any qualification; shared
632
690
  # names must resolve to the rule's namespace.
@@ -648,6 +706,65 @@ _effective_register)
648
706
  (colon = attr.name.rindex(":")) ? attr.name[(colon + 1)..] : attr.name
649
707
  end
650
708
 
709
+ # lutaml-model#154: decode HTML entities for mappings that opted in
710
+ # (`html_entities` in the xml block). Values stay untouched
711
+ # otherwise — XML keeps undefined entities literal by design.
712
+ def decode_html_entities_value(value, enabled)
713
+ return value if value.nil? || !value.is_a?(String)
714
+ return value unless enabled
715
+ return value if Lutaml::Model.opal?
716
+
717
+ Lutaml::Xml::HtmlEntities.decode(value)
718
+ end
719
+
720
+ Record = Struct.new(:attr, :derived, :group_skip, :valid)
721
+
722
+ def compiled_rule_records(model_class, register, grouped_plain_rules)
723
+ return {}.compare_by_identity unless model_class.include?(Lutaml::Model::Serialize)
724
+
725
+ mapping = model_class.mappings_for(:xml, register)
726
+ version = mapping&.rule_records_version.to_i
727
+ per_class = RULE_RECORDS[model_class.object_id] || # rubocop:disable Lint/HashCompareByIdentity
728
+ (RULE_RECORDS[model_class.object_id] = Concurrent::Map.new) # rubocop:disable Lint/HashCompareByIdentity,Layout/MultilineAssignmentLayout
729
+ cached = per_class[register]
730
+ return cached.records if cached && cached.version == version
731
+
732
+ records = {}.compare_by_identity
733
+ mapping&.mappings(register)&.each do |rule| # rubocop:disable Style/SafeNavigationChain,Style/SafeNavigation
734
+ attr = attribute_for_rule_static(model_class, rule, register)
735
+ group = grouped_plain_rules[rule.to]
736
+ records[rule] = Record.new(
737
+ attr,
738
+ attr&.derived? || false,
739
+ !!(group && group.size > 1 && attr&.collection? &&
740
+ !group.first.equal?(rule)),
741
+ !!(attr || rule.custom_methods[:from]),
742
+ )
743
+ end
744
+ entry = Struct.new(:version, :records).new(version, records)
745
+ per_class[register] = entry
746
+ records
747
+ end
748
+
749
+ def attribute_for_rule_static(model_class, rule, register)
750
+ if rule.delegate
751
+ delegate_attr = model_class.attributes(register)[rule.delegate]
752
+ delegate_type = delegate_attr&.type(register)
753
+ delegate_type&.attributes(register)&.[](rule.to) # rubocop:disable Style/SafeNavigationChain
754
+ else
755
+ model_class.attributes(register)[rule.to]
756
+ end
757
+ rescue StandardError
758
+ nil
759
+ end
760
+
761
+ def decode_html_entities_for(instance, register)
762
+ klass = instance.class
763
+ return false unless klass.is_a?(Class) && klass.include?(Lutaml::Model::Serialize)
764
+
765
+ klass.mappings_for(:xml, register)&.decode_html_entities?
766
+ end
767
+
651
768
  def value_for_rule(session, rule, options, cached_attr = nil,
652
769
  extra_rule_names = nil)
653
770
  doc = session.doc
@@ -682,12 +799,16 @@ _effective_register)
682
799
  rule_names = rule_names.concat(extra_rule_names).uniq if extra_rule_names
683
800
 
684
801
  if rule.attribute?
685
- return value_for_xml_attribute(
802
+ value = value_for_xml_attribute(
686
803
  doc, rule, rule_names,
687
804
  flexible_local: attribute_rule_sole_local_claimant?(
688
805
  instance, rule, effective_register
689
- )
806
+ ),
807
+ session: session
690
808
  )
809
+ return decode_html_entities_value(value, decode_html_entities_for(
810
+ instance, effective_register
811
+ ))
691
812
  end
692
813
 
693
814
  # Performance: Pre-compute type-related values used in the hot loop
@@ -24,18 +24,31 @@ module Lutaml
24
24
  @instance_is_serialize ||= instance.is_a?(::Lutaml::Model::Serialize)
25
25
  end
26
26
 
27
- # Local-name -> [attributes] index over the root element's
28
- # attributes, built on first lenient lookup (TODO.max-perf/08).
29
- # The fallback used to rescan every attribute per missed rule;
30
- # elements are parse-frozen, so the index builds at most once per
31
- # session. Each attribute is filed under every local-name spelling
32
- # the matcher compares (unprefixed name and colon-split local).
33
- def root_local_attribute_index
34
- @root_local_attribute_index ||= begin
35
- index = ::Hash.new { |h, k| h[k] = [] }
36
- doc.root.attributes.each_value do |attr|
27
+ # (element, rule name) -> resolved attribute name / matched
28
+ # attribute VALUE for the lenient lookup paths. Both are pure
29
+ # functions of the element and the name; ISO-13849-shaped
30
+ # documents repeat the same resolutions per rule application, so
31
+ # the computed answer is memoized per element for the parse.
32
+ def rule_name_resolution
33
+ @rule_name_resolution ||= {}
34
+ end
35
+
36
+ # Local-name -> [attributes] index over one element's attributes,
37
+ # built on first lenient lookup (TODO.max-perf/08) and memoized per
38
+ # element for the life of the session. The URI-form attribute
39
+ # conversion and the lenient fallback used to rescan every
40
+ # attribute per rule per element (the ISO-13849 pathology);
41
+ # elements are parse-frozen, so each index builds at most once.
42
+ def element_local_attribute_index(element)
43
+ @element_local_attribute_index ||= {}.compare_by_identity
44
+ @element_local_attribute_index[element] ||= begin
45
+ # Plain hash: a miss must stay a nil lookup, not allocate an
46
+ # empty default array — misses dominate (the ISO-13849 shape
47
+ # resolves ~390k lenient lookups that match nothing).
48
+ index = {}
49
+ element.attributes.each_value do |attr|
37
50
  local_names(attr).each do |key|
38
- entries = index[key]
51
+ entries = (index[key] ||= [])
39
52
  entries << attr unless entries.include?(attr)
40
53
  end
41
54
  end
@@ -24,6 +24,7 @@ Lutaml::Model::FormatRegistry.register(
24
24
  available: %i[standard standard_yaml yeptris],
25
25
  default: :standard,
26
26
  },
27
+ stream_methods: true,
27
28
  )
28
29
 
29
30
  require_relative "type/serializers"
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ # lutaml-model#550: options passed to `from_*` / `to_*` flow to custom
6
+ # methods that declare the extra context parameter (arity-aware; the
7
+ # historical signatures keep working).
8
+ RSpec.describe "Custom method context forwarding" do
9
+ let(:model_class) do
10
+ Class.new(Lutaml::Model::Serializable) do
11
+ attribute :name, :string
12
+
13
+ def name_from(model, value, ctx = nil)
14
+ model.name = "#{value} (#{ctx ? ctx[:schema] : 'none'})"
15
+ end
16
+
17
+ def name_to(model, hash, ctx = nil)
18
+ hash["name"] = "#{model.name} <#{ctx ? ctx[:schema] : 'none'}>"
19
+ end
20
+
21
+ key_value do
22
+ map "name", to: :name,
23
+ with: { from: :name_from, to: :name_to }
24
+ end
25
+ end
26
+ end
27
+
28
+ it "passes context to custom methods on parse when accepted" do
29
+ parsed = model_class.from_yaml({ "name" => "Alpine" }.to_yaml,
30
+ context: { schema: "ISO" })
31
+ expect(parsed.name).to eq("Alpine (ISO)")
32
+ end
33
+
34
+ it "passes context to custom methods on serialize when accepted" do
35
+ instance = model_class.from_yaml({ "name" => "Alpine" }.to_yaml)
36
+ out = instance.to_yaml(context: { schema: "ISO" })
37
+ expect(out).to include("Alpine (none) <ISO>")
38
+ end
39
+
40
+ it "keeps two-parameter custom methods working without context" do
41
+ parsed = model_class.from_yaml({ "name" => "Alpine" }.to_yaml)
42
+ expect(parsed.name).to eq("Alpine (none)")
43
+
44
+ out = parsed.to_yaml
45
+ expect(out).to include("Alpine (none) <none>")
46
+ end
47
+
48
+ it "forwards context to with-lambdas of exact arity 2" do
49
+ klass = Class.new(Lutaml::Model::Serializable) do
50
+ attribute :code, :string
51
+
52
+ key_value do
53
+ map "code", to: :code,
54
+ with: { from: ->(value, ctx) { "#{value}-#{ctx[:rev]}" } }
55
+ end
56
+ end
57
+
58
+ parsed = klass.from_yaml({ "code" => "A1" }.to_yaml,
59
+ context: { rev: 7 })
60
+ expect(parsed.code).to eq("A1-7")
61
+ end
62
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ # lutaml-model#436: multi-document YAML streams with per-document model
6
+ # dispatch (the glossarist-ruby#132 / ISO 5843-6 shape).
7
+ RSpec.describe "YAML streams" do
8
+ let(:concept_class) do
9
+ Class.new(Lutaml::Model::Serializable) do
10
+ attribute :id, :string
11
+ attribute :language_code, :string
12
+
13
+ key_value do
14
+ map "id", to: :id
15
+ map "language_code", to: :language_code
16
+ end
17
+ end
18
+ end
19
+
20
+ let(:localized_class) do
21
+ Class.new(Lutaml::Model::Serializable) do
22
+ attribute :id, :string
23
+ attribute :status, :string
24
+
25
+ key_value do
26
+ map "id", to: :id
27
+ map "status", to: :status
28
+ end
29
+ end
30
+ end
31
+
32
+ let(:stream) do
33
+ <<~YAML
34
+ ---
35
+ id: 1-EN
36
+ language_code: eng
37
+ ---
38
+ id: 3a75
39
+ status: accepted
40
+ ---
41
+ id: 1-FR
42
+ language_code: fra
43
+ YAML
44
+ end
45
+
46
+ it "parses every document in the stream" do
47
+ models = concept_class.from_yaml_stream(stream)
48
+ expect(models.map(&:id)).to eq(%w[1-EN 3a75 1-FR])
49
+ end
50
+
51
+ it "dispatches documents polymorphically via discriminator" do
52
+ models = concept_class.from_yaml_stream(
53
+ stream,
54
+ discriminator: lambda { |doc|
55
+ doc.key?("language_code") ? concept_class : localized_class
56
+ },
57
+ )
58
+ expect(models.map(&:class)).to eq([concept_class, localized_class,
59
+ concept_class])
60
+ expect(models[1].status).to eq("accepted")
61
+ end
62
+
63
+ it "round-trips through to_yaml_stream" do
64
+ models = concept_class.from_yaml_stream(stream)
65
+ out = concept_class.to_yaml_stream(models)
66
+ reparsed = concept_class.from_yaml_stream(out)
67
+ expect(reparsed.map(&:id)).to eq(models.map(&:id))
68
+ expect(out).to include("---")
69
+ end
70
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ # lutaml-model#154: HTML named/numeric entities decode only for
6
+ # mappings that opt in via `html_entities` — XML otherwise keeps
7
+ # undefined entities literal.
8
+ RSpec.describe "Opt-in HTML entity decoding" do
9
+ context "when the mapping opts in" do
10
+ let(:model_class) do
11
+ Class.new(Lutaml::Model::Serializable) do
12
+ attribute :t, :string
13
+
14
+ xml do
15
+ element "doc"
16
+ map_element "t", to: :t
17
+ html_entities
18
+ end
19
+ end
20
+ end
21
+
22
+ it "decodes named and numeric entities in element text" do
23
+ parsed = model_class.from_xml("<doc><t>a &amp; b &#8212; c &copy; d</t></doc>")
24
+ expect(parsed.t).to eq("a & b — c © d")
25
+ end
26
+ end
27
+
28
+ context "when the mapping does not opt in" do
29
+ let(:model_class) do
30
+ Class.new(Lutaml::Model::Serializable) do
31
+ attribute :t, :string
32
+
33
+ xml do
34
+ element "doc"
35
+ map_element "t", to: :t
36
+ end
37
+ end
38
+ end
39
+
40
+ it "keeps undefined entities literal" do
41
+ parsed = model_class.from_xml("<doc><t>a &amp; b &copy; d</t></doc>")
42
+ expect(parsed.t).to eq("a & b &copy; d")
43
+ end
44
+ end
45
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.37
4
+ version: 0.8.38
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -776,6 +776,7 @@ files:
776
776
  - lib/lutaml/xml/format.rb
777
777
  - lib/lutaml/xml/format_chooser.rb
778
778
  - lib/lutaml/xml/hoisting_algorithm.rb
779
+ - lib/lutaml/xml/html_entities.rb
779
780
  - lib/lutaml/xml/leptris/element.rb
780
781
  - lib/lutaml/xml/listener.rb
781
782
  - lib/lutaml/xml/mapping.rb
@@ -1716,6 +1717,7 @@ files:
1716
1717
  - spec/lutaml/model/custom_bibtex_adapter_spec.rb
1717
1718
  - spec/lutaml/model/custom_collection_spec.rb
1718
1719
  - spec/lutaml/model/custom_from_empty_values_spec.rb
1720
+ - spec/lutaml/model/custom_method_context_spec.rb
1719
1721
  - spec/lutaml/model/custom_model_spec.rb
1720
1722
  - spec/lutaml/model/custom_serialization_spec.rb
1721
1723
  - spec/lutaml/model/custom_vobject_adapter_spec.rb
@@ -1859,6 +1861,7 @@ files:
1859
1861
  - spec/lutaml/model/xsd_type_spec.rb
1860
1862
  - spec/lutaml/model/xsd_type_validation_spec.rb
1861
1863
  - spec/lutaml/model/yaml_adapter_spec.rb
1864
+ - spec/lutaml/model/yaml_stream_spec.rb
1862
1865
  - spec/lutaml/model/yamls/standard_adapter_spec.rb
1863
1866
  - spec/lutaml/model/yamls_range_spec.rb
1864
1867
  - spec/lutaml/model/yamls_sequence_spec.rb
@@ -1913,6 +1916,7 @@ files:
1913
1916
  - spec/lutaml/xml/format_chooser_spec.rb
1914
1917
  - spec/lutaml/xml/fpi_namespace_spec.rb
1915
1918
  - spec/lutaml/xml/general_namespace_spec.rb
1919
+ - spec/lutaml/xml/html_entities_spec.rb
1916
1920
  - spec/lutaml/xml/indent_spec.rb
1917
1921
  - spec/lutaml/xml/line_ending_spec.rb
1918
1922
  - spec/lutaml/xml/mapping_finalization_guard_spec.rb