fix: enhance global key validation and update template parameters

This commit is contained in:
Relism
2026-04-29 10:31:14 +02:00
parent 0e2dad23e5
commit f310646868
6 changed files with 26 additions and 30 deletions
@@ -22,7 +22,6 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
final class JteRuntime implements ViewRuntimeBridge<JteTarget> {
private static final String GLOBAL_NAMESPACE = "global";
private final JteSettings settings;
private final List<GlobalValue> globals;
@@ -60,30 +59,25 @@ final class JteRuntime implements ViewRuntimeBridge<JteTarget> {
}
private ViewModel merge(Request req, ViewModel local) {
LinkedHashMap<String, Object> values = null;
LinkedHashMap<String, Object> values = new LinkedHashMap<>();
if (!globals.isEmpty()) {
LinkedHashMap<String, Object> 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<String, Object> 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);
}
@@ -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
@@ -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<String, Object> global
@param String appName
<h1>${page.title()}</h1>
<p>${page.author()}</p>
<small>${build}</small>
<small>${(String) global.get("appName")}</small>
<small>${appName}</small>