some cleanup

This commit is contained in:
udo
2026-04-28 12:10:07 +00:00
parent 223cf4c6e1
commit cd445f3c9b
224 changed files with 1558 additions and 38907 deletions
+3 -4
View File
@@ -28,9 +28,8 @@ Map-shaped `DTree` values can also represent list-like data when their keys are
You will encounter `DTree` throughout the runtime, especially in:
- `context.var`
- `context.cfg`
- `context.call`
- `context.props`
- `context.connection`
- `json_decode()` results
- `unit_call()` return values
@@ -107,7 +106,7 @@ For non-map values, `each()` still invokes the callback once:
- `key` is an empty string
```cpp
context.var["items"].each([&](DTree item, String key) {
context.connection["items"].each([&](DTree item, String key) {
print(key, ": ", item.to_string(), "\n");
});
```
@@ -119,7 +118,7 @@ String theme = context.cfg.get_by_path("theme/key").to_string();
u64 compiled_mtime = unit_info("test/hello.uce")["compiled_mtime"].to_u64();
bool dark_mode = context.call["dark_mode"].to_bool();
bool dark_mode = context.props["dark_mode"].to_bool();
if(DTree* user = payload.key("user")) {
print(user->to_json());
+5 -4
View File
@@ -8,7 +8,7 @@ Request& context;
>types
:content
`Request& context` is the request-local state object passed into UCE handlers. It carries incoming request data, response state, runtime metadata, and helper trees such as `context.cfg`, `context.var`, and `context.call`.
`Request& context` is the request-local state object passed into UCE handlers. It carries incoming request data, response state, runtime metadata, and helper trees such as `context.cfg`, `context.props`, and `context.connection`.
## Core Fields
@@ -20,9 +20,8 @@ Request& context;
- `StringMap session`: current session data
- `String session_id`: session cookie ID
- `String session_name`: session cookie name
- `DTree var`: user-defined request-local data
- `DTree cfg`: request-local configuration tree
- `DTree call`: invocation or message-local structured data
- `DTree call`: invocation-local structured data for helpers such as component and unit calls
- `DTree connection`: broker-owned WebSocket connection state that persists across `WS(Request& context)` calls for the same socket
- `std::vector<UploadedFile> uploaded_files`: files uploaded in the current request
- `StringMap header`: headers to send back to the browser
@@ -45,7 +44,9 @@ Request& context;
## Common Usage Notes
- `context.cfg` is the usual place for structured configuration. Use `context.cfg.get_by_path("path/to/value")` for deep reads.
- `context.call` carries invocation data for component calls, unit calls, and WebSocket messages.
- `context.props` carries invocation data for component calls and unit calls.
- `context.in` carries the current request body, and for `WS(Request& context)` it is the current WebSocket message payload.
- `context.params["WS_..."]` exposes the current WebSocket message metadata directly on the request parameter map.
- `context.connection` is only meaningful for WebSocket traffic and persists for the lifetime of the connection.
`unit_render(String file_name, [Request& context])` invokes another UCE file using the current or supplied request context.
+3 -3
View File
@@ -25,7 +25,7 @@ This keeps page rendering and component rendering separate:
A file intended only for component reuse can define `COMPONENT()` without defining `RENDER()`.
Inside component handlers, props arrive through `context.call`.
Inside component handlers, props arrive through `context.props`.
When you call `component(":NAME", props, context)` or `component_render(":NAME", props, context)`, the runtime resolves `:NAME` against the current `.uce` file instead of requiring the file name again.
@@ -34,12 +34,12 @@ When you call `component(":NAME", props, context)` or `component_render(":NAME",
```cpp
COMPONENT(Request& context)
{
<><section><?: component(":BODY", context.call, context) ?></section></>
<><section><?: component(":BODY", context.props, context) ?></section></>
}
COMPONENT:BODY(Request& context)
{
<><p><?= context.call["body"] ?></p></>
<><p><?= context.props["body"] ?></p></>
}
```
+2 -2
View File
@@ -18,9 +18,9 @@ The default page entrypoint is always the plain `RENDER(Request& context)` handl
Reusable component handlers now live on `COMPONENT(Request& context)` and `COMPONENT:NAME(Request& context)`. The component helpers call those handlers, not `RENDER()`.
The request environment is passed explicitly through `context`, including params, cookies, post data, session state, headers, uploaded files, and the current `context.call` tree.
The request environment is passed explicitly through `context`, including params, cookies, post data, session state, headers, uploaded files, and the current `context.props` tree.
For a normal direct page request, `context.call` starts empty.
For a normal direct page request, `context.props` starts empty.
If the page is invoked from another UCE file via `unit_render(file_name, context)`, the callee receives that same `context`.
+15 -7
View File
@@ -12,7 +12,7 @@ Defines the WebSocket message handler for the current `.ws.uce` page.
The same page may expose both `RENDER(Request& context)` and `WS(Request& context)`. `RENDER(Request& context)` serves the initial HTTP response, while `WS(Request& context)` is called whenever a complete WebSocket message arrives for that page.
UCE reassembles fragmented messages before calling `WS(Request& context)`. Text and binary frames are both delivered. Use `context.call`, `context.connection`, `ws_opcode()`, and `ws_is_binary()` to inspect the current message.
UCE reassembles fragmented messages before calling `WS(Request& context)`. Text and binary frames are both delivered. The current payload is available directly on `context.in`, message metadata is mirrored into `context.params["WS_..."]`, and connection-local state lives on `context.connection`.
## Connection State
@@ -20,13 +20,21 @@ UCE reassembles fragmented messages before calling `WS(Request& context)`. Text
## Message Data
The current message data is available in `context.call`:
The current message payload is available as:
- `context.call["message"]`: current message payload
- `context.call["connection_id"]`: sender connection ID
- `context.call["scope"]`: current endpoint scope
- `context.call["opcode"]`: WebSocket opcode of the current message
- `context.call["document_uri"]`: request URI of the current endpoint
- `context.in`: current WebSocket payload
- `context.params["WS_MESSAGE"]`: same payload mirrored into the parameter map
The current message metadata is available as:
- `context.params["WS_CONNECTION_ID"]`: sender connection ID
- `context.params["WS_SCOPE"]`: current endpoint scope
- `context.params["WS_CONNECTION_COUNT"]`: number of currently connected clients in that scope
- `context.params["WS_OPCODE"]`: WebSocket opcode of the current message
- `context.params["WS_MESSAGE_TYPE"]`: `TEXT` or `BINARY`
- `context.params["WS_DOCUMENT_URI"]`: request URI of the current endpoint
Helper wrappers such as `ws_message()`, `ws_connection_id()`, `ws_scope()`, `ws_connection_count()`, `ws_opcode()`, and `ws_is_binary()` are still available when that reads better for the handler.
## Related Concepts
+2 -2
View File
@@ -88,7 +88,7 @@ Literal output with trusted unescaped markup:
```cpp
RENDER(Request& context)
{
<><div class="panel"><?: component("components/card", context.call, context) ?></div></>
<><div class="panel"><?: component("components/card", context.props, context) ?></div></>
}
```
@@ -96,7 +96,7 @@ Roughly becomes:
```cpp
print(R"(<div class="panel">)");
print(component("components/card", context.call, context));
print(component("components/card", context.props, context));
print(R"(</div>)");
```
+1 -1
View File
@@ -9,7 +9,7 @@ Renders another `.uce` file as a component and returns the captured output as a
`component()` resolves the target file relative to the current page and also tries the `components/` prefix automatically, mirroring the shorthand used by the starter example project.
Component props are passed in `context.call`.
Component props are passed in `context.props`.
Because `<?= ... ?>` HTML-escapes its value, embed component markup with `<?: component(...) ?>`, `print(component(...))`, or use `component_render(...)` for direct output.
+1 -1
View File
@@ -9,7 +9,7 @@ Renders another `.uce` file as a component and writes the result directly to the
This is the direct-output counterpart to `component()`.
Component props are passed through `context.call`, and `name:COMPONENTFUNC` may be used to select a named handler exported by `COMPONENT:COMPONENTFUNC(Request& context)`.
Component props are passed through `context.props`, and `name:COMPONENTFUNC` may be used to select a named handler exported by `COMPONENT:COMPONENTFUNC(Request& context)`.
When `name` starts with `:`, the runtime resolves that named handler against the current `.uce` file.
+13 -13
View File
@@ -70,22 +70,22 @@ options["components"]["node.directive"] = "components/markdown/directive";
If both an exact directive hook and a generic `node.directive` hook exist, the exact directive hook wins.
When a markdown hook component is called, its props arrive in `context.call`.
When a markdown hook component is called, its props arrive in `context.props`.
Useful fields include:
- `context.call["hook"]` for the matched hook key such as `:::warning` or `node.code_block`
- `context.call["target"]` for the resolved component target name
- `context.call["default_html"]` for the renderer output without the hook
- `context.call["children_html"]` for already-rendered child HTML
- `context.call["node"]` for the full AST node
- `context.call["type"]` for the node type
- `context.call["name"]` for the directive name when applicable
- `context.call["argument"]` for directive remainder after the name
- `context.call["text"]` for source text used by nodes such as `code_block`
- `context.call["lang"]` for fenced code language
- `context.call["href"]`, `context.call["src"]`, and `context.call["title"]`
- `context.call["options"]` for the full markdown options tree
- `context.props["hook"]` for the matched hook key such as `:::warning` or `node.code_block`
- `context.props["target"]` for the resolved component target name
- `context.props["default_html"]` for the renderer output without the hook
- `context.props["children_html"]` for already-rendered child HTML
- `context.props["node"]` for the full AST node
- `context.props["type"]` for the node type
- `context.props["name"]` for the directive name when applicable
- `context.props["argument"]` for directive remainder after the name
- `context.props["text"]` for source text used by nodes such as `code_block`
- `context.props["lang"]` for fenced code language
- `context.props["href"]`, `context.props["src"]`, and `context.props["title"]`
- `context.props["options"]` for the full markdown options tree
Directive blocks use this form: