lutaml-xsd 1.2.102 → 1.2.103

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1b37fc4af01d8c2f652a899644d9f85f13fec225d6ae0ce393b7d16f19df5bc
4
- data.tar.gz: 2b08927d906be739a784888c3e1d9c9fb5a303362cc6dcc565404e0500b4f74d
3
+ metadata.gz: 0406cd7f1ca030db5b4c6db63f060fdaae3981f61d2913f3552c510129f80b8c
4
+ data.tar.gz: 067f44365c98c7a9b3fd221c74d35965d5e628b3cb58f788e7210bd8a8cc6964
5
5
  SHA512:
6
- metadata.gz: 95823a7f86274b2363e65b1a36d0b9aff1078c55196c8f53982d065ec67f0b32b60d1c18436ff8839f65f150373ffa822fa0c4cdaf046f042694ef94279fb0cc
7
- data.tar.gz: f85b40f50b7ac8d93bfe7341feb8eaf4442ea4ac3b0fb9f3ea51cbb3f832835ac3f36033f9897e816371ba99ddf206f7c271a81389b3bf32370acc2104670968
6
+ metadata.gz: d7b9a1f01944bfe42b257e750226f2e9b200fbe3a30fe14ac834f3b1b7fdd675a12afb77764eaf821e09662674788ecf764064516477e26df394da4ba8b66ac2
7
+ data.tar.gz: 8dc0ac9729456a8903c6a2f70c4db8d1d2c7704076654ac173c4450aa089c76d3369a48f61d1638c210e26cd5b94584cebeff2af4700bdf3964b587136082183
data/TODO.conformance.md CHANGED
@@ -519,6 +519,30 @@ tuple keys, node-set field violations and absent-field rows handled, cross-eleme
519
519
  0.6.3 + lutaml-model 0.8.166 train carried fixes (the FULL #45
520
520
  stE legs, the #522 attgC four + attgD mostly + attJ018 +
521
521
  schF1/P2, stE065/066/096) AND a WHOLESALE 407 regex regression:
522
+ - PARENT-CONTEXT ROUND B (2026-11-08): +1 Additional (isDefault079;
523
+ suite 4629->4630 = 98.59%, zero regressions, rspec green).
524
+ POSITIONAL BINDING for duplicate same-named locals: a model with
525
+ two regvalueop locals carrying DIFFERENT fixed values never bound
526
+ the second child to the second particle — the name-only dispatch
527
+ always hit the first. The engine computes each child's same-name
528
+ sibling index (on the RAW moxml nodes — wrapper objects are not
529
+ identity-stable across accessor calls, the IdUniquenessRule
530
+ lesson) and dispatches the positionally-bound declaration when
531
+ (a) the parent's model holds MORE THAN ONE same-named particle,
532
+ (b) every particle is INDEXED (attempt-3's starvation guard: raw
533
+ parent-model particles carry none of the form/ns metadata the
534
+ rules assume — resolver positional_children returns [] otherwise),
535
+ and (c) the candidate's expected namespace AGREES with the child's
536
+ (particlesQ016's global/local namesake guard). The ordered walk
537
+ keeps a PER-CALL visited set — the resolver's
538
+ each_particle_element memoizes on the instance and would poison
539
+ repeats. LESSON: scripted line-surgery on lib files dropped a
540
+ class end and leaked methods to top level (runtime-only
541
+ uninitialized-constant failures, caught by sentinel probes) —
542
+ structural edits go through the Edit tool only. Remaining parked
543
+ (matcher-assignment + root-assessment shapes): QFE1700c1,
544
+ addB065, addB188, schA1/D10 + the lax-wildcard six.
545
+
522
546
  ~177 cases — the ENTIRE Unicode-block escape family (~80
523
547
  - PARENT-CONTEXT ROUND A (2026-11-08): +1 Errata10 (errC007; suite
524
548
  4628->4629 = 98.57%, zero regressions, rspec green). The
@@ -65,6 +65,25 @@ module Lutaml
65
65
  schema_def = resolver.resolve(
66
66
  xml_element.name, xml_element.namespace_uri
67
67
  )
68
+ if parent
69
+ parent_declaration =
70
+ resolver.resolve(parent.name, parent.namespace_uri)
71
+ candidates = resolver.positional_children(parent_declaration,
72
+ xml_element.name)
73
+ positional = candidates[same_name_sibling_index(xml_element,
74
+ parent)]
75
+ # The binding must agree with the child's OWN namespace:
76
+ # an unqualified ref's global namesake never serves a
77
+ # qualified local namesake (particlesQ016).
78
+ child_ns = xml_element.namespace_uri.to_s
79
+ expected_ns =
80
+ resolver.expected_namespace_for(positional).to_s
81
+ if positional &&
82
+ ((child_ns.empty? && expected_ns.empty?) ||
83
+ child_ns == expected_ns)
84
+ schema_def = positional
85
+ end
86
+ end
68
87
  rules.each do |rule|
69
88
  argument = rule.schema_argument(schema_def, repository: resolver)
70
89
  next if argument.nil? && !rule.runs_without_schema?
@@ -204,6 +223,23 @@ module Lutaml
204
223
  end
205
224
  end
206
225
 
226
+ # The child's position among its same-named siblings — the index
227
+ # the positional binding (duplicate same-named declarations,
228
+ # isDefault079) binds to. Computed on the RAW moxml nodes: the
229
+ # wrapper objects are not identity-stable across accessor calls
230
+ # (the IdUniquenessRule lesson).
231
+ #
232
+ # @return [Integer]
233
+ def same_name_sibling_index(element, parent)
234
+ raw_children = Array(parent.moxml_element.elements)
235
+ position = raw_children.index do |node|
236
+ node.equal?(element.moxml_element)
237
+ end
238
+ return 0 if position.nil?
239
+
240
+ raw_children.take(position).count { |node| node.name == element.name }
241
+ end
242
+
207
243
  # Whether the parent's content model holds a processContents
208
244
  # skip wildcard whose namespace range admits the child — the
209
245
  # child subtree then escapes assessment entirely (addB125).
@@ -587,8 +587,92 @@ module Lutaml
587
587
  element_declaration_simple?(field_decl)
588
588
  end
589
589
 
590
+ # The ordered same-named inline particles of the parent's
591
+ # content model — the POSITIONAL binding for duplicate
592
+ # declarations (isDefault079: two regvalueop locals with
593
+ # different fixed values; the second child binds to the second
594
+ # particle). Returns [] unless the name appears MORE THAN ONCE
595
+ # and every particle is INDEXED (attempt-3's starvation: raw
596
+ # particles carry none of the form/ns metadata the rules
597
+ # assume). The walk keeps its own cycle guard — the resolver's
598
+ # each_particle_element memoizes visited nodes on the instance
599
+ # and would poison repeated walks.
600
+ #
601
+ # @param parent_declaration [Lutaml::Xml::Schema::Xsd::Element, nil]
602
+ # @param local_name [String]
603
+ # @return [Array<Lutaml::Xml::Schema::Xsd::Element>]
604
+ def positional_children(parent_declaration, local_name)
605
+ type = parent_declaration&.complex_type ||
606
+ resolve_type(parent_declaration)
607
+ return [] unless type.is_a?(Lutaml::Xml::Schema::Xsd::ComplexType)
608
+
609
+ particles = []
610
+ collect_named_particles(particle_for_type(type), local_name,
611
+ particles, {}.compare_by_identity, 0)
612
+ return [] if particles.length < 2
613
+ return [] unless particles.all? { |p| @namespaces.key?(p) }
614
+
615
+ particles
616
+ end
617
+
590
618
  private
591
619
 
620
+ # Depth-first ordered collection of same-named element
621
+ # particles; per-call visited set (identity-keyed), group refs
622
+ # expanded.
623
+ #
624
+ # @return [void]
625
+ def collect_named_particles(node, local_name, out, visited, depth)
626
+ return if node.nil? || depth > 24
627
+
628
+ if node.is_a?(Array)
629
+ node.each do |child|
630
+ collect_named_particles(child, local_name, out, visited,
631
+ depth + 1)
632
+ end
633
+ return
634
+ end
635
+ return if visited[node]
636
+
637
+ visited[node] = true
638
+
639
+ if node.is_a?(Lutaml::Xml::Schema::Xsd::Element)
640
+ if node.name.to_s.split(":").last == local_name
641
+ out << node
642
+ elsif node.ref.to_s.match?(/\S/) &&
643
+ node.ref.to_s.split(":").last == local_name
644
+ global = resolve_global(node.ref.to_s.split(":").last, nil)
645
+ out << global if global
646
+ end
647
+ return
648
+ end
649
+
650
+ nested = CONTAINER_NESTED_KINDS[node.class]
651
+ nested&.each do |kind|
652
+ collect_named_particles(Array(node.public_send(kind)),
653
+ local_name, out, visited, depth + 1)
654
+ end
655
+ (CONTAINER_LEAF_KINDS[node.class] || []).each do |kind|
656
+ Array(node.public_send(kind)).each do |leaf|
657
+ next unless leaf
658
+
659
+ if leaf.is_a?(Lutaml::Xml::Schema::Xsd::Group)
660
+ resolved = if leaf.ref
661
+ resolve_group(leaf.ref.to_s
662
+ .split(":").last)
663
+ else
664
+ leaf
665
+ end
666
+ collect_named_particles(resolved, local_name, out, visited,
667
+ depth + 1)
668
+ elsif leaf.is_a?(Lutaml::Xml::Schema::Xsd::Element)
669
+ collect_named_particles(leaf, local_name, out, visited,
670
+ depth + 1)
671
+ end
672
+ end
673
+ end
674
+ end
675
+
592
676
  # Whether a TYPE carries an identity value for a field bound to
593
677
  # the selector node itself (a "." field): a simple type or a
594
678
  # complex type with simple content does; complex content does not.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Xsd
5
- VERSION = "1.2.102"
5
+ VERSION = "1.2.103"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-xsd
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.102
4
+ version: 1.2.103
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.