Apply attribute filter
This commit is contained in:
parent
a6cb43b3e4
commit
69c2733046
|
|
@ -5,8 +5,10 @@ using Microsoft.CodeAnalysis.Text;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
|
@ -79,7 +81,7 @@ namespace AutoMapProperty
|
||||||
public string Namespace;
|
public string Namespace;
|
||||||
public string Name;
|
public string Name;
|
||||||
|
|
||||||
public record struct ProperyGenerationInfo(PropertyDeclarationSyntax prop, bool generateConverter = true);
|
public record struct ProperyGenerationInfo(PropertyDeclarationSyntax prop, bool customFrom, IMethodSymbol? customFromMethod, bool customTo, IMethodSymbol? customToMethod);
|
||||||
public List<ProperyGenerationInfo> Properties;
|
public List<ProperyGenerationInfo> Properties;
|
||||||
|
|
||||||
public struct MappableTypes
|
public struct MappableTypes
|
||||||
|
|
@ -89,13 +91,20 @@ namespace AutoMapProperty
|
||||||
|
|
||||||
public IPropertySymbol FromProperty;
|
public IPropertySymbol FromProperty;
|
||||||
public bool FromIsReadOnly => FromProperty.SetMethod == null;
|
public bool FromIsReadOnly => FromProperty.SetMethod == null;
|
||||||
public bool GenerateConverter = true;
|
|
||||||
public MappableTypes(string from, string to, IPropertySymbol fromProperty, bool generateConverter = true)
|
public bool CustomFrom;
|
||||||
|
public IMethodSymbol? CustomFromMethod;
|
||||||
|
public bool CustomTo;
|
||||||
|
public IMethodSymbol? CustomToMethod;
|
||||||
|
public MappableTypes(string from, string to, IPropertySymbol fromProperty, bool customFrom, IMethodSymbol? customFromMethod, bool customTo, IMethodSymbol? customToMethod, bool generateConverter = true)
|
||||||
{
|
{
|
||||||
From = from;
|
From = from;
|
||||||
To = to;
|
To = to;
|
||||||
FromProperty = fromProperty;
|
FromProperty = fromProperty;
|
||||||
GenerateConverter = generateConverter;
|
CustomFrom = customFrom;
|
||||||
|
CustomFromMethod = customFromMethod;
|
||||||
|
CustomTo = customTo;
|
||||||
|
CustomToMethod = customToMethod;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,7 +181,7 @@ namespace AutoMapProperty
|
||||||
|
|
||||||
string className = classSymbol.Name;
|
string className = classSymbol.Name;
|
||||||
|
|
||||||
foreach (var attr in propSymbol.GetAttributes())
|
foreach (AttributeData attr in propSymbol.GetAttributes())
|
||||||
{
|
{
|
||||||
if (!propAttribute.Equals(attr.AttributeClass, SymbolEqualityComparer.Default))
|
if (!propAttribute.Equals(attr.AttributeClass, SymbolEqualityComparer.Default))
|
||||||
{
|
{
|
||||||
|
|
@ -196,13 +205,39 @@ namespace AutoMapProperty
|
||||||
classesToGenerate[name] = new ClassToGenerate(PropParentDecl, name, ns, usings, new List<ClassToGenerate.ProperyGenerationInfo>());
|
classesToGenerate[name] = new ClassToGenerate(PropParentDecl, name, ns, usings, new List<ClassToGenerate.ProperyGenerationInfo>());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Modify attributes to not include our generation attribute
|
var mem = propSyntax;
|
||||||
var mem = propSyntax.WithAttributeLists(GetModifiedAttributeList(compilation, propSyntax.AttributeLists));
|
try
|
||||||
|
{
|
||||||
|
var newList = GetModifiedAttributeList(compilation, propSyntax.AttributeLists);
|
||||||
|
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(
|
||||||
|
new DiagnosticDescriptor("NEJ23", "Error", "New list on: {1} {0}", "NEJ", DiagnosticSeverity.Warning, true), null, string.Join(", ", newList.Select(x => x.ToString())), propSymbol.Name)
|
||||||
|
);
|
||||||
|
|
||||||
|
//Modify attributes to not include our generation attribute
|
||||||
|
mem = propSyntax.WithAttributeLists(newList);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(
|
||||||
|
new DiagnosticDescriptor("NEJ23", "Error", "Error processing {0}", "NEJ", DiagnosticSeverity.Error, true), null, propSymbol.Name)
|
||||||
|
);
|
||||||
|
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(
|
||||||
|
new DiagnosticDescriptor("NEJ23", "Error", "{0}", "NEJ", DiagnosticSeverity.Error, true), null, ex.Message)
|
||||||
|
);
|
||||||
|
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(
|
||||||
|
new DiagnosticDescriptor("NEJ23", "Error", "{0}", "NEJ", DiagnosticSeverity.Error, true), null, ex.StackTrace)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
//If we have a special overwrite type, replace it
|
//If we have a special overwrite type, replace it
|
||||||
INamedTypeSymbol? dataTypename = (INamedTypeSymbol?)attr?.ConstructorArguments[1].Value;
|
if (attr.ConstructorArguments.Count() >= 2)
|
||||||
if (dataTypename != null)
|
{
|
||||||
|
INamedTypeSymbol dataTypename = attr?.ConstructorArguments[1].Value as INamedTypeSymbol;
|
||||||
mem = mem.WithType(SyntaxFactory.ParseTypeName(dataTypename.ToDisplayString() + " "));
|
mem = mem.WithType(SyntaxFactory.ParseTypeName(dataTypename.ToDisplayString() + " "));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//if the property is readonly, remove the readonly modifier
|
//if the property is readonly, remove the readonly modifier
|
||||||
|
|
@ -227,11 +262,24 @@ namespace AutoMapProperty
|
||||||
mem = mem.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None));
|
mem = mem.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None));
|
||||||
|
|
||||||
//if we dont want to generate converter
|
//if we dont want to generate converter
|
||||||
//bool generateConverters = true;
|
bool customFrom = false;
|
||||||
bool generateConverters = !(attr?.ConstructorArguments[2] != null && attr?.ConstructorArguments[2].Value is bool b && b == false);
|
IMethodSymbol? customFromMethod = null;
|
||||||
|
bool customTo = false;
|
||||||
|
IMethodSymbol? customToMethod = null;
|
||||||
|
if (attr.ConstructorArguments.Count() >= 3)
|
||||||
|
{
|
||||||
|
customTo = true;
|
||||||
|
customToMethod = ProcessCustomAttribute(context, classSymbol, attr.ConstructorArguments[2]);
|
||||||
|
}
|
||||||
|
if (attr.ConstructorArguments.Count() >= 4)
|
||||||
|
{
|
||||||
|
customFrom = true;
|
||||||
|
customFromMethod = ProcessCustomAttribute(context, classSymbol, attr.ConstructorArguments[3]);
|
||||||
|
}
|
||||||
//Add the property to the carrier type
|
//Add the property to the carrier type
|
||||||
classesToGenerate[name].Properties.Add(new ClassToGenerate.ProperyGenerationInfo(mem, generateConverters));
|
classesToGenerate[name].Properties.Add(
|
||||||
|
new ClassToGenerate.ProperyGenerationInfo(mem, customFrom, customFromMethod, customTo, customToMethod)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,7 +291,34 @@ namespace AutoMapProperty
|
||||||
return classesToGenerate.Values.ToList();
|
return classesToGenerate.Values.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public record struct PropertyGenInfo(string type, IPropertySymbol? symbol = null, bool generateConverter = true);
|
public static IMethodSymbol? ProcessCustomAttribute(SourceProductionContext cont, INamedTypeSymbol classSymbol, TypedConstant attr)
|
||||||
|
{
|
||||||
|
var arg = attr.Value as string;
|
||||||
|
//get all methods of the declaring parent type
|
||||||
|
var methods = classSymbol.GetMembers().OfType<IMethodSymbol>();
|
||||||
|
//get the method with the same name as the attribute argument
|
||||||
|
var method = methods.FirstOrDefault(x => x.Name == arg);
|
||||||
|
if (method == null)
|
||||||
|
{
|
||||||
|
cont.ReportDiagnostic(Diagnostic.Create(
|
||||||
|
new DiagnosticDescriptor("NEJ10", "No method found", "Couldn't find method {0} on {1}", "NEJ", DiagnosticSeverity.Error, true), null, arg, classSymbol.Name)
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if the method is static
|
||||||
|
if (!method.IsStatic)
|
||||||
|
{
|
||||||
|
cont.ReportDiagnostic(Diagnostic.Create(
|
||||||
|
new DiagnosticDescriptor("NEJ10", "Method not static", "Method {0} on {1} is not static", "NEJ", DiagnosticSeverity.Error, true), null, arg, classSymbol.Name)
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record struct PropertyGenInfo(string type, IPropertySymbol? symbol = null, bool customFrom = false, IMethodSymbol? customFromMethod = null, bool customTo = false, IMethodSymbol? customToMethod = null);
|
||||||
|
|
||||||
public static void ProcessClassToGenerateVariations(SourceProductionContext context, Compilation compilation, Dictionary<string, ClassToGenerate> classesToGenerate, ClassToGenerate cls)
|
public static void ProcessClassToGenerateVariations(SourceProductionContext context, Compilation compilation, Dictionary<string, ClassToGenerate> classesToGenerate, ClassToGenerate cls)
|
||||||
{
|
{
|
||||||
|
|
@ -260,7 +335,7 @@ namespace AutoMapProperty
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
possibleCandidates.AddRange(GetClassToGenerate(cls));
|
possibleCandidates.AddRange(GetInfoFromClassToGenerate(cls));
|
||||||
}
|
}
|
||||||
|
|
||||||
//get properties on the source class
|
//get properties on the source class
|
||||||
|
|
@ -285,16 +360,14 @@ namespace AutoMapProperty
|
||||||
var sourceNames = source.ToDictionary(x => x.Item1, x => x.Item2);
|
var sourceNames = source.ToDictionary(x => x.Item1, x => x.Item2);
|
||||||
var possibleNames = possible.ToDictionary(x => x.Item1, x => x.Item2);
|
var possibleNames = possible.ToDictionary(x => x.Item1, x => x.Item2);
|
||||||
cls.MappableProperties = possibleNames.Keys.Where(x => sourceNames.Keys.Contains(x))
|
cls.MappableProperties = possibleNames.Keys.Where(x => sourceNames.Keys.Contains(x))
|
||||||
.ToDictionary(x => x, x => new ClassToGenerate.MappableTypes(sourceNames[x].type, possibleNames[x].type, sourceNames[x].symbol, possibleNames[x].generateConverter));
|
.ToDictionary(x => x, x => new ClassToGenerate.MappableTypes(sourceNames[x].type, possibleNames[x].type, sourceNames[x].symbol, possibleNames[x].customFrom, possibleNames[x].customFromMethod, possibleNames[x].customTo, possibleNames[x].customToMethod));
|
||||||
//c.MappableProperties = c.MappableProperties.ToDictionary(x => x.Item1, x => x.Item2).Select(x => (x.Key, x.Value)).ToList();
|
//c.MappableProperties = c.MappableProperties.ToDictionary(x => x.Item1, x => x.Item2).Select(x => (x.Key, x.Value)).ToList();
|
||||||
context.ReportDiagnostic(
|
context.ReportDiagnostic(
|
||||||
Diagnostic.Create(
|
Diagnostic.Create(
|
||||||
new DiagnosticDescriptor(
|
new DiagnosticDescriptor(
|
||||||
"NEJ01", "Report candidates vs real", "{0} had: {1} possible candidates and:{2} source values, but in the end there were: {3} values",
|
"NEJ01", "Report candidates vs real", "{0} had: {1} possible candidates and:{2} source values, but in the end there were: {3} values",
|
||||||
"NEJ", DiagnosticSeverity.Warning, true), null, cls.Name, possibleCandidates.Count, sourceCandidates.Count, cls.MappableProperties.Count));
|
"NEJ", DiagnosticSeverity.Warning, true), null, cls.Name, possibleCandidates.Count, sourceCandidates.Count, cls.MappableProperties.Count));
|
||||||
context.ReportDiagnostic(Diagnostic.Create(
|
|
||||||
new DiagnosticDescriptor("Nej10", "TestShow", "{0}", "NEJ", DiagnosticSeverity.Warning, true), null, string.Join(",", cls.MappableProperties.Select(x => x.Key + ":" + x.Value.From + "->" + x.Value.To))
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<(string, PropertyGenInfo)> GetSymbolsForTypedSymbol(Compilation comp, INamedTypeSymbol cls, Dictionary<string, ClassToGenerate> ctg)
|
public static List<(string, PropertyGenInfo)> GetSymbolsForTypedSymbol(Compilation comp, INamedTypeSymbol cls, Dictionary<string, ClassToGenerate> ctg)
|
||||||
|
|
@ -315,70 +388,144 @@ namespace AutoMapProperty
|
||||||
{
|
{
|
||||||
var c = currentClassesToBeGenerated[className];
|
var c = currentClassesToBeGenerated[className];
|
||||||
|
|
||||||
return GetClassToGenerate(c);
|
return GetInfoFromClassToGenerate(c);
|
||||||
}
|
}
|
||||||
return new List<(string, PropertyGenInfo)>();
|
return new List<(string, PropertyGenInfo)>();
|
||||||
}
|
}
|
||||||
public static List<(string, PropertyGenInfo)> GetClassToGenerate(ClassToGenerate cls)
|
public static List<(string, PropertyGenInfo)> GetInfoFromClassToGenerate(ClassToGenerate cls)
|
||||||
{
|
{
|
||||||
return cls.Properties.Select(x => (x.prop.Identifier.ToFullString().Trim(),
|
return cls.Properties.Select(x => (x.prop.Identifier.ToFullString().Trim(),
|
||||||
new PropertyGenInfo(x.prop.Type.ToFullString().Trim(), (IPropertySymbol?)null, x.generateConverter)))
|
new PropertyGenInfo(x.prop.Type.ToFullString().Trim(), (IPropertySymbol?)null, x.customFrom, x.customFromMethod, x.customTo, x.customToMethod)))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Attribute_Editing
|
#region Attribute_Editing
|
||||||
public static SyntaxList<AttributeListSyntax> GetModifiedAttributeList(Compilation com, SyntaxList<AttributeListSyntax> inList)
|
public static SyntaxList<AttributeListSyntax> GetModifiedAttributeList(Compilation com, SyntaxList<AttributeListSyntax> attListList)
|
||||||
{
|
{
|
||||||
AttributeListSyntax node = inList.Where(x => x.Attributes.Where(y => IsOurAttribute(com, y)).Where(y => y != null).Count() > 0).FirstOrDefault();
|
if (attListList == null)
|
||||||
if (node == null)
|
return attListList;
|
||||||
throw new Exception("We didnt find a single node in attribute list");
|
if (attListList.Count <= 0)
|
||||||
|
return attListList;
|
||||||
|
|
||||||
var newNode = node.WithAttributes(GetModifiedAttributes(com, node.Attributes));
|
var toRemove = new List<AttributeListSyntax>();
|
||||||
if (newNode.Attributes.Count <= 0)
|
|
||||||
return inList.Remove(node);
|
foreach (var node in attListList.ToList().Where(x => x != null && x.Attributes != null && x.Attributes.Count > 0))
|
||||||
return inList.Replace(node, newNode);
|
{
|
||||||
|
var atts = GetModifiedAttributes(com, node.Attributes);
|
||||||
|
node.WithAttributes(atts);
|
||||||
|
|
||||||
|
if (atts.Count <= 0)
|
||||||
|
toRemove.Add(node);
|
||||||
|
}
|
||||||
|
return new SyntaxList<AttributeListSyntax>(attListList.Where(x => !toRemove.Contains(x)));
|
||||||
}
|
}
|
||||||
public static SeparatedSyntaxList<AttributeSyntax> GetModifiedAttributes(Compilation com, SeparatedSyntaxList<AttributeSyntax> inList)
|
public static SeparatedSyntaxList<AttributeSyntax> GetModifiedAttributes(Compilation com, SeparatedSyntaxList<AttributeSyntax> attList)
|
||||||
{
|
{
|
||||||
AttributeSyntax node = inList.Where(x => IsOurAttribute(com, x)).FirstOrDefault();
|
var toRemove = new List<AttributeSyntax>();
|
||||||
if (node == null)
|
foreach (var x in attList.ToList().Where(x => x != null).Where(x => IsOurAttribute(com, x)))
|
||||||
throw new Exception("We didnt find a single node in attributes");
|
{
|
||||||
return inList.Remove(node);
|
toRemove.Add(x);
|
||||||
|
}
|
||||||
|
var newList = SyntaxFactory.SeparatedList<AttributeSyntax>(attList.Where(x => !toRemove.Contains(x)));
|
||||||
|
return newList;
|
||||||
}
|
}
|
||||||
public static bool IsOurAttribute(Compilation com, AttributeSyntax syntax)
|
public static bool IsOurAttribute(Compilation com, AttributeSyntax syntax)
|
||||||
{
|
{
|
||||||
if (com.GetSemanticModel(syntax.SyntaxTree).GetSymbolInfo(syntax).Symbol is not IMethodSymbol attrSymbol)
|
if (com.GetSemanticModel(syntax.SyntaxTree).GetSymbolInfo(syntax).Symbol is not IMethodSymbol attrSymbol)
|
||||||
return false;
|
return syntax.ToString().Contains(AutoMapPropertyAttributeName);
|
||||||
|
|
||||||
return attrSymbol.ContainingType.Equals(com.GetTypeByMetadataName(AutoMapPropertyAttributeName), SymbolEqualityComparer.Default);
|
var t = com.GetTypeByMetadataName(AutoMapPropertyAttributeName);
|
||||||
|
if (t == null)
|
||||||
|
throw new Exception("AutoMapPropertyAttributeName is null");
|
||||||
|
|
||||||
|
return attrSymbol.ContainingSymbol.Equals(t, SymbolEqualityComparer.Default);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public static string GeneratePropertyFrom(string Key, ClassToGenerate.MappableTypes Value)
|
public static string GetFullMethodName(IMethodSymbol method)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.Append(Key).Append(@" = (").Append(Value.To).Append(@")source.").Append(Key);
|
sb.Append(method.ContainingType.ToDisplayString()).Append(".").Append(method.Name);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
public static string GeneratePropertyFrom(string Key, string Type, bool nullable = true)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(Key).Append(@" = ");
|
||||||
|
|
||||||
//using regex check if the type is IEnumerable or IList or List or ICollection or HashSet or ISet(it can have leading namespace), if so remove them to get the original type
|
//using regex check if the type is IEnumerable or IList or List or ICollection or HashSet or ISet(it can have leading namespace), if so remove them to get the original type
|
||||||
//example System.Collections.Generic.IEnumerable<TestType>
|
//example System.Collections.Generic.IEnumerable<TestType>
|
||||||
//example System.Collections.Generic.IList<TestType>
|
//example System.Collections.Generic.IList<TestType>
|
||||||
//also catch the IEnumerable or IList or List or ICollection or HashSet or ISet and add the appropriate ToHashSet or ToSet or ToCollection or ToList
|
//also catch the IEnumerable or IList or List or ICollection or HashSet or ISet and add the appropriate ToHashSet or ToSet or ToCollection or ToList
|
||||||
var regex = new Regex(@"(?<type>(System\.Collections\.Generic\.)?(IEnumerable|IList|List|ICollection|HashSet|ISet)<(?<type2>.*)>)");
|
var regex = new Regex(@"(?<type>(System\.Collections\.Generic\.)?(IEnumerable|IList|List|ICollection|HashSet|ISet)<(?<type2>.*)>)");
|
||||||
var match = regex.Match(Value.To);
|
var match = regex.Match(Type);
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
var type = match.Groups["type2"].Value;
|
var type = match.Groups["type2"].Value;
|
||||||
sb.Append(@".Select(x => (").Append(type).Append(@")x)");
|
sb.Append("(").Append(Type).Append(@")(source.").Append(Key).Append(" != null ? ");
|
||||||
|
sb.Append("source.").Append(Key);
|
||||||
|
sb.Append(nullable ? "?" : "").Append(@".Select(x => (").Append(type).Append(@")x)").Append(nullable ? "?" : "");
|
||||||
|
|
||||||
//Add the appropriate ToHashSet or ToSet or ToCollection or ToList
|
//Add the appropriate ToHashSet or ToSet or ToCollection or ToList
|
||||||
if (match.Groups["type"].Value.Contains("Set"))
|
if (match.Groups["type"].Value.Contains("Set"))
|
||||||
sb.Append(@".ToHashSet()");
|
sb.Append(@".ToHashSet()");
|
||||||
else
|
else
|
||||||
sb.Append(@".ToList()");
|
sb.Append(@".ToList()");
|
||||||
|
|
||||||
|
sb.Append(" : new ");
|
||||||
|
if (match.Groups["type"].Value.Contains("Set"))
|
||||||
|
sb.Append("HashSet<").Append(type).Append(">()");
|
||||||
|
else
|
||||||
|
sb.Append("List<").Append(type).Append(">()");
|
||||||
|
|
||||||
|
sb.Append(")");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append("(").Append(Type).Append(@")source.").Append(Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
public static string? GenerateCorrectFromProperty(string Key, ClassToGenerate.MappableTypes Value, bool nullable = true)
|
||||||
|
{
|
||||||
|
if (!Value.CustomFrom)
|
||||||
|
{
|
||||||
|
return GeneratePropertyFrom(Key, Value.To, nullable);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Value.CustomFromMethod == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.Append(Key).Append(" = (").Append(Value.To).Append(@")").Append(GetFullMethodName(Value.CustomFromMethod)).Append(@"(providers, this, source.").Append(Key).Append(")");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static string GeneratePropertyTo(string Key, string Type)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(Key).Append(@" = (").Append(Type).Append(@")this.").Append(Key);
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
public static string? GenerateCorrectToProperty(string Key, ClassToGenerate.MappableTypes Value)
|
||||||
|
{
|
||||||
|
if (!Value.CustomTo)
|
||||||
|
{
|
||||||
|
return GeneratePropertyTo(Key, Value.From);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Value.CustomToMethod == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.Append(Key).Append(" = (").Append(Value.From).Append(@")").Append(GetFullMethodName(Value.CustomToMethod)).Append(@"(providers, source, this.").Append(Key).Append(")");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string GenerateExtensionClass(ClassToGenerate classToGenerate)
|
public static string GenerateExtensionClass(ClassToGenerate classToGenerate)
|
||||||
{
|
{
|
||||||
|
|
@ -393,6 +540,7 @@ namespace AutoMapProperty
|
||||||
#nullable enable
|
#nullable enable
|
||||||
namespace ").Append(classToGenerate.Namespace).Append(@"
|
namespace ").Append(classToGenerate.Namespace).Append(@"
|
||||||
{
|
{
|
||||||
|
[System.CodeDom.Compiler.GeneratedCode(""AutoMapProperty"", ""1.0.0"")]
|
||||||
public partial ").Append(classToGenerate.SourceContainer is ClassDeclarationSyntax ? "class " : "interface ").Append(classToGenerate.Name);
|
public partial ").Append(classToGenerate.SourceContainer is ClassDeclarationSyntax ? "class " : "interface ").Append(classToGenerate.Name);
|
||||||
|
|
||||||
if (classToGenerate.SourceContainer is ClassDeclarationSyntax && !classToGenerate.SourceContainer.Modifiers.Any(x => x.IsKind(SyntaxKind.AbstractKeyword)))
|
if (classToGenerate.SourceContainer is ClassDeclarationSyntax && !classToGenerate.SourceContainer.Modifiers.Any(x => x.IsKind(SyntaxKind.AbstractKeyword)))
|
||||||
|
|
@ -411,54 +559,111 @@ namespace ").Append(classToGenerate.Namespace).Append(@"
|
||||||
public static implicit operator ").Append(classToGenerate.Name).Append(@"(").Append(classToGenerate.SourceContainer.Identifier).Append(@" source)
|
public static implicit operator ").Append(classToGenerate.Name).Append(@"(").Append(classToGenerate.SourceContainer.Identifier).Append(@" source)
|
||||||
{
|
{
|
||||||
var dat = new ").Append(classToGenerate.Name).Append(@"();
|
var dat = new ").Append(classToGenerate.Name).Append(@"();
|
||||||
dat.ApplyFrom(source);
|
return dat.ApplyFrom(null, source);
|
||||||
return dat;
|
|
||||||
}");
|
}");
|
||||||
sb.Append(@"
|
sb.Append(@"
|
||||||
public ").Append(classToGenerate.Name).Append(@" ApplyFrom(").Append(classToGenerate.SourceContainer.Identifier).Append(@" source)
|
public ").Append(classToGenerate.Name).Append(@" ApplyFrom(System.IServiceProvider providers, ").Append(classToGenerate.SourceContainer.Identifier).Append(@" source)
|
||||||
{
|
{
|
||||||
|
if(source == null)
|
||||||
|
return null;
|
||||||
{");
|
{");
|
||||||
foreach (var prop in classToGenerate.MappableProperties)
|
foreach (var prop in classToGenerate.MappableProperties)
|
||||||
{
|
{
|
||||||
if (!prop.Value.GenerateConverter)
|
var property = GenerateCorrectFromProperty(prop.Key, prop.Value);
|
||||||
|
if (property == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sb.Append(@"
|
sb.Append(@"
|
||||||
").Append(GeneratePropertyFrom(prop.Key, prop.Value)).Append(@";");
|
").Append(property).Append(@";");
|
||||||
}
|
}
|
||||||
sb.Append(@"
|
sb.Append(@"
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}");
|
}");
|
||||||
sb.Append(@"
|
sb.Append(@"
|
||||||
public System.Linq.Expressions.Expression<Func<").Append(classToGenerate.SourceContainer.Identifier).Append(", ").Append(classToGenerate.Name).Append(@">> GetProjectorFrom() => (source)=>new ").Append(classToGenerate.Name).Append(@"()
|
public System.Linq.Expressions.Expression<Func<").Append(classToGenerate.SourceContainer.Identifier).Append(", ").Append(classToGenerate.Name).Append(@">> GetProjectorFrom(System.IServiceProvider providers) => (source)=>new ").Append(classToGenerate.Name).Append(@"()
|
||||||
{");
|
{");
|
||||||
foreach (var prop in classToGenerate.MappableProperties)
|
foreach (var prop in classToGenerate.MappableProperties)
|
||||||
{
|
{
|
||||||
if (!prop.Value.GenerateConverter)
|
var property = GenerateCorrectFromProperty(prop.Key, prop.Value, false);
|
||||||
|
if (property == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sb.Append(@"
|
sb.Append(@"
|
||||||
").Append(GeneratePropertyFrom(prop.Key, prop.Value)).Append(@",");
|
").Append(property).Append(@",");
|
||||||
}
|
}
|
||||||
sb.Append(@"
|
sb.Append(@"
|
||||||
};");
|
};");
|
||||||
|
|
||||||
|
sb.Append(@"
|
||||||
|
public static System.Linq.Expressions.Expression<Func<").Append(classToGenerate.Name).Append(@", bool>> EqualExpression(System.IServiceProvider providers,").Append(classToGenerate.SourceContainer.Identifier).Append(@" item1) => (item2)=>
|
||||||
|
(");
|
||||||
|
foreach (var prop in classToGenerate.MappableProperties)
|
||||||
|
{
|
||||||
|
if (prop.Value.From != prop.Value.To)
|
||||||
|
continue;
|
||||||
|
sb.Append(@"
|
||||||
|
item1.").Append(prop.Key).Append(" == item2.").Append(prop.Key).Append(" && ");
|
||||||
|
}
|
||||||
|
sb.Append(@"true
|
||||||
|
);");
|
||||||
|
|
||||||
|
sb.Append(@"
|
||||||
|
public static System.Linq.Expressions.Expression<Func<").Append(classToGenerate.SourceContainer.Identifier).Append(@", bool>> EqualExpression(System.IServiceProvider providers,").Append(classToGenerate.Name).Append(@" item1) => (item2)=>
|
||||||
|
(");
|
||||||
|
foreach (var prop in classToGenerate.MappableProperties)
|
||||||
|
{
|
||||||
|
if (prop.Value.From != prop.Value.To)
|
||||||
|
continue;
|
||||||
|
sb.Append(@"
|
||||||
|
item1.").Append(prop.Key).Append(" == item2.").Append(prop.Key).Append(" && ");
|
||||||
|
}
|
||||||
|
sb.Append(@"true
|
||||||
|
);");
|
||||||
|
|
||||||
|
sb.Append(@"
|
||||||
|
public override bool Equals(object obj){
|
||||||
|
if(obj == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ReferenceEquals(obj, this))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (obj.GetType() != this.GetType())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
").Append(classToGenerate.Name).Append(@" other = obj as ").Append(classToGenerate.Name).Append(@";
|
||||||
|
|
||||||
|
return (");
|
||||||
|
foreach (var prop in classToGenerate.MappableProperties)
|
||||||
|
{
|
||||||
|
sb.Append(@"
|
||||||
|
this.").Append(prop.Key).Append(" == other.").Append(prop.Key).Append(" && ");
|
||||||
|
}
|
||||||
|
sb.Append(@"true
|
||||||
|
);
|
||||||
|
}");
|
||||||
|
|
||||||
var abstr = cds.Modifiers.Any(x => x.IsKind(SyntaxKind.AbstractKeyword));
|
var abstr = cds.Modifiers.Any(x => x.IsKind(SyntaxKind.AbstractKeyword));
|
||||||
if (!abstr)
|
if (!abstr)
|
||||||
{
|
{
|
||||||
|
|
||||||
sb.Append(@"
|
sb.Append(@"
|
||||||
|
|
||||||
public ").Append(classToGenerate.SourceContainer.Identifier).Append(@" ApplyTo(").Append(classToGenerate.SourceContainer.Identifier).Append(@" source)
|
public ").Append(classToGenerate.SourceContainer.Identifier).Append(@" ApplyTo(System.IServiceProvider providers, ").Append(classToGenerate.SourceContainer.Identifier).Append(@" source)
|
||||||
{
|
{
|
||||||
|
if(source == null)
|
||||||
|
return null;
|
||||||
{");
|
{");
|
||||||
foreach (var prop in classToGenerate.MappableProperties)
|
foreach (var prop in classToGenerate.MappableProperties)
|
||||||
{
|
{
|
||||||
if (!prop.Value.GenerateConverter)
|
|
||||||
continue;
|
|
||||||
if (prop.Value.FromIsReadOnly)
|
if (prop.Value.FromIsReadOnly)
|
||||||
continue;
|
continue;
|
||||||
|
var property = GenerateCorrectToProperty(prop.Key, prop.Value);
|
||||||
|
if (property == null)
|
||||||
|
continue;
|
||||||
sb.Append(@"
|
sb.Append(@"
|
||||||
source.").Append(prop.Key).Append(@" = (").Append(prop.Value.From).Append(@")this.").Append(prop.Key).Append(@";");
|
source.").Append(property).Append(@";");
|
||||||
}
|
}
|
||||||
sb.Append(@"
|
sb.Append(@"
|
||||||
}
|
}
|
||||||
|
|
@ -469,8 +674,7 @@ namespace ").Append(classToGenerate.Namespace).Append(@"
|
||||||
public static explicit operator ").Append(classToGenerate.SourceContainer.Identifier).Append(@"(").Append(classToGenerate.Name).Append(@" source)
|
public static explicit operator ").Append(classToGenerate.SourceContainer.Identifier).Append(@"(").Append(classToGenerate.Name).Append(@" source)
|
||||||
{
|
{
|
||||||
var dat = new ").Append(classToGenerate.SourceContainer.Identifier).Append(@"();
|
var dat = new ").Append(classToGenerate.SourceContainer.Identifier).Append(@"();
|
||||||
source.ApplyTo(dat);
|
return source.ApplyTo(null, dat);
|
||||||
return dat;
|
|
||||||
}");
|
}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,16 @@ namespace AutoMapPropertyHelper
|
||||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
|
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
|
||||||
public class AutoMapPropertyAttribute : System.Attribute
|
public class AutoMapPropertyAttribute : System.Attribute
|
||||||
{
|
{
|
||||||
public AutoMapPropertyAttribute(string name, Type? typeName = null, bool generateConverter = true)
|
public AutoMapPropertyAttribute(string name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public AutoMapPropertyAttribute(string name, Type? typeName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public AutoMapPropertyAttribute(string name, Type? typeName, string? customTo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public AutoMapPropertyAttribute(string name, Type? typeName, string? customTo, string? customFrom)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,8 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,16 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace AutoMapPropertyHelper
|
namespace AutoMapPropertyHelper
|
||||||
{
|
{
|
||||||
public interface IAutomappedAttribute<TSource, TSelf>
|
public interface IAutomappedAttribute<TSource, TSelf>
|
||||||
{
|
{
|
||||||
public TSource ApplyTo(TSource value);
|
public TSource ApplyTo(IServiceProvider providers, TSource value);
|
||||||
public TSelf ApplyFrom(TSource source);
|
public TSelf ApplyFrom(IServiceProvider providers, TSource source);
|
||||||
|
|
||||||
public Expression<Func<TSource, TSelf>> GetProjectorFrom();
|
public Expression<Func<TSource, TSelf>> GetProjectorFrom(IServiceProvider providers);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user