Files
csharp/gen/LibKubernetesGenerator/VersionConverterGenerator.cs

117 lines
3.9 KiB
C#
Raw Normal View History

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace LibKubernetesGenerator
{
[Generator]
public class VersionConverterGenerator : ISourceGenerator
{
private IEnumerable<string> PathSplit(string path)
{
var p = path;
while (!string.IsNullOrEmpty(p))
{
yield return Path.GetFileName(p);
p = Path.GetDirectoryName(p);
}
}
private bool PathSuffixMath(string path, string suffix)
{
var s = PathSplit(suffix).ToList();
return PathSplit(path).Take(s.Count).SequenceEqual(s);
}
public void Execute(GeneratorExecutionContext context)
{
// TODO should parse syntax node instead of text
var allGeneratedModelClassNames = new List<string>();
var manualMaps = new List<(string, string)>();
foreach (var s in context.Compilation.SyntaxTrees)
{
var p = s.FilePath;
if (PathSuffixMath(p, "Versioning/VersionConverter.cs"))
{
manualMaps = Regex.Matches(s.GetText().ToString(), @"\.CreateMap<(?<T1>.+?),\s?(?<T2>.+?)>")
.OfType<Match>()
.Select(x => (x.Groups["T1"].Value, x.Groups["T2"].Value))
.ToList();
}
else if (PathSuffixMath(Path.GetDirectoryName(p), "generated/Models"))
{
allGeneratedModelClassNames.Add(Path.GetFileNameWithoutExtension(p));
}
}
var versionRegex = @"(^V|v)[0-9]+((alpha|beta)[0-9]+)?";
var typePairs = allGeneratedModelClassNames
.OrderBy(x => x)
.Select(x => new
{
Version = Regex.Match(x, versionRegex).Value?.ToLower(),
Kinda = Regex.Replace(x, versionRegex, string.Empty),
Type = x,
})
.Where(x => !string.IsNullOrEmpty(x.Version))
.GroupBy(x => x.Kinda)
.Where(x => x.Count() > 1)
.SelectMany(x =>
x.SelectMany((value, index) => x.Skip(index + 1), (first, second) => new { first, second }))
.OrderBy(x => x.first.Kinda)
.ThenBy(x => x.first.Version)
.Select(x => (x.first.Type, x.second.Type))
.ToList();
var versionConverterPairs = typePairs.Except(manualMaps).ToList();
var sbmodel = new StringBuilder(@"// <auto-generated />
namespace k8s.Models;
using k8s.Versioning;
");
var sbversion = new StringBuilder(@"// <auto-generated />
namespace k8s.Versioning;
using AutoMapper;
using k8s.Models;
public static partial class VersionConverter
{
private static void AutoConfigurations(IMapperConfigurationExpression cfg)
{
");
foreach (var (t0, t1) in versionConverterPairs)
{
sbmodel.AppendLine($@"
public partial class {t0}
{{
public static explicit operator {t0}({t1} s) => VersionConverter.Mapper.Map<{t0}>(s);
}}
public partial class {t1}
{{
public static explicit operator {t1}({t0} s) => VersionConverter.Mapper.Map<{t1}>(s);
}}");
sbversion.AppendLine($@"cfg.CreateMap<{t0}, {t1}>().ReverseMap();");
}
sbversion.AppendLine("}}");
context.AddSource($"generated_ModelOperators.cs", SourceText.From(sbmodel.ToString(), Encoding.UTF8));
context.AddSource($"generated_VersionConverter.cs", SourceText.From(sbversion.ToString(), Encoding.UTF8));
}
public void Initialize(GeneratorInitializationContext context)
{
}
}
}