lutaml-xsd 1.2.76 → 1.2.78

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: 9c49965da4c942d79c67fd51902349ca702ed0f60a35bb44aef6a2f47f4745bc
4
- data.tar.gz: d9bfe229ec7147df509f0b8f01ea18e3b263df232b041d76d12c7c3f86362286
3
+ metadata.gz: 22d795e689f88ccef5f61459e717e04bafc7eaf5504b080a6062a59d9501a86e
4
+ data.tar.gz: fb39b92dc122c263bf6b144c70d7f6eaee7841209f8d2ad8a013daa540c13f5c
5
5
  SHA512:
6
- metadata.gz: 559fe20193f7575c8893b5e25fc656b3cface817c7aa7190b97ab8d2e7ae226330281e02e6eeae3e02b38965ba77f3e958d94688aa788b015f7736692ba7d403
7
- data.tar.gz: 638b9280631242c2ada79b449bbc19f30cd1d706b502d7db9bce4d012dc3e421ed35312eacd0b9b64ef373bf283436105eb98a7abcf70e54ba0665d67fa8a73c
6
+ metadata.gz: 311267aaa35718e4f3c149ed3d7e7f14eda7bee3a077ca39c6c5c4041ca70184bd4aa458c2680ed435295bbe8460bf0b1b96ce77d473225062e5afa6439cc353
7
+ data.tar.gz: 36edcae8faa4d6062edc3f873cc34e0c67c01c156089c1517ed21cb265df5e66729ca5588264eb856476705f62e59879c3bf47aed112497b97f5b16c17475d23
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lutaml-xsd (1.2.76)
4
+ lutaml-xsd (1.2.78)
5
5
  liquid (>= 4.0, < 6.0)
6
6
  lutaml-model (~> 0.8.123)
7
7
  lutaml-store (~> 0.3)
@@ -264,7 +264,7 @@ CHECKSUMS
264
264
  liquid (5.14.0) sha256=e1020c2b2ee58c7a4d3bfdc7a331537bd27a783353748bff0bf27c6ac0c17065
265
265
  lutaml-model (0.8.155) sha256=3d90f2fb4fdf41a42d4a05b62b3f6644b433070b82291a9371deaa8e68a1e02d
266
266
  lutaml-store (0.3.2) sha256=9c455dbab32b4c635c48a27213f6f56fda191731c4574eb6187184ba0588a672
267
- lutaml-xsd (1.2.76)
267
+ lutaml-xsd (1.2.78)
268
268
  memo_wise (1.13.0) sha256=30220c38c4cef410849bc73553c58664dc2c91c6379e4a1df22aea02358b716b
269
269
  moxml (0.6.1) sha256=5b7677258bbad372f0725a421f8adeae37b65d6f7871da2747e2c1906cdac7ea
270
270
  nokogiri (1.19.4-aarch64-linux-gnu) sha256=1269fb644a6de405057a53dd5c762b1209b43ca7424f839454d3dbc677c31a8f
data/TODO.conformance.md CHANGED
@@ -120,21 +120,21 @@ pinned commit) is measured via `rake conformance:w3c`:
120
120
 
121
121
  | mode | pass-rate |
122
122
  |---|---|
123
- | pipeline | 4546/4696 (96.8%) |
123
+ | pipeline | 4565/4696 (97.2%) |
124
124
 
125
125
  (2026-11-02, bundled-stack measurement on main with the escape,
126
126
  hint-following, pattern-alternative, identity-crash, engine-set,
127
127
  engine-refresh, IC value-space, IC field-resolution, facade-silence,
128
- regex-semantics, redefine-refresh, gmonth-refresh, digit-vintage and
129
- stgh-refresh rounds; moxml 0.6.1 (gemspec floor `~> 0.6.0` per the
130
- owner — the 0.6 line drops the Opal surface; measured
131
- conformance-neutral), lutaml-model 0.8.155, engine leptris
132
- 1.9.401.0.) Same-stack comparison: 1.2.43 baseline 3961 (84.3%) →
133
- 4039 (86.0%) → 4090 (87.1%) → 4360 (92.8%, lockfile refresh) → 4411
134
- (93.9%) → 4430 (94.3%) → 4435 (94.4%) → 4436 (94.5%) → 4439 (94.5%)
135
- → 4454 (94.9%) → 4495 (95.7%) → 4524 (96.3%) → 4534 (96.6%) → 4540
136
- (96.7%) → 4542 (96.7%) → 4546 (96.8%), +585 net over the 1.2.43
137
- baseline. The escapes round (PR #197 — \d→\p{Nd},
128
+ regex-semantics, redefine-refresh, gmonth-refresh, digit-vintage,
129
+ stgh-refresh, group-ref and attribute-group-redefine rounds; moxml
130
+ 0.6.1 (gemspec floor `~> 0.6.0` per the owner — the 0.6 line drops
131
+ the Opal surface; measured conformance-neutral), lutaml-model
132
+ 0.8.155, engine leptris 1.9.401.0.) Same-stack comparison: 1.2.43
133
+ baseline 3961 (84.3%) → 4039 (86.0%) → 4090 (87.1%) → 4360 (92.8%,
134
+ lockfile refresh) → 4411 (93.9%) → 4430 (94.3%) → 4435 (94.4%) →
135
+ 4436 (94.5%) → 4439 (94.5%) → 4454 (94.9%) → 4495 (95.7%) → 4524
136
+ (96.3%) → 4534 (96.6%) → 4540 (96.7%) → 4542 (96.7%) → 4546 (96.8%)
137
+ → 4557 (97.0%) → 4565 (97.2%), +604 net over the 1.2.43 baseline. The escapes round (PR #197 — \d→\p{Nd},
138
138
  \w/\W/\s to their XSD value spaces) collapses Regex 120→69;
139
139
  same-step pattern facets now behave as alternatives and
140
140
  whitespace-only text reaches the facets intact (PR #200), Regex
@@ -242,7 +242,8 @@ moxml 0.5.170 + lutaml-model 0.8.147) → 93.9% (escape + hint rounds)
242
242
  4439) → 94.9% (IC field-resolution round PR #206, 4454) → 95.7%
243
243
  (facade-silence dep refresh, moxml 0.5.177, 4495) → 96.3% (regex
244
244
  semantics round PR #208, 4524) → 96.6% (redefine refresh, leptris
245
- 1.9.396/1.9.397, 4534). Failure
245
+ 1.9.396/1.9.397, 4534) → 96.8% (stG/stH refresh, leptris 1.9.401,
246
+ 4546) → 97.0% (group-ref round PR #217, 4557). Failure
246
247
  concentration (the work queue, largest first):
247
248
 
248
249
  - `Regex_w3c` (131) — decomposed by error source (2026-10-25): the
@@ -344,6 +345,33 @@ tuple keys, node-set field violations and absent-field rows handled, cross-eleme
344
345
  (stG010/012, stH005/007); SimpleType 10→6; suite 4546/4696
345
346
  (96.8%), zero regressions. #1936 remainder: reZ char-reference
346
347
  shapes, reT51 \D vintage; plus moxml#510 addB116 straggler.
348
+ - GROUP-REF ROUND (2026-11-02, PR #217): +11 Group cases (19→8,
349
+ suite 4557/4696 = 97.0%). TWO Ruby defects: (a) `particle_for_type`
350
+ read sequence/choice/all from extension and restriction bodies but
351
+ NOT `group` — a derivation body that is a bare group reference
352
+ compiled to NO content model and the walk enforced nothing
353
+ (groupG/groupH class); (b) `composite_capacity` decided sum-vs-max
354
+ from the PARTICLE's class — for a Group ref it always took the max
355
+ branch even when the group's declaration is a SEQUENCE whose
356
+ members' capacities must ADD (groupH002: one branch of x1+x2 was
357
+ counted as two choice occurrences). Neighbors verified identical;
358
+ zero regressions. Group remainder: groupB009/010 + groupO004
359
+ (false-reject class), groupH008/J003/006/008/L008 under-detections
360
+ (choice-of-group capacity depth).
361
+ - ATTRIBUTE-GROUP-REDEFINE ROUND (2026-11-02, PR #218): +8 net
362
+ (AttributeGroup 17→11, Schema 14→12, Attribute 10→9; suite
363
+ 4557→4565 = 97.2%). lutaml-model does NOT chase xs:redefine
364
+ targets — the original document was never parsed, so the
365
+ redefined group's self-ref hook had nothing to hook to and
366
+ expansions truncated at the cycle guard. The resolver now chases
367
+ the redefine target itself (relative to the defining file, via
368
+ the repository's source path), indexes it, keeps the ORIGINAL
369
+ declaration as the hook target, and expands the redefining body
370
+ with the self-ref resolved to that original (attgC007/attgD036).
371
+ Wildcards nested in attributeGroup DECLARATIONS reach types
372
+ through the group's resolution (attgD019). All remaining
373
+ AttributeGroup failures are ENGINE-only strict re-checks on
374
+ composed shapes (the moxml#510 thread).
347
375
  - REGEX SEMANTICS ROUND (2026-10-31, PR #208): \w/\W now carry their
348
376
  Appendix F complements (\w = [^\p{P}\p{Z}\p{C}], class interiors
349
377
  via the exact positive partition L/M/N/S), \I/\C complements added
@@ -268,14 +268,23 @@ module Lutaml
268
268
  return [] if depth > 5
269
269
  return [] unless group
270
270
 
271
+ own = (group.name || group.ref).to_s.split(":").last
271
272
  attrs = Array(group.attribute)
272
273
 
273
274
  # An attributeGroup may reference other attributeGroups —
274
- # their declarations flow into the expansion (attgD004).
275
+ # their declarations flow into the expansion (attgD004). A
276
+ # reference to the group's OWN name inside an xs:redefine
277
+ # body is the §4.2.2 hook to the ORIGINAL definition.
275
278
  Array(group.attribute_group).each do |nested_ref|
276
279
  local = (nested_ref.ref || nested_ref.name).to_s
277
280
  .split(":").last
278
- declaration = repository&.resolve_attribute_group(local)
281
+ declaration =
282
+ if !local.empty? && local == own &&
283
+ repository&.redefined_original_for(local)
284
+ repository.redefined_original_for(local)
285
+ else
286
+ repository&.resolve_attribute_group(local)
287
+ end
279
288
  next unless declaration
280
289
 
281
290
  attrs.concat(expand_attribute_group(declaration, repository,
@@ -889,10 +898,15 @@ module Lutaml
889
898
  complex_type_wildcard_support?
890
899
  wildcards << complex_wildcard if complex_wildcard
891
900
 
901
+ # A wildcard nested in an attributeGroup DECLARATION reaches
902
+ # the type only through the group's resolution — the type's
903
+ # ref particle carries no children of its own (attgD019).
892
904
  Array(schema_def.attribute_group).each do |group|
893
905
  Array(group.any_attribute).each do |wildcard|
894
906
  wildcards << wildcard
895
907
  end
908
+
909
+ collect_group_wildcards(group, repository, wildcards, 0)
896
910
  end
897
911
 
898
912
  CONTENT_KINDS.each do |content_kind|
@@ -916,6 +930,29 @@ module Lutaml
916
930
  wildcards
917
931
  end
918
932
 
933
+ # The wildcards of an attributeGroup reference's DECLARATION,
934
+ # following nested attributeGroup refs (depth-guarded).
935
+ #
936
+ # @return [void]
937
+ def collect_group_wildcards(group, repository, wildcards, depth)
938
+ return if depth > 5
939
+
940
+ local = (group.ref || group.name).to_s.split(":").last
941
+ return if local.to_s.empty?
942
+
943
+ declaration = repository&.resolve_attribute_group(local)
944
+ return unless declaration
945
+
946
+ Array(declaration.any_attribute).each do |wildcard|
947
+ wildcards << wildcard
948
+ end
949
+
950
+ Array(declaration.attribute_group).each do |nested|
951
+ collect_group_wildcards(nested, repository, wildcards,
952
+ depth + 1)
953
+ end
954
+ end
955
+
919
956
  # The named base type of the derivation shape, when present.
920
957
  #
921
958
  # @return [Lutaml::Xml::Schema::Xsd::ComplexType, nil]
@@ -501,24 +501,36 @@ module Lutaml
501
501
  end
502
502
 
503
503
  def composite_capacity(particle, repository, depth)
504
- children = if particle.is_a?(Lutaml::Xml::Schema::Xsd::Group)
505
- container = expand_group_container(particle,
506
- repository).first
507
- container ? choice_alternatives(container) : []
508
- else
509
- # sequence: capacities add; choice: the largest
510
- choice_alternatives(particle)
511
- end
504
+ # The CONTAINER's kind decides aggregation: a group whose
505
+ # declaration is a sequence ADDS its members' capacities, a
506
+ # choice takes the largest — deciding from the ref particle
507
+ # itself always maxed (groupH class).
508
+ children, aggregate =
509
+ if particle.is_a?(Lutaml::Xml::Schema::Xsd::Group)
510
+ container = expand_group_container(particle,
511
+ repository).first
512
+ if container
513
+ [choice_alternatives(container),
514
+ container_choice?(container) ? :max : :sum]
515
+ else
516
+ [[], :max]
517
+ end
518
+ else
519
+ [choice_alternatives(particle),
520
+ particle.is_a?(Lutaml::Xsd::Sequence) ? :sum : :max]
521
+ end
512
522
  caps = children.map do |child|
513
523
  branch_capacity(child, repository, depth + 1)
514
524
  end
515
525
  return :unbounded if caps.include?(:unbounded)
516
526
 
517
- if particle.is_a?(Lutaml::Xsd::Sequence)
518
- caps.sum
519
- else
520
- caps.max || 0
521
- end
527
+ aggregate == :sum ? caps.sum : (caps.max || 0)
528
+ end
529
+
530
+ # @return [Boolean]
531
+ def container_choice?(container)
532
+ container.is_a?(Lutaml::Xsd::Choice) ||
533
+ container.is_a?(Lutaml::Xml::Schema::Xsd::Choice)
522
534
  end
523
535
 
524
536
  # Choice alternatives are particles of any kind.
@@ -49,6 +49,7 @@ module Lutaml
49
49
  @named_types = {}
50
50
  @attributes = Hash.new { |hash, key| hash[key] = [] }
51
51
  @attribute_groups = {}
52
+ @redefined_originals = {}
52
53
  @elements = index_elements
53
54
  end
54
55
 
@@ -100,6 +101,16 @@ module Lutaml
100
101
  @attribute_groups[local_name]
101
102
  end
102
103
 
104
+ # The pre-redefinition declaration of an attributeGroup that an
105
+ # xs:redefine replaced — the target of the redefining body's
106
+ # self-reference hook.
107
+ #
108
+ # @param local_name [String]
109
+ # @return [Object, nil]
110
+ def redefined_original_for(local_name)
111
+ @redefined_originals[local_name]
112
+ end
113
+
103
114
  # Owner schema's target namespace for a resolved declaration
104
115
  # (parsed element models carry no owner-schema link).
105
116
  #
@@ -428,8 +439,12 @@ module Lutaml
428
439
  nil
429
440
  when Lutaml::Xml::Schema::Xsd::ExtensionComplexContent,
430
441
  Lutaml::Xml::Schema::Xsd::RestrictionComplexContent
442
+ # A derivation body may be a bare group reference — the
443
+ # ref's own minOccurs/maxOccurs govern the expanded model
444
+ # (groupG/groupH class).
431
445
  Array(type.sequence).first ||
432
- Array(type.choice).first || Array(type.all).first
446
+ Array(type.choice).first || Array(type.all).first ||
447
+ Array(type.group).first
433
448
  end
434
449
  end
435
450
 
@@ -534,6 +549,46 @@ module Lutaml
534
549
 
535
550
  index_schema(index, nested)
536
551
  end
552
+
553
+ # xs:redefine replaces an attributeGroup with a body whose
554
+ # self-reference is the §4.2.2 hook to the ORIGINAL
555
+ # definition. lutaml-model does NOT chase the redefine
556
+ # target, so the original document is parsed here (relative
557
+ # to the defining file) and indexed; the original
558
+ # declaration is kept for that hook and the redefining body
559
+ # indexed under the name (attgC007/attgD036). Runs after the
560
+ # nested descent so included declarations are already in.
561
+ Array(schema.redefine).each do |red|
562
+ target_path = nil
563
+ base = begin
564
+ File.dirname(@repository.source_path_for(schema))
565
+ rescue StandardError
566
+ nil
567
+ end
568
+ if base && red.schema_path.to_s.match?(/\S/)
569
+ candidate = File.expand_path(red.schema_path.to_s, base)
570
+ target_path = candidate if File.exist?(candidate)
571
+ end
572
+ if target_path
573
+ begin
574
+ target = Lutaml::Xml::Schema::Xsd.parse(
575
+ File.read(target_path), location: target_path
576
+ )
577
+ index_schema(index, target, held_signatures, namespace,
578
+ defaults_schema)
579
+ rescue StandardError
580
+ nil
581
+ end
582
+ end
583
+ Array(red.attribute_group).each do |group|
584
+ name = group.name.to_s
585
+ next if name.empty?
586
+
587
+ original = @attribute_groups[name]
588
+ @redefined_originals[name] = original if original
589
+ @attribute_groups[name] = group
590
+ end
591
+ end
537
592
  end
538
593
 
539
594
  def index_attribute(attribute, namespace)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Xsd
5
- VERSION = "1.2.76"
5
+ VERSION = "1.2.78"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-xsd
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.76
4
+ version: 1.2.78
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-11-01 00:00:00.000000000 Z
11
+ date: 2026-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid