Add factory method.

This commit is contained in:
Mohammadreza Taikandi 2020-12-19 08:08:19 +00:00
parent f607df6312
commit 1f517dd196
3 changed files with 93 additions and 38 deletions

View File

@ -0,0 +1,33 @@
using System;
using System.Text;
namespace MapTo.Extensions
{
internal static class StringBuilderExtensions
{
public static StringBuilder PadLeft(this StringBuilder builder, int width)
{
for (var i = 0; i < width; i++)
{
builder.Append(" ");
}
return builder;
}
internal static StringBuilder AppendOpeningBracket(this StringBuilder builder, int indent = 0)
{
return builder.AppendLine().PadLeft(indent).AppendFormat("{{{0}", Environment.NewLine);
}
internal static StringBuilder AppendClosingBracket(this StringBuilder builder, int indent = 0, bool padNewLine = true)
{
if (padNewLine)
{
builder.AppendLine();
}
return builder.PadLeft(indent).Append("}");
}
}
}

View File

@ -45,9 +45,12 @@ namespace MapTo
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
// Namespace declaration
builder builder
.AppendFileHeader() .AppendFileHeader()
.GenerateUsings();
// Namespace declaration
builder
.AppendFormat("namespace {0}", model.Namespace) .AppendFormat("namespace {0}", model.Namespace)
.AppendOpeningBracket(); .AppendOpeningBracket();
@ -57,8 +60,11 @@ namespace MapTo
.AppendFormat("{0} class {1}", model.ClassModifiers, model.ClassName) .AppendFormat("{0} class {1}", model.ClassModifiers, model.ClassName)
.AppendOpeningBracket(Indent1); .AppendOpeningBracket(Indent1);
// Constructor declaration // Class body
builder.GenerateConstructor(model, out var mappedProperties); builder
.GenerateConstructor(model, out var mappedProperties)
.AppendLine()
.GenerateFactoryMethod(model);
// End class declaration // End class declaration
builder.AppendClosingBracket(Indent1); builder.AppendClosingBracket(Indent1);
@ -69,6 +75,13 @@ namespace MapTo
return (builder.ToString(), $"{model.ClassName}.cs"); return (builder.ToString(), $"{model.ClassName}.cs");
} }
private static StringBuilder GenerateUsings(this StringBuilder builder)
{
return builder
.AppendLine("using System;")
.AppendLine();
}
private static StringBuilder GenerateConstructor(this StringBuilder builder, MapModel model, out List<IPropertySymbol> mappedProperties) private static StringBuilder GenerateConstructor(this StringBuilder builder, MapModel model, out List<IPropertySymbol> mappedProperties)
{ {
var destinationClassParameterName = model.DestinationClassName.ToCamelCase(); var destinationClassParameterName = model.DestinationClassName.ToCamelCase();
@ -76,7 +89,10 @@ namespace MapTo
builder builder
.PadLeft(Indent2) .PadLeft(Indent2)
.AppendFormat("public {0}({1} {2})", model.ClassName, model.DestinationClassName, destinationClassParameterName) .AppendFormat("public {0}({1} {2})", model.ClassName, model.DestinationClassName, destinationClassParameterName)
.AppendOpeningBracket(Indent2); .AppendOpeningBracket(Indent2)
.PadLeft(Indent3)
.AppendFormat("if ({0} == null) throw new ArgumentNullException(nameof({0}));", destinationClassParameterName)
.AppendLine();
mappedProperties = new List<IPropertySymbol>(); mappedProperties = new List<IPropertySymbol>();
foreach (var propertySymbol in model.DestinationTypeProperties) foreach (var propertySymbol in model.DestinationTypeProperties)
@ -94,41 +110,24 @@ namespace MapTo
return builder.AppendClosingBracket(Indent2, padNewLine: false); return builder.AppendClosingBracket(Indent2, padNewLine: false);
} }
private static StringBuilder AppendOpeningBracket(this StringBuilder builder, int indent = 0) private static StringBuilder GenerateFactoryMethod(this StringBuilder builder, MapModel model)
{ {
return builder.AppendLine().PadLeft(indent).AppendFormat("{{{0}", Environment.NewLine); var destinationClassParameterName = model.DestinationClassName.ToCamelCase();
}
private static StringBuilder AppendClosingBracket(this StringBuilder builder, int indent = 0, bool padNewLine = true) return builder
{ .AppendLine()
if (padNewLine) .PadLeft(Indent2)
{ .AppendFormat("public static {0} From({1} {2})", model.ClassName, model.DestinationClassName, destinationClassParameterName)
builder.AppendLine(); .AppendOpeningBracket(Indent2)
} .PadLeft(Indent3)
.AppendFormat("return {0} == null ? null : new {1}({0});", destinationClassParameterName, model.ClassName )
return builder.PadLeft(indent).Append("}"); .AppendClosingBracket(Indent2);
}
private static StringBuilder PadLeft(this StringBuilder builder, int width)
{
for (var i = 0; i < width; i++)
{
builder.Append(" ");
}
return builder;
} }
private static StringBuilder AppendFileHeader(this StringBuilder builder) private static StringBuilder AppendFileHeader(this StringBuilder builder)
{ {
return builder return builder
.AppendLine("// <auto-generated />") .AppendLine("// <auto-generated />");
.AppendLine();
}
private static string GetValueText(this NameSyntax? nameSyntax)
{
return (nameSyntax as IdentifierNameSyntax)?.Identifier.ValueText ?? string.Empty;
} }
} }
} }

View File

@ -84,6 +84,7 @@ namespace Test
const string expectedResult = @" const string expectedResult = @"
// <auto-generated /> // <auto-generated />
using System;
namespace Test namespace Test
{ {
@ -91,9 +92,8 @@ namespace Test
{ {
public Foo(Baz baz) public Foo(Baz baz)
{ {
if (baz == null) throw new ArgumentNullException(nameof(baz));
} }
}
}
"; ";
// Act // Act
@ -102,7 +102,7 @@ namespace Test
// Assert // Assert
diagnostics.ShouldBeSuccessful(); diagnostics.ShouldBeSuccessful();
compilation.SyntaxTrees.Count().ShouldBe(3); compilation.SyntaxTrees.Count().ShouldBe(3);
compilation.SyntaxTrees.Last().ToString().ShouldBe(expectedResult.Trim()); compilation.SyntaxTrees.Last().ToString().ShouldStartWith(expectedResult.Trim());
} }
[Fact] [Fact]
@ -127,6 +127,7 @@ namespace Test
const string expectedResult = @" const string expectedResult = @"
// <auto-generated /> // <auto-generated />
using System;
namespace Test namespace Test
{ {
@ -134,9 +135,8 @@ namespace Test
{ {
public Foo(Baz baz) public Foo(Baz baz)
{ {
if (baz == null) throw new ArgumentNullException(nameof(baz));
} }
}
}
"; ";
// Act // Act
@ -145,7 +145,7 @@ namespace Test
// Assert // Assert
diagnostics.ShouldBeSuccessful(); diagnostics.ShouldBeSuccessful();
compilation.SyntaxTrees.Count().ShouldBe(3); compilation.SyntaxTrees.Count().ShouldBe(3);
compilation.SyntaxTrees.Last().ToString().ShouldBe(expectedResult.Trim()); compilation.SyntaxTrees.Last().ToString().ShouldStartWith(expectedResult.Trim());
} }
[Fact] [Fact]
@ -159,6 +159,7 @@ namespace Test
{ {
public Foo(Baz baz) public Foo(Baz baz)
{ {
if (baz == null) throw new ArgumentNullException(nameof(baz));
Prop1 = baz.Prop1; Prop1 = baz.Prop1;
Prop2 = baz.Prop2; Prop2 = baz.Prop2;
Prop3 = baz.Prop3; Prop3 = baz.Prop3;
@ -173,6 +174,28 @@ namespace Test
compilation.SyntaxTrees.Count().ShouldBe(3); compilation.SyntaxTrees.Count().ShouldBe(3);
compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedResult.Trim()); compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedResult.Trim());
} }
[Fact]
public void When_SourceTypeHasMatchingProperties_Should_CreateFromStaticMethod()
{
// Arrange
var source = GetSourceText();
const string expectedResult = @"
public static Foo From(Baz baz)
{
return baz == null ? null : new Foo(baz);
}
";
// Act
var (compilation, diagnostics) = CSharpGenerator.GetOutputCompilation(source);
// Assert
diagnostics.ShouldBeSuccessful();
compilation.SyntaxTrees.Count().ShouldBe(3);
compilation.SyntaxTrees.Last().ToString().ShouldContain(expectedResult.Trim());
}
private static string GetSourceText(bool includeAttributeNamespace = false) private static string GetSourceText(bool includeAttributeNamespace = false)
{ {