Skip to content

Commit

Permalink
feat: Added initial endpoints generation.
Browse files Browse the repository at this point in the history
  • Loading branch information
HavenDV committed Jan 7, 2024
1 parent 43b3c3c commit 3ab210e
Show file tree
Hide file tree
Showing 13 changed files with 175 additions and 18 deletions.
12 changes: 11 additions & 1 deletion src/libs/OpenApiGenerator/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static OpenApiDocument GetOpenApiDocument(

openApiDocument.Components ??= new OpenApiComponents();
openApiDocument.Components.Schemas ??= new Dictionary<string, OpenApiSchema>();

return openApiDocument;
}

Expand Down Expand Up @@ -73,6 +73,16 @@ public static string AsArray(this string type)
return $"global::System.Collections.Generic.IList<{type}>";
}

public static string? WithPostfix(this string? type, string postfix)
{
if (type == null)
{
return null;
}

return type + postfix;
}

public static string? GetDefaultValue(this OpenApiSchema schema)
{
return schema.Default?.GetString();
Expand Down
69 changes: 69 additions & 0 deletions src/libs/OpenApiGenerator/Generators/ClientGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Collections.Immutable;
using H.Generators.Extensions;
using Microsoft.CodeAnalysis;
using OpenApiGenerator.Models;

namespace OpenApiGenerator.Generators;

[Generator]
public class ClientGenerator : IIncrementalGenerator
{
#region Constants

private const string Id = "OACG";

#endregion

#region Methods

public void Initialize(IncrementalGeneratorInitializationContext context)
{
var settings = context.DetectSettings();

context.AdditionalTextsProvider
.Where(static text => text.Path.EndsWith(".yaml", StringComparison.InvariantCultureIgnoreCase))
.Combine(settings)
.SelectAndReportExceptions(PrepareData, context, Id)
.SelectMany(static (x, _) => x)
.SelectAndReportExceptions(GetSourceCode, context, Id)
.AddSource(context);
}

private static EquatableArray<EndPoint> PrepareData(
(AdditionalText text, Settings settings) tuple,
CancellationToken cancellationToken = default)
{
var (text, settings) = tuple;
if (settings.UseNSwag)
{
return ImmutableArray<EndPoint>.Empty;
}

var openApiDocument = text.GetOpenApiDocument(cancellationToken);

var includedOperationIds = new HashSet<string>(settings.IncludeOperationIds);

return openApiDocument.Paths.SelectMany(path =>
path.Value.Operations
.Where(x =>
//includedOperationIds.Count == 0 ||
includedOperationIds.Contains(x.Value.OperationId) ||
includedOperationIds.Contains(x.Value.OperationId.ToPropertyName()))
.Select(operation => new EndPoint(
Id: operation.Value.OperationId,
Namespace: settings.Namespace,
ClassName: settings.ClassName)))
.ToImmutableArray();
}

private static FileWithName GetSourceCode(
EndPoint endPoint,
CancellationToken cancellationToken = default)
{
return new FileWithName(
Name: $"{endPoint.FileNameWithoutExtension}.g.cs",
Text: Sources.GenerateEndPoint(endPoint, cancellationToken: cancellationToken));
}

#endregion
}
2 changes: 1 addition & 1 deletion src/libs/OpenApiGenerator/Generators/ModelGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Microsoft.CodeAnalysis;
using OpenApiGenerator.Models;

namespace OpenApiGenerator;
namespace OpenApiGenerator.Generators;

[Generator]
public class ModelGenerator : IIncrementalGenerator
Expand Down
2 changes: 1 addition & 1 deletion src/libs/OpenApiGenerator/Generators/NSwagGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Microsoft.CodeAnalysis;
using OpenApiGenerator.Models;

namespace OpenApiGenerator;
namespace OpenApiGenerator.Generators;

[Generator]
public class NSwagGenerator : IIncrementalGenerator
Expand Down
14 changes: 14 additions & 0 deletions src/libs/OpenApiGenerator/Models/EndPoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using H.Generators.Extensions;

namespace OpenApiGenerator.Models;

internal readonly record struct EndPoint(
string Id,
string Namespace,
string ClassName
)
{
public string MethodName => Id.ToPropertyName();

public string FileNameWithoutExtension => $"{Namespace}.{ClassName}.EndPoints.{MethodName}";
}
14 changes: 12 additions & 2 deletions src/libs/OpenApiGenerator/Models/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ namespace OpenApiGenerator.Models;
internal readonly record struct Settings(
string TargetFramework,
string Namespace,
string ClassName,
NamingConvention NamingConvention,
bool UseNSwag,

EquatableArray<string> IncludeOperationIds,

bool GenerateModels,
ModelStyle ModelStyle,
EquatableArray<string> IncludeModels)
Expand All @@ -22,19 +25,26 @@ public static Settings FromOptions(
TargetFramework: options.GetGlobalOption("TargetFramework", prefix) ??
options.GetGlobalOption("TargetFramework") ??
"netstandard2.0",
Namespace: options.GetGlobalOption("Namespace", prefix) ??
Namespace: options.GetGlobalOption(nameof(Namespace), prefix) ??
options.GetGlobalOption("PackageId") ??
options.GetGlobalOption("AssemblyName") ??
prefix,
ClassName: options.GetGlobalOption(nameof(ClassName), prefix) ??
options.GetGlobalOption("PackageId")?.WithPostfix("Api") ??
options.GetGlobalOption("AssemblyName")?.WithPostfix("Api") ??
"Api",
NamingConvention: Enum.TryParse<NamingConvention>(
options.GetGlobalOption(nameof(NamingConvention), prefix) ??
$"{default(NamingConvention):G}",
ignoreCase: true,
out var namingConvention) ? namingConvention : default,
UseNSwag: bool.TryParse(
options.GetGlobalOption("UseNSwag", prefix),
options.GetGlobalOption(nameof(UseNSwag), prefix),
out var useNSwag) && useNSwag,

IncludeOperationIds: (options.GetGlobalOption(nameof(IncludeOperationIds), prefix)?.Split(';') ??
Array.Empty<string>()).ToImmutableArray(),

GenerateModels: bool.TryParse(
options.GetGlobalOption(nameof(GenerateModels), prefix),
out var generateModels) && generateModels,
Expand Down
5 changes: 5 additions & 0 deletions src/libs/OpenApiGenerator/OpenApiGenerator.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@
<CompilerVisibleProperty Include="OpenApiGenerator_TargetFramework"/>
<!-- Namespace. Default: $(PackageId) or $(AssemblyName) or "OpenApiGenerator" -->
<CompilerVisibleProperty Include="OpenApiGenerator_Namespace"/>
<!-- Namespace. Default: $(PackageId)Api or $(AssemblyName)Api or "Api" -->
<CompilerVisibleProperty Include="OpenApiGenerator_ClassName"/>
<!-- InnerClasses/ConcatNames. Default: InnerClasses -->
<CompilerVisibleProperty Include="OpenApiGenerator_NamingConvention"/>
<!-- true/false. Default: false -->
<CompilerVisibleProperty Include="OpenApiGenerator_UseNSwag"/>

<!-- List of ids separated by ;. Default: Empty(all models) -->
<CompilerVisibleProperty Include="OpenApiGenerator_IncludeOperationIds"/>

<!-- true/false. Default: false -->
<CompilerVisibleProperty Include="OpenApiGenerator_GenerateModels"/>
Expand Down
25 changes: 25 additions & 0 deletions src/libs/OpenApiGenerator/Sources/Sources.EndPoints.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using H.Generators.Extensions;
using OpenApiGenerator.Models;

namespace OpenApiGenerator;

internal static partial class Sources
{
public static string GenerateEndPoint(
EndPoint endPoint,
CancellationToken cancellationToken = default)
{
return $@"
#nullable enable
namespace {endPoint.Namespace}
{{
public partial class {endPoint.ClassName}
{{
public void {endPoint.MethodName}()
{{
}}
}}
}}".RemoveBlankLinesWhereOnlyWhitespaces();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;

namespace H.Generators.IntegrationTests;
namespace OpenApiGenerator.SnapshotTests;

public class CustomAdditionalText(string path, string text) : AdditionalText
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Runtime.CompilerServices;

namespace H.Generators.IntegrationTests;
namespace OpenApiGenerator.SnapshotTests;

public static class ModuleInitializer
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//HintName: G.Api.EndPoints.ListModels.g.cs

#nullable enable

namespace G
{
public partial class Api
{
public void ListModels()
{
}
}
}
12 changes: 8 additions & 4 deletions src/tests/OpenApiGenerator.SnapshotTests/Tests.Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using Microsoft.CodeAnalysis.Testing;
using OpenApiGenerator;

namespace H.Generators.IntegrationTests;
namespace OpenApiGenerator.SnapshotTests;

[TestClass]
public partial class Tests : VerifyBase
Expand All @@ -15,7 +15,8 @@ private async Task CheckSourceAsync<T>(
AdditionalText[] additionalTexts,
Dictionary<string, string>? globalOptions = null,
[CallerMemberName] string? callerName = null,
CancellationToken cancellationToken = default)
CancellationToken cancellationToken = default,
params IIncrementalGenerator[] additionalGenerators)
where T : IIncrementalGenerator, new()
{
globalOptions ??= new Dictionary<string, string>();
Expand All @@ -28,8 +29,11 @@ private async Task CheckSourceAsync<T>(
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
var generator = new T();
var driver = CSharpGeneratorDriver
.Create(generator)
var driver = CSharpGeneratorDriver.Create(
generators: new IIncrementalGenerator[] { generator }
.Concat(additionalGenerators)
.Select(GeneratorExtensions.AsSourceGenerator)
.ToArray())
.AddAdditionalTexts(ImmutableArray.Create(additionalTexts))
.WithUpdatedAnalyzerConfigOptions(new DictionaryAnalyzerConfigOptionsProvider(globalOptions))
.RunGeneratorsAndUpdateCompilation(compilation, out compilation, out _, cancellationToken);
Expand Down
21 changes: 14 additions & 7 deletions src/tests/OpenApiGenerator.SnapshotTests/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
using Microsoft.OpenApi;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using OpenApiGenerator;
using OpenApiGenerator.Generators;

namespace H.Generators.IntegrationTests;
namespace OpenApiGenerator.SnapshotTests;

public partial class Tests
{
Expand Down Expand Up @@ -53,7 +53,7 @@ public Task YamlWithLocalFileUseNSwag()
{
return CheckSourceAsync<NSwagGenerator>(new AdditionalText[]
{
new CustomAdditionalText("openapi.yaml", Resources.ipinfo_yaml.AsString()),
new CustomAdditionalText("openapi.yaml", H.Resources.ipinfo_yaml.AsString()),
}, new Dictionary<string, string>
{
["build_property.OpenApiGenerator_UseNSwag"] = "true",
Expand All @@ -65,19 +65,24 @@ public Task OpenAi()
{
return CheckSourceAsync<ModelGenerator>(new AdditionalText[]
{
new CustomAdditionalText(Resources.openai_yaml.FileName, Resources.openai_yaml.AsString()),
new CustomAdditionalText(
path: H.Resources.openai_yaml.FileName,
text: H.Resources.openai_yaml.AsString()),
}, new Dictionary<string, string>
{
["build_property.OpenApiGenerator_IncludeOperationIds"] = "ListModels",
["build_property.OpenApiGenerator_IncludeModels"] = "Error;ErrorResponse;ListModelsResponse;Model;DeleteModelResponse;CreateCompletionRequest",
});
}, additionalGenerators: new IIncrementalGenerator[]{ new ClientGenerator() });
}

[TestMethod]
public Task OpenAi_CreateCompletionResponse()
{
return CheckSourceAsync<ModelGenerator>(new AdditionalText[]
{
new CustomAdditionalText(Resources.openai_yaml.FileName, Resources.openai_yaml.AsString()),
new CustomAdditionalText(
path: H.Resources.openai_yaml.FileName,
text: H.Resources.openai_yaml.AsString()),
}, new Dictionary<string, string>
{
["build_property.OpenApiGenerator_IncludeModels"] = "CreateCompletionResponse",
Expand All @@ -89,7 +94,9 @@ public Task YamlWithLocalFile()
{
return CheckSourceAsync<ModelGenerator>(new AdditionalText[]
{
new CustomAdditionalText("openapi.yaml", Resources.ipinfo_yaml.AsString()),
new CustomAdditionalText(
path: "openapi.yaml",
text: H.Resources.ipinfo_yaml.AsString()),
});
}

Expand Down

0 comments on commit 3ab210e

Please sign in to comment.