lutaml-model 0.8.145 → 0.8.147
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/lib/lutaml/key_value/adapter/yamls/standard_adapter.rb +1 -1
- data/lib/lutaml/model/utils.rb +11 -0
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/xml/leptris/plan_hydrator.rb +53 -21
- data/lib/lutaml/xml/schema/xsd/schema.rb +3 -1
- data/lib/lutaml/yamls/adapter/standard_adapter.rb +2 -2
- data/spec/lutaml/model/yamls_spec.rb +32 -0
- data/spec/lutaml/xml/leptris/plan_hydrator_ns_snapshot_spec.rb +61 -0
- data/spec/lutaml/xml/schema/xsd/import_without_namespace_spec.rb +61 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 73297b741e0c6f033811660bef32b0bcd51529d9ebd517ec3c67cd386e7134e6
|
|
4
|
+
data.tar.gz: a8fd9b7f9f0d6d95fd40441a116dc8e81639b8ef8e79c5c9c026c7d82691a7bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 24717f565b570a808908949176ba5b006fc1b176018776a85f62df04d63e152bb8fc6e5c88badca9d7ede0911cffe79b65c908de9fec356af56f4fc7ba0a7b2e
|
|
7
|
+
data.tar.gz: a3203db4195bf6f4a5d32529febd708ab574c07e0d7b93dfdb64674d1e0bdd37c5a2d5965e8506d023ea90c70d620622c38d43b3a02072f1fc4c014483b65590
|
data/lib/lutaml/model/utils.rb
CHANGED
|
@@ -34,6 +34,17 @@ module Lutaml
|
|
|
34
34
|
false
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
# Parse-error classes of every YAML engine that may be answering
|
|
38
|
+
# ::YAML in this process. A host bundle can rebind ::YAML (a
|
|
39
|
+
# Psych drop-in), so the multi-document skip-rescues must cover
|
|
40
|
+
# each loaded engine's parse error, not only Psych's (#1053: a
|
|
41
|
+
# raw Yeptris::ParseError escaped from_yamls).
|
|
42
|
+
def yaml_parse_errors
|
|
43
|
+
errors = [Psych::SyntaxError]
|
|
44
|
+
errors << Yeptris::ParseError if defined?(Yeptris::ParseError)
|
|
45
|
+
errors
|
|
46
|
+
end
|
|
47
|
+
|
|
37
48
|
# Convert string to camel case (cached)
|
|
38
49
|
def camel_case(str)
|
|
39
50
|
return "" if str.nil? || str.empty?
|
data/lib/lutaml/model/version.rb
CHANGED
|
@@ -94,6 +94,50 @@ module Lutaml
|
|
|
94
94
|
instance
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
+
# leptris#1874: snapshot rows -> the ns_data hash
|
|
98
|
+
# ({path => {prefix_key => {uri:, prefix:, format:}}}), the
|
|
99
|
+
# exact shape the recursion builds. Public: it is the
|
|
100
|
+
# contract the binding's snapshot rows must satisfy.
|
|
101
|
+
def ns_data_from_snapshot_rows(rows)
|
|
102
|
+
rows.each_with_object({}) do |row, result|
|
|
103
|
+
prefix = row[:prefix]
|
|
104
|
+
# One element carrying several declarations emits one
|
|
105
|
+
# row PER declaration with the same path — merge them,
|
|
106
|
+
# exactly as the recursion accumulates per path.
|
|
107
|
+
(result[row[:path]] ||= {})[row[:prefix] || :default] = {
|
|
108
|
+
uri: row[:href], prefix: prefix,
|
|
109
|
+
format: prefix ? :prefix : :default
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def collect_native_namespaces(element, path = [], result = {})
|
|
115
|
+
if element.respond_to?(:namespace_declarations_snapshot)
|
|
116
|
+
return ns_data_from_snapshot_rows(
|
|
117
|
+
element.namespace_declarations_snapshot,
|
|
118
|
+
)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
own = element.namespace_definitions
|
|
122
|
+
unless own.empty?
|
|
123
|
+
namespaces = {}
|
|
124
|
+
own.each do |ns|
|
|
125
|
+
key = ns.prefix || :default
|
|
126
|
+
namespaces[key] = { uri: ns.href, prefix: ns.prefix,
|
|
127
|
+
format: ns.prefix ? :prefix : :default }
|
|
128
|
+
end
|
|
129
|
+
result[path.dup] = namespaces
|
|
130
|
+
end
|
|
131
|
+
element.children.each do |child|
|
|
132
|
+
next unless child.is_a?(::Leptris::XML::Element)
|
|
133
|
+
|
|
134
|
+
path.push(child.name)
|
|
135
|
+
collect_native_namespaces(child, path, result)
|
|
136
|
+
path.pop
|
|
137
|
+
end
|
|
138
|
+
result
|
|
139
|
+
end
|
|
140
|
+
|
|
97
141
|
private
|
|
98
142
|
|
|
99
143
|
def record_declaration_plan(instance, node, model_class)
|
|
@@ -123,27 +167,15 @@ module Lutaml
|
|
|
123
167
|
# Iterates children with an inline element filter:
|
|
124
168
|
# element_children materializes a filtered array per node,
|
|
125
169
|
# which the niso allocation gate caught at scale.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
result[path.dup] = namespaces
|
|
136
|
-
end
|
|
137
|
-
element.children.each do |child|
|
|
138
|
-
next unless child.is_a?(::Leptris::XML::Element)
|
|
139
|
-
|
|
140
|
-
path.push(child.name)
|
|
141
|
-
collect_native_namespaces(child, path, result)
|
|
142
|
-
path.pop
|
|
143
|
-
end
|
|
144
|
-
result
|
|
145
|
-
end
|
|
146
|
-
|
|
170
|
+
#
|
|
171
|
+
# leptris#1874: when the binding exposes the bulk snapshot
|
|
172
|
+
# face (namespace_declarations_snapshot — one FFI crossing
|
|
173
|
+
# for the whole subtree; shipped engine-side in 1.9.387),
|
|
174
|
+
# the whole-subtree Ruby recursion collapses into a single
|
|
175
|
+
# call. Rows: {path: [names...], prefix: String|nil,
|
|
176
|
+
# href: String} in pre-order, paths relative to the
|
|
177
|
+
# receiver. The face probe keeps older bindings on the
|
|
178
|
+
# recursion unchanged.
|
|
147
179
|
def register
|
|
148
180
|
Lutaml::Model::Config.default_register
|
|
149
181
|
end
|
|
@@ -86,7 +86,9 @@ module Lutaml
|
|
|
86
86
|
"import",
|
|
87
87
|
model,
|
|
88
88
|
schema,
|
|
89
|
-
|
|
89
|
+
# An xs:import without a namespace attribute is legal
|
|
90
|
+
# (XSD 1.0 §3.13.2); the raw read stays nil-safe (#1051).
|
|
91
|
+
namespace: schema.attributes["namespace"]&.value,
|
|
90
92
|
)
|
|
91
93
|
end
|
|
92
94
|
end
|
|
@@ -22,7 +22,7 @@ module Lutaml
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
results
|
|
25
|
-
rescue
|
|
25
|
+
rescue *Lutaml::Model::Utils.yaml_parse_errors => e
|
|
26
26
|
warn "Skipping invalid yaml: #{e.message}"
|
|
27
27
|
parse_with_split(yamls)
|
|
28
28
|
end
|
|
@@ -36,7 +36,7 @@ module Lutaml
|
|
|
36
36
|
begin
|
|
37
37
|
doc = YAML.safe_load(yaml, aliases: true)
|
|
38
38
|
results << doc unless doc.nil?
|
|
39
|
-
rescue
|
|
39
|
+
rescue *Lutaml::Model::Utils.yaml_parse_errors => e
|
|
40
40
|
warn "Skipping invalid yaml: #{e.message}"
|
|
41
41
|
end
|
|
42
42
|
end
|
|
@@ -154,6 +154,38 @@ RSpec.describe "Yamls" do
|
|
|
154
154
|
end.to output(/Skipping invalid yaml: /).to_stderr
|
|
155
155
|
end
|
|
156
156
|
|
|
157
|
+
# #1053: a host bundle can rebind ::YAML to another engine (a Psych
|
|
158
|
+
# drop-in), so the multi-doc lane must treat every loaded engine's
|
|
159
|
+
# parse error as a skippable document error — never let a raw engine
|
|
160
|
+
# error escape.
|
|
161
|
+
describe "engine parse errors" do
|
|
162
|
+
it "rescues every loaded YAML engine's parse errors" do
|
|
163
|
+
errors = Lutaml::Model::Utils.yaml_parse_errors
|
|
164
|
+
|
|
165
|
+
expect(errors).to include(Psych::SyntaxError)
|
|
166
|
+
if defined?(Yeptris::ParseError)
|
|
167
|
+
expect(errors).to include(Yeptris::ParseError)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "skips an invalid document when the active engine raises its own parse error" do
|
|
172
|
+
skip "yeptris not loadable in this process" unless Lutaml::Model::Utils.safe_load("yeptris", :Yeptris)
|
|
173
|
+
|
|
174
|
+
allow(YAML).to receive(:load_stream).and_raise(
|
|
175
|
+
Yeptris::ParseError.new("parse failed: unexpected parser state at line 11, column 26"),
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
expect do
|
|
179
|
+
expect(Lutaml::Yamls::Adapter::StandardAdapter.parse(invalid_yamls_content)).to eq(
|
|
180
|
+
[
|
|
181
|
+
{ "full_name" => "John", "age" => 30, "address" => { "city" => "New York" } },
|
|
182
|
+
{ "full_name" => "Bob", "age" => 35, "address" => { "city" => "Paris" } },
|
|
183
|
+
],
|
|
184
|
+
)
|
|
185
|
+
end.to output(/Skipping invalid yaml: /).to_stderr
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
157
189
|
describe "parsing" do
|
|
158
190
|
it "handles empty documents" do
|
|
159
191
|
yamls_with_empty_docs = <<~YAMLS
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require_relative "../../../../lib/lutaml/model"
|
|
3
|
+
|
|
4
|
+
# leptris#1874: the plan hydrator's namespace collection collapses the
|
|
5
|
+
# whole-subtree Ruby recursion (one namespace_definitions FFI crossing
|
|
6
|
+
# per node) into the engine's bulk snapshot face when the binding
|
|
7
|
+
# exposes it. These specs pin the ROW CONTRACT the binding must
|
|
8
|
+
# satisfy and the dispatch, so the binding PR can be verified without
|
|
9
|
+
# waiting for the native pin bump.
|
|
10
|
+
# A real lightweight struct standing in for the future binding
|
|
11
|
+
# element: responds to the bulk face with fixed rows, carries no
|
|
12
|
+
# behavior of its own.
|
|
13
|
+
SnapshotFaceElement = Struct.new(:rows) do
|
|
14
|
+
def namespace_declarations_snapshot
|
|
15
|
+
rows
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
RSpec.describe Lutaml::Xml::Leptris::PlanHydrator do
|
|
20
|
+
describe ".ns_data_from_snapshot_rows" do
|
|
21
|
+
it "builds the ns_data hash from pre-order snapshot rows" do
|
|
22
|
+
rows = [
|
|
23
|
+
{ path: [], prefix: nil, href: "urn:d" },
|
|
24
|
+
{ path: [], prefix: "a", href: "urn:a" },
|
|
25
|
+
{ path: ["c1"], prefix: "b", href: "urn:b" },
|
|
26
|
+
{ path: ["c2"], prefix: nil, href: "urn:d2" },
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
result = described_class.ns_data_from_snapshot_rows(rows)
|
|
30
|
+
|
|
31
|
+
expect(result).to eq(
|
|
32
|
+
[] => { default: { uri: "urn:d", prefix: nil,
|
|
33
|
+
format: :default },
|
|
34
|
+
"a" => { uri: "urn:a", prefix: "a", format: :prefix } },
|
|
35
|
+
["c1"] => { "b" => { uri: "urn:b", prefix: "b",
|
|
36
|
+
format: :prefix } },
|
|
37
|
+
["c2"] => { default: { uri: "urn:d2", prefix: nil,
|
|
38
|
+
format: :default } },
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "returns an empty hash for a declaration-free subtree" do
|
|
43
|
+
expect(described_class.ns_data_from_snapshot_rows([])).to eq({})
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe "the snapshot face probe in collect_native_namespaces" do
|
|
48
|
+
it "prefers the bulk face when the binding exposes it" do
|
|
49
|
+
element = SnapshotFaceElement.new(
|
|
50
|
+
[{ path: ["x"], prefix: "p", href: "urn:p" }],
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
result = described_class.collect_native_namespaces(element)
|
|
54
|
+
|
|
55
|
+
expect(result).to eq(
|
|
56
|
+
["x"] => { "p" => { uri: "urn:p", prefix: "p",
|
|
57
|
+
format: :prefix } },
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tmpdir"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require_relative "../../../../spec_helper"
|
|
6
|
+
require "lutaml/xml/schema/xsd"
|
|
7
|
+
|
|
8
|
+
# #1051: an xs:import without a namespace attribute is legal
|
|
9
|
+
# (XSD 1.0 §3.13.2 — it imports a schema document with no target
|
|
10
|
+
# namespace). The schema walk read the attribute store unguarded, so
|
|
11
|
+
# a follow-up schema document carrying such an import crashed the
|
|
12
|
+
# parse with "undefined method 'value' for nil".
|
|
13
|
+
RSpec.describe "Xsd import without a namespace attribute" do
|
|
14
|
+
let(:dir) { Dir.mktmpdir }
|
|
15
|
+
|
|
16
|
+
before do
|
|
17
|
+
File.write(File.join(dir, "a.xsd"), <<~XSD)
|
|
18
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
19
|
+
<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="b.xsd"/>
|
|
20
|
+
<xs:element name="root"/>
|
|
21
|
+
</xs:schema>
|
|
22
|
+
XSD
|
|
23
|
+
File.write(File.join(dir, "b.xsd"), <<~XSD)
|
|
24
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
25
|
+
<xs:import schemaLocation="c.xsd"/>
|
|
26
|
+
<xs:attribute name="lang" type="xs:language"/>
|
|
27
|
+
</xs:schema>
|
|
28
|
+
XSD
|
|
29
|
+
File.write(File.join(dir, "c.xsd"), <<~XSD)
|
|
30
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
31
|
+
<xs:element name="helper"/>
|
|
32
|
+
</xs:schema>
|
|
33
|
+
XSD
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
after { FileUtils.remove_entry(dir) }
|
|
37
|
+
|
|
38
|
+
it "parses the whole chain" do
|
|
39
|
+
parsed = Lutaml::Xml::Schema::Xsd.parse(
|
|
40
|
+
File.read(File.join(dir, "a.xsd")),
|
|
41
|
+
location: dir,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
expect(parsed).to be_a(Lutaml::Xml::Schema::Xsd::Schema)
|
|
45
|
+
expect(parsed.imports.first.schema_path).to eq("b.xsd")
|
|
46
|
+
expect(parsed.import.first).to be_a(Lutaml::Xml::Schema::Xsd::Schema)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "keeps the namespace-less import unnamed" do
|
|
50
|
+
parsed = Lutaml::Xml::Schema::Xsd.parse(
|
|
51
|
+
<<~XSD,
|
|
52
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
53
|
+
<xs:import schemaLocation="c.xsd"/>
|
|
54
|
+
</xs:schema>
|
|
55
|
+
XSD
|
|
56
|
+
location: dir,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
expect(parsed.imports.first.namespace).to be_nil
|
|
60
|
+
end
|
|
61
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lutaml-model
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.147
|
|
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-10-
|
|
11
|
+
date: 2026-10-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|
|
@@ -1990,6 +1990,7 @@ files:
|
|
|
1990
1990
|
- spec/lutaml/xml/general_namespace_spec.rb
|
|
1991
1991
|
- spec/lutaml/xml/html_entities_spec.rb
|
|
1992
1992
|
- spec/lutaml/xml/indent_spec.rb
|
|
1993
|
+
- spec/lutaml/xml/leptris/plan_hydrator_ns_snapshot_spec.rb
|
|
1993
1994
|
- spec/lutaml/xml/leptris_string_encoding_spec.rb
|
|
1994
1995
|
- spec/lutaml/xml/line_ending_spec.rb
|
|
1995
1996
|
- spec/lutaml/xml/mapping_finalization_guard_spec.rb
|
|
@@ -2054,6 +2055,7 @@ files:
|
|
|
2054
2055
|
- spec/lutaml/xml/schema/xsd/errors/suggestion_spec.rb
|
|
2055
2056
|
- spec/lutaml/xml/schema/xsd/file_validation_result_spec.rb
|
|
2056
2057
|
- spec/lutaml/xml/schema/xsd/glob_spec.rb
|
|
2058
|
+
- spec/lutaml/xml/schema/xsd/import_without_namespace_spec.rb
|
|
2057
2059
|
- spec/lutaml/xml/schema/xsd/keyref_refer_spec.rb
|
|
2058
2060
|
- spec/lutaml/xml/schema/xsd/liquid_methods/attribute_and_group_spec.rb
|
|
2059
2061
|
- spec/lutaml/xml/schema/xsd/liquid_methods/complex_type_spec.rb
|