Skip to content

Commit

Permalink
Merge pull request #227 from christianhelle/sanitize-path
Browse files Browse the repository at this point in the history
  • Loading branch information
christianhelle authored Nov 22, 2023
2 parents 5d90acc + 4fafe4f commit 15639b4
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/Refitter.Core/OperationNameGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public string GetOperationName(
.CapitalizeFirstCharacter()
.ConvertKebabCaseToPascalCase()
.ConvertRouteToCamelCase()
.ConvertSpacesToPascalCase();
.ConvertSpacesToPascalCase()
.ConvertColonsToPascalCase();

public bool CheckForDuplicateOperationIds(
OpenApiDocument document)
Expand Down
32 changes: 31 additions & 1 deletion src/Refitter.Core/RefitGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class RefitGenerator(RefitGeneratorSettings settings, OpenApiDocument doc
/// <returns>A new instance of the <see cref="RefitGenerator"/> class.</returns>
public static async Task<RefitGenerator> CreateAsync(RefitGeneratorSettings settings)
{
var openApiDocument = await OpenApiDocumentFactory.CreateAsync(settings);
var openApiDocument = await GetOpenApiDocument(settings);

ProcessTagFilters(openApiDocument, settings.IncludeTags);
ProcessPathFilters(openApiDocument, settings.IncludePathMatches);
Expand All @@ -27,6 +27,36 @@ public static async Task<RefitGenerator> CreateAsync(RefitGeneratorSettings sett
return new RefitGenerator(settings, openApiDocument);
}

private static async Task<OpenApiDocument> GetOpenApiDocument(RefitGeneratorSettings settings)
{
var specialCharacters = new[]
{
":"
};

return specialCharacters.Aggregate(
await OpenApiDocumentFactory.CreateAsync(settings),
SanitizePath);
}

private static OpenApiDocument SanitizePath(
OpenApiDocument openApiDocument,
string stringToRemove)
{
var paths = openApiDocument.Paths.Keys
.Where(pathKey => pathKey.Contains(stringToRemove))
.ToArray();

foreach (var path in paths)
{
var value = openApiDocument.Paths[path];
openApiDocument.Paths.Remove(path);
openApiDocument.Paths.Add(path.Replace(stringToRemove, string.Empty), value);
}

return openApiDocument;
}

private static void ProcessContractFilter(OpenApiDocument openApiDocument, bool removeUnusedSchema, string[] includeSchemaMatches)
{
if (!removeUnusedSchema)
Expand Down
14 changes: 14 additions & 0 deletions src/Refitter.Core/StringCasingExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public static string ConvertRouteToCamelCase(this string str)

public static string CapitalizeFirstCharacter(this string str)
{
if (string.IsNullOrEmpty(str))
return str;

return str.Substring(0, 1).ToUpperInvariant() +
str.Substring(1, str.Length - 1);
}
Expand All @@ -52,4 +55,15 @@ public static string ConvertSpacesToPascalCase(this string str)

return string.Join(string.Empty, parts);
}

public static string ConvertColonsToPascalCase(this string str)
{
var parts = str.Split(':');
for (var i = 0; i < parts.Length; i++)
{
parts[i] = parts[i].CapitalizeFirstCharacter();
}

return string.Join(string.Empty, parts);
}
}
90 changes: 90 additions & 0 deletions src/Refitter.Tests/Examples/ColonsInPathTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using FluentAssertions;
using FluentAssertions.Execution;
using Refitter.Core;
using Refitter.Tests.Build;
using Xunit;

namespace Refitter.Tests.Examples;

public class ColonsInPathTests
{
private const string OpenApiSpec = @"
swagger: '2.0'
info:
title: Reference parameters
version: v0.0.1
paths:
'/orders/{orderId}/:orderItems/{orderItemId}':
parameters:
- $ref: '#/parameters/OrderId'
- $ref: '#/parameters/OrderItemId'
delete:
summary: Delete an order item
description: >-
This method allows to remove an order item from an order, by specifying
their ids.
responses:
'204':
description: No Content.
parameters:
OrderId:
name: orderId
in: path
description: Identifier of the order.
required: true
type: string
format: uuid
OrderItemId:
name: orderItemId
in: path
description: Identifier of the order item.
required: true
type: string
format: uuid
";

[Fact]
public async Task Can_Generate_Code()
{
var generateCode = await GenerateCode();
generateCode.Should().NotBeNullOrWhiteSpace();
}

[Fact]
public async Task Generates_Path_Without_Colons()
{
var generateCode = await GenerateCode();
using var scope = new AssertionScope();
generateCode.Should().NotContain("/:");
}

[Fact]
public async Task Can_Build_Generated_Code()
{
var generateCode = await GenerateCode();
BuildHelper
.BuildCSharp(generateCode)
.Should()
.BeTrue();
}

private static async Task<string> GenerateCode()
{
var swaggerFile = await CreateSwaggerFile(OpenApiSpec);
var settings = new RefitGeneratorSettings { OpenApiPath = swaggerFile };

var sut = await RefitGenerator.CreateAsync(settings);
var generateCode = sut.Generate();
return generateCode;
}

private static async Task<string> CreateSwaggerFile(string contents)
{
var filename = $"{Guid.NewGuid()}.yml";
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;
}
}
10 changes: 10 additions & 0 deletions src/Refitter.Tests/StringCasingExtensionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ public void CanConvertToCamelCase(string input, string expected)
public void CanCaptilalizeFirstLetter(string input, string expected)
=> input.CapitalizeFirstCharacter().Should().Be(expected);

[Theory]
[InlineData("", "")]
public void CaptilalizeFirstLetterHandlesEmptyStrings(string input, string expected)
=> input.CapitalizeFirstCharacter().Should().Be(expected);

[Theory]
[InlineData("foo/bar", "fooBar")]
public void CanConvertRouteToCamelCase(string input, string expected)
Expand All @@ -30,4 +35,9 @@ public void CanConvertRouteToCamelCase(string input, string expected)
[InlineData("foo bar", "FooBar")]
public void CanConvertSpacesToPascalCase(string input, string expected)
=> input.ConvertSpacesToPascalCase().Should().Be(expected);

[Theory]
[InlineData("foo:bar", "FooBar")]
public void CanConvertColonsToPascalCase(string input, string expected)
=> input.ConvertColonsToPascalCase().Should().Be(expected);
}

0 comments on commit 15639b4

Please sign in to comment.