From b1f5b2208eebfcd3cc6047d80b86c2af283e4e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20Hellstr=C3=B6m?= Date: Tue, 7 May 2024 13:45:19 +0200 Subject: [PATCH 1/7] Added a way to send data to generated service call extensions for missing metadata --- .../CodeGeneration/ExtensionMethodsGenerator.cs | 4 ++-- .../CodeGeneration/Generator.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs index 9c00449fc..a4e9af7a6 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs @@ -85,9 +85,9 @@ private static IEnumerable GenerateExtensionMethodsForS private static MemberDeclarationSyntax ExtensionMethodWithoutArguments(HassService service, string serviceName, string entityTypeName) { return ParseMemberDeclaration($$""" - public static void {{GetServiceMethodName(serviceName)}}(this {{entityTypeName}} target) + public static void {{GetServiceMethodName(serviceName)}}(this {{entityTypeName}} target, object? data = null) { - target.CallService("{{serviceName}}"); + target.CallService("{{serviceName}}", data); } """)! .WithSummaryComment(service.Description); diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/Generator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/Generator.cs index aada7a154..a422a0d06 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/Generator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/Generator.cs @@ -53,7 +53,7 @@ private static SyntaxTrivia[] GetFileHeader() // In the template projects we provided a convenience powershell script that will update // the codegen and nugets to latest versions update_all_dependencies.ps1. // - // For more information: https://netdaemon.xyz/docs/v3/hass_model/hass_model_codegen + // For more information: https://netdaemon.xyz/docs/user/hass_model/hass_model_codegen // For more information about NetDaemon: https://netdaemon.xyz/ // //------------------------------------------------------------------------------"; From aaf85ea1806cfeb598b6fcd4f993ac91a8e21aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20Hellstr=C3=B6m?= Date: Tue, 7 May 2024 13:48:09 +0200 Subject: [PATCH 2/7] Add all generated files in .gitignore --- .gitignore | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 639feac6c..fa58a5919 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ codecover_merged.info # User-specific files .idea/ appsettings.Development.json +appsettings.development.json **/core @@ -62,4 +63,9 @@ appsettings.Development.json # remove HA integration test files from git tests/Integration/HA/config/* -!tests/Integration/HA/config/*.yaml \ No newline at end of file +!tests/Integration/HA/config/*.yaml + +# remove codegenerated files +HomeAssistantGenerated.cs +EntityMetaData.json +ServicesMetaData.json From e61dee2aa8ae246f77142a9d0cff22937f3f8036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20Hellstr=C3=B6m?= Date: Tue, 7 May 2024 14:58:49 +0200 Subject: [PATCH 3/7] Add the optional data parameters to service declarations too for services without metadata --- .../CodeGeneration/ServicesGenerator.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs index e0bb5cee4..e885b0706 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs @@ -97,6 +97,8 @@ private static IEnumerable GenerateServiceMethod(string if (serviceArguments is null) { + targetParam = "object? data"; + targetArg = "null, data"; // method without arguments yield return ParseMemberDeclaration($$""" void {{serviceMethodName}}({{targetParam}}) From fe15b06edd472cf6aa8ee21d3799b694053fdcf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20Hellstr=C3=B6m?= Date: Tue, 7 May 2024 17:47:36 +0200 Subject: [PATCH 4/7] Fix test and bug found when doint tests :) --- .../CodeGeneration/ServicesGenerator.cs | 9 ++- .../CodeGenerator/ServicesGeneratorTest.cs | 55 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs index e885b0706..5e51422aa 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs @@ -97,7 +97,14 @@ private static IEnumerable GenerateServiceMethod(string if (serviceArguments is null) { - targetParam = "object? data"; + if (service.Target is not null) + { + targetParam = $"{targetParam}, object? data = null"; + } + else + { + targetParam = "object? data = null"; + } targetArg = "null, data"; // method without arguments yield return ParseMemberDeclaration($$""" diff --git a/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs b/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs index 3daa35de8..cf2721d7a 100644 --- a/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs +++ b/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs @@ -82,6 +82,61 @@ public void Run(IHaContext ha) CodeGenTestHelper.AssertCodeCompiles(code.ToString(), appCode); } + [Fact] + public void TestServicesGenerationWithAndWithoutProvidingDataForServicesWithoutTargetOrFields() + { + var readOnlyCollection = new HassState[] { + new() { EntityId = "script.script1" }, + }; + + var hassServiceDomains = new HassServiceDomain[] { + new() { + Domain = "script", + Services = [ + new() { + Service = "turn_off", + Target = new TargetSelector + { + Entity = [new EntitySelector { Domain = ["script"] }] + } + + }, + ] + } + }; + + // Act: + var code = CodeGenTestHelper.GenerateCompilationUnit(_settings, readOnlyCollection, hassServiceDomains); + + var appCode = """ + using NetDaemon.HassModel; + using NetDaemon.HassModel.Entities; + using RootNameSpace; + + public class Root + { + public void Run(IHaContext ha) + { + var s = new RootNameSpace.Services(ha); + + s.Script.TurnOff(new ServiceTarget()); + s.Script.TurnOff(new ServiceTarget(), new { }); + + ScriptEntity script = new RootNameSpace.ScriptEntity(ha, "script.testScript"); + + script.TurnOff(new { }); + script.TurnOff(); + + IScriptEntityCore scriptCore = script; + scriptCore.TurnOff(); + scriptCore.TurnOff(new { }); + } + } + """; + + CodeGenTestHelper.AssertCodeCompiles(code.ToString(), appCode); + } + [Fact] public void TestServiceWithoutAnyTargetEntity_ExtensionMethodSkipped() { From 712d00c348500c565abe15b2b307bd183fd08f9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20Hellstr=C3=B6m?= Date: Tue, 7 May 2024 18:03:20 +0200 Subject: [PATCH 5/7] Added a non target cast to the test --- .../CodeGenerator/ServicesGeneratorTest.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs b/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs index cf2721d7a..75b8fa5c4 100644 --- a/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs +++ b/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs @@ -101,6 +101,9 @@ public void TestServicesGenerationWithAndWithoutProvidingDataForServicesWithoutT } }, + new() { + Service = "reload", + }, ] } }; @@ -122,6 +125,9 @@ public void Run(IHaContext ha) s.Script.TurnOff(new ServiceTarget()); s.Script.TurnOff(new ServiceTarget(), new { }); + s.Script.Reload(); + s.Script.Reload(new { }); + ScriptEntity script = new RootNameSpace.ScriptEntity(ha, "script.testScript"); script.TurnOff(new { }); From e96034f76bb3538d3ec884d15452bd05dd3908d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20Hellstr=C3=B6m?= Date: Tue, 7 May 2024 18:13:25 +0200 Subject: [PATCH 6/7] Fix for the target to get passed too --- .../CodeGeneration/ServicesGenerator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs index 5e51422aa..8425b12a7 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs @@ -100,12 +100,13 @@ private static IEnumerable GenerateServiceMethod(string if (service.Target is not null) { targetParam = $"{targetParam}, object? data = null"; + targetArg = "target, data"; } else { targetParam = "object? data = null"; + targetArg = "null, data"; } - targetArg = "null, data"; // method without arguments yield return ParseMemberDeclaration($$""" void {{serviceMethodName}}({{targetParam}}) From efd030af7dfca11efa680defd6890620d717db66 Mon Sep 17 00:00:00 2001 From: Frank Bakker Date: Tue, 7 May 2024 22:32:03 +0200 Subject: [PATCH 7/7] Small refactor using helper method to join arguments --- .../CodeGeneration/ServicesGenerator.cs | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs index 8425b12a7..73a75002a 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServicesGenerator.cs @@ -97,21 +97,11 @@ private static IEnumerable GenerateServiceMethod(string if (serviceArguments is null) { - if (service.Target is not null) - { - targetParam = $"{targetParam}, object? data = null"; - targetArg = "target, data"; - } - else - { - targetParam = "object? data = null"; - targetArg = "null, data"; - } // method without arguments yield return ParseMemberDeclaration($$""" - void {{serviceMethodName}}({{targetParam}}) + void {{serviceMethodName}}({{CommaSeparateNonEmpty(targetParam, "object? data = null")}}) { - {{haContextVariableName}}.CallService("{{domain}}", "{{serviceName}}", {{targetArg}}); + {{haContextVariableName}}.CallService("{{domain}}", "{{serviceName}}", {{CommaSeparateNonEmpty(targetArg, "data")}}); } """)! .ToPublic() @@ -122,7 +112,7 @@ private static IEnumerable GenerateServiceMethod(string { // method using arguments object yield return ParseMemberDeclaration($$""" - void {{serviceMethodName}}({{JoinList(targetParam, serviceArguments.TypeName)}} data) + void {{serviceMethodName}}({{CommaSeparateNonEmpty(targetParam, serviceArguments.TypeName)}} data) { {{haContextVariableName}}.CallService("{{domain}}", "{{serviceName}}", {{targetArg}}, data); } @@ -133,7 +123,7 @@ private static IEnumerable GenerateServiceMethod(string // method using arguments as separate parameters yield return ParseMemberDeclaration($$""" - void {{serviceMethodName}}({{JoinList(targetParam, serviceArguments.GetParametersList())}}) + void {{serviceMethodName}}({{CommaSeparateNonEmpty(targetParam, serviceArguments.GetParametersList())}}) { {{haContextVariableName}}.CallService("{{domain}}", "{{serviceName}}", {{targetArg}}, {{serviceArguments.GetNewServiceArgumentsTypeExpression()}}); } @@ -145,5 +135,5 @@ private static IEnumerable GenerateServiceMethod(string } } - private static string JoinList(params string?[] args) => string.Join(", ", args.Where(s => !string.IsNullOrEmpty(s))); + private static string CommaSeparateNonEmpty(params string?[] args) => string.Join(", ", args.Where(s => !string.IsNullOrEmpty(s))); }