lutaml-xsd 1.2.114 → 1.2.115
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8361d002b4925f8e9617b1befc010cdf69eda020d9819ad6cb563d5716fd0cb3
|
|
4
|
+
data.tar.gz: d7ee489b009dbfe0f537b6ec11ea9e68435161619db337801a8b2fe44881b267
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a67d033744fd14e969811aed1d8b7f7e679a50b2c535a1ea649e670d5e4baf6f5fef3c5b11349cfef519dbfb0cdacdc467270ccf6c3c231d3f6f234b2c7f84b2
|
|
7
|
+
data.tar.gz: 02fec25f4e6c24ecf8c591e8fff9dfb245acaeacb41a09c36223ae6a1da1cdc8e35a22c215b2a11c137982b1d49c284c568e926faf49d856bcc52f68a13be1a3
|
data/TODO.conformance.md
CHANGED
|
@@ -120,7 +120,7 @@ pinned commit) is measured via `rake conformance:w3c`:
|
|
|
120
120
|
|
|
121
121
|
| mode | pass-rate |
|
|
122
122
|
|---|---|
|
|
123
|
-
| pipeline |
|
|
123
|
+
| pipeline | 4664/4696 (99.32%) |
|
|
124
124
|
|
|
125
125
|
(2026-11-02, bundled-stack measurement with the escape,
|
|
126
126
|
hint-following, pattern-alternative, identity-crash, engine-set,
|
|
@@ -144,7 +144,7 @@ lockfile refresh) → 4411 (93.9%) → 4430 (94.3%) → 4435 (94.4%) →
|
|
|
144
144
|
→ 4557 (97.0%) → 4565 (97.2%) → 4569 (97.3%) → 4562 (drift raw) →
|
|
145
145
|
4563 (97.17%, ref-namespace round) → 4573 (97.38%, group-content
|
|
146
146
|
round) → 4578 (97.49%, attribute-prohibition round) → 4585 (97.64%,
|
|
147
|
-
multi-document round) → 4588 (97.7%, type-binding round) → 4592 (97.79%, model-161 ride) → 4611 (98.19%, engine-406 ride) → 4613 (98.23%, temporal-enumeration round) → 4614 (98.25%, simple-type-children round) → 4617 (98.32%, ic-ancestor-scope round) → 4637 (parent-context rounds + chameleon round 1.2.109) → 4637 (nested-type-candidates round, 1.2.110) → 4637 (redefine-cycle round, 1.2.111) → 4644 measured (98.96% of measured, train-adoption round: moxml 0.6.6 + leptris 1.9.418.0) → 4649 (98.91%, quadratic-dispatch round — first FULL-denominator measure, the 5 reZ budget exclusions retired) → 4658 (99.19%, remainder-classification round — first measure above 99), +
|
|
147
|
+
multi-document round) → 4588 (97.7%, type-binding round) → 4592 (97.79%, model-161 ride) → 4611 (98.19%, engine-406 ride) → 4613 (98.23%, temporal-enumeration round) → 4614 (98.25%, simple-type-children round) → 4617 (98.32%, ic-ancestor-scope round) → 4637 (parent-context rounds + chameleon round 1.2.109) → 4637 (nested-type-candidates round, 1.2.110) → 4637 (redefine-cycle round, 1.2.111) → 4644 measured (98.96% of measured, train-adoption round: moxml 0.6.6 + leptris 1.9.418.0) → 4649 (98.91%, quadratic-dispatch round — first FULL-denominator measure, the 5 reZ budget exclusions retired) → 4658 (99.19%, remainder-classification round — first measure above 99) → 4664 (99.32%, ride-419 round), +703 net over the 1.2.43 baseline. The escapes round (PR #197 — \d→\p{Nd},
|
|
148
148
|
\w/\W/\s to their XSD value spaces) collapses Regex 120→69;
|
|
149
149
|
same-step pattern facets now behave as alternatives and
|
|
150
150
|
whitespace-only text reaches the facets intact (PR #200), Regex
|
|
@@ -684,6 +684,38 @@ tuple keys, node-set field violations and absent-field rows handled, cross-eleme
|
|
|
684
684
|
false, which would have flagged every schema-type override
|
|
685
685
|
undervalued; caught by re-reading the -A diff (the standing
|
|
686
686
|
predicate-nil lesson, now with the rename fix applied).
|
|
687
|
+
- RIDE-419 ROUND (2026-11-13, release pending): leptris
|
|
688
|
+
1.9.419.0 closed BOTH overnight filings — leptris-rs#72
|
|
689
|
+
(wildZ013b/c: the namespace-less-import wildcard admission
|
|
690
|
+
restored) and #73 (attZ014a/b: the multi-xs:ID 1.0 reading
|
|
691
|
+
restored). The ride also surfaced that OUR fixed-value check
|
|
692
|
+
was lexical-only where the suite demands VALUE-space equality
|
|
693
|
+
through a union's first-accepting member (§4.1.7): stE050
|
|
694
|
+
('true' == fixed '1' as boolean-true) and stE055 (float forms)
|
|
695
|
+
now pass via ValueSpace.union_member_value_key + the
|
|
696
|
+
fixed_value_space_equal? comparison in TypeValidationRule
|
|
697
|
+
(union members split per the established member_types.to_s.
|
|
698
|
+
split pattern — Array() on the attribute yields ONE
|
|
699
|
+
space-separated string, which silently never matches; three
|
|
700
|
+
call sites corrected, including a latent one from the previous
|
|
701
|
+
round). stE065/066/096 remain ENGINE-bound — filed
|
|
702
|
+
leptris-rs#74 (the engine's own fixed-value comparison is
|
|
703
|
+
lexical-only for unions); attgC035-038 remain FACADE-bound —
|
|
704
|
+
filed moxml#545 (the closed-#522 thread's uncovered legs: the
|
|
705
|
+
strict re-check false-reports attributeGroup-redefine §4.2.2
|
|
706
|
+
hook members). SUITE 4664/4696 (99.32%), zero regressions;
|
|
707
|
+
rspec 1663 green; rubocop clean. INCIDENT (recovered
|
|
708
|
+
in-round): threading repository: into validate_fixed_content
|
|
709
|
+
via a bulk gsub landed a call inside validate_builtin_type,
|
|
710
|
+
whose scope has no repository local — NameError on every
|
|
711
|
+
builtin-typed element, a 686-case regression wave that
|
|
712
|
+
briefly looked like a leptris-419 breakage; the pin-back
|
|
713
|
+
battery exonerated the train (the wave reproduced on 418)
|
|
714
|
+
and the signature fix recovered the battery. LESSON: when
|
|
715
|
+
threading a parameter through call sites, verify the RECEIVER
|
|
716
|
+
method's signature carries it — a mechanical gsub crosses
|
|
717
|
+
scope boundaries silently, and the crash-as-invalid
|
|
718
|
+
convention turns the NameError into wholesale false verdicts.
|
|
687
719
|
- TRAIN ADOPTION REGRESSION — CHARACTER REFERENCES (2026-11-11):
|
|
688
720
|
the 2026-11-10 adoption verdict ("conformance-IDENTICAL") was
|
|
689
721
|
WRONG for one class: moxml 0.6.4 stopped decoding numeric
|
|
@@ -127,7 +127,8 @@ module Lutaml
|
|
|
127
127
|
# A type-less declaration is xs:anyType; its fixed value
|
|
128
128
|
# still constrains the lexical content (isDefault070).
|
|
129
129
|
validate_fixed_content(xml_element, schema_element,
|
|
130
|
-
xml_element.text_content, collector
|
|
130
|
+
xml_element.text_content, collector,
|
|
131
|
+
repository: repository)
|
|
131
132
|
return
|
|
132
133
|
end
|
|
133
134
|
|
|
@@ -143,14 +144,16 @@ module Lutaml
|
|
|
143
144
|
# complex walk checks the type's model, this checks the
|
|
144
145
|
# declaration's own fixed content (isDefault077).
|
|
145
146
|
validate_fixed_content(xml_element, schema_element,
|
|
146
|
-
xml_element.text_content, collector
|
|
147
|
+
xml_element.text_content, collector,
|
|
148
|
+
repository: repository)
|
|
147
149
|
validate_complex_type_content(xml_element, type_def, collector,
|
|
148
150
|
repository: repository,
|
|
149
151
|
declared: schema_element)
|
|
150
152
|
else
|
|
151
153
|
# Handle built-in types
|
|
152
154
|
validate_builtin_type(xml_element, type_def, collector,
|
|
153
|
-
declared: schema_element
|
|
155
|
+
declared: schema_element,
|
|
156
|
+
repository: repository)
|
|
154
157
|
end
|
|
155
158
|
end
|
|
156
159
|
|
|
@@ -557,7 +560,7 @@ module Lutaml
|
|
|
557
560
|
#
|
|
558
561
|
# @return [Boolean]
|
|
559
562
|
def union_member_covers_builtin?(union_type, override, repository)
|
|
560
|
-
members =
|
|
563
|
+
members = union_type.union.member_types.to_s.split(/\s+/)
|
|
561
564
|
members.any? do |member|
|
|
562
565
|
local = member.to_s.split(":").last
|
|
563
566
|
next true if local == override
|
|
@@ -592,7 +595,8 @@ module Lutaml
|
|
|
592
595
|
validate_builtin_type(xml_element,
|
|
593
596
|
builtin_override_reference(xml_element),
|
|
594
597
|
collector,
|
|
595
|
-
declared: schema_element
|
|
598
|
+
declared: schema_element,
|
|
599
|
+
repository: repository)
|
|
596
600
|
true
|
|
597
601
|
end
|
|
598
602
|
|
|
@@ -653,12 +657,17 @@ module Lutaml
|
|
|
653
657
|
end
|
|
654
658
|
|
|
655
659
|
# XSD 1.0 §3.3.3: a fixed value constrains the element — a
|
|
656
|
-
# non-empty lexical must equal it in the
|
|
660
|
+
# non-empty lexical must equal it in the VALUE space
|
|
657
661
|
# (elemQ018). Empty content already validates against the
|
|
658
|
-
# fixed value through effective_text.
|
|
662
|
+
# fixed value through effective_text. Union/list-typed
|
|
663
|
+
# declarations map each lexical through the FIRST accepting
|
|
664
|
+
# member (§4.1.7) — 'true' equals fixed '1' as boolean-true
|
|
665
|
+
# (stE050), token collapse equates trailing blanks
|
|
666
|
+
# (stE065/066), float forms compare numerically (stE055).
|
|
659
667
|
#
|
|
660
668
|
# @return [void]
|
|
661
|
-
def validate_fixed_content(xml_element, declared, value, collector
|
|
669
|
+
def validate_fixed_content(xml_element, declared, value, collector,
|
|
670
|
+
repository: nil)
|
|
662
671
|
return unless declared.is_a?(Lutaml::Xml::Schema::Xsd::Element)
|
|
663
672
|
|
|
664
673
|
fixed = declared.fixed.to_s
|
|
@@ -667,6 +676,8 @@ module Lutaml
|
|
|
667
676
|
|
|
668
677
|
rule = declared_whitespace_rule(declared)
|
|
669
678
|
return if canonical(value.to_s, rule) == canonical(fixed, rule)
|
|
679
|
+
return if fixed_value_space_equal?(declared, value.to_s, fixed,
|
|
680
|
+
repository)
|
|
670
681
|
|
|
671
682
|
report_error(
|
|
672
683
|
collector,
|
|
@@ -682,6 +693,76 @@ module Lutaml
|
|
|
682
693
|
)
|
|
683
694
|
end
|
|
684
695
|
|
|
696
|
+
# Value-space equality for union/list-typed declarations:
|
|
697
|
+
# each side keys through the first accepting member and the
|
|
698
|
+
# keys must match.
|
|
699
|
+
#
|
|
700
|
+
# @return [Boolean]
|
|
701
|
+
def fixed_value_space_equal?(declared, value, fixed, repository)
|
|
702
|
+
simple = declared.simple_type
|
|
703
|
+
return false unless simple
|
|
704
|
+
|
|
705
|
+
if simple.union
|
|
706
|
+
members = simple.union.member_types.to_s.split(/\s+/)
|
|
707
|
+
return union_keys_equal?(value, fixed, members, repository)
|
|
708
|
+
end
|
|
709
|
+
return false unless simple.list
|
|
710
|
+
|
|
711
|
+
item_union = inline_item_union(simple.list, repository)
|
|
712
|
+
return false unless item_union
|
|
713
|
+
|
|
714
|
+
left = value.split
|
|
715
|
+
right = fixed.split
|
|
716
|
+
return false unless left.size == right.size
|
|
717
|
+
|
|
718
|
+
left.zip(right).all? do |a, b|
|
|
719
|
+
union_keys_equal?(a, b, item_union, repository)
|
|
720
|
+
end
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
# The member_types array of a list's item type: an inline
|
|
724
|
+
# union, else the named union resolved through the
|
|
725
|
+
# repository.
|
|
726
|
+
#
|
|
727
|
+
# @return [Array, nil]
|
|
728
|
+
def inline_item_union(list, repository)
|
|
729
|
+
inline = Array(list.simple_type).first
|
|
730
|
+
return inline.union.member_types.to_s.split(/\s+/) if inline&.union
|
|
731
|
+
|
|
732
|
+
reference = list.item_type.to_s.split(":").last
|
|
733
|
+
named = repository&.resolve_named_type(reference)
|
|
734
|
+
return named.union.member_types.to_s.split(/\s+/) if
|
|
735
|
+
named.is_a?(Lutaml::Xml::Schema::Xsd::SimpleType) && named.union
|
|
736
|
+
|
|
737
|
+
nil
|
|
738
|
+
end
|
|
739
|
+
|
|
740
|
+
# @return [Boolean]
|
|
741
|
+
def union_keys_equal?(value, fixed, members, repository)
|
|
742
|
+
a = first_member_key(value, members, repository)
|
|
743
|
+
b = first_member_key(fixed, members, repository)
|
|
744
|
+
!a.nil? && !b.nil? && a == b
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
# @return [Object, nil]
|
|
748
|
+
def first_member_key(lexical, members, repository)
|
|
749
|
+
members.each do |member|
|
|
750
|
+
local = member.to_s.split(":").last
|
|
751
|
+
key = ValueSpace.union_member_value_key(local, lexical)
|
|
752
|
+
return key unless key.nil?
|
|
753
|
+
|
|
754
|
+
named = repository&.resolve_named_type(local)
|
|
755
|
+
next unless named.is_a?(Lutaml::Xml::Schema::Xsd::SimpleType) &&
|
|
756
|
+
named.union
|
|
757
|
+
|
|
758
|
+
nested = first_member_key(lexical,
|
|
759
|
+
named.union.member_types.to_s.split(/\s+/),
|
|
760
|
+
repository)
|
|
761
|
+
return nested unless nested.nil?
|
|
762
|
+
end
|
|
763
|
+
nil
|
|
764
|
+
end
|
|
765
|
+
|
|
685
766
|
# @return [Symbol] :preserve, :replace or :collapse
|
|
686
767
|
def declared_whitespace_rule(declared)
|
|
687
768
|
reference = declared.type.to_s
|
|
@@ -730,7 +811,8 @@ module Lutaml
|
|
|
730
811
|
collector, repository: nil,
|
|
731
812
|
declared: nil)
|
|
732
813
|
value = effective_text(xml_element, declared)
|
|
733
|
-
validate_fixed_content(xml_element, declared, value, collector
|
|
814
|
+
validate_fixed_content(xml_element, declared, value, collector,
|
|
815
|
+
repository: repository)
|
|
734
816
|
|
|
735
817
|
# Validate base type if present
|
|
736
818
|
if simple_type.restriction
|
|
@@ -1251,7 +1333,8 @@ module Lutaml
|
|
|
1251
1333
|
declared: declared)
|
|
1252
1334
|
elsif builtin_base?(raw_base)
|
|
1253
1335
|
validate_builtin_type(xml_element, raw_base, collector,
|
|
1254
|
-
declared: declared
|
|
1336
|
+
declared: declared,
|
|
1337
|
+
repository: repository)
|
|
1255
1338
|
end
|
|
1256
1339
|
elsif simple_content.restriction
|
|
1257
1340
|
# Restriction constrains a simple type
|
|
@@ -1273,9 +1356,10 @@ module Lutaml
|
|
|
1273
1356
|
# @param collector [ResultCollector] Result collector
|
|
1274
1357
|
# @return [void]
|
|
1275
1358
|
def validate_builtin_type(xml_element, type_name, collector,
|
|
1276
|
-
declared: nil)
|
|
1359
|
+
declared: nil, repository: nil)
|
|
1277
1360
|
value = effective_text(xml_element, declared)
|
|
1278
|
-
validate_fixed_content(xml_element, declared, value, collector
|
|
1361
|
+
validate_fixed_content(xml_element, declared, value, collector,
|
|
1362
|
+
repository: repository)
|
|
1279
1363
|
# A simple type has no element content: children under a
|
|
1280
1364
|
# builtin-typed element are illegal even when the lexical
|
|
1281
1365
|
# text is fine (dtZ86723 — the xsi:type-overridden root
|
|
@@ -120,6 +120,71 @@ module Lutaml
|
|
|
120
120
|
"NOTATION" => %w[QName anySimpleType anyType].freeze,
|
|
121
121
|
}.freeze
|
|
122
122
|
|
|
123
|
+
# The VALUE-SPACE key of a lexical under a union member
|
|
124
|
+
# builtin — nil when the member does not accept the lexical.
|
|
125
|
+
# A union maps a lexical through its FIRST accepting member
|
|
126
|
+
# (§4.1.7), so 'true' and '1' are both boolean-true (stE050)
|
|
127
|
+
# and token collapse equates trailing blanks (stE065/066).
|
|
128
|
+
#
|
|
129
|
+
# @param local [String] builtin member local name
|
|
130
|
+
# @param value [String] the lexical
|
|
131
|
+
# @return [Object, nil] a comparable value, or nil
|
|
132
|
+
def self.union_member_value_key(local, value)
|
|
133
|
+
text = value.to_s
|
|
134
|
+
case local
|
|
135
|
+
when "boolean"
|
|
136
|
+
b = text.strip
|
|
137
|
+
return nil unless b.match?(/\A(?:true|false|1|0)\z/)
|
|
138
|
+
|
|
139
|
+
%w[true 1].include?(b)
|
|
140
|
+
when *INTEGER_TYPES
|
|
141
|
+
return nil unless integer_valid?(local, text)
|
|
142
|
+
|
|
143
|
+
Integer(text.strip)
|
|
144
|
+
when "float", "double"
|
|
145
|
+
return nil unless text.strip.match?(
|
|
146
|
+
/\A(?:[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?|INF|-INF|NaN)\z/,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
f = Float(text.strip)
|
|
150
|
+
f.nan? ? "nan" : f
|
|
151
|
+
when "decimal"
|
|
152
|
+
return nil unless text.strip.match?(
|
|
153
|
+
/\A[+-]?(?:\d+(?:\.\d*)?|\.\d+)\z/,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
require "bigdecimal"
|
|
157
|
+
BigDecimal(text.strip)
|
|
158
|
+
when "string"
|
|
159
|
+
text
|
|
160
|
+
when "normalizedString"
|
|
161
|
+
text.gsub(/[\t\n\r]/, " ")
|
|
162
|
+
when *COLLAPSED_STRING_TYPES, "language", "Name", "NCName",
|
|
163
|
+
"ID", "IDREF", "NMTOKEN", "anyURI"
|
|
164
|
+
text.strip.split(/\s+/).join(" ")
|
|
165
|
+
when "gYear", "gYearMonth", "gMonth", "gMonthDay", "gDay"
|
|
166
|
+
return nil unless calendar_lexical_valid?(local, text)
|
|
167
|
+
|
|
168
|
+
calendar_key(text)
|
|
169
|
+
when "date", "dateTime", "time"
|
|
170
|
+
return nil unless lexical_answer(local, text) == true
|
|
171
|
+
|
|
172
|
+
temporal_key(text)
|
|
173
|
+
when "duration"
|
|
174
|
+
return nil unless duration_valid?(text)
|
|
175
|
+
|
|
176
|
+
duration_key(text)
|
|
177
|
+
when "hexBinary"
|
|
178
|
+
return nil unless text.match?(/\A(?:[0-9a-fA-F]{2})*\z/)
|
|
179
|
+
|
|
180
|
+
text.upcase
|
|
181
|
+
when "base64Binary"
|
|
182
|
+
return nil unless base64_valid?(text)
|
|
183
|
+
|
|
184
|
+
text
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
123
188
|
# Whether a builtin override local is validly derived from the
|
|
124
189
|
# declared local: identity or the declared name sits in the
|
|
125
190
|
# override's builtin ancestry. TRI-STATE: nil when the override
|
data/lib/lutaml/xsd/version.rb
CHANGED