Add template working
This commit is contained in:
parent
340a89bbd2
commit
e232fa6e76
|
@ -12,16 +12,21 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|||
|
||||
namespace MapTo
|
||||
{
|
||||
internal class EfGeneratorContext
|
||||
internal class EfAddGeneratorContext
|
||||
{
|
||||
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;
|
||||
_ignoredNamespaces = new();
|
||||
Diagnostics = ImmutableArray<Diagnostic>.Empty;
|
||||
Usings = ImmutableArray.Create("System", Constants.RootNamespace);
|
||||
SourceTemplate = addSourceTemplate;
|
||||
SourceGenerationOptions = sourceGenerationOptions;
|
||||
MemberSyntax = memberSyntax;
|
||||
|
||||
|
@ -30,6 +35,8 @@ namespace MapTo
|
|||
AddUsingIfRequired(sourceGenerationOptions.SupportNullableStaticAnalysis, "System.Diagnostics.CodeAnalysis");
|
||||
}
|
||||
|
||||
public string SourceTemplate { get; }
|
||||
|
||||
public ImmutableArray<Diagnostic> Diagnostics { get; private set; }
|
||||
|
||||
public EfMethodsModel? Model { get; private set; }
|
||||
|
@ -38,19 +45,21 @@ namespace MapTo
|
|||
|
||||
protected INamedTypeSymbol MappingContextTypeSymbol { get; }
|
||||
|
||||
protected INamedTypeSymbol EfAddMethodsAttributeTypeSymbol { get; }
|
||||
|
||||
protected SourceGenerationOptions SourceGenerationOptions { get; }
|
||||
|
||||
protected MemberDeclarationSyntax MemberSyntax { get; }
|
||||
|
||||
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()
|
||||
};
|
||||
|
||||
|
@ -178,9 +187,9 @@ namespace MapTo
|
|||
// context name
|
||||
var dbContextName = classDeclarationSyntax.Identifier.ValueText;
|
||||
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;
|
||||
|
||||
|
@ -208,7 +217,7 @@ namespace MapTo
|
|||
|
||||
return new EfMethodsModel(
|
||||
SourceGenerationOptions,
|
||||
namespaceFullName,
|
||||
contextNamespace,
|
||||
propertyName,
|
||||
dbContextName,
|
||||
contextTypeFullName,
|
|
@ -10,20 +10,11 @@ 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 EfMethodsGenerator: ISourceGenerator
|
||||
public class EfAddMethodsGenerator: ISourceGenerator
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
|
@ -59,18 +50,28 @@ namespace MapTo
|
|||
|
||||
foreach (var memberDeclarationSyntax in candidateTypes)
|
||||
{
|
||||
var mappingContext = EfGeneratorContext.Create(compilation, options, memberDeclarationSyntax);
|
||||
mappingContext.Diagnostics.ForEach(context.ReportDiagnostic);
|
||||
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);
|
||||
|
||||
if (mappingContext.Model is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
var (source, hintName) = memberDeclarationSyntax switch
|
||||
{
|
||||
PropertyDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model),
|
||||
PropertyDeclarationSyntax => EfMethodsSource.Generate(mappingContext.Model, addSourceTemplate),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
|
@ -74,7 +74,7 @@ namespace MapTo
|
|||
string Namespace,
|
||||
string PropertyName,
|
||||
string ContextTypeName,
|
||||
string ContestFullType,
|
||||
string ContextFullType,
|
||||
|
||||
string EntityTypeFullName,
|
||||
string EntityTypeIdentifierName,
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MapTo.Extensions;
|
||||
using static MapTo.Sources.Constants;
|
||||
|
||||
|
@ -6,42 +9,84 @@ namespace MapTo.Sources
|
|||
{
|
||||
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();
|
||||
|
||||
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";
|
||||
|
||||
List<string> constructorHeaders = new List<string>();
|
||||
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);
|
||||
|
||||
using var builder = new SourceBuilder()
|
||||
builder
|
||||
.Write(templateToSourceBuilder.ToString());
|
||||
|
||||
}
|
||||
|
||||
if (addSourceTemplate.IsEmpty())
|
||||
{
|
||||
builder
|
||||
.WriteLine(GeneratedFilesHeader)
|
||||
.WriteUsings(model.Usings)
|
||||
.WriteLine("using Microsoft.EntityFrameworkCore;")
|
||||
.WriteLine()
|
||||
// Namespace declaration
|
||||
.WriteLine($"namespace {model.Namespace}")
|
||||
.WriteOpeningBracket()
|
||||
// Class declaration
|
||||
.WriteLine($"public static partial class {model.EntityTypeIdentifierName}Extensions")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine()
|
||||
.WriteLine($"public static (bool, {model.ReadTypeFullName}) Add{model.EntityTypeIdentifierName}(")
|
||||
.WriteLine($"this {model.ContestFullType} dbContext,")
|
||||
.WriteLine($"{model.CreateTypeFullName} {model.EntityTypeIdentifierName.ToLower()}toCreate)")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine($"var new{model.EntityTypeIdentifierName} = new {model.EntityTypeFullName}({model.EntityTypeIdentifierName.ToLower()}toCreate);")
|
||||
.WriteLine($"dbContext.{model.PropertyName}.Add(new{model.EntityTypeIdentifierName});")
|
||||
.WriteLine($"var success = dbContext.SaveChanges() >= 0;")
|
||||
.WriteLine($"return (success, new {model.ReadTypeFullName}(new{model.EntityTypeIdentifierName}));")
|
||||
.WriteClosingBracket();
|
||||
builder
|
||||
.WriteLine()
|
||||
// End class declaration
|
||||
.WriteClosingBracket()
|
||||
.WriteLine()
|
||||
// End namespace declaration
|
||||
.WriteClosingBracket();
|
||||
.WriteUsings(model.Usings)
|
||||
.WriteLine("using Microsoft.EntityFrameworkCore;")
|
||||
.WriteLine()
|
||||
// Namespace declaration
|
||||
.WriteLine($"namespace {model.Namespace}")
|
||||
.WriteOpeningBracket()
|
||||
// Class declaration
|
||||
.WriteLine($"public static partial class {model.EntityTypeIdentifierName}Extensions")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine()
|
||||
.WriteLine($"public static (bool, {model.ReadTypeFullName}) Add{entityTypeName}(")
|
||||
.WriteLine($"this {contextFullName} dbContext,")
|
||||
.WriteLine($"{createTypeFullName} {toCreateVarName})")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine($"var {newEntityVarName} = new {model.EntityTypeFullName}({toCreateVarName});")
|
||||
.WriteLine($"dbContext.{propertyName}.Add({newEntityVarName});")
|
||||
.WriteLine($"var success = dbContext.SaveChanges() >= 0;")
|
||||
.WriteLine($"return (success, new {readTypeFullName}({newEntityVarName}));")
|
||||
.WriteClosingBracket();
|
||||
builder
|
||||
.WriteLine()
|
||||
// End class declaration
|
||||
.WriteClosingBracket()
|
||||
.WriteLine()
|
||||
// End namespace declaration
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ namespace MapTo.Tests.Infrastructure
|
|||
}
|
||||
|
||||
var driver = CSharpGeneratorDriver.Create(
|
||||
new List<ISourceGenerator>() { new MapToGenerator(), new EfMethodsGenerator() },
|
||||
new List<ISourceGenerator>() { new MapToGenerator(), new EfAddMethodsGenerator() },
|
||||
optionsProvider: new TestAnalyzerConfigOptionsProvider(analyzerConfigOptions),
|
||||
parseOptions: new CSharpParseOptions(languageVersion)
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue