polyxml 0.30.2__tar.gz → 0.30.3__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.
- {polyxml-0.30.2 → polyxml-0.30.3}/Cargo.lock +6 -6
- {polyxml-0.30.2 → polyxml-0.30.3}/Cargo.toml +1 -1
- {polyxml-0.30.2 → polyxml-0.30.3}/PKG-INFO +1 -1
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/codegen/cpp/mod.rs +7 -5
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/codegen/csharp/mod.rs +49 -12
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/codegen/mod.rs +10 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/codegen/python/mod.rs +16 -6
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/codegen/rust/mod.rs +12 -9
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/schema_parser/mod.rs +4 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_cpp_codegen.rs +22 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_csharp_codegen.rs +62 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_python_codegen.rs +12 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_rust_codegen.rs +16 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_schema_ir.rs +20 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/pyproject.toml +1 -1
- {polyxml-0.30.2 → polyxml-0.30.3}/README.md +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/Cargo.toml +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/README.md +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/benches/tag_dispatch.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/codegen/go/mod.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/codegen/java/codec.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/codegen/java/mod.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/codegen/java/models.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/codegen/python/aot.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/converters.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/error.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/ir/mod.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/json.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/lib.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/parser.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/schema.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/serializer.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/transcoder.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/src/value.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/fixtures/lexical_union.xsd +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/fixtures/mixed_content.xsd +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_adversarial_identifiers.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_conformance.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_core.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_go_codegen.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_json.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_lexical_union_codegen.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_mixed_content.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_pattern_codegen.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_schema_audit.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_security.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_unbounded_choice.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/tests/test_xsi_type.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-python/Cargo.toml +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-python/README.md +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-python/benches/aot_vs_dataclass.py +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-python/src/lib.rs +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-python/tests/test_conformance.py +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-python/tests/test_generated_models.py +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-python/tests/test_json.py +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-python/tests/test_mixed_content.py +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-python/tests/test_polyxml.py +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-python/tests/test_xsi_type.py +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/python/polyxml/AGENT_GUIDE.md +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/python/polyxml/__init__.py +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/python/polyxml/compat/__init__.py +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/python/polyxml/compat/xsdata.py +0 -0
- {polyxml-0.30.2 → polyxml-0.30.3}/python/polyxml/py.typed +0 -0
|
@@ -608,7 +608,7 @@ dependencies = [
|
|
|
608
608
|
|
|
609
609
|
[[package]]
|
|
610
610
|
name = "polyxml"
|
|
611
|
-
version = "0.30.
|
|
611
|
+
version = "0.30.3"
|
|
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.
|
|
632
|
+
version = "0.30.3"
|
|
633
633
|
dependencies = [
|
|
634
634
|
"polyxml",
|
|
635
635
|
]
|
|
636
636
|
|
|
637
637
|
[[package]]
|
|
638
638
|
name = "polyxml-cli"
|
|
639
|
-
version = "0.30.
|
|
639
|
+
version = "0.30.3"
|
|
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.
|
|
653
|
+
version = "0.30.3"
|
|
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.
|
|
663
|
+
version = "0.30.3"
|
|
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.
|
|
673
|
+
version = "0.30.3"
|
|
674
674
|
dependencies = [
|
|
675
675
|
"polyxml",
|
|
676
676
|
"quick-xml",
|
|
@@ -656,9 +656,13 @@ concept XmlModel = requires(T a) {{
|
|
|
656
656
|
}
|
|
657
657
|
|
|
658
658
|
fn emit_types(&self, out: &mut String, ir: &SchemaIR) {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
659
|
+
let sorted_qnames = self.topological_sort_types(ir);
|
|
660
|
+
|
|
661
|
+
// Aliases must follow their base aliases, which may sort later by name.
|
|
662
|
+
for qname in &sorted_qnames {
|
|
663
|
+
if let Some(TypeDef::Simple(simple)) =
|
|
664
|
+
ir.types.get(qname).filter(|_| !ir.is_external_type(qname))
|
|
665
|
+
{
|
|
662
666
|
self.emit_simple_type(out, simple, ir);
|
|
663
667
|
}
|
|
664
668
|
}
|
|
@@ -671,8 +675,6 @@ concept XmlModel = requires(T a) {{
|
|
|
671
675
|
}
|
|
672
676
|
|
|
673
677
|
// Topologically sort structs and unions (DAG order)
|
|
674
|
-
let sorted_qnames = self.topological_sort_types(ir);
|
|
675
|
-
|
|
676
678
|
for qname in sorted_qnames {
|
|
677
679
|
if ir.is_external_type(&qname) {
|
|
678
680
|
continue;
|
|
@@ -244,13 +244,34 @@ fn type_ident(q: &QName) -> String {
|
|
|
244
244
|
|
|
245
245
|
fn choice_variant_name(branch: &UnionBranch) -> String {
|
|
246
246
|
let name = to_csharp_type_name(&branch.variant_name);
|
|
247
|
-
if matches!(
|
|
247
|
+
if matches!(
|
|
248
|
+
name.as_str(),
|
|
249
|
+
"Value" | "Equals" | "GetHashCode" | "ToString"
|
|
250
|
+
) || matches!(&branch.type_ref, TypeRef::Named(qname) if type_ident(qname) == name)
|
|
251
|
+
{
|
|
248
252
|
format!("{name}Branch")
|
|
249
253
|
} else {
|
|
250
254
|
name
|
|
251
255
|
}
|
|
252
256
|
}
|
|
253
257
|
|
|
258
|
+
fn simple_value_target(base: &TypeRef, ir: &SchemaIR) -> String {
|
|
259
|
+
let mut target = "Value".to_string();
|
|
260
|
+
let mut current = base;
|
|
261
|
+
let mut seen = HashSet::new();
|
|
262
|
+
while let TypeRef::Named(qname) = current {
|
|
263
|
+
if !seen.insert(qname.clone()) {
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
let Some(TypeDef::Simple(simple)) = ir.types.get(qname) else {
|
|
267
|
+
break;
|
|
268
|
+
};
|
|
269
|
+
target.push_str(".Value");
|
|
270
|
+
current = &simple.base_type;
|
|
271
|
+
}
|
|
272
|
+
target
|
|
273
|
+
}
|
|
274
|
+
|
|
254
275
|
impl CSharpCodegen {
|
|
255
276
|
/// Creates a new C# code generator with the given configuration options.
|
|
256
277
|
pub fn new(options: CSharpOptions) -> Self {
|
|
@@ -315,7 +336,7 @@ impl CSharpCodegen {
|
|
|
315
336
|
if !simple.facets.patterns.is_empty() {
|
|
316
337
|
simple.base_type = super::primitive_base(&simple.base_type, ir).clone();
|
|
317
338
|
}
|
|
318
|
-
self.emit_simple(&mut out, &simple, indent);
|
|
339
|
+
self.emit_simple(&mut out, &simple, ir, indent);
|
|
319
340
|
}
|
|
320
341
|
}
|
|
321
342
|
|
|
@@ -510,8 +531,10 @@ impl CSharpCodegen {
|
|
|
510
531
|
writeln!(out, "{}}}\n", indent).unwrap();
|
|
511
532
|
}
|
|
512
533
|
|
|
513
|
-
fn emit_simple(&self, out: &mut String, s: &SimpleTypeDef, indent: &str) {
|
|
514
|
-
|
|
534
|
+
fn emit_simple(&self, out: &mut String, s: &SimpleTypeDef, ir: &SchemaIR, indent: &str) {
|
|
535
|
+
// Named simple types may be referenced by structs and choices even
|
|
536
|
+
// when they have no facets, so every one needs a declaration.
|
|
537
|
+
{
|
|
515
538
|
let type_name = type_ident(&s.qname);
|
|
516
539
|
let base_type = self.context.map_type_ref(&s.base_type);
|
|
517
540
|
|
|
@@ -550,7 +573,8 @@ impl CSharpCodegen {
|
|
|
550
573
|
.unwrap();
|
|
551
574
|
if self.options.emit_validation {
|
|
552
575
|
writeln!(out, "{} public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)\n{} {{", indent, indent).unwrap();
|
|
553
|
-
|
|
576
|
+
let value = simple_value_target(&s.base_type, ir);
|
|
577
|
+
self.emit_facet_checks(out, &s.facets, &value, &format!("{} ", indent));
|
|
554
578
|
writeln!(out, "{} yield break;\n{} }}", indent, indent).unwrap();
|
|
555
579
|
}
|
|
556
580
|
writeln!(out, "{}}}\n", indent).unwrap();
|
|
@@ -579,7 +603,8 @@ impl CSharpCodegen {
|
|
|
579
603
|
)
|
|
580
604
|
.unwrap();
|
|
581
605
|
writeln!(out, "{} {{", indent).unwrap();
|
|
582
|
-
|
|
606
|
+
let value = simple_value_target(&s.base_type, ir);
|
|
607
|
+
self.emit_facet_checks(out, &s.facets, &value, &format!("{} ", indent));
|
|
583
608
|
writeln!(out, "{} yield break;", indent).unwrap();
|
|
584
609
|
writeln!(out, "{} }}", indent).unwrap();
|
|
585
610
|
writeln!(out, "{}}}\n", indent).unwrap();
|
|
@@ -1076,12 +1101,24 @@ impl CSharpCodegen {
|
|
|
1076
1101
|
|
|
1077
1102
|
// Collect fields and parameters
|
|
1078
1103
|
if s.fields.is_empty() {
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1104
|
+
if self.options.emit_validation {
|
|
1105
|
+
writeln!(
|
|
1106
|
+
out,
|
|
1107
|
+
"{}public {} {}{}",
|
|
1108
|
+
indent, record_keyword, struct_name, implements_str
|
|
1109
|
+
)
|
|
1110
|
+
.unwrap();
|
|
1111
|
+
writeln!(out, "{}{{", indent).unwrap();
|
|
1112
|
+
self.emit_struct_validator(out, s, &prop_names, indent);
|
|
1113
|
+
writeln!(out, "{}}}", indent).unwrap();
|
|
1114
|
+
} else {
|
|
1115
|
+
writeln!(
|
|
1116
|
+
out,
|
|
1117
|
+
"{}public {} {}{};",
|
|
1118
|
+
indent, record_keyword, struct_name, implements_str
|
|
1119
|
+
)
|
|
1120
|
+
.unwrap();
|
|
1121
|
+
}
|
|
1085
1122
|
writeln!(out).unwrap();
|
|
1086
1123
|
return;
|
|
1087
1124
|
}
|
|
@@ -24,6 +24,16 @@ pub use python::{
|
|
|
24
24
|
pub use rust::{RustCodegen, RustOptions};
|
|
25
25
|
pub use typescript::{TypeScriptBackend, TypeScriptCodegen, TypeScriptOptions};
|
|
26
26
|
|
|
27
|
+
/// Prefix every physical XSD documentation line so embedded newlines cannot
|
|
28
|
+
/// escape a generated source comment.
|
|
29
|
+
pub(crate) fn write_documentation_lines(out: &mut String, prefix: &str, doc: &str) {
|
|
30
|
+
for line in doc.trim().lines() {
|
|
31
|
+
out.push_str(prefix);
|
|
32
|
+
out.push_str(line.trim_end_matches('\r'));
|
|
33
|
+
out.push('\n');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
use crate::ir::{FieldDef, PrimitiveType, QName, SchemaIR, StructDef, TypeRef};
|
|
28
38
|
|
|
29
39
|
#[derive(Debug, Error)]
|
|
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
|
|
6
6
|
|
|
7
7
|
use crate::codegen::{
|
|
8
8
|
build_type_name_map, lookup_type_name, normalize_symbol_name, sanitize_keyword,
|
|
9
|
-
set_type_name_map, LanguageContext,
|
|
9
|
+
set_type_name_map, write_documentation_lines, LanguageContext,
|
|
10
10
|
};
|
|
11
11
|
use crate::ir::{
|
|
12
12
|
EnumDef, FieldDef, FieldKind, PrimitiveType, QName, RestrictionFacets, SchemaIR, SimpleTypeDef,
|
|
@@ -32,6 +32,15 @@ const PATTERN_VALIDATOR_HELPER: &str = r#"def _polyxml_patterns(*patterns: str):
|
|
|
32
32
|
pub mod aot;
|
|
33
33
|
pub use aot::{PythonAotCodegen, PythonAotCrate, PythonAotOptions};
|
|
34
34
|
|
|
35
|
+
fn write_python_docstring(out: &mut String, indent: &str, doc: &str) {
|
|
36
|
+
let escaped = doc
|
|
37
|
+
.trim()
|
|
38
|
+
.replace('\\', "\\\\")
|
|
39
|
+
.replace("\"\"\"", "\\\"\\\"\\\"")
|
|
40
|
+
.replace('\r', "");
|
|
41
|
+
let _ = writeln!(out, "{indent}\"\"\"{escaped}\"\"\"");
|
|
42
|
+
}
|
|
43
|
+
|
|
35
44
|
/// Target backend for Python code emission.
|
|
36
45
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
|
|
37
46
|
pub enum PythonBackend {
|
|
@@ -444,7 +453,7 @@ impl PythonCodegen {
|
|
|
444
453
|
let base_type = self.context.map_type_ref(&s.base_type);
|
|
445
454
|
|
|
446
455
|
if let Some(ref doc) = s.documentation {
|
|
447
|
-
|
|
456
|
+
write_documentation_lines(out, "# ", doc);
|
|
448
457
|
}
|
|
449
458
|
|
|
450
459
|
if self.options.backend == PythonBackend::Pydantic && !s.facets.is_empty() {
|
|
@@ -492,7 +501,7 @@ impl PythonCodegen {
|
|
|
492
501
|
let _ = writeln!(out, "class {}(StrEnum):", enum_name);
|
|
493
502
|
|
|
494
503
|
if let Some(ref doc) = e.documentation {
|
|
495
|
-
|
|
504
|
+
write_python_docstring(out, " ", doc);
|
|
496
505
|
}
|
|
497
506
|
|
|
498
507
|
if e.variants.is_empty() {
|
|
@@ -549,7 +558,7 @@ impl PythonCodegen {
|
|
|
549
558
|
}
|
|
550
559
|
|
|
551
560
|
if let Some(ref doc) = u.documentation {
|
|
552
|
-
|
|
561
|
+
write_documentation_lines(out, "# ", doc);
|
|
553
562
|
}
|
|
554
563
|
|
|
555
564
|
if u.branches.is_empty() {
|
|
@@ -613,7 +622,8 @@ impl PythonCodegen {
|
|
|
613
622
|
let mut has_body = false;
|
|
614
623
|
|
|
615
624
|
if let Some(ref doc) = s.documentation {
|
|
616
|
-
|
|
625
|
+
write_python_docstring(out, " ", doc);
|
|
626
|
+
out.push('\n');
|
|
617
627
|
has_body = true;
|
|
618
628
|
}
|
|
619
629
|
|
|
@@ -763,7 +773,7 @@ impl PythonCodegen {
|
|
|
763
773
|
};
|
|
764
774
|
|
|
765
775
|
if let Some(ref doc) = field.documentation {
|
|
766
|
-
|
|
776
|
+
write_documentation_lines(out, " # ", doc);
|
|
767
777
|
}
|
|
768
778
|
|
|
769
779
|
let _ = writeln!(out, " {}: {} = {}", py_name, field_type, field_call);
|
|
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
|
|
6
6
|
|
|
7
7
|
use crate::codegen::{
|
|
8
8
|
build_type_name_map, flatten_fields, lookup_type_name, primitive_base, sanitize_keyword,
|
|
9
|
-
set_type_name_map, LanguageContext,
|
|
9
|
+
set_type_name_map, write_documentation_lines, LanguageContext,
|
|
10
10
|
};
|
|
11
11
|
use crate::ir::{
|
|
12
12
|
EnumDef, FieldDef, FieldKind, PrimitiveType, QName, SchemaIR, SimpleTypeDef, StructDef,
|
|
@@ -279,7 +279,10 @@ impl RustCodegen {
|
|
|
279
279
|
self.emit_pymodule(&mut out, ir, &sorted_types);
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
|
|
282
|
+
// A field may use a raw identifier such as `r#type`. Local codec
|
|
283
|
+
// variables have a `var_` prefix, so the raw marker is neither needed
|
|
284
|
+
// nor valid there (`var_r#type` is not a Rust identifier).
|
|
285
|
+
out.replace("var_r#", "var_")
|
|
283
286
|
}
|
|
284
287
|
|
|
285
288
|
/// Fixed-point analysis determining which types in SchemaIR require a lifetime parameter `<'a>`.
|
|
@@ -456,7 +459,7 @@ impl RustCodegen {
|
|
|
456
459
|
let needs_lifetime = types_with_lifetime.contains(&s.qname);
|
|
457
460
|
|
|
458
461
|
if let Some(ref doc) = s.documentation {
|
|
459
|
-
|
|
462
|
+
write_documentation_lines(out, "/// ", doc);
|
|
460
463
|
}
|
|
461
464
|
|
|
462
465
|
let base_type = self.format_rust_type_ref(&s.base_type, types_with_lifetime);
|
|
@@ -482,7 +485,7 @@ impl RustCodegen {
|
|
|
482
485
|
let enum_name = type_ident(&e.qname);
|
|
483
486
|
|
|
484
487
|
if let Some(ref doc) = e.documentation {
|
|
485
|
-
|
|
488
|
+
write_documentation_lines(out, "/// ", doc);
|
|
486
489
|
}
|
|
487
490
|
|
|
488
491
|
let mut derives = vec!["Debug", "Clone", "Copy", "PartialEq", "Eq", "Hash"];
|
|
@@ -520,7 +523,7 @@ impl RustCodegen {
|
|
|
520
523
|
seen_variants.insert(var_id.clone());
|
|
521
524
|
|
|
522
525
|
if let Some(ref doc) = variant.documentation {
|
|
523
|
-
|
|
526
|
+
write_documentation_lines(out, " /// ", doc);
|
|
524
527
|
}
|
|
525
528
|
if self.options.derive_serde {
|
|
526
529
|
let _ = writeln!(out, " #[serde(rename = \"{}\")]", variant.value);
|
|
@@ -595,7 +598,7 @@ impl RustCodegen {
|
|
|
595
598
|
let needs_lifetime = types_with_lifetime.contains(&u.qname);
|
|
596
599
|
|
|
597
600
|
if let Some(ref doc) = u.documentation {
|
|
598
|
-
|
|
601
|
+
write_documentation_lines(out, "/// ", doc);
|
|
599
602
|
}
|
|
600
603
|
|
|
601
604
|
let mut derives = vec!["Debug", "Clone", "PartialEq"];
|
|
@@ -640,7 +643,7 @@ impl RustCodegen {
|
|
|
640
643
|
let branch_type = self.format_rust_type_ref(&branch.type_ref, types_with_lifetime);
|
|
641
644
|
|
|
642
645
|
if let Some(ref doc) = branch.documentation {
|
|
643
|
-
|
|
646
|
+
write_documentation_lines(out, " /// ", doc);
|
|
644
647
|
}
|
|
645
648
|
if self.options.derive_serde && !u.is_lexical() {
|
|
646
649
|
let _ = writeln!(out, " #[serde(rename = \"{}\")]", branch.xml_name);
|
|
@@ -685,7 +688,7 @@ impl RustCodegen {
|
|
|
685
688
|
let needs_lifetime = types_with_lifetime.contains(&s.qname);
|
|
686
689
|
|
|
687
690
|
if let Some(ref doc) = s.documentation {
|
|
688
|
-
|
|
691
|
+
write_documentation_lines(out, "/// ", doc);
|
|
689
692
|
}
|
|
690
693
|
|
|
691
694
|
let mut derives = vec!["Debug", "Clone", "PartialEq"];
|
|
@@ -763,7 +766,7 @@ impl RustCodegen {
|
|
|
763
766
|
has_boxed: bool,
|
|
764
767
|
) {
|
|
765
768
|
if let Some(ref doc) = field.documentation {
|
|
766
|
-
|
|
769
|
+
write_documentation_lines(out, " /// ", doc);
|
|
767
770
|
}
|
|
768
771
|
|
|
769
772
|
let is_list = field.cardinality.is_list() || field.type_ref.is_list();
|
|
@@ -504,6 +504,7 @@ impl XsdParser {
|
|
|
504
504
|
.push((fields.len(), resolve_qname(&r, target_ns, prefixes)));
|
|
505
505
|
}
|
|
506
506
|
skip_subtree(reader)?;
|
|
507
|
+
depth -= 1;
|
|
507
508
|
}
|
|
508
509
|
"sequence" | "all" => {
|
|
509
510
|
let is_unbounded = get_attr_value(e, "maxOccurs")
|
|
@@ -560,6 +561,7 @@ impl XsdParser {
|
|
|
560
561
|
self.consume_inline_element_type(
|
|
561
562
|
reader, e, target_ns, prefixes, &name, &mut field, ir,
|
|
562
563
|
)?;
|
|
564
|
+
depth -= 1;
|
|
563
565
|
if in_choice {
|
|
564
566
|
if let Some(frame) = compositor_stack.last_mut() {
|
|
565
567
|
if frame.kind == CompositorKind::Choice {
|
|
@@ -869,6 +871,7 @@ impl XsdParser {
|
|
|
869
871
|
self.consume_inline_element_type(
|
|
870
872
|
reader, e, target_ns, prefixes, "", &mut field, ir,
|
|
871
873
|
)?;
|
|
874
|
+
depth -= 1;
|
|
872
875
|
def.fields.push(field);
|
|
873
876
|
}
|
|
874
877
|
}
|
|
@@ -880,6 +883,7 @@ impl XsdParser {
|
|
|
880
883
|
));
|
|
881
884
|
}
|
|
882
885
|
skip_subtree(reader)?;
|
|
886
|
+
depth -= 1;
|
|
883
887
|
}
|
|
884
888
|
"any" => def.fields.push(parse_any_field(e)),
|
|
885
889
|
_ => {}
|
|
@@ -11,6 +11,28 @@ use polyxml::ir::{
|
|
|
11
11
|
SchemaIR, StructDef, TypeDef, TypeRef, UnionBranch, UnionDef,
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
#[test]
|
|
15
|
+
fn simple_aliases_follow_their_base_types() {
|
|
16
|
+
let mut ir = SchemaIR::new().with_target_namespace("urn:test");
|
|
17
|
+
ir.add_type(TypeDef::Simple(Box::new(polyxml::ir::SimpleTypeDef {
|
|
18
|
+
qname: QName::new(Some("urn:test"), "AreaType"),
|
|
19
|
+
base_type: TypeRef::Named(QName::new(Some("urn:test"), "DoubleNonNegativeType")),
|
|
20
|
+
facets: RestrictionFacets::default(),
|
|
21
|
+
documentation: None,
|
|
22
|
+
})));
|
|
23
|
+
ir.add_type(TypeDef::Simple(Box::new(polyxml::ir::SimpleTypeDef {
|
|
24
|
+
qname: QName::new(Some("urn:test"), "DoubleNonNegativeType"),
|
|
25
|
+
base_type: TypeRef::Primitive(PrimitiveType::Double),
|
|
26
|
+
facets: RestrictionFacets::default(),
|
|
27
|
+
documentation: None,
|
|
28
|
+
})));
|
|
29
|
+
let code = CppCodegen::new(CppOptions::default()).generate_header(&ir);
|
|
30
|
+
assert!(
|
|
31
|
+
code.find("using DoubleNonNegativeType =").unwrap()
|
|
32
|
+
< code.find("using AreaType =").unwrap()
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
14
36
|
#[test]
|
|
15
37
|
fn test_cpp_sanitization() {
|
|
16
38
|
assert_eq!(to_cpp_field_name("class"), "class_");
|
|
@@ -12,6 +12,68 @@ use polyxml::ir::{
|
|
|
12
12
|
use std::sync::Mutex;
|
|
13
13
|
use tempfile::tempdir;
|
|
14
14
|
|
|
15
|
+
#[test]
|
|
16
|
+
fn emits_unrestricted_simple_types_and_validates_empty_records() {
|
|
17
|
+
let mut ir = SchemaIR::new().with_target_namespace("urn:test");
|
|
18
|
+
ir.add_type(TypeDef::Simple(Box::new(polyxml::ir::SimpleTypeDef {
|
|
19
|
+
qname: QName::new(Some("urn:test"), "DistanceType"),
|
|
20
|
+
base_type: TypeRef::Primitive(PrimitiveType::Double),
|
|
21
|
+
facets: RestrictionFacets::default(),
|
|
22
|
+
documentation: None,
|
|
23
|
+
})));
|
|
24
|
+
ir.add_type(TypeDef::Simple(Box::new(polyxml::ir::SimpleTypeDef {
|
|
25
|
+
qname: QName::new(Some("urn:test"), "PositiveDistanceType"),
|
|
26
|
+
base_type: TypeRef::Named(QName::new(Some("urn:test"), "DistanceType")),
|
|
27
|
+
facets: RestrictionFacets {
|
|
28
|
+
min_inclusive: Some("0".into()),
|
|
29
|
+
..Default::default()
|
|
30
|
+
},
|
|
31
|
+
documentation: None,
|
|
32
|
+
})));
|
|
33
|
+
ir.add_type(TypeDef::Struct(StructDef {
|
|
34
|
+
qname: QName::new(Some("urn:test"), "EmptyType"),
|
|
35
|
+
base_type: None,
|
|
36
|
+
is_abstract: false,
|
|
37
|
+
is_mixed: false,
|
|
38
|
+
fields: vec![],
|
|
39
|
+
documentation: None,
|
|
40
|
+
}));
|
|
41
|
+
let code = CSharpCodegen::new(CSharpOptions::default()).generate_module(&ir);
|
|
42
|
+
assert!(code.contains("record DistanceType("));
|
|
43
|
+
assert!(code.contains("if (Value.Value < 0)"));
|
|
44
|
+
assert!(code.contains("record EmptyType : IValidatableObject"));
|
|
45
|
+
assert!(code.contains("IEnumerable<ValidationResult> Validate"));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#[test]
|
|
49
|
+
fn choice_variants_avoid_record_member_names() {
|
|
50
|
+
let mut ir = SchemaIR::new().with_target_namespace("urn:test");
|
|
51
|
+
ir.add_type(TypeDef::Union(UnionDef {
|
|
52
|
+
qname: QName::new(Some("urn:test"), "ParameterValueType"),
|
|
53
|
+
branches: vec![
|
|
54
|
+
UnionBranch {
|
|
55
|
+
variant_name: "Value".into(),
|
|
56
|
+
xml_name: "Value".into(),
|
|
57
|
+
namespace: None,
|
|
58
|
+
type_ref: TypeRef::Primitive(PrimitiveType::String),
|
|
59
|
+
documentation: None,
|
|
60
|
+
},
|
|
61
|
+
UnionBranch {
|
|
62
|
+
variant_name: "Equals".into(),
|
|
63
|
+
xml_name: "Equals".into(),
|
|
64
|
+
namespace: None,
|
|
65
|
+
type_ref: TypeRef::Primitive(PrimitiveType::Int),
|
|
66
|
+
documentation: None,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
documentation: None,
|
|
70
|
+
}));
|
|
71
|
+
let code = CSharpCodegen::new(CSharpOptions::default()).generate_module(&ir);
|
|
72
|
+
assert!(code.contains("record ValueBranch("));
|
|
73
|
+
assert!(code.contains("record EqualsBranch("));
|
|
74
|
+
assert!(code.contains("XmlElement(\"Value\")"));
|
|
75
|
+
}
|
|
76
|
+
|
|
15
77
|
static DOTNET_LOCK: Mutex<()> = Mutex::new(());
|
|
16
78
|
|
|
17
79
|
fn dotnet_command() -> Command {
|
|
@@ -5,6 +5,18 @@ use polyxml::ir::{
|
|
|
5
5
|
Cardinality, EnumDef, EnumValue, FieldDef, FieldKind, OccursLimit, PrimitiveType, QName,
|
|
6
6
|
RestrictionFacets, SchemaIR, SimpleTypeDef, StructDef, TypeDef, TypeRef, UnionBranch, UnionDef,
|
|
7
7
|
};
|
|
8
|
+
use polyxml::schema_parser::XsdParser;
|
|
9
|
+
|
|
10
|
+
#[test]
|
|
11
|
+
fn multiline_xsd_documentation_stays_inside_python_comments() {
|
|
12
|
+
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:test">
|
|
13
|
+
<xs:simpleType name="Code"><xs:annotation><xs:documentation>First line
|
|
14
|
+
Second line</xs:documentation></xs:annotation><xs:restriction base="xs:string"/></xs:simpleType>
|
|
15
|
+
</xs:schema>"#;
|
|
16
|
+
let ir = XsdParser::new().parse_str(xsd).unwrap();
|
|
17
|
+
let code = PythonCodegen::new(PythonOptions::default()).generate_module(&ir);
|
|
18
|
+
assert!(code.contains("# First line\n# Second line"));
|
|
19
|
+
}
|
|
8
20
|
|
|
9
21
|
#[test]
|
|
10
22
|
fn test_identifier_sanitization() {
|
|
@@ -35,6 +35,22 @@ fn test_rust_identifier_sanitization() {
|
|
|
35
35
|
assert_eq!(to_rust_field_identifier("normalField"), "normal_field");
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
#[test]
|
|
39
|
+
fn multiline_docs_and_raw_field_names_are_valid_source() {
|
|
40
|
+
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:test">
|
|
41
|
+
<xs:complexType name="Sample"><xs:annotation><xs:documentation>First line
|
|
42
|
+
Second line</xs:documentation></xs:annotation><xs:sequence>
|
|
43
|
+
<xs:element name="type" type="xs:string"/>
|
|
44
|
+
</xs:sequence></xs:complexType>
|
|
45
|
+
</xs:schema>"#;
|
|
46
|
+
let ir = XsdParser::new().parse_str(xsd).unwrap();
|
|
47
|
+
let code = RustCodegen::new(RustOptions::default()).generate_module(&ir);
|
|
48
|
+
assert!(code.contains("/// First line\n/// Second line"));
|
|
49
|
+
assert!(code.contains("pub r#type:"));
|
|
50
|
+
assert!(code.contains("var_type"));
|
|
51
|
+
assert!(!code.contains("var_r#"));
|
|
52
|
+
}
|
|
53
|
+
|
|
38
54
|
#[test]
|
|
39
55
|
fn test_rust_zero_copy_codegen() {
|
|
40
56
|
let mut ir = SchemaIR::new().with_target_namespace("https://example.com/crm");
|
|
@@ -7,6 +7,26 @@ use polyxml::ir::{
|
|
|
7
7
|
};
|
|
8
8
|
use polyxml::schema_parser::XsdParser;
|
|
9
9
|
|
|
10
|
+
#[test]
|
|
11
|
+
fn consumed_child_subtrees_do_not_swallow_following_types() {
|
|
12
|
+
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:test">
|
|
13
|
+
<xs:complexType name="First"><xs:sequence>
|
|
14
|
+
<xs:element name="nested"><xs:complexType><xs:sequence><xs:element name="value" type="xs:string"/></xs:sequence></xs:complexType></xs:element>
|
|
15
|
+
<xs:group ref="missing"><xs:annotation><xs:documentation>ignored</xs:documentation></xs:annotation></xs:group>
|
|
16
|
+
</xs:sequence></xs:complexType>
|
|
17
|
+
<xs:complexType name="Second"><xs:sequence><xs:element name="other" type="xs:string"/></xs:sequence></xs:complexType>
|
|
18
|
+
</xs:schema>"#;
|
|
19
|
+
let ir = XsdParser::new().parse_str(xsd).unwrap();
|
|
20
|
+
let first = match &ir.types[&QName::new(Some("urn:test"), "First")] {
|
|
21
|
+
TypeDef::Struct(value) => value,
|
|
22
|
+
other => panic!("expected struct: {other:?}"),
|
|
23
|
+
};
|
|
24
|
+
assert_eq!(first.fields.len(), 1);
|
|
25
|
+
assert!(ir
|
|
26
|
+
.types
|
|
27
|
+
.contains_key(&QName::new(Some("urn:test"), "Second")));
|
|
28
|
+
}
|
|
29
|
+
|
|
10
30
|
#[test]
|
|
11
31
|
fn test_parse_lexical_union_member_types_and_inline_members() {
|
|
12
32
|
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="urn:test" targetNamespace="urn:test">
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polyxml-0.30.2 → polyxml-0.30.3}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|