Add template working

This commit is contained in:
Wvader 2022-08-27 04:19:43 +01:00
parent 340a89bbd2
commit e232fa6e76
5 changed files with 112 additions and 57 deletions

View File

@ -12,16 +12,21 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace MapTo namespace MapTo
{ {
internal class EfGeneratorContext internal class EfAddGeneratorContext
{ {
private readonly List<SymbolDisplayPart> _ignoredNamespaces; private readonly List<SymbolDisplayPart> _ignoredNamespaces;
public EfGeneratorContext(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, MemberDeclarationSyntax memberSyntax) protected EfAddGeneratorContext(
Compilation compilation,
SourceGenerationOptions sourceGenerationOptions,
MemberDeclarationSyntax memberSyntax,
string addSourceTemplate)
{ {
Compilation = compilation; Compilation = compilation;
_ignoredNamespaces = new(); _ignoredNamespaces = new();
Diagnostics = ImmutableArray<Diagnostic>.Empty; Diagnostics = ImmutableArray<Diagnostic>.Empty;
Usings = ImmutableArray.Create("System", Constants.RootNamespace); Usings = ImmutableArray.Create("System", Constants.RootNamespace);
SourceTemplate = addSourceTemplate;
SourceGenerationOptions = sourceGenerationOptions; SourceGenerationOptions = sourceGenerationOptions;
MemberSyntax = memberSyntax; MemberSyntax = memberSyntax;
@ -30,6 +35,8 @@ namespace MapTo
AddUsingIfRequired(sourceGenerationOptions.SupportNullableStaticAnalysis, "System.Diagnostics.CodeAnalysis"); AddUsingIfRequired(sourceGenerationOptions.SupportNullableStaticAnalysis, "System.Diagnostics.CodeAnalysis");
} }
public string SourceTemplate { get; }
public ImmutableArray<Diagnostic> Diagnostics { get; private set; } public ImmutableArray<Diagnostic> Diagnostics { get; private set; }
public EfMethodsModel? Model { get; private set; } public EfMethodsModel? Model { get; private set; }
@ -38,19 +45,21 @@ namespace MapTo
protected INamedTypeSymbol MappingContextTypeSymbol { get; } protected INamedTypeSymbol MappingContextTypeSymbol { get; }
protected INamedTypeSymbol EfAddMethodsAttributeTypeSymbol { get; }
protected SourceGenerationOptions SourceGenerationOptions { get; } protected SourceGenerationOptions SourceGenerationOptions { get; }
protected MemberDeclarationSyntax MemberSyntax { get; } protected MemberDeclarationSyntax MemberSyntax { get; }
protected ImmutableArray<string> Usings { get; private set; } protected ImmutableArray<string> Usings { get; private set; }
public static EfGeneratorContext Create(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, MemberDeclarationSyntax typeSyntax) public static EfAddGeneratorContext Create(
Compilation compilation,
SourceGenerationOptions sourceGenerationOptions,
MemberDeclarationSyntax typeSyntax,
string addSourceTemplate)
{ {
EfGeneratorContext context = typeSyntax switch EfAddGeneratorContext context = typeSyntax switch
{ {
PropertyDeclarationSyntax => new EfGeneratorContext(compilation, sourceGenerationOptions, typeSyntax), PropertyDeclarationSyntax => new EfAddGeneratorContext(compilation, sourceGenerationOptions, typeSyntax, addSourceTemplate),
_ => throw new ArgumentOutOfRangeException() _ => throw new ArgumentOutOfRangeException()
}; };
@ -178,9 +187,9 @@ namespace MapTo
// context name // context name
var dbContextName = classDeclarationSyntax.Identifier.ValueText; var dbContextName = classDeclarationSyntax.Identifier.ValueText;
var namespaceDeclaration = classDeclarationSyntax.Parent as NamespaceDeclarationSyntax; var namespaceDeclaration = classDeclarationSyntax.Parent as NamespaceDeclarationSyntax;
var namespaceFullName = namespaceDeclaration.Name.ToString(); var contextNamespace = namespaceDeclaration.Name.ToString();
var contextTypeFullName = $"{namespaceFullName}.{dbContextName}"; var contextTypeFullName = $"{contextNamespace}.{dbContextName}";
var propertyName = entityTypeName; var propertyName = entityTypeName;
@ -208,7 +217,7 @@ namespace MapTo
return new EfMethodsModel( return new EfMethodsModel(
SourceGenerationOptions, SourceGenerationOptions,
namespaceFullName, contextNamespace,
propertyName, propertyName,
dbContextName, dbContextName,
contextTypeFullName, contextTypeFullName,

View File

@ -10,20 +10,11 @@ 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 EfMethodsGenerator: ISourceGenerator public class EfAddMethodsGenerator: ISourceGenerator
{ {
/// <inheritdoc /> /// <inheritdoc />
public void Initialize(GeneratorInitializationContext context) public void Initialize(GeneratorInitializationContext context)
@ -59,7 +50,18 @@ namespace MapTo
foreach (var memberDeclarationSyntax in candidateTypes) foreach (var memberDeclarationSyntax in candidateTypes)
{ {
var mappingContext = EfGeneratorContext.Create(compilation, options, memberDeclarationSyntax); string addSourceTemplate = string.Empty;
if (context.AdditionalFiles.Length > 0)
{
addSourceTemplate = context.AdditionalFiles
.FirstOrDefault()?
.GetText()?
.ToString() ?? string.Empty;
}
var mappingContext = EfAddGeneratorContext.Create(compilation, options, memberDeclarationSyntax, addSourceTemplate);
mappingContext.Diagnostics.ForEach(context.ReportDiagnostic); mappingContext.Diagnostics.ForEach(context.ReportDiagnostic);
if (mappingContext.Model is null) if (mappingContext.Model is null)
@ -67,10 +69,9 @@ namespace MapTo
continue; continue;
} }
var (source, hintName) = memberDeclarationSyntax switch var (source, hintName) = memberDeclarationSyntax switch
{ {
PropertyDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model), PropertyDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model, addSourceTemplate),
_ => throw new ArgumentOutOfRangeException() _ => throw new ArgumentOutOfRangeException()
}; };

View File

@ -74,7 +74,7 @@ namespace MapTo
string Namespace, string Namespace,
string PropertyName, string PropertyName,
string ContextTypeName, string ContextTypeName,
string ContestFullType, string ContextFullType,
string EntityTypeFullName, string EntityTypeFullName,
string EntityTypeIdentifierName, string EntityTypeIdentifierName,

View File

@ -1,4 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using MapTo.Extensions; using MapTo.Extensions;
using static MapTo.Sources.Constants; using static MapTo.Sources.Constants;
@ -6,13 +9,51 @@ namespace MapTo.Sources
{ {
internal static class EfMethodsSource internal static class EfMethodsSource
{ {
internal static SourceCode Generate(EfMethodsModel model)
static IEnumerable<string> GetFilesFromDir(string dir) =>
Directory.EnumerateFiles(dir);
internal static SourceCode Generate(EfMethodsModel model, string addSourceTemplate)
{ {
const bool writeDebugInfo = false; using var builder = new SourceBuilder();
List<string> constructorHeaders = new List<string>(); var entityTypeName = model.EntityTypeIdentifierName;
var entityTypeFullName = model.EntityTypeFullName;
var readTypeName = model.ReadTypeIdentifierName;
var readTypeFullName = model.ReadTypeFullName;
var createTypeName = model.CreateTypeIdentifierName;
var createTypeFullName = model.CreateTypeFullName;
var contextFullName = model.ContextFullType;
var propertyName = model.PropertyName;
var newEntityVarName = $"new{model.EntityTypeIdentifierName}";
var toCreateVarName = $"{model.EntityTypeIdentifierName.ToCamelCase()}ToCreate";
using var builder = new SourceBuilder() if (!addSourceTemplate.IsEmpty())
{
builder
.WriteLine(GeneratedFilesHeader)
.WriteUsings(model.Usings);
var templateToSourceBuilder = new StringBuilder(addSourceTemplate);
templateToSourceBuilder
.Replace("{Namespace} ", model.Namespace)
.Replace("{entityTypeName}", entityTypeName)
.Replace("{readTypeFullName}", readTypeFullName)
.Replace("{createTypeFullName}", createTypeFullName)
.Replace("{contextFullName}", contextFullName)
.Replace("{toCreateVarName}", toCreateVarName)
.Replace("{newEntityVarName}", newEntityVarName)
.Replace("{entityTypeFullName}", entityTypeFullName)
.Replace("{propertyName}", propertyName);
builder
.Write(templateToSourceBuilder.ToString());
}
if (addSourceTemplate.IsEmpty())
{
builder
.WriteLine(GeneratedFilesHeader) .WriteLine(GeneratedFilesHeader)
.WriteUsings(model.Usings) .WriteUsings(model.Usings)
.WriteLine("using Microsoft.EntityFrameworkCore;") .WriteLine("using Microsoft.EntityFrameworkCore;")
@ -24,14 +65,14 @@ namespace MapTo.Sources
.WriteLine($"public static partial class {model.EntityTypeIdentifierName}Extensions") .WriteLine($"public static partial class {model.EntityTypeIdentifierName}Extensions")
.WriteOpeningBracket() .WriteOpeningBracket()
.WriteLine() .WriteLine()
.WriteLine($"public static (bool, {model.ReadTypeFullName}) Add{model.EntityTypeIdentifierName}(") .WriteLine($"public static (bool, {model.ReadTypeFullName}) Add{entityTypeName}(")
.WriteLine($"this {model.ContestFullType} dbContext,") .WriteLine($"this {contextFullName} dbContext,")
.WriteLine($"{model.CreateTypeFullName} {model.EntityTypeIdentifierName.ToLower()}toCreate)") .WriteLine($"{createTypeFullName} {toCreateVarName})")
.WriteOpeningBracket() .WriteOpeningBracket()
.WriteLine($"var new{model.EntityTypeIdentifierName} = new {model.EntityTypeFullName}({model.EntityTypeIdentifierName.ToLower()}toCreate);") .WriteLine($"var {newEntityVarName} = new {model.EntityTypeFullName}({toCreateVarName});")
.WriteLine($"dbContext.{model.PropertyName}.Add(new{model.EntityTypeIdentifierName});") .WriteLine($"dbContext.{propertyName}.Add({newEntityVarName});")
.WriteLine($"var success = dbContext.SaveChanges() >= 0;") .WriteLine($"var success = dbContext.SaveChanges() >= 0;")
.WriteLine($"return (success, new {model.ReadTypeFullName}(new{model.EntityTypeIdentifierName}));") .WriteLine($"return (success, new {readTypeFullName}({newEntityVarName}));")
.WriteClosingBracket(); .WriteClosingBracket();
builder builder
.WriteLine() .WriteLine()
@ -41,7 +82,11 @@ namespace MapTo.Sources
// End namespace declaration // End namespace declaration
.WriteClosingBracket(); .WriteClosingBracket();
return new(builder.ToString(), $"{model.Namespace}.{model.EntityTypeIdentifierName}Extensions.g.cs"); }
var generatedCode = builder.ToString();
var hintName = $"{model.EntityTypeIdentifierName}Extensions.g.cs";
return new(generatedCode, hintName);
} }
} }
} }

View File

@ -50,7 +50,7 @@ namespace MapTo.Tests.Infrastructure
} }
var driver = CSharpGeneratorDriver.Create( var driver = CSharpGeneratorDriver.Create(
new List<ISourceGenerator>() { new MapToGenerator(), new EfMethodsGenerator() }, new List<ISourceGenerator>() { new MapToGenerator(), new EfAddMethodsGenerator() },
optionsProvider: new TestAnalyzerConfigOptionsProvider(analyzerConfigOptions), optionsProvider: new TestAnalyzerConfigOptionsProvider(analyzerConfigOptions),
parseOptions: new CSharpParseOptions(languageVersion) parseOptions: new CSharpParseOptions(languageVersion)
); );