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>
<Folder Include="bin\Release\netstandard2.0" />
<Folder Include="Sources\EntityFramework" />
</ItemGroup>
</Project>

View File

@ -10,11 +10,20 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
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>
/// Ef methods source generator
/// </summary>
[Generator]
public class EfAddMethodsGenerator: ISourceGenerator
public class EfMethodsGenerator: ISourceGenerator
{
/// <inheritdoc />
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);
foreach (var memberDeclarationSyntax in candidateTypes)
foreach (var candidateMember in candidateMembers)
{
string addSourceTemplate = string.Empty;
@ -60,7 +69,7 @@ namespace MapTo
.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);
@ -69,7 +78,7 @@ namespace MapTo
continue;
}
var (source, hintName) = memberDeclarationSyntax switch
var (source, hintName) = candidateMember.MemberDeclarationSyntax switch
{
PropertyDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model, addSourceTemplate),
_ => throw new ArgumentOutOfRangeException()

View File

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