polyxml 0.30.4__tar.gz → 0.30.6__tar.gz

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.
Files changed (72) hide show
  1. {polyxml-0.30.4 → polyxml-0.30.6}/Cargo.lock +6 -6
  2. {polyxml-0.30.4 → polyxml-0.30.6}/Cargo.toml +1 -1
  3. {polyxml-0.30.4 → polyxml-0.30.6}/PKG-INFO +1 -1
  4. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/codegen/cpp/mod.rs +130 -7
  5. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/schema_parser/mod.rs +10 -0
  6. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_cpp_codegen.rs +58 -0
  7. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_schema_ir.rs +24 -0
  8. {polyxml-0.30.4 → polyxml-0.30.6}/pyproject.toml +1 -1
  9. {polyxml-0.30.4 → polyxml-0.30.6}/README.md +0 -0
  10. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/Cargo.toml +0 -0
  11. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/README.md +0 -0
  12. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
  13. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +0 -0
  14. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/benches/tag_dispatch.rs +0 -0
  15. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/codegen/csharp/mod.rs +0 -0
  16. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/codegen/go/mod.rs +0 -0
  17. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/codegen/java/codec.rs +0 -0
  18. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/codegen/java/mod.rs +0 -0
  19. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/codegen/java/models.rs +0 -0
  20. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/codegen/mod.rs +0 -0
  21. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/codegen/python/aot.rs +0 -0
  22. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/codegen/python/mod.rs +0 -0
  23. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/codegen/rust/mod.rs +0 -0
  24. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
  25. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/converters.rs +0 -0
  26. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/error.rs +0 -0
  27. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/ir/mod.rs +0 -0
  28. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
  29. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/json.rs +0 -0
  30. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/lib.rs +0 -0
  31. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/parser.rs +0 -0
  32. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/schema.rs +0 -0
  33. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/serializer.rs +0 -0
  34. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/transcoder.rs +0 -0
  35. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/src/value.rs +0 -0
  36. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/fixtures/lexical_union.xsd +0 -0
  37. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/fixtures/mixed_content.xsd +0 -0
  38. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/fixtures/ts_mixed_content_inheritance.xsd +0 -0
  39. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_adversarial_identifiers.rs +0 -0
  40. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_conformance.rs +0 -0
  41. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_core.rs +0 -0
  42. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
  43. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_go_codegen.rs +0 -0
  44. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
  45. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_json.rs +0 -0
  46. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_lexical_union_codegen.rs +0 -0
  47. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_mixed_content.rs +0 -0
  48. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_pattern_codegen.rs +0 -0
  49. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_python_codegen.rs +0 -0
  50. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
  51. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_rust_codegen.rs +0 -0
  52. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_schema_audit.rs +0 -0
  53. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_security.rs +0 -0
  54. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
  55. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
  56. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_unbounded_choice.rs +0 -0
  57. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-core/tests/test_xsi_type.rs +0 -0
  58. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-python/Cargo.toml +0 -0
  59. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-python/README.md +0 -0
  60. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-python/benches/aot_vs_dataclass.py +0 -0
  61. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-python/src/lib.rs +0 -0
  62. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-python/tests/test_conformance.py +0 -0
  63. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-python/tests/test_generated_models.py +0 -0
  64. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-python/tests/test_json.py +0 -0
  65. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-python/tests/test_mixed_content.py +0 -0
  66. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-python/tests/test_polyxml.py +0 -0
  67. {polyxml-0.30.4 → polyxml-0.30.6}/crates/polyxml-python/tests/test_xsi_type.py +0 -0
  68. {polyxml-0.30.4 → polyxml-0.30.6}/python/polyxml/AGENT_GUIDE.md +0 -0
  69. {polyxml-0.30.4 → polyxml-0.30.6}/python/polyxml/__init__.py +0 -0
  70. {polyxml-0.30.4 → polyxml-0.30.6}/python/polyxml/compat/__init__.py +0 -0
  71. {polyxml-0.30.4 → polyxml-0.30.6}/python/polyxml/compat/xsdata.py +0 -0
  72. {polyxml-0.30.4 → polyxml-0.30.6}/python/polyxml/py.typed +0 -0
@@ -608,7 +608,7 @@ dependencies = [
608
608
 
609
609
  [[package]]
610
610
  name = "polyxml"
611
- version = "0.30.4"
611
+ version = "0.30.6"
612
612
  dependencies = [
613
613
  "criterion",
614
614
  "heck",
@@ -629,14 +629,14 @@ dependencies = [
629
629
 
630
630
  [[package]]
631
631
  name = "polyxml-c"
632
- version = "0.30.4"
632
+ version = "0.30.6"
633
633
  dependencies = [
634
634
  "polyxml",
635
635
  ]
636
636
 
637
637
  [[package]]
638
638
  name = "polyxml-cli"
639
- version = "0.30.4"
639
+ version = "0.30.6"
640
640
  dependencies = [
641
641
  "clap",
642
642
  "glob",
@@ -650,7 +650,7 @@ dependencies = [
650
650
 
651
651
  [[package]]
652
652
  name = "polyxml-js"
653
- version = "0.30.4"
653
+ version = "0.30.6"
654
654
  dependencies = [
655
655
  "napi",
656
656
  "napi-build",
@@ -660,7 +660,7 @@ dependencies = [
660
660
 
661
661
  [[package]]
662
662
  name = "polyxml-python"
663
- version = "0.30.4"
663
+ version = "0.30.6"
664
664
  dependencies = [
665
665
  "lexical-core",
666
666
  "polyxml",
@@ -670,7 +670,7 @@ dependencies = [
670
670
 
671
671
  [[package]]
672
672
  name = "polyxml-wasm"
673
- version = "0.30.4"
673
+ version = "0.30.6"
674
674
  dependencies = [
675
675
  "polyxml",
676
676
  "quick-xml",
@@ -3,7 +3,7 @@ resolver = "2"
3
3
  members = ["crates/polyxml-core", "crates/polyxml-python"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.30.4"
6
+ version = "0.30.6"
7
7
  edition = "2021"
8
8
  rust-version = "1.80"
9
9
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polyxml
3
- Version: 0.30.4
3
+ Version: 0.30.6
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -674,15 +674,19 @@ concept XmlModel = requires(T a) {{
674
674
  }
675
675
  }
676
676
 
677
- // Topologically sort structs and unions (DAG order)
677
+ // Cut cyclic value dependencies through struct fields or union branches,
678
+ // then emit types in dependency order.
679
+ let mut prepared = ir.clone();
680
+ let sorted_qnames = self.order_with_forward_cuts(&mut prepared);
681
+
678
682
  for qname in sorted_qnames {
679
- if ir.is_external_type(&qname) {
683
+ if prepared.is_external_type(&qname) {
680
684
  continue;
681
685
  }
682
- if let Some(type_def) = ir.types.get(&qname) {
686
+ if let Some(type_def) = prepared.types.get(&qname) {
683
687
  match type_def {
684
688
  TypeDef::Union(u) => self.emit_union(out, u),
685
- TypeDef::Struct(s) => self.emit_struct(out, s, ir),
689
+ TypeDef::Struct(s) => self.emit_struct(out, s, &prepared),
686
690
  TypeDef::Simple(_) | TypeDef::Enum(_) => {}
687
691
  }
688
692
  }
@@ -1126,7 +1130,120 @@ concept XmlModel = requires(T a) {{
1126
1130
  }
1127
1131
  }
1128
1132
 
1129
- /// Topologically sort types (DAG) to ensure value types are declared before use.
1133
+ /// Box cyclic value edges until the C++ dependency graph can be ordered.
1134
+ fn order_with_forward_cuts(&self, ir: &mut SchemaIR) -> Vec<QName> {
1135
+ loop {
1136
+ let order = self.topological_sort_types(ir);
1137
+ let mut candidate: Option<(bool, QName, usize)> = None;
1138
+ for (owner, def) in &ir.types {
1139
+ let TypeDef::Struct(structure) = def else {
1140
+ continue;
1141
+ };
1142
+ for (index, field) in structure.fields.iter().enumerate() {
1143
+ if field.is_cycle_cut || field.cardinality.is_list() {
1144
+ continue;
1145
+ }
1146
+ let TypeRef::Named(target) = &field.type_ref else {
1147
+ continue;
1148
+ };
1149
+ if !matches!(ir.types.get(target), Some(TypeDef::Struct(_)))
1150
+ || !self.has_cpp_dependency_path(ir, target, owner, &mut HashSet::new())
1151
+ {
1152
+ continue;
1153
+ }
1154
+ let optional = field.cardinality.is_optional() || field.nillable;
1155
+ if candidate
1156
+ .as_ref()
1157
+ .is_none_or(|(was_optional, _, _)| optional && !was_optional)
1158
+ {
1159
+ candidate = Some((optional, owner.clone(), index));
1160
+ }
1161
+ }
1162
+ }
1163
+ let Some((_, owner, index)) = candidate else {
1164
+ let union_cut = ir.types.iter().find_map(|(owner, def)| {
1165
+ let TypeDef::Union(union) = def else {
1166
+ return None;
1167
+ };
1168
+ union
1169
+ .branches
1170
+ .iter()
1171
+ .enumerate()
1172
+ .find_map(|(index, branch)| {
1173
+ let TypeRef::Named(target) = &branch.type_ref else {
1174
+ return None;
1175
+ };
1176
+ (matches!(ir.types.get(target), Some(TypeDef::Struct(_)))
1177
+ && self.has_cpp_dependency_path(
1178
+ ir,
1179
+ target,
1180
+ owner,
1181
+ &mut HashSet::new(),
1182
+ ))
1183
+ .then(|| (owner.clone(), index))
1184
+ })
1185
+ });
1186
+ let Some((owner, index)) = union_cut else {
1187
+ return order;
1188
+ };
1189
+ if let Some(TypeDef::Union(union)) = ir.types.get_mut(&owner) {
1190
+ let branch = &mut union.branches[index];
1191
+ branch.type_ref = TypeRef::Boxed(Box::new(branch.type_ref.clone()));
1192
+ }
1193
+ continue;
1194
+ };
1195
+ if let Some(TypeDef::Struct(structure)) = ir.types.get_mut(&owner) {
1196
+ structure.fields[index].is_cycle_cut = true;
1197
+ }
1198
+ }
1199
+ }
1200
+
1201
+ fn has_cpp_dependency_path(
1202
+ &self,
1203
+ ir: &SchemaIR,
1204
+ current: &QName,
1205
+ goal: &QName,
1206
+ seen: &mut HashSet<QName>,
1207
+ ) -> bool {
1208
+ if current == goal {
1209
+ return true;
1210
+ }
1211
+ if !seen.insert(current.clone()) {
1212
+ return false;
1213
+ }
1214
+ let mut deps = Vec::new();
1215
+ match ir.types.get(current) {
1216
+ Some(TypeDef::Struct(structure)) => {
1217
+ if let Some(base) = &structure.base_type {
1218
+ deps.push(base.clone());
1219
+ }
1220
+ for field in &structure.fields {
1221
+ if !field.is_cycle_cut
1222
+ && !(field.cardinality.is_list()
1223
+ && matches!(&field.type_ref, TypeRef::Named(target) if matches!(ir.types.get(target), Some(TypeDef::Struct(_)))))
1224
+ {
1225
+ self.collect_type_dependencies(&field.type_ref, ir, current, &mut deps);
1226
+ }
1227
+ }
1228
+ }
1229
+ Some(TypeDef::Union(union)) => {
1230
+ for branch in &union.branches {
1231
+ if !matches!(&branch.type_ref, TypeRef::Boxed(inner) if matches!(inner.as_ref(), TypeRef::Named(target) if matches!(ir.types.get(target), Some(TypeDef::Struct(_)))))
1232
+ {
1233
+ self.collect_type_dependencies(&branch.type_ref, ir, current, &mut deps);
1234
+ }
1235
+ }
1236
+ }
1237
+ Some(TypeDef::Simple(simple)) => {
1238
+ self.collect_type_dependencies(&simple.base_type, ir, current, &mut deps);
1239
+ }
1240
+ _ => {}
1241
+ }
1242
+ deps.iter()
1243
+ .any(|dep| self.has_cpp_dependency_path(ir, dep, goal, seen))
1244
+ }
1245
+
1246
+ /// Put definitions before every value use that requires a complete type.
1130
1247
  fn topological_sort_types(&self, ir: &SchemaIR) -> Vec<QName> {
1131
1248
  let mut in_degree: HashMap<QName, usize> = HashMap::new();
1132
1249
  let mut adj: HashMap<QName, Vec<QName>> = HashMap::new();
@@ -1147,14 +1264,20 @@ concept XmlModel = requires(T a) {{
1147
1264
  }
1148
1265
  for f in &s.fields {
1149
1266
  // Skip cycle cuts because they use std::unique_ptr (only need forward declarations)
1150
- if !f.is_cycle_cut {
1267
+ if !f.is_cycle_cut
1268
+ && !(f.cardinality.is_list()
1269
+ && matches!(&f.type_ref, TypeRef::Named(target) if matches!(ir.types.get(target), Some(TypeDef::Struct(_)))))
1270
+ {
1151
1271
  self.collect_type_dependencies(&f.type_ref, ir, qname, &mut deps);
1152
1272
  }
1153
1273
  }
1154
1274
  }
1155
1275
  TypeDef::Union(u) => {
1156
1276
  for b in &u.branches {
1157
- self.collect_type_dependencies(&b.type_ref, ir, qname, &mut deps);
1277
+ if !matches!(&b.type_ref, TypeRef::Boxed(inner) if matches!(inner.as_ref(), TypeRef::Named(target) if matches!(ir.types.get(target), Some(TypeDef::Struct(_)))))
1278
+ {
1279
+ self.collect_type_dependencies(&b.type_ref, ir, qname, &mut deps);
1280
+ }
1158
1281
  }
1159
1282
  }
1160
1283
  TypeDef::Simple(s) => {
@@ -255,6 +255,11 @@ impl XsdParser {
255
255
  }
256
256
  }
257
257
  merge_ir(&mut ir, sub_ir);
258
+ } else {
259
+ return Err(SchemaError::Resolution(format!(
260
+ "included schema not found: {}",
261
+ inc_path.display()
262
+ )));
258
263
  }
259
264
  }
260
265
  }
@@ -366,6 +371,11 @@ impl XsdParser {
366
371
  }
367
372
  }
368
373
  merge_ir(&mut ir, sub_ir);
374
+ } else {
375
+ return Err(SchemaError::Resolution(format!(
376
+ "included schema not found: {}",
377
+ inc_path.display()
378
+ )));
369
379
  }
370
380
  }
371
381
  }
@@ -33,6 +33,64 @@ fn simple_aliases_follow_their_base_types() {
33
33
  );
34
34
  }
35
35
 
36
+ #[test]
37
+ fn mixed_content_mutual_cycle_compiles() {
38
+ use polyxml::schema_parser::XsdParser;
39
+ let schema = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:test" xmlns:t="urn:test">
40
+ <xs:complexType name="Cd"><xs:sequence><xs:element name="originalText" type="t:Ed" minOccurs="0"/></xs:sequence></xs:complexType>
41
+ <xs:complexType name="Ed" mixed="true"><xs:sequence><xs:element name="concept" type="t:Cd" minOccurs="0"/></xs:sequence></xs:complexType>
42
+ </xs:schema>"#;
43
+ let ir = XsdParser::new().parse_str(schema).unwrap();
44
+ let code = CppCodegen::new(CppOptions::default()).generate_header(&ir);
45
+ let dir = tempdir().unwrap();
46
+ let header = dir.path().join("model.hpp");
47
+ fs::write(&header, code).unwrap();
48
+ fs::write(
49
+ dir.path().join("main.cpp"),
50
+ "#include \"model.hpp\"\nint main() { return 0; }\n",
51
+ )
52
+ .unwrap();
53
+ let result = Command::new("g++")
54
+ .args(["-std=c++20", "-fsyntax-only", "-fmax-errors=3"])
55
+ .arg(dir.path().join("main.cpp"))
56
+ .output()
57
+ .unwrap();
58
+ assert!(
59
+ result.status.success(),
60
+ "{}",
61
+ String::from_utf8_lossy(&result.stderr)
62
+ );
63
+ }
64
+
65
+ #[test]
66
+ fn mixed_content_self_cycle_compiles() {
67
+ use polyxml::schema_parser::XsdParser;
68
+ let schema = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:test" xmlns:t="urn:test">
69
+ <xs:complexType name="Thumbnail" mixed="true"><xs:sequence>
70
+ <xs:element name="thumbnail" type="t:Thumbnail" minOccurs="0" maxOccurs="unbounded"/>
71
+ </xs:sequence></xs:complexType>
72
+ </xs:schema>"#;
73
+ let ir = XsdParser::new().parse_str(schema).unwrap();
74
+ let code = CppCodegen::new(CppOptions::default()).generate_header(&ir);
75
+ let dir = tempdir().unwrap();
76
+ fs::write(dir.path().join("model.hpp"), code).unwrap();
77
+ fs::write(
78
+ dir.path().join("main.cpp"),
79
+ "#include \"model.hpp\"\nint main() { return 0; }\n",
80
+ )
81
+ .unwrap();
82
+ let result = Command::new("g++")
83
+ .args(["-std=c++20", "-fsyntax-only", "-fmax-errors=3"])
84
+ .arg(dir.path().join("main.cpp"))
85
+ .output()
86
+ .unwrap();
87
+ assert!(
88
+ result.status.success(),
89
+ "{}",
90
+ String::from_utf8_lossy(&result.stderr)
91
+ );
92
+ }
93
+
36
94
  #[test]
37
95
  fn test_cpp_sanitization() {
38
96
  assert_eq!(to_cpp_field_name("class"), "class_");
@@ -6,6 +6,30 @@ use polyxml::ir::{
6
6
  TypeDef, TypeRef,
7
7
  };
8
8
  use polyxml::schema_parser::XsdParser;
9
+ use tempfile::tempdir;
10
+
11
+ #[test]
12
+ fn missing_included_schema_is_an_error() {
13
+ let dir = tempdir().unwrap();
14
+ for (name, include) in [
15
+ ("empty.xsd", r#"<xs:include schemaLocation="missing.xsd"/>"#),
16
+ (
17
+ "start.xsd",
18
+ r#"<xs:include schemaLocation="missing.xsd"></xs:include>"#,
19
+ ),
20
+ ] {
21
+ let path = dir.path().join(name);
22
+ std::fs::write(
23
+ &path,
24
+ format!(
25
+ r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">{include}</xs:schema>"#
26
+ ),
27
+ )
28
+ .unwrap();
29
+ let error = XsdParser::new().parse_file(&path).unwrap_err();
30
+ assert!(error.to_string().contains("missing.xsd"), "{error}");
31
+ }
32
+ }
9
33
 
10
34
  #[test]
11
35
  fn consumed_child_subtrees_do_not_swallow_following_types() {
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "polyxml"
7
- version = "0.30.4"
7
+ version = "0.30.6"
8
8
  description = "High-performance, polyglot XML data-binding engine built in Rust"
9
9
  authors = [
10
10
  { name = "Bailey Nguyen", email = "bailey.tan.nguyen@gmail.com" }
File without changes