From accda3dba015f5f19b6fa0d14f071398f01ff458 Mon Sep 17 00:00:00 2001 From: Frank Bakker Date: Thu, 26 Jan 2023 21:10:20 +0100 Subject: [PATCH] - Fix overwrite existing json file. - Only escape parameter names when needed. --- .../CodeGeneration/ServiceArguments.cs | 22 +++++++-- .../CodeGeneration/SyntaxFactoryHelper.cs | 2 +- .../Controller.cs | 2 +- .../CodeGenerator/ServicesGeneratorTest.cs | 46 +++++++++++++++++++ 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServiceArguments.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServiceArguments.cs index e7c1059c9..81fd9f048 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServiceArguments.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ServiceArguments.cs @@ -1,4 +1,6 @@ -namespace NetDaemon.HassModel.CodeGenerator; +using Microsoft.CodeAnalysis.CSharp; + +namespace NetDaemon.HassModel.CodeGenerator; internal record ServiceArgument { @@ -14,9 +16,10 @@ internal record ServiceArgument public string PropertyName => HaName.ToNormalizedPascalCase(); - public string VariableName => HaName.ToNormalizedCamelCase(); + public string ParameterName => HaName.ToNormalizedCamelCase(); - public string ParameterVariableName => Required ? VariableName : $"{VariableName} = null"; + + public string ParameterDefault => Required ? "" : " = null"; } internal class ServiceArguments @@ -49,15 +52,24 @@ public string GetParametersList() { var argumentList = Arguments.OrderByDescending(arg => arg.Required); - var anonymousVariableStr = argumentList.Select(x => $"{x.ParameterTypeName} @{x.ParameterVariableName}"); + var anonymousVariableStr = argumentList.Select(x => $"{x.ParameterTypeName} {EscapeIfRequired(x.ParameterName)}{x.ParameterDefault}"); return $"{string.Join(", ", anonymousVariableStr)}"; } public string GetNewServiceArgumentsTypeExpression() { - var propertyInitializers = Arguments.Select(x => $"{x.PropertyName} = @{x.VariableName}"); + var propertyInitializers = Arguments.Select(x => $"{x.PropertyName} = {EscapeIfRequired(x.ParameterName)}"); return $"new {TypeName} {{ { string.Join(", ", propertyInitializers) } }}"; } + + private static string EscapeIfRequired(string name) + { + var match = SyntaxFacts.GetKeywordKind(name) != SyntaxKind.None || + SyntaxFacts.GetContextualKeywordKind(name) != SyntaxKind.None; + + return match ? "@" + name : name; + } + } \ No newline at end of file diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/SyntaxFactoryHelper.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/SyntaxFactoryHelper.cs index 83c081b5f..34898e89c 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/SyntaxFactoryHelper.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/SyntaxFactoryHelper.cs @@ -77,7 +77,7 @@ public static T WithSummaryComment(this T node, string? summary) where T : S string.IsNullOrWhiteSpace(summary) ? node : node.WithLeadingTrivia(Comment($"///{summary.ReplaceLineEndings(" ")}")); public static T AppendParameterComments(this T node, ServiceArguments arguments) where T : SyntaxNode - => node.WithLeadingTrivia(node.GetLeadingTrivia().Concat(arguments.Arguments.Select(a => ParameterComment(a.VariableName, a.Comment)))); + => node.WithLeadingTrivia(node.GetLeadingTrivia().Concat(arguments.Arguments.Select(a => ParameterComment(a.ParameterName, a.Comment)))); public static T AppendParameterComment(this T node, string? name, string? description) where T : SyntaxNode diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/Controller.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/Controller.cs index 5b194602d..876fadcae 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/Controller.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/Controller.cs @@ -57,7 +57,7 @@ private async Task Save(T merged, string fileName) { Directory.CreateDirectory(OutputFolder); - var fileStream = File.OpenWrite(fileName); + var fileStream = File.Create(fileName); await using var _ = fileStream.ConfigureAwait(false); await JsonSerializer.SerializeAsync(fileStream, merged, JsonSerializerOptions).ConfigureAwait(false); } diff --git a/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs b/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs index 676b09a7e..eee7864a0 100644 --- a/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs +++ b/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs @@ -162,5 +162,51 @@ public void Run(Entities entities, Services services) CodeGenTestHelper.AssertCodeCompiles(code.ToString(), appCode); } + + + [Fact] + public void TestServiceWithKeyWordFieldName_ParamEscaped() + { + var readOnlyCollection = new HassState[] { + new() { EntityId = "light.light1" }, + }; + + var hassServiceDomains = new HassServiceDomain[] { + new() { + Domain = "light", + Services = new HassService[] { + new() { + Service = "set_value", + Target = new TargetSelector { + Entity = new() { Domain = new [] {"light"} } + }, + Fields = new HassServiceField[] { + new() { Field = "class", Selector = new NumberSelector(), }, + }, + } + } + } + }; + + // 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(Entities entities, Services services) + { + entities.Light.Light1.SetValue(@class:2); + services.Light.SetValue(new ServiceTarget(), @class:2); + } + } + """; + + CodeGenTestHelper.AssertCodeCompiles(code.ToString(), appCode); + } } \ No newline at end of file