fix canonical component artifact identity

This commit is contained in:
udo 2026-07-14 21:32:29 +00:00
parent b6c2b8b08d
commit d33d5e80ba
4 changed files with 20 additions and 3 deletions

View File

@ -396,7 +396,9 @@ header free-functions are `inline`. The wasm backend exposes only declarations
child and again with that child activated. This guards the component-slot
cache invariant that a cache hit must restore both the function-table slot
and the resolved unit path; otherwise nested relative targets resolve from
the caller after a repeated parent invocation.
the caller after a repeated parent invocation. Resolved component paths are
canonical absolute paths: equivalent spellings containing `.` or `..` must
share one source, compile, artifact, and module-cache identity.
- **WebSocket end-to-end**: a headless client performs a raw WS handshake to
`:HTTP_PORT` with path `/site/tests/websockets.ws.uce` (self-resolving

View File

@ -27,6 +27,8 @@ RENDER(Request& context)
String lazy_first = component("components/lazy-parent", lazy_props, context);
lazy_props["show_child"].set_bool(true);
String lazy_second = component("components/lazy-parent", lazy_props, context);
String relative_resolved = component_resolve("components/../relative-child");
String relative_markup = component("components/../relative-child", props, context);
String alias_markup = component("components/props_alias", props, context);
// Named handler through the string-returning component("unit:NAME") form
// (distinct path from component_render below): resolves __uce_component_HEADER
@ -47,6 +49,8 @@ RENDER(Request& context)
check("component_resolve()", resolved != "", resolved);
check("component()", panel_markup.find("Component Output") != String::npos && panel_markup.find("This body comes from component()") != String::npos, panel_markup);
check("cached component retains path for a newly activated relative child", lazy_first.find("lazy-child") == String::npos && lazy_second.find("lazy-child") != String::npos, lazy_second);
check("relative component path has canonical identity", relative_resolved.find("/../") == String::npos && str_ends_with(relative_resolved, "/site/tests/relative-child.uce"), relative_resolved);
check("relative component path renders its canonical artifact", relative_markup.find("relative-child") != String::npos, relative_markup);
check("COMPONENT(Request& props) alias", alias_markup.find("alias=Component Output") != String::npos && alias_markup.find("body=This body comes from component()") != String::npos, alias_markup);
check("component_render() named handler", footer_markup.find("Named footer render") != String::npos, footer_markup);
check("component(\"unit:NAME\") named handler", header_markup.find("Component Output") != String::npos && header_markup.find("This body comes from component()") == String::npos, header_markup);

View File

@ -0,0 +1,6 @@
#include "testlib.h"
COMPONENT(Request& context)
{
?><span>relative-child</span><?
}

View File

@ -1455,8 +1455,13 @@ private:
candidates.push_back(base + "components/" + normalize_component_path(file_name));
}
for(auto& candidate : candidates)
if(file_exists_host(candidate))
return(candidate);
{
if(!file_exists_host(candidate))
continue;
char resolved[PATH_MAX];
if(realpath(candidate.c_str(), resolved))
return(String(resolved));
}
}
return("");
}