Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add C# Support #155

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub enum AvailableLanguage {
Go,
#[cfg(feature = "python")]
Python,
CSharp,
}

#[derive(clap::Parser)]
Expand Down Expand Up @@ -49,6 +50,10 @@ pub struct Args {
#[arg(long)]
pub scala_package: Option<String>,

/// CSharp namespace
#[arg(long)]
pub csharp_namespace: Option<String>,

/// Scala serializer module name
#[arg(long)]
pub scala_module_name: Option<String>,
Expand Down
11 changes: 10 additions & 1 deletion cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,15 @@ pub struct GoParams {
pub type_mappings: HashMap<String, String>,
}

/// The parameters that are used to configure the behaviour of typeshare
#[derive(Default, Serialize, Deserialize, PartialEq, Eq, Debug)]
#[serde(default)]
pub struct CSharpParams {
pub type_mappings: HashMap<String, String>,
pub namespace: String,
pub without_csharp_naming_convention: bool,
}

/// The paramters that are used to configure the behaviour of typeshare
/// from the configuration file `typeshare.toml`
#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
#[serde(default)]
Expand All @@ -77,6 +85,7 @@ pub(crate) struct Config {
pub go: GoParams,
#[serde(skip)]
pub target_os: Vec<String>,
pub csharp: CSharpParams,
}

pub(crate) fn store_config(config: &Config, file_path: Option<&Path>) -> anyhow::Result<()> {
Expand Down
13 changes: 12 additions & 1 deletion cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use typeshare_core::language::Go;
use typeshare_core::language::Python;
use typeshare_core::{
context::ParseContext,
language::{CrateName, Kotlin, Language, Scala, SupportedLanguage, Swift, TypeScript},
language::{CSharp, CrateName, Kotlin, Language, Scala, SupportedLanguage, Swift, TypeScript},
parser::ParsedData,
reconcile::reconcile_aliases,
};
Expand Down Expand Up @@ -95,6 +95,7 @@ fn generate_types(config_file: Option<&Path>, options: &Args) -> anyhow::Result<
args::AvailableLanguage::Go => SupportedLanguage::Go,
#[cfg(feature = "python")]
args::AvailableLanguage::Python => SupportedLanguage::Python,
args::AvailableLanguage::CSharp => SupportedLanguage::CSharp,
},
};

Expand Down Expand Up @@ -212,6 +213,12 @@ fn language(
type_mappings: config.typescript.type_mappings,
..Default::default()
}),
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()
}),
#[cfg(feature = "go")]
SupportedLanguage::Go => Box::new(Go {
package: config.go.package,
Expand Down Expand Up @@ -262,6 +269,10 @@ fn override_configuration(mut config: Config, options: &Args) -> anyhow::Result<
config.scala.module_name = scala_module_name.to_string();
}

if let Some(csharp_namespace) = options.csharp_namespace.as_ref() {
config.csharp.namespace = csharp_namespace.to_string();
}

#[cfg(feature = "go")]
{
if let Some(go_package) = options.go_package.as_ref() {
Expand Down
1 change: 1 addition & 0 deletions cli/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ fn output_file_name(language_type: SupportedLanguage, crate_name: &CrateName) ->
SupportedLanguage::Swift => pascal_case(),
SupportedLanguage::TypeScript => snake_case(),
SupportedLanguage::Python => snake_case(),
SupportedLanguage::CSharp => pascal_case(),
}
}

Expand Down
45 changes: 45 additions & 0 deletions core/data/tests/anonymous_struct_with_rename/output.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#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 {
[JsonProperty(Required = Required.Always)]
public IEnumerable<string> list { get; set; }
}

/** Generated type representing the anonymous struct variant `LongFieldNames` of the `AnonymousStructWithRename` Rust enum */
public class AnonymousStructWithRenameLongFieldNamesInner {
[JsonProperty(Required = Required.Always)]
public string some_long_field_name { get; set; }
[JsonProperty(Required = Required.Always)]
public bool and { get; set; }
[JsonProperty(Required = Required.Always)]
public IEnumerable<string> but_one_more { get; set; }
}

/** Generated type representing the anonymous struct variant `KebabCase` of the `AnonymousStructWithRename` Rust enum */
public class AnonymousStructWithRenameKebabCaseInner {
[JsonProperty(Required = Required.Always)]
public IEnumerable<string> another-list { get; set; }
[JsonProperty(Required = Required.Always)]
public string camelCaseStringField { get; set; }
[JsonProperty(Required = Required.Always)]
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();
}


30 changes: 30 additions & 0 deletions core/data/tests/can_apply_prefix_correctly/output.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#nullable enable

using System.Reflection;
using JsonSubTypes;
using Newtonsoft.Json;
using System.Runtime.Serialization;

public class ItemDetailsFieldValue {
[JsonProperty(Required = Required.Always)]
public string Hello { get; set; }
}

[JsonConverter(typeof(JsonSubtypes), "t")]
[JsonSubtypes.KnownSubType(typeof(String), "String")]
[JsonSubtypes.KnownSubType(typeof(Number), "Number")]
[JsonSubtypes.KnownSubType(typeof(NumberArray), "NumberArray")]
[JsonSubtypes.KnownSubType(typeof(ReallyCoolType), "ReallyCoolType")]
[JsonSubtypes.KnownSubType(typeof(ArrayReallyCoolType), "ArrayReallyCoolType")]
[JsonSubtypes.KnownSubType(typeof(DictionaryReallyCoolType), "DictionaryReallyCoolType")]
public abstract record AdvancedColors
{
public record String(string C) : AdvancedColors();
public record Number(int C) : AdvancedColors();
public record NumberArray(IEnumerable<int> C) : AdvancedColors();
public record ReallyCoolType(ItemDetailsFieldValue C) : AdvancedColors();
public record ArrayReallyCoolType(IEnumerable<ItemDetailsFieldValue> C) : AdvancedColors();
public record DictionaryReallyCoolType(IDictionary<string, ItemDetailsFieldValue> C) : AdvancedColors();
}


48 changes: 48 additions & 0 deletions core/data/tests/can_generate_algebraic_enum/output.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#nullable enable

using System.Reflection;
using JsonSubTypes;
using Newtonsoft.Json;
using System.Runtime.Serialization;

namespace Company.Domain.Models;

/** Struct comment */
public class ItemDetailsFieldValue {
}

/** Enum comment */
[JsonConverter(typeof(JsonSubtypes), "type")]
[JsonSubtypes.KnownSubType(typeof(String), "String")]
[JsonSubtypes.KnownSubType(typeof(Number), "Number")]
[JsonSubtypes.KnownSubType(typeof(UnsignedNumber), "UnsignedNumber")]
[JsonSubtypes.KnownSubType(typeof(NumberArray), "NumberArray")]
[JsonSubtypes.KnownSubType(typeof(ReallyCoolType), "ReallyCoolType")]
public abstract record AdvancedColors
{
/** This is a case comment */
public record String(string Content) : AdvancedColors();
public record Number(int Content) : AdvancedColors();
public record UnsignedNumber(uint Content) : AdvancedColors();
public record NumberArray(IEnumerable<int> Content) : AdvancedColors();
/** Comment on the last element */
public record ReallyCoolType(ItemDetailsFieldValue Content) : AdvancedColors();
}


[JsonConverter(typeof(JsonSubtypes), "type")]
[JsonSubtypes.KnownSubType(typeof(String), "string")]
[JsonSubtypes.KnownSubType(typeof(Number), "number")]
[JsonSubtypes.KnownSubType(typeof(NumberArray), "number-array")]
[JsonSubtypes.KnownSubType(typeof(ReallyCoolType), "really-cool-type")]
public abstract record AdvancedColors2
{
/** This is a case comment */
public record String(string Content) : AdvancedColors2();
public record Number(int Content) : AdvancedColors2();
public record NumberArray(IEnumerable<int> Content) : AdvancedColors2();
/** Comment on the last element */
public record ReallyCoolType(ItemDetailsFieldValue Content) : AdvancedColors2();
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#nullable enable

using System.Reflection;
using JsonSubTypes;
using Newtonsoft.Json;
using System.Runtime.Serialization;

[JsonConverter(typeof(JsonSubtypes), "type")]
[JsonSubtypes.KnownSubType(typeof(A), "A")]
[JsonSubtypes.KnownSubType(typeof(C), "C")]
public abstract record SomeEnum
{
public record A(): SomeEnum();
public record C(int Content) : SomeEnum();
}


18 changes: 18 additions & 0 deletions core/data/tests/can_generate_bare_string_enum/output.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#nullable enable

using System.Reflection;
using JsonSubTypes;
using Newtonsoft.Json;
using System.Runtime.Serialization;

/** This is a comment. */
public enum Colors
{
Red,

Blue,

Green,

}

20 changes: 20 additions & 0 deletions core/data/tests/can_generate_empty_algebraic_enum/output.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#nullable enable

using System.Reflection;
using JsonSubTypes;
using Newtonsoft.Json;
using System.Runtime.Serialization;

public class AddressDetails {
}

[JsonConverter(typeof(JsonSubtypes), "type")]
[JsonSubtypes.KnownSubType(typeof(FixedAddress), "FixedAddress")]
[JsonSubtypes.KnownSubType(typeof(NoFixedAddress), "NoFixedAddress")]
public abstract record Address
{
public record FixedAddress(AddressDetails Content) : Address();
public record NoFixedAddress(): Address();
}


76 changes: 76 additions & 0 deletions core/data/tests/can_generate_generic_enum/output.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#nullable enable

using System.Reflection;
using JsonSubTypes;
using Newtonsoft.Json;
using System.Runtime.Serialization;

[JsonConverter(typeof(JsonSubtypes), "type")]
[JsonSubtypes.KnownSubType(typeof(VariantA), "VariantA")]
[JsonSubtypes.KnownSubType(typeof(VariantB), "VariantB")]
public abstract record GenericEnum<TA, TB>
{
public record VariantA(TA Content) : GenericEnum<TA, TB>();
public record VariantB(TB Content) : GenericEnum<TA, TB>();
}


public class StructUsingGenericEnum {
[JsonProperty(Required = Required.Always)]
public GenericEnum<string, short> EnumField { get; set; }
}

[JsonConverter(typeof(JsonSubtypes), "type")]
[JsonSubtypes.KnownSubType(typeof(VariantC), "VariantC")]
[JsonSubtypes.KnownSubType(typeof(VariantD), "VariantD")]
[JsonSubtypes.KnownSubType(typeof(VariantE), "VariantE")]
public abstract record GenericEnumUsingGenericEnum<T>
{
public record VariantC(GenericEnum<T, T> Content) : GenericEnumUsingGenericEnum<T>();
public record VariantD(GenericEnum<string, IDictionary<string, T>> Content) : GenericEnumUsingGenericEnum<T>();
public record VariantE(GenericEnum<string, uint> Content) : GenericEnumUsingGenericEnum<T>();
}


/** Generated type representing the anonymous struct variant `VariantF` of the `GenericEnumsUsingStructVariants` Rust enum */
public class GenericEnumsUsingStructVariantsVariantFInner<T> {
[JsonProperty(Required = Required.Always)]
public T Action { get; set; }
}

/** Generated type representing the anonymous struct variant `VariantG` of the `GenericEnumsUsingStructVariants` Rust enum */
public class GenericEnumsUsingStructVariantsVariantGInner<T, TU> {
[JsonProperty(Required = Required.Always)]
public T Action { get; set; }
[JsonProperty(Required = Required.Always)]
public TU Response { get; set; }
}

/** Generated type representing the anonymous struct variant `VariantH` of the `GenericEnumsUsingStructVariants` Rust enum */
public class GenericEnumsUsingStructVariantsVariantHInner {
[JsonProperty(Required = Required.Always)]
public int NonGeneric { get; set; }
}

/** Generated type representing the anonymous struct variant `VariantI` of the `GenericEnumsUsingStructVariants` Rust enum */
public class GenericEnumsUsingStructVariantsVariantIInner<T, TU> {
[JsonProperty(Required = Required.Always)]
public IEnumerable<T> Vec { get; set; }
[JsonProperty(Required = Required.Always)]
public MyType<T, TU> Action { get; set; }
}

[JsonConverter(typeof(JsonSubtypes), "type")]
[JsonSubtypes.KnownSubType(typeof(VariantF), "VariantF")]
[JsonSubtypes.KnownSubType(typeof(VariantG), "VariantG")]
[JsonSubtypes.KnownSubType(typeof(VariantH), "VariantH")]
[JsonSubtypes.KnownSubType(typeof(VariantI), "VariantI")]
public abstract record GenericEnumsUsingStructVariants<T, TU>
{
public record VariantF(GenericEnumsUsingStructVariantsVariantFInner<T> Content): GenericEnumsUsingStructVariants<T, TU>();
public record VariantG(GenericEnumsUsingStructVariantsVariantGInner<T, TU> Content): GenericEnumsUsingStructVariants<T, TU>();
public record VariantH(GenericEnumsUsingStructVariantsVariantHInner Content): GenericEnumsUsingStructVariants<T, TU>();
public record VariantI(GenericEnumsUsingStructVariantsVariantIInner<T, TU> Content): GenericEnumsUsingStructVariants<T, TU>();
}


12 changes: 12 additions & 0 deletions core/data/tests/can_generate_readonly_fields/output.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#nullable enable

using System.Reflection;
using JsonSubTypes;
using Newtonsoft.Json;
using System.Runtime.Serialization;

public class SomeStruct {
[JsonProperty(Required = Required.Always)]
public uint FieldA { get; set; }
}

22 changes: 22 additions & 0 deletions core/data/tests/can_generate_simple_enum/output.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#nullable enable

using System.Reflection;
using JsonSubTypes;
using Newtonsoft.Json;
using System.Runtime.Serialization;

/**
* This is a comment.
* Continued lovingly here
*/
public enum Colors
{
Red,

Blue,

/** Green is a cool color */
Green,

}

Loading