polyxml 0.27.0__tar.gz → 0.28.0__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.27.0 → polyxml-0.28.0}/Cargo.lock +7 -6
- {polyxml-0.27.0 → polyxml-0.28.0}/Cargo.toml +1 -1
- {polyxml-0.27.0 → polyxml-0.28.0}/PKG-INFO +1 -1
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/Cargo.toml +1 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/codegen/csharp/mod.rs +197 -6
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/codegen/go/mod.rs +189 -13
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/codegen/java/codec.rs +33 -19
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/codegen/java/mod.rs +2 -2
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/codegen/python/mod.rs +21 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/codegen/rust/mod.rs +140 -4
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/codegen/typescript/mod.rs +48 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/converters.rs +102 -1
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/ir/mod.rs +12 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/schema.rs +30 -2
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/schema_parser/mod.rs +107 -3
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/serializer.rs +8 -1
- polyxml-0.28.0/crates/polyxml-core/tests/fixtures/lexical_union.xsd +38 -0
- polyxml-0.28.0/crates/polyxml-core/tests/test_lexical_union_codegen.rs +107 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_schema_ir.rs +32 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-python/src/lib.rs +60 -3
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-python/tests/test_polyxml.py +36 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/pyproject.toml +1 -1
- {polyxml-0.27.0 → polyxml-0.28.0}/README.md +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/README.md +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/benches/tag_dispatch.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/codegen/cpp/mod.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/codegen/java/models.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/codegen/mod.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/codegen/python/aot.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/error.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/json.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/lib.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/parser.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/transcoder.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/src/value.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_adversarial_identifiers.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_conformance.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_core.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_go_codegen.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_json.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_pattern_codegen.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_python_codegen.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_rust_codegen.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_schema_audit.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_security.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_unbounded_choice.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-core/tests/test_xsi_type.rs +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-python/Cargo.toml +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-python/README.md +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-python/benches/aot_vs_dataclass.py +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-python/tests/test_conformance.py +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-python/tests/test_generated_models.py +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-python/tests/test_json.py +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/crates/polyxml-python/tests/test_xsi_type.py +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/python/polyxml/AGENT_GUIDE.md +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/python/polyxml/__init__.py +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/python/polyxml/compat/__init__.py +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/python/polyxml/compat/xsdata.py +0 -0
- {polyxml-0.27.0 → polyxml-0.28.0}/python/polyxml/py.typed +0 -0
|
@@ -608,7 +608,7 @@ dependencies = [
|
|
|
608
608
|
|
|
609
609
|
[[package]]
|
|
610
610
|
name = "polyxml"
|
|
611
|
-
version = "0.
|
|
611
|
+
version = "0.28.0"
|
|
612
612
|
dependencies = [
|
|
613
613
|
"criterion",
|
|
614
614
|
"heck",
|
|
@@ -619,6 +619,7 @@ dependencies = [
|
|
|
619
619
|
"phf_codegen",
|
|
620
620
|
"pretty_assertions",
|
|
621
621
|
"quick-xml",
|
|
622
|
+
"regex",
|
|
622
623
|
"serde",
|
|
623
624
|
"serde_json",
|
|
624
625
|
"smallvec",
|
|
@@ -628,14 +629,14 @@ dependencies = [
|
|
|
628
629
|
|
|
629
630
|
[[package]]
|
|
630
631
|
name = "polyxml-c"
|
|
631
|
-
version = "0.
|
|
632
|
+
version = "0.28.0"
|
|
632
633
|
dependencies = [
|
|
633
634
|
"polyxml",
|
|
634
635
|
]
|
|
635
636
|
|
|
636
637
|
[[package]]
|
|
637
638
|
name = "polyxml-cli"
|
|
638
|
-
version = "0.
|
|
639
|
+
version = "0.28.0"
|
|
639
640
|
dependencies = [
|
|
640
641
|
"clap",
|
|
641
642
|
"glob",
|
|
@@ -649,7 +650,7 @@ dependencies = [
|
|
|
649
650
|
|
|
650
651
|
[[package]]
|
|
651
652
|
name = "polyxml-js"
|
|
652
|
-
version = "0.
|
|
653
|
+
version = "0.28.0"
|
|
653
654
|
dependencies = [
|
|
654
655
|
"napi",
|
|
655
656
|
"napi-build",
|
|
@@ -659,7 +660,7 @@ dependencies = [
|
|
|
659
660
|
|
|
660
661
|
[[package]]
|
|
661
662
|
name = "polyxml-python"
|
|
662
|
-
version = "0.
|
|
663
|
+
version = "0.28.0"
|
|
663
664
|
dependencies = [
|
|
664
665
|
"lexical-core",
|
|
665
666
|
"polyxml",
|
|
@@ -669,7 +670,7 @@ dependencies = [
|
|
|
669
670
|
|
|
670
671
|
[[package]]
|
|
671
672
|
name = "polyxml-wasm"
|
|
672
|
-
version = "0.
|
|
673
|
+
version = "0.28.0"
|
|
673
674
|
dependencies = [
|
|
674
675
|
"polyxml",
|
|
675
676
|
"quick-xml",
|
|
@@ -313,7 +313,7 @@ impl CSharpCodegen {
|
|
|
313
313
|
// Emit Unions (Choices)
|
|
314
314
|
for def in ir.types.values() {
|
|
315
315
|
if let TypeDef::Union(u) = def {
|
|
316
|
-
self.emit_union(&mut out, u, indent);
|
|
316
|
+
self.emit_union(&mut out, u, ir, indent);
|
|
317
317
|
}
|
|
318
318
|
}
|
|
319
319
|
|
|
@@ -577,14 +577,14 @@ impl CSharpCodegen {
|
|
|
577
577
|
}
|
|
578
578
|
}
|
|
579
579
|
|
|
580
|
-
fn emit_union(&self, out: &mut String, u: &UnionDef, indent: &str) {
|
|
580
|
+
fn emit_union(&self, out: &mut String, u: &UnionDef, ir: &SchemaIR, indent: &str) {
|
|
581
581
|
let choice_name = type_ident(&u.qname);
|
|
582
582
|
if let Some(ref doc) = u.documentation {
|
|
583
583
|
self.emit_docstring(out, doc, indent);
|
|
584
584
|
}
|
|
585
585
|
|
|
586
|
-
// XmlInclude attributes for polymorphism
|
|
587
|
-
if self.options.emit_xml_attributes {
|
|
586
|
+
// XmlInclude attributes for element-choice polymorphism.
|
|
587
|
+
if self.options.emit_xml_attributes && !u.is_lexical() {
|
|
588
588
|
for branch in &u.branches {
|
|
589
589
|
let variant_name = to_csharp_type_name(&branch.variant_name);
|
|
590
590
|
writeln!(
|
|
@@ -632,10 +632,10 @@ impl CSharpCodegen {
|
|
|
632
632
|
}
|
|
633
633
|
|
|
634
634
|
let mut branch_attrs = Vec::new();
|
|
635
|
-
if self.options.emit_xml_attributes {
|
|
635
|
+
if self.options.emit_xml_attributes && !u.is_lexical() {
|
|
636
636
|
branch_attrs.push(format!("XmlElement(\"{}\")", branch.xml_name));
|
|
637
637
|
}
|
|
638
|
-
if self.options.emit_json_attributes {
|
|
638
|
+
if self.options.emit_json_attributes && !u.is_lexical() {
|
|
639
639
|
branch_attrs.push(format!("JsonPropertyName(\"{}\")", branch.xml_name));
|
|
640
640
|
}
|
|
641
641
|
let xml_attr = if branch_attrs.is_empty() {
|
|
@@ -679,9 +679,129 @@ impl CSharpCodegen {
|
|
|
679
679
|
writeln!(out).unwrap();
|
|
680
680
|
}
|
|
681
681
|
|
|
682
|
+
if u.is_lexical() {
|
|
683
|
+
self.emit_lexical_union_helpers(out, u, ir, indent);
|
|
684
|
+
}
|
|
682
685
|
writeln!(out, "{}}}\n", indent).unwrap();
|
|
683
686
|
}
|
|
684
687
|
|
|
688
|
+
fn emit_lexical_union_helpers(
|
|
689
|
+
&self,
|
|
690
|
+
out: &mut String,
|
|
691
|
+
u: &UnionDef,
|
|
692
|
+
ir: &SchemaIR,
|
|
693
|
+
indent: &str,
|
|
694
|
+
) {
|
|
695
|
+
let name = type_ident(&u.qname);
|
|
696
|
+
let _ = writeln!(
|
|
697
|
+
out,
|
|
698
|
+
"{} public static {} Parse(string text)",
|
|
699
|
+
indent, name
|
|
700
|
+
);
|
|
701
|
+
let _ = writeln!(out, "{} {{", indent);
|
|
702
|
+
let _ = writeln!(out, "{} var value = text.Trim();", indent);
|
|
703
|
+
for (idx, branch) in u.branches.iter().enumerate() {
|
|
704
|
+
let variant = to_csharp_type_name(&branch.variant_name);
|
|
705
|
+
let mapped = self.context.map_type_ref(&branch.type_ref);
|
|
706
|
+
if let TypeRef::Named(qname) = &branch.type_ref {
|
|
707
|
+
if let Some(TypeDef::Enum(def)) = ir.types.get(qname) {
|
|
708
|
+
for item in &def.variants {
|
|
709
|
+
let item_name = to_csharp_variant_name(&item.name);
|
|
710
|
+
let _ = writeln!(
|
|
711
|
+
out,
|
|
712
|
+
"{} if (value == {:?}) return new {}({}.{});",
|
|
713
|
+
indent, item.value, variant, mapped, item_name
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
let simple = match &branch.type_ref {
|
|
720
|
+
TypeRef::Named(qname) => ir.types.get(qname).and_then(|def| match def {
|
|
721
|
+
TypeDef::Simple(s) => Some(s.as_ref()),
|
|
722
|
+
_ => None,
|
|
723
|
+
}),
|
|
724
|
+
_ => None,
|
|
725
|
+
};
|
|
726
|
+
let base = super::primitive_base(&branch.type_ref, ir);
|
|
727
|
+
let base_name = self.context.map_type_ref(base);
|
|
728
|
+
let wrap = if simple.is_some() {
|
|
729
|
+
format!("new {}(candidate{})", mapped, idx)
|
|
730
|
+
} else {
|
|
731
|
+
format!("candidate{}", idx)
|
|
732
|
+
};
|
|
733
|
+
if base_name == "string" {
|
|
734
|
+
if let Some(simple) = simple.filter(|s| !s.facets.patterns.is_empty()) {
|
|
735
|
+
let checks = simple
|
|
736
|
+
.facets
|
|
737
|
+
.patterns
|
|
738
|
+
.iter()
|
|
739
|
+
.map(|pattern| {
|
|
740
|
+
format!("Regex.IsMatch(value, {:?})", format!(r"\A(?:{pattern})\z"))
|
|
741
|
+
})
|
|
742
|
+
.collect::<Vec<_>>()
|
|
743
|
+
.join(" && ");
|
|
744
|
+
let _ = writeln!(
|
|
745
|
+
out,
|
|
746
|
+
"{} if ({}) {{ var candidate{} = value; return new {}({}); }}",
|
|
747
|
+
indent, checks, idx, variant, wrap
|
|
748
|
+
);
|
|
749
|
+
} else {
|
|
750
|
+
let _ = writeln!(
|
|
751
|
+
out,
|
|
752
|
+
"{} {{ var candidate{} = value; return new {}({}); }}",
|
|
753
|
+
indent, idx, variant, wrap
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
} else if base_name == "bool" {
|
|
757
|
+
let _ = writeln!(out, "{} if (value == \"true\" || value == \"1\") {{ var candidate{} = true; return new {}({}); }}", indent, idx, variant, wrap);
|
|
758
|
+
let _ = writeln!(out, "{} if (value == \"false\" || value == \"0\") {{ var candidate{} = false; return new {}({}); }}", indent, idx, variant, wrap);
|
|
759
|
+
} else if base_name == "DateOnly" {
|
|
760
|
+
let _ = writeln!(out, "{} if (DateOnly.TryParseExact(value, \"yyyy-MM-dd\", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out var candidate{})) return new {}({});", indent, idx, variant, wrap);
|
|
761
|
+
} else {
|
|
762
|
+
let _ = writeln!(
|
|
763
|
+
out,
|
|
764
|
+
"{} if ({}.TryParse(value, out var candidate{})) return new {}({});",
|
|
765
|
+
indent, base_name, idx, variant, wrap
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
let _ = writeln!(
|
|
770
|
+
out,
|
|
771
|
+
"{} throw new FormatException(\"No {} union member accepts the value\");",
|
|
772
|
+
indent, name
|
|
773
|
+
);
|
|
774
|
+
let _ = writeln!(out, "{} }}", indent);
|
|
775
|
+
let _ = writeln!(
|
|
776
|
+
out,
|
|
777
|
+
"{} public string ToXmlString() => this switch",
|
|
778
|
+
indent
|
|
779
|
+
);
|
|
780
|
+
let _ = writeln!(out, "{} {{", indent);
|
|
781
|
+
for branch in &u.branches {
|
|
782
|
+
let variant = to_csharp_type_name(&branch.variant_name);
|
|
783
|
+
let value = if matches!(
|
|
784
|
+
super::primitive_base(&branch.type_ref, ir),
|
|
785
|
+
TypeRef::Primitive(PrimitiveType::Date)
|
|
786
|
+
) {
|
|
787
|
+
"item.Value.ToString(\"yyyy-MM-dd\", System.Globalization.CultureInfo.InvariantCulture)".to_string()
|
|
788
|
+
} else {
|
|
789
|
+
match &branch.type_ref {
|
|
790
|
+
TypeRef::Named(qname) if matches!(ir.types.get(qname), Some(TypeDef::Enum(_))) => "item.Value.ToXmlValue()".to_string(),
|
|
791
|
+
TypeRef::Named(qname) if matches!(ir.types.get(qname), Some(TypeDef::Simple(_))) => "Convert.ToString(item.Value.Value, System.Globalization.CultureInfo.InvariantCulture) ?? \"\"".to_string(),
|
|
792
|
+
_ => "Convert.ToString(item.Value, System.Globalization.CultureInfo.InvariantCulture) ?? \"\"".to_string(),
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
let _ = writeln!(out, "{} {} item => {},", indent, variant, value);
|
|
796
|
+
}
|
|
797
|
+
let _ = writeln!(
|
|
798
|
+
out,
|
|
799
|
+
"{} _ => throw new InvalidOperationException()",
|
|
800
|
+
indent
|
|
801
|
+
);
|
|
802
|
+
let _ = writeln!(out, "{} }};", indent);
|
|
803
|
+
}
|
|
804
|
+
|
|
685
805
|
fn emit_struct(&self, out: &mut String, s: &StructDef, ir: &SchemaIR, indent: &str) {
|
|
686
806
|
let struct_name = type_ident(&s.qname);
|
|
687
807
|
if let Some(ref doc) = s.documentation {
|
|
@@ -732,6 +852,55 @@ impl CSharpCodegen {
|
|
|
732
852
|
.map(|f| self.unique_property_name(&f.name, &mut seen_props, Some(&struct_name)))
|
|
733
853
|
.collect();
|
|
734
854
|
|
|
855
|
+
let has_lexical_union = self.options.emit_xml_attributes && s.fields.iter().any(|f| {
|
|
856
|
+
matches!(&f.type_ref, TypeRef::Named(q) if matches!(ir.types.get(q), Some(TypeDef::Union(u)) if u.is_lexical()))
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
if self.options.use_records && has_lexical_union {
|
|
860
|
+
writeln!(
|
|
861
|
+
out,
|
|
862
|
+
"{}public record {}{}\n{}{{",
|
|
863
|
+
indent, struct_name, implements_str, indent
|
|
864
|
+
)
|
|
865
|
+
.unwrap();
|
|
866
|
+
for (f, name) in s.fields.iter().zip(&prop_names) {
|
|
867
|
+
let ty = self.map_field_type(f, ir);
|
|
868
|
+
if let TypeRef::Named(q) = &f.type_ref {
|
|
869
|
+
if matches!(ir.types.get(q), Some(TypeDef::Union(u)) if u.is_lexical()) {
|
|
870
|
+
let _ = writeln!(out, "{} [XmlIgnore]", indent);
|
|
871
|
+
if self.options.emit_json_attributes {
|
|
872
|
+
let _ =
|
|
873
|
+
writeln!(out, "{} [JsonPropertyName({:?})]", indent, f.xml_name);
|
|
874
|
+
}
|
|
875
|
+
let _ = writeln!(
|
|
876
|
+
out,
|
|
877
|
+
"{} public {} {} {{ get; set; }} = default!;",
|
|
878
|
+
indent, ty, name
|
|
879
|
+
);
|
|
880
|
+
let _ = writeln!(out, "{} [XmlElement({:?})]", indent, f.xml_name);
|
|
881
|
+
if self.options.emit_json_attributes {
|
|
882
|
+
let _ = writeln!(out, "{} [JsonIgnore]", indent);
|
|
883
|
+
}
|
|
884
|
+
let _ = writeln!(out, "{} public string? {}Xml {{ get => {}?.ToXmlString(); set => {} = value is null ? default! : {}.Parse(value); }}", indent, name, name, name, type_ident(q));
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
let attrs = self
|
|
889
|
+
.build_field_attributes(f, ir)
|
|
890
|
+
.replace("[property: ", "[");
|
|
891
|
+
let _ = writeln!(
|
|
892
|
+
out,
|
|
893
|
+
"{} {}public {} {} {{ get; set; }} = default!;",
|
|
894
|
+
indent, attrs, ty, name
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
if self.options.emit_validation {
|
|
898
|
+
self.emit_struct_validator(out, s, &prop_names, indent);
|
|
899
|
+
}
|
|
900
|
+
writeln!(out, "{}}}\n", indent).unwrap();
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
|
|
735
904
|
if !self.options.use_records {
|
|
736
905
|
writeln!(
|
|
737
906
|
out,
|
|
@@ -742,6 +911,28 @@ impl CSharpCodegen {
|
|
|
742
911
|
writeln!(out, "{} public {}() {{ }}", indent, struct_name).unwrap();
|
|
743
912
|
for (f, name) in s.fields.iter().zip(&prop_names) {
|
|
744
913
|
let ty = self.map_field_type(f, ir);
|
|
914
|
+
if let TypeRef::Named(q) = &f.type_ref {
|
|
915
|
+
if self.options.emit_xml_attributes
|
|
916
|
+
&& matches!(ir.types.get(q), Some(TypeDef::Union(u)) if u.is_lexical())
|
|
917
|
+
{
|
|
918
|
+
let _ = writeln!(out, "{} [XmlIgnore]", indent);
|
|
919
|
+
if self.options.emit_json_attributes {
|
|
920
|
+
let _ =
|
|
921
|
+
writeln!(out, "{} [JsonPropertyName({:?})]", indent, f.xml_name);
|
|
922
|
+
}
|
|
923
|
+
let _ = writeln!(
|
|
924
|
+
out,
|
|
925
|
+
"{} public {} {} {{ get; set; }} = default!;",
|
|
926
|
+
indent, ty, name
|
|
927
|
+
);
|
|
928
|
+
let _ = writeln!(out, "{} [XmlElement({:?})]", indent, f.xml_name);
|
|
929
|
+
if self.options.emit_json_attributes {
|
|
930
|
+
let _ = writeln!(out, "{} [JsonIgnore]", indent);
|
|
931
|
+
}
|
|
932
|
+
let _ = writeln!(out, "{} public string? {}Xml {{ get => {}?.ToXmlString(); set => {} = value is null ? default! : {}.Parse(value); }}", indent, name, name, name, type_ident(q));
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
745
936
|
let attrs = self
|
|
746
937
|
.build_field_attributes(f, ir)
|
|
747
938
|
.replace("[property: ", "[");
|
|
@@ -255,15 +255,22 @@ impl GoCodegen {
|
|
|
255
255
|
set_type_name_map(build_type_name_map(ir, to_go_type_name));
|
|
256
256
|
let mut body = String::new();
|
|
257
257
|
let mut has_time = false;
|
|
258
|
-
let
|
|
259
|
-
|
|
260
|
-
TypeDef::Simple(s)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
258
|
+
let lexical_patterns = ir.types.values().any(|def| match def {
|
|
259
|
+
TypeDef::Union(u) if u.is_lexical() => u.branches.iter().any(|branch| {
|
|
260
|
+
matches!(&branch.type_ref, TypeRef::Named(q) if matches!(ir.types.get(q), Some(TypeDef::Simple(s)) if !s.facets.patterns.is_empty()))
|
|
261
|
+
}),
|
|
262
|
+
_ => false,
|
|
263
|
+
});
|
|
264
|
+
let has_patterns = lexical_patterns
|
|
265
|
+
|| (self.options.validate_facets
|
|
266
|
+
&& ir.types.values().any(|t| match t {
|
|
267
|
+
TypeDef::Simple(s) => !s.facets.patterns.is_empty(),
|
|
268
|
+
TypeDef::Struct(s) => s
|
|
269
|
+
.fields
|
|
270
|
+
.iter()
|
|
271
|
+
.any(|f| f.facets.as_ref().is_some_and(|f| !f.patterns.is_empty())),
|
|
272
|
+
_ => false,
|
|
273
|
+
}));
|
|
267
274
|
let mut has_fmt = has_patterns;
|
|
268
275
|
let mut has_io = false;
|
|
269
276
|
let mut has_xml = self.options.emit_xml_tags;
|
|
@@ -288,12 +295,22 @@ impl GoCodegen {
|
|
|
288
295
|
has_fmt = true;
|
|
289
296
|
}
|
|
290
297
|
}
|
|
291
|
-
TypeDef::Union(
|
|
292
|
-
if
|
|
298
|
+
TypeDef::Union(u) => {
|
|
299
|
+
if u.branches
|
|
300
|
+
.iter()
|
|
301
|
+
.any(|branch| self.references_time(&branch.type_ref))
|
|
302
|
+
{
|
|
303
|
+
has_time = true;
|
|
304
|
+
}
|
|
305
|
+
if self.options.validate_choice_exclusivity && !u.is_lexical() {
|
|
293
306
|
has_fmt = true;
|
|
294
307
|
has_io = true;
|
|
295
308
|
has_xml = true;
|
|
296
309
|
}
|
|
310
|
+
if u.is_lexical() {
|
|
311
|
+
has_fmt = true;
|
|
312
|
+
has_xml = true;
|
|
313
|
+
}
|
|
297
314
|
}
|
|
298
315
|
TypeDef::Simple(st) => {
|
|
299
316
|
if self.references_time(&st.base_type) {
|
|
@@ -344,6 +361,14 @@ impl GoCodegen {
|
|
|
344
361
|
if has_patterns {
|
|
345
362
|
imports.push("\"regexp\"");
|
|
346
363
|
}
|
|
364
|
+
if ir
|
|
365
|
+
.types
|
|
366
|
+
.values()
|
|
367
|
+
.any(|def| matches!(def, TypeDef::Union(u) if u.is_lexical()))
|
|
368
|
+
{
|
|
369
|
+
imports.push("\"strconv\"");
|
|
370
|
+
imports.push("\"strings\"");
|
|
371
|
+
}
|
|
347
372
|
if has_time {
|
|
348
373
|
imports.push("\"time\"");
|
|
349
374
|
}
|
|
@@ -399,7 +424,7 @@ impl GoCodegen {
|
|
|
399
424
|
// Emit choices (unions)
|
|
400
425
|
for type_def in ir.types.values() {
|
|
401
426
|
if let TypeDef::Union(u) = type_def {
|
|
402
|
-
self.emit_union(out, u);
|
|
427
|
+
self.emit_union(out, u, ir);
|
|
403
428
|
}
|
|
404
429
|
}
|
|
405
430
|
|
|
@@ -509,7 +534,11 @@ impl GoCodegen {
|
|
|
509
534
|
writeln!(out, "}}\n").unwrap();
|
|
510
535
|
}
|
|
511
536
|
|
|
512
|
-
fn emit_union(&self, out: &mut String, u: &UnionDef) {
|
|
537
|
+
fn emit_union(&self, out: &mut String, u: &UnionDef, ir: &SchemaIR) {
|
|
538
|
+
if u.is_lexical() {
|
|
539
|
+
self.emit_lexical_union(out, u, ir);
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
513
542
|
let choice_name = type_ident(&u.qname);
|
|
514
543
|
if let Some(ref doc) = u.documentation {
|
|
515
544
|
for line in doc.lines() {
|
|
@@ -689,6 +718,153 @@ impl GoCodegen {
|
|
|
689
718
|
}
|
|
690
719
|
}
|
|
691
720
|
|
|
721
|
+
fn emit_lexical_union(&self, out: &mut String, u: &UnionDef, ir: &SchemaIR) {
|
|
722
|
+
let name = type_ident(&u.qname);
|
|
723
|
+
let mut seen = HashSet::new();
|
|
724
|
+
let fields = u
|
|
725
|
+
.branches
|
|
726
|
+
.iter()
|
|
727
|
+
.map(|b| self.unique_field_name(&b.variant_name, &mut seen))
|
|
728
|
+
.collect::<Vec<_>>();
|
|
729
|
+
let _ = writeln!(out, "type {} struct {{", name);
|
|
730
|
+
for (branch, field) in u.branches.iter().zip(&fields) {
|
|
731
|
+
let _ = writeln!(
|
|
732
|
+
out,
|
|
733
|
+
" {} *{} `json:{:?}`",
|
|
734
|
+
field,
|
|
735
|
+
self.context.map_type_ref(&branch.type_ref),
|
|
736
|
+
format!("{},omitempty", field)
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
out.push_str("}\n\n");
|
|
740
|
+
let _ = writeln!(out, "func (c {}) Selected() string {{", name);
|
|
741
|
+
for field in &fields {
|
|
742
|
+
let _ = writeln!(out, " if c.{} != nil {{ return {:?} }}", field, field);
|
|
743
|
+
}
|
|
744
|
+
out.push_str(" return \"\"\n}\n\n");
|
|
745
|
+
let _ = writeln!(
|
|
746
|
+
out,
|
|
747
|
+
"func (c *{}) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {{",
|
|
748
|
+
name
|
|
749
|
+
);
|
|
750
|
+
out.push_str(" var raw string\n if err := d.DecodeElement(&raw, &start); err != nil { return err }\n value := strings.TrimSpace(raw)\n *c = ");
|
|
751
|
+
let _ = writeln!(out, "{}{{}}", name);
|
|
752
|
+
for (branch, field) in u.branches.iter().zip(&fields) {
|
|
753
|
+
let mapped = self.context.map_type_ref(&branch.type_ref);
|
|
754
|
+
if let TypeRef::Named(qname) = &branch.type_ref {
|
|
755
|
+
if let Some(TypeDef::Enum(def)) = ir.types.get(qname) {
|
|
756
|
+
let comparisons = def
|
|
757
|
+
.variants
|
|
758
|
+
.iter()
|
|
759
|
+
.map(|v| format!("value == {:?}", v.value))
|
|
760
|
+
.collect::<Vec<_>>()
|
|
761
|
+
.join(" || ");
|
|
762
|
+
let _ = writeln!(
|
|
763
|
+
out,
|
|
764
|
+
" if {} {{ v := {}(value); c.{} = &v; return nil }}",
|
|
765
|
+
comparisons, mapped, field
|
|
766
|
+
);
|
|
767
|
+
continue;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
let base = super::primitive_base(&branch.type_ref, ir);
|
|
771
|
+
let numeric = match base {
|
|
772
|
+
TypeRef::Primitive(
|
|
773
|
+
PrimitiveType::Int
|
|
774
|
+
| PrimitiveType::Integer
|
|
775
|
+
| PrimitiveType::Long
|
|
776
|
+
| PrimitiveType::Short
|
|
777
|
+
| PrimitiveType::Byte,
|
|
778
|
+
) => Some("signed"),
|
|
779
|
+
TypeRef::Primitive(
|
|
780
|
+
PrimitiveType::UnsignedInt
|
|
781
|
+
| PrimitiveType::UnsignedLong
|
|
782
|
+
| PrimitiveType::UnsignedShort
|
|
783
|
+
| PrimitiveType::UnsignedByte
|
|
784
|
+
| PrimitiveType::PositiveInteger
|
|
785
|
+
| PrimitiveType::NonNegativeInteger,
|
|
786
|
+
) => Some("unsigned"),
|
|
787
|
+
TypeRef::Primitive(
|
|
788
|
+
PrimitiveType::Float | PrimitiveType::Double | PrimitiveType::Decimal,
|
|
789
|
+
) => Some("float"),
|
|
790
|
+
_ => None,
|
|
791
|
+
};
|
|
792
|
+
if matches!(base, TypeRef::Primitive(PrimitiveType::Date)) {
|
|
793
|
+
let _ = writeln!(out, " if parsed, err := time.Parse(\"2006-01-02\", value); err == nil {{ v := {}(parsed); c.{} = &v; return nil }}", mapped, field);
|
|
794
|
+
} else if let Some(kind) = numeric {
|
|
795
|
+
let parse = match kind {
|
|
796
|
+
"signed" => "strconv.ParseInt(value, 10, 64)",
|
|
797
|
+
"unsigned" => "strconv.ParseUint(value, 10, 64)",
|
|
798
|
+
_ => "strconv.ParseFloat(value, 64)",
|
|
799
|
+
};
|
|
800
|
+
let _ = writeln!(out, " if parsed, err := {}; err == nil {{ v := {}(parsed); c.{} = &v; return nil }}", parse, mapped, field);
|
|
801
|
+
} else if matches!(base, TypeRef::Primitive(PrimitiveType::Boolean)) {
|
|
802
|
+
let _ = writeln!(out, " if parsed, err := strconv.ParseBool(value); err == nil {{ v := {}(parsed); c.{} = &v; return nil }}", mapped, field);
|
|
803
|
+
} else {
|
|
804
|
+
let simple = match &branch.type_ref {
|
|
805
|
+
TypeRef::Named(qname) => ir.types.get(qname).and_then(|def| match def {
|
|
806
|
+
TypeDef::Simple(s) => Some(s.as_ref()),
|
|
807
|
+
_ => None,
|
|
808
|
+
}),
|
|
809
|
+
_ => None,
|
|
810
|
+
};
|
|
811
|
+
if let Some(simple) = simple.filter(|s| !s.facets.patterns.is_empty()) {
|
|
812
|
+
let checks = simple
|
|
813
|
+
.facets
|
|
814
|
+
.patterns
|
|
815
|
+
.iter()
|
|
816
|
+
.map(|pattern| {
|
|
817
|
+
format!(
|
|
818
|
+
"regexp.MustCompile({:?}).MatchString(value)",
|
|
819
|
+
format!("^(?:{pattern})$")
|
|
820
|
+
)
|
|
821
|
+
})
|
|
822
|
+
.collect::<Vec<_>>()
|
|
823
|
+
.join(" && ");
|
|
824
|
+
let _ = writeln!(
|
|
825
|
+
out,
|
|
826
|
+
" if {} {{ v := {}(value); c.{} = &v; return nil }}",
|
|
827
|
+
checks, mapped, field
|
|
828
|
+
);
|
|
829
|
+
} else {
|
|
830
|
+
let _ = writeln!(
|
|
831
|
+
out,
|
|
832
|
+
" {{ v := {}(value); c.{} = &v; return nil }}",
|
|
833
|
+
mapped, field
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
let _ = writeln!(
|
|
839
|
+
out,
|
|
840
|
+
" return fmt.Errorf(\"invalid lexical value for {}: %q\", value)",
|
|
841
|
+
name
|
|
842
|
+
);
|
|
843
|
+
out.push_str("}\n\n");
|
|
844
|
+
let _ = writeln!(
|
|
845
|
+
out,
|
|
846
|
+
"func (c {}) MarshalXML(e *xml.Encoder, start xml.StartElement) error {{",
|
|
847
|
+
name
|
|
848
|
+
);
|
|
849
|
+
out.push_str(" count := 0\n var value string\n");
|
|
850
|
+
for (branch, field) in u.branches.iter().zip(&fields) {
|
|
851
|
+
let expr = if matches!(
|
|
852
|
+
super::primitive_base(&branch.type_ref, ir),
|
|
853
|
+
TypeRef::Primitive(PrimitiveType::Date)
|
|
854
|
+
) {
|
|
855
|
+
format!("c.{}.Format(\"2006-01-02\")", field)
|
|
856
|
+
} else {
|
|
857
|
+
format!("fmt.Sprint(*c.{})", field)
|
|
858
|
+
};
|
|
859
|
+
let _ = writeln!(
|
|
860
|
+
out,
|
|
861
|
+
" if c.{} != nil {{ count++; value = {} }}",
|
|
862
|
+
field, expr
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
out.push_str(" if count != 1 { return fmt.Errorf(\"lexical union requires exactly one member\") }\n return e.EncodeElement(value, start)\n}\n\n");
|
|
866
|
+
}
|
|
867
|
+
|
|
692
868
|
fn emit_struct(&self, out: &mut String, s: &StructDef, ir: &SchemaIR) {
|
|
693
869
|
let struct_name = type_ident(&s.qname);
|
|
694
870
|
if let Some(ref doc) = s.documentation {
|
|
@@ -40,10 +40,9 @@ impl JavaCodegen {
|
|
|
40
40
|
check_type(&f.type_ref, ir)?;
|
|
41
41
|
if matches!(f.kind, FieldKind::Attribute | FieldKind::Text) {
|
|
42
42
|
if let TypeRef::Named(q) = &f.type_ref {
|
|
43
|
-
if matches!(
|
|
44
|
-
ir.types.get(q),
|
|
45
|
-
|
|
46
|
-
) {
|
|
43
|
+
if matches!(ir.types.get(q), Some(TypeDef::Struct(_)))
|
|
44
|
+
|| matches!(ir.types.get(q), Some(TypeDef::Union(u)) if !u.is_lexical())
|
|
45
|
+
{
|
|
47
46
|
return Err(format!(
|
|
48
47
|
"non-scalar XML text/attribute {}.{}",
|
|
49
48
|
name, f.name
|
|
@@ -176,13 +175,23 @@ impl JavaCodegen {
|
|
|
176
175
|
);
|
|
177
176
|
}
|
|
178
177
|
TypeDef::Union(u) => {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
178
|
+
if u.is_lexical() {
|
|
179
|
+
out.push_str(" String text = reader.getElementText();\n");
|
|
180
|
+
for b in &u.branches {
|
|
181
|
+
let expr = self.parse_scalar(&b.type_ref, "text", ir);
|
|
182
|
+
let variant = to_java_type_name(&b.variant_name);
|
|
183
|
+
let _ = writeln!(out, " try {{ return new {name}.{variant}({expr}); }} catch (RuntimeException ignored) {{ }}");
|
|
184
|
+
}
|
|
185
|
+
let _ = writeln!(out, " throw new XMLStreamException(\"No {} union member accepts: \" + text);", name);
|
|
186
|
+
} else {
|
|
187
|
+
let _=writeln!(out," {name} result = null;\n while (reader.hasNext()) {{\n int event = reader.next();\n if (event == XMLStreamConstants.END_ELEMENT) return result;\n if (event != XMLStreamConstants.START_ELEMENT) continue;");
|
|
188
|
+
for (i, b) in u.branches.iter().enumerate() {
|
|
189
|
+
let expr = self.read_value(&b.type_ref, ir);
|
|
190
|
+
let variant = to_java_type_name(&b.variant_name);
|
|
191
|
+
let _=writeln!(out," {}if (reader.getLocalName().equals({:?})) result = new {name}.{variant}({expr});",if i==0 {""}else{"else "},b.xml_name);
|
|
192
|
+
}
|
|
193
|
+
out.push_str(" else skip(reader);\n }\n return result;\n");
|
|
184
194
|
}
|
|
185
|
-
out.push_str(" else skip(reader);\n }\n return result;\n");
|
|
186
195
|
}
|
|
187
196
|
}
|
|
188
197
|
out.push_str(" } catch (IllegalArgumentException | java.time.DateTimeException ex) { throw new XMLStreamException(\"Invalid XML value\", reader.getLocation(), ex); }\n }\n");
|
|
@@ -230,15 +239,20 @@ impl JavaCodegen {
|
|
|
230
239
|
} else {
|
|
231
240
|
"branch.getValue()"
|
|
232
241
|
};
|
|
233
|
-
|
|
234
|
-
&
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
+
if u.is_lexical() {
|
|
243
|
+
let text = self.format_scalar(&b.type_ref, access, ir);
|
|
244
|
+
let _ = writeln!(out, " writer.writeCharacters({text});");
|
|
245
|
+
} else {
|
|
246
|
+
self.emit_write_value(
|
|
247
|
+
&mut out,
|
|
248
|
+
&b.type_ref,
|
|
249
|
+
access,
|
|
250
|
+
&b.xml_name,
|
|
251
|
+
u.qname.namespace.as_deref().unwrap_or(""),
|
|
252
|
+
ir,
|
|
253
|
+
" ",
|
|
254
|
+
);
|
|
255
|
+
}
|
|
242
256
|
out.push_str(" }\n");
|
|
243
257
|
}
|
|
244
258
|
}
|