Skip to content

Commit

Permalink
Merge pull request #173 from darrell-roberts/swift-decorators-generics
Browse files Browse the repository at this point in the history
Allow swift decorator constraints to apply to generics

Support CSharp

Create basic language implementation.
Start adding tests.

Add snapshot tests

Update slice type to map to IEnumerable instead of Array.
Drop support for Unit type and return an error.

Support anonymous structs

Update slice of user type test snapshot

Support namespace option

Support serialization with json attributes

Remove EnumLabel and use EnumMember attribute instead.
Update all test snapshots according to the new changes.

C# without naming convention option

Add required attribute

For newtonsoft json to require a non optional property, the property has
to have the required attribute. Otherwise, it allows it to be null and a
default value is provided.
  • Loading branch information
charlespierce authored and dandro committed Jun 5, 2024
2 parents 2262a56 + 9950499 commit 33dfda7
Show file tree
Hide file tree
Showing 50 changed files with 1,556 additions and 54 deletions.
13 changes: 10 additions & 3 deletions cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ pub const ARG_SCALA_PACKAGE: &str = "SCALAPACKAGE";
pub const ARG_SCALA_MODULE_NAME: &str = "SCALAMODULENAME";
#[cfg(feature = "go")]
pub const ARG_GO_PACKAGE: &str = "GOPACKAGE";
pub const ARG_CSHARP_NAMESPACE: &str = "CSHARP_NAMESPACE";
pub const ARG_CONFIG_FILE_NAME: &str = "CONFIGFILENAME";
pub const ARG_GENERATE_CONFIG: &str = "generate-config-file";
pub const ARG_OUTPUT_FILE: &str = "output-file";
pub const ARG_OUTPUT_FOLDER: &str = "output-folder";
pub const ARG_FOLLOW_LINKS: &str = "follow-links";

#[cfg(feature = "go")]
const AVAILABLE_LANGUAGES: [&str; 5] = ["kotlin", "scala", "swift", "typescript", "go"];
const AVAILABLE_LANGUAGES: [&str; 6] = ["kotlin", "scala", "swift", "typescript", "go", "csharp"];

#[cfg(not(feature = "go"))]
const AVAILABLE_LANGUAGES: [&str; 4] = ["kotlin", "scala", "swift", "typescript"];
const AVAILABLE_LANGUAGES: [&str; 5] = ["kotlin", "scala", "swift", "typescript", "csharp"];

/// Parse command line arguments.
pub(crate) fn build_command() -> Command<'static> {
Expand Down Expand Up @@ -96,7 +97,13 @@ pub(crate) fn build_command() -> Command<'static> {
.takes_value(true)
.required(false),
)

.arg(
Arg::new(ARG_CSHARP_NAMESPACE)
.long("namespace")
.help("C# namespace")
.takes_value(true)
.required(false)
)
.arg(
Arg::new(ARG_CONFIG_FILE_NAME)
.short('c')
Expand Down
9 changes: 9 additions & 0 deletions cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ pub struct GoParams {
pub uppercase_acronyms: Vec<String>,
}

#[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)]
Expand All @@ -62,6 +70,7 @@ pub(crate) struct Config {
pub scala: ScalaParams,
#[cfg(feature = "go")]
pub go: GoParams,
pub csharp: CSharpParams,
}

pub(crate) fn store_config(config: &Config, file_path: Option<&str>) -> anyhow::Result<()> {
Expand Down
18 changes: 14 additions & 4 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

use anyhow::{anyhow, Context};
use args::{
build_command, ARG_CONFIG_FILE_NAME, ARG_FOLLOW_LINKS, ARG_GENERATE_CONFIG, ARG_JAVA_PACKAGE,
ARG_KOTLIN_PREFIX, ARG_MODULE_NAME, ARG_OUTPUT_FOLDER, ARG_SCALA_MODULE_NAME,
ARG_SCALA_PACKAGE, ARG_SWIFT_PREFIX, ARG_TYPE,
build_command, ARG_CONFIG_FILE_NAME, ARG_CSHARP_NAMESPACE, ARG_FOLLOW_LINKS,
ARG_GENERATE_CONFIG, ARG_JAVA_PACKAGE, ARG_KOTLIN_PREFIX, ARG_MODULE_NAME, ARG_OUTPUT_FOLDER,
ARG_SCALA_MODULE_NAME, ARG_SCALA_PACKAGE, ARG_SWIFT_PREFIX, ARG_TYPE,
};
use clap::ArgMatches;
use config::Config;
Expand All @@ -16,7 +16,7 @@ use std::collections::HashMap;
use typeshare_core::language::Go;
use typeshare_core::{
language::{
CrateName, GenericConstraints, Kotlin, Language, Scala, SupportedLanguage, Swift,
CSharp, CrateName, GenericConstraints, Kotlin, Language, Scala, SupportedLanguage, Swift,
TypeScript,
},
parser::ParsedData,
Expand Down Expand Up @@ -165,6 +165,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 @@ -205,6 +211,10 @@ fn override_configuration(mut config: Config, options: &ArgMatches) -> Config {
config.scala.module_name = scala_module_name.to_string();
}

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

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

Expand Down
38 changes: 38 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,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<string> 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<string> but_one_more { get; set; }
}

/** Generated type representing the anonymous struct variant `KebabCase` of the `AnonymousStructWithRename` Rust enum */
public class AnonymousStructWithRenameKebabCaseInner {
public IEnumerable<string> 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();
}


29 changes: 29 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,29 @@
#nullable enable

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

public class ItemDetailsFieldValue {
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), "NumberArray")]
[JsonSubtypes.KnownSubType(typeof(ReallyCoolType), "ReallyCoolType")]
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();
}


69 changes: 69 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,69 @@
#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 {
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> {
public T Action { get; set; }
}

/** Generated type representing the anonymous struct variant `VariantG` of the `GenericEnumsUsingStructVariants` Rust enum */
public class GenericEnumsUsingStructVariantsVariantGInner<T, TU> {
public T Action { get; set; }
public TU Response { get; set; }
}

/** Generated type representing the anonymous struct variant `VariantH` of the `GenericEnumsUsingStructVariants` Rust enum */
public class GenericEnumsUsingStructVariantsVariantHInner {
public int NonGeneric { get; set; }
}

/** Generated type representing the anonymous struct variant `VariantI` of the `GenericEnumsUsingStructVariants` Rust enum */
public class GenericEnumsUsingStructVariantsVariantIInner<T, TU> {
public IEnumerable<T> Vec { get; set; }
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>();
}


11 changes: 11 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,11 @@
#nullable enable

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

public class SomeStruct {
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

0 comments on commit 33dfda7

Please sign in to comment.