From d4f82bf04d162cd574dd31cdf00bf2d0104357a8 Mon Sep 17 00:00:00 2001 From: Marcos Pereira Date: Fri, 19 Jan 2024 02:49:24 -0500 Subject: [PATCH] kte: Fix parameter declaration for generated templates (#319) * kte: Fix parameter declaration for generated templates * Some minor clean ups --- .../compiler/kotlin/KotlinCodeGenerator.java | 31 +++++++++++---- .../gg/jte/kotlin/TemplateEngineTest.java | 39 +++++++++++++++++++ 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/jte-kotlin/src/main/java/gg/jte/compiler/kotlin/KotlinCodeGenerator.java b/jte-kotlin/src/main/java/gg/jte/compiler/kotlin/KotlinCodeGenerator.java index 74d381ae..8151ffb2 100644 --- a/jte-kotlin/src/main/java/gg/jte/compiler/kotlin/KotlinCodeGenerator.java +++ b/jte-kotlin/src/main/java/gg/jte/compiler/kotlin/KotlinCodeGenerator.java @@ -144,13 +144,7 @@ public void onComplete() { continue; } - kotlinCode.setCurrentTemplateLine(parameter.templateLine); - kotlinCode.append("\t\tval ").append(parameter.name).append(" = params[\"").append(parameter.name).append("\"] as ").append(parameter.type); - if (parameter.defaultValue != null) { - kotlinCode.append("? ?: "); - writeCodeWithContentSupport(0, parameter.defaultValue); - } - kotlinCode.append('\n'); + writeParameterDeclaration(parameter); } kotlinCode.append("\t\trender(jteOutput, jteHtmlInterceptor"); @@ -184,6 +178,29 @@ public void onComplete() { this.classInfo.lineInfo = kotlinCode.getLineInfo(); } + private void writeParameterDeclaration(ParamInfo parameter) { + var nonNullDefaultValue = parameter.defaultValue != null && !parameter.defaultValue.equals("null"); + + kotlinCode.setCurrentTemplateLine(parameter.templateLine); + kotlinCode.append("\t\tval ").append(parameter.name).append(" = params[\"").append(parameter.name).append("\"] as "); + if (nonNullDefaultValue) { + kotlinCode.append(asNullableType(parameter.type)); + kotlinCode.append(" ?: "); + writeCodeWithContentSupport(0, parameter.defaultValue); + } else { + kotlinCode.append(parameter.type); + } + kotlinCode.append('\n'); + } + + private String asNullableType(String type) { + if (type.endsWith("?")) { + return type; + } else { + return type + "?"; + } + } + private void addNameField(StringBuilder fields, String name) { fields.append("\t@JvmField val ").append(Constants.NAME_FIELD).append(" = \""); fields.append(name); diff --git a/jte-kotlin/src/test/java/gg/jte/kotlin/TemplateEngineTest.java b/jte-kotlin/src/test/java/gg/jte/kotlin/TemplateEngineTest.java index 7f7433a7..97491128 100644 --- a/jte-kotlin/src/test/java/gg/jte/kotlin/TemplateEngineTest.java +++ b/jte-kotlin/src/test/java/gg/jte/kotlin/TemplateEngineTest.java @@ -7,6 +7,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.time.LocalDateTime; import java.util.*; @@ -764,6 +768,41 @@ void paramWithDefaultValue() { assertThat(output.toString()).isEqualTo("Your age is 10"); } + @Test + void nullableParamsShouldNotHaveDoubleQuestionMarks() throws IOException { + givenRawTemplate("@param age: Int? = 10\nYour age is ${age}"); + + List compiledPaths = templateEngine.precompileAll(); + Path classDirectory = Paths.get("jte-classes"); + var templateContent = Files.readString(classDirectory.resolve(compiledPaths.get(0))); + + assertThat(templateContent).contains("val age = params[\"age\"] as Int?"); + assertThat(templateContent).doesNotContain("val age = params[\"age\"] as Int??"); + } + + @Test + void nullableParamsWithNonNullDefaultValuesShouldFallbackToTheDefault() throws IOException { + givenRawTemplate("@param age: Int? = 10\nYour age is ${age}"); + + List compiledPaths = templateEngine.precompileAll(); + Path classDirectory = Paths.get("jte-classes"); + var templateContent = Files.readString(classDirectory.resolve(compiledPaths.get(0))); + + assertThat(templateContent).contains("val age = params[\"age\"] as Int? ?: 10"); + } + + @Test + void nullableParamsWithNullDefaultValuesShouldNotUseElvisOperator() throws IOException { + givenRawTemplate("@param age: Int? = null\nYour age is ${age}"); + + List compiledPaths = templateEngine.precompileAll(); + Path classDirectory = Paths.get("jte-classes"); + var templateContent = Files.readString(classDirectory.resolve(compiledPaths.get(0))); + + assertThat(templateContent).contains("val age = params[\"age\"] as Int?"); + assertThat(templateContent).doesNotContain("val age = params[\"age\"] as Int? ?: null"); + } + @Test void contentParamWithDefaultValue() { givenRawTemplate("@param content:gg.jte.Content = @`Some Content`\nThe default content is ${content}");