Simplified using statements and fix nested mappings.
This commit is contained in:
parent
6ad7ea83f9
commit
c1a763a474
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MapTo.Sources;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
|
@ -68,7 +67,13 @@ namespace MapTo.Extensions
|
|||
targetProperty.NullableAnnotation == NullableAnnotation.Annotated));
|
||||
}
|
||||
|
||||
public static INamedTypeSymbol GetTypeByMetadataNameOrThrow(this Compilation compilation, string fullyQualifiedMetadataName) =>
|
||||
public static INamedTypeSymbol GetTypeByMetadataNameOrThrow(this Compilation compilation, string fullyQualifiedMetadataName) =>
|
||||
compilation.GetTypeByMetadataName(fullyQualifiedMetadataName) ?? throw new TypeLoadException($"Unable to find '{fullyQualifiedMetadataName}' type.");
|
||||
|
||||
public static bool IsGenericEnumerable(this Compilation compilation, ITypeSymbol typeSymbol) =>
|
||||
typeSymbol is INamedTypeSymbol { IsGenericType: true } &&
|
||||
compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T).Equals(typeSymbol.OriginalDefinition, SymbolEqualityComparer.Default);
|
||||
|
||||
public static bool IsArray(this Compilation compilation, ITypeSymbol typeSymbol) => typeSymbol is IArrayTypeSymbol;
|
||||
}
|
||||
}
|
|
@ -12,16 +12,19 @@ namespace MapTo
|
|||
{
|
||||
private readonly ClassDeclarationSyntax _classSyntax;
|
||||
private readonly Compilation _compilation;
|
||||
private readonly List<Diagnostic> _diagnostics;
|
||||
private readonly INamedTypeSymbol _ignorePropertyAttributeTypeSymbol;
|
||||
private readonly INamedTypeSymbol _mapFromAttributeTypeSymbol;
|
||||
private readonly INamedTypeSymbol _mapPropertyAttributeTypeSymbol;
|
||||
private readonly INamedTypeSymbol _mapTypeConverterAttributeTypeSymbol;
|
||||
private readonly SourceGenerationOptions _sourceGenerationOptions;
|
||||
private readonly INamedTypeSymbol _typeConverterInterfaceTypeSymbol;
|
||||
private readonly List<string> _usings;
|
||||
|
||||
internal MappingContext(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, ClassDeclarationSyntax classSyntax)
|
||||
{
|
||||
Diagnostics = ImmutableArray<Diagnostic>.Empty;
|
||||
_diagnostics = new List<Diagnostic>();
|
||||
_usings = new List<string> { "System" };
|
||||
_sourceGenerationOptions = sourceGenerationOptions;
|
||||
_classSyntax = classSyntax;
|
||||
_compilation = compilation;
|
||||
|
@ -32,26 +35,28 @@ namespace MapTo
|
|||
_mapPropertyAttributeTypeSymbol = compilation.GetTypeByMetadataNameOrThrow(MapPropertyAttributeSource.FullyQualifiedName);
|
||||
_mapFromAttributeTypeSymbol = compilation.GetTypeByMetadataNameOrThrow(MapFromAttributeSource.FullyQualifiedName);
|
||||
|
||||
AddUsingIfRequired(sourceGenerationOptions.SupportNullableReferenceTypes, "System.Diagnostics.CodeAnalysis");
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public MappingModel? Model { get; private set; }
|
||||
|
||||
public ImmutableArray<Diagnostic> Diagnostics { get; private set; }
|
||||
public IEnumerable<Diagnostic> Diagnostics => _diagnostics;
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
var semanticModel = _compilation.GetSemanticModel(_classSyntax.SyntaxTree);
|
||||
if (!(semanticModel.GetDeclaredSymbol(_classSyntax) is INamedTypeSymbol classTypeSymbol))
|
||||
{
|
||||
ReportDiagnostic(DiagnosticProvider.TypeNotFoundError(_classSyntax.GetLocation(), _classSyntax.Identifier.ValueText));
|
||||
_diagnostics.Add(DiagnosticProvider.TypeNotFoundError(_classSyntax.GetLocation(), _classSyntax.Identifier.ValueText));
|
||||
return;
|
||||
}
|
||||
|
||||
var sourceTypeSymbol = GetSourceTypeSymbol(_classSyntax, semanticModel);
|
||||
if (sourceTypeSymbol is null)
|
||||
{
|
||||
ReportDiagnostic(DiagnosticProvider.MapFromAttributeNotFoundError(_classSyntax.GetLocation()));
|
||||
_diagnostics.Add(DiagnosticProvider.MapFromAttributeNotFoundError(_classSyntax.GetLocation()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -62,10 +67,13 @@ namespace MapTo
|
|||
var mappedProperties = GetMappedProperties(classTypeSymbol, sourceTypeSymbol, isClassInheritFromMappedBaseClass);
|
||||
if (!mappedProperties.Any())
|
||||
{
|
||||
ReportDiagnostic(DiagnosticProvider.NoMatchingPropertyFoundError(_classSyntax.GetLocation(), classTypeSymbol, sourceTypeSymbol));
|
||||
_diagnostics.Add(DiagnosticProvider.NoMatchingPropertyFoundError(_classSyntax.GetLocation(), classTypeSymbol, sourceTypeSymbol));
|
||||
return;
|
||||
}
|
||||
|
||||
AddUsingIfRequired(sourceTypeSymbol);
|
||||
AddUsingIfRequired(mappedProperties.Any(p => p.IsEnumerable), "System.Linq");
|
||||
|
||||
Model = new MappingModel(
|
||||
_sourceGenerationOptions,
|
||||
_classSyntax.GetNamespace(),
|
||||
|
@ -75,7 +83,8 @@ namespace MapTo
|
|||
sourceClassName,
|
||||
sourceTypeSymbol.ToString(),
|
||||
mappedProperties.ToImmutableArray(),
|
||||
isClassInheritFromMappedBaseClass);
|
||||
isClassInheritFromMappedBaseClass,
|
||||
_usings.ToImmutableArray());
|
||||
}
|
||||
|
||||
private bool IsClassInheritFromMappedBaseClass(SemanticModel semanticModel)
|
||||
|
@ -103,60 +112,73 @@ namespace MapTo
|
|||
|
||||
string? converterFullyQualifiedName = null;
|
||||
var converterParameters = ImmutableArray<string>.Empty;
|
||||
string? mappedSourcePropertyType = null;
|
||||
ITypeSymbol? mappedSourcePropertyType = null;
|
||||
ITypeSymbol? enumerableTypeArgumentType = null;
|
||||
|
||||
if (!_compilation.HasCompatibleTypes(sourceProperty, property))
|
||||
{
|
||||
if (!TryGetMapTypeConverter(property, sourceProperty, out converterFullyQualifiedName, out converterParameters) &&
|
||||
!TryGetNestedObjectMappings(property, out mappedSourcePropertyType))
|
||||
!TryGetNestedObjectMappings(property, out mappedSourcePropertyType, out enumerableTypeArgumentType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
mappedProperties.Add(new MappedProperty(
|
||||
property.Name,
|
||||
property.Type.Name,
|
||||
converterFullyQualifiedName,
|
||||
converterParameters.ToImmutableArray(),
|
||||
sourceProperty.Name,
|
||||
mappedSourcePropertyType));
|
||||
AddUsingIfRequired(property.Type);
|
||||
AddUsingIfRequired(sourceTypeSymbol);
|
||||
AddUsingIfRequired(enumerableTypeArgumentType);
|
||||
AddUsingIfRequired(mappedSourcePropertyType);
|
||||
|
||||
mappedProperties.Add(
|
||||
new MappedProperty(
|
||||
property.Name,
|
||||
property.Type.Name,
|
||||
converterFullyQualifiedName,
|
||||
converterParameters.ToImmutableArray(),
|
||||
sourceProperty.Name,
|
||||
mappedSourcePropertyType?.Name,
|
||||
enumerableTypeArgumentType?.Name));
|
||||
}
|
||||
|
||||
return mappedProperties.ToImmutableArray();
|
||||
}
|
||||
|
||||
private bool TryGetNestedObjectMappings(IPropertySymbol property, out string? mappedSourcePropertyType)
|
||||
private bool TryGetNestedObjectMappings(IPropertySymbol property, out ITypeSymbol? mappedSourcePropertyType, out ITypeSymbol? enumerableTypeArgument)
|
||||
{
|
||||
mappedSourcePropertyType = null;
|
||||
enumerableTypeArgument = null;
|
||||
|
||||
if (!Diagnostics.IsEmpty)
|
||||
if (!_diagnostics.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var nestedSourceMapFromAttribute = property.Type.GetAttribute(_mapFromAttributeTypeSymbol);
|
||||
if (nestedSourceMapFromAttribute is null)
|
||||
var mapFromAttribute = property.Type.GetAttribute(_mapFromAttributeTypeSymbol);
|
||||
if (mapFromAttribute is null && property.Type is INamedTypeSymbol namedTypeSymbol && _compilation.IsGenericEnumerable(property.Type))
|
||||
{
|
||||
ReportDiagnostic(DiagnosticProvider.NoMatchingPropertyTypeFoundError(property));
|
||||
return false;
|
||||
enumerableTypeArgument = namedTypeSymbol.TypeArguments.First();
|
||||
mapFromAttribute = enumerableTypeArgument.GetAttribute(_mapFromAttributeTypeSymbol);
|
||||
}
|
||||
|
||||
if (!(nestedSourceMapFromAttribute.ApplicationSyntaxReference?.GetSyntax() is AttributeSyntax nestedAttributeSyntax))
|
||||
mappedSourcePropertyType = mapFromAttribute?.ConstructorArguments.First().Value as INamedTypeSymbol;
|
||||
|
||||
if (mappedSourcePropertyType is null && enumerableTypeArgument is null)
|
||||
{
|
||||
ReportDiagnostic(DiagnosticProvider.NoMatchingPropertyTypeFoundError(property));
|
||||
return false;
|
||||
_diagnostics.Add(DiagnosticProvider.NoMatchingPropertyTypeFoundError(property));
|
||||
}
|
||||
|
||||
var nestedSourceTypeSymbol = GetSourceTypeSymbol(nestedAttributeSyntax);
|
||||
if (nestedSourceTypeSymbol is null)
|
||||
{
|
||||
ReportDiagnostic(DiagnosticProvider.NoMatchingPropertyTypeFoundError(property));
|
||||
return false;
|
||||
}
|
||||
return _diagnostics.IsEmpty();
|
||||
}
|
||||
|
||||
mappedSourcePropertyType = nestedSourceTypeSymbol.Name;
|
||||
return true;
|
||||
private void AddUsingIfRequired(ISymbol? namedTypeSymbol) =>
|
||||
AddUsingIfRequired(namedTypeSymbol?.ContainingNamespace.IsGlobalNamespace == false, namedTypeSymbol?.ContainingNamespace.ToDisplayString());
|
||||
|
||||
private void AddUsingIfRequired(bool condition, string? ns)
|
||||
{
|
||||
if (condition && ns is not null && ns != _classSyntax.GetNamespace() && !_usings.Contains(ns))
|
||||
{
|
||||
_usings.Add(ns);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetMapTypeConverter(IPropertySymbol property, IPropertySymbol sourceProperty, out string? converterFullyQualifiedName, out ImmutableArray<string> converterParameters)
|
||||
|
@ -164,7 +186,7 @@ namespace MapTo
|
|||
converterFullyQualifiedName = null;
|
||||
converterParameters = ImmutableArray<string>.Empty;
|
||||
|
||||
if (!Diagnostics.IsEmpty)
|
||||
if (!_diagnostics.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -178,7 +200,7 @@ namespace MapTo
|
|||
var baseInterface = GetTypeConverterBaseInterface(converterTypeSymbol, property, sourceProperty);
|
||||
if (baseInterface is null)
|
||||
{
|
||||
ReportDiagnostic(DiagnosticProvider.InvalidTypeConverterGenericTypesError(property, sourceProperty));
|
||||
_diagnostics.Add(DiagnosticProvider.InvalidTypeConverterGenericTypesError(property, sourceProperty));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -216,11 +238,6 @@ namespace MapTo
|
|||
: converterParameter.Values.Where(v => v.Value is not null).Select(v => v.Value!.ToSourceCodeString()).ToImmutableArray();
|
||||
}
|
||||
|
||||
private void ReportDiagnostic(Diagnostic diagnostic)
|
||||
{
|
||||
Diagnostics = Diagnostics.Add(diagnostic);
|
||||
}
|
||||
|
||||
private INamedTypeSymbol? GetSourceTypeSymbol(ClassDeclarationSyntax classDeclarationSyntax, SemanticModel? semanticModel = null) =>
|
||||
GetSourceTypeSymbol(classDeclarationSyntax.GetAttribute(MapFromAttributeSource.AttributeName), semanticModel);
|
||||
|
||||
|
|
|
@ -8,12 +8,16 @@ namespace MapTo
|
|||
internal record SourceCode(string Text, string HintName);
|
||||
|
||||
internal record MappedProperty(
|
||||
string Name,
|
||||
string Name,
|
||||
string Type,
|
||||
string? TypeConverter,
|
||||
string? TypeConverter,
|
||||
ImmutableArray<string> TypeConverterParameters,
|
||||
string SourcePropertyName,
|
||||
string? MappedSourcePropertyTypeName);
|
||||
string? MappedSourcePropertyTypeName,
|
||||
string? EnumerableTypeArgument)
|
||||
{
|
||||
public bool IsEnumerable => EnumerableTypeArgument is not null;
|
||||
}
|
||||
|
||||
internal record MappingModel (
|
||||
SourceGenerationOptions Options,
|
||||
|
@ -24,7 +28,8 @@ namespace MapTo
|
|||
string SourceClassName,
|
||||
string SourceClassFullName,
|
||||
ImmutableArray<MappedProperty> MappedProperties,
|
||||
bool HasMappedBaseClass
|
||||
bool HasMappedBaseClass,
|
||||
ImmutableArray<string> Usings
|
||||
);
|
||||
|
||||
internal record SourceGenerationOptions(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MapTo.Extensions;
|
||||
using System.Linq;
|
||||
using MapTo.Extensions;
|
||||
using static MapTo.Sources.Constants;
|
||||
|
||||
namespace MapTo.Sources
|
||||
|
@ -42,9 +43,8 @@ namespace MapTo.Sources
|
|||
|
||||
private static SourceBuilder WriteUsings(this SourceBuilder builder, MappingModel model)
|
||||
{
|
||||
return builder
|
||||
.WriteLine("using System;")
|
||||
.WriteLineIf(model.Options.SupportNullableReferenceTypes, "using System.Diagnostics.CodeAnalysis;");
|
||||
model.Usings.Sort().ForEach(u => builder.WriteLine($"using {u};"));
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static SourceBuilder GenerateConstructor(this SourceBuilder builder, MappingModel model)
|
||||
|
@ -64,7 +64,7 @@ namespace MapTo.Sources
|
|||
var baseConstructor = model.HasMappedBaseClass ? $" : base({sourceClassParameterName})" : string.Empty;
|
||||
|
||||
builder
|
||||
.WriteLine($"{model.Options.ConstructorAccessModifier.ToLowercaseString()} {model.ClassName}({model.SourceClassFullName} {sourceClassParameterName}){baseConstructor}")
|
||||
.WriteLine($"{model.Options.ConstructorAccessModifier.ToLowercaseString()} {model.ClassName}({model.SourceClassName} {sourceClassParameterName}){baseConstructor}")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine($"if ({sourceClassParameterName} == null) throw new ArgumentNullException(nameof({sourceClassParameterName}));")
|
||||
.WriteLine();
|
||||
|
@ -73,9 +73,16 @@ namespace MapTo.Sources
|
|||
{
|
||||
if (property.TypeConverter is null)
|
||||
{
|
||||
builder.WriteLine(property.MappedSourcePropertyTypeName is null
|
||||
? $"{property.Name} = {sourceClassParameterName}.{property.SourcePropertyName};"
|
||||
: $"{property.Name} = {sourceClassParameterName}.{property.SourcePropertyName}.To{property.Type}();");
|
||||
if (property.IsEnumerable)
|
||||
{
|
||||
builder.WriteLine($"{property.Name} = {sourceClassParameterName}.{property.SourcePropertyName}.Select({property.MappedSourcePropertyTypeName}To{property.EnumerableTypeArgument}Extensions.To{property.EnumerableTypeArgument}).ToList();");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.WriteLine(property.MappedSourcePropertyTypeName is null
|
||||
? $"{property.Name} = {sourceClassParameterName}.{property.SourcePropertyName};"
|
||||
: $"{property.Name} = {sourceClassParameterName}.{property.SourcePropertyName}.To{property.Type}();");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -98,7 +105,7 @@ namespace MapTo.Sources
|
|||
return builder
|
||||
.GenerateConvertorMethodsXmlDocs(model, sourceClassParameterName)
|
||||
.WriteLineIf(model.Options.SupportNullableReferenceTypes, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]")
|
||||
.WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.ClassName}{model.Options.NullableReferenceSyntax} From({model.SourceClassFullName}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})")
|
||||
.WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.ClassName}{model.Options.NullableReferenceSyntax} From({model.SourceClassName}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine($"return {sourceClassParameterName} == null ? null : new {model.ClassName}({sourceClassParameterName});")
|
||||
.WriteClosingBracket();
|
||||
|
@ -136,7 +143,7 @@ namespace MapTo.Sources
|
|||
return builder
|
||||
.GenerateConvertorMethodsXmlDocs(model, sourceClassParameterName)
|
||||
.WriteLineIf(model.Options.SupportNullableReferenceTypes, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]")
|
||||
.WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.ClassName}{model.Options.NullableReferenceSyntax} To{model.ClassName}(this {model.SourceClassFullName}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})")
|
||||
.WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.ClassName}{model.Options.NullableReferenceSyntax} To{model.ClassName}(this {model.SourceClassName}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})")
|
||||
.WriteOpeningBracket()
|
||||
.WriteLine($"return {sourceClassParameterName} == null ? null : new {model.ClassName}({sourceClassParameterName});")
|
||||
.WriteClosingBracket();
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MapTo.Extensions;
|
||||
using MapTo.Sources;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
@ -96,11 +95,19 @@ namespace MapTo.Tests
|
|||
return builder.ToString();
|
||||
}
|
||||
|
||||
internal static string[] GetEmployeeManagerSourceText(Func<string> employeeClassSource = null, Func<string> managerClassSource = null, Func<string> employeeViewModelSource = null, Func<string> managerViewModelSource = null)
|
||||
internal static string[] GetEmployeeManagerSourceText(Func<string> employeeClassSource = null, Func<string> managerClassSource = null, Func<string> employeeViewModelSource = null, Func<string> managerViewModelSource = null, bool useDifferentViewModelNamespace = false)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
employeeClassSource?.Invoke() ?? @"
|
||||
employeeClassSource?.Invoke() ?? DefaultEmployeeClassSource(),
|
||||
managerClassSource?.Invoke() ?? DefaultManagerClassSource(),
|
||||
employeeViewModelSource?.Invoke() ??
|
||||
DefaultEmployeeViewModelSource(useDifferentViewModelNamespace),
|
||||
managerViewModelSource?.Invoke() ?? DefaultManagerViewModelSource(useDifferentViewModelNamespace)
|
||||
};
|
||||
|
||||
static string DefaultEmployeeClassSource() =>
|
||||
@"
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
@ -115,8 +122,10 @@ namespace Test.Data.Models
|
|||
|
||||
public Manager Manager { get; set; }
|
||||
}
|
||||
}".Trim(),
|
||||
managerClassSource?.Invoke() ?? @"using System;
|
||||
}".Trim();
|
||||
|
||||
static string DefaultManagerClassSource() =>
|
||||
@"using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
|
@ -129,8 +138,28 @@ namespace Test.Data.Models
|
|||
public IEnumerable<Employee> Employees { get; set; } = Array.Empty<Employee>();
|
||||
}
|
||||
}
|
||||
".Trim(),
|
||||
employeeViewModelSource?.Invoke() ?? @"
|
||||
".Trim();
|
||||
|
||||
static string DefaultEmployeeViewModelSource(bool useDifferentNamespace) => useDifferentNamespace
|
||||
? @"
|
||||
using MapTo;
|
||||
using Test.Data.Models;
|
||||
using Test.ViewModels2;
|
||||
|
||||
namespace Test.ViewModels
|
||||
{
|
||||
[MapFrom(typeof(Employee))]
|
||||
public partial class EmployeeViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string EmployeeCode { get; set; }
|
||||
|
||||
public ManagerViewModel Manager { get; set; }
|
||||
}
|
||||
}
|
||||
".Trim()
|
||||
: @"
|
||||
using MapTo;
|
||||
using Test.Data.Models;
|
||||
|
||||
|
@ -146,8 +175,28 @@ namespace Test.ViewModels
|
|||
public ManagerViewModel Manager { get; set; }
|
||||
}
|
||||
}
|
||||
".Trim(),
|
||||
managerViewModelSource?.Invoke() ?? @"
|
||||
".Trim();
|
||||
|
||||
static string DefaultManagerViewModelSource(bool useDifferentNamespace) => useDifferentNamespace
|
||||
? @"
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MapTo;
|
||||
using Test.Data.Models;
|
||||
using Test.ViewModels;
|
||||
|
||||
namespace Test.ViewModels2
|
||||
{
|
||||
[MapFrom(typeof(Manager))]
|
||||
public partial class ManagerViewModel : EmployeeViewModel
|
||||
{
|
||||
public int Level { get; set; }
|
||||
|
||||
public IEnumerable<EmployeeViewModel> Employees { get; set; } = Array.Empty<EmployeeViewModel>();
|
||||
}
|
||||
}
|
||||
".Trim()
|
||||
: @"
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MapTo;
|
||||
|
@ -162,8 +211,7 @@ namespace Test.ViewModels
|
|||
|
||||
public IEnumerable<EmployeeViewModel> Employees { get; set; } = Array.Empty<EmployeeViewModel>();
|
||||
}
|
||||
}".Trim()
|
||||
};
|
||||
}".Trim();
|
||||
}
|
||||
|
||||
internal static PropertyDeclarationSyntax GetPropertyDeclarationSyntax(SyntaxTree syntaxTree, string targetPropertyName, string targetClass = "Foo")
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace MapTo
|
|||
var expectedResult = @"
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Models.Baz baz)
|
||||
public Foo(Baz baz)
|
||||
{
|
||||
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace MapTo.Tests.Infrastructure
|
|||
|
||||
driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generateDiagnostics);
|
||||
|
||||
generateDiagnostics.ShouldBeSuccessful();
|
||||
generateDiagnostics.ShouldBeSuccessful(ignoreDiagnosticsIds: new[] { "MT" });
|
||||
outputCompilation.GetDiagnostics().ShouldBeSuccessful(outputCompilation);
|
||||
|
||||
return (outputCompilation, generateDiagnostics);
|
||||
|
|
|
@ -60,7 +60,7 @@ namespace MapTo
|
|||
var expectedResult = @"
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Models.Baz baz)
|
||||
public Foo(Baz baz)
|
||||
{
|
||||
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
||||
|
||||
|
|
|
@ -75,14 +75,14 @@ namespace MapTo
|
|||
var expectedExtension = @"
|
||||
internal static partial class BazToFooExtensions
|
||||
{
|
||||
internal static Foo ToFoo(this Test.Models.Baz baz)
|
||||
internal static Foo ToFoo(this Baz baz)
|
||||
{
|
||||
return baz == null ? null : new Foo(baz);
|
||||
}
|
||||
}".Trim();
|
||||
|
||||
var expectedFactory = @"
|
||||
internal static Foo From(Test.Models.Baz baz)
|
||||
internal static Foo From(Baz baz)
|
||||
{
|
||||
return baz == null ? null : new Foo(baz);
|
||||
}".Trim();
|
||||
|
@ -129,7 +129,7 @@ namespace Test
|
|||
{
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Baz baz)
|
||||
public Foo(Baz baz)
|
||||
{
|
||||
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
||||
|
||||
|
@ -199,7 +199,7 @@ namespace Test
|
|||
{
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Baz baz)
|
||||
public Foo(Baz baz)
|
||||
{
|
||||
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
||||
|
||||
|
@ -249,6 +249,7 @@ namespace Test
|
|||
const string expectedResult = @"
|
||||
// <auto-generated />
|
||||
|
||||
using Bazaar;
|
||||
using System;
|
||||
|
||||
namespace Test
|
||||
|
@ -271,7 +272,7 @@ namespace Test
|
|||
const string expectedResult = @"
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Models.Baz baz)
|
||||
public Foo(Baz baz)
|
||||
{
|
||||
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
||||
|
||||
|
@ -296,7 +297,7 @@ namespace Test
|
|||
var source = GetSourceText();
|
||||
|
||||
const string expectedResult = @"
|
||||
public static Foo From(Test.Models.Baz baz)
|
||||
public static Foo From(Baz baz)
|
||||
{
|
||||
return baz == null ? null : new Foo(baz);
|
||||
}
|
||||
|
@ -319,7 +320,7 @@ namespace Test
|
|||
const string expectedResult = @"
|
||||
public static partial class BazToFooExtensions
|
||||
{
|
||||
public static Foo ToFoo(this Test.Models.Baz baz)
|
||||
public static Foo ToFoo(this Baz baz)
|
||||
{
|
||||
return baz == null ? null : new Foo(baz);
|
||||
}
|
||||
|
@ -356,7 +357,7 @@ namespace Test
|
|||
var expectedResult = @"
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Baz baz)
|
||||
public Foo(Baz baz)
|
||||
{
|
||||
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
||||
|
||||
|
@ -442,7 +443,7 @@ namespace Test
|
|||
const string expectedResult = @"
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Models.Baz baz)
|
||||
public Foo(Baz baz)
|
||||
{
|
||||
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
||||
|
||||
|
@ -468,12 +469,76 @@ namespace Test
|
|||
var sources = GetEmployeeManagerSourceText();
|
||||
|
||||
const string expectedResult = @"
|
||||
public ManagerViewModel(Test.Data.Models.Manager manager) : base(manager)
|
||||
public ManagerViewModel(Manager manager) : base(manager)
|
||||
{
|
||||
if (manager == null) throw new ArgumentNullException(nameof(manager));
|
||||
|
||||
Level = manager.Level;
|
||||
}
|
||||
";
|
||||
|
||||
// Act
|
||||
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(sources, analyzerConfigOptions: DefaultAnalyzerOptions);
|
||||
|
||||
// Assert
|
||||
diagnostics.ShouldBeSuccessful();
|
||||
compilation.SyntaxTrees.Last().ShouldContainPartialSource(expectedResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void When_SourceTypeHasEnumerablePropertiesWithMapFromAttribute_Should_CreateANewEnumerableWithMappedObjects()
|
||||
{
|
||||
// Arrange
|
||||
var sources = GetEmployeeManagerSourceText();
|
||||
|
||||
const string expectedResult = @"
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Test.Data.Models;
|
||||
|
||||
namespace Test.ViewModels
|
||||
{
|
||||
partial class ManagerViewModel
|
||||
{
|
||||
public ManagerViewModel(Manager manager) : base(manager)
|
||||
{
|
||||
if (manager == null) throw new ArgumentNullException(nameof(manager));
|
||||
|
||||
Level = manager.Level;
|
||||
Employees = manager.Employees.Select(EmployeeToEmployeeViewModelExtensions.ToEmployeeViewModel).ToList();
|
||||
";
|
||||
|
||||
// Act
|
||||
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(sources, analyzerConfigOptions: DefaultAnalyzerOptions);
|
||||
|
||||
// Assert
|
||||
diagnostics.ShouldBeSuccessful();
|
||||
compilation.SyntaxTrees.Last().ShouldContainPartialSource(expectedResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void When_SourceTypeHasEnumerablePropertiesWithMapFromAttributeInDifferentNamespaces_Should_CreateANewEnumerableWithMappedObjectsAndImportNamespace()
|
||||
{
|
||||
// Arrange
|
||||
var sources = GetEmployeeManagerSourceText(useDifferentViewModelNamespace: true);
|
||||
|
||||
const string expectedResult = @"
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Test.Data.Models;
|
||||
using Test.ViewModels;
|
||||
|
||||
namespace Test.ViewModels2
|
||||
{
|
||||
partial class ManagerViewModel
|
||||
{
|
||||
public ManagerViewModel(Manager manager) : base(manager)
|
||||
{
|
||||
if (manager == null) throw new ArgumentNullException(nameof(manager));
|
||||
|
||||
Level = manager.Level;
|
||||
Employees = manager.Employees.Select(EmployeeToEmployeeViewModelExtensions.ToEmployeeViewModel).ToList();
|
||||
";
|
||||
|
||||
// Act
|
||||
|
|
|
@ -219,7 +219,7 @@ namespace Test
|
|||
var expectedResult = @"
|
||||
partial class Foo
|
||||
{
|
||||
public Foo(Test.Models.Baz baz)
|
||||
public Foo(Baz baz)
|
||||
{
|
||||
if (baz == null) throw new ArgumentNullException(nameof(baz));
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using TestConsoleApp.Data.Models;
|
||||
using TestConsoleApp.ViewModels;
|
||||
using TestConsoleApp.ViewModels2;
|
||||
|
||||
namespace TestConsoleApp
|
||||
{
|
||||
|
@ -41,8 +42,8 @@ namespace TestConsoleApp
|
|||
manager1.Employees = new[] { employee1, manager2 };
|
||||
manager2.Employees = new[] { employee2 };
|
||||
|
||||
var manager1ViewModel = manager1.ToManagerViewModel();
|
||||
int a = 0;
|
||||
manager1.ToManagerViewModel();
|
||||
employee1.ToEmployeeViewModel();
|
||||
}
|
||||
|
||||
private static void UserTest()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using MapTo;
|
||||
using TestConsoleApp.Data.Models;
|
||||
using TestConsoleApp.ViewModels2;
|
||||
|
||||
namespace TestConsoleApp.ViewModels
|
||||
{
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
using System.Collections.Generic;
|
||||
using MapTo;
|
||||
using TestConsoleApp.Data.Models;
|
||||
using TestConsoleApp.ViewModels;
|
||||
|
||||
namespace TestConsoleApp.ViewModels
|
||||
namespace TestConsoleApp.ViewModels2
|
||||
{
|
||||
[MapFrom(typeof(Manager))]
|
||||
public partial class ManagerViewModel : EmployeeViewModel
|
||||
|
|
Loading…
Reference in New Issue