Add MapProperty attribute.

This commit is contained in:
Mohammadreza Taikandi 2021-01-07 08:17:36 +00:00
parent e9e44b979a
commit ec21abcf0e
12 changed files with 121 additions and 11 deletions

View File

@ -35,7 +35,7 @@ namespace MapTo.Extensions
internal static string GetBuildPropertyName(string propertyName) => $"build_property.{PropertyNameSuffix}{propertyName}";
internal static void AddSource(this GeneratorExecutionContext context, Source source) =>
context.AddSource(source.HintName, source.Code);
internal static void AddSource(this GeneratorExecutionContext context, SourceCode sourceCode) =>
context.AddSource(sourceCode.HintName, sourceCode.Text);
}
}

View File

@ -25,6 +25,7 @@ namespace MapTo
context.AddSource(MapFromAttributeSource.Generate(options));
context.AddSource(IgnorePropertyAttributeSource.Generate(options));
context.AddSource(TypeConverterSource.Generate(options));
context.AddSource(MapPropertyAttributeSource.Generate(options));
if (context.SyntaxReceiver is MapToSyntaxReceiver receiver && receiver.CandidateClasses.Any())
{

View File

@ -7,7 +7,7 @@ namespace MapTo.Sources
{
internal const string AttributeName = "IgnoreProperty";
internal static Source Generate(SourceGenerationOptions options)
internal static SourceCode Generate(SourceGenerationOptions options)
{
var builder = new SourceBuilder()
.WriteLine(GeneratedFilesHeader)

View File

@ -6,7 +6,7 @@ namespace MapTo.Sources
{
internal static class MapClassSource
{
internal static Source Generate(MapModel model)
internal static SourceCode Generate(MapModel model)
{
using var builder = new SourceBuilder()
.WriteLine(GeneratedFilesHeader)

View File

@ -7,7 +7,7 @@ namespace MapTo.Sources
{
internal const string AttributeName = "MapFrom";
internal static Source Generate(SourceGenerationOptions options)
internal static SourceCode Generate(SourceGenerationOptions options)
{
using var builder = new SourceBuilder()
.WriteLine(GeneratedFilesHeader)

View File

@ -0,0 +1,64 @@
using MapTo.Models;
using static MapTo.Sources.Constants;
namespace MapTo.Sources
{
internal static class MapPropertyAttributeSource
{
internal const string AttributeName = "MapProperty";
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("/// Maps a property to property of another object.")
.WriteLine("/// </summary>");
}
builder
.WriteLine("[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]")
.WriteLine($"public sealed class {AttributeName}Attribute : Attribute")
.WriteOpeningBracket();
if (options.GenerateXmlDocument)
{
builder
.WriteLine("/// <summary>")
.WriteLine("/// Initializes a new instance of <see cref=\"MapPropertyAttribute\"/>.")
.WriteLine("/// </summary>")
.WriteLine("/// <param name=\"converter\">The <see cref=\"ITypeConverter{TSource,TDestination}\" /> to convert the value of the annotated property.</param>");
}
builder
.WriteLine($"public {AttributeName}Attribute(Type converter = null)")
.WriteOpeningBracket()
.WriteLine("Converter = converter;")
.WriteClosingBracket()
.WriteLine();
if (options.GenerateXmlDocument)
{
builder
.WriteLine("/// <summary>")
.WriteLine("/// Gets the <see cref=\"ITypeConverter{TSource,TDestination}\" /> to convert the value of the annotated property.")
.WriteLine("/// </summary>");
}
builder
.WriteLine("public Type Converter { get; }")
.WriteClosingBracket()
.WriteClosingBracket();
return new(builder.ToString(), $"{AttributeName}Attribute.g.cs");
}
}
}

View File

@ -1,4 +0,0 @@
namespace MapTo.Sources
{
internal record Source(string Code, string HintName);
}

View File

@ -0,0 +1,4 @@
namespace MapTo.Sources
{
internal record SourceCode(string Text, string HintName);
}

View File

@ -7,7 +7,7 @@ namespace MapTo.Sources
{
internal const string InterfaceName = "ITypeConverter";
internal static Source Generate(SourceGenerationOptions options)
internal static SourceCode Generate(SourceGenerationOptions options)
{
using var builder = new SourceBuilder()
.WriteLine(GeneratedFilesHeader)

View File

@ -512,5 +512,37 @@ namespace MapTo
diagnostics.ShouldBeSuccessful();
compilation.SyntaxTrees.ShouldContainSource(TypeConverterSource.InterfaceName, expectedInterface);
}
[Fact]
public void VerifyMapPropertyAttribute()
{
// Arrange
const string source = "";
var expectedInterface = $@"
{Constants.GeneratedFilesHeader}
using System;
namespace MapTo
{{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public sealed class MapPropertyAttribute : Attribute
{{
public MapPropertyAttribute(Type converter = null)
{{
Converter = converter;
}}
public Type Converter {{ get; }}
}}
}}
".Trim();
// Act
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source, analyzerConfigOptions: DefaultAnalyzerOptions);
// Assert
diagnostics.ShouldBeSuccessful();
compilation.SyntaxTrees.ShouldContainSource(MapPropertyAttributeSource.AttributeName, expectedInterface);
}
}
}

View File

@ -7,6 +7,10 @@ namespace TestConsoleApp.ViewModels
[MapFrom(typeof(Data.Models.User))]
public partial class User
{
public int Id { get; }
public string FirstName { get; }
public string LastName { get; }
}
}

View File

@ -7,7 +7,16 @@ namespace TestConsoleApp.ViewModels
{
public string FirstName { get; }
// [IgnoreProerty]
[IgnoreProperty]
public string LastName { get; }
[MapProperty(converter: typeof(LastNameConverter))]
public string Key { get; }
private class LastNameConverter : ITypeConverter<int, string>
{
/// <inheritdoc />
public string Convert(int source) => $"{source} :: With Type Converter";
}
}
}