lutaml-xsd 1.2.82 → 1.2.83
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 +4 -4
- data/TODO.conformance.md +26 -2
- data/lib/lutaml/xsd/conformance/w3c_suite.rb +11 -2
- data/lib/lutaml/xsd/validation/rules/attribute_validation_rule.rb +15 -5
- data/lib/lutaml/xsd/validation/rules/content_model_validation_rule.rb +2 -1
- data/lib/lutaml/xsd/validation/schema_definition_resolver.rb +76 -32
- data/lib/lutaml/xsd/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: efe4fbd2d864e7cbe9218faaf7f67fc879c4e20cc32c54e04761fcee59d2d1dc
|
|
4
|
+
data.tar.gz: 3b5618daa924a8a493645bab5ea7f0408d3b9245c32695306131c1cb9a0cfeb8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 909c81244dd126cbbb8843fcd3a010f5da4a3c70bd325b71ed5865496cc390d101fecb6d6a4c38069b350abad064c4837328f5ee28cdcb583b4ec5e439c629da
|
|
7
|
+
data.tar.gz: 34a60915d85511b36be444dc6903e8f3f221e6740d3d6147fd5966c0fe82a852896dffb20fbf6253376bb78abeaa4a2717da83b4b44e644739acda1e85105c33
|
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 | 4585/4696 (97.64%) |
|
|
124
124
|
|
|
125
125
|
(2026-11-02, bundled-stack measurement with the escape,
|
|
126
126
|
hint-following, pattern-alternative, identity-crash, engine-set,
|
|
@@ -143,7 +143,8 @@ lockfile refresh) → 4411 (93.9%) → 4430 (94.3%) → 4435 (94.4%) →
|
|
|
143
143
|
(96.3%) → 4534 (96.6%) → 4540 (96.7%) → 4542 (96.7%) → 4546 (96.8%)
|
|
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
|
-
round) → 4578 (97.49%, attribute-prohibition round)
|
|
146
|
+
round) → 4578 (97.49%, attribute-prohibition round) → 4585 (97.64%,
|
|
147
|
+
multi-document round), +624 net over the 1.2.43 baseline. The escapes round (PR #197 — \d→\p{Nd},
|
|
147
148
|
\w/\W/\s to their XSD value spaces) collapses Regex 120→69;
|
|
148
149
|
same-step pattern facets now behave as alternatives and
|
|
149
150
|
whitespace-only text reaches the facets intact (PR #200), Regex
|
|
@@ -470,6 +471,29 @@ tuple keys, node-set field violations and absent-field rows handled, cross-eleme
|
|
|
470
471
|
use-site fixed overlays the global declaration in the value check
|
|
471
472
|
(attLa005). Attribute remainder (4): attJ018 + attO009/011
|
|
472
473
|
(engine-silent — queue), attO006 (leptris-rs#25 attribute leg).
|
|
474
|
+
- MULTI-DOCUMENT ROUND (2026-11-03): +7 (Schema 12→9 — the schT3/T9/
|
|
475
|
+
T10 redefine trio; ComplexType 4→1, Particles 12→10, Additional
|
|
476
|
+
10→9, IC 7→6 — same-namespace collision pairs; suite 4578→4585 =
|
|
477
|
+
97.64%, zero regressions, rspec green). TWO defects: (a) the
|
|
478
|
+
conformance repository keyed documents by TARGET NAMESPACE, so two
|
|
479
|
+
schemaDocuments sharing a namespace silently overwrote each other
|
|
480
|
+
and only one survived (schT3's redefine pair, both ns-a); a
|
|
481
|
+
same-namespace collision now suffixes the key instead of dropping
|
|
482
|
+
the document — every other case keeps the production one-doc-per-
|
|
483
|
+
namespace semantics (a naive path-key for everything cost 25
|
|
484
|
+
regressions via the unique-name fallback and first-match type
|
|
485
|
+
lookup, caught and reverted in-round). (b) resolve_named_type now
|
|
486
|
+
falls back to the parsed xs:redefine target documents: types living
|
|
487
|
+
only in the target (schT3 b-ct/b-st) resolve for plain references;
|
|
488
|
+
names a redefine BODY redefines stay OFF that path (the body is the
|
|
489
|
+
effective type and is not resolvable here — idF/idG/idH keep the
|
|
490
|
+
lenient path). KNOWN GAPS left open: schA1/schQ1/schD10/schF2
|
|
491
|
+
(hint-composition with same-local-name ct-A across namespaces —
|
|
492
|
+
per-namespace type binding), full type-redefine body semantics
|
|
493
|
+
(the body as effective type with the self-base hook — a
|
|
494
|
+
lutaml-model Redefine model shape study). Remaining Schema 9:
|
|
495
|
+
schA1/Q1/D10/F2 (ours), schD7/G8 (lutaml-model#1087),
|
|
496
|
+
schF1/G2/G7/P2 (moxml#510 composed bindings).
|
|
473
497
|
- REGEX SEMANTICS ROUND (2026-10-31, PR #208): \w/\W now carry their
|
|
474
498
|
Appendix F complements (\w = [^\p{P}\p{Z}\p{C}], class interiors
|
|
475
499
|
via the exact positive partition L/M/N/S), \I/\C complements added
|
|
@@ -154,8 +154,17 @@ module Lutaml
|
|
|
154
154
|
test_case.schema_paths.each do |path|
|
|
155
155
|
schema = Lutaml::Xml::Schema::Xsd.parse(File.read(path),
|
|
156
156
|
location: path)
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
# Keyed by target namespace like production, EXCEPT that a
|
|
158
|
+
# same-namespace collision suffixes the key instead of
|
|
159
|
+
# dropping the document (schT3's redefine pair both declare
|
|
160
|
+
# ns-a). The resolver iterates values; keys only need to
|
|
161
|
+
# keep every document present.
|
|
162
|
+
key = if schema.target_namespace.to_s.match?(/\S/)
|
|
163
|
+
schema.target_namespace
|
|
164
|
+
else
|
|
165
|
+
path
|
|
166
|
+
end
|
|
167
|
+
key = "#{key}##{path}" while schemas.key?(key)
|
|
159
168
|
schemas[key] = schema
|
|
160
169
|
locations[path] = schema
|
|
161
170
|
end
|
|
@@ -222,7 +222,11 @@ module Lutaml
|
|
|
222
222
|
# Base attributes flow through both derivations — a
|
|
223
223
|
# restriction narrows them but cannot drop them (XSD 1.0
|
|
224
224
|
# §3.4.2).
|
|
225
|
-
|
|
225
|
+
if part
|
|
226
|
+
attributes.concat(
|
|
227
|
+
inherited_attributes(part, repository),
|
|
228
|
+
)
|
|
229
|
+
end
|
|
226
230
|
end
|
|
227
231
|
|
|
228
232
|
# Handle simple content
|
|
@@ -234,7 +238,11 @@ module Lutaml
|
|
|
234
238
|
)
|
|
235
239
|
part = Array(schema_def.simple_content.extension).first ||
|
|
236
240
|
Array(schema_def.simple_content.restriction).first
|
|
237
|
-
|
|
241
|
+
if part
|
|
242
|
+
attributes.concat(
|
|
243
|
+
inherited_attributes(part, repository),
|
|
244
|
+
)
|
|
245
|
+
end
|
|
238
246
|
end
|
|
239
247
|
|
|
240
248
|
override_base_prohibitions(schema_def, attributes)
|
|
@@ -267,11 +275,13 @@ module Lutaml
|
|
|
267
275
|
end
|
|
268
276
|
|
|
269
277
|
# The base type's attribute set flows into the derived type
|
|
270
|
-
# through extension and restriction alike.
|
|
278
|
+
# through extension and restriction alike. The base resolves
|
|
279
|
+
# through the derivation so a redefine body's own base hooks
|
|
280
|
+
# to the original definition.
|
|
271
281
|
#
|
|
272
282
|
# @return [Array<Lutaml::Xml::Schema::Xsd::Attribute>]
|
|
273
|
-
def inherited_attributes(
|
|
274
|
-
local =
|
|
283
|
+
def inherited_attributes(part, repository)
|
|
284
|
+
local = part.base.to_s.split(":").last
|
|
275
285
|
return [] if local.to_s.empty?
|
|
276
286
|
|
|
277
287
|
base = repository&.resolve_named_type(local)
|
|
@@ -302,7 +302,8 @@ module Lutaml
|
|
|
302
302
|
restriction = Array(content.restriction).first
|
|
303
303
|
if extension
|
|
304
304
|
base_local = extension.base.to_s.split(":").last
|
|
305
|
-
base_type = base_local &&
|
|
305
|
+
base_type = base_local &&
|
|
306
|
+
repository&.resolve_named_type(base_local)
|
|
306
307
|
particles = type_particles(base_type, repository, seen) +
|
|
307
308
|
particles
|
|
308
309
|
COMPLEX_PARTICLE_KINDS.each do |kind|
|
|
@@ -50,6 +50,14 @@ module Lutaml
|
|
|
50
50
|
@attributes = Hash.new { |hash, key| hash[key] = [] }
|
|
51
51
|
@attribute_groups = {}
|
|
52
52
|
@redefined_originals = {}
|
|
53
|
+
# Parsed xs:redefine target documents: their named types back
|
|
54
|
+
# the redefined bodies (schT3: b-ct/b-st live in the target,
|
|
55
|
+
# which the repository does not hold). Names a redefine BODY
|
|
56
|
+
# redefines are NOT served from the target: the body is the
|
|
57
|
+
# effective type and is not resolvable here, so those keep
|
|
58
|
+
# the lenient unresolvable path (idF/idG/idH class).
|
|
59
|
+
@redefined_targets = []
|
|
60
|
+
@redefined_body_names = []
|
|
53
61
|
@elements = index_elements
|
|
54
62
|
end
|
|
55
63
|
|
|
@@ -200,18 +208,29 @@ module Lutaml
|
|
|
200
208
|
|
|
201
209
|
result = nil
|
|
202
210
|
schemas.each do |schema|
|
|
203
|
-
|
|
204
|
-
ct.name == local_name
|
|
205
|
-
end
|
|
206
|
-
found ||= Array(schema.simple_type).find do |st|
|
|
207
|
-
st.name == local_name
|
|
208
|
-
end
|
|
209
|
-
result = found || find_nested_named_type(local_name, schema)
|
|
211
|
+
result = named_type_in(local_name, schema)
|
|
210
212
|
break if result
|
|
211
213
|
end
|
|
214
|
+
if result.nil? && !@redefined_body_names.include?(local_name)
|
|
215
|
+
@redefined_targets.each do |schema|
|
|
216
|
+
result = named_type_in(local_name, schema)
|
|
217
|
+
break if result
|
|
218
|
+
end
|
|
219
|
+
end
|
|
212
220
|
@named_types[local_name] = result
|
|
213
221
|
end
|
|
214
222
|
|
|
223
|
+
# @return [Object, nil]
|
|
224
|
+
def named_type_in(local_name, schema)
|
|
225
|
+
found = Array(schema.complex_type).find do |ct|
|
|
226
|
+
ct.name == local_name
|
|
227
|
+
end
|
|
228
|
+
found ||= Array(schema.simple_type).find do |st|
|
|
229
|
+
st.name == local_name
|
|
230
|
+
end
|
|
231
|
+
found || find_nested_named_type(local_name, schema)
|
|
232
|
+
end
|
|
233
|
+
|
|
215
234
|
# Named types declared in documents reached through resolved
|
|
216
235
|
# includes/imports — chameleon types (ctE018) live in a
|
|
217
236
|
# no-namespace include target.
|
|
@@ -602,35 +621,60 @@ module Lutaml
|
|
|
602
621
|
# indexed under the name (attgC007/attgD036). Runs after the
|
|
603
622
|
# nested descent so included declarations are already in.
|
|
604
623
|
Array(schema.redefine).each do |red|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
624
|
+
index_redefine(index, schema, red, held_signatures, namespace,
|
|
625
|
+
defaults_schema)
|
|
626
|
+
end
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
# xs:redefine replaces an attributeGroup with a body whose
|
|
630
|
+
# self-reference is the §4.2.2 hook to the ORIGINAL
|
|
631
|
+
# definition. lutaml-model does NOT chase the redefine
|
|
632
|
+
# target, so the original document is parsed here (relative
|
|
633
|
+
# to the defining file) and indexed; the original
|
|
634
|
+
# declaration is kept for that hook and the redefining body
|
|
635
|
+
# indexed under the name (attgC007/attgD036). Runs after the
|
|
636
|
+
# nested descent so included declarations are already in.
|
|
637
|
+
def index_redefine(index, schema, red, held_signatures, namespace,
|
|
638
|
+
defaults_schema)
|
|
639
|
+
target_path = nil
|
|
640
|
+
base = begin
|
|
641
|
+
File.dirname(@repository.source_path_for(schema))
|
|
642
|
+
rescue StandardError
|
|
643
|
+
nil
|
|
644
|
+
end
|
|
645
|
+
if base && red.schema_path.to_s.match?(/\S/)
|
|
646
|
+
candidate = File.expand_path(red.schema_path.to_s, base)
|
|
647
|
+
target_path = candidate if File.exist?(candidate)
|
|
648
|
+
end
|
|
649
|
+
if target_path
|
|
650
|
+
begin
|
|
651
|
+
target = Lutaml::Xml::Schema::Xsd.parse(
|
|
652
|
+
File.read(target_path), location: target_path
|
|
653
|
+
)
|
|
654
|
+
@redefined_targets << target
|
|
655
|
+
index_schema(index, target, held_signatures, namespace,
|
|
656
|
+
defaults_schema)
|
|
608
657
|
rescue StandardError
|
|
609
658
|
nil
|
|
610
659
|
end
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
end
|
|
626
|
-
Array(red.attribute_group).each do |group|
|
|
627
|
-
name = group.name.to_s
|
|
628
|
-
next if name.empty?
|
|
660
|
+
end
|
|
661
|
+
# Names the body redefines: served by the body (not
|
|
662
|
+
# resolvable here), never by the target originals.
|
|
663
|
+
Array(red.complex_type).each do |body|
|
|
664
|
+
name = body.name.to_s
|
|
665
|
+
@redefined_body_names << name unless name.empty?
|
|
666
|
+
end
|
|
667
|
+
Array(red.simple_type).each do |body|
|
|
668
|
+
name = body.name.to_s
|
|
669
|
+
@redefined_body_names << name unless name.empty?
|
|
670
|
+
end
|
|
671
|
+
Array(red.attribute_group).each do |group|
|
|
672
|
+
name = group.name.to_s
|
|
673
|
+
next if name.empty?
|
|
629
674
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
end
|
|
675
|
+
original = @attribute_groups[name]
|
|
676
|
+
@redefined_originals[name] = original if original
|
|
677
|
+
@attribute_groups[name] = group
|
|
634
678
|
end
|
|
635
679
|
end
|
|
636
680
|
|
data/lib/lutaml/xsd/version.rb
CHANGED