polyxml 0.20.0__tar.gz → 0.20.1__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 (57) hide show
  1. {polyxml-0.20.0 → polyxml-0.20.1}/Cargo.lock +5 -5
  2. {polyxml-0.20.0 → polyxml-0.20.1}/Cargo.toml +1 -1
  3. {polyxml-0.20.0 → polyxml-0.20.1}/PKG-INFO +1 -1
  4. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/codegen/cpp/mod.rs +31 -13
  5. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/codegen/csharp/mod.rs +25 -16
  6. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/codegen/go/mod.rs +19 -10
  7. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/codegen/java/codec.rs +8 -12
  8. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/codegen/java/mod.rs +18 -8
  9. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/codegen/java/models.rs +2 -2
  10. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/codegen/mod.rs +49 -2
  11. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/codegen/python/mod.rs +94 -13
  12. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/codegen/rust/mod.rs +24 -13
  13. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/codegen/typescript/mod.rs +21 -12
  14. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/schema_parser/mod.rs +776 -21
  15. polyxml-0.20.1/crates/polyxml-core/tests/test_issue51_audit.rs +581 -0
  16. {polyxml-0.20.0 → polyxml-0.20.1}/pyproject.toml +1 -1
  17. {polyxml-0.20.0 → polyxml-0.20.1}/README.md +0 -0
  18. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/Cargo.toml +0 -0
  19. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/README.md +0 -0
  20. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
  21. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/converters.rs +0 -0
  22. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/error.rs +0 -0
  23. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/ir/mod.rs +0 -0
  24. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
  25. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/json.rs +0 -0
  26. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/lib.rs +0 -0
  27. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/parser.rs +0 -0
  28. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/schema.rs +0 -0
  29. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/serializer.rs +0 -0
  30. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/transcoder.rs +0 -0
  31. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/src/value.rs +0 -0
  32. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_conformance.rs +0 -0
  33. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_core.rs +0 -0
  34. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
  35. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
  36. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_go_codegen.rs +0 -0
  37. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
  38. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_json.rs +0 -0
  39. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_python_codegen.rs +0 -0
  40. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
  41. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_rust_codegen.rs +0 -0
  42. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_schema_ir.rs +0 -0
  43. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_security.rs +0 -0
  44. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
  45. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
  46. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-python/Cargo.toml +0 -0
  47. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-python/README.md +0 -0
  48. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-python/src/lib.rs +0 -0
  49. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-python/tests/test_conformance.py +0 -0
  50. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-python/tests/test_generated_models.py +0 -0
  51. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-python/tests/test_json.py +0 -0
  52. {polyxml-0.20.0 → polyxml-0.20.1}/crates/polyxml-python/tests/test_polyxml.py +0 -0
  53. {polyxml-0.20.0 → polyxml-0.20.1}/python/polyxml/AGENT_GUIDE.md +0 -0
  54. {polyxml-0.20.0 → polyxml-0.20.1}/python/polyxml/__init__.py +0 -0
  55. {polyxml-0.20.0 → polyxml-0.20.1}/python/polyxml/compat/__init__.py +0 -0
  56. {polyxml-0.20.0 → polyxml-0.20.1}/python/polyxml/compat/xsdata.py +0 -0
  57. {polyxml-0.20.0 → polyxml-0.20.1}/python/polyxml/py.typed +0 -0
@@ -549,7 +549,7 @@ dependencies = [
549
549
 
550
550
  [[package]]
551
551
  name = "polyxml"
552
- version = "0.20.0"
552
+ version = "0.20.1"
553
553
  dependencies = [
554
554
  "criterion",
555
555
  "heck",
@@ -567,14 +567,14 @@ dependencies = [
567
567
 
568
568
  [[package]]
569
569
  name = "polyxml-c"
570
- version = "0.20.0"
570
+ version = "0.20.1"
571
571
  dependencies = [
572
572
  "polyxml",
573
573
  ]
574
574
 
575
575
  [[package]]
576
576
  name = "polyxml-cli"
577
- version = "0.20.0"
577
+ version = "0.20.1"
578
578
  dependencies = [
579
579
  "clap",
580
580
  "glob",
@@ -588,7 +588,7 @@ dependencies = [
588
588
 
589
589
  [[package]]
590
590
  name = "polyxml-js"
591
- version = "0.20.0"
591
+ version = "0.20.1"
592
592
  dependencies = [
593
593
  "napi",
594
594
  "napi-build",
@@ -598,7 +598,7 @@ dependencies = [
598
598
 
599
599
  [[package]]
600
600
  name = "polyxml-python"
601
- version = "0.20.0"
601
+ version = "0.20.1"
602
602
  dependencies = [
603
603
  "lexical-core",
604
604
  "polyxml",
@@ -3,7 +3,7 @@ resolver = "2"
3
3
  members = ["crates/polyxml-core", "crates/polyxml-python"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.20.0"
6
+ version = "0.20.1"
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.20.0
3
+ Version: 0.20.1
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -4,7 +4,9 @@ use std::fmt::Write as FmtWrite;
4
4
  use heck::{AsPascalCase, AsSnakeCase};
5
5
  use serde::{Deserialize, Serialize};
6
6
 
7
- use crate::codegen::{sanitize_keyword, LanguageContext};
7
+ use crate::codegen::{
8
+ build_type_name_map, lookup_type_name, sanitize_keyword, set_type_name_map, LanguageContext,
9
+ };
8
10
  use crate::ir::{
9
11
  EnumDef, PrimitiveType, QName, RestrictionFacets, SchemaIR, SimpleTypeDef, StructDef, TypeDef,
10
12
  TypeRef, UnionDef,
@@ -157,7 +159,7 @@ impl LanguageContext for CppLanguageContext {
157
159
  fn map_type_ref(&self, type_ref: &TypeRef) -> String {
158
160
  match type_ref {
159
161
  TypeRef::Primitive(prim) => self.map_primitive(*prim).to_string(),
160
- TypeRef::Named(qname) => to_cpp_type_name(&qname.local),
162
+ TypeRef::Named(qname) => type_ident(qname),
161
163
  TypeRef::Boxed(inner) => format!("std::unique_ptr<{}>", self.map_type_ref(inner)),
162
164
  TypeRef::List(inner) => format!("std::vector<{}>", self.map_type_ref(inner)),
163
165
  }
@@ -239,6 +241,12 @@ pub struct CppCodegen {
239
241
  context: CppLanguageContext,
240
242
  }
241
243
 
244
+ /// Emitted C++ identifier for a named type, disambiguated across namespaces
245
+ /// for the IR currently being generated (issue #51 item 3).
246
+ fn type_ident(q: &QName) -> String {
247
+ lookup_type_name(q, || to_cpp_type_name(&q.local))
248
+ }
249
+
242
250
  impl CppCodegen {
243
251
  pub fn new(options: CppOptions) -> Self {
244
252
  Self {
@@ -249,6 +257,7 @@ impl CppCodegen {
249
257
 
250
258
  /// Generate complete header-only source (`.hpp`).
251
259
  pub fn generate_header(&self, ir: &SchemaIR) -> String {
260
+ set_type_name_map(build_type_name_map(ir, to_cpp_type_name));
252
261
  let mut out = String::new();
253
262
  if let Some(ref header) = self.options.custom_header {
254
263
  let trimmed = header.trim();
@@ -286,6 +295,7 @@ impl CppCodegen {
286
295
 
287
296
  /// Generate complete C++20 module interface unit (`.cppm`).
288
297
  pub fn generate_module_unit(&self, ir: &SchemaIR, module_name: &str) -> String {
298
+ set_type_name_map(build_type_name_map(ir, to_cpp_type_name));
289
299
  let mut out = String::new();
290
300
  if let Some(ref header) = self.options.custom_header {
291
301
  let trimmed = header.trim();
@@ -470,7 +480,7 @@ endif()
470
480
  // 1. Enums
471
481
  for type_def in ir.types.values() {
472
482
  if let TypeDef::Enum(enum_def) = type_def {
473
- let enum_name = to_cpp_type_name(&enum_def.qname.local);
483
+ let enum_name = type_ident(&enum_def.qname);
474
484
  let full_type = format!("{}::{}", ns, enum_name);
475
485
  writeln!(out, "template <>").unwrap();
476
486
  writeln!(out, "struct glz::meta<{}> {{", full_type).unwrap();
@@ -498,7 +508,7 @@ endif()
498
508
  let sorted_qnames = self.topological_sort_types(ir);
499
509
  for qname in sorted_qnames {
500
510
  if let Some(TypeDef::Struct(s)) = ir.types.get(&qname) {
501
- let struct_name = to_cpp_type_name(&s.qname.local);
511
+ let struct_name = type_ident(&s.qname);
502
512
  let full_type = format!("{}::{}", ns, struct_name);
503
513
  writeln!(out, "template <>").unwrap();
504
514
  writeln!(out, "struct glz::meta<{}> {{", full_type).unwrap();
@@ -570,7 +580,7 @@ concept XmlModel = requires(T a) {{
570
580
  .values()
571
581
  .filter_map(|t| {
572
582
  if let TypeDef::Struct(s) = t {
573
- Some(to_cpp_type_name(&s.qname.local))
583
+ Some(type_ident(&s.qname))
574
584
  } else {
575
585
  None
576
586
  }
@@ -622,7 +632,7 @@ concept XmlModel = requires(T a) {{
622
632
  writeln!(out, "/// {}", line).unwrap();
623
633
  }
624
634
  }
625
- let type_name = to_cpp_type_name(&simple.qname.local);
635
+ let type_name = type_ident(&simple.qname);
626
636
  let base_type = self.context.map_type_ref(&simple.base_type);
627
637
  writeln!(out, "using {} = {};\n", type_name, base_type).unwrap();
628
638
  }
@@ -634,7 +644,7 @@ concept XmlModel = requires(T a) {{
634
644
  }
635
645
  }
636
646
 
637
- let enum_name = to_cpp_type_name(&enum_def.qname.local);
647
+ let enum_name = type_ident(&enum_def.qname);
638
648
  writeln!(out, "enum class {} {{", enum_name).unwrap();
639
649
 
640
650
  for variant in &enum_def.variants {
@@ -668,8 +678,16 @@ concept XmlModel = requires(T a) {{
668
678
  writeln!(out, " return \"\";").unwrap();
669
679
  writeln!(out, "}}\n").unwrap();
670
680
 
671
- // from_string
672
- let func_name = format!("{}_from_string", AsSnakeCase(&enum_def.qname.local));
681
+ // from_string — stem follows the disambiguated type name only when
682
+ // it differs from the natural one, preserving the historical
683
+ // snake-of-local form otherwise (issue #51 item 3).
684
+ let natural = to_cpp_type_name(&enum_def.qname.local);
685
+ let stem = if enum_name == natural {
686
+ AsSnakeCase(&enum_def.qname.local).to_string()
687
+ } else {
688
+ AsSnakeCase(&enum_name).to_string()
689
+ };
690
+ let func_name = format!("{stem}_from_string");
673
691
  writeln!(
674
692
  out,
675
693
  "[[nodiscard]] inline std::optional<{}> {}(std::string_view s) noexcept {{",
@@ -697,7 +715,7 @@ concept XmlModel = requires(T a) {{
697
715
  }
698
716
  }
699
717
 
700
- let union_name = to_cpp_type_name(&u.qname.local);
718
+ let union_name = type_ident(&u.qname);
701
719
 
702
720
  // Check if branches have distinct types and no primitives
703
721
  let mut branch_types = Vec::new();
@@ -758,17 +776,17 @@ concept XmlModel = requires(T a) {{
758
776
  }
759
777
  }
760
778
 
761
- let struct_name = to_cpp_type_name(&s.qname.local);
779
+ let struct_name = type_ident(&s.qname);
762
780
  let mut base_clause = String::new();
763
781
  let mut simple_content_base: Option<String> = None;
764
782
 
765
783
  if let Some(ref base_qname) = s.base_type {
766
784
  if matches!(ir.types.get(base_qname), Some(TypeDef::Struct(_))) {
767
- base_clause = format!(" : public {}", to_cpp_type_name(&base_qname.local));
785
+ base_clause = format!(" : public {}", type_ident(base_qname));
768
786
  } else if let Some(prim) = PrimitiveType::from_xsd_name(&base_qname.local) {
769
787
  simple_content_base = Some(self.context.map_primitive(prim).to_string());
770
788
  } else if let Some(TypeDef::Simple(st)) = ir.types.get(base_qname) {
771
- simple_content_base = Some(to_cpp_type_name(&st.qname.local));
789
+ simple_content_base = Some(type_ident(&st.qname));
772
790
  }
773
791
  }
774
792
 
@@ -8,9 +8,11 @@ use std::fmt::Write as FmtWrite;
8
8
  use heck::{AsLowerCamelCase, AsPascalCase};
9
9
  use serde::{Deserialize, Serialize};
10
10
 
11
- use crate::codegen::{sanitize_keyword, LanguageContext};
11
+ use crate::codegen::{
12
+ build_type_name_map, lookup_type_name, sanitize_keyword, set_type_name_map, LanguageContext,
13
+ };
12
14
  use crate::ir::{
13
- EnumDef, FieldDef, FieldKind, PrimitiveType, RestrictionFacets, SchemaIR, SimpleTypeDef,
15
+ EnumDef, FieldDef, FieldKind, PrimitiveType, QName, RestrictionFacets, SchemaIR, SimpleTypeDef,
14
16
  StructDef, TypeDef, TypeRef, UnionDef,
15
17
  };
16
18
 
@@ -218,7 +220,7 @@ impl LanguageContext for CSharpLanguageContext {
218
220
  fn map_type_ref(&self, type_ref: &TypeRef) -> String {
219
221
  match type_ref {
220
222
  TypeRef::Primitive(prim) => self.map_primitive(*prim).to_string(),
221
- TypeRef::Named(qname) => to_csharp_type_name(&qname.local),
223
+ TypeRef::Named(qname) => type_ident(qname),
222
224
  TypeRef::Boxed(inner) => self.map_type_ref(inner),
223
225
  TypeRef::List(inner) => format!("List<{}>", self.map_type_ref(inner)),
224
226
  }
@@ -231,6 +233,12 @@ pub struct CSharpCodegen {
231
233
  context: CSharpLanguageContext,
232
234
  }
233
235
 
236
+ /// Emitted C# identifier for a named type, disambiguated across namespaces
237
+ /// for the IR currently being generated (issue #51 item 3).
238
+ fn type_ident(q: &QName) -> String {
239
+ lookup_type_name(q, || to_csharp_type_name(&q.local))
240
+ }
241
+
234
242
  impl CSharpCodegen {
235
243
  /// Creates a new C# code generator with the given configuration options.
236
244
  pub fn new(options: CSharpOptions) -> Self {
@@ -242,6 +250,7 @@ impl CSharpCodegen {
242
250
 
243
251
  /// Emits all types in the given SchemaIR as a single C# compilation unit.
244
252
  pub fn generate_module(&self, ir: &SchemaIR) -> String {
253
+ set_type_name_map(build_type_name_map(ir, to_csharp_type_name));
245
254
  let mut out = String::new();
246
255
 
247
256
  if let Some(ref header) = self.options.custom_header {
@@ -350,7 +359,7 @@ impl CSharpCodegen {
350
359
  // Enums
351
360
  for def in ir.types.values() {
352
361
  if let TypeDef::Enum(e) = def {
353
- let name = to_csharp_type_name(&e.qname.local);
362
+ let name = type_ident(&e.qname);
354
363
  writeln!(out, "{}[JsonSerializable(typeof({}))]", indent, name).unwrap();
355
364
  }
356
365
  }
@@ -358,7 +367,7 @@ impl CSharpCodegen {
358
367
  // Simple types
359
368
  for def in ir.types.values() {
360
369
  if let TypeDef::Simple(s) = def {
361
- let name = to_csharp_type_name(&s.qname.local);
370
+ let name = type_ident(&s.qname);
362
371
  writeln!(out, "{}[JsonSerializable(typeof({}))]", indent, name).unwrap();
363
372
  }
364
373
  }
@@ -366,7 +375,7 @@ impl CSharpCodegen {
366
375
  // Unions
367
376
  for def in ir.types.values() {
368
377
  if let TypeDef::Union(u) = def {
369
- let name = to_csharp_type_name(&u.qname.local);
378
+ let name = type_ident(&u.qname);
370
379
  writeln!(out, "{}[JsonSerializable(typeof({}))]", indent, name).unwrap();
371
380
  }
372
381
  }
@@ -374,7 +383,7 @@ impl CSharpCodegen {
374
383
  // Structs
375
384
  for def in ir.types.values() {
376
385
  if let TypeDef::Struct(s) = def {
377
- let name = to_csharp_type_name(&s.qname.local);
386
+ let name = type_ident(&s.qname);
378
387
  writeln!(out, "{}[JsonSerializable(typeof({}))]", indent, name).unwrap();
379
388
  writeln!(out, "{}[JsonSerializable(typeof(List<{}>))]", indent, name).unwrap();
380
389
  }
@@ -399,7 +408,7 @@ impl CSharpCodegen {
399
408
  }
400
409
 
401
410
  fn emit_enum(&self, out: &mut String, e: &EnumDef, indent: &str) {
402
- let enum_name = to_csharp_type_name(&e.qname.local);
411
+ let enum_name = type_ident(&e.qname);
403
412
  if let Some(ref doc) = e.documentation {
404
413
  self.emit_docstring(out, doc, indent);
405
414
  }
@@ -482,7 +491,7 @@ impl CSharpCodegen {
482
491
 
483
492
  fn emit_simple(&self, out: &mut String, s: &SimpleTypeDef, indent: &str) {
484
493
  if !s.facets.is_empty() || !self.options.use_records {
485
- let type_name = to_csharp_type_name(&s.qname.local);
494
+ let type_name = type_ident(&s.qname);
486
495
  let base_type = self.context.map_type_ref(&s.base_type);
487
496
 
488
497
  if let Some(ref doc) = s.documentation {
@@ -557,7 +566,7 @@ impl CSharpCodegen {
557
566
  }
558
567
 
559
568
  fn emit_union(&self, out: &mut String, u: &UnionDef, indent: &str) {
560
- let choice_name = to_csharp_type_name(&u.qname.local);
569
+ let choice_name = type_ident(&u.qname);
561
570
  if let Some(ref doc) = u.documentation {
562
571
  self.emit_docstring(out, doc, indent);
563
572
  }
@@ -662,7 +671,7 @@ impl CSharpCodegen {
662
671
  }
663
672
 
664
673
  fn emit_struct(&self, out: &mut String, s: &StructDef, ir: &SchemaIR, indent: &str) {
665
- let struct_name = to_csharp_type_name(&s.qname.local);
674
+ let struct_name = type_ident(&s.qname);
666
675
  if let Some(ref doc) = s.documentation {
667
676
  self.emit_docstring(out, doc, indent);
668
677
  }
@@ -690,7 +699,7 @@ impl CSharpCodegen {
690
699
  let mut base_clause = Vec::new();
691
700
  if let Some(ref base_qname) = s.base_type {
692
701
  if matches!(ir.types.get(base_qname), Some(TypeDef::Struct(_))) {
693
- let base_name = to_csharp_type_name(&base_qname.local);
702
+ let base_name = type_ident(base_qname);
694
703
  base_clause.push(base_name);
695
704
  }
696
705
  }
@@ -816,7 +825,7 @@ impl CSharpCodegen {
816
825
  }
817
826
 
818
827
  fn emit_struct_validator(&self, out: &mut String, s: &StructDef, indent: &str) {
819
- let struct_name = to_csharp_type_name(&s.qname.local);
828
+ let struct_name = type_ident(&s.qname);
820
829
  let new_kw = if !self.options.use_records {
821
830
  if s.base_type.is_some() {
822
831
  "override "
@@ -940,9 +949,9 @@ impl CSharpCodegen {
940
949
  TypeRef::Primitive(p) => self.context.map_primitive(*p).to_string(),
941
950
  TypeRef::Named(qn) => {
942
951
  if let Some(TypeDef::Union(u)) = ir.types.get(qn) {
943
- to_csharp_type_name(&u.qname.local)
952
+ type_ident(&u.qname)
944
953
  } else {
945
- to_csharp_type_name(&qn.local)
954
+ type_ident(qn)
946
955
  }
947
956
  }
948
957
  TypeRef::Boxed(inner) => self.context.map_type_ref(inner),
@@ -969,7 +978,7 @@ impl CSharpCodegen {
969
978
  // If the field is a choice (UnionDef), emit XmlElement("branchXml", typeof(BranchType))
970
979
  if let TypeRef::Named(ref qname) = f.type_ref {
971
980
  if let Some(TypeDef::Union(u)) = ir.types.get(qname) {
972
- let choice_name = to_csharp_type_name(&u.qname.local);
981
+ let choice_name = type_ident(&u.qname);
973
982
  for branch in &u.branches {
974
983
  let variant_name = to_csharp_type_name(&branch.variant_name);
975
984
  parts.push(format!(
@@ -3,9 +3,11 @@ use std::fmt::Write as FmtWrite;
3
3
  use heck::{AsPascalCase, AsSnakeCase};
4
4
  use serde::{Deserialize, Serialize};
5
5
 
6
- use crate::codegen::{sanitize_keyword, LanguageContext};
6
+ use crate::codegen::{
7
+ build_type_name_map, lookup_type_name, sanitize_keyword, set_type_name_map, LanguageContext,
8
+ };
7
9
  use crate::ir::{
8
- EnumDef, FieldDef, FieldKind, PrimitiveType, RestrictionFacets, SchemaIR, SimpleTypeDef,
10
+ EnumDef, FieldDef, FieldKind, PrimitiveType, QName, RestrictionFacets, SchemaIR, SimpleTypeDef,
9
11
  StructDef, TypeDef, TypeRef, UnionDef,
10
12
  };
11
13
 
@@ -124,7 +126,7 @@ impl LanguageContext for GoLanguageContext {
124
126
  fn map_type_ref(&self, type_ref: &TypeRef) -> String {
125
127
  match type_ref {
126
128
  TypeRef::Primitive(prim) => self.map_primitive(*prim).to_string(),
127
- TypeRef::Named(qname) => to_go_type_name(&qname.local),
129
+ TypeRef::Named(qname) => type_ident(qname),
128
130
  TypeRef::Boxed(inner) => format!("*{}", self.map_type_ref(inner)),
129
131
  TypeRef::List(inner) => format!("[]{}", self.map_type_ref(inner)),
130
132
  }
@@ -231,6 +233,12 @@ pub struct GoCodegen {
231
233
  context: GoLanguageContext,
232
234
  }
233
235
 
236
+ /// Emitted Go identifier for a named type, disambiguated across namespaces
237
+ /// for the IR currently being generated (issue #51 item 3).
238
+ fn type_ident(q: &QName) -> String {
239
+ lookup_type_name(q, || to_go_type_name(&q.local))
240
+ }
241
+
234
242
  impl GoCodegen {
235
243
  pub fn new(options: GoOptions) -> Self {
236
244
  Self {
@@ -241,6 +249,7 @@ impl GoCodegen {
241
249
 
242
250
  /// Generate complete Go module content.
243
251
  pub fn generate_module(&self, ir: &SchemaIR) -> String {
252
+ set_type_name_map(build_type_name_map(ir, to_go_type_name));
244
253
  let mut body = String::new();
245
254
  let mut has_time = false;
246
255
  let mut has_fmt = false;
@@ -394,13 +403,13 @@ impl GoCodegen {
394
403
  }
395
404
  }
396
405
 
397
- let type_name = to_go_type_name(&simple.qname.local);
406
+ let type_name = type_ident(&simple.qname);
398
407
  let base_type = self.context.map_type_ref(&simple.base_type);
399
408
  writeln!(out, "type {} {}\n", type_name, base_type).unwrap();
400
409
  }
401
410
 
402
411
  fn emit_enum(&self, out: &mut String, enum_def: &EnumDef) {
403
- let enum_name = to_go_type_name(&enum_def.qname.local);
412
+ let enum_name = type_ident(&enum_def.qname);
404
413
  if let Some(ref doc) = enum_def.documentation {
405
414
  for line in doc.lines() {
406
415
  writeln!(out, "// {}", line).unwrap();
@@ -441,7 +450,7 @@ impl GoCodegen {
441
450
  }
442
451
 
443
452
  fn emit_union(&self, out: &mut String, u: &UnionDef) {
444
- let choice_name = to_go_type_name(&u.qname.local);
453
+ let choice_name = type_ident(&u.qname);
445
454
  if let Some(ref doc) = u.documentation {
446
455
  for line in doc.lines() {
447
456
  writeln!(out, "// {}", line).unwrap();
@@ -587,7 +596,7 @@ impl GoCodegen {
587
596
  }
588
597
 
589
598
  fn emit_struct(&self, out: &mut String, s: &StructDef, ir: &SchemaIR) {
590
- let struct_name = to_go_type_name(&s.qname.local);
599
+ let struct_name = type_ident(&s.qname);
591
600
  if let Some(ref doc) = s.documentation {
592
601
  for line in doc.lines() {
593
602
  writeln!(out, "// {}", line).unwrap();
@@ -620,12 +629,12 @@ impl GoCodegen {
620
629
  let mut simple_content_base: Option<String> = None;
621
630
  if let Some(ref base_qname) = s.base_type {
622
631
  if matches!(ir.types.get(base_qname), Some(TypeDef::Struct(_))) {
623
- let base_name = to_go_type_name(&base_qname.local);
632
+ let base_name = type_ident(base_qname);
624
633
  writeln!(out, " {}", base_name).unwrap();
625
634
  } else if let Some(prim) = PrimitiveType::from_xsd_name(&base_qname.local) {
626
635
  simple_content_base = Some(self.context.map_primitive(prim).to_string());
627
636
  } else if let Some(TypeDef::Simple(st)) = ir.types.get(base_qname) {
628
- simple_content_base = Some(to_go_type_name(&st.qname.local));
637
+ simple_content_base = Some(type_ident(&st.qname));
629
638
  }
630
639
  }
631
640
 
@@ -744,7 +753,7 @@ impl GoCodegen {
744
753
  }
745
754
 
746
755
  fn emit_struct_validator(&self, out: &mut String, s: &StructDef) {
747
- let struct_name = to_go_type_name(&s.qname.local);
756
+ let struct_name = type_ident(&s.qname);
748
757
  writeln!(out, "func (s {}) Validate() error {{", struct_name).unwrap();
749
758
 
750
759
  let mut has_checks = false;
@@ -20,13 +20,9 @@ impl JavaCodegen {
20
20
  _ => Ok(()),
21
21
  }
22
22
  }
23
- let names: HashSet<_> = ir
24
- .types
25
- .values()
26
- .map(|d| to_java_type_name(&d.qname().local))
27
- .collect();
23
+ let names: HashSet<_> = ir.types.values().map(|d| type_ident(d.qname())).collect();
28
24
  for def in ir.types.values() {
29
- let name = to_java_type_name(&def.qname().local);
25
+ let name = type_ident(def.qname());
30
26
  if names.contains(&format!("{name}Codec")) {
31
27
  return Err(format!(
32
28
  "direct codec name {name}Codec collides with a schema type"
@@ -70,7 +66,7 @@ impl JavaCodegen {
70
66
  }
71
67
 
72
68
  pub(super) fn generate_codec(&self, def: &TypeDef, ir: &SchemaIR) -> String {
73
- let name = to_java_type_name(&def.qname().local);
69
+ let name = type_ident(def.qname());
74
70
  let mut out = String::new();
75
71
  self.emit_file_header(&mut out);
76
72
  out.push_str("import javax.xml.stream.*;\nimport java.io.*;\n\n");
@@ -224,7 +220,7 @@ impl JavaCodegen {
224
220
  }
225
221
 
226
222
  fn emit_read_struct(&self, out: &mut String, s: &StructDef, ir: &SchemaIR) {
227
- let name = to_java_type_name(&s.qname.local);
223
+ let name = type_ident(&s.qname);
228
224
  if s.is_abstract && !self.options.use_records {
229
225
  out.push_str(" throw new XMLStreamException(\"Cannot instantiate abstract XML type without a concrete codec\");\n");
230
226
  return;
@@ -400,7 +396,7 @@ impl JavaCodegen {
400
396
  self.emit_write_value(out, inner, value, local, ns, ir, indent)
401
397
  }
402
398
  TypeRef::Named(q) => {
403
- let name = to_java_type_name(&q.local);
399
+ let name = type_ident(q);
404
400
  let _ = writeln!(
405
401
  out,
406
402
  "{indent}{name}Codec.writeXml({value}, writer, {local:?}, {ns:?});"
@@ -415,7 +411,7 @@ impl JavaCodegen {
415
411
 
416
412
  fn read_value(&self, ty: &TypeRef, ir: &SchemaIR) -> String {
417
413
  match ty {
418
- TypeRef::Named(q) => format!("{}Codec.readXml(reader)", to_java_type_name(&q.local)),
414
+ TypeRef::Named(q) => format!("{}Codec.readXml(reader)", type_ident(q)),
419
415
  TypeRef::Boxed(t) => self.read_value(t, ir),
420
416
  _ => self.parse_scalar(ty, "reader.getElementText()", ir),
421
417
  }
@@ -431,11 +427,11 @@ impl JavaCodegen {
431
427
  }
432
428
  TypeRef::Named(q) => match ir.types.get(q) {
433
429
  Some(TypeDef::Enum(_)) => {
434
- format!("{}.fromValue({raw})", to_java_type_name(&q.local))
430
+ format!("{}.fromValue({raw})", type_ident(q))
435
431
  }
436
432
  Some(TypeDef::Simple(s)) => format!(
437
433
  "new {}({})",
438
- to_java_type_name(&q.local),
434
+ type_ident(q),
439
435
  self.parse_scalar(&s.base_type, raw, ir)
440
436
  ),
441
437
  _ => "null".into(),
@@ -7,9 +7,11 @@ use std::fmt::Write as FmtWrite;
7
7
  use heck::{AsLowerCamelCase, AsPascalCase, AsShoutySnakeCase};
8
8
  use serde::{Deserialize, Serialize};
9
9
 
10
- use crate::codegen::{sanitize_keyword, LanguageContext};
10
+ use crate::codegen::{
11
+ build_type_name_map, lookup_type_name, sanitize_keyword, set_type_name_map, LanguageContext,
12
+ };
11
13
  use crate::ir::{
12
- EnumDef, PrimitiveType, RestrictionFacets, SchemaIR, SimpleTypeDef, StructDef, TypeDef,
14
+ EnumDef, PrimitiveType, QName, RestrictionFacets, SchemaIR, SimpleTypeDef, StructDef, TypeDef,
13
15
  TypeRef, UnionDef,
14
16
  };
15
17
 
@@ -134,7 +136,7 @@ impl LanguageContext for JavaLanguageContext {
134
136
  fn map_type_ref(&self, type_ref: &TypeRef) -> String {
135
137
  match type_ref {
136
138
  TypeRef::Primitive(prim) => self.map_primitive(*prim).to_string(),
137
- TypeRef::Named(qname) => to_java_type_name(&qname.local),
139
+ TypeRef::Named(qname) => type_ident(qname),
138
140
  TypeRef::Boxed(inner) | TypeRef::List(inner) => {
139
141
  let inner_str = self.boxed_type(inner);
140
142
  if matches!(type_ref, TypeRef::List(_)) {
@@ -172,7 +174,7 @@ impl JavaLanguageContext {
172
174
  PrimitiveType::Base64Binary | PrimitiveType::HexBinary => "byte[]".to_string(),
173
175
  _ => self.map_primitive(*prim).to_string(),
174
176
  },
175
- TypeRef::Named(qname) => to_java_type_name(&qname.local),
177
+ TypeRef::Named(qname) => type_ident(qname),
176
178
  TypeRef::Boxed(inner) => self.boxed_type(inner),
177
179
  TypeRef::List(inner) => format!("java.util.List<{}>", self.boxed_type(inner)),
178
180
  }
@@ -205,6 +207,12 @@ pub fn to_java_type_name(name: &str) -> String {
205
207
  sanitize_keyword(&sanitized, "java")
206
208
  }
207
209
 
210
+ /// Emitted Java identifier for a named type, disambiguated across
211
+ /// namespaces for the IR currently being generated (issue #51 item 3).
212
+ pub(super) fn type_ident(q: &QName) -> String {
213
+ lookup_type_name(q, || to_java_type_name(&q.local))
214
+ }
215
+
208
216
  /// Convert an XML enumeration variant name to SCREAMING_SNAKE_CASE for Java enum constants.
209
217
  pub fn to_java_enum_constant(name: &str) -> String {
210
218
  let raw = AsShoutySnakeCase(name).to_string();
@@ -234,6 +242,7 @@ impl JavaCodegen {
234
242
 
235
243
  /// Generate individual compilation units (`{TypeName}.java`), one for each schema type.
236
244
  pub fn generate_files(&self, ir: &SchemaIR) -> Vec<(String, String)> {
245
+ set_type_name_map(build_type_name_map(ir, to_java_type_name));
237
246
  let mut files = Vec::new();
238
247
 
239
248
  for type_def in ir.types.values() {
@@ -253,6 +262,7 @@ impl JavaCodegen {
253
262
 
254
263
  /// Generate a single outer class (`{outer_class_name}.java`) enclosing all types as static members.
255
264
  pub fn generate_module(&self, ir: &SchemaIR, outer_class_name: &str) -> String {
265
+ set_type_name_map(build_type_name_map(ir, to_java_type_name));
256
266
  let mut out = String::new();
257
267
 
258
268
  self.emit_file_header(&mut out);
@@ -368,22 +378,22 @@ impl JavaCodegen {
368
378
  let mut out = String::new();
369
379
  let type_name = match type_def {
370
380
  TypeDef::Struct(s) => {
371
- let name = to_java_type_name(&s.qname.local);
381
+ let name = type_ident(&s.qname);
372
382
  self.emit_struct(&mut out, s, &name, indent, ir);
373
383
  name
374
384
  }
375
385
  TypeDef::Enum(e) => {
376
- let name = to_java_type_name(&e.qname.local);
386
+ let name = type_ident(&e.qname);
377
387
  self.emit_enum(&mut out, e, &name, indent);
378
388
  name
379
389
  }
380
390
  TypeDef::Union(u) => {
381
- let name = to_java_type_name(&u.qname.local);
391
+ let name = type_ident(&u.qname);
382
392
  self.emit_union(&mut out, u, &name, indent);
383
393
  name
384
394
  }
385
395
  TypeDef::Simple(s) => {
386
- let name = to_java_type_name(&s.qname.local);
396
+ let name = type_ident(&s.qname);
387
397
  self.emit_simple(&mut out, s, &name, indent);
388
398
  name
389
399
  }
@@ -160,7 +160,7 @@ impl JavaCodegen {
160
160
  .as_ref()
161
161
  .filter(|q| matches!(ir.types.get(q), Some(TypeDef::Struct(_))));
162
162
  let extends = base
163
- .map(|q| format!(" extends {}", to_java_type_name(&q.local)))
163
+ .map(|q| format!(" extends {}", type_ident(q)))
164
164
  .unwrap_or_default();
165
165
  let nested = if indent.is_empty() { "" } else { "static " };
166
166
  let abstract_kw = if s.is_abstract { "abstract " } else { "" };
@@ -258,7 +258,7 @@ impl JavaCodegen {
258
258
  };
259
259
  let extends = base
260
260
  .map(|q| {
261
- let n = to_java_type_name(&q.local);
261
+ let n = type_ident(q);
262
262
  format!(" extends {n}.{n}Builder")
263
263
  })
264
264
  .unwrap_or_default();