From f3106468683363bd59d97e3bef4e22b8d0137976 Mon Sep 17 00:00:00 2001 From: Relism Date: Wed, 29 Apr 2026 10:31:14 +0200 Subject: [PATCH] fix: enhance global key validation and update template parameters --- .../ext/view/core/BaseViewExtension.java | 6 +++- .../ondemand/pages/JtehomeGenerated.class | Bin 2126 -> 1905 bytes .../ondemand/pages/JtehomeGenerated.java | 13 ++++----- .../relism/flash/ext/view/jte/JteRuntime.java | 26 +++++++----------- .../flash/ext/view/jte/JteRuntimeTest.java | 6 ++-- .../test/resources/templates/pages/home.jte | 5 ++-- 6 files changed, 26 insertions(+), 30 deletions(-) diff --git a/flash-extensions/flash-ext-view-core/src/main/java/dev/relism/flash/ext/view/core/BaseViewExtension.java b/flash-extensions/flash-ext-view-core/src/main/java/dev/relism/flash/ext/view/core/BaseViewExtension.java index e475de1..1d83b9c 100644 --- a/flash-extensions/flash-ext-view-core/src/main/java/dev/relism/flash/ext/view/core/BaseViewExtension.java +++ b/flash-extensions/flash-ext-view-core/src/main/java/dev/relism/flash/ext/view/core/BaseViewExtension.java @@ -18,9 +18,13 @@ public abstract class BaseViewExtension implements FlashExtension { if (k.isEmpty()) { throw new IllegalArgumentException("global key must not be blank"); } - if (k.equals("global") || k.contains(".")) { + if (k.contains(".")) { throw new IllegalArgumentException("global key must be a simple key (no dots), received: " + key); } + boolean duplicate = globals.stream().anyMatch(g -> g.key().equals(k)); + if (duplicate) { + throw new IllegalArgumentException("global key '" + k + "' is already registered"); + } globals.add(new GlobalValue(k, Objects.requireNonNull(resolver, "global resolver must not be null"))); return this; } diff --git a/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.class b/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.class index 22995af0c53796fd6a4e1d9873bb02988921f760..d706ab35e525debd9096b8fb8a095e699b0eb4c0 100644 GIT binary patch delta 718 zcmYk3O>YuW6o%hB-!pu4IxQ563yq0M3oX_UR6wwPRci|>ieY7jhy+8C)Z&)J_zRq! zJ6EpJjhM!`c47Pr{sjMk@x9ZgHIw(b_ndpqz3-j-)BO{7e*FFV4Zu2{Oq_{0X_fP@ zcKm+7VqsN48~WW&1ZS~k;#?HxaUu96swE2r0lhuy^`DuzEa1NIU;FvKKj`Kgd%L|s z*FsUi^oPTmzteG0##IxQD5|&?w3Ui@7kp6Orv9rhEj4XcU60}hZU#klL);DCsDAKK zdmghJz3#x@8|`)kMr^DG+j=ishCFq(nm|W9dojl^H!$FEBKCNE$3Z4 zoL?$xIq%9*pf6`v(pp;og3__gWO$PW8cXp%q;Up|e7a0%A*LQ#c)(L0QVJTp(W8T( z#P}1&8VBILdt%>dscOBYQMy)d8I(y`lxtXoDPc+25{_$-k&w}lG1p`!9&#q6>&nX6 rkY32SknYuW6o%hBAIt{>y-W+1Qe%vXiG>zwwN_feuUfSfR4jGem?4r0W{OzBs2hHQ zCi4?qxg^F!)EHMTT)1&#;;--z7|+~NJCpOAIdATq`<{FM#D8$}``?dW09?ZTp*dtp z&Fyxp?rtlJ1>`jpEG*)5@SBzE8qP5ANA5E>@4Fo@U+?X;JD!eZ24gM%bl3I$lBr{b zLFu|)OGlAGZT8##Lmg`j5zl|zbbS*glr>zmXvfRJwp3!Tf{IcOeoE`fey{E4x7_aP zsfIzzu3A{fwV)txu+8AP>{|7<*KvFOy%xj!gP(%e%2M!4_JU32ZMFo7Mv;)l2CjqQ zhNx~*O^xVVAx%YuSP71)spDIug%wCOLPL;Iq3RoDmGaA=p*9D0c7%BeU$HboM#7wZ zb_7GhkQOk6EsBT}4d^hDKol8RIDr^)q%UKFM&V>Afhue?Fo_44!V@I%0x8mfq>37) zTNEo4MT#|w+Y}P+45)J*cgNNoF#xcbv(JrfrK&mm{DH-ylCxLG#X?b?%g(2jwE6)T z4(+DIY|~^iP45g&lHmeog_W56-^%vb!ayR^I(GKYjl@rMj^Xo$AN_1PvRrc%3RS5& z5w+%M6gmYD3$F19Q5Q4>O~EMFNVf!If^n{sG9kzX6Wk!h-Vte1aEhBGB?VK0N5WmE f!%fm*$C(hB5VKnC9j+Wsy?@UdUD-YIF2VT+xz2dY diff --git a/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.java b/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.java index 9fb39b4..3395b87 100644 --- a/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.java +++ b/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.java @@ -1,11 +1,10 @@ package gg.jte.generated.ondemand.pages; import dev.relism.flash.ext.view.jte.model.HomePage; -import java.util.Map; @SuppressWarnings("unchecked") public final class JtehomeGenerated { public static final String JTE_NAME = "pages/home.jte"; - public static final int[] JTE_LINE_INFO = {0,0,1,2,2,2,2,6,6,6,6,7,7,7,8,8,8,9,9,9,10,10,10,2,3,4,4,4,4}; - public static void render(gg.jte.html.HtmlTemplateOutput jteOutput, gg.jte.html.HtmlInterceptor jteHtmlInterceptor, HomePage page, String build, Map global) { + public static final int[] JTE_LINE_INFO = {0,0,1,1,1,1,5,5,5,5,6,6,6,7,7,7,8,8,8,8,8,8,1,2,3,3,3,3}; + public static void render(gg.jte.html.HtmlTemplateOutput jteOutput, gg.jte.html.HtmlInterceptor jteHtmlInterceptor, HomePage page, String build, String appName) { jteOutput.writeContent("\n

"); jteOutput.setContext("h1", null); jteOutput.writeUserContent(page.title()); @@ -17,13 +16,13 @@ public final class JtehomeGenerated { jteOutput.writeUserContent(build); jteOutput.writeContent("\n"); jteOutput.setContext("small", null); - jteOutput.writeUserContent((String) global.get("appName")); - jteOutput.writeContent("\n"); + jteOutput.writeUserContent(appName); + jteOutput.writeContent(""); } public static void renderMap(gg.jte.html.HtmlTemplateOutput jteOutput, gg.jte.html.HtmlInterceptor jteHtmlInterceptor, java.util.Map params) { HomePage page = (HomePage)params.get("page"); String build = (String)params.get("build"); - Map global = (Map)params.get("global"); - render(jteOutput, jteHtmlInterceptor, page, build, global); + String appName = (String)params.get("appName"); + render(jteOutput, jteHtmlInterceptor, page, build, appName); } } diff --git a/flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/flash/ext/view/jte/JteRuntime.java b/flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/flash/ext/view/jte/JteRuntime.java index edccec7..e7f4b41 100644 --- a/flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/flash/ext/view/jte/JteRuntime.java +++ b/flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/flash/ext/view/jte/JteRuntime.java @@ -22,7 +22,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; final class JteRuntime implements ViewRuntimeBridge { - private static final String GLOBAL_NAMESPACE = "global"; private final JteSettings settings; private final List globals; @@ -60,30 +59,25 @@ final class JteRuntime implements ViewRuntimeBridge { } private ViewModel merge(Request req, ViewModel local) { - LinkedHashMap values = null; + LinkedHashMap values = new LinkedHashMap<>(); - if (!globals.isEmpty()) { - LinkedHashMap globalMap = new LinkedHashMap<>(); - for (GlobalValue binding : globals) { - Object resolved = binding.resolver().apply(req); - globalMap.put(binding.key(), ViewModel.unwrapValue(resolved)); - } - if (!globalMap.isEmpty()) { - values = new LinkedHashMap<>(); - values.put(GLOBAL_NAMESPACE, Collections.unmodifiableMap(globalMap)); - } + for (GlobalValue binding : globals) { + Object resolved = binding.resolver().apply(req); + values.put(binding.key(), ViewModel.unwrapValue(resolved)); } if (local != null) { Map localMap = local.toMap(); - if (localMap.containsKey(GLOBAL_NAMESPACE)) { - throw new IllegalStateException("ViewModel key 'global' is reserved for framework globals"); + for (String key : localMap.keySet()) { + if (values.containsKey(key)) { + throw new IllegalStateException( + "ViewModel key '" + key + "' conflicts with a registered global"); + } } - if (values == null) return ViewModel.copyOf(local); values.putAll(localMap); } - if (values == null || values.isEmpty()) return ViewModel.empty(); + if (values.isEmpty()) return ViewModel.empty(); return ViewModel.owned(values); } diff --git a/flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/flash/ext/view/jte/JteRuntimeTest.java b/flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/flash/ext/view/jte/JteRuntimeTest.java index bed62c5..cc2bcc3 100644 --- a/flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/flash/ext/view/jte/JteRuntimeTest.java +++ b/flash-extensions/flash-ext-view-jte/src/test/java/dev/relism/flash/ext/view/jte/JteRuntimeTest.java @@ -38,7 +38,7 @@ class JteRuntimeTest { } @Test - void render_rejectsReservedGlobalKeyInLocalModel() { + void render_rejectsConflictingLocalKey() { JteRuntime runtime = new JteRuntime( JteSettings.builder().templateRoot("/templates").developmentMode(true).build(), List.of(new GlobalValue("appName", req -> "Flash")) @@ -48,12 +48,12 @@ class JteRuntimeTest { runtime.render(new JteHandler() { @Override public ViewModel render(Request req) { - return ViewModel.of("global", "bad"); + return ViewModel.of("appName", "override"); // collide con global } }, new JteTarget("pages/home.jte", ContentType.TEXT_HTML), null, new Response(200, ContentType.JSON)) ); - assertTrue(ex.getMessage().contains("reserved")); + assertTrue(ex.getMessage().contains("appName")); } @Test diff --git a/flash-extensions/flash-ext-view-jte/src/test/resources/templates/pages/home.jte b/flash-extensions/flash-ext-view-jte/src/test/resources/templates/pages/home.jte index 7106021..a03157f 100644 --- a/flash-extensions/flash-ext-view-jte/src/test/resources/templates/pages/home.jte +++ b/flash-extensions/flash-ext-view-jte/src/test/resources/templates/pages/home.jte @@ -1,10 +1,9 @@ @import dev.relism.flash.ext.view.jte.model.HomePage -@import java.util.Map @param HomePage page @param String build -@param Map global +@param String appName

${page.title()}

${page.author()}

${build} -${(String) global.get("appName")} +${appName} \ No newline at end of file