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 22995af..d706ab3 100644 Binary files a/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.class and b/flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.class differ 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