lutaml-xsd 1.2.88 → 1.2.90

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: 39fc8674b3e5a3676a21e771abf673d48800564a4180cba74309033d31cbb59f
4
- data.tar.gz: ea5b72895e06313b4bb04802f4abb151aa3c3b3717f48186b7d23ca571faedc8
3
+ metadata.gz: 455a2b544740a5953b1d2195962d89a3b549c8daa3b97c97b8bc8a9739bec815
4
+ data.tar.gz: 5157237514326ad902236ce4a3f2f67940680ef8a3e0f2a080d3012a2ee6c6c1
5
5
  SHA512:
6
- metadata.gz: 96cb8f6600383f33e791d38544fec82e80c3c9abc376626d851a22165dff8be2d4c9d44011602f25280814d1ae8a55e53084c7fb247c81fbf517f30a28a9c95b
7
- data.tar.gz: ac0bd6900bb0ac55b5ca948f2f8c4881666340270d96277ffd541aef68ef6eae1bb6283ab43dfdd8c08f2a582b4d269d46a7a5f2c428e00bcf9e2d43b7a2d556
6
+ metadata.gz: 539801642fef0b0625c6d647305411294f71164f0ebc49b92993895b473784112aafde653b46cc87f32d3b278dc71a7eed6468b366343a1731bd51304102814a
7
+ data.tar.gz: 00413b4b3e957a333d13285ad87219cdec576d7ac135dbc7d8561aee6f41b3bd613338910b4b366622805e685c7c34cbb204b6bfbc74376bee5c5b3424e2723c
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 | 4611/4696 (98.19%) |
123
+ | pipeline | 4614/4696 (98.25%) |
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), +650 net over the 1.2.43 baseline. The escapes round (PR #197 — \d→\p{Nd},
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), +653 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
@@ -512,6 +512,37 @@ tuple keys, node-set field violations and absent-field rows handled, cross-eleme
512
512
  checks bind the no-ns int ct-A to the ns-b boolean children —
513
513
  'true' vs xsd:int — the per-child type plumbing under hint
514
514
  layering), full type-redefine body semantics.
515
+ - SIMPLE-TYPE-CHILDREN ROUND (2026-11-05, third attempt — the first
516
+ two regressed 15 at scale): +1 DataTypes (dtZ86723; suite
517
+ 4613->4614 = 98.25%, zero regressions, rspec green). A simple
518
+ type has no element content: the builtin assessment reports
519
+ children even when the lexical text is valid. THREE guards make
520
+ it sound where the earlier attempts were not: xs:anyType
521
+ overrides admit anything (isDefault072); unresolvable type
522
+ REFERENCES arrive at the builtin path as BARE NAMES through the
523
+ lenient fallback (resolve_element_type returns
524
+ schema_element.type on miss) — only xs/xsd-prefixed names are
525
+ builtin-typed, so the redefine-lenient tabletype class
526
+ (idF/idG) never triggers. The full 19-case battery — including
527
+ every case both earlier attempts regressed — passes. THE ROOT
528
+ CAUSE DISCOVERY: the lenient string fallback meant every
529
+ failed type resolution silently took the builtin path — the
530
+ children check is the first consumer that had to distinguish.
531
+ - TEMPORAL-ENUMERATION ROUND (2026-11-05): +2 DataTypes (10->8,
532
+ dateTime_enumeration005a/b; suite 4611->4613 = 98.23%, zero
533
+ regressions, rspec green). Enumeration membership is a VALUE-space
534
+ test (Appendix E): the element- and attribute-side enumeration
535
+ checks now retry with INSTANT equality when the string compare
536
+ misses — both sides must parse as date-times and denote the same
537
+ instant (+00:00 equals Z). Unparseable forms never match, so the
538
+ string compare stays authoritative for every non-temporal type.
539
+ The 005a/b cases were orphaned legs of leptris-rs#27 (the engine
540
+ side fixed; our Ruby enumeration check carried the same lexical
541
+ comparison). ALSO UPSTREAM this round: three orphaned-leg
542
+ evidence comments posted (leptris-rs#36 confirmed FIXED by 406
543
+ and closed-out; #35 comment — stE050/stE055 fixed+empty root
544
+ legs still firing; #29 comment — elemZ020 substitution binding
545
+ still firing); the per-team remaining-issue inventory registered.
515
546
  - ENGINE-406 RIDE ROUND (2026-11-04, owner "leptris is updated"):
516
547
  leptris 1.9.403.0 -> 1.9.406.0 (three rides). +19 (suite
517
548
  4592->4611 = 98.19%, rspec green): the FULL #35 wave (fixed-empty
@@ -829,6 +829,20 @@ module Lutaml
829
829
  allowed = Array(restriction.enumeration).map(&:value)
830
830
  return nil if allowed.empty? || allowed.include?(value)
831
831
 
832
+ # Appendix E membership is by VALUE: timezone-shifted
833
+ # spellings of the same instant are members. Unparseable
834
+ # forms never match — the string compare stays
835
+ # authoritative.
836
+ require "date"
837
+ instant = begin
838
+ DateTime.parse(value.to_s)
839
+ rescue StandardError
840
+ nil
841
+ end
842
+ return nil if instant && allowed.any? do |candidate|
843
+ parse_candidate_instant(candidate) == instant
844
+ end
845
+
832
846
  {
833
847
  code: "attribute_enumeration_violation",
834
848
  message: "has value '#{value}' that is not among " \
@@ -837,6 +851,14 @@ module Lutaml
837
851
  }
838
852
  end
839
853
 
854
+ # @return [DateTime, nil]
855
+ def parse_candidate_instant(text)
856
+ require "date"
857
+ DateTime.parse(text.to_s)
858
+ rescue StandardError
859
+ nil
860
+ end
861
+
840
862
  def pattern_violation(value, restriction)
841
863
  patterns = Array(restriction.pattern)
842
864
  return nil if patterns.empty?
@@ -852,6 +852,10 @@ module Lutaml
852
852
  end
853
853
 
854
854
  return if allowed_values.include?(value)
855
+ # Appendix E membership is by VALUE: timezone-shifted
856
+ # lexical forms of the same instant are members (the #27
857
+ # reading — "+00:00" equals "Z").
858
+ return if temporal_enumeration_match?(allowed_values, value)
855
859
 
856
860
  report_error(
857
861
  collector,
@@ -866,6 +870,29 @@ module Lutaml
866
870
  )
867
871
  end
868
872
 
873
+ # Instant-equality membership for temporal enumerations: both
874
+ # sides must parse as date-times and denote the same instant
875
+ # (timezone-shifted spellings are members). Unparseable forms
876
+ # never match — the string compare stays authoritative.
877
+ #
878
+ # @return [Boolean]
879
+ def temporal_enumeration_match?(allowed_values, value)
880
+ require "date"
881
+ instant = parse_instant(value)
882
+ return false unless instant
883
+
884
+ allowed_values.any? do |allowed|
885
+ parse_instant(allowed) == instant
886
+ end
887
+ end
888
+
889
+ # @return [DateTime, nil]
890
+ def parse_instant(text)
891
+ DateTime.parse(text.to_s)
892
+ rescue StandardError
893
+ nil
894
+ end
895
+
869
896
  # Validate list type
870
897
  #
871
898
  # @param value [String] The value
@@ -1022,6 +1049,33 @@ module Lutaml
1022
1049
  declared: nil)
1023
1050
  value = effective_text(xml_element, declared)
1024
1051
  validate_fixed_content(xml_element, declared, value, collector)
1052
+ # A simple type has no element content: children under a
1053
+ # builtin-typed element are illegal even when the lexical
1054
+ # text is fine (dtZ86723 — the xsi:type-overridden root
1055
+ # carries a stray child beside a valid int). xs:anyType
1056
+ # overrides admit anything (isDefault072); unresolvable
1057
+ # type REFERENCES arrive here as bare names (the lenient
1058
+ # fallback returns schema_element.type) and are not
1059
+ # builtin-typed at all (idF/idG's redefine-lenient
1060
+ # "tabletype").
1061
+ prefix = type_name.to_s.split(":").first
1062
+ local = type_name.to_s.split(":").last
1063
+ if !xml_element.children.empty? &&
1064
+ BUILTIN_PREFIXES.include?(prefix) &&
1065
+ local != "anyType"
1066
+ report_error(
1067
+ collector,
1068
+ code: "simple_type_element_content",
1069
+ message: "Element '#{xml_element.name}' has a simple " \
1070
+ "type (#{type_name}) and cannot carry " \
1071
+ "element children",
1072
+ location: xml_element.xpath,
1073
+ context: {
1074
+ element: xml_element.name,
1075
+ type: type_name,
1076
+ },
1077
+ )
1078
+ end
1025
1079
  answer = engine_builtin_answer(type_name, value)
1026
1080
  return if answer.nil?
1027
1081
  return if answer
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Xsd
5
- VERSION = "1.2.88"
5
+ VERSION = "1.2.90"
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.88
4
+ version: 1.2.90
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-04 00:00:00.000000000 Z
11
+ date: 2026-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid