117 lines
3.9 KiB
C#
117 lines
3.9 KiB
C#
|
|
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)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|