Skip to content

Commit

Permalink
Merge pull request #200 from christianhelle/output-filename
Browse files Browse the repository at this point in the history
Output filename customization
  • Loading branch information
christianhelle authored Oct 28, 2023
2 parents eec04f4 + a213294 commit f834c91
Show file tree
Hide file tree
Showing 19 changed files with 223 additions and 114 deletions.
1 change: 1 addition & 0 deletions .github/workflows/qodana.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
fetch-depth: 0 # a full history is required for pull request analysis
- name: 'Qodana Scan'
uses: JetBrains/qodana-action@v2023.2
continue-on-error: true
with:
push-fixes: pull-request
pr-mode: false
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,10 @@ The following is an example `.refitter` file
"useIsoDateFormat": false, // Optional. Default=false
"multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag"
"generateDeprecatedOperations": false, // Optional. Default=true
"operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}
"operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName} when multipleInterfaces != ByEndpoint
"optionalParameters": false, // Optional. Default=false
"outputFolder": "../CustomOutput" // Optional. Default=./Generated
"outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool
"additionalNamespaces": [ // Optional
"Namespace1",
"Namespace2"
Expand Down Expand Up @@ -215,6 +216,7 @@ The following is an example `.refitter` file
- `useIsoDateFormat` - Set to `true` to explicitly format date query string parameters in ISO 8601 standard date format using delimiters (for example: 2023-06-15). Default is `false`
- `multipleInterfaces` - Set to `ByEndpoint` to generate an interface for each endpoint, or `ByTag` to group Endpoints by their Tag (like SwaggerUI groups them).
- `outputFolder` - a string describing a relative path to a desired output folder. Default is `./Generated`
- `outputFilename` - Output filename. Default is `Output.cs` when used from the CLI tool, otherwise its the .refitter filename. So `Petstore.refitter` becomes `Petstore.cs`.
- `additionalNamespaces` - A collection of additional namespaces to include in the generated file. A use case for this is when you want to reuse contracts from a different namespace than the generated code. Default is empty
- `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.
Expand Down
8 changes: 4 additions & 4 deletions docs/docfx_project/articles/refitter-file-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ The following is an example `.refitter` file
"useIsoDateFormat": false, // Optional. Default=false
"multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag"
"generateDeprecatedOperations": false, // Optional. Default=true
"operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName}
"operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName} when multipleInterfaces != ByEndpoint
"optionalParameters": false, // Optional. Default=false
"outputFolder": "../CustomOutput" // Optional. Default=./Generated
"outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool
"additionalNamespaces": [ // Optional
"Namespace1",
"Namespace2"
Expand All @@ -39,7 +40,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",
Expand Down Expand Up @@ -86,8 +87,6 @@ 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
- `naming.useOpenApiTitle` - a boolean indicating whether the OpenApi title should be used. Default is `true`
- `naming.interfaceName` - the name of the generated interface. The generated code will automatically prefix this with `I` so if this set to `MyApiClient` then the generated interface is called `IMyApiClient`. Default is `ApiClient`
Expand All @@ -102,6 +101,7 @@ Here are some basic explanations of each property:
- `useIsoDateFormat` - Set to `true` to explicitly format date query string parameters in ISO 8601 standard date format using delimiters (for example: 2023-06-15). Default is `false`
- `multipleInterfaces` - Set to `ByEndpoint` to generate an interface for each endpoint, or `ByTag` to group Endpoints by their Tag (like SwaggerUI groups them).
- `outputFolder` - a string describing a relative path to a desired output folder. Default is `./Generated`
- `outputFilename` - Output filename. Default is `Output.cs` when used from the CLI tool, otherwise its the .refitter filename. So `Petstore.refitter` becomes `Petstore.cs`.
- `additionalNamespaces` - A collection of additional namespaces to include in the generated file. A use case for this is when you want to reuse contracts from a different namespace than the generated code. Default is empty
- `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.
Expand Down
3 changes: 2 additions & 1 deletion src/Refitter.Core/Serializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public static class Serializer
{
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
{
PropertyNameCaseInsensitive = true
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};

/// <summary>
Expand Down
9 changes: 1 addition & 8 deletions src/Refitter.Core/Settings/DependencyInjectionSettings.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Text.Json.Serialization;

namespace Refitter.Core;
namespace Refitter.Core;

/// <summary>
/// Dependency Injection settings describing how the Refit client should be configured.
Expand All @@ -11,31 +9,26 @@ public class DependencyInjectionSettings
/// <summary>
/// Base Address for the HttpClient
/// </summary>
[JsonPropertyName("baseUrl")]
public string? BaseUrl { get; set; }

/// <summary>
/// A collection of HttpMessageHandlers to be added to the HttpClient pipeline.
/// This can be for telemetry logging, authorization, etc.
/// </summary>
[JsonPropertyName("httpMessageHandlers")]
public string[] HttpMessageHandlers { get; set; } = Array.Empty<string>();

/// <summary>
/// Set this to true to use Polly for transient fault handling.
/// </summary>
[JsonPropertyName("usePolly")]
public bool UsePolly { get; set; }

/// <summary>
/// Default max retry count for Polly. Default is 6.
/// </summary>
[JsonPropertyName("pollyMaxRetryCount")]
public int PollyMaxRetryCount { get; set; } = 6;

/// <summary>
/// The median delay to target before the first retry in seconds. Default is 1 second
/// </summary>
[JsonPropertyName("firstBackoffRetryInSeconds")]
public double FirstBackoffRetryInSeconds { get; set; } = 1.0;
}
13 changes: 5 additions & 8 deletions src/Refitter.Core/Settings/MultipleInterfaces.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Text.Json.Serialization;

namespace Refitter.Core;
namespace Refitter.Core;

/// <summary>
/// Enum representing the different options for generating multiple Refit interfaces.
Expand All @@ -10,17 +8,16 @@ public enum MultipleInterfaces
/// <summary>
/// Do not generate multiple interfaces
/// </summary>
[JsonPropertyName("unset")] Unset,
Unset,

/// <summary>
/// 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.
/// The method name can be customized using the <see cref="RefitGeneratorSettings.OperationNameTemplate"/> setting.
/// </summary>
[JsonPropertyName("byEndpoint")] ByEndpoint,
ByEndpoint,

/// <summary>
/// Generate a Refit interface for each tag
/// </summary>
[JsonPropertyName("byTag")] ByTag
ByTag
}
3 changes: 0 additions & 3 deletions src/Refitter.Core/Settings/NamingSettings.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;

namespace Refitter.Core;

Expand All @@ -12,12 +11,10 @@ public class NamingSettings
/// <summary>
/// Gets or sets a value indicating whether the OpenApi title should be used. Default is true.
/// </summary>
[JsonPropertyName("useOpenApiTitle")]
public bool UseOpenApiTitle { get; set; } = true;

/// <summary>
/// Gets or sets the name of the Interface. Default is "ApiClient".
/// </summary>
[JsonPropertyName("interfaceName")]
public string InterfaceName { get; set; } = "ApiClient";
}
35 changes: 11 additions & 24 deletions src/Refitter.Core/Settings/RefitGeneratorSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,138 +9,125 @@ namespace Refitter.Core;
[ExcludeFromCodeCoverage]
public class RefitGeneratorSettings
{
public const string DefaultOutputFolder = "./Generated";

/// <summary>
/// Gets or sets the path to the Open API.
/// </summary>
[JsonPropertyName("openApiPath")]
public string OpenApiPath { get; set; } = null!;

/// <summary>
/// Gets or sets the namespace for the generated code. (default: GeneratedCode)
/// </summary>
[JsonPropertyName("namespace")]
public string Namespace { get; set; } = "GeneratedCode";

/// <summary>
/// Gets or sets the naming settings.
/// </summary>
[JsonPropertyName("naming")]
public NamingSettings Naming { get; set; } = new();

/// <summary>
/// Gets or sets a value indicating whether contracts should be generated.
/// </summary>
[JsonPropertyName("generateContracts")]
public bool GenerateContracts { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether XML doc comments should be generated.
/// </summary>
[JsonPropertyName("generateXmlDocCodeComments")]
public bool GenerateXmlDocCodeComments { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether to add auto-generated header.
/// </summary>
[JsonPropertyName("addAutoGeneratedHeader")]
public bool AddAutoGeneratedHeader { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether to add accept headers [Headers("Accept: application/json")].
/// </summary>
[JsonPropertyName("addAcceptHeaders")]
public bool AddAcceptHeaders { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether to return <c>IApiResponse</c> objects.
/// </summary>
[JsonPropertyName("returnIApiResponse")]
public bool ReturnIApiResponse { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to generate operation headers.
/// </summary>
[JsonPropertyName("generateOperationHeaders")]
public bool GenerateOperationHeaders { get; set; } = true;

/// <summary>
/// Gets or sets the generated type accessibility. (default: Public)
/// </summary>
[JsonPropertyName("typeAccessibility")]
public TypeAccessibility TypeAccessibility { get; set; } = TypeAccessibility.Public;

/// <summary>
/// Enable or disable the use of cancellation tokens.
/// </summary>
[JsonPropertyName("useCancellationTokens")]
public bool UseCancellationTokens { get; set; }

/// <summary>
/// Set to <c>true</c> to explicitly format date query string parameters
/// in ISO 8601 standard date format using delimiters (for example: 2023-06-15)
/// </summary>
[JsonPropertyName("useIsoDateFormat")]
public bool UseIsoDateFormat { get; set; }

/// <summary>
/// Add additional namespace to generated types
/// </summary>
[JsonPropertyName("additionalNamespaces")]
public string[] AdditionalNamespaces { get; set; } = Array.Empty<string>();

/// <summary>
/// Set to <c>true</c> to Generate a Refit interface for each endpoint
/// </summary>
[JsonPropertyName("multipleInterfaces")]
[JsonConverter(typeof(JsonStringEnumConverter))]
public MultipleInterfaces MultipleInterfaces { get; set; }

/// <summary>
/// Set to <c>true</c> to Generate a Refit interface for each endpoint
/// </summary>
[JsonPropertyName("includePathMatches")]
public string[] IncludePathMatches { get; set; } = Array.Empty<string>();

/// <summary>
/// Set to <c>true</c> to Generate a Refit interface for each endpoint
/// </summary>
[JsonPropertyName("includeTags")]
public string[] IncludeTags { get; set; } = Array.Empty<string>();

/// <summary>
/// Set to <c>true</c> to generate deprecated operations, otherwise <c>false</c>
/// </summary>
[JsonPropertyName("generateDeprecatedOperations")]
public bool GenerateDeprecatedOperations { get; set; } = true;

/// <summary>
/// Generate operation names using pattern.
/// When using <see cref="MultipleInterfaces"/> <see cref="ByEndpoint"/>, this is name of the Execute() method in the interface.
/// When using <see cref="MultipleInterfaces"/> <see cref="Core.MultipleInterfaces.ByEndpoint"/>, this is name of the Execute() method in the interface.
/// </summary>
[JsonPropertyName("operationNameTemplate")]
public string? OperationNameTemplate { get; set; }

/// <summary>
/// Set to <c>true</c> to re-order optional parameters to the end of the parameter list
/// </summary>
[JsonPropertyName("optionalParameters")]
public bool OptionalParameters { get; set; }

/// <summary>
/// Gets or sets the relative path to a folder in which the output files are generated. (default: ./Generated)
/// </summary>
[JsonPropertyName("outputFolder")]
public string OutputFolder { get; set; } = "./Generated";
public string OutputFolder { get; set; } = DefaultOutputFolder;

/// <summary>
/// Gets or sets the filename of the generated code.
/// For the CLI tool, the default is Output.cs
/// For the Source Generator, this is the name of the generated class and the default is [.refitter defined naming OR .refitter filename].g.cs)
/// </summary>
public string? OutputFilename { get; set; }

/// <summary>
/// Gets or sets the settings describing how to register generated interface to the .NET Core DI container
/// </summary>
[JsonPropertyName("dependencyInjectionSettings")]
public DependencyInjectionSettings? DependencyInjectionSettings { get; set; }

/// <summary>
/// Gets or sets the settings describing how to generate types using NSwag
/// </summary>
[JsonPropertyName("codeGeneratorSettings")]
public CodeGeneratorSettings? CodeGeneratorSettings { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"openApiPath": "../Resources/V3/SwaggerPetstore.json",
"namespace": "Refitter.Tests.CustomGenerated",
"outputFolder": "../CustomGenerated",
"outputFileName": "CustomGenerated.cs",
"generateContracts": false,
"additionalNamespaces": ["Refitter.Tests.AdditionalFiles.SingeInterface"],
"naming": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class CustomOutputFolderGeneratorTests
{
[Fact]
public void Can_Create_File_In_Custom_Path() =>
File.Exists("../../../CustomGenerated/SwaggerPetstoreCustomOutputFolder.g.cs").Should().BeTrue();
File.Exists("../../../CustomGenerated/CustomGenerated.cs").Should().BeTrue();

[Fact]
public void Can_Resolve_Refit_Interface() =>
Expand Down
4 changes: 3 additions & 1 deletion src/Refitter.SourceGenerator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ The following is an example `.refitter` file
"operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName} when multipleInterfaces != ByEndpoint
"optionalParameters": false, // Optional. Default=false
"outputFolder": "../CustomOutput" // Optional. Default=./Generated
"outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool
"additionalNamespaces": [ // Optional
"Namespace1",
"Namespace2"
Expand All @@ -59,7 +60,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",
Expand Down Expand Up @@ -122,6 +123,7 @@ The following is an example `.refitter` file
- `useIsoDateFormat` - Set to `true` to explicitly format date query string parameters in ISO 8601 standard date format using delimiters (for example: 2023-06-15). Default is `false`
- `multipleInterfaces` - Set to `ByEndpoint` to generate an interface for each endpoint, or `ByTag` to group Endpoints by their Tag (like SwaggerUI groups them).
- `outputFolder` - a string describing a relative path to a desired output folder. Default is `./Generated`
- `outputFilename` - Output filename. Default is `Output.cs` when used from the CLI tool, otherwise its the .refitter filename. So `Petstore.refitter` becomes `Petstore.cs`.
- `additionalNamespaces` - A collection of additional namespaces to include in the generated file. A use case for this is when you want to reuse contracts from a different namespace than the generated code. Default is empty
- `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.
Expand Down
14 changes: 7 additions & 7 deletions src/Refitter.SourceGenerator/RefitterSourceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,6 @@ private static List<Diagnostic> GenerateCode(

try
{
var filename = Path.GetFileName(file.Path).Replace(".refitter", ".g.cs");
if (filename == ".g.cs")
{
filename = "Refitter.g.cs";
}

var content = file.GetText(cancellationToken)!;
var json = content.ToString();
var settings = Serializer.Deserialize<RefitGeneratorSettings>(json);
Expand Down Expand Up @@ -102,7 +96,13 @@ private static List<Diagnostic> GenerateCode(
cancellationToken.ThrowIfCancellationRequested();
try
{
var folder = Path.Combine(Path.GetDirectoryName(file.Path), settings.OutputFolder);
var filename = settings.OutputFilename ?? Path.GetFileName(file.Path).Replace(".refitter", ".g.cs");
if (filename == ".g.cs")
{
filename = "Refitter.g.cs";
}

var folder = Path.Combine(Path.GetDirectoryName(file.Path)!, settings.OutputFolder);
var output = Path.Combine(folder, filename);
if (!Directory.Exists(folder))
{
Expand Down
Loading

0 comments on commit f834c91

Please sign in to comment.