Add generator attribute source

This commit is contained in:
CodeLiturgy 2022-09-04 19:07:59 +01:00
parent 9257d389ba
commit 3917d231a2
3 changed files with 119 additions and 0 deletions

View File

@ -0,0 +1,41 @@
using static MapTo.Sources.Constants;
namespace MapTo.Sources
{
public class EfGeneratorAttributeSource
{
internal const string AttributeName = "EfGenerator";
internal const string AttributeClassName = AttributeName + "Attribute";
internal const string FullyQualifiedName = RootNamespace + "." + AttributeClassName;
internal static SourceCode Generate(SourceGenerationOptions options)
{
using var builder = new SourceBuilder()
.WriteLine(GeneratedFilesHeader)
.WriteLine("using System;")
.WriteLine()
.WriteLine($"namespace {RootNamespace}")
.WriteOpeningBracket();
if (options.GenerateXmlDocument)
{
builder
.WriteLine("/// <summary>")
.WriteLine("/// Generate Add methods for interacting with the entity")
.WriteLine("/// </summary>");
}
builder
.WriteLine("[AttributeUsage(AttributeTargets.Class)]")
.WriteLine($"public sealed class {AttributeName}Attribute : Attribute")
.WriteOpeningBracket()
.WriteLine();
builder
.WriteClosingBracket() // class
.WriteClosingBracket(); // namespace
return new(builder.ToString(), $"{AttributeName}Attribute.g.cs");
}
}
}

View File

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MapTo.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace MapTo.Sources.EfMethods
{
public static class EfGeneratorExtensionMethods
{
public static void InitializeEfGenerator(this ISourceGenerator sourceGenerator, GeneratorInitializationContext context)
{
context.RegisterForSyntaxNotifications(() => new EfMethodsSyntaxReceiver());
}
/// <inheritdoc />
public static void ExecuteEfGenerator(this ISourceGenerator sourceGenerator, GeneratorExecutionContext context)
{
try
{
var options = SourceGenerationOptions.From(context);
var compilation = context.Compilation
.AddSource(ref context, EfAddMethodsAttributeSource.Generate(options))
.AddSource(ref context, EfUpdateMethodsAttributeSource.Generate(options));
if (context.SyntaxReceiver is EfMethodsSyntaxReceiver receiver && receiver.CandidateMembers.Any())
{
AddGeneratedExtensions(context, compilation, receiver.CandidateMembers, options);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
private static void AddGeneratedExtensions( GeneratorExecutionContext context, Compilation compilation, IEnumerable<CandidateMember> candidateMembers, SourceGenerationOptions options)
{
//SpinWait.SpinUntil(() => Debugger.IsAttached);
foreach (var candidateMember in candidateMembers)
{
string addSourceTemplate = context.AdditionalFiles
.FirstOrDefault(x => x.Path.Contains("AddToEntityTemplate"))?
.GetText()?
.ToString() ?? string.Empty;
string updateSourceTemplate = context.AdditionalFiles
.FirstOrDefault(x => x.Path.Contains("UpdateEntityTemplate"))?
.GetText()?
.ToString() ?? string.Empty;
var mappingContext = EfGeneratorContext.Create(compilation, options, candidateMember.MemberDeclarationSyntax);
mappingContext.Diagnostics.ForEach(context.ReportDiagnostic);
if (mappingContext.Model is null)
{
continue;
}
var (source, hintName) = candidateMember.MemberDeclarationSyntax switch
{
PropertyDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model, addSourceTemplate, updateSourceTemplate),
_ => throw new ArgumentOutOfRangeException()
};
context.AddSource(hintName, source);
}
}
}
}

View File

@ -30,6 +30,7 @@ namespace MapTo
var options = SourceGenerationOptions.From(context);
var compilation = context.Compilation
.AddSource(ref context, EfGeneratorAttributeSource.Generate(options))
.AddSource(ref context, EfAddMethodsAttributeSource.Generate(options))
.AddSource(ref context, EfUpdateMethodsAttributeSource.Generate(options));