Skip to content

Refactor LibKubernetesGenerator code structure #1546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions src/LibKubernetesGenerator/ApiGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ namespace LibKubernetesGenerator
{
internal class ApiGenerator
{
private readonly ScriptObjectFactory scriptObjectFactory;

public ApiGenerator(ScriptObjectFactory scriptObjectFactory)
{
this.scriptObjectFactory = scriptObjectFactory;
}

public void Generate(OpenApiDocument swagger, IncrementalGeneratorPostInitializationContext context)
{
var data = swagger.Operations
Expand Down Expand Up @@ -42,6 +49,8 @@ public void Generate(OpenApiDocument swagger, IncrementalGeneratorPostInitializa
})
.ToArray();

var sc = scriptObjectFactory.CreateScriptObject();

var groups = new List<string>();

foreach (var grouped in data.GroupBy(d => d.Operation.Tags.First()))
Expand All @@ -50,14 +59,20 @@ public void Generate(OpenApiDocument swagger, IncrementalGeneratorPostInitializa
groups.Add(name);

var apis = grouped.ToArray();
var gctx = new { name, apis };
context.RenderToContext($"IOperations.cs.template", gctx, $"I{name}Operations.g.cs");
context.RenderToContext("Operations.cs.template", gctx, $"{name}Operations.g.cs");
context.RenderToContext("OperationsExtensions.cs.template", gctx, $"{name}OperationsExtensions.g.cs");

sc.SetValue("name", name, true);
sc.SetValue("apis", apis, true);

context.RenderToContext($"IOperations.cs.template", sc, $"I{name}Operations.g.cs");
context.RenderToContext("Operations.cs.template", sc, $"{name}Operations.g.cs");
context.RenderToContext("OperationsExtensions.cs.template", sc, $"{name}OperationsExtensions.g.cs");
}

context.RenderToContext($"IBasicKubernetes.cs.template", groups, $"IBasicKubernetes.g.cs");
context.RenderToContext($"AbstractKubernetes.cs.template", groups, $"AbstractKubernetes.g.cs");
sc = scriptObjectFactory.CreateScriptObject();
sc.SetValue("groups", groups, true);

context.RenderToContext($"IBasicKubernetes.cs.template", sc, $"IBasicKubernetes.g.cs");
context.RenderToContext($"AbstractKubernetes.cs.template", sc, $"AbstractKubernetes.g.cs");
}
}
}
37 changes: 7 additions & 30 deletions src/LibKubernetesGenerator/ClassNameHelper.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using CaseExtensions;
using NJsonSchema;
using NSwag;
using Nustache.Core;
using Scriban.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;

namespace LibKubernetesGenerator
{
internal class ClassNameHelper : INustacheHelper
internal class ClassNameHelper : IScriptObjectHelper
{
private readonly Dictionary<string, string> classNameMap;
private readonly Dictionary<JsonSchema, string> schemaToNameMapCooked;
Expand All @@ -18,9 +19,10 @@ public ClassNameHelper(OpenApiDocument swagger)
schemaToNameMapCooked = GenerateSchemaToNameMapCooked(swagger);
}

public void RegisterHelper()

public void RegisterHelper(ScriptObject scriptObject)
{
Helpers.Register(nameof(GetClassName), GetClassName);
scriptObject.Import(nameof(GetClassName), new Func<JsonSchema, string>(GetClassNameForSchemaDefinition));
}

private static Dictionary<JsonSchema, string> GenerateSchemaToNameMapCooked(OpenApiDocument swagger)
Expand Down Expand Up @@ -50,27 +52,7 @@ private Dictionary<string, string> InitClassNameMap(OpenApiDocument doc)
return map;
}

public void GetClassName(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
RenderBlock fn, RenderBlock inverse)
{
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is OpenApiOperation)
{
context.Write(GetClassName(arguments[0] as OpenApiOperation));
}
else if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema)
{
context.Write(GetClassNameForSchemaDefinition(arguments[0] as JsonSchema));
}
}

public string GetClassName(OpenApiOperation operation)
{
var groupVersionKind =
(Dictionary<string, object>)operation.ExtensionData["x-kubernetes-group-version-kind"];
return GetClassName(groupVersionKind);
}

public string GetClassName(Dictionary<string, object> groupVersionKind)
private string GetClassName(Dictionary<string, object> groupVersionKind)
{
var group = (string)groupVersionKind["group"];
var kind = (string)groupVersionKind["kind"];
Expand Down Expand Up @@ -98,10 +80,5 @@ public string GetClassNameForSchemaDefinition(JsonSchema definition)

return schemaToNameMapCooked[definition];
}

private static Dictionary<JsonSchema, string> InitSchemaToNameCooked(OpenApiDocument swagger)
{
return swagger.Definitions.ToDictionary(x => x.Value, x => x.Key.Replace(".", "").ToPascalCase());
}
}
}
61 changes: 13 additions & 48 deletions src/LibKubernetesGenerator/GeneralNameHelper.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using CaseExtensions;
using NJsonSchema;
using NSwag;
using Nustache.Core;
using Scriban.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace LibKubernetesGenerator
{
internal class GeneralNameHelper : INustacheHelper
internal class GeneralNameHelper : IScriptObjectHelper
{
private readonly ClassNameHelper classNameHelper;

Expand All @@ -17,20 +18,12 @@ public GeneralNameHelper(ClassNameHelper classNameHelper)
this.classNameHelper = classNameHelper;
}

public void RegisterHelper()
public void RegisterHelper(ScriptObject scriptObject)
{
Helpers.Register(nameof(GetInterfaceName), GetInterfaceName);
Helpers.Register(nameof(GetMethodName), GetMethodName);
Helpers.Register(nameof(GetDotNetName), GetDotNetName);
}

public void GetInterfaceName(RenderContext context, IList<object> arguments,
IDictionary<string, object> options, RenderBlock fn, RenderBlock inverse)
{
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema)
{
context.Write(GetInterfaceName(arguments[0] as JsonSchema));
}
scriptObject.Import(nameof(GetInterfaceName), new Func<JsonSchema, string>(GetInterfaceName));
scriptObject.Import(nameof(GetMethodName), new Func<OpenApiOperation, string, string>(GetMethodName));
scriptObject.Import(nameof(GetDotNetName), new Func<string, string, string>(GetDotNetName));
scriptObject.Import(nameof(GetDotNetNameOpenApiParameter), new Func<OpenApiParameter, string, string>(GetDotNetNameOpenApiParameter));
}

private string GetInterfaceName(JsonSchema definition)
Expand Down Expand Up @@ -68,44 +61,16 @@ private string GetInterfaceName(JsonSchema definition)
return string.Join(", ", interfaces);
}

public void GetMethodName(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
RenderBlock fn, RenderBlock inverse)
public string GetDotNetNameOpenApiParameter(OpenApiParameter parameter, string init)
{
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is OpenApiOperation)
{
string suffix = null;
if (arguments.Count > 1)
{
suffix = arguments[1] as string;
}
var name = GetDotNetName(parameter.Name);

context.Write(GetMethodName(arguments[0] as OpenApiOperation, suffix));
}
}

public void GetDotNetName(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
RenderBlock fn, RenderBlock inverse)
{
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is OpenApiParameter)
if (init == "true" && !parameter.IsRequired)
{
var parameter = arguments[0] as OpenApiParameter;
context.Write(GetDotNetName(parameter.Name));

if (arguments.Count > 1 && (arguments[1] as string) == "true" && !parameter.IsRequired)
{
context.Write(" = null");
}
name += " = null";
}
else if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is string)
{
var style = "parameter";
if (arguments.Count > 1)
{
style = arguments[1] as string;
}

context.Write(GetDotNetName((string)arguments[0], style));
}
return name;
}

public string GetDotNetName(string jsonName, string style = "parameter")
Expand Down
16 changes: 12 additions & 4 deletions src/LibKubernetesGenerator/GeneratorExecutionContextExt.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Nustache.Core;
using Scriban;
using Scriban.Runtime;
using System.Text;

namespace LibKubernetesGenerator
{
internal static class GeneratorExecutionContextExt
{
public static void RenderToContext(this IncrementalGeneratorPostInitializationContext context, string templatefile, object data, string generatedfile)
public static void RenderToContext(this IncrementalGeneratorPostInitializationContext context, string templatefile, ScriptObject sc, string generatedfile)
{
var template = EmbedResource.GetResource(templatefile);
var generated = Render.StringToString(template, data);
var tc = new TemplateContext();
tc.PushGlobal(sc);
context.RenderToContext(templatefile, tc, generatedfile);
}

public static void RenderToContext(this IncrementalGeneratorPostInitializationContext context, string templatefile, TemplateContext tc, string generatedfile)
{
var template = Template.Parse(EmbedResource.GetResource(templatefile));
var generated = template.Render(tc);
context.AddSource(generatedfile, SourceText.From(generated, Encoding.UTF8));
}
}
Expand Down
7 changes: 0 additions & 7 deletions src/LibKubernetesGenerator/INustacheHelper.cs

This file was deleted.

8 changes: 8 additions & 0 deletions src/LibKubernetesGenerator/IScriptObjectHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Scriban.Runtime;

namespace LibKubernetesGenerator;

internal interface IScriptObjectHelper
{
void RegisterHelper(ScriptObject scriptObject);
}
45 changes: 12 additions & 33 deletions src/LibKubernetesGenerator/KubernetesClientSourceGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,22 @@
using Autofac;
using Microsoft.CodeAnalysis;
using NSwag;
using Nustache.Core;
#if GENERATE_AUTOMAPPER
using System.Collections.Generic;
using System;
using System.IO;
using System.Linq;
#endif
using System.Collections.Generic;
using System.Reflection;

namespace LibKubernetesGenerator
{
[Generator]
public class KubernetesClientSourceGenerator : IIncrementalGenerator
{
private static readonly object Execlock = new object();

private static (OpenApiDocument, IContainer) BuildContainer()
{
var swagger = OpenApiDocument.FromJsonAsync(EmbedResource.GetResource("swagger.json")).GetAwaiter().GetResult();
var container = BuildContainer(swagger);
// TODO move to Handlebars.Net
// here is to clean up the custom helpers in static Nustache.Core.Helpers
{
var ch = typeof(Helpers).GetField("CustomHelpers", BindingFlags.Static | BindingFlags.NonPublic);
((Dictionary<string, Helper>)ch.GetValue(null)).Clear();
}

foreach (var helper in container.Resolve<IEnumerable<INustacheHelper>>())
{
helper.RegisterHelper();
}

return (swagger, container);
}

Expand Down Expand Up @@ -77,6 +61,9 @@ private static IContainer BuildContainer(OpenApiDocument swagger)
.AsImplementedInterfaces()
;

builder.RegisterType<ScriptObjectFactory>()
;

builder.RegisterType<ModelExtGenerator>();
builder.RegisterType<ModelGenerator>();
builder.RegisterType<ApiGenerator>();
Expand All @@ -92,31 +79,23 @@ public void Initialize(IncrementalGeneratorInitializationContext generatorContex
#if GENERATE_BASIC
generatorContext.RegisterPostInitializationOutput(ctx =>
{
lock (Execlock)
{
var (swagger, container) = BuildContainer();

container.Resolve<VersionGenerator>().Generate(swagger, ctx);
var (swagger, container) = BuildContainer();

container.Resolve<ModelGenerator>().Generate(swagger, ctx);
container.Resolve<ModelExtGenerator>().Generate(swagger, ctx);
container.Resolve<VersionConverterStubGenerator>().Generate(swagger, ctx);
container.Resolve<VersionGenerator>().Generate(swagger, ctx);

container.Resolve<ApiGenerator>().Generate(swagger, ctx);
}
container.Resolve<ModelGenerator>().Generate(swagger, ctx);
container.Resolve<ModelExtGenerator>().Generate(swagger, ctx);
container.Resolve<VersionConverterStubGenerator>().Generate(swagger, ctx);
container.Resolve<ApiGenerator>().Generate(swagger, ctx);
});
#endif

#if GENERATE_AUTOMAPPER
var automappersrc = generatorContext.CompilationProvider.Select((c, _) => c.SyntaxTrees.First(s => PathSuffixMath(s.FilePath, "AutoMapper/VersionConverter.cs")));
generatorContext.RegisterSourceOutput(automappersrc, (ctx, srctree) =>
{
lock (Execlock)
{
var (swagger, container) = BuildContainer();

container.Resolve<VersionConverterAutoMapperGenerator>().Generate(swagger, ctx, srctree);
}
var (swagger, container) = BuildContainer();
container.Resolve<VersionConverterAutoMapperGenerator>().Generate(swagger, ctx, srctree);
});
#endif
}
Expand Down
Loading