From ffeef86e671e039a958b50abe6b9f61e3fdfd794 Mon Sep 17 00:00:00 2001 From: Adolfo Marinucci Date: Tue, 2 Jan 2024 23:57:10 +0100 Subject: [PATCH] More fixes and performance improvements --- .github/workflows/build-deploy.yml | 2 +- samples/UnitTests/TestScaffoldGenerator.cs | 9 + .../ComponentTypeGenerator.cs | 73 +- .../ComponentTypeGenerator.tt | 14 +- .../ComponentPartialClassGenerator.cs | 2 +- .../ComponentPartialClassGenerator.partial.cs | 7 +- .../ComponentPartialClassGenerator.tt | 2 +- .../ComponentPartialClassSourceGenerator.cs | 43 +- src/MauiReactor/Component.cs | 6 +- src/MauiReactor/Component.partial.cs | 1050 ++++++++++++++++- src/MauiReactor/ContentPage.partial.cs | 2 +- src/MauiReactor/Grid.partial.cs | 11 +- .../HorizontalStackLayout.partial.cs | 4 +- src/MauiReactor/Label.partial.cs | 2 +- src/MauiReactor/ScrollView.partial.cs | 4 +- .../VerticalStackLayout.partial.cs | 4 +- 16 files changed, 1201 insertions(+), 34 deletions(-) diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml index bdf101ee..35e362e1 100644 --- a/.github/workflows/build-deploy.yml +++ b/.github/workflows/build-deploy.yml @@ -15,7 +15,7 @@ jobs: env: Solution_Name: ./src/MauiReactor.Build.sln TemplatePack_Name: ./src/MauiReactor.TemplatePack/MauiReactor.TemplatePack.csproj - Version: 2.0.13-beta + Version: 2.0.14-beta steps: - name: Checkout diff --git a/samples/UnitTests/TestScaffoldGenerator.cs b/samples/UnitTests/TestScaffoldGenerator.cs index 70442e5b..f2ee7fde 100644 --- a/samples/UnitTests/TestScaffoldGenerator.cs +++ b/samples/UnitTests/TestScaffoldGenerator.cs @@ -54,6 +54,9 @@ partial class MyComponent [Prop] Action? _myProp10; + + [Prop("MyTestMethod")] + int _myProp11; } """); @@ -106,6 +109,12 @@ public MyComponent MyProp10(Action? propValue) _myProp10 = propValue; return this; } + + public MyComponent MyTestMethod(int propValue) + { + _myProp11 = propValue; + return this; + } public MyComponent MyProp2(int? propValue) { diff --git a/src/MauiReactor.Scaffold/ComponentTypeGenerator.cs b/src/MauiReactor.Scaffold/ComponentTypeGenerator.cs index 20efa296..f05b07de 100644 --- a/src/MauiReactor.Scaffold/ComponentTypeGenerator.cs +++ b/src/MauiReactor.Scaffold/ComponentTypeGenerator.cs @@ -185,9 +185,80 @@ public partial class Component #line default #line hidden - this.Write(";\r\n }\r\n\r\n "); + this.Write(";\r\n }\r\n \r\n "); #line 48 "C:\Source\github\reactorui-maui\src\MauiReactor.Scaffold\ComponentTypeGenerator.tt" + if (typeof(Element).IsAssignableFrom(type)) { + + #line default + #line hidden + this.Write(" public static "); + + #line 49 "C:\Source\github\reactorui-maui\src\MauiReactor.Scaffold\ComponentTypeGenerator.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(typeName)); + + #line default + #line hidden + this.Write(" "); + + #line 49 "C:\Source\github\reactorui-maui\src\MauiReactor.Scaffold\ComponentTypeGenerator.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(type.Name)); + + #line default + #line hidden + this.Write("(Action<"); + + #line 49 "C:\Source\github\reactorui-maui\src\MauiReactor.Scaffold\ComponentTypeGenerator.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(type.FullName)); + + #line default + #line hidden + this.Write("?> componentRefAction, params VisualNode?[]? children)\r\n {\r\n var @"); + + #line 51 "C:\Source\github\reactorui-maui\src\MauiReactor.Scaffold\ComponentTypeGenerator.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(type.Name.ToLower())); + + #line default + #line hidden + this.Write(" = GetNodeFromPool<"); + + #line 51 "C:\Source\github\reactorui-maui\src\MauiReactor.Scaffold\ComponentTypeGenerator.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(typeName)); + + #line default + #line hidden + this.Write(">();\r\n @"); + + #line 52 "C:\Source\github\reactorui-maui\src\MauiReactor.Scaffold\ComponentTypeGenerator.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(type.Name.ToLower())); + + #line default + #line hidden + this.Write(".ComponentRefAction = componentRefAction;\r\n if (children != null)\r\n " + + " {\r\n @"); + + #line 55 "C:\Source\github\reactorui-maui\src\MauiReactor.Scaffold\ComponentTypeGenerator.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(type.Name.ToLower())); + + #line default + #line hidden + this.Write(".AddChildren(children);\r\n }\r\n return @"); + + #line 57 "C:\Source\github\reactorui-maui\src\MauiReactor.Scaffold\ComponentTypeGenerator.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(type.Name.ToLower())); + + #line default + #line hidden + this.Write(";\r\n }\r\n "); + + #line 59 "C:\Source\github\reactorui-maui\src\MauiReactor.Scaffold\ComponentTypeGenerator.tt" + } + + #line default + #line hidden + this.Write(" "); + + #line 60 "C:\Source\github\reactorui-maui\src\MauiReactor.Scaffold\ComponentTypeGenerator.tt" } #line default diff --git a/src/MauiReactor.Scaffold/ComponentTypeGenerator.tt b/src/MauiReactor.Scaffold/ComponentTypeGenerator.tt index 721f4b6b..40f8ab57 100644 --- a/src/MauiReactor.Scaffold/ComponentTypeGenerator.tt +++ b/src/MauiReactor.Scaffold/ComponentTypeGenerator.tt @@ -44,7 +44,19 @@ public partial class Component @<#= type.Name.ToLower() #>.ComponentRefAction = componentRefAction; return @<#= type.Name.ToLower() #>; } - + + <# if (typeof(Element).IsAssignableFrom(type)) { #> + public static <#= typeName #> <#= type.Name #>(Action<<#= type.FullName #>?> componentRefAction, params VisualNode?[]? children) + { + var @<#= type.Name.ToLower() #> = GetNodeFromPool<<#= typeName #>>(); + @<#= type.Name.ToLower() #>.ComponentRefAction = componentRefAction; + if (children != null) + { + @<#= type.Name.ToLower() #>.AddChildren(children); + } + return @<#= type.Name.ToLower() #>; + } + <# } #> <# } #> } diff --git a/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassGenerator.cs b/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassGenerator.cs index 6dcc555e..8b39bc4d 100644 --- a/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassGenerator.cs +++ b/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassGenerator.cs @@ -156,7 +156,7 @@ public virtual string TransformText() this.Write(" "); #line 30 "C:\Source\github\reactorui-maui\src\MauiReactor.ScaffoldGenerator\ComponentPartialClassGenerator.tt" - this.Write(this.ToStringHelper.ToStringWithCulture(GetPropMethodName(fieldItem.FieldName))); + this.Write(this.ToStringHelper.ToStringWithCulture(fieldItem.GetPropMethodName())); #line default #line hidden diff --git a/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassGenerator.partial.cs b/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassGenerator.partial.cs index ccf150af..46ec5eb0 100644 --- a/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassGenerator.partial.cs +++ b/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassGenerator.partial.cs @@ -24,17 +24,12 @@ public string TransformAndPrettify() return $"// {Environment.NewLine}{ret}"; } - private string GetPropMethodName(string fieldName) - { - fieldName = fieldName.TrimStart('_'); - fieldName = char.ToUpper(fieldName[0]) + fieldName.Substring(1); - return fieldName; - } private IEnumerable GetInjectFields() { return _classItem.FieldItems.Where(_ => _.Value.Type == FieldAttributeType.Inject).OrderBy(_ => _.Key).Select(_=>_.Value); } + private IEnumerable GetPropFields() { return _classItem.FieldItems.Where(_ => _.Value.Type == FieldAttributeType.Prop).OrderBy(_ => _.Key).Select(_ => _.Value); diff --git a/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassGenerator.tt b/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassGenerator.tt index 0701736f..291bcfb2 100644 --- a/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassGenerator.tt +++ b/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassGenerator.tt @@ -27,7 +27,7 @@ namespace <#= _classItem.Namespace #> <# } #> <# foreach (var fieldItem in GetPropFields()) { #> - public <#= _classItem.ClassName #> <#= GetPropMethodName(fieldItem.FieldName) #>(<#= fieldItem.FieldTypeFullyQualifiedName #> propValue) + public <#= _classItem.ClassName #> <#= fieldItem.GetPropMethodName() #>(<#= fieldItem.FieldTypeFullyQualifiedName #> propValue) { <#= fieldItem.FieldName #> = propValue; return this; diff --git a/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassSourceGenerator.cs b/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassSourceGenerator.cs index 207c1730..8acf9874 100644 --- a/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassSourceGenerator.cs +++ b/src/MauiReactor.ScaffoldGenerator/ComponentPartialClassSourceGenerator.cs @@ -20,6 +20,7 @@ public void Initialize(GeneratorInitializationContext context) { context.RegisterForPostInitialization((i) => i.AddSource("ComponentAttributes.g.cs", @"using System; +#nullable enable namespace MauiReactor { [AttributeUsage(AttributeTargets.Field)] @@ -33,7 +34,7 @@ public InjectAttribute() [AttributeUsage(AttributeTargets.Field)] internal class PropAttribute : Attribute { - public PropAttribute() + public PropAttribute(string? methodName = null) { } } @@ -118,15 +119,33 @@ void generateClassItem(FieldDeclarationSyntax fieldDeclaration, FieldAttributeTy generatingClassItems[fullyQualifiedTypeName] = generatingClassItem = new GeneratorClassItem(namespaceName, className); } - foreach (var variableFieldName in fieldDeclaration.Declaration.Variables.Select(_=>_.Identifier.ValueText)) + foreach (var variableFieldSyntax in fieldDeclaration.Declaration.Variables) { + var variableFieldName = variableFieldSyntax.Identifier.ValueText; + if (generatingClassItem.FieldItems.ContainsKey(variableFieldName)) { return; } + string? methodName = null; + if (attributeType == FieldAttributeType.Prop) + { + if (semanticModel.GetDeclaredSymbol(variableFieldSyntax) + is IFieldSymbol variableDeclaratorFieldSymbol) + { + var propAttributeData = variableDeclaratorFieldSymbol.GetAttributes() + .FirstOrDefault(_ => _.AttributeClass?.Name == "PropAttribute" || _.AttributeClass?.Name == "Prop"); + + if (propAttributeData?.ConstructorArguments.Length > 0) + { + methodName = propAttributeData.ConstructorArguments[0].Value?.ToString(); + } + } + } + generatingClassItem.FieldItems[variableFieldName] - = new GeneratorFieldItem(variableFieldName, fieldTypeFullyQualifiedName, attributeType); + = new GeneratorFieldItem(variableFieldName, fieldTypeFullyQualifiedName, attributeType, methodName); } } @@ -201,17 +220,33 @@ public GeneratorClassItem(string @namespace, string className) public class GeneratorFieldItem { - public GeneratorFieldItem(string fieldName, string fieldTypeFullyQualifiedName, FieldAttributeType type) + private readonly string? _propMethodName; + + public GeneratorFieldItem(string fieldName, string fieldTypeFullyQualifiedName, FieldAttributeType type, string? propMethodName) { FieldName = fieldName; FieldTypeFullyQualifiedName = fieldTypeFullyQualifiedName; Type = type; + _propMethodName = propMethodName; } public string FieldName { get; } + public string FieldTypeFullyQualifiedName { get; } public FieldAttributeType Type { get; } + + public string GetPropMethodName() + { + if (_propMethodName != null) + { + return _propMethodName; + } + + var fieldName = FieldName.TrimStart('_'); + fieldName = char.ToUpper(fieldName[0]) + fieldName.Substring(1); + return fieldName; + } } public enum FieldAttributeType diff --git a/src/MauiReactor/Component.cs b/src/MauiReactor/Component.cs index f7a9aa0e..e44700b0 100644 --- a/src/MauiReactor/Component.cs +++ b/src/MauiReactor/Component.cs @@ -276,7 +276,7 @@ object IComponentWithProps.Props internal override void MergeWith(VisualNode newNode) { - if (!_derivedProps && newNode is IComponentWithProps newComponentWithProps) + if (!_derivedProps && newNode != this && newNode is IComponentWithProps newComponentWithProps) { if (newNode.GetType() == GetType()) { @@ -311,7 +311,7 @@ protected Component(S? state = null, P? props = null) : base(props) { _state = state; - _derivedState = state != null; + _derivedState = state != null; } internal override void Reset() @@ -458,7 +458,7 @@ protected virtual void SetState(Action action, bool invalidateComponent = tru internal override void MergeWith(VisualNode newNode) { - if (!_derivedState && newNode is IComponentWithState newComponentWithState) + if (!_derivedState && newNode != this && newNode is IComponentWithState newComponentWithState) { _newComponent = newComponentWithState; if (newNode.GetType() == this.GetType()) diff --git a/src/MauiReactor/Component.partial.cs b/src/MauiReactor/Component.partial.cs index fdef5471..3038457c 100644 --- a/src/MauiReactor/Component.partial.cs +++ b/src/MauiReactor/Component.partial.cs @@ -31,6 +31,18 @@ public static ListView ListView(Action compon return @listview; } + public static ListView ListView(Action componentRefAction, params VisualNode? []? children) + { + var @listview = GetNodeFromPool(); + @listview.ComponentRefAction = componentRefAction; + if (children != null) + { + @listview.AddChildren(children); + } + + return @listview; + } + public static TabbedPage TabbedPage() => GetNodeFromPool(); public static TabbedPage TabbedPage(params VisualNode? []? children) { @@ -50,6 +62,18 @@ public static TabbedPage TabbedPage(Action return @tabbedpage; } + public static TabbedPage TabbedPage(Action componentRefAction, params VisualNode? []? children) + { + var @tabbedpage = GetNodeFromPool(); + @tabbedpage.ComponentRefAction = componentRefAction; + if (children != null) + { + @tabbedpage.AddChildren(children); + } + + return @tabbedpage; + } + public static Page Page() => GetNodeFromPool(); public static Page Page(params VisualNode? []? children) { @@ -69,6 +93,18 @@ public static Page Page(Action componentRefAction return @page; } + public static Page Page(Action componentRefAction, params VisualNode? []? children) + { + var @page = GetNodeFromPool(); + @page.ComponentRefAction = componentRefAction; + if (children != null) + { + @page.AddChildren(children); + } + + return @page; + } + public static TemplatedPage TemplatedPage() => GetNodeFromPool(); public static TemplatedPage TemplatedPage(params VisualNode? []? children) { @@ -88,6 +124,18 @@ public static TemplatedPage TemplatedPage(Action componentRefAction, params VisualNode? []? children) + { + var @templatedpage = GetNodeFromPool(); + @templatedpage.ComponentRefAction = componentRefAction; + if (children != null) + { + @templatedpage.AddChildren(children); + } + + return @templatedpage; + } + public static ContentPage ContentPage() => GetNodeFromPool(); public static ContentPage ContentPage(params VisualNode? []? children) { @@ -107,6 +155,18 @@ public static ContentPage ContentPage(Action componentRefAction, params VisualNode? []? children) + { + var @contentpage = GetNodeFromPool(); + @contentpage.ComponentRefAction = componentRefAction; + if (children != null) + { + @contentpage.AddChildren(children); + } + + return @contentpage; + } + public static NavigationPage NavigationPage() => GetNodeFromPool(); public static NavigationPage NavigationPage(params VisualNode? []? children) { @@ -126,6 +186,18 @@ public static NavigationPage NavigationPage(Action componentRefAction, params VisualNode? []? children) + { + var @navigationpage = GetNodeFromPool(); + @navigationpage.ComponentRefAction = componentRefAction; + if (children != null) + { + @navigationpage.AddChildren(children); + } + + return @navigationpage; + } + public static FlyoutPage FlyoutPage() => GetNodeFromPool(); public static FlyoutPage FlyoutPage(params VisualNode? []? children) { @@ -145,6 +217,18 @@ public static FlyoutPage FlyoutPage(Action return @flyoutpage; } + public static FlyoutPage FlyoutPage(Action componentRefAction, params VisualNode? []? children) + { + var @flyoutpage = GetNodeFromPool(); + @flyoutpage.ComponentRefAction = componentRefAction; + if (children != null) + { + @flyoutpage.AddChildren(children); + } + + return @flyoutpage; + } + public static Button Button() => GetNodeFromPool