Add template working
This commit is contained in:
parent
340a89bbd2
commit
e232fa6e76
|
@ -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,
|
|
@ -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()
|
||||||
};
|
};
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,42 +9,84 @@ 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;")
|
||||||
.WriteLine()
|
.WriteLine()
|
||||||
// Namespace declaration
|
// Namespace declaration
|
||||||
.WriteLine($"namespace {model.Namespace}")
|
.WriteLine($"namespace {model.Namespace}")
|
||||||
.WriteOpeningBracket()
|
.WriteOpeningBracket()
|
||||||
// Class declaration
|
// Class declaration
|
||||||
.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()
|
||||||
// End class declaration
|
// End class declaration
|
||||||
.WriteClosingBracket()
|
.WriteClosingBracket()
|
||||||
.WriteLine()
|
.WriteLine()
|
||||||
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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)
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue