diff --git a/cli/src/config.rs b/cli/src/config.rs index d726f018..1cb4544b 100644 --- a/cli/src/config.rs +++ b/cli/src/config.rs @@ -54,6 +54,7 @@ pub struct GoParams { pub struct CSharpParams { pub type_mappings: HashMap, pub namespace: String, + pub without_csharp_naming_convention: bool, } /// The paramters that are used to configure the behaviour of typeshare diff --git a/cli/src/main.rs b/cli/src/main.rs index 39fdd568..9e114b6b 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -237,6 +237,7 @@ fn main() { Some(SupportedLanguage::CSharp) => Box::new(CSharp { namespace: config.csharp.namespace, type_mappings: config.csharp.type_mappings, + without_csharp_naming_convention: config.csharp.without_csharp_naming_convention, ..Default::default() }), _ => { diff --git a/core/data/tests/anonymous_struct_with_rename/output.cs b/core/data/tests/anonymous_struct_with_rename/output.cs new file mode 100644 index 00000000..d4e2f2da --- /dev/null +++ b/core/data/tests/anonymous_struct_with_rename/output.cs @@ -0,0 +1,38 @@ +#nullable enable + +using System.Reflection; +using JsonSubTypes; +using Newtonsoft.Json; +using System.Runtime.Serialization; + +/** Generated type representing the anonymous struct variant `List` of the `AnonymousStructWithRename` Rust enum */ +public class AnonymousStructWithRenameListInner { + public IEnumerable list { get; set; } +} + +/** Generated type representing the anonymous struct variant `LongFieldNames` of the `AnonymousStructWithRename` Rust enum */ +public class AnonymousStructWithRenameLongFieldNamesInner { + public string some_long_field_name { get; set; } + public bool and { get; set; } + public IEnumerable but_one_more { get; set; } +} + +/** Generated type representing the anonymous struct variant `KebabCase` of the `AnonymousStructWithRename` Rust enum */ +public class AnonymousStructWithRenameKebabCaseInner { + public IEnumerable another-list { get; set; } + public string camelCaseStringField { get; set; } + public bool something-else { get; set; } +} + +[JsonConverter(typeof(JsonSubtypes), "type")] +[JsonSubtypes.KnownSubType(typeof(List), "List")] +[JsonSubtypes.KnownSubType(typeof(LongFieldNames), "LongFieldNames")] +[JsonSubtypes.KnownSubType(typeof(KebabCase), "KebabCase")] +public abstract record AnonymousStructWithRename +{ + public record list(AnonymousStructWithRenameListInner Content): AnonymousStructWithRename(); + public record longFieldNames(AnonymousStructWithRenameLongFieldNamesInner Content): AnonymousStructWithRename(); + public record kebabCase(AnonymousStructWithRenameKebabCaseInner Content): AnonymousStructWithRename(); +} + + diff --git a/core/data/tests/can_handle_serde_rename/output.cs b/core/data/tests/can_handle_serde_rename/output.cs new file mode 100644 index 00000000..4d6440d6 --- /dev/null +++ b/core/data/tests/can_handle_serde_rename/output.cs @@ -0,0 +1,20 @@ +#nullable enable + +using System.Reflection; +using JsonSubTypes; +using Newtonsoft.Json; +using System.Runtime.Serialization; + +public class OtherType { +} + +/** This is a comment. */ +public class Person { + public string name { get; set; } + public ushort age { get; set; } + public int extraSpecialFieldOne { get; set; } + public IEnumerable? extraSpecialFieldTwo { get; set; } + public OtherType nonStandardDataType { get; set; } + public IEnumerable? nonStandardDataTypeInArray { get; set; } +} + diff --git a/core/data/tests/can_handle_serde_rename_all/output.cs b/core/data/tests/can_handle_serde_rename_all/output.cs new file mode 100644 index 00000000..584912f7 --- /dev/null +++ b/core/data/tests/can_handle_serde_rename_all/output.cs @@ -0,0 +1,23 @@ +#nullable enable + +using System.Reflection; +using JsonSubTypes; +using Newtonsoft.Json; +using System.Runtime.Serialization; + +/** This is a Person struct with camelCase rename */ +public class Person { + public string firstName { get; set; } + public string lastName { get; set; } + public ushort age { get; set; } + public int extraSpecialField1 { get; set; } + public IEnumerable? extraSpecialField2 { get; set; } +} + +/** This is a Person2 struct with UPPERCASE rename */ +public class Person2 { + public string FIRST_NAME { get; set; } + public string LAST_NAME { get; set; } + public ushort AGE { get; set; } +} + diff --git a/core/data/tests/can_handle_serde_rename_on_top_level/output.cs b/core/data/tests/can_handle_serde_rename_on_top_level/output.cs new file mode 100644 index 00000000..1043375d --- /dev/null +++ b/core/data/tests/can_handle_serde_rename_on_top_level/output.cs @@ -0,0 +1,20 @@ +#nullable enable + +using System.Reflection; +using JsonSubTypes; +using Newtonsoft.Json; +using System.Runtime.Serialization; + +public class OtherType { +} + +/** This is a comment. */ +public class PersonTwo { + public string name { get; set; } + public ushort age { get; set; } + public int extraSpecialFieldOne { get; set; } + public IEnumerable? extraSpecialFieldTwo { get; set; } + public OtherType nonStandardDataType { get; set; } + public IEnumerable? nonStandardDataTypeInArray { get; set; } +} + diff --git a/core/data/tests/can_override_types/output.cs b/core/data/tests/can_override_types/output.cs new file mode 100644 index 00000000..836a61ca --- /dev/null +++ b/core/data/tests/can_override_types/output.cs @@ -0,0 +1,28 @@ +#nullable enable + +using System.Reflection; +using JsonSubTypes; +using Newtonsoft.Json; +using System.Runtime.Serialization; + +public class OverrideStruct { + public char fieldToOverride { get; set; } +} + +/** Generated type representing the anonymous struct variant `AnonymousStructVariant` of the `OverrideEnum` Rust enum */ +public class OverrideEnumAnonymousStructVariantInner { + public char fieldToOverride { get; set; } +} + +[JsonConverter(typeof(JsonSubtypes), "type")] +[JsonSubtypes.KnownSubType(typeof(UnitVariant), "UnitVariant")] +[JsonSubtypes.KnownSubType(typeof(TupleVariant), "TupleVariant")] +[JsonSubtypes.KnownSubType(typeof(AnonymousStructVariant), "AnonymousStructVariant")] +public abstract record OverrideEnum +{ + public record UnitVariant(): OverrideEnum(); + public record TupleVariant(string Content) : OverrideEnum(); + public record AnonymousStructVariant(OverrideEnumAnonymousStructVariantInner Content): OverrideEnum(); +} + + diff --git a/core/data/tests/kebab_case_rename/output.cs b/core/data/tests/kebab_case_rename/output.cs new file mode 100644 index 00000000..b79628e0 --- /dev/null +++ b/core/data/tests/kebab_case_rename/output.cs @@ -0,0 +1,14 @@ +#nullable enable + +using System.Reflection; +using JsonSubTypes; +using Newtonsoft.Json; +using System.Runtime.Serialization; + +/** This is a comment. */ +public class Things { + public string bla { get; set; } + public string? label { get; set; } + public string? label-left { get; set; } +} + diff --git a/core/src/language/csharp.rs b/core/src/language/csharp.rs index e1a7a486..8cfb3e5c 100644 --- a/core/src/language/csharp.rs +++ b/core/src/language/csharp.rs @@ -21,6 +21,8 @@ pub struct CSharp { pub no_version_header: bool, /// Namespace to use in the generated file pub namespace: String, + /// Disable C# property naming convention and follow Serde renaming rules on properties + pub without_csharp_naming_convention: bool, } impl Language for CSharp { @@ -335,12 +337,18 @@ impl CSharp { .filter(|v| v.iter().any(|dec| dec.name() == "readonly")) .is_some(); + let property_name = if self.without_csharp_naming_convention { + field.id.renamed.clone() + } else { + csharp_property_aware_rename(&field.id.renamed) + }; + writeln!( w, "\tpublic {}{} {} {{ get;{} }}", cs_ty, optional.then(|| "?").unwrap_or_default(), - csharp_property_aware_rename(&field.id.renamed), + property_name, if !is_readonly { " set;" } else { "" }, )?; diff --git a/core/src/rust_types.rs b/core/src/rust_types.rs index 4e7e4f4a..e88ffdae 100644 --- a/core/src/rust_types.rs +++ b/core/src/rust_types.rs @@ -378,7 +378,7 @@ pub enum RustTypeFormatError { GenericsForbiddenInGo(String), #[error("Generic type `{0}` cannot be used as a map key in Typescript")] GenericKeyForbiddenInTS(String), - #[error("Type aliases not support in C# 11 or lower")] + #[error("Type aliases are not supported in C# 11 or lower")] TypeAliasesForbiddenInCS(String), #[error("Type Unit is not supported in C#")] TypeUnitInCS(), diff --git a/core/tests/snapshot_tests.rs b/core/tests/snapshot_tests.rs index 3e582994..279dd668 100644 --- a/core/tests/snapshot_tests.rs +++ b/core/tests/snapshot_tests.rs @@ -219,7 +219,9 @@ macro_rules! language_instance { // Default C# (csharp) => { - language_instance!(csharp { }) + language_instance!(csharp { + without_csharp_naming_convention: false, + }) }; // C# with configuration fields forwarded (csharp {$($field:ident: $val:expr),* $(,)?}) => { @@ -480,7 +482,9 @@ tests! { scala, typescript, go, - // csharp, TODO serde renaming ignored when following C# roperty naming convention + csharp { + without_csharp_naming_convention: true, + }, ]; can_override_types: [ swift, @@ -488,7 +492,9 @@ tests! { scala, typescript, go, - // csharp, TODO serde renaming ignored when following C# roperty naming convention + csharp { + without_csharp_naming_convention: true, + }, ]; /// Structs @@ -502,7 +508,9 @@ tests! { scala, typescript, go, - // csharp, TODO serde renaming ignored when following C# roperty naming convention + csharp { + without_csharp_naming_convention: true, + }, ]; // TODO: kotlin and typescript don't appear to support this yet generates_empty_structs_and_initializers: [swift, kotlin, scala, typescript, go, csharp]; @@ -587,7 +595,9 @@ tests! { scala, typescript, go, - // csharp, TODO serde renaming ignored when following C# roperty naming convention + csharp { + without_csharp_naming_convention: true, + }, ]; can_handle_serde_rename_on_top_level: [ swift { prefix: "OP".to_string(), }, @@ -595,7 +605,9 @@ tests! { scala, typescript, go, - // csharp, TODO serde renaming ignored when following C# roperty naming convention + csharp { + without_csharp_naming_convention: true, + }, ]; can_generate_unit_structs: [swift, kotlin, scala, typescript, go, csharp]; kebab_case_rename: [ @@ -604,7 +616,9 @@ tests! { scala, typescript, go, - // csharp, TODO serde renaming ignored when following C# roperty naming convention + csharp { + without_csharp_naming_convention: true, + }, ]; /// Globals get topologically sorted