End merge Add with template and Update

This commit is contained in:
CodeLiturgy 2022-08-27 21:01:52 +01:00
commit 4d9cc4b029
4 changed files with 107 additions and 16 deletions

View File

@ -45,6 +45,7 @@
<ItemGroup> <ItemGroup>
<Folder Include="bin\Release\netstandard2.0" /> <Folder Include="bin\Release\netstandard2.0" />
<Folder Include="Sources\EntityFramework" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -10,11 +10,20 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace MapTo namespace MapTo
{ {
/*/// <summary>
/// Base source code generator typed class.
/// </summary>
public class SourceCodeGenerator : ISourceGenerator
{
public virtual void Initialize(GeneratorInitializationContext context) {}
public virtual void Execute(GeneratorExecutionContext context) {}
}*/
/// <summary> /// <summary>
/// Ef methods source generator /// Ef methods source generator
/// </summary> /// </summary>
[Generator] [Generator]
public class EfAddMethodsGenerator: ISourceGenerator public class EfMethodsGenerator: ISourceGenerator
{ {
/// <inheritdoc /> /// <inheritdoc />
public void Initialize(GeneratorInitializationContext context) public void Initialize(GeneratorInitializationContext context)
@ -44,11 +53,11 @@ namespace MapTo
} }
} }
private static void AddGeneratedExtensions(GeneratorExecutionContext context, Compilation compilation, IEnumerable<MemberDeclarationSyntax> candidateTypes, SourceGenerationOptions options) private static void AddGeneratedExtensions(GeneratorExecutionContext context, Compilation compilation, IEnumerable<CandidateMember> candidateMembers, SourceGenerationOptions options)
{ {
//SpinWait.SpinUntil(() => Debugger.IsAttached); //SpinWait.SpinUntil(() => Debugger.IsAttached);
foreach (var memberDeclarationSyntax in candidateTypes) foreach (var candidateMember in candidateMembers)
{ {
string addSourceTemplate = string.Empty; string addSourceTemplate = string.Empty;
@ -60,7 +69,7 @@ namespace MapTo
.ToString() ?? string.Empty; .ToString() ?? string.Empty;
} }
var mappingContext = EfAddGeneratorContext.Create(compilation, options, memberDeclarationSyntax, addSourceTemplate); var mappingContext = EfAddGeneratorContext.Create(compilation, options, candidateMember.MemberDeclarationSyntax, addSourceTemplate);
mappingContext.Diagnostics.ForEach(context.ReportDiagnostic); mappingContext.Diagnostics.ForEach(context.ReportDiagnostic);
@ -69,7 +78,7 @@ namespace MapTo
continue; continue;
} }
var (source, hintName) = memberDeclarationSyntax switch var (source, hintName) = candidateMember.MemberDeclarationSyntax switch
{ {
PropertyDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model, addSourceTemplate), PropertyDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model, addSourceTemplate),
_ => throw new ArgumentOutOfRangeException() _ => throw new ArgumentOutOfRangeException()

View File

@ -6,9 +6,22 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace MapTo namespace MapTo
{ {
internal enum EfMethodsAttributeType
{
Add,
Update,
Invalid
}
internal record CandidateMember(
MemberDeclarationSyntax MemberDeclarationSyntax,
EfMethodsAttributeType AttributeType
);
internal class EfMethodsSyntaxReceiver : ISyntaxReceiver internal class EfMethodsSyntaxReceiver : ISyntaxReceiver
{ {
public List<MemberDeclarationSyntax> CandidateMembers { get; } = new(); public List<CandidateMember> CandidateMembers { get; } = new();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode) public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{ {
@ -17,22 +30,44 @@ namespace MapTo
return; return;
} }
var syntaxAttributeState = EfMethodsAttributeType.Invalid;
var attributeSyntax = attributes var attributeSyntax = attributes
.SelectMany(a => a.Attributes) .SelectMany(a => a.Attributes)
.FirstOrDefault(a => a.Name is .FirstOrDefault(a =>
IdentifierNameSyntax { Identifier: { ValueText: EfAddMethodsAttributeSource.AttributeName } } // For: [EfAddMethods] {
or syntaxAttributeState = IsValidAttributeType(a);
QualifiedNameSyntax // For: [MapTo.EfAddMethods] return syntaxAttributeState != EfMethodsAttributeType.Invalid;
{ });
Left: IdentifierNameSyntax { Identifier: { ValueText: Constants.RootNamespace } },
Right: IdentifierNameSyntax { Identifier: { ValueText: EfAddMethodsAttributeSource.AttributeName } }
}
);
if (attributeSyntax is not null) if (attributeSyntax is not null)
{ {
CandidateMembers.Add(typeDeclarationSyntax); CandidateMembers.Add(new CandidateMember(typeDeclarationSyntax, syntaxAttributeState));
} }
} }
private static EfMethodsAttributeType IsValidAttributeType(AttributeSyntax a)
{
return a.Name switch
{
IdentifierNameSyntax { Identifier: { ValueText: EfAddMethodsAttributeSource.AttributeName } } // For: [EfAddMethods]
or QualifiedNameSyntax // For: [MapTo.EfAddMethods]
{
Left: IdentifierNameSyntax { Identifier: { ValueText: Constants.RootNamespace } },
Right: IdentifierNameSyntax { Identifier: { ValueText: EfAddMethodsAttributeSource.AttributeName } }
} => EfMethodsAttributeType.Add,
IdentifierNameSyntax { Identifier: { ValueText: EfUpdateMethodsAttributeSource.AttributeName } } // For: [EfAddMethods]
or QualifiedNameSyntax // For: [MapTo.EfUpdateMethods]
{
Left: IdentifierNameSyntax { Identifier: { ValueText: Constants.RootNamespace } },
Right: IdentifierNameSyntax { Identifier: { ValueText: EfUpdateMethodsAttributeSource.AttributeName } }
} => EfMethodsAttributeType.Update,
_ => EfMethodsAttributeType.Invalid
};
}
} }
} }

View File

@ -0,0 +1,46 @@
using static MapTo.Sources.Constants;
namespace MapTo.Sources
{
public class EfUpdateMethodsAttributeSource
{
internal const string AttributeName = "EfUpdateMethods";
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.Property | AttributeTargets.Field)]")
.WriteLine($"public sealed class {AttributeName}Attribute : Attribute")
.WriteOpeningBracket();
builder
.WriteLine($"public {AttributeName}Attribute(Type updateType = null, Type returnType = null, string keyPropertyMemberName, Type keyPropertyMemberType)")
.WriteOpeningBracket()
.WriteClosingBracket()
.WriteLine();
builder
.WriteClosingBracket() // class
.WriteClosingBracket(); // namespace
return new(builder.ToString(), $"{AttributeName}Attribute.g.cs");
}
}
}