From 6a3b2cc63915cc4454753c4cb74ead1d7e4d999b Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 17:28:07 +0200 Subject: [PATCH 01/23] Add ContractsGeneratorSettings to RefitGeneratorSettings A new property `ContractsGeneratorSettings` was added to the `RefitGeneratorSettings` class. This change was made to provide customizable settings for generating contracts using NSwag. This enhancement provides users more control over contract generation. --- src/Refitter.Core/RefitGeneratorSettings.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Refitter.Core/RefitGeneratorSettings.cs b/src/Refitter.Core/RefitGeneratorSettings.cs index 32db9ec8..6b26c08b 100644 --- a/src/Refitter.Core/RefitGeneratorSettings.cs +++ b/src/Refitter.Core/RefitGeneratorSettings.cs @@ -4,6 +4,8 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; +using NJsonSchema.CodeGeneration.CSharp; + namespace Refitter.Core; /// @@ -161,6 +163,13 @@ public class RefitGeneratorSettings [JsonPropertyName("dependencyInjectionSettings")] [JsonProperty("dependencyInjectionSettings")] public DependencyInjectionSettings? DependencyInjectionSettings { get; set; } + + /// + /// Gets or sets the settings describing how to generate contracts using NSwag + /// + [JsonPropertyName("contractsGeneratorSettings")] + [JsonProperty("contractsGeneratorSettings")] + public CSharpGeneratorSettings? ContractsGeneratorSettings { get; set; } } /// From 6991505b914641874f15aa0bc91146a0f3b2a3fe Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 17:36:52 +0200 Subject: [PATCH 02/23] Switch JSON deserialization library to System.Text.Json Adjusted the deserialization of JSON files across the project from NewtonSoft.Json to System.Text.Json. The primary changes include adjustments to deserialization methods in "GenerateCommand.cs" and "RefitterSourceGenerator" where weaker camel-case is now used to serialize/deserialize, and property name case insensitivity is allowed. This change also involved removing all attributes related to Newtonsoft's JsonProperty from the "RefitGeneratorSettings.cs". The switch to System.Text.Json provides more native performance benefits and tight integration with the .NET ecosystem. --- src/Refitter.Core/RefitGeneratorSettings.cs | 37 +------------------ .../RefitterSourceGenerator.cs | 17 ++++++--- src/Refitter/GenerateCommand.cs | 8 +++- 3 files changed, 19 insertions(+), 43 deletions(-) diff --git a/src/Refitter.Core/RefitGeneratorSettings.cs b/src/Refitter.Core/RefitGeneratorSettings.cs index 6b26c08b..54abb3e1 100644 --- a/src/Refitter.Core/RefitGeneratorSettings.cs +++ b/src/Refitter.Core/RefitGeneratorSettings.cs @@ -1,9 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; - using NJsonSchema.CodeGeneration.CSharp; namespace Refitter.Core; @@ -18,77 +15,66 @@ public class RefitGeneratorSettings /// Gets or sets the path to the Open API. /// [JsonPropertyName("openApiPath")] - [JsonProperty("openApiPath")] public string OpenApiPath { get; set; } = null!; /// /// Gets or sets the namespace for the generated code. (default: GeneratedCode) /// [JsonPropertyName("namespace")] - [JsonProperty("namespace")] public string Namespace { get; set; } = "GeneratedCode"; /// /// Gets or sets the naming settings. /// [JsonPropertyName("naming")] - [JsonProperty("naming")] public NamingSettings Naming { get; set; } = new(); /// /// Gets or sets a value indicating whether contracts should be generated. /// [JsonPropertyName("generateContracts")] - [JsonProperty("generateContracts")] public bool GenerateContracts { get; set; } = true; /// /// Gets or sets a value indicating whether XML doc comments should be generated. /// [JsonPropertyName("generateXmlDocCodeComments")] - [JsonProperty("generateXmlDocCodeComments")] public bool GenerateXmlDocCodeComments { get; set; } = true; /// /// Gets or sets a value indicating whether to add auto-generated header. /// [JsonPropertyName("addAutoGeneratedHeader")] - [JsonProperty("addAutoGeneratedHeader")] public bool AddAutoGeneratedHeader { get; set; } = true; /// /// Gets or sets a value indicating whether to add accept headers [Headers("Accept: application/json")]. /// [JsonPropertyName("addAcceptHeaders")] - [JsonProperty("addAcceptHeaders")] public bool AddAcceptHeaders { get; set; } = true; /// /// Gets or sets a value indicating whether to return IApiResponse objects. /// [JsonPropertyName("returnIApiResponse")] - [JsonProperty("returnIApiResponse")] public bool ReturnIApiResponse { get; set; } /// /// Gets or sets a value indicating whether to generate operation headers. /// [JsonPropertyName("generateOperationHeaders")] - [JsonProperty("generateOperationHeaders")] public bool GenerateOperationHeaders { get; set; } = true; /// /// Gets or sets the generated type accessibility. (default: Public) /// [JsonPropertyName("typeAccessibility")] - [JsonProperty("typeAccessibility")] public TypeAccessibility TypeAccessibility { get; set; } = TypeAccessibility.Public; /// /// Enable or disable the use of cancellation tokens. /// [JsonPropertyName("useCancellationTokens")] - [JsonProperty("useCancellationTokens")] public bool UseCancellationTokens { get; set; } /// @@ -96,43 +82,37 @@ public class RefitGeneratorSettings /// in ISO 8601 standard date format using delimiters (for example: 2023-06-15) /// [JsonPropertyName("useIsoDateFormat")] - [JsonProperty("useIsoDateFormat")] public bool UseIsoDateFormat { get; set; } /// /// Add additional namespace to generated types /// [JsonPropertyName("additionalNamespaces")] - [JsonProperty("additionalNamespaces")] public string[] AdditionalNamespaces { get; set; } = Array.Empty(); /// /// Set to true to Generate a Refit interface for each endpoint /// [JsonPropertyName("multipleInterfaces")] - [JsonProperty("multipleInterfaces")] - [Newtonsoft.Json.JsonConverter(typeof(StringEnumConverter))] + [JsonConverter(typeof(JsonStringEnumConverter))] public MultipleInterfaces MultipleInterfaces { get; set; } /// /// Set to true to Generate a Refit interface for each endpoint /// [JsonPropertyName("includePathMatches")] - [JsonProperty("includePathMatches")] public string[] IncludePathMatches { get; set; } = Array.Empty(); /// /// Set to true to Generate a Refit interface for each endpoint /// [JsonPropertyName("includeTags")] - [JsonProperty("includeTags")] public string[] IncludeTags { get; set; } = Array.Empty(); /// /// Set to true to generate deprecated operations, otherwise false /// [JsonPropertyName("generateDeprecatedOperations")] - [JsonProperty("generateDeprecatedOperations")] public bool GenerateDeprecatedOperations { get; set; } = true; /// @@ -140,35 +120,30 @@ public class RefitGeneratorSettings /// When using --multiple-interfaces ByEndpoint, this is name of the Execute() method in the interface. /// [JsonPropertyName("operationNameTemplate")] - [JsonProperty("operationNameTemplate")] public string? OperationNameTemplate { get; set; } /// /// Set to true to re-order optional parameters to the end of the parameter list /// [JsonPropertyName("optionalParameters")] - [JsonProperty("optionalParameters")] public bool OptionalParameters { get; set; } /// /// Gets or sets the relative path to a folder in which the output files are generated. (default: ./Generated) /// [JsonPropertyName("outputFolder")] - [JsonProperty("outputFolder")] public string OutputFolder { get; set; } = "./Generated"; /// /// Gets or sets the settings describing how to register generated interface to the .NET Core DI container /// [JsonPropertyName("dependencyInjectionSettings")] - [JsonProperty("dependencyInjectionSettings")] public DependencyInjectionSettings? DependencyInjectionSettings { get; set; } /// /// Gets or sets the settings describing how to generate contracts using NSwag /// [JsonPropertyName("contractsGeneratorSettings")] - [JsonProperty("contractsGeneratorSettings")] public CSharpGeneratorSettings? ContractsGeneratorSettings { get; set; } } @@ -181,7 +156,6 @@ public enum MultipleInterfaces /// Do not generate multiple interfaces /// [JsonPropertyName("unset")] - [JsonProperty("unset")] Unset, /// /// Generate a Refit interface for each endpoint with a single Execute() method. @@ -189,13 +163,11 @@ public enum MultipleInterfaces /// or the operationNameTemplate property in the settings file. /// [JsonPropertyName("byEndpoint")] - [JsonProperty("byEndpoint")] ByEndpoint, /// /// Generate a Refit interface for each tag /// [JsonPropertyName("byTag")] - [JsonProperty("byTag")] ByTag } @@ -209,14 +181,12 @@ public class NamingSettings /// Gets or sets a value indicating whether the OpenApi title should be used. Default is true. /// [JsonPropertyName("useOpenApiTitle")] - [JsonProperty("useOpenApiTitle")] public bool UseOpenApiTitle { get; set; } = true; /// /// Gets or sets the name of the Interface. Default is "ApiClient". /// [JsonPropertyName("interfaceName")] - [JsonProperty("interfaceName")] public string InterfaceName { get; set; } = "ApiClient"; } @@ -246,7 +216,6 @@ public class DependencyInjectionSettings /// Base Address for the HttpClient /// [JsonPropertyName("baseUrl")] - [JsonProperty("baseUrl")] public string? BaseUrl { get; set; } /// @@ -254,27 +223,23 @@ public class DependencyInjectionSettings /// This can be for telemetry logging, authorization, etc. /// [JsonPropertyName("httpMessageHandlers")] - [JsonProperty("httpMessageHandlers")] public string[] HttpMessageHandlers { get; set; } = Array.Empty(); /// /// Set this to true to use Polly for transient fault handling. /// [JsonPropertyName("usePolly")] - [JsonProperty("usePolly")] public bool UsePolly { get; set; } /// /// Default max retry count for Polly. Default is 6. /// [JsonPropertyName("pollyMaxRetryCount")] - [JsonProperty("pollyMaxRetryCount")] public int PollyMaxRetryCount { get; set; } = 6; /// /// The median delay to target before the first retry in seconds. Default is 1 second /// [JsonPropertyName("firstBackoffRetryInSeconds")] - [JsonProperty("firstBackoffRetryInSeconds")] public double FirstBackoffRetryInSeconds { get; set; } = 1.0; } diff --git a/src/Refitter.SourceGenerator/RefitterSourceGenerator.cs b/src/Refitter.SourceGenerator/RefitterSourceGenerator.cs index 03991777..2d088b0f 100644 --- a/src/Refitter.SourceGenerator/RefitterSourceGenerator.cs +++ b/src/Refitter.SourceGenerator/RefitterSourceGenerator.cs @@ -1,10 +1,9 @@ using System.Diagnostics.CodeAnalysis; using System.Text; +using System.Text.Json; using Microsoft.CodeAnalysis; -using Newtonsoft.Json; - using Refitter.Core; namespace Refitter.SourceGenerator; @@ -74,7 +73,13 @@ private static List GenerateCode( var content = file.GetText(cancellationToken)!; var json = content.ToString(); - var settings = JsonConvert.DeserializeObject(json)!; + var settings = JsonSerializer.Deserialize( + json, + new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + })!; cancellationToken.ThrowIfCancellationRequested(); diagnostics.Add( @@ -101,7 +106,7 @@ private static List GenerateCode( var refit = generator.Generate(); cancellationToken.ThrowIfCancellationRequested(); - try + try { var folder = Path.Combine(Path.GetDirectoryName(file.Path), settings.OutputFolder); var output = Path.Combine(folder, filename); @@ -111,8 +116,8 @@ private static List GenerateCode( } File.WriteAllText( - output, - refit, + output, + refit, Encoding.UTF8); return diagnostics; diff --git a/src/Refitter/GenerateCommand.cs b/src/Refitter/GenerateCommand.cs index 0a808b72..ea3fdad0 100644 --- a/src/Refitter/GenerateCommand.cs +++ b/src/Refitter/GenerateCommand.cs @@ -97,7 +97,13 @@ public override async Task ExecuteAsync(CommandContext context, Settings se if (!string.IsNullOrWhiteSpace(settings.SettingsFilePath)) { var json = await File.ReadAllTextAsync(settings.SettingsFilePath); - refitGeneratorSettings = JsonSerializer.Deserialize(json)!; + refitGeneratorSettings = JsonSerializer.Deserialize( + json, + new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + })!; refitGeneratorSettings.OpenApiPath = settings.OpenApiPath!; } From 63da2d2b66c6049e51fe50f02dfa4089b042b49b Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 22:03:23 +0200 Subject: [PATCH 03/23] Add support for customizing the NSwag CSharpGeneratorSettings from CSharpClientGeneratorFactory --- .../CSharpClientGeneratorFactory.cs | 85 ++++++++++++++----- .../CustomCSharpGeneratorSettingsTests.cs | 80 +++++++++++++++++ src/Refitter.Tests/Refitter.Tests.csproj | 5 +- 3 files changed, 145 insertions(+), 25 deletions(-) create mode 100644 src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs diff --git a/src/Refitter.Core/CSharpClientGeneratorFactory.cs b/src/Refitter.Core/CSharpClientGeneratorFactory.cs index c00fa4b5..05b9d1f3 100644 --- a/src/Refitter.Core/CSharpClientGeneratorFactory.cs +++ b/src/Refitter.Core/CSharpClientGeneratorFactory.cs @@ -1,36 +1,79 @@ +using System.Diagnostics; + using NJsonSchema.CodeGeneration.CSharp; + using NSwag; using NSwag.CodeGeneration.CSharp; namespace Refitter.Core; -internal class CSharpClientGeneratorFactory +internal class CSharpClientGeneratorFactory(RefitGeneratorSettings settings, OpenApiDocument document) { - private readonly RefitGeneratorSettings settings; - private readonly OpenApiDocument document; - - public CSharpClientGeneratorFactory(RefitGeneratorSettings settings, OpenApiDocument document) + public CustomCSharpClientGenerator Create() { - this.settings = settings; - this.document = document; + var generator = new CustomCSharpClientGenerator( + document, + new CSharpClientGeneratorSettings + { + GenerateClientClasses = false, + GenerateDtoTypes = true, + GenerateClientInterfaces = false, + GenerateExceptionClasses = false, + CodeGeneratorSettings = + { + PropertyNameGenerator = new CustomCSharpPropertyNameGenerator(), + }, + CSharpGeneratorSettings = + { + Namespace = settings.Namespace, + JsonLibrary = CSharpJsonLibrary.SystemTextJson, + TypeAccessModifier = settings.TypeAccessibility.ToString().ToLowerInvariant(), + } + }); + + MapCSharpGeneratorSettings( + settings.ContractsGeneratorSettings, + generator.Settings.CSharpGeneratorSettings); + + return generator; } - public CustomCSharpClientGenerator Create() => - new(document, new CSharpClientGeneratorSettings + private static void MapCSharpGeneratorSettings( + CSharpGeneratorSettings? source, + CSharpGeneratorSettings destination) + { + if (source is null) { - GenerateClientClasses = false, - GenerateDtoTypes = true, - GenerateClientInterfaces = false, - GenerateExceptionClasses = false, - CodeGeneratorSettings = + return; + } + + var defaultInstance = new CSharpGeneratorSettings(); + foreach (var property in source.GetType().GetProperties()) + { + if (property.PropertyType != typeof(string) && + property.PropertyType != typeof(bool)) { - PropertyNameGenerator = new CustomCSharpPropertyNameGenerator(), - }, - CSharpGeneratorSettings = + continue; + } + + var value = property.GetValue(source); + if (value == null) { - Namespace = settings.Namespace, - JsonLibrary = CSharpJsonLibrary.SystemTextJson, - TypeAccessModifier = settings.TypeAccessibility.ToString().ToLowerInvariant() + continue; } - }); + + if (value.Equals(property.GetValue(defaultInstance))) + { + continue; + } + + var settingsProperty = destination.GetType().GetProperty(property.Name); + if (settingsProperty == null) + { + continue; + } + + settingsProperty.SetValue(destination, value); + } + } } \ No newline at end of file diff --git a/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs b/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs new file mode 100644 index 00000000..9e48522c --- /dev/null +++ b/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs @@ -0,0 +1,80 @@ +using System.Dynamic; + +using Atc.Test; + +using FluentAssertions; + +using NJsonSchema.CodeGeneration.CSharp; + +using Refitter.Core; +using Refitter.Tests.Resources; + +using Xunit; + +namespace Refitter.Tests; + +public class CustomCSharpGeneratorSettingsTests +{ + [Theory] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV2, "SwaggerPetstore.json")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV2, "SwaggerPetstore.yaml")] + public async Task Can_Generate_Custom_DateType( + SampleOpenSpecifications version, + string filename) + { + var settings = new RefitGeneratorSettings(); + settings.ContractsGeneratorSettings = new CSharpGeneratorSettings(); + settings.ContractsGeneratorSettings!.DateType = "DateTime"; + var generateCode = await GenerateCode(version, filename, settings); + generateCode.Should().NotBeNullOrWhiteSpace(); + generateCode.Should().Contain("DateTime"); + } + + [Theory] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV2, "SwaggerPetstore.json")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV2, "SwaggerPetstore.yaml")] + public async Task Can_Generate_Custom_DateTimeType( + SampleOpenSpecifications version, + string filename) + { + var settings = new RefitGeneratorSettings(); + settings.ContractsGeneratorSettings = new CSharpGeneratorSettings(); + settings.ContractsGeneratorSettings!.DateTimeType = "DateTime"; + var generateCode = await GenerateCode(version, filename, settings); + generateCode.Should().NotBeNullOrWhiteSpace(); + generateCode.Should().Contain("DateTime"); + } + + [Theory] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV2, "SwaggerPetstore.json")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV2, "SwaggerPetstore.yaml")] + public async Task Can_Generate_Custom_ArrayType( + SampleOpenSpecifications version, + string filename) + { + var settings = new RefitGeneratorSettings(); + settings.ContractsGeneratorSettings = new CSharpGeneratorSettings(); + settings.ContractsGeneratorSettings!.ArrayType = "System.Collection.Generic.IList"; + var generateCode = await GenerateCode(version, filename, settings); + generateCode.Should().NotBeNullOrWhiteSpace(); + generateCode.Should().Contain("System.Collection.Generic.IList<"); + } + + private static async Task GenerateCode( + SampleOpenSpecifications version, + string filename, + RefitGeneratorSettings settings) + { + var swaggerFile = await TestFile.CreateSwaggerFile(EmbeddedResources.GetSwaggerPetstore(version), filename); + settings.OpenApiPath = swaggerFile; + + var sut = await RefitGenerator.CreateAsync(settings); + return sut.Generate(); + } +} \ No newline at end of file diff --git a/src/Refitter.Tests/Refitter.Tests.csproj b/src/Refitter.Tests/Refitter.Tests.csproj index ef7969a2..ce2b7b8f 100644 --- a/src/Refitter.Tests/Refitter.Tests.csproj +++ b/src/Refitter.Tests/Refitter.Tests.csproj @@ -14,6 +14,7 @@ + @@ -41,8 +42,4 @@ - - - - From f98b0d0e3e01f652599e1c74e9e5bac17075981b Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 22:08:40 +0200 Subject: [PATCH 04/23] Rename `ContractsGeneratorSettings` to `CodeGeneratorSettings` The name of `ContractsGeneratorSettings` is changed to `CodeGeneratorSettings` throughout the project files. This name is more reflective of the setting's usage, as it influences the generation of all types, not just contracts. The NSwag configuration JSON property is also updated from `contractsGeneratorSettings` to `codeGeneratorSettings` to reflect this change and maintain consistency. --- src/Refitter.Core/CSharpClientGeneratorFactory.cs | 2 +- src/Refitter.Core/RefitGeneratorSettings.cs | 6 +++--- .../CustomCSharpGeneratorSettingsTests.cs | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Refitter.Core/CSharpClientGeneratorFactory.cs b/src/Refitter.Core/CSharpClientGeneratorFactory.cs index 05b9d1f3..04fe81f5 100644 --- a/src/Refitter.Core/CSharpClientGeneratorFactory.cs +++ b/src/Refitter.Core/CSharpClientGeneratorFactory.cs @@ -32,7 +32,7 @@ public CustomCSharpClientGenerator Create() }); MapCSharpGeneratorSettings( - settings.ContractsGeneratorSettings, + settings.CodeGeneratorSettings, generator.Settings.CSharpGeneratorSettings); return generator; diff --git a/src/Refitter.Core/RefitGeneratorSettings.cs b/src/Refitter.Core/RefitGeneratorSettings.cs index 54abb3e1..6941526d 100644 --- a/src/Refitter.Core/RefitGeneratorSettings.cs +++ b/src/Refitter.Core/RefitGeneratorSettings.cs @@ -141,10 +141,10 @@ public class RefitGeneratorSettings public DependencyInjectionSettings? DependencyInjectionSettings { get; set; } /// - /// Gets or sets the settings describing how to generate contracts using NSwag + /// Gets or sets the settings describing how to generate types using NSwag /// - [JsonPropertyName("contractsGeneratorSettings")] - public CSharpGeneratorSettings? ContractsGeneratorSettings { get; set; } + [JsonPropertyName("codeGeneratorSettings")] + public CSharpGeneratorSettings? CodeGeneratorSettings { get; set; } } /// diff --git a/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs b/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs index 9e48522c..de5696ae 100644 --- a/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs +++ b/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs @@ -25,8 +25,8 @@ public async Task Can_Generate_Custom_DateType( string filename) { var settings = new RefitGeneratorSettings(); - settings.ContractsGeneratorSettings = new CSharpGeneratorSettings(); - settings.ContractsGeneratorSettings!.DateType = "DateTime"; + settings.CodeGeneratorSettings = new CSharpGeneratorSettings(); + settings.CodeGeneratorSettings!.DateType = "DateTime"; var generateCode = await GenerateCode(version, filename, settings); generateCode.Should().NotBeNullOrWhiteSpace(); generateCode.Should().Contain("DateTime"); @@ -42,8 +42,8 @@ public async Task Can_Generate_Custom_DateTimeType( string filename) { var settings = new RefitGeneratorSettings(); - settings.ContractsGeneratorSettings = new CSharpGeneratorSettings(); - settings.ContractsGeneratorSettings!.DateTimeType = "DateTime"; + settings.CodeGeneratorSettings = new CSharpGeneratorSettings(); + settings.CodeGeneratorSettings!.DateTimeType = "DateTime"; var generateCode = await GenerateCode(version, filename, settings); generateCode.Should().NotBeNullOrWhiteSpace(); generateCode.Should().Contain("DateTime"); @@ -59,8 +59,8 @@ public async Task Can_Generate_Custom_ArrayType( string filename) { var settings = new RefitGeneratorSettings(); - settings.ContractsGeneratorSettings = new CSharpGeneratorSettings(); - settings.ContractsGeneratorSettings!.ArrayType = "System.Collection.Generic.IList"; + settings.CodeGeneratorSettings = new CSharpGeneratorSettings(); + settings.CodeGeneratorSettings!.ArrayType = "System.Collection.Generic.IList"; var generateCode = await GenerateCode(version, filename, settings); generateCode.Should().NotBeNullOrWhiteSpace(); generateCode.Should().Contain("System.Collection.Generic.IList<"); From c71890b0c6d405fb562bf070b3d30107a3e5b680 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 22:08:55 +0200 Subject: [PATCH 05/23] Add codeGeneratorSettings in petstore.refitter CodeGeneratorSettings have been added to the configuration in petstore.refitter. This was necessary to set the package-specific types for Date, DateTime and Arrays in the generated code. Consequently, the setup becomes more compatible with the .NET environment. --- test/petstore.refitter | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/petstore.refitter b/test/petstore.refitter index 860a0e96..60d54a4c 100644 --- a/test/petstore.refitter +++ b/test/petstore.refitter @@ -10,5 +10,10 @@ "usePolly": true, "pollyMaxRetryCount": 3, "firstBackoffRetryInSeconds": 0.5 + }, + "codeGeneratorSettings": { + "dateType": "System.DateTime", + "dateTimeType": "System.DateTime", + "arrayType": "System.Collections.Generic.IList" } } \ No newline at end of file From 09e55fea511f4605c00e07248b27261df24d0033 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 22:44:17 +0200 Subject: [PATCH 06/23] Refactor serialization to use the new Serializer class The serialization process was refactored to use a new Serializer class, which was included in a standalone 'Refitter.Core' namespace. The purpose of this change is to eliminate redundancy and improve the manageability of the serialization settings applied in different parts of the project. This new Serializer class leverages the JsonSerializerOptions for consistency and ease of maintainability. --- src/Refitter.Core/Serializer.cs | 21 +++++++++++++++++++ .../RefitterSourceGenerator.cs | 8 +------ src/Refitter/Analytics.cs | 4 ++-- src/Refitter/GenerateCommand.cs | 10 ++------- 4 files changed, 26 insertions(+), 17 deletions(-) create mode 100644 src/Refitter.Core/Serializer.cs diff --git a/src/Refitter.Core/Serializer.cs b/src/Refitter.Core/Serializer.cs new file mode 100644 index 00000000..7786580e --- /dev/null +++ b/src/Refitter.Core/Serializer.cs @@ -0,0 +1,21 @@ +using System.Text.Json; + +using JsonNamingPolicy = System.Text.Json.JsonNamingPolicy; +using JsonSerializerOptions = System.Text.Json.JsonSerializerOptions; + +namespace Refitter.Core; + +public static class Serializer +{ + private static readonly JsonSerializerOptions JsonSerializerOptions = new() + { + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }; + + public static T Deserialize(string json) => + JsonSerializer.Deserialize(json, JsonSerializerOptions)!; + + public static string Serialize(object any) => + JsonSerializer.Serialize(any, JsonSerializerOptions); +} \ No newline at end of file diff --git a/src/Refitter.SourceGenerator/RefitterSourceGenerator.cs b/src/Refitter.SourceGenerator/RefitterSourceGenerator.cs index 2d088b0f..e23c420f 100644 --- a/src/Refitter.SourceGenerator/RefitterSourceGenerator.cs +++ b/src/Refitter.SourceGenerator/RefitterSourceGenerator.cs @@ -73,13 +73,7 @@ private static List GenerateCode( var content = file.GetText(cancellationToken)!; var json = content.ToString(); - var settings = JsonSerializer.Deserialize( - json, - new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - })!; + var settings = Serializer.Deserialize(json); cancellationToken.ThrowIfCancellationRequested(); diagnostics.Add( diff --git a/src/Refitter/Analytics.cs b/src/Refitter/Analytics.cs index 8bfa5ad0..d2d938ff 100644 --- a/src/Refitter/Analytics.cs +++ b/src/Refitter/Analytics.cs @@ -76,8 +76,8 @@ public static Task LogError(Exception exception, Settings settings) exception .ToExceptionless( new ContextData( - JsonSerializer.Deserialize>( - JsonSerializer.Serialize(settings))!)) + Serializer.Deserialize>( + Serializer.Serialize(settings))!)) .Submit(); return ExceptionlessClient.Default.ProcessQueueAsync(); diff --git a/src/Refitter/GenerateCommand.cs b/src/Refitter/GenerateCommand.cs index ea3fdad0..15f7dc1b 100644 --- a/src/Refitter/GenerateCommand.cs +++ b/src/Refitter/GenerateCommand.cs @@ -34,7 +34,7 @@ public override ValidationResult Validate(CommandContext context, Settings setti if (!string.IsNullOrWhiteSpace(settings.SettingsFilePath)) { var json = File.ReadAllText(settings.SettingsFilePath); - var refitGeneratorSettings = JsonSerializer.Deserialize(json)!; + var refitGeneratorSettings = Serializer.Deserialize(json); settings.OpenApiPath = refitGeneratorSettings.OpenApiPath; if (string.IsNullOrWhiteSpace(refitGeneratorSettings.OpenApiPath)) @@ -97,13 +97,7 @@ public override async Task ExecuteAsync(CommandContext context, Settings se if (!string.IsNullOrWhiteSpace(settings.SettingsFilePath)) { var json = await File.ReadAllTextAsync(settings.SettingsFilePath); - refitGeneratorSettings = JsonSerializer.Deserialize( - json, - new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - })!; + refitGeneratorSettings = Serializer.Deserialize(json); refitGeneratorSettings.OpenApiPath = settings.OpenApiPath!; } From 11c9a777334ff47a6a8db56ad7fd8fd3dd41c6b3 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 22:45:02 +0200 Subject: [PATCH 07/23] Update RefitGeneratorSettings and add NSwagCodeGeneratorSettings CodeGeneratorSettings' type was changed from 'CSharpGeneratorSettings' to 'NSwagCodeGeneratorSettings'. This change was necessary to better accommodate NSwag specifications for generating types. Added class 'NSwagCodeGeneratorSettings' to handle a broad range of .NET type settings for NSwag, improving configurability. Furthermore, organization of JsonPropertyName and corresponding enum was simplified for clearer readability. --- src/Refitter.Core/RefitGeneratorSettings.cs | 179 +++++++++++++++++++- 1 file changed, 171 insertions(+), 8 deletions(-) diff --git a/src/Refitter.Core/RefitGeneratorSettings.cs b/src/Refitter.Core/RefitGeneratorSettings.cs index 6941526d..b4092c9f 100644 --- a/src/Refitter.Core/RefitGeneratorSettings.cs +++ b/src/Refitter.Core/RefitGeneratorSettings.cs @@ -127,7 +127,7 @@ public class RefitGeneratorSettings /// [JsonPropertyName("optionalParameters")] public bool OptionalParameters { get; set; } - + /// /// Gets or sets the relative path to a folder in which the output files are generated. (default: ./Generated) /// @@ -144,7 +144,7 @@ public class RefitGeneratorSettings /// Gets or sets the settings describing how to generate types using NSwag /// [JsonPropertyName("codeGeneratorSettings")] - public CSharpGeneratorSettings? CodeGeneratorSettings { get; set; } + public NSwagCodeGeneratorSettings? CodeGeneratorSettings { get; set; } } /// @@ -155,20 +155,19 @@ public enum MultipleInterfaces /// /// Do not generate multiple interfaces /// - [JsonPropertyName("unset")] - Unset, + [JsonPropertyName("unset")] Unset, + /// /// Generate a Refit interface for each endpoint with a single Execute() method. /// The method name can be customized using the --operation-name-template command line option, /// or the operationNameTemplate property in the settings file. /// - [JsonPropertyName("byEndpoint")] - ByEndpoint, + [JsonPropertyName("byEndpoint")] ByEndpoint, + /// /// Generate a Refit interface for each tag /// - [JsonPropertyName("byTag")] - ByTag + [JsonPropertyName("byTag")] ByTag } /// @@ -243,3 +242,167 @@ public class DependencyInjectionSettings [JsonPropertyName("firstBackoffRetryInSeconds")] public double FirstBackoffRetryInSeconds { get; set; } = 1.0; } + +/// +/// CSharp code generator settings +/// +public class NSwagCodeGeneratorSettings +{ + /// + /// Gets or sets the .NET namespace of the generated types (default: GeneratedCode). + /// + public string Namespace { get; set; } = "GeneratedCode"; + + /// + /// Gets or sets a value indicating whether a required property must be defined in JSON + /// (sets Required.Always when the property is required) (default: true). + /// + public bool RequiredPropertiesMustBeDefined { get; set; } = true; + + /// + /// Gets or sets a value indicating whether to generated data annotation attributes (default: true). + /// + public bool GenerateDataAnnotations { get; set; } = true; + + /// + /// Gets or sets the any type (default: "object"). + /// + public string AnyType { get; set; } = "object"; + + /// + /// Gets or sets the date .NET type (default: 'DateTimeOffset'). + /// + public string DateType { get; set; } = "System.DateTimeOffset"; + + /// + /// Gets or sets the date time .NET type (default: 'DateTimeOffset'). + /// + public string DateTimeType { get; set; } = "System.DateTimeOffset"; + + /// + /// Gets or sets the time .NET type (default: 'TimeSpan'). + /// + public string TimeType { get; set; } = "System.TimeSpan"; + + /// + /// Gets or sets the time span .NET type (default: 'TimeSpan'). + /// + public string TimeSpanType { get; set; } = "System.TimeSpan"; + + /// + /// Gets or sets the generic array .NET type (default: 'ICollection'). + /// + public string ArrayType { get; set; } = "System.Collections.Generic.ICollection"; + + /// + /// Gets or sets the generic dictionary .NET type (default: 'IDictionary'). + /// + public string DictionaryType { get; set; } = "System.Collections.Generic.IDictionary"; + + /// + /// Gets or sets the generic array .NET type which is used for ArrayType instances (default: 'Collection'). + /// + public string ArrayInstanceType { get; set; } = "System.Collections.ObjectModel.Collection"; + + /// + /// Gets or sets the generic dictionary .NET type which is used for DictionaryType instances (default: 'Dictionary'). + /// + public string DictionaryInstanceType { get; set; } = "System.Collections.Generic.Dictionary"; + + /// + /// Gets or sets the generic array .NET type which is used as base class (default: 'Collection'). + /// + public string ArrayBaseType { get; set; } = "System.Collections.ObjectModel.Collection"; + + /// + /// Gets or sets the generic dictionary .NET type which is used as base class (default: 'Dictionary'). + /// + public string DictionaryBaseType { get; set; } = "System.Collections.Generic.Dictionary"; + + /// + /// Gets or sets the CSharp class style (default: 'Poco'). + /// + [JsonConverter(typeof(JsonStringEnumConverter))] + public CSharpClassStyle ClassStyle { get; set; } = CSharpClassStyle.Poco; + + /// + /// Gets or sets the CSharp JSON library to use (default: 'NewtonsoftJson', 'SystemTextJson' is experimental/not complete). + /// + [JsonConverter(typeof(JsonStringEnumConverter))] + public CSharpJsonLibrary JsonLibrary { get; set; } = CSharpJsonLibrary.NewtonsoftJson; + + /// + /// Gets or sets the access modifier of generated classes and interfaces (default: 'public'). + /// + public string TypeAccessModifier { get; set; } = "public"; + + /// + /// Gets the access modifier of property setters (default: ''). + /// + public string PropertySetterAccessModifier { get; set; } = string.Empty; + + /// + /// Gets or sets the custom Json.NET converters (class names) which are registered for serialization and deserialization. + /// + public string[]? JsonConverters { get; set; } + + /// + /// Gets or sets a value indicating whether to remove the setter for non-nullable array properties (default: false). + /// + public bool GenerateImmutableArrayProperties { get; set; } + + /// + /// Gets or sets a value indicating whether to remove the setter for non-nullable dictionary properties (default: false). + /// + public bool GenerateImmutableDictionaryProperties { get; set; } + + /// + /// Gets or sets a value indicating whether to use preserve references handling (All) in the JSON serializer (default: false). + /// + public bool HandleReferences { get; set; } + + /// + /// Gets or sets the name of a static method which is called to transform the JsonSerializerSettings (for Newtonsoft.Json) or the JsonSerializerOptions (for System.Text.Json) used in the generated ToJson()/FromJson() methods (default: null). + /// + public string? JsonSerializerSettingsTransformationMethod { get; set; } + + /// + /// Gets or sets a value indicating whether to render ToJson() and FromJson() methods (default: false). + /// + public bool GenerateJsonMethods { get; set; } = false; + + /// + /// Gets or sets a value indicating whether enums should be always generated as bit flags (default: false). + /// + public bool EnforceFlagEnums { get; set; } = false; + + /// + /// Gets or sets a value indicating whether named/referenced dictionaries should be inlined or generated as class with dictionary inheritance. + /// + public bool InlineNamedDictionaries { get; set; } = false; + + /// + /// Gets or sets a value indicating whether named/referenced tuples should be inlined or generated as class with tuple inheritance. + /// + public bool InlineNamedTuples { get; set; } = true; + + /// + /// Gets or sets a value indicating whether named/referenced arrays should be inlined or generated as class with array inheritance. + /// + public bool InlineNamedArrays { get; set; } = false; + + /// + /// Gets or sets a value indicating whether optional schema properties (not required) are generated as nullable properties (default: false). + /// + public bool GenerateOptionalPropertiesAsNullable { get; set; } + + /// + /// Gets or sets a value indicating whether to generate Nullable Reference Type annotations (default: false). + /// + public bool GenerateNullableReferenceTypes { get; set; } + + /// + /// Generate C# 9.0 record types instead of record-like classes. + /// + public bool GenerateNativeRecords { get; set; } +} \ No newline at end of file From a9e55dda17bed263c510213daada0ab226d2c567 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 22:45:31 +0200 Subject: [PATCH 08/23] Update generator settings type in MapCSharpGeneratorSettings Changed the generator settings type reference in the MapCSharpGeneratorSettings method. Instead of referring to the CSharpGeneratorSettings type, changed to NSwagCodeGeneratorSettings type. This change is necessary to align with NSwag, which is the library used for generating clients. --- src/Refitter.Core/CSharpClientGeneratorFactory.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Refitter.Core/CSharpClientGeneratorFactory.cs b/src/Refitter.Core/CSharpClientGeneratorFactory.cs index 04fe81f5..8c92a7b6 100644 --- a/src/Refitter.Core/CSharpClientGeneratorFactory.cs +++ b/src/Refitter.Core/CSharpClientGeneratorFactory.cs @@ -39,7 +39,7 @@ public CustomCSharpClientGenerator Create() } private static void MapCSharpGeneratorSettings( - CSharpGeneratorSettings? source, + NSwagCodeGeneratorSettings? source, CSharpGeneratorSettings destination) { if (source is null) @@ -47,7 +47,7 @@ private static void MapCSharpGeneratorSettings( return; } - var defaultInstance = new CSharpGeneratorSettings(); + var defaultInstance = new NSwagCodeGeneratorSettings(); foreach (var property in source.GetType().GetProperties()) { if (property.PropertyType != typeof(string) && From 57d0a37594c3341ce02971c7a992b9ecc4457629 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 22:46:11 +0200 Subject: [PATCH 09/23] Add new tests for default types in RefitGeneratorSettings Added new tests to verify the default value of date, datetime, array type in the RefitGeneratorSettings class. System.Text.Json namespace has also been added to support these tests. Additionally, replaced instances of CSharpGeneratorSettings with NSwagCodeGeneratorSettings to improve test consistency. These changes are crucial to ensure the code generator settings are working as expected for different data types. --- .../CustomCSharpGeneratorSettingsTests.cs | 53 +++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs b/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs index de5696ae..51f32d56 100644 --- a/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs +++ b/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs @@ -1,4 +1,5 @@ using System.Dynamic; +using System.Text.Json; using Atc.Test; @@ -15,6 +16,52 @@ namespace Refitter.Tests; public class CustomCSharpGeneratorSettingsTests { + [Theory] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV2, "SwaggerPetstore.json")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV2, "SwaggerPetstore.yaml")] + public async Task Can_Generate_Default_DateType( + SampleOpenSpecifications version, + string filename) + { + var settings = new RefitGeneratorSettings(); + settings.CodeGeneratorSettings = new NSwagCodeGeneratorSettings(); + var generateCode = await GenerateCode(version, filename, settings); + generateCode.Should().NotBeNullOrWhiteSpace(); + generateCode.Should().Contain(settings.CodeGeneratorSettings!.DateType); + } + [Theory] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV2, "SwaggerPetstore.json")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV2, "SwaggerPetstore.yaml")] + public async Task Can_Generate_Default_DateTimeType( + SampleOpenSpecifications version, + string filename) + { + var settings = new RefitGeneratorSettings(); + settings.CodeGeneratorSettings = new NSwagCodeGeneratorSettings(); + var generateCode = await GenerateCode(version, filename, settings); + generateCode.Should().NotBeNullOrWhiteSpace(); + generateCode.Should().Contain(settings.CodeGeneratorSettings!.DateTimeType); + } + [Theory] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV2, "SwaggerPetstore.json")] + [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV2, "SwaggerPetstore.yaml")] + public async Task Can_Generate_Default_ArrayType( + SampleOpenSpecifications version, + string filename) + { + var settings = new RefitGeneratorSettings(); + settings.CodeGeneratorSettings = new NSwagCodeGeneratorSettings(); + var generateCode = await GenerateCode(version, filename, settings); + generateCode.Should().NotBeNullOrWhiteSpace(); + generateCode.Should().Contain("ICollection<"); + } + [Theory] [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")] [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")] @@ -25,7 +72,7 @@ public async Task Can_Generate_Custom_DateType( string filename) { var settings = new RefitGeneratorSettings(); - settings.CodeGeneratorSettings = new CSharpGeneratorSettings(); + settings.CodeGeneratorSettings = new NSwagCodeGeneratorSettings(); settings.CodeGeneratorSettings!.DateType = "DateTime"; var generateCode = await GenerateCode(version, filename, settings); generateCode.Should().NotBeNullOrWhiteSpace(); @@ -42,7 +89,7 @@ public async Task Can_Generate_Custom_DateTimeType( string filename) { var settings = new RefitGeneratorSettings(); - settings.CodeGeneratorSettings = new CSharpGeneratorSettings(); + settings.CodeGeneratorSettings = new NSwagCodeGeneratorSettings(); settings.CodeGeneratorSettings!.DateTimeType = "DateTime"; var generateCode = await GenerateCode(version, filename, settings); generateCode.Should().NotBeNullOrWhiteSpace(); @@ -59,7 +106,7 @@ public async Task Can_Generate_Custom_ArrayType( string filename) { var settings = new RefitGeneratorSettings(); - settings.CodeGeneratorSettings = new CSharpGeneratorSettings(); + settings.CodeGeneratorSettings = new NSwagCodeGeneratorSettings(); settings.CodeGeneratorSettings!.ArrayType = "System.Collection.Generic.IList"; var generateCode = await GenerateCode(version, filename, settings); generateCode.Should().NotBeNullOrWhiteSpace(); From ba8d0e614d400165de34a7d13e453b6b511bf6ee Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 23:11:01 +0200 Subject: [PATCH 10/23] Add spacing for readability in test methods Added spacing between methods in `CustomCSharpGeneratorSettingsTests.cs` to improve code readability. No changes to logic or functionality were made. This change purely enhances the structure and legibility of the code making it easier for developers to navigate and understand. --- src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs b/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs index 51f32d56..2f726cd0 100644 --- a/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs +++ b/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs @@ -31,6 +31,7 @@ public async Task Can_Generate_Default_DateType( generateCode.Should().NotBeNullOrWhiteSpace(); generateCode.Should().Contain(settings.CodeGeneratorSettings!.DateType); } + [Theory] [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")] [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")] @@ -46,6 +47,7 @@ public async Task Can_Generate_Default_DateTimeType( generateCode.Should().NotBeNullOrWhiteSpace(); generateCode.Should().Contain(settings.CodeGeneratorSettings!.DateTimeType); } + [Theory] [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")] [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")] @@ -61,7 +63,7 @@ public async Task Can_Generate_Default_ArrayType( generateCode.Should().NotBeNullOrWhiteSpace(); generateCode.Should().Contain("ICollection<"); } - + [Theory] [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")] [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")] @@ -78,7 +80,7 @@ public async Task Can_Generate_Custom_DateType( generateCode.Should().NotBeNullOrWhiteSpace(); generateCode.Should().Contain("DateTime"); } - + [Theory] [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")] [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")] @@ -95,7 +97,7 @@ public async Task Can_Generate_Custom_DateTimeType( generateCode.Should().NotBeNullOrWhiteSpace(); generateCode.Should().Contain("DateTime"); } - + [Theory] [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreJsonV3, "SwaggerPetstore.json")] [InlineAutoNSubstituteData(SampleOpenSpecifications.SwaggerPetstoreYamlV3, "SwaggerPetstore.yaml")] From fb486700850614602c661361cb993f4b6abde295 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 23:14:13 +0200 Subject: [PATCH 11/23] Split settings into respective classes for better maintainability Refactored `RefitGeneratorSettings.cs` into different classes, each encapsulating settings related to distinct functionalities such as `NSwagCodeGeneratorSettings.cs`, `DependencyInjectionSettings.cs`, `NamingSettings.cs`, `TypeAccessibility.cs`, and `MultipleInterfaces.cs`. This overhaul would enhance maintainability of the settings configuration by segregating settings based on their respective areas of concern. Any future modifications or additions can now be applied to the respective class directly, thereby minimizing the potential impact radius of the change. --- src/Refitter.Core/RefitGeneratorSettings.cs | 408 ------------------ .../Settings/DependencyInjectionSettings.cs | 41 ++ .../Settings/MultipleInterfaces.cs | 26 ++ .../Settings/NSwagCodeGeneratorSettings.cs | 169 ++++++++ src/Refitter.Core/Settings/NamingSettings.cs | 23 + .../Settings/RefitGeneratorSettings.cs | 146 +++++++ .../Settings/TypeAccessibility.cs | 17 + .../Refitter.SourceGenerator.csproj | 1 + 8 files changed, 423 insertions(+), 408 deletions(-) delete mode 100644 src/Refitter.Core/RefitGeneratorSettings.cs create mode 100644 src/Refitter.Core/Settings/DependencyInjectionSettings.cs create mode 100644 src/Refitter.Core/Settings/MultipleInterfaces.cs create mode 100644 src/Refitter.Core/Settings/NSwagCodeGeneratorSettings.cs create mode 100644 src/Refitter.Core/Settings/NamingSettings.cs create mode 100644 src/Refitter.Core/Settings/RefitGeneratorSettings.cs create mode 100644 src/Refitter.Core/Settings/TypeAccessibility.cs diff --git a/src/Refitter.Core/RefitGeneratorSettings.cs b/src/Refitter.Core/RefitGeneratorSettings.cs deleted file mode 100644 index b4092c9f..00000000 --- a/src/Refitter.Core/RefitGeneratorSettings.cs +++ /dev/null @@ -1,408 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Text.Json.Serialization; - -using NJsonSchema.CodeGeneration.CSharp; - -namespace Refitter.Core; - -/// -/// Provide settings for Refit generator. -/// -[ExcludeFromCodeCoverage] -public class RefitGeneratorSettings -{ - /// - /// Gets or sets the path to the Open API. - /// - [JsonPropertyName("openApiPath")] - public string OpenApiPath { get; set; } = null!; - - /// - /// Gets or sets the namespace for the generated code. (default: GeneratedCode) - /// - [JsonPropertyName("namespace")] - public string Namespace { get; set; } = "GeneratedCode"; - - /// - /// Gets or sets the naming settings. - /// - [JsonPropertyName("naming")] - public NamingSettings Naming { get; set; } = new(); - - /// - /// Gets or sets a value indicating whether contracts should be generated. - /// - [JsonPropertyName("generateContracts")] - public bool GenerateContracts { get; set; } = true; - - /// - /// Gets or sets a value indicating whether XML doc comments should be generated. - /// - [JsonPropertyName("generateXmlDocCodeComments")] - public bool GenerateXmlDocCodeComments { get; set; } = true; - - /// - /// Gets or sets a value indicating whether to add auto-generated header. - /// - [JsonPropertyName("addAutoGeneratedHeader")] - public bool AddAutoGeneratedHeader { get; set; } = true; - - /// - /// Gets or sets a value indicating whether to add accept headers [Headers("Accept: application/json")]. - /// - [JsonPropertyName("addAcceptHeaders")] - public bool AddAcceptHeaders { get; set; } = true; - - /// - /// Gets or sets a value indicating whether to return IApiResponse objects. - /// - [JsonPropertyName("returnIApiResponse")] - public bool ReturnIApiResponse { get; set; } - - /// - /// Gets or sets a value indicating whether to generate operation headers. - /// - [JsonPropertyName("generateOperationHeaders")] - public bool GenerateOperationHeaders { get; set; } = true; - - /// - /// Gets or sets the generated type accessibility. (default: Public) - /// - [JsonPropertyName("typeAccessibility")] - public TypeAccessibility TypeAccessibility { get; set; } = TypeAccessibility.Public; - - /// - /// Enable or disable the use of cancellation tokens. - /// - [JsonPropertyName("useCancellationTokens")] - public bool UseCancellationTokens { get; set; } - - /// - /// Set to true to explicitly format date query string parameters - /// in ISO 8601 standard date format using delimiters (for example: 2023-06-15) - /// - [JsonPropertyName("useIsoDateFormat")] - public bool UseIsoDateFormat { get; set; } - - /// - /// Add additional namespace to generated types - /// - [JsonPropertyName("additionalNamespaces")] - public string[] AdditionalNamespaces { get; set; } = Array.Empty(); - - /// - /// Set to true to Generate a Refit interface for each endpoint - /// - [JsonPropertyName("multipleInterfaces")] - [JsonConverter(typeof(JsonStringEnumConverter))] - public MultipleInterfaces MultipleInterfaces { get; set; } - - /// - /// Set to true to Generate a Refit interface for each endpoint - /// - [JsonPropertyName("includePathMatches")] - public string[] IncludePathMatches { get; set; } = Array.Empty(); - - /// - /// Set to true to Generate a Refit interface for each endpoint - /// - [JsonPropertyName("includeTags")] - public string[] IncludeTags { get; set; } = Array.Empty(); - - /// - /// Set to true to generate deprecated operations, otherwise false - /// - [JsonPropertyName("generateDeprecatedOperations")] - public bool GenerateDeprecatedOperations { get; set; } = true; - - /// - /// Generate operation names using pattern. - /// When using --multiple-interfaces ByEndpoint, this is name of the Execute() method in the interface. - /// - [JsonPropertyName("operationNameTemplate")] - public string? OperationNameTemplate { get; set; } - - /// - /// Set to true to re-order optional parameters to the end of the parameter list - /// - [JsonPropertyName("optionalParameters")] - public bool OptionalParameters { get; set; } - - /// - /// Gets or sets the relative path to a folder in which the output files are generated. (default: ./Generated) - /// - [JsonPropertyName("outputFolder")] - public string OutputFolder { get; set; } = "./Generated"; - - /// - /// Gets or sets the settings describing how to register generated interface to the .NET Core DI container - /// - [JsonPropertyName("dependencyInjectionSettings")] - public DependencyInjectionSettings? DependencyInjectionSettings { get; set; } - - /// - /// Gets or sets the settings describing how to generate types using NSwag - /// - [JsonPropertyName("codeGeneratorSettings")] - public NSwagCodeGeneratorSettings? CodeGeneratorSettings { get; set; } -} - -/// -/// Enum representing the different options for generating multiple Refit interfaces. -/// -public enum MultipleInterfaces -{ - /// - /// Do not generate multiple interfaces - /// - [JsonPropertyName("unset")] Unset, - - /// - /// Generate a Refit interface for each endpoint with a single Execute() method. - /// The method name can be customized using the --operation-name-template command line option, - /// or the operationNameTemplate property in the settings file. - /// - [JsonPropertyName("byEndpoint")] ByEndpoint, - - /// - /// Generate a Refit interface for each tag - /// - [JsonPropertyName("byTag")] ByTag -} - -/// -/// Configurable settings for naming in the client API -/// -[ExcludeFromCodeCoverage] -public class NamingSettings -{ - /// - /// Gets or sets a value indicating whether the OpenApi title should be used. Default is true. - /// - [JsonPropertyName("useOpenApiTitle")] - public bool UseOpenApiTitle { get; set; } = true; - - /// - /// Gets or sets the name of the Interface. Default is "ApiClient". - /// - [JsonPropertyName("interfaceName")] - public string InterfaceName { get; set; } = "ApiClient"; -} - -/// -/// Specifies the accessibility of a type. -/// -public enum TypeAccessibility -{ - /// - /// Indicates that the type is accessible by any assembly that references it. - /// - Public, - - /// - /// Indicates that the type is only accessible within its own assembly. - /// - Internal -} - -/// -/// Dependency Injection settings describing how the Refit client should be configured. -/// This can be used to configure the HttpClient pipeline with additional handlers -/// -public class DependencyInjectionSettings -{ - /// - /// Base Address for the HttpClient - /// - [JsonPropertyName("baseUrl")] - public string? BaseUrl { get; set; } - - /// - /// A collection of HttpMessageHandlers to be added to the HttpClient pipeline. - /// This can be for telemetry logging, authorization, etc. - /// - [JsonPropertyName("httpMessageHandlers")] - public string[] HttpMessageHandlers { get; set; } = Array.Empty(); - - /// - /// Set this to true to use Polly for transient fault handling. - /// - [JsonPropertyName("usePolly")] - public bool UsePolly { get; set; } - - /// - /// Default max retry count for Polly. Default is 6. - /// - [JsonPropertyName("pollyMaxRetryCount")] - public int PollyMaxRetryCount { get; set; } = 6; - - /// - /// The median delay to target before the first retry in seconds. Default is 1 second - /// - [JsonPropertyName("firstBackoffRetryInSeconds")] - public double FirstBackoffRetryInSeconds { get; set; } = 1.0; -} - -/// -/// CSharp code generator settings -/// -public class NSwagCodeGeneratorSettings -{ - /// - /// Gets or sets the .NET namespace of the generated types (default: GeneratedCode). - /// - public string Namespace { get; set; } = "GeneratedCode"; - - /// - /// Gets or sets a value indicating whether a required property must be defined in JSON - /// (sets Required.Always when the property is required) (default: true). - /// - public bool RequiredPropertiesMustBeDefined { get; set; } = true; - - /// - /// Gets or sets a value indicating whether to generated data annotation attributes (default: true). - /// - public bool GenerateDataAnnotations { get; set; } = true; - - /// - /// Gets or sets the any type (default: "object"). - /// - public string AnyType { get; set; } = "object"; - - /// - /// Gets or sets the date .NET type (default: 'DateTimeOffset'). - /// - public string DateType { get; set; } = "System.DateTimeOffset"; - - /// - /// Gets or sets the date time .NET type (default: 'DateTimeOffset'). - /// - public string DateTimeType { get; set; } = "System.DateTimeOffset"; - - /// - /// Gets or sets the time .NET type (default: 'TimeSpan'). - /// - public string TimeType { get; set; } = "System.TimeSpan"; - - /// - /// Gets or sets the time span .NET type (default: 'TimeSpan'). - /// - public string TimeSpanType { get; set; } = "System.TimeSpan"; - - /// - /// Gets or sets the generic array .NET type (default: 'ICollection'). - /// - public string ArrayType { get; set; } = "System.Collections.Generic.ICollection"; - - /// - /// Gets or sets the generic dictionary .NET type (default: 'IDictionary'). - /// - public string DictionaryType { get; set; } = "System.Collections.Generic.IDictionary"; - - /// - /// Gets or sets the generic array .NET type which is used for ArrayType instances (default: 'Collection'). - /// - public string ArrayInstanceType { get; set; } = "System.Collections.ObjectModel.Collection"; - - /// - /// Gets or sets the generic dictionary .NET type which is used for DictionaryType instances (default: 'Dictionary'). - /// - public string DictionaryInstanceType { get; set; } = "System.Collections.Generic.Dictionary"; - - /// - /// Gets or sets the generic array .NET type which is used as base class (default: 'Collection'). - /// - public string ArrayBaseType { get; set; } = "System.Collections.ObjectModel.Collection"; - - /// - /// Gets or sets the generic dictionary .NET type which is used as base class (default: 'Dictionary'). - /// - public string DictionaryBaseType { get; set; } = "System.Collections.Generic.Dictionary"; - - /// - /// Gets or sets the CSharp class style (default: 'Poco'). - /// - [JsonConverter(typeof(JsonStringEnumConverter))] - public CSharpClassStyle ClassStyle { get; set; } = CSharpClassStyle.Poco; - - /// - /// Gets or sets the CSharp JSON library to use (default: 'NewtonsoftJson', 'SystemTextJson' is experimental/not complete). - /// - [JsonConverter(typeof(JsonStringEnumConverter))] - public CSharpJsonLibrary JsonLibrary { get; set; } = CSharpJsonLibrary.NewtonsoftJson; - - /// - /// Gets or sets the access modifier of generated classes and interfaces (default: 'public'). - /// - public string TypeAccessModifier { get; set; } = "public"; - - /// - /// Gets the access modifier of property setters (default: ''). - /// - public string PropertySetterAccessModifier { get; set; } = string.Empty; - - /// - /// Gets or sets the custom Json.NET converters (class names) which are registered for serialization and deserialization. - /// - public string[]? JsonConverters { get; set; } - - /// - /// Gets or sets a value indicating whether to remove the setter for non-nullable array properties (default: false). - /// - public bool GenerateImmutableArrayProperties { get; set; } - - /// - /// Gets or sets a value indicating whether to remove the setter for non-nullable dictionary properties (default: false). - /// - public bool GenerateImmutableDictionaryProperties { get; set; } - - /// - /// Gets or sets a value indicating whether to use preserve references handling (All) in the JSON serializer (default: false). - /// - public bool HandleReferences { get; set; } - - /// - /// Gets or sets the name of a static method which is called to transform the JsonSerializerSettings (for Newtonsoft.Json) or the JsonSerializerOptions (for System.Text.Json) used in the generated ToJson()/FromJson() methods (default: null). - /// - public string? JsonSerializerSettingsTransformationMethod { get; set; } - - /// - /// Gets or sets a value indicating whether to render ToJson() and FromJson() methods (default: false). - /// - public bool GenerateJsonMethods { get; set; } = false; - - /// - /// Gets or sets a value indicating whether enums should be always generated as bit flags (default: false). - /// - public bool EnforceFlagEnums { get; set; } = false; - - /// - /// Gets or sets a value indicating whether named/referenced dictionaries should be inlined or generated as class with dictionary inheritance. - /// - public bool InlineNamedDictionaries { get; set; } = false; - - /// - /// Gets or sets a value indicating whether named/referenced tuples should be inlined or generated as class with tuple inheritance. - /// - public bool InlineNamedTuples { get; set; } = true; - - /// - /// Gets or sets a value indicating whether named/referenced arrays should be inlined or generated as class with array inheritance. - /// - public bool InlineNamedArrays { get; set; } = false; - - /// - /// Gets or sets a value indicating whether optional schema properties (not required) are generated as nullable properties (default: false). - /// - public bool GenerateOptionalPropertiesAsNullable { get; set; } - - /// - /// Gets or sets a value indicating whether to generate Nullable Reference Type annotations (default: false). - /// - public bool GenerateNullableReferenceTypes { get; set; } - - /// - /// Generate C# 9.0 record types instead of record-like classes. - /// - public bool GenerateNativeRecords { get; set; } -} \ No newline at end of file diff --git a/src/Refitter.Core/Settings/DependencyInjectionSettings.cs b/src/Refitter.Core/Settings/DependencyInjectionSettings.cs new file mode 100644 index 00000000..e700493d --- /dev/null +++ b/src/Refitter.Core/Settings/DependencyInjectionSettings.cs @@ -0,0 +1,41 @@ +using System.Text.Json.Serialization; + +namespace Refitter.Core; + +/// +/// Dependency Injection settings describing how the Refit client should be configured. +/// This can be used to configure the HttpClient pipeline with additional handlers +/// +public class DependencyInjectionSettings +{ + /// + /// Base Address for the HttpClient + /// + [JsonPropertyName("baseUrl")] + public string? BaseUrl { get; set; } + + /// + /// A collection of HttpMessageHandlers to be added to the HttpClient pipeline. + /// This can be for telemetry logging, authorization, etc. + /// + [JsonPropertyName("httpMessageHandlers")] + public string[] HttpMessageHandlers { get; set; } = Array.Empty(); + + /// + /// Set this to true to use Polly for transient fault handling. + /// + [JsonPropertyName("usePolly")] + public bool UsePolly { get; set; } + + /// + /// Default max retry count for Polly. Default is 6. + /// + [JsonPropertyName("pollyMaxRetryCount")] + public int PollyMaxRetryCount { get; set; } = 6; + + /// + /// The median delay to target before the first retry in seconds. Default is 1 second + /// + [JsonPropertyName("firstBackoffRetryInSeconds")] + public double FirstBackoffRetryInSeconds { get; set; } = 1.0; +} \ No newline at end of file diff --git a/src/Refitter.Core/Settings/MultipleInterfaces.cs b/src/Refitter.Core/Settings/MultipleInterfaces.cs new file mode 100644 index 00000000..e95ab9a7 --- /dev/null +++ b/src/Refitter.Core/Settings/MultipleInterfaces.cs @@ -0,0 +1,26 @@ +using System.Text.Json.Serialization; + +namespace Refitter.Core; + +/// +/// Enum representing the different options for generating multiple Refit interfaces. +/// +public enum MultipleInterfaces +{ + /// + /// Do not generate multiple interfaces + /// + [JsonPropertyName("unset")] Unset, + + /// + /// Generate a Refit interface for each endpoint with a single Execute() method. + /// The method name can be customized using the --operation-name-template command line option, + /// or the operationNameTemplate property in the settings file. + /// + [JsonPropertyName("byEndpoint")] ByEndpoint, + + /// + /// Generate a Refit interface for each tag + /// + [JsonPropertyName("byTag")] ByTag +} \ No newline at end of file diff --git a/src/Refitter.Core/Settings/NSwagCodeGeneratorSettings.cs b/src/Refitter.Core/Settings/NSwagCodeGeneratorSettings.cs new file mode 100644 index 00000000..28f9bc72 --- /dev/null +++ b/src/Refitter.Core/Settings/NSwagCodeGeneratorSettings.cs @@ -0,0 +1,169 @@ +using System.Text.Json.Serialization; + +using NJsonSchema.CodeGeneration.CSharp; + +namespace Refitter.Core; + +/// +/// CSharp code generator settings +/// +public class NSwagCodeGeneratorSettings +{ + /// + /// Gets or sets the .NET namespace of the generated types (default: GeneratedCode). + /// + public string Namespace { get; set; } = "GeneratedCode"; + + /// + /// Gets or sets a value indicating whether a required property must be defined in JSON + /// (sets Required.Always when the property is required) (default: true). + /// + public bool RequiredPropertiesMustBeDefined { get; set; } = true; + + /// + /// Gets or sets a value indicating whether to generated data annotation attributes (default: true). + /// + public bool GenerateDataAnnotations { get; set; } = true; + + /// + /// Gets or sets the any type (default: "object"). + /// + public string AnyType { get; set; } = "object"; + + /// + /// Gets or sets the date .NET type (default: 'DateTimeOffset'). + /// + public string DateType { get; set; } = "System.DateTimeOffset"; + + /// + /// Gets or sets the date time .NET type (default: 'DateTimeOffset'). + /// + public string DateTimeType { get; set; } = "System.DateTimeOffset"; + + /// + /// Gets or sets the time .NET type (default: 'TimeSpan'). + /// + public string TimeType { get; set; } = "System.TimeSpan"; + + /// + /// Gets or sets the time span .NET type (default: 'TimeSpan'). + /// + public string TimeSpanType { get; set; } = "System.TimeSpan"; + + /// + /// Gets or sets the generic array .NET type (default: 'ICollection'). + /// + public string ArrayType { get; set; } = "System.Collections.Generic.ICollection"; + + /// + /// Gets or sets the generic dictionary .NET type (default: 'IDictionary'). + /// + public string DictionaryType { get; set; } = "System.Collections.Generic.IDictionary"; + + /// + /// Gets or sets the generic array .NET type which is used for ArrayType instances (default: 'Collection'). + /// + public string ArrayInstanceType { get; set; } = "System.Collections.ObjectModel.Collection"; + + /// + /// Gets or sets the generic dictionary .NET type which is used for DictionaryType instances (default: 'Dictionary'). + /// + public string DictionaryInstanceType { get; set; } = "System.Collections.Generic.Dictionary"; + + /// + /// Gets or sets the generic array .NET type which is used as base class (default: 'Collection'). + /// + public string ArrayBaseType { get; set; } = "System.Collections.ObjectModel.Collection"; + + /// + /// Gets or sets the generic dictionary .NET type which is used as base class (default: 'Dictionary'). + /// + public string DictionaryBaseType { get; set; } = "System.Collections.Generic.Dictionary"; + + /// + /// Gets or sets the CSharp class style (default: 'Poco'). + /// + [JsonConverter(typeof(JsonStringEnumConverter))] + public CSharpClassStyle ClassStyle { get; set; } = CSharpClassStyle.Poco; + + /// + /// Gets or sets the CSharp JSON library to use (default: 'NewtonsoftJson', 'SystemTextJson' is experimental/not complete). + /// + [JsonConverter(typeof(JsonStringEnumConverter))] + public CSharpJsonLibrary JsonLibrary { get; set; } = CSharpJsonLibrary.NewtonsoftJson; + + /// + /// Gets or sets the access modifier of generated classes and interfaces (default: 'public'). + /// + public string TypeAccessModifier { get; set; } = "public"; + + /// + /// Gets the access modifier of property setters (default: ''). + /// + public string PropertySetterAccessModifier { get; set; } = string.Empty; + + /// + /// Gets or sets the custom Json.NET converters (class names) which are registered for serialization and deserialization. + /// + public string[]? JsonConverters { get; set; } + + /// + /// Gets or sets a value indicating whether to remove the setter for non-nullable array properties (default: false). + /// + public bool GenerateImmutableArrayProperties { get; set; } + + /// + /// Gets or sets a value indicating whether to remove the setter for non-nullable dictionary properties (default: false). + /// + public bool GenerateImmutableDictionaryProperties { get; set; } + + /// + /// Gets or sets a value indicating whether to use preserve references handling (All) in the JSON serializer (default: false). + /// + public bool HandleReferences { get; set; } + + /// + /// Gets or sets the name of a static method which is called to transform the JsonSerializerSettings (for Newtonsoft.Json) or the JsonSerializerOptions (for System.Text.Json) used in the generated ToJson()/FromJson() methods (default: null). + /// + public string? JsonSerializerSettingsTransformationMethod { get; set; } + + /// + /// Gets or sets a value indicating whether to render ToJson() and FromJson() methods (default: false). + /// + public bool GenerateJsonMethods { get; set; } = false; + + /// + /// Gets or sets a value indicating whether enums should be always generated as bit flags (default: false). + /// + public bool EnforceFlagEnums { get; set; } = false; + + /// + /// Gets or sets a value indicating whether named/referenced dictionaries should be inlined or generated as class with dictionary inheritance. + /// + public bool InlineNamedDictionaries { get; set; } = false; + + /// + /// Gets or sets a value indicating whether named/referenced tuples should be inlined or generated as class with tuple inheritance. + /// + public bool InlineNamedTuples { get; set; } = true; + + /// + /// Gets or sets a value indicating whether named/referenced arrays should be inlined or generated as class with array inheritance. + /// + public bool InlineNamedArrays { get; set; } = false; + + /// + /// Gets or sets a value indicating whether optional schema properties (not required) are generated as nullable properties (default: false). + /// + public bool GenerateOptionalPropertiesAsNullable { get; set; } + + /// + /// Gets or sets a value indicating whether to generate Nullable Reference Type annotations (default: false). + /// + public bool GenerateNullableReferenceTypes { get; set; } + + /// + /// Generate C# 9.0 record types instead of record-like classes. + /// + public bool GenerateNativeRecords { get; set; } +} \ No newline at end of file diff --git a/src/Refitter.Core/Settings/NamingSettings.cs b/src/Refitter.Core/Settings/NamingSettings.cs new file mode 100644 index 00000000..0554ff2d --- /dev/null +++ b/src/Refitter.Core/Settings/NamingSettings.cs @@ -0,0 +1,23 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; + +namespace Refitter.Core; + +/// +/// Configurable settings for naming in the client API +/// +[ExcludeFromCodeCoverage] +public class NamingSettings +{ + /// + /// Gets or sets a value indicating whether the OpenApi title should be used. Default is true. + /// + [JsonPropertyName("useOpenApiTitle")] + public bool UseOpenApiTitle { get; set; } = true; + + /// + /// Gets or sets the name of the Interface. Default is "ApiClient". + /// + [JsonPropertyName("interfaceName")] + public string InterfaceName { get; set; } = "ApiClient"; +} \ No newline at end of file diff --git a/src/Refitter.Core/Settings/RefitGeneratorSettings.cs b/src/Refitter.Core/Settings/RefitGeneratorSettings.cs new file mode 100644 index 00000000..8a0aba19 --- /dev/null +++ b/src/Refitter.Core/Settings/RefitGeneratorSettings.cs @@ -0,0 +1,146 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; + +namespace Refitter.Core; + +/// +/// Provide settings for Refit generator. +/// +[ExcludeFromCodeCoverage] +public class RefitGeneratorSettings +{ + /// + /// Gets or sets the path to the Open API. + /// + [JsonPropertyName("openApiPath")] + public string OpenApiPath { get; set; } = null!; + + /// + /// Gets or sets the namespace for the generated code. (default: GeneratedCode) + /// + [JsonPropertyName("namespace")] + public string Namespace { get; set; } = "GeneratedCode"; + + /// + /// Gets or sets the naming settings. + /// + [JsonPropertyName("naming")] + public NamingSettings Naming { get; set; } = new(); + + /// + /// Gets or sets a value indicating whether contracts should be generated. + /// + [JsonPropertyName("generateContracts")] + public bool GenerateContracts { get; set; } = true; + + /// + /// Gets or sets a value indicating whether XML doc comments should be generated. + /// + [JsonPropertyName("generateXmlDocCodeComments")] + public bool GenerateXmlDocCodeComments { get; set; } = true; + + /// + /// Gets or sets a value indicating whether to add auto-generated header. + /// + [JsonPropertyName("addAutoGeneratedHeader")] + public bool AddAutoGeneratedHeader { get; set; } = true; + + /// + /// Gets or sets a value indicating whether to add accept headers [Headers("Accept: application/json")]. + /// + [JsonPropertyName("addAcceptHeaders")] + public bool AddAcceptHeaders { get; set; } = true; + + /// + /// Gets or sets a value indicating whether to return IApiResponse objects. + /// + [JsonPropertyName("returnIApiResponse")] + public bool ReturnIApiResponse { get; set; } + + /// + /// Gets or sets a value indicating whether to generate operation headers. + /// + [JsonPropertyName("generateOperationHeaders")] + public bool GenerateOperationHeaders { get; set; } = true; + + /// + /// Gets or sets the generated type accessibility. (default: Public) + /// + [JsonPropertyName("typeAccessibility")] + public TypeAccessibility TypeAccessibility { get; set; } = TypeAccessibility.Public; + + /// + /// Enable or disable the use of cancellation tokens. + /// + [JsonPropertyName("useCancellationTokens")] + public bool UseCancellationTokens { get; set; } + + /// + /// Set to true to explicitly format date query string parameters + /// in ISO 8601 standard date format using delimiters (for example: 2023-06-15) + /// + [JsonPropertyName("useIsoDateFormat")] + public bool UseIsoDateFormat { get; set; } + + /// + /// Add additional namespace to generated types + /// + [JsonPropertyName("additionalNamespaces")] + public string[] AdditionalNamespaces { get; set; } = Array.Empty(); + + /// + /// Set to true to Generate a Refit interface for each endpoint + /// + [JsonPropertyName("multipleInterfaces")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public MultipleInterfaces MultipleInterfaces { get; set; } + + /// + /// Set to true to Generate a Refit interface for each endpoint + /// + [JsonPropertyName("includePathMatches")] + public string[] IncludePathMatches { get; set; } = Array.Empty(); + + /// + /// Set to true to Generate a Refit interface for each endpoint + /// + [JsonPropertyName("includeTags")] + public string[] IncludeTags { get; set; } = Array.Empty(); + + /// + /// Set to true to generate deprecated operations, otherwise false + /// + [JsonPropertyName("generateDeprecatedOperations")] + public bool GenerateDeprecatedOperations { get; set; } = true; + + /// + /// Generate operation names using pattern. + /// When using --multiple-interfaces ByEndpoint, this is name of the Execute() method in the interface. + /// + [JsonPropertyName("operationNameTemplate")] + public string? OperationNameTemplate { get; set; } + + /// + /// Set to true to re-order optional parameters to the end of the parameter list + /// + [JsonPropertyName("optionalParameters")] + public bool OptionalParameters { get; set; } + + /// + /// Gets or sets the relative path to a folder in which the output files are generated. (default: ./Generated) + /// + [JsonPropertyName("outputFolder")] + public string OutputFolder { get; set; } = "./Generated"; + + /// + /// Gets or sets the settings describing how to register generated interface to the .NET Core DI container + /// + [JsonPropertyName("dependencyInjectionSettings")] + public DependencyInjectionSettings? DependencyInjectionSettings { get; set; } + + /// + /// Gets or sets the settings describing how to generate types using NSwag + /// + [JsonPropertyName("codeGeneratorSettings")] + public NSwagCodeGeneratorSettings? CodeGeneratorSettings { get; set; } +} \ No newline at end of file diff --git a/src/Refitter.Core/Settings/TypeAccessibility.cs b/src/Refitter.Core/Settings/TypeAccessibility.cs new file mode 100644 index 00000000..5eb28a6b --- /dev/null +++ b/src/Refitter.Core/Settings/TypeAccessibility.cs @@ -0,0 +1,17 @@ +namespace Refitter.Core; + +/// +/// Specifies the accessibility of a type. +/// +public enum TypeAccessibility +{ + /// + /// Indicates that the type is accessible by any assembly that references it. + /// + Public, + + /// + /// Indicates that the type is only accessible within its own assembly. + /// + Internal +} \ No newline at end of file diff --git a/src/Refitter.SourceGenerator/Refitter.SourceGenerator.csproj b/src/Refitter.SourceGenerator/Refitter.SourceGenerator.csproj index bd5c7c77..5acbc488 100644 --- a/src/Refitter.SourceGenerator/Refitter.SourceGenerator.csproj +++ b/src/Refitter.SourceGenerator/Refitter.SourceGenerator.csproj @@ -25,6 +25,7 @@ + \ No newline at end of file From 9d47c6dc0d81ae67ac95cf67351bc2be351991da Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 23:18:30 +0200 Subject: [PATCH 12/23] Remove unnecessary properties from NSwagCodeGeneratorSettings This commit removes several class properties from NSwagCodeGeneratorSettings. This includes ClassStyle, JsonLibrary and TypeAccessModifier properties. These properties were not being used and removing them helps to declutter the class and improve code readability without impacting functionality. --- .../Settings/NSwagCodeGeneratorSettings.cs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/Refitter.Core/Settings/NSwagCodeGeneratorSettings.cs b/src/Refitter.Core/Settings/NSwagCodeGeneratorSettings.cs index 28f9bc72..9e00845c 100644 --- a/src/Refitter.Core/Settings/NSwagCodeGeneratorSettings.cs +++ b/src/Refitter.Core/Settings/NSwagCodeGeneratorSettings.cs @@ -80,23 +80,6 @@ public class NSwagCodeGeneratorSettings /// public string DictionaryBaseType { get; set; } = "System.Collections.Generic.Dictionary"; - /// - /// Gets or sets the CSharp class style (default: 'Poco'). - /// - [JsonConverter(typeof(JsonStringEnumConverter))] - public CSharpClassStyle ClassStyle { get; set; } = CSharpClassStyle.Poco; - - /// - /// Gets or sets the CSharp JSON library to use (default: 'NewtonsoftJson', 'SystemTextJson' is experimental/not complete). - /// - [JsonConverter(typeof(JsonStringEnumConverter))] - public CSharpJsonLibrary JsonLibrary { get; set; } = CSharpJsonLibrary.NewtonsoftJson; - - /// - /// Gets or sets the access modifier of generated classes and interfaces (default: 'public'). - /// - public string TypeAccessModifier { get; set; } = "public"; - /// /// Gets the access modifier of property setters (default: ''). /// From 8db73f9289327566a27337361e3e7cbc6a4d5422 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Wed, 11 Oct 2023 23:20:46 +0200 Subject: [PATCH 13/23] Add "codeGeneratorSettings" to README and docs This commit introduces a new "codeGeneratorSettings" section to our project README and documentation. These settings allow users to tailor the output of our code generator to meet their specific requirements. Update not only provides more granular control over the code generation process but also improves adaptability for a variety of project architectures and coding standards. --- README.md | 31 ++++++++++++++++++- .../articles/refitter-file-format.md | 29 +++++++++++++++++ src/Refitter.SourceGenerator/README.md | 29 +++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a07bb75..495e7575 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ The following is an example `.refitter` file "^/pet/.*", "^/store/.*" ], - "dependencyInjectionSettings": { + "dependencyInjectionSettings": { // Optional "baseUrl": "https://petstore3.swagger.io/api/v3", // Optional. Leave this blank to set the base address manually "httpMessageHandlers": [ // Optional "AuthorizationMessageHandler", @@ -161,6 +161,35 @@ The following is an example `.refitter` file "usePolly": true, // Optional. Set this to true, to configure Polly with a retry policy that uses a jittered backoff. Default=false "pollyMaxRetryCount": 3, // Optional. Default=6 "firstBackoffRetryInSeconds": 0.5 // Optional. Default=1.0 + }, + "codeGeneratorSettings": { // Optional. Default settings are the values set in this example + "namespace": "GeneratedCode", + "requiredPropertiesMustBeDefined": true, + "generateDataAnnotations": true, + "anyType": "object", + "dateType": "System.DateTimeOffset", + "dateTimeType": "System.DateTimeOffset", + "timeType": "System.TimeSpan", + "timeSpanType": "System.TimeSpan", + "arrayType": "System.Collections.Generic.ICollection", + "dictionaryType": "System.Collections.Generic.IDictionary", + "arrayInstanceType": "System.Collections.ObjectModel.Collection", + "dictionaryInstanceType": "System.Collections.Generic.Dictionary", + "arrayBaseType": "System.Collections.ObjectModel.Collection", + "dictionaryBaseType": "System.Collections.Generic.Dictionary", + "propertySetterAccessModifier": "", + "generateImmutableArrayProperties": false, + "generateImmutableDictionaryProperties": false, + "handleReferences": false, + "jsonSerializerSettingsTransformationMethod": null, + "generateJsonMethods": false, + "enforceFlagEnums": false, + "inlineNamedDictionaries": false, + "inlineNamedTuples": true, + "inlineNamedArrays": false, + "generateOptionalPropertiesAsNullable": false, + "generateNullableReferenceTypes": false, + "generateNativeRecords": false } } ``` diff --git a/docs/docfx_project/articles/refitter-file-format.md b/docs/docfx_project/articles/refitter-file-format.md index 3b769ecd..907c0b08 100644 --- a/docs/docfx_project/articles/refitter-file-format.md +++ b/docs/docfx_project/articles/refitter-file-format.md @@ -46,6 +46,35 @@ The following is an example `.refitter` file "usePolly": true, // Optional. Set this to true, to configure Polly with a retry policy that uses a jittered backoff. Default=false "pollyMaxRetryCount": 3, // Optional. Default=6 "firstBackoffRetryInSeconds": 0.5 // Optional. Default=1.0 + }, + "codeGeneratorSettings": { // Optional. Default settings are the values set in this example + "namespace": "GeneratedCode", + "requiredPropertiesMustBeDefined": true, + "generateDataAnnotations": true, + "anyType": "object", + "dateType": "System.DateTimeOffset", + "dateTimeType": "System.DateTimeOffset", + "timeType": "System.TimeSpan", + "timeSpanType": "System.TimeSpan", + "arrayType": "System.Collections.Generic.ICollection", + "dictionaryType": "System.Collections.Generic.IDictionary", + "arrayInstanceType": "System.Collections.ObjectModel.Collection", + "dictionaryInstanceType": "System.Collections.Generic.Dictionary", + "arrayBaseType": "System.Collections.ObjectModel.Collection", + "dictionaryBaseType": "System.Collections.Generic.Dictionary", + "propertySetterAccessModifier": "", + "generateImmutableArrayProperties": false, + "generateImmutableDictionaryProperties": false, + "handleReferences": false, + "jsonSerializerSettingsTransformationMethod": null, + "generateJsonMethods": false, + "enforceFlagEnums": false, + "inlineNamedDictionaries": false, + "inlineNamedTuples": true, + "inlineNamedArrays": false, + "generateOptionalPropertiesAsNullable": false, + "generateNullableReferenceTypes": false, + "generateNativeRecords": false } } ``` diff --git a/src/Refitter.SourceGenerator/README.md b/src/Refitter.SourceGenerator/README.md index 553b0884..2d3b4a80 100644 --- a/src/Refitter.SourceGenerator/README.md +++ b/src/Refitter.SourceGenerator/README.md @@ -68,6 +68,35 @@ The following is an example `.refitter` file "usePolly": true, // Optional. Set this to true, to configure Polly with a retry policy that uses a jittered backoff. Default=false "pollyMaxRetryCount": 3, // Optional. Default=6 "firstBackoffRetryInSeconds": 0.5 // Optional. Default=1.0 + }, + "codeGeneratorSettings": { // Optional. Default settings are the values set in this example + "namespace": "GeneratedCode", + "requiredPropertiesMustBeDefined": true, + "generateDataAnnotations": true, + "anyType": "object", + "dateType": "System.DateTimeOffset", + "dateTimeType": "System.DateTimeOffset", + "timeType": "System.TimeSpan", + "timeSpanType": "System.TimeSpan", + "arrayType": "System.Collections.Generic.ICollection", + "dictionaryType": "System.Collections.Generic.IDictionary", + "arrayInstanceType": "System.Collections.ObjectModel.Collection", + "dictionaryInstanceType": "System.Collections.Generic.Dictionary", + "arrayBaseType": "System.Collections.ObjectModel.Collection", + "dictionaryBaseType": "System.Collections.Generic.Dictionary", + "propertySetterAccessModifier": "", + "generateImmutableArrayProperties": false, + "generateImmutableDictionaryProperties": false, + "handleReferences": false, + "jsonSerializerSettingsTransformationMethod": null, + "generateJsonMethods": false, + "enforceFlagEnums": false, + "inlineNamedDictionaries": false, + "inlineNamedTuples": true, + "inlineNamedArrays": false, + "generateOptionalPropertiesAsNullable": false, + "generateNullableReferenceTypes": false, + "generateNativeRecords": false } } ``` From f220ea894d64652c1cc777108b49f5b935e7a7a7 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Thu, 12 Oct 2023 00:58:17 +0200 Subject: [PATCH 14/23] Update Serializer.cs with comments and remove CamelCase naming The JsonNamingPolicy.CamelCase was removed from JsonSerializerOptions since the case-insensitivity setting simplifies our JSON handling. Detailed comments have also been added to improve readability and code understanding. --- src/Refitter.Core/Serializer.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Refitter.Core/Serializer.cs b/src/Refitter.Core/Serializer.cs index 7786580e..c08684f0 100644 --- a/src/Refitter.Core/Serializer.cs +++ b/src/Refitter.Core/Serializer.cs @@ -1,21 +1,34 @@ using System.Text.Json; -using JsonNamingPolicy = System.Text.Json.JsonNamingPolicy; using JsonSerializerOptions = System.Text.Json.JsonSerializerOptions; namespace Refitter.Core; +/// +/// Provides methods for serializing and deserializing objects to and from JSON. +/// This serializer is configured to be case-insensitive. +/// public static class Serializer { private static readonly JsonSerializerOptions JsonSerializerOptions = new() { - PropertyNameCaseInsensitive = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + PropertyNameCaseInsensitive = true }; + /// + /// Deserializes the JSON string to the specified type. + /// + /// The type to deserialize the JSON string to. + /// The JSON string to deserialize. + /// The deserialized object of type T. public static T Deserialize(string json) => JsonSerializer.Deserialize(json, JsonSerializerOptions)!; + /// + /// Serializes the specified object to a JSON string. + /// + /// The object to serialize. + /// The JSON string representation of the object. public static string Serialize(object any) => JsonSerializer.Serialize(any, JsonSerializerOptions); } \ No newline at end of file From 947771d23b4a5b6e2421bd557ed38127c3535fc1 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Thu, 12 Oct 2023 00:58:41 +0200 Subject: [PATCH 15/23] Update documentation to include `codeGeneratorSettings` Added detailed `codeGeneratorSettings` to README.md and refitter-file-format.md. This update provides information about NSwag code generation customization, improving users' understanding of how they can manipulate the generated types and contracts. --- README.md | 28 ++++++++++++++++ .../articles/refitter-file-format.md | 32 ++++++++++++++++++- src/Refitter.SourceGenerator/README.md | 30 ++++++++++++++++- 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 495e7575..f152faa6 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,34 @@ The following is an example `.refitter` file - `usePolly` - Set this to true to configure the HttpClient to use Polly using a retry policy with a jittered backoff - `pollyMaxRetryCount` - This is the max retry count used in the Polly retry policy. Default is 6 - `firstBackoffRetryInSeconds` - This is the duration of the initial retry backoff. Default is 1 second +- `codeGeneratorSettings` - Setting this allows customization of the NSwag generated types and contracts + - `namespace` - Default is `GeneratedCode`, + - `requiredPropertiesMustBeDefined` - Default is true, + - `generateDataAnnotations` - Default is true, + - `anyType` - Default is `object`, + - `dateType` - Default is `System.DateTimeOffset`, + - `dateTimeType` - Default is `System.DateTimeOffset`, + - `timeType` - Default is `System.TimeSpan`, + - `timeSpanType` - Default is `System.TimeSpan`, + - `arrayType` - Default is `System.Collections.Generic.ICollection`, + - `dictionaryType` - Default is `System.Collections.Generic.IDictionary`, + - `arrayInstanceType` - Default is `System.Collections.ObjectModel.Collection`, + - `dictionaryInstanceType` - Default is `System.Collections.Generic.Dictionary`, + - `arrayBaseType` - Default is `System.Collections.ObjectModel.Collection`, + - `dictionaryBaseType` - Default is `System.Collections.Generic.Dictionary`, + - `propertySetterAccessModifier` - Default is ``, + - `generateImmutableArrayProperties` - Default is false, + - `generateImmutableDictionaryProperties` - Default is false, + - `handleReferences` - Default is false, + - `jsonSerializerSettingsTransformationMethod` - Default is null, + - `generateJsonMethods` - Default is false, + - `enforceFlagEnums` - Default is false, + - `inlineNamedDictionaries` - Default is false, + - `inlineNamedTuples` - Default is true, + - `inlineNamedArrays` - Default is false, + - `generateOptionalPropertiesAsNullable` - Default is false, + - `generateNullableReferenceTypes` - Default is false, + - `generateNativeRecords` - Default is false # Using the generated code diff --git a/docs/docfx_project/articles/refitter-file-format.md b/docs/docfx_project/articles/refitter-file-format.md index 907c0b08..dd379898 100644 --- a/docs/docfx_project/articles/refitter-file-format.md +++ b/docs/docfx_project/articles/refitter-file-format.md @@ -1,5 +1,7 @@ ## .Refitter File format +The `.refitter` file is a JSON serialized version of the [RefitGeneratorSettings](/api/Refitter.Core.RefitGeneratorSettings.html) + The following is an example `.refitter` file ```js @@ -105,4 +107,32 @@ The following is an example `.refitter` file - `httpMessageHandlers` - A collection of `HttpMessageHandler` that is added to the HttpClient pipeline - `usePolly` - Set this to true to configure the HttpClient to use Polly using a retry policy with a jittered backoff - `pollyMaxRetryCount` - This is the max retry count used in the Polly retry policy. Default is 6 - - `firstBackoffRetryInSeconds` - This is the duration of the initial retry backoff. Default is 1 second \ No newline at end of file + - `firstBackoffRetryInSeconds` - This is the duration of the initial retry backoff. Default is 1 second +- `codeGeneratorSettings` - Setting this allows customization of the NSwag generated types and contracts + - `namespace` - Default is `GeneratedCode`, + - `requiredPropertiesMustBeDefined` - Default is true, + - `generateDataAnnotations` - Default is true, + - `anyType` - Default is `object`, + - `dateType` - Default is `System.DateTimeOffset`, + - `dateTimeType` - Default is `System.DateTimeOffset`, + - `timeType` - Default is `System.TimeSpan`, + - `timeSpanType` - Default is `System.TimeSpan`, + - `arrayType` - Default is `System.Collections.Generic.ICollection`, + - `dictionaryType` - Default is `System.Collections.Generic.IDictionary`, + - `arrayInstanceType` - Default is `System.Collections.ObjectModel.Collection`, + - `dictionaryInstanceType` - Default is `System.Collections.Generic.Dictionary`, + - `arrayBaseType` - Default is `System.Collections.ObjectModel.Collection`, + - `dictionaryBaseType` - Default is `System.Collections.Generic.Dictionary`, + - `propertySetterAccessModifier` - Default is ``, + - `generateImmutableArrayProperties` - Default is false, + - `generateImmutableDictionaryProperties` - Default is false, + - `handleReferences` - Default is false, + - `jsonSerializerSettingsTransformationMethod` - Default is null, + - `generateJsonMethods` - Default is false, + - `enforceFlagEnums` - Default is false, + - `inlineNamedDictionaries` - Default is false, + - `inlineNamedTuples` - Default is true, + - `inlineNamedArrays` - Default is false, + - `generateOptionalPropertiesAsNullable` - Default is false, + - `generateNullableReferenceTypes` - Default is false, + - `generateNativeRecords` - Default is false \ No newline at end of file diff --git a/src/Refitter.SourceGenerator/README.md b/src/Refitter.SourceGenerator/README.md index 2d3b4a80..cf83408b 100644 --- a/src/Refitter.SourceGenerator/README.md +++ b/src/Refitter.SourceGenerator/README.md @@ -127,4 +127,32 @@ The following is an example `.refitter` file - `httpMessageHandlers` - A collection of `HttpMessageHandler` that is added to the HttpClient pipeline - `usePolly` - Set this to true to configure the HttpClient to use Polly using a retry policy with a jittered backoff - `pollyMaxRetryCount` - This is the max retry count used in the Polly retry policy. Default is 6 - - `firstBackoffRetryInSeconds` - This is the duration of the initial retry backoff. Default is 1 second \ No newline at end of file + - `firstBackoffRetryInSeconds` - This is the duration of the initial retry backoff. Default is 1 second +- `codeGeneratorSettings` - Setting this allows customization of the NSwag generated types and contracts + - `namespace` - Default is `GeneratedCode`, + - `requiredPropertiesMustBeDefined` - Default is true, + - `generateDataAnnotations` - Default is true, + - `anyType` - Default is `object`, + - `dateType` - Default is `System.DateTimeOffset`, + - `dateTimeType` - Default is `System.DateTimeOffset`, + - `timeType` - Default is `System.TimeSpan`, + - `timeSpanType` - Default is `System.TimeSpan`, + - `arrayType` - Default is `System.Collections.Generic.ICollection`, + - `dictionaryType` - Default is `System.Collections.Generic.IDictionary`, + - `arrayInstanceType` - Default is `System.Collections.ObjectModel.Collection`, + - `dictionaryInstanceType` - Default is `System.Collections.Generic.Dictionary`, + - `arrayBaseType` - Default is `System.Collections.ObjectModel.Collection`, + - `dictionaryBaseType` - Default is `System.Collections.Generic.Dictionary`, + - `propertySetterAccessModifier` - Default is ``, + - `generateImmutableArrayProperties` - Default is false, + - `generateImmutableDictionaryProperties` - Default is false, + - `handleReferences` - Default is false, + - `jsonSerializerSettingsTransformationMethod` - Default is null, + - `generateJsonMethods` - Default is false, + - `enforceFlagEnums` - Default is false, + - `inlineNamedDictionaries` - Default is false, + - `inlineNamedTuples` - Default is true, + - `inlineNamedArrays` - Default is false, + - `generateOptionalPropertiesAsNullable` - Default is false, + - `generateNullableReferenceTypes` - Default is false, + - `generateNativeRecords` - Default is false \ No newline at end of file From e4c02ee1709e7aba0ae6d48d9d2fd0ef76c5f37f Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Thu, 12 Oct 2023 01:01:31 +0200 Subject: [PATCH 16/23] Add explanations for Refitter file properties Added basic explanations for each property in the Refitter file format. This update enhances clarity for users reading the documentation, helping them understand each property's purpose. --- docs/docfx_project/articles/refitter-file-format.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docfx_project/articles/refitter-file-format.md b/docs/docfx_project/articles/refitter-file-format.md index dd379898..06a159f0 100644 --- a/docs/docfx_project/articles/refitter-file-format.md +++ b/docs/docfx_project/articles/refitter-file-format.md @@ -81,6 +81,8 @@ The following is an example `.refitter` file } ``` +Here are some basic explanations of each property: + - `openApiPath` - points to the OpenAPI Specifications file. This can be the path to a file stored on disk, relative to the `.refitter` file. This can also be a URL to a remote file that will be downloaded over HTTP/HTTPS - `namespace` - the namespace used in the generated code. If not specified, this defaults to `GeneratedCode` - `naming.useOpenApiTitle` - a boolean indicating whether the OpenApi title should be used. Default is `true` From ebab1ea0a0f7fa2264dd17bad41845c992492031 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Thu, 12 Oct 2023 01:02:16 +0200 Subject: [PATCH 17/23] Refactor NSwagCodeGeneratorSettings to CodeGeneratorSettings The class NSwagCodeGeneratorSettings has been renamed to CodeGeneratorSettings. This refactoring intends to make the class more generic, eliminating the reference to NSwag in its naming, given it's used for setting code generation parameters without depending specifically on NSwag. This change affects also its instances and references within both the test and core files within the Refitter project. --- src/Refitter.Core/CSharpClientGeneratorFactory.cs | 4 ++-- ...GeneratorSettings.cs => CodeGeneratorSettings.cs} | 8 ++------ src/Refitter.Core/Settings/RefitGeneratorSettings.cs | 2 +- .../CustomCSharpGeneratorSettingsTests.cs | 12 ++++++------ 4 files changed, 11 insertions(+), 15 deletions(-) rename src/Refitter.Core/Settings/{NSwagCodeGeneratorSettings.cs => CodeGeneratorSettings.cs} (97%) diff --git a/src/Refitter.Core/CSharpClientGeneratorFactory.cs b/src/Refitter.Core/CSharpClientGeneratorFactory.cs index 8c92a7b6..24f8bb6a 100644 --- a/src/Refitter.Core/CSharpClientGeneratorFactory.cs +++ b/src/Refitter.Core/CSharpClientGeneratorFactory.cs @@ -39,7 +39,7 @@ public CustomCSharpClientGenerator Create() } private static void MapCSharpGeneratorSettings( - NSwagCodeGeneratorSettings? source, + CodeGeneratorSettings? source, CSharpGeneratorSettings destination) { if (source is null) @@ -47,7 +47,7 @@ private static void MapCSharpGeneratorSettings( return; } - var defaultInstance = new NSwagCodeGeneratorSettings(); + var defaultInstance = new CodeGeneratorSettings(); foreach (var property in source.GetType().GetProperties()) { if (property.PropertyType != typeof(string) && diff --git a/src/Refitter.Core/Settings/NSwagCodeGeneratorSettings.cs b/src/Refitter.Core/Settings/CodeGeneratorSettings.cs similarity index 97% rename from src/Refitter.Core/Settings/NSwagCodeGeneratorSettings.cs rename to src/Refitter.Core/Settings/CodeGeneratorSettings.cs index 9e00845c..4e64dad8 100644 --- a/src/Refitter.Core/Settings/NSwagCodeGeneratorSettings.cs +++ b/src/Refitter.Core/Settings/CodeGeneratorSettings.cs @@ -1,13 +1,9 @@ -using System.Text.Json.Serialization; - -using NJsonSchema.CodeGeneration.CSharp; - -namespace Refitter.Core; +namespace Refitter.Core; /// /// CSharp code generator settings /// -public class NSwagCodeGeneratorSettings +public class CodeGeneratorSettings { /// /// Gets or sets the .NET namespace of the generated types (default: GeneratedCode). diff --git a/src/Refitter.Core/Settings/RefitGeneratorSettings.cs b/src/Refitter.Core/Settings/RefitGeneratorSettings.cs index 8a0aba19..eac0f82f 100644 --- a/src/Refitter.Core/Settings/RefitGeneratorSettings.cs +++ b/src/Refitter.Core/Settings/RefitGeneratorSettings.cs @@ -142,5 +142,5 @@ public class RefitGeneratorSettings /// Gets or sets the settings describing how to generate types using NSwag /// [JsonPropertyName("codeGeneratorSettings")] - public NSwagCodeGeneratorSettings? CodeGeneratorSettings { get; set; } + public CodeGeneratorSettings? CodeGeneratorSettings { get; set; } } \ No newline at end of file diff --git a/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs b/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs index 2f726cd0..b8f46b5d 100644 --- a/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs +++ b/src/Refitter.Tests/CustomCSharpGeneratorSettingsTests.cs @@ -26,7 +26,7 @@ public async Task Can_Generate_Default_DateType( string filename) { var settings = new RefitGeneratorSettings(); - settings.CodeGeneratorSettings = new NSwagCodeGeneratorSettings(); + settings.CodeGeneratorSettings = new CodeGeneratorSettings(); var generateCode = await GenerateCode(version, filename, settings); generateCode.Should().NotBeNullOrWhiteSpace(); generateCode.Should().Contain(settings.CodeGeneratorSettings!.DateType); @@ -42,7 +42,7 @@ public async Task Can_Generate_Default_DateTimeType( string filename) { var settings = new RefitGeneratorSettings(); - settings.CodeGeneratorSettings = new NSwagCodeGeneratorSettings(); + settings.CodeGeneratorSettings = new CodeGeneratorSettings(); var generateCode = await GenerateCode(version, filename, settings); generateCode.Should().NotBeNullOrWhiteSpace(); generateCode.Should().Contain(settings.CodeGeneratorSettings!.DateTimeType); @@ -58,7 +58,7 @@ public async Task Can_Generate_Default_ArrayType( string filename) { var settings = new RefitGeneratorSettings(); - settings.CodeGeneratorSettings = new NSwagCodeGeneratorSettings(); + settings.CodeGeneratorSettings = new CodeGeneratorSettings(); var generateCode = await GenerateCode(version, filename, settings); generateCode.Should().NotBeNullOrWhiteSpace(); generateCode.Should().Contain("ICollection<"); @@ -74,7 +74,7 @@ public async Task Can_Generate_Custom_DateType( string filename) { var settings = new RefitGeneratorSettings(); - settings.CodeGeneratorSettings = new NSwagCodeGeneratorSettings(); + settings.CodeGeneratorSettings = new CodeGeneratorSettings(); settings.CodeGeneratorSettings!.DateType = "DateTime"; var generateCode = await GenerateCode(version, filename, settings); generateCode.Should().NotBeNullOrWhiteSpace(); @@ -91,7 +91,7 @@ public async Task Can_Generate_Custom_DateTimeType( string filename) { var settings = new RefitGeneratorSettings(); - settings.CodeGeneratorSettings = new NSwagCodeGeneratorSettings(); + settings.CodeGeneratorSettings = new CodeGeneratorSettings(); settings.CodeGeneratorSettings!.DateTimeType = "DateTime"; var generateCode = await GenerateCode(version, filename, settings); generateCode.Should().NotBeNullOrWhiteSpace(); @@ -108,7 +108,7 @@ public async Task Can_Generate_Custom_ArrayType( string filename) { var settings = new RefitGeneratorSettings(); - settings.CodeGeneratorSettings = new NSwagCodeGeneratorSettings(); + settings.CodeGeneratorSettings = new CodeGeneratorSettings(); settings.CodeGeneratorSettings!.ArrayType = "System.Collection.Generic.IList"; var generateCode = await GenerateCode(version, filename, settings); generateCode.Should().NotBeNullOrWhiteSpace(); From f0c6b414d21da5d4da92b7c4825baff379f2184a Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Thu, 12 Oct 2023 01:17:07 +0200 Subject: [PATCH 18/23] Add tests for CustomCodeGenerator with System.DateTime A new test class, CustomCodeGeneratorWithDateTimeTests, is introduced in the Refitter.Tests/Examples suite. This class includes tests to validate the correct generation of custom code that handles date and time. These tests confirm that generation code should contain the specific date format, TimeSpan parameter, DateTime parameter, while not containing DateTimeOffset parameter. This helps to ensure the generator is properly supporting date and time types. --- .../CustomCodeGeneratorWithDateTimeTests.cs | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 src/Refitter.Tests/Examples/CustomCodeGeneratorWithDateTimeTests.cs diff --git a/src/Refitter.Tests/Examples/CustomCodeGeneratorWithDateTimeTests.cs b/src/Refitter.Tests/Examples/CustomCodeGeneratorWithDateTimeTests.cs new file mode 100644 index 00000000..1258b245 --- /dev/null +++ b/src/Refitter.Tests/Examples/CustomCodeGeneratorWithDateTimeTests.cs @@ -0,0 +1,148 @@ +using FluentAssertions; + +using Refitter.Core; +using Refitter.Tests.Build; + +using Xunit; + +namespace Refitter.Tests.Examples; + +public class CustomCodeGeneratorWithDateTimeTests +{ + private const string OpenApiSpec = + """ + { + "swagger": "2.0", + "info": { + "title": "Dummy API", + "version": "0.0.0" + }, + "host": "x.io", + "basePath": "/", + "schemes": [ + "https" + ], + "paths": { + "/t/dummy/{employee_id}": { + "get": { + "summary": "X", + "description": "X", + "operationId": "dummy", + "parameters": [ + { + "name": "employee_id", + "in": "path", + "description": "the specific employee", + "required": true, + "format": "int64", + "type": "integer" + }, + { + "name": "valid_from", + "in": "query", + "description": "the start of the period", + "required": true, + "format": "date", + "type": "string" + }, + { + "name": "valid_to", + "in": "query", + "description": "the end of the period", + "required": true, + "format": "date", + "type": "string" + }, + { + "name": "test_time", + "in": "query", + "description": "test parameter", + "required": true, + "format": "time", + "type": "string" + } + ], + "responses": { + "200": { + "description": "No response was specified" + } + } + } + } + } + } + """; + + [Fact] + public async Task Can_Generate_Code() + { + string generateCode = await GenerateCode(); + generateCode.Should().NotBeNullOrWhiteSpace(); + } + + [Fact] + public async Task GeneratedCode_Contains_Date_Format_String() + { + string generateCode = await GenerateCode(); + generateCode.Should().Contain(@"[Query(Format = ""yyyy-MM-dd"")] "); + } + + [Fact] + public async Task GeneratedCode_Contains_TimeSpan_Parameter() + { + string generateCode = await GenerateCode(); + generateCode.Should().Contain("[Query] System.TimeSpan"); + } + + [Fact] + public async Task GeneratedCode_Contains_DateTime_Parameter() + { + string generateCode = await GenerateCode(); + generateCode.Should().Contain("System.DateTime"); + } + + [Fact] + public async Task GeneratedCode_NotContains_DateTimeOffset_Parameter() + { + string generateCode = await GenerateCode(); + generateCode.Should().NotContain("System.DateTimeOffset"); + } + + [Fact] + public async Task Can_Build_Generated_Code() + { + string generateCode = await GenerateCode(); + BuildHelper + .BuildCSharp(generateCode) + .Should() + .BeTrue(); + } + + private static async Task GenerateCode() + { + var swaggerFile = await CreateSwaggerFile(OpenApiSpec); + var settings = new RefitGeneratorSettings + { + OpenApiPath = swaggerFile, + UseIsoDateFormat = true, + CodeGeneratorSettings = new CodeGeneratorSettings + { + DateType = "System.DateTime", + } + }; + + var sut = await RefitGenerator.CreateAsync(settings); + var generateCode = sut.Generate(); + return generateCode; + } + + private static async Task CreateSwaggerFile(string contents) + { + var filename = $"{Guid.NewGuid()}.json"; + var folder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + Directory.CreateDirectory(folder); + var swaggerFile = Path.Combine(folder, filename); + await File.WriteAllTextAsync(swaggerFile, contents); + return swaggerFile; + } +} \ No newline at end of file From 599c844ba297caf0e47754d4706f50fb8be8faa8 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Thu, 12 Oct 2023 01:40:52 +0200 Subject: [PATCH 19/23] Remove UseIsoDateFormat from settings in CustomCodeGeneratorWithDateTimeTests The UseIsoDateFormat setting has been removed from the CustomCodeGeneratorWithDateTimeTests.cs file under the Refitter.Tests project. This attribute was redundant, as the default settings already set date type as System.DateTime, making the specification of using ISO date format unnecessary and potentially confusing. --- .../Examples/CustomCodeGeneratorWithDateTimeTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Refitter.Tests/Examples/CustomCodeGeneratorWithDateTimeTests.cs b/src/Refitter.Tests/Examples/CustomCodeGeneratorWithDateTimeTests.cs index 1258b245..2ee359f9 100644 --- a/src/Refitter.Tests/Examples/CustomCodeGeneratorWithDateTimeTests.cs +++ b/src/Refitter.Tests/Examples/CustomCodeGeneratorWithDateTimeTests.cs @@ -124,7 +124,6 @@ private static async Task GenerateCode() var settings = new RefitGeneratorSettings { OpenApiPath = swaggerFile, - UseIsoDateFormat = true, CodeGeneratorSettings = new CodeGeneratorSettings { DateType = "System.DateTime", From 8e2e9f1b687bd0ebcc7586cbc3883ab7b5ee471e Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Thu, 12 Oct 2023 01:42:06 +0200 Subject: [PATCH 20/23] Remove redundant date format test The test case `GeneratedCode_Contains_Date_Format_String` was removed from `CustomCodeGeneratorWithDateTimeTests.cs`. It was unnecessary as the date format is not a concern of the code generator and therefore does not need to be tested here. --- .../Examples/CustomCodeGeneratorWithDateTimeTests.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Refitter.Tests/Examples/CustomCodeGeneratorWithDateTimeTests.cs b/src/Refitter.Tests/Examples/CustomCodeGeneratorWithDateTimeTests.cs index 2ee359f9..657ae446 100644 --- a/src/Refitter.Tests/Examples/CustomCodeGeneratorWithDateTimeTests.cs +++ b/src/Refitter.Tests/Examples/CustomCodeGeneratorWithDateTimeTests.cs @@ -80,13 +80,6 @@ public async Task Can_Generate_Code() generateCode.Should().NotBeNullOrWhiteSpace(); } - [Fact] - public async Task GeneratedCode_Contains_Date_Format_String() - { - string generateCode = await GenerateCode(); - generateCode.Should().Contain(@"[Query(Format = ""yyyy-MM-dd"")] "); - } - [Fact] public async Task GeneratedCode_Contains_TimeSpan_Parameter() { From eef96ca7a6ea69efb3a963e575bf97eba0b8c744 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Thu, 12 Oct 2023 09:47:04 +0200 Subject: [PATCH 21/23] Add Serializer tests --- src/Refitter.Tests/SerializerTests.cs | 56 +++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/Refitter.Tests/SerializerTests.cs diff --git a/src/Refitter.Tests/SerializerTests.cs b/src/Refitter.Tests/SerializerTests.cs new file mode 100644 index 00000000..fee8288d --- /dev/null +++ b/src/Refitter.Tests/SerializerTests.cs @@ -0,0 +1,56 @@ +using System.Diagnostics; +using System.Reflection; +using System.Text.Json; + +using Atc.Test; + +using FluentAssertions; + +using Refitter.Core; + +using Xunit; + +namespace Refitter.Tests; + +public class SerializerTests +{ + [Theory, AutoNSubstituteData] + public void Can_Serialize_RefitGeneratorSettings( + RefitGeneratorSettings settings) + { + Serializer + .Serialize(settings) + .Should() + .NotBeNullOrWhiteSpace(); + } + + [Theory, AutoNSubstituteData] + public void Can_Deserialize_RefitGeneratorSettings( + RefitGeneratorSettings settings) + { + var json = Serializer.Serialize(settings); + Serializer + .Deserialize(json) + .Should() + .BeEquivalentTo(settings); + } + + [Theory, AutoNSubstituteData] + public void Deserialize_Is_Case_Insensitive( + RefitGeneratorSettings settings) + { + var json = Serializer.Serialize(settings); + foreach (var property in typeof(RefitGeneratorSettings).GetProperties()) + { + var jsonProperty = "\"" + property.Name + "\""; + json = json.Replace( + jsonProperty, + jsonProperty.ToUpperInvariant()); + } + + Serializer + .Deserialize(json) + .Should() + .BeEquivalentTo(settings); + } +} From a4f57992f1bf130596d48f401df22a0f4eb7a52e Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Thu, 12 Oct 2023 09:59:40 +0200 Subject: [PATCH 22/23] Add new configuration options to CodeGeneratorSettings Added three new properties to CodeGeneratorSettings: GenerateDefaultValues, InlineNamedAny, and ExcludedTypeNames. GenerateDefaultValues will manage whether to generate default values for properties, InlineNamedAny indicates whether to inline any named/referenced schemas or generate them as a class, and ExcludedTypeNames will store excluded type names. These changes give users more control over code generation, making the tool more flexible to accommodate different project requirements. The README files have been updated to include these new options. --- README.md | 11 ++++++++++- .../Settings/CodeGeneratorSettings.cs | 15 +++++++++++++++ src/Refitter.SourceGenerator/README.md | 15 ++++++++++++--- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f152faa6..e1155bc3 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,13 @@ The following is an example `.refitter` file "inlineNamedArrays": false, "generateOptionalPropertiesAsNullable": false, "generateNullableReferenceTypes": false, - "generateNativeRecords": false + "generateNativeRecords": false, + "generateDefaultValues": true, + "inlineNamedAny": false, + "excludedTypeNames": [ + "ExcludedTypeFoo", + "ExcludedTypeBar" + ] } } ``` @@ -249,6 +255,9 @@ The following is an example `.refitter` file - `generateOptionalPropertiesAsNullable` - Default is false, - `generateNullableReferenceTypes` - Default is false, - `generateNativeRecords` - Default is false + - `generateDefaultValues` - Default is true + - `inlineNamedAny` - Default is false + - `excludedTypeNames` - Default is empty # Using the generated code diff --git a/src/Refitter.Core/Settings/CodeGeneratorSettings.cs b/src/Refitter.Core/Settings/CodeGeneratorSettings.cs index 4e64dad8..bda4199e 100644 --- a/src/Refitter.Core/Settings/CodeGeneratorSettings.cs +++ b/src/Refitter.Core/Settings/CodeGeneratorSettings.cs @@ -145,4 +145,19 @@ public class CodeGeneratorSettings /// Generate C# 9.0 record types instead of record-like classes. /// public bool GenerateNativeRecords { get; set; } + + /// + /// Gets or sets a value indicating whether to generate default values for properties (when JSON Schema default is set, default: true). + /// + public bool GenerateDefaultValues { get; set; } = true; + + /// + /// Gets or sets a value indicating whether named/referenced any schemas should be inlined or generated as class. + /// + public bool InlineNamedAny { get; set; } + + /// + /// Gets or sets the excluded type names (must be defined in an import or other namespace). + /// + public string[] ExcludedTypeNames { get; set; } = Array.Empty(); } \ No newline at end of file diff --git a/src/Refitter.SourceGenerator/README.md b/src/Refitter.SourceGenerator/README.md index cf83408b..ad26ce2a 100644 --- a/src/Refitter.SourceGenerator/README.md +++ b/src/Refitter.SourceGenerator/README.md @@ -96,7 +96,13 @@ The following is an example `.refitter` file "inlineNamedArrays": false, "generateOptionalPropertiesAsNullable": false, "generateNullableReferenceTypes": false, - "generateNativeRecords": false + "generateNativeRecords": false, + "generateDefaultValues": true, + "inlineNamedAny": false, + "excludedTypeNames": [ + "ExcludedTypeFoo", + "ExcludedTypeBar" + ] } } ``` @@ -120,7 +126,7 @@ The following is an example `.refitter` file - `includeTags` - A collection of tags to use a filter for including endpoints that contain this tag. - `includePathMatches` - A collection of regular expressions used to filter paths. - `generateDeprecatedOperations` - a boolean indicating whether deprecated operations should be generated or skipped. Default is `true` -- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using multipleIinterfaces=ByEndpoint, This is name of the Execute() method in the interface +- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async - `optionalParameters` - Generate non-required parameters as nullable optional parameters - `dependencyInjectionSettings` - Setting this will generated extension methods to `IServiceCollection` for configuring Refit clients - `baseUrl` - Used as the HttpClient base address. Leave this blank to manually set the base URL @@ -155,4 +161,7 @@ The following is an example `.refitter` file - `inlineNamedArrays` - Default is false, - `generateOptionalPropertiesAsNullable` - Default is false, - `generateNullableReferenceTypes` - Default is false, - - `generateNativeRecords` - Default is false \ No newline at end of file + - `generateNativeRecords` - Default is false + - `generateDefaultValues` - Default is true + - `inlineNamedAny` - Default is false + - `excludedTypeNames` - Default is empty \ No newline at end of file From e2c24b847657520aeb9f05ad3be14549fc029b2e Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Thu, 12 Oct 2023 10:08:08 +0200 Subject: [PATCH 23/23] Update docfx article on .refitter file format [skip ci] --- docs/docfx_project/articles/refitter-file-format.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/docfx_project/articles/refitter-file-format.md b/docs/docfx_project/articles/refitter-file-format.md index 06a159f0..ca6c54e8 100644 --- a/docs/docfx_project/articles/refitter-file-format.md +++ b/docs/docfx_project/articles/refitter-file-format.md @@ -76,7 +76,13 @@ The following is an example `.refitter` file "inlineNamedArrays": false, "generateOptionalPropertiesAsNullable": false, "generateNullableReferenceTypes": false, - "generateNativeRecords": false + "generateNativeRecords": false, + "generateDefaultValues": true, + "inlineNamedAny": false, + "excludedTypeNames": [ + "ExcludedTypeFoo", + "ExcludedTypeBar" + ] } } ``` @@ -137,4 +143,7 @@ Here are some basic explanations of each property: - `inlineNamedArrays` - Default is false, - `generateOptionalPropertiesAsNullable` - Default is false, - `generateNullableReferenceTypes` - Default is false, - - `generateNativeRecords` - Default is false \ No newline at end of file + - `generateNativeRecords` - Default is false + - `generateDefaultValues` - Default is true + - `inlineNamedAny` - Default is false + - `excludedTypeNames` - Default is empty \ No newline at end of file