Skip to content

Commit 276ec38

Browse files
committed
chore: merge development to v10.1.0 branch
2 parents bd79138 + e8d3295 commit 276ec38

11 files changed

Lines changed: 497 additions & 14 deletions

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<PropertyGroup>
33
<!-- Properties related to build/pack -->
44
<IsPackable>false</IsPackable>
5-
<Version>10.1.0-pre02</Version>
5+
<Version>10.0.13-pre02</Version>
66
<MapsterPluginsTFMs>netstandard2.0;net10.0;net9.0;net8.0</MapsterPluginsTFMs>
77
<MapsterTFMs>netstandard2.0;net10.0;net9.0;net8.0</MapsterTFMs>
88
<MapsterEFCoreTFMs>net10.0;net9.0;net8.0</MapsterEFCoreTFMs>

src/ExpressionTranslator/ExpressionTranslator.cs

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System.Linq.Expressions;
1212
using System.Reflection;
1313
using System.Runtime.CompilerServices;
14+
using System.Xml.Linq;
1415

1516
namespace ExpressionDebugger
1617
{
@@ -1268,6 +1269,88 @@ public Expression VisitLambda(LambdaExpression node, LambdaType type, string? me
12681269
}
12691270
}
12701271

1272+
public Expression VisitLambdaForGenerateMappers(LambdaExpression node, LambdaType type, Type InterfaceType, string? methodName = null,
1273+
bool isInternal = false)
1274+
{
1275+
VisitLambda(node, type, methodName, isInternal);
1276+
1277+
if (!isInternal)
1278+
isInternal = node.ReturnType.GetTypeInfo().IsNotPublic ||
1279+
node.Parameters.Any(it => it.Type.GetTypeInfo().IsNotPublic);
1280+
1281+
if(!isInternal)
1282+
return node; // skip create interface implimentation if public only
1283+
1284+
if (type == LambdaType.PrivateLambda || type == LambdaType.PublicLambda)
1285+
{
1286+
_inlineCount++;
1287+
if (type == LambdaType.PublicLambda)
1288+
{
1289+
var name = methodName != null ? $"{InterfaceType.FullName}.{methodName}" : "Main";
1290+
WriteLine();
1291+
var funcType = MakeDelegateType(node.ReturnType, node.Parameters.Select(it => it.Type).ToArray());
1292+
var exprType = typeof(Expression<>).MakeGenericType(funcType);
1293+
Write(Translate(exprType), " ", name, " => ");
1294+
}
1295+
1296+
IList<ParameterExpression> args;
1297+
if (node.Parameters.Count == 1)
1298+
{
1299+
args = new List<ParameterExpression>();
1300+
var arg = VisitParameter(node.Parameters[0]);
1301+
args.Add((ParameterExpression)arg);
1302+
}
1303+
else
1304+
{
1305+
args = VisitArguments("(", node.Parameters.ToList(), p => (ParameterExpression)VisitParameter(p),
1306+
")");
1307+
}
1308+
1309+
Write(" => ");
1310+
var body = VisitGroup(node.Body, ExpressionType.Quote);
1311+
if (type == LambdaType.PublicLambda)
1312+
Write(";");
1313+
_inlineCount--;
1314+
return Expression.Lambda(body, node.Name, node.TailCall, args);
1315+
}
1316+
else
1317+
{
1318+
var name = methodName != null ? $"{InterfaceType.FullName}.{methodName}" : "Main";
1319+
if (type == LambdaType.PublicMethod || type == LambdaType.ExtensionMethod)
1320+
{
1321+
if (!isInternal)
1322+
isInternal = node.ReturnType.GetTypeInfo().IsNotPublic ||
1323+
node.Parameters.Any(it => it.Type.GetTypeInfo().IsNotPublic);
1324+
WriteLine();
1325+
Methods[name] = node.Type;
1326+
}
1327+
else
1328+
{
1329+
name = GetName(node, name);
1330+
WriteModifierNextLine("private");
1331+
}
1332+
1333+
Write(Translate(node.ReturnType), " ", name);
1334+
var open = "(";
1335+
if (type == LambdaType.ExtensionMethod)
1336+
{
1337+
if (Definitions?.IsStatic != true)
1338+
throw new InvalidOperationException("Extension method requires static class");
1339+
if (node.Parameters.Count == 0)
1340+
throw new InvalidOperationException("Extension method requires at least 1 parameter");
1341+
open = "(this ";
1342+
}
1343+
1344+
var args = VisitArguments(open, node.Parameters, VisitParameterDeclaration, ")");
1345+
Indent();
1346+
var body = VisitBody(node.Body, true);
1347+
1348+
Outdent();
1349+
1350+
return Expression.Lambda(body, name, node.TailCall, args);
1351+
}
1352+
}
1353+
12711354
private HashSet<LambdaExpression>? _visitedLambda;
12721355
private int _writerLevel;
12731356

@@ -1865,9 +1948,16 @@ public override string ToString()
18651948
WriteNextLine("using ", ns, ";");
18661949
}
18671950

1868-
WriteLine();
18691951
}
18701952

1953+
foreach (var ns in Definitions.GeneratedAttributes.Select(x => x.NameSpace).Distinct())
1954+
{
1955+
WriteNextLine("using ", ns, ";");
1956+
}
1957+
1958+
if(_usings != null || Definitions.GeneratedAttributes.Count != 0)
1959+
WriteLine();
1960+
18711961
// NOTE: type alias cannot solve all name conflicted case, user should use PrintFullTypeName
18721962
// keep logic here for compatibility
18731963
if (_typeNames != null)
@@ -1891,6 +1981,11 @@ public override string ToString()
18911981
Indent();
18921982
}
18931983

1984+
foreach (var gAttr in Definitions.GeneratedAttributes)
1985+
{
1986+
WriteNextLine(gAttr.Implimentation);
1987+
}
1988+
18941989
var isInternal = Definitions.IsInternal;
18951990
if (!isInternal)
18961991
isInternal = Definitions.Implements?.Any(it =>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace ExpressionDebugger.Helpers.GeneratedAttributes
2+
{
3+
public interface IGeneratedAttribute
4+
{
5+
public string NameSpace { get;}
6+
public string Declaration { get;}
7+
public string Implimentation { get; }
8+
public string FileName { get;}
9+
10+
}
11+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Text;
3+
using static ExpressionDebugger.Helpers.RandomNamespaceGenerator;
4+
5+
namespace ExpressionDebugger.Helpers.GeneratedAttributes
6+
{
7+
public class MapsterToolGeneratedMapperAttribute : GeneratedBase, IGeneratedAttribute
8+
{
9+
private readonly StringBuilder _Declaration;
10+
private readonly string _NameSpace;
11+
12+
public string NameSpace => _NameSpace;
13+
14+
public string Declaration => _Declaration.ToString();
15+
16+
public string Implimentation => "[MapsterToolGeneratedMapper]";
17+
18+
public string FileName => "MapsterToolGeneratedMapperAttribute";
19+
20+
public MapsterToolGeneratedMapperAttribute(string extendedNameSpace)
21+
{
22+
if (String.IsNullOrEmpty(extendedNameSpace))
23+
throw new ArgumentNullException("Extended namespace not specified or is null/empty string");
24+
25+
if(CheckNameSpace.IsMatch(extendedNameSpace))
26+
_NameSpace = $"Mapster.Generated.Attributes.{extendedNameSpace}";
27+
else
28+
_NameSpace = $"Mapster.Generated.Attributes.{Generate(extendedNameSpace,1,1)}";
29+
30+
_Declaration = new StringBuilder();
31+
32+
_Declaration.Append("using System;\r\n\r\n");
33+
_Declaration.Append($"namespace {NameSpace}");
34+
_Declaration.Append("\r\n{\r\n public sealed class MapsterToolGeneratedMapperAttribute : Attribute\r\n {\r\n\r\n }\r\n} ");
35+
}
36+
37+
}
38+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace ExpressionDebugger.Helpers
2+
{
3+
public abstract class GeneratedBase
4+
{
5+
public override bool Equals(object obj)
6+
{
7+
if(obj is null)
8+
return base.Equals(obj);
9+
else
10+
return this.GetType() == obj.GetType();
11+
}
12+
13+
public override int GetHashCode()
14+
{
15+
return this.GetType().GetHashCode();
16+
}
17+
}
18+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Reflection;
3+
4+
namespace ExpressionDebugger.Helpers
5+
{
6+
public static class MemberInfoExtensions
7+
{
8+
public static bool IsPublicOrInternal(this MethodInfo method)
9+
{
10+
if (method == null) throw new ArgumentNullException(nameof(method));
11+
12+
return !method.IsPrivate
13+
&& !method.IsFamily
14+
&& !method.IsFamilyOrAssembly
15+
&& !method.IsFamilyAndAssembly
16+
&& (method.IsPublic || true);
17+
}
18+
19+
20+
21+
public static bool IsGetterPublicOrInternal(this PropertyInfo property)
22+
{
23+
if (property == null) throw new ArgumentNullException(nameof(property));
24+
25+
MethodInfo? getMethod = property.GetMethod;
26+
27+
if (getMethod == null) return false;
28+
29+
return getMethod.IsPublicOrInternal();
30+
}
31+
}
32+
33+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System;
2+
using System.Security.Cryptography;
3+
using System.Text;
4+
using System.Text.RegularExpressions;
5+
6+
namespace ExpressionDebugger.Helpers
7+
{
8+
public static class RandomNamespaceGenerator
9+
{
10+
public static readonly Regex CheckNameSpace = new Regex(@"^([a-zA-Z_]\w*)(\.[a-zA-Z_]\w*)*$", RegexOptions.Compiled | RegexOptions.CultureInvariant);
11+
private const string Consonants = "bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ";
12+
private const string Vowels = "aeiouAEIOU";
13+
private const string Digits = "0123456789";
14+
15+
public static string Generate(string input, int minParts = 2, int maxParts = 4)
16+
{
17+
if (string.IsNullOrEmpty(input)) throw new ArgumentException("Input cannot be empty.");
18+
if (minParts < 1) minParts = 1;
19+
if (maxParts < minParts) maxParts = minParts;
20+
21+
using var sha256 = SHA256.Create();
22+
byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(input));
23+
24+
long seed = BitConverter.ToInt64(hashBytes, 0);
25+
var random = new Random(unchecked((int)seed ^ (int)(seed >> 32)));
26+
27+
int partsCount = random.Next(minParts, maxParts + 1);
28+
var sb = new StringBuilder();
29+
30+
for (int i = 0; i < partsCount; i++)
31+
{
32+
if (i > 0) sb.Append('.');
33+
sb.Append(GeneratePart(random));
34+
}
35+
36+
return sb.ToString();
37+
}
38+
39+
40+
public static string Generate(int minParts = 2, int maxParts = 4)
41+
{
42+
if (minParts < 1) minParts = 1;
43+
if (maxParts < minParts) maxParts = minParts;
44+
45+
var _random = new Random();
46+
47+
int partsCount = _random.Next(minParts, maxParts + 1);
48+
var sb = new StringBuilder();
49+
50+
for (int i = 0; i < partsCount; i++)
51+
{
52+
if (i > 0) sb.Append('.');
53+
sb.Append(GeneratePart(_random));
54+
}
55+
56+
return sb.ToString();
57+
}
58+
59+
private static string GeneratePart(Random random, int minLength = 2, int maxLength = 10)
60+
{
61+
if (minLength < 1) minLength = 1;
62+
if (maxLength < minLength) maxLength = minLength;
63+
64+
int length = random.Next(minLength, maxLength + 1);
65+
var sb = new StringBuilder(length);
66+
67+
sb.Append(Consonants[random.Next(Consonants.Length)]);
68+
69+
for (int i = 1; i < length; i++)
70+
{
71+
string pool = (i % 2 == 0) ? Vowels : Consonants;
72+
if (random.NextDouble() < 0.1) pool = Digits;
73+
sb.Append(pool[random.Next(pool.Length)]);
74+
}
75+
76+
return sb.ToString();
77+
}
78+
}
79+
}
80+

src/ExpressionTranslator/TypeDefinitions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using ExpressionDebugger.Helpers.GeneratedAttributes;
2+
using System;
23
using System.Collections.Generic;
34

45
namespace ExpressionDebugger
@@ -12,6 +13,7 @@ public class TypeDefinitions
1213
public IEnumerable<Type>? Implements { get; set; }
1314
public bool PrintFullTypeName { get; set; }
1415
public bool IsRecordType { get; set; }
16+
public HashSet<IGeneratedAttribute> GeneratedAttributes { get; set; } = new HashSet<IGeneratedAttribute>();
1517

1618
/// <summary>
1719
/// Set to 2 to mark all properties as nullable

src/Mapster.Tool/MapperOptions.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ public class MapperOptions
2828
[Option('N', "nullableDirective", Required = false, HelpText = "Set true to add \"#nullable enable\" to the top of generated mapper files")]
2929
public bool GenerateNullableDirective { get; set; }
3030

31+
[Option('h', "helpersCreate", Required = false, HelpText = "Generate helpers features")]
32+
public bool CreateHelpers { get; set; }
33+
34+
[Option('H', "helpersNamespace", Required = false, HelpText = "Specify additional namespace to generated helpers features")]
35+
public string? HelpersNamespace { get; set; }
36+
37+
3138
[Usage(ApplicationAlias = "dotnet mapster mapper")]
3239
public static IEnumerable<Example> Examples =>
3340
new List<Example>

0 commit comments

Comments
 (0)