From c33500440e98ec60c44a447bcfe9eccee4997796 Mon Sep 17 00:00:00 2001 From: slhx agent Date: Fri, 5 Jun 2026 06:52:37 +0200 Subject: [PATCH] refactor!: rename slhx to hemx Rename the tracked product identity, crate/package names, Rust paths/macros, generated artifacts, runtime files, public attributes, examples, docs, requirements, and tests from slhx to hemx without compatibility shims. Verified with cargo run -p hemx-xtask -- test, cargo test -p hemx-derive --test compile_fail, cargo test -p hemx-js, cargo test -p hemx-axum, cargo test -p hemx-v0-examples, cargo check --workspace, redgate list, redgate refs, redgate health --strict, git diff --check, and git grep/ls-files legacy-name audits. req: misc/001 req: codegen/001 req: component/004 req: runtime/001 --- AGENTS.md | 6 +- Cargo.lock | 214 +++---- Cargo.toml | 2 +- REQUIREMENTS.md | 252 ++++---- examples/kanban.md | 70 +-- examples/kanban/Cargo.toml | 10 +- examples/kanban/README.md | 4 +- examples/kanban/build.rs | 2 +- examples/kanban/src/lib.rs | 12 +- examples/kanban/src/main.rs | 20 +- examples/kanban/templates/app_shell.heml | 4 +- examples/kanban/templates/board.heml | 12 +- .../kanban/templates/partials/board_card.heml | 10 +- examples/techdemo/Cargo.toml | 10 +- examples/techdemo/README.md | 18 +- examples/techdemo/build.rs | 2 +- examples/techdemo/src/lib.rs | 12 +- examples/techdemo/src/main.rs | 32 +- examples/techdemo/templates/app_shell.css | 2 +- examples/techdemo/templates/app_shell.heml | 4 +- .../techdemo/templates/control_center.heml | 32 +- examples/techdemo/templates/island.js | 12 +- .../partials/architecture_activity.heml | 2 +- .../partials/architecture_board.heml | 2 +- .../templates/partials/issue_card.heml | 6 +- .../templates/partials/issue_lane.heml | 2 +- examples/techdemo/tests/browser_e2e.rs | 12 +- examples/techdemo/tests/e2e.rs | 32 +- examples/v0/Cargo.toml | 10 +- examples/v0/README.md | 4 +- examples/v0/build.rs | 2 +- examples/v0/src/lib.rs | 28 +- examples/v0/src/main.rs | 64 +- examples/v0/templates/app_shell.heml | 6 +- examples/v0/templates/auth.heml | 6 +- examples/v0/templates/counter.heml | 6 +- examples/v0/templates/notifications.heml | 4 +- examples/v0/templates/page_swap.heml | 10 +- examples/v0/templates/partials/todo_row.heml | 4 +- examples/v0/templates/todos.heml | 16 +- examples/v0/templates/wizard.heml | 6 +- {slhx-axum => hemx-axum}/Cargo.toml | 6 +- {slhx-axum => hemx-axum}/src/lib.rs | 84 +-- {slhx-axum => hemx-axum}/tests/response.rs | 28 +- {slhx-build => hemx-build}/Cargo.toml | 4 +- {slhx-build => hemx-build}/src/lib.rs | 560 +++++++++--------- {slhx-core => hemx-core}/Cargo.toml | 2 +- {slhx-core => hemx-core}/src/lib.rs | 12 +- .../tests/effect_batch.rs | 6 +- {slhx-derive => hemx-derive}/Cargo.toml | 2 +- {slhx-derive => hemx-derive}/build.rs | 2 +- {slhx-derive => hemx-derive}/src/lib.rs | 182 +++--- .../tests/compile_fail.rs | 342 +++++------ {slhx-derive => hemx-derive}/tests/surface.rs | 2 +- {slhx-js => hemx-js}/Cargo.toml | 2 +- .../slhx.d.ts => hemx-js/runtime/hemx.d.ts | 8 +- .../slhx.js => hemx-js/runtime/hemx.js | 104 ++-- hemx-js/src/lib.rs | 3 + {slhx-js => hemx-js}/tests/runtime.rs | 88 +-- {slhx-test => hemx-test}/Cargo.toml | 4 +- {slhx-test => hemx-test}/src/lib.rs | 60 +- .../tests/examples_contract.rs | 24 +- hemx-test/tests/inspector.rs | 140 +++++ {slhx-xtask => hemx-xtask}/Cargo.toml | 4 +- {slhx-xtask => hemx-xtask}/src/main.rs | 24 +- {slhx => hemx}/Cargo.toml | 6 +- {slhx => hemx}/src/lib.rs | 24 +- slhx-js/src/lib.rs | 3 - slhx-test/tests/inspector.rs | 140 ----- 69 files changed, 1415 insertions(+), 1415 deletions(-) rename {slhx-axum => hemx-axum}/Cargo.toml (79%) rename {slhx-axum => hemx-axum}/src/lib.rs (94%) rename {slhx-axum => hemx-axum}/tests/response.rs (94%) rename {slhx-build => hemx-build}/Cargo.toml (76%) rename {slhx-build => hemx-build}/src/lib.rs (80%) rename {slhx-core => hemx-core}/Cargo.toml (94%) rename {slhx-core => hemx-core}/src/lib.rs (98%) rename {slhx-core => hemx-core}/tests/effect_batch.rs (98%) rename {slhx-derive => hemx-derive}/Cargo.toml (90%) rename {slhx-derive => hemx-derive}/build.rs (58%) rename {slhx-derive => hemx-derive}/src/lib.rs (83%) rename {slhx-derive => hemx-derive}/tests/compile_fail.rs (71%) rename {slhx-derive => hemx-derive}/tests/surface.rs (90%) rename {slhx-js => hemx-js}/Cargo.toml (83%) rename slhx-js/runtime/slhx.d.ts => hemx-js/runtime/hemx.d.ts (94%) rename slhx-js/runtime/slhx.js => hemx-js/runtime/hemx.js (90%) create mode 100644 hemx-js/src/lib.rs rename {slhx-js => hemx-js}/tests/runtime.rs (86%) rename {slhx-test => hemx-test}/Cargo.toml (57%) rename {slhx-test => hemx-test}/src/lib.rs (93%) rename {slhx-test => hemx-test}/tests/examples_contract.rs (94%) create mode 100644 hemx-test/tests/inspector.rs rename {slhx-xtask => hemx-xtask}/Cargo.toml (74%) rename {slhx-xtask => hemx-xtask}/src/main.rs (89%) rename {slhx => hemx}/Cargo.toml (61%) rename {slhx => hemx}/src/lib.rs (89%) delete mode 100644 slhx-js/src/lib.rs delete mode 100644 slhx-test/tests/inspector.rs diff --git a/AGENTS.md b/AGENTS.md index 9498f09..90470ca 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ -# slhx — AGENTS.md +# hemx — AGENTS.md ## Purpose @@ -48,8 +48,8 @@ Keep it stable. Prefer pointers to canonical sources over copied structure, file - Add only durable style, ownership, gotchas, and at most a few stable commands agents should actually run. - Prefer links or pointers to canonical sources over copied lists. - Avoid project trees, architecture maps, generated inventories, current file sizes, issue lists, TODO inventories, and other snapshots that will rot. -- Stable commands: `cargo run -p slhx-xtask -- test`, `cargo check --workspace`, `redgate health --strict`. Use the xtask runner for full verification so jobs are capped from local CPU and memory. req: test/004 -- slhx core stays small: effects, typed ids, registries, and wire schema only. +- Stable commands: `cargo run -p hemx-xtask -- test`, `cargo check --workspace`, `redgate health --strict`. Use the xtask runner for full verification so jobs are capped from local CPU and memory. req: test/004 +- hemx core stays small: effects, typed ids, registries, and wire schema only. - Routing, auth, sessions, transport, transitions, sync, and storage belong in integration/user crates. - Public examples and beginner APIs should use generated resources and `IntoEffect`, not raw ids or runtime opcodes. - Hemlate examples must use real hemplate syntax, not Vue/Handlebars sketches: `{+ expr +}` for escaped text, `{+= expr =+}` only for trusted/rendered HTML, `+attr="expr"` for dynamic attributes, and Rust-shaped `h-if`, `h-for`, `h-match`, `h-case` directives (`h-case="_"` is the default arm). diff --git a/Cargo.lock b/Cargo.lock index 843c5aa..545c9ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -424,6 +424,113 @@ dependencies = [ "tree-sitter-hemplate", ] +[[package]] +name = "hemx" +version = "0.1.0" +dependencies = [ + "hemplate", + "hemx-core", + "hemx-derive", +] + +[[package]] +name = "hemx-axum" +version = "0.1.0" +dependencies = [ + "axum", + "futures-util", + "hemx-core", + "hemx-js", + "scraper", + "tokio", +] + +[[package]] +name = "hemx-build" +version = "0.1.0" +dependencies = [ + "hemplate-core", + "hemx-core", +] + +[[package]] +name = "hemx-core" +version = "0.1.0" +dependencies = [ + "postcard", + "serde", +] + +[[package]] +name = "hemx-derive" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "hemx-js" +version = "0.1.0" + +[[package]] +name = "hemx-kanban-example" +version = "0.1.0" +dependencies = [ + "axum", + "futures-util", + "hemplate", + "hemx", + "hemx-axum", + "hemx-build", + "hemx-test", + "scraper", + "tokio", +] + +[[package]] +name = "hemx-techdemo" +version = "0.1.0" +dependencies = [ + "axum", + "futures-util", + "hemplate", + "hemx", + "hemx-axum", + "hemx-build", + "hemx-test", + "scraper", + "thirtyfour", + "tokio", +] + +[[package]] +name = "hemx-test" +version = "0.1.0" +dependencies = [ + "hemx-core", +] + +[[package]] +name = "hemx-v0-examples" +version = "0.1.0" +dependencies = [ + "axum", + "futures-util", + "hemplate", + "hemx", + "hemx-axum", + "hemx-build", + "hemx-test", + "scraper", + "tokio", +] + +[[package]] +name = "hemx-xtask" +version = "0.1.0" + [[package]] name = "html5ever" version = "0.29.1" @@ -1355,113 +1462,6 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" -[[package]] -name = "slhx" -version = "0.1.0" -dependencies = [ - "hemplate", - "slhx-core", - "slhx-derive", -] - -[[package]] -name = "slhx-axum" -version = "0.1.0" -dependencies = [ - "axum", - "futures-util", - "scraper", - "slhx-core", - "slhx-js", - "tokio", -] - -[[package]] -name = "slhx-build" -version = "0.1.0" -dependencies = [ - "hemplate-core", - "slhx-core", -] - -[[package]] -name = "slhx-core" -version = "0.1.0" -dependencies = [ - "postcard", - "serde", -] - -[[package]] -name = "slhx-derive" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "slhx-js" -version = "0.1.0" - -[[package]] -name = "slhx-kanban-example" -version = "0.1.0" -dependencies = [ - "axum", - "futures-util", - "hemplate", - "scraper", - "slhx", - "slhx-axum", - "slhx-build", - "slhx-test", - "tokio", -] - -[[package]] -name = "slhx-techdemo" -version = "0.1.0" -dependencies = [ - "axum", - "futures-util", - "hemplate", - "scraper", - "slhx", - "slhx-axum", - "slhx-build", - "slhx-test", - "thirtyfour", - "tokio", -] - -[[package]] -name = "slhx-test" -version = "0.1.0" -dependencies = [ - "slhx-core", -] - -[[package]] -name = "slhx-v0-examples" -version = "0.1.0" -dependencies = [ - "axum", - "futures-util", - "hemplate", - "scraper", - "slhx", - "slhx-axum", - "slhx-build", - "slhx-test", - "tokio", -] - -[[package]] -name = "slhx-xtask" -version = "0.1.0" - [[package]] name = "smallvec" version = "1.15.1" diff --git a/Cargo.toml b/Cargo.toml index 47ddba3..52f2bd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["slhx", "slhx-core", "slhx-derive", "slhx-js", "slhx-axum", "slhx-build", "slhx-test", "slhx-xtask", "examples/v0", "examples/kanban", "examples/techdemo"] +members = ["hemx", "hemx-core", "hemx-derive", "hemx-js", "hemx-axum", "hemx-build", "hemx-test", "hemx-xtask", "examples/v0", "examples/kanban", "examples/techdemo"] [workspace.package] version = "0.1.0" diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md index 50f5a09..993896c 100644 --- a/REQUIREMENTS.md +++ b/REQUIREMENTS.md @@ -1,11 +1,11 @@ -# slhx — Semantic, Laterally HX +# hemx — Semantic, Laterally HX -slhx makes server-rendered HTML feel like it grew just enough interactivity. +hemx makes server-rendered HTML feel like it grew just enough interactivity. App authors change state in Rust, render hemplate partials, and return generated UI intent; the runtime swaps generated slots without selectors, a VDOM, or a client app state framework. -> **hemplate owns syntax. hemplate emits surface. slhx consumes surface. slhx owns semantics. JS applies effects.** +> **hemplate owns syntax. hemplate emits surface. hemx consumes surface. hemx owns semantics. JS applies effects.** --- @@ -31,13 +31,13 @@ client app state framework. ## pitch ### req: pitch/001 -001 slhx is checked hypermedia for Rust. Write `.heml`, write Rust handlers, return generated UI commands. The compiler checks every cross-file reference. The browser runtime only sees lowered ids and effect bytes. No JS app code is required for ordinary server-first apps. [north_star] +001 hemx is checked hypermedia for Rust. Write `.heml`, write Rust handlers, return generated UI commands. The compiler checks every cross-file reference. The browser runtime only sees lowered ids and effect bytes. No JS app code is required for ordinary server-first apps. [north_star] ### req: pitch/002 -002 No CSS selectors. No hx-* strings. No virtual DOM. No client framework. No hidden global proxy magic. No component hydration. SSR state bootstrap via `data-slhx-st` is allowed, but the browser never reconstructs a component tree. [north_star] +002 No CSS selectors. No hx-* strings. No virtual DOM. No client framework. No hidden global proxy magic. No component hydration. SSR state bootstrap via `data-hemx-st` is allowed, but the browser never reconstructs a component tree. [north_star] ### req: pitch/003 -003 slhx replaces React/Vue not with a UI framework, but with a compiler contract: hemplate knows the surface, Rust knows the types, slhx knows the effects, the browser only executes commands. [north_star] +003 hemx replaces React/Vue not with a UI framework, but with a compiler contract: hemplate knows the surface, Rust knows the types, hemx knows the effects, the browser only executes commands. [north_star] ### req: pitch/004 004 The north-star feel: **boring server-rendered HTML with typed, selectorless partial swaps.** Short handler bodies, compile-checked HTML contracts, plain Rust state changes, hemplate-rendered partials, and a tiny runtime that applies effects. [north_star] @@ -47,7 +47,7 @@ client app state framework. ## canonical_authoring ### req: canonical/001 -001 The canonical app shape is templates plus Rust, not a frontend folder: `.heml` files declare `data-slhx-root`, `data-slhx-slot`, `data-slhx-handle`, `data-slhx-form`, `h-key`, optional pending/page/island facts, and handlers return generated UI commands. Ordinary app code avoids selectors, numeric ids, raw effects, wire formats, manual registries/form parsing, raw `SafeHtml`, and raw render calls. Plain CSS owns appearance. [north_star] +001 The canonical app shape is templates plus Rust, not a frontend folder: `.heml` files declare `data-hemx-root`, `data-hemx-slot`, `data-hemx-handle`, `data-hemx-form`, `h-key`, optional pending/page/island facts, and handlers return generated UI commands. Ordinary app code avoids selectors, numeric ids, raw effects, wire formats, manual registries/form parsing, raw `SafeHtml`, and raw render calls. Plain CSS owns appearance. [north_star] ### req: canonical/002 002 Typed partial swaps are the primary UX, not an advanced feature: handlers change domain state in Rust, convert domain values into view values, render hemplate partials through generated helpers, and place them into generated targets. The real primitive is generated target + rendered partial + swap kind. [north_star] @@ -65,20 +65,20 @@ client app state framework. 006 There is no separate beginner API and expert API. The simple generated shape is canonical and should scale: generated slots, partials, forms, class constants, islands/events, and page helpers are normal. Explicit primitives, raw targets, raw HTML, raw effects, manual registries/form parsing, low-level ids/opcodes, wire formats, and raw routes remain named escape hatches or internals around the same render/target/effect/transport model. [north_star] ### req: canonical/007 -007 Opaque islands are explicit leaf adapters: templates declare `data-slhx-island` and optional generated handles/events; server code may emit snapshots/events such as `ui::game.emit(event)`, while island JS owns only high-frequency local behavior. Islands do not introduce a component runtime, client state graph, VDOM, or second UI model. [north_star] +007 Opaque islands are explicit leaf adapters: templates declare `data-hemx-island` and optional generated handles/events; server code may emit snapshots/events such as `ui::game.emit(event)`, while island JS owns only high-frequency local behavior. Islands do not introduce a component runtime, client state graph, VDOM, or second UI model. [north_star] ### req: canonical/008 -008 Offline/PWA support is opt-in adapter territory. Server-first slhx may fail interactions while offline; cached shells and local-sync queues live in crates such as `slhx-pwa` or `slhx-sync`, reuse generated slots/effects, queue explicit patches, and reconcile with server-canonical effects. Core slhx must not gain a mandatory client state graph, scheduler, CRDT, or local app runtime. [north_star] +008 Offline/PWA support is opt-in adapter territory. Server-first hemx may fail interactions while offline; cached shells and local-sync queues live in crates such as `hemx-pwa` or `hemx-sync`, reuse generated slots/effects, queue explicit patches, and reconcile with server-canonical effects. Core hemx must not gain a mandatory client state graph, scheduler, CRDT, or local app runtime. [north_star] --- ## modes ### req: mode/001 -001 slhx has one core authoring loop: render a partial and place it into a generated target with a swap kind. HTTP handlers, page navigation, push streams, and island events are transport/adapters around that loop. +001 hemx has one core authoring loop: render a partial and place it into a generated target with a swap kind. HTTP handlers, page navigation, push streams, and island events are transport/adapters around that loop. ### req: mode/002 -002 Page Enhancer mode is a specialized partial swap for navigation: it updates generated page/content/title/nav targets and adds history, scroll, shell, and fallback behavior. Authors use real anchors with `data-slhx-nav` or `data-slhx-boost`; no user-authored handler is required for ordinary navigation. +002 Page Enhancer mode is a specialized partial swap for navigation: it updates generated page/content/title/nav targets and adds history, scroll, shell, and fallback behavior. Authors use real anchors with `data-hemx-nav` or `data-hemx-boost`; no user-authored handler is required for ordinary navigation. ### req: mode/003 003 Interaction Handler mode handles forms, buttons, typed params, and generated partial/text/form/island effects through Rust handlers. @@ -97,7 +97,7 @@ client app state framework. 002 The happy path is: write `.heml`, write a Rust handler, return generated partial/text/form/page/island commands. No manual ids, no manual registry, no manual serialization, no CSS selector targets, no raw render calls, and no manual JavaScript for ordinary app UI. [north_star] ### req: dx/003 -003 Public APIs are generated around the user's names. If the template declares `data-slhx-slot="todo_list"`, the user gets `slots::todo_list`, not `SlotId(12)`. +003 Public APIs are generated around the user's names. If the template declares `data-hemx-slot="todo_list"`, the user gets `slots::todo_list`, not `SlotId(12)`. ### req: dx/004 004 Common handlers must fit in a small function. Advanced contexts (`EffectWriter`, raw ops, custom encoders) exist but are not part of the beginner path. @@ -125,7 +125,7 @@ client app state framework. 002 Generated modules are imported through a prelude or component namespace. Users should not manually include `$OUT_DIR` files in normal apps. ### req: ceremony/003 -003 `build.rs` must be a one-liner for the common case: `fn main() { slhx_build::app().run().unwrap(); }` +003 `build.rs` must be a one-liner for the common case: `fn main() { hemx_build::app().run().unwrap(); }` ### req: ceremony/004 004 No API may require users to write numeric ids, raw ResourceIds, raw opcodes, or serialized payloads in normal code. @@ -151,10 +151,10 @@ client app state framework. ## page_swap ### req: page_swap/001 -001 Page swapping is a first-class specialization of partial swapping: render a page partial, place it into generated page targets, then apply history/title/scroll/shell behavior. Authors mark real anchors with `data-slhx-nav`; links keep valid `href` and work without JS. Missing or empty static `href` on a `data-slhx-nav` anchor is a build error. +001 Page swapping is a first-class specialization of partial swapping: render a page partial, place it into generated page targets, then apply history/title/scroll/shell behavior. Authors mark real anchors with `data-hemx-nav`; links keep valid `href` and work without JS. Missing or empty static `href` on a `data-hemx-nav` anchor is a build error. ### req: page_swap/002 -002 A `data-slhx-nav` click fetches the target URL as a slhx partial request. The response is conceptually `ui::content.replace(page)` plus optional generated nav/title targets and a `Navigate` effect; it must not introduce selector targeting or a second page-specific UI model. +002 A `data-hemx-nav` click fetches the target URL as a hemx partial request. The response is conceptually `ui::content.replace(page)` plus optional generated nav/title targets and a `Navigate` effect; it must not introduce selector targeting or a second page-specific UI model. ### req: page_swap/003 003 Page swapping uses generated targets, not CSS selectors. The default content target is the generated slot named `content`, not `#content`; explicit page helpers such as `ui::content.page(req, view)` or `request.page_html(ui::content.render(view), shell)` are adapters around the same partial-swap primitive. @@ -163,26 +163,26 @@ client app state framework. 004 Ordinary page navigation must not require user-authored handlers. Explicit navigation handlers are available only when custom application logic is needed, and they still return generated target/page commands. ### req: page_swap/005 -005 Browser back/forward is supported. On `popstate`, slhx fetches the URL as a partial request and applies the same page-swap update without pushing a new history entry. +005 Browser back/forward is supported. On `popstate`, hemx fetches the URL as a partial request and applies the same page-swap update without pushing a new history entry. ### req: page_swap/006 -006 If a page lacks the expected `content` slot, slhx-axum falls back to normal browser navigation in production and emits a diagnostic in development. +006 If a page lacks the expected `content` slot, hemx-axum falls back to normal browser navigation in production and emits a diagnostic in development. ### req: page_swap/007 -007 `data-slhx-boost` progressively enhances descendant same-origin anchors and forms. It is a container convention, not a replacement for `data-slhx-nav` on an anchor or `data-slhx-handle` on a form; placing it directly on static anchors or forms is a build error. Links behave like `data-slhx-nav`; forms behave like slhx form submissions. External links, downloads, new-tab links, and modified-clicks preserve native browser behavior. +007 `data-hemx-boost` progressively enhances descendant same-origin anchors and forms. It is a container convention, not a replacement for `data-hemx-nav` on an anchor or `data-hemx-handle` on a form; placing it directly on static anchors or forms is a build error. Links behave like `data-hemx-nav`; forms behave like hemx form submissions. External links, downloads, new-tab links, and modified-clicks preserve native browser behavior. --- ## htmx_equivalents ### req: htmx/001 -001 slhx replaces common HTMX use-cases through typed equivalents, not HTMX syntax. +001 hemx replaces common HTMX use-cases through typed equivalents, not HTMX syntax. ### req: htmx/002 002 Easy equivalents must exist for: generated target replacement, append/prepend/remove, boosted links/forms, page swap, form submit, loading indicators, confirmation, debounce/throttle, polling, history navigation, multi-target updates, response events, SSE/push, validation errors, modals, toasts, table rows, SVG fragments, and form error regions. ### req: htmx/003 -003 slhx core deliberately does not clone selector-based HTMX features: `hx-target` selectors, `hx-select`, `hx-include` selectors, `closest/find/this` target strings, or trigger mini-languages. Equivalent patterns use generated targets, typed params, forms, explicit handlers, and page/push adapters around partial swaps. +003 hemx core deliberately does not clone selector-based HTMX features: `hx-target` selectors, `hx-select`, `hx-include` selectors, `closest/find/this` target strings, or trigger mini-languages. Equivalent patterns use generated targets, typed params, forms, explicit handlers, and page/push adapters around partial swaps. --- @@ -192,7 +192,7 @@ client app state framework. 001 The primary authoring unit is a hemplate component plus adjacent Rust handlers. A component owns a template root, generated slots, generated handles, generated form checks, and source spans. ### req: component/002 -002 slhx supports colocated layout: `todo_list.heml` beside `todo_list.rs`, with generated APIs namespaced by component to avoid global symbol soup. +002 hemx supports colocated layout: `todo_list.heml` beside `todo_list.rs`, with generated APIs namespaced by component to avoid global symbol soup. ### req: component/003 003 Generated APIs are component-namespaced by default: @@ -200,20 +200,20 @@ client app state framework. Category modules such as `targets`, `handles`, and `forms` remain available for organization/compatibility, while raw slot constants live under `advanced::slots`; global exports (`ui::slots::*`, `ui::handles::*`, `ui::components::*`) are opt-in only. ### req: component/004 -004 `#[slhx::surface]` bridges generated code into a user module. Users write `#[slhx::surface] mod ui {}` instead of `include!(concat!(env!("OUT_DIR"), ...))`. slhx-build emits `slhx.generated.rs` which the macro expands in place. No direct `$OUT_DIR` includes in user-authored source. +004 `#[hemx::surface]` bridges generated code into a user module. Users write `#[hemx::surface] mod ui {}` instead of `include!(concat!(env!("OUT_DIR"), ...))`. hemx-build emits `hemx.generated.rs` which the macro expands in place. No direct `$OUT_DIR` includes in user-authored source. ### req: component/005 -005 An optional `#[slhx::component]` macro may validate that every handle declared in the template Surface has a corresponding `#[slhx::handler]` within the annotated module. This is the only macro with cross-handler visibility inside a single module; it remains strictly local. Missing handlers without `#[slhx::component]` are caught at app mount or test time, not `cargo check`. +005 An optional `#[hemx::component]` macro may validate that every handle declared in the template Surface has a corresponding `#[hemx::handler]` within the annotated module. This is the only macro with cross-handler visibility inside a single module; it remains strictly local. Missing handlers without `#[hemx::component]` are caught at app mount or test time, not `cargo check`. ### req: component/006 -006 `#[derive(Hemplate)]` structs are natural component boundaries. slhx_build discovers them automatically; no additional configuration is required for most apps. +006 `#[derive(Hemplate)]` structs are natural component boundaries. hemx_build discovers them automatically; no additional configuration is required for most apps. --- ## surface ### req: surface/001 -001 `hemplate_build` may scan `.heml` files and emit `$OUT_DIR/hemplate.surface.postcard` (postcard-encoded, deterministic, versioned). `slhx_build` may also be called in-process with precomputed hemplate Surface facts or, for simple build scripts, ask hemplate to parse/extract the Surface before slhx interprets it. slhx owns no independent `.heml` parser. +001 `hemplate_build` may scan `.heml` files and emit `$OUT_DIR/hemplate.surface.postcard` (postcard-encoded, deterministic, versioned). `hemx_build` may also be called in-process with precomputed hemplate Surface facts or, for simple build scripts, ask hemplate to parse/extract the Surface before hemx interprets it. hemx owns no independent `.heml` parser. ### req: surface/002 002 The Surface contains: nodes (NodeId, parent, scope, element, attrs, source span), scopes (ScopeKind: Root | If | Match | Case | For { binding, key_expr }), forms (form controls with raw HTML types), and component uses. @@ -225,7 +225,7 @@ Category modules such as `targets`, `handles`, and `forms` remain available for 004 Form controls in the Surface carry raw HTML facts: `ControlKind::Text`, `ControlKind::Number { min, max, step }`, `ControlKind::Checkbox`, `ControlKind::Select { multiple, options }`, etc. No Rust type mapping lives in hemplate. ### req: surface/005 -005 Loop scopes expose the binding name and an optional `key_expr` (e.g. `todo.id`). hemplate does not enforce key usage; it only records it for consumers. slhx_build enforces key presence only when a slhx-addressable node appears inside the loop. +005 Loop scopes expose the binding name and an optional `key_expr` (e.g. `todo.id`). hemplate does not enforce key usage; it only records it for consumers. hemx_build enforces key presence only when a hemx-addressable node appears inside the loop. ### req: surface/006 006 Surface schema is versioned (`schema_version: u32`). Postcard encoding, no JSON. `no_std`-compatible schema definition so any tool can read it without heavy dependencies. @@ -236,16 +236,16 @@ Category modules such as `targets`, `handles`, and `forms` remain available for ### req: surface/008 008 The Surface records hemplate structural directives as first-class facts: `h-for`, `h-key`, `h-if`, `h-else-if`, `h-else`, `h-match`, `h-case`, -dynamic `+attr` bindings, and interpolated attr/text expressions. slhx consumes -these facts; if a build script points slhx_build at `.heml` files, hemplate still performs parsing and Surface extraction. +dynamic `+attr` bindings, and interpolated attr/text expressions. hemx consumes +these facts; if a build script points hemx_build at `.heml` files, hemplate still performs parsing and Surface extraction. ### req: surface/009 009 Raw/pre-rendered HTML insertions are opaque Surface holes. The parent -element is present; slhx_build emits the appropriate rendering call. +element is present; hemx_build emits the appropriate rendering call. ### req: surface/010 010 Attribute values preserve their origin: static literal, dynamic `+attr` -binding, or interpolated expression. slhx-build uses this to determine whether +binding, or interpolated expression. hemx-build uses this to determine whether a `data-*` handle param is statically known or runtime-extracted. --- @@ -253,22 +253,22 @@ a `data-*` handle param is statically known or runtime-extracted. ## codegen ### req: codegen/001 -001 `slhx_build` generates three artifacts from the generic Surface IR: (a) `slhx.generated.rs` containing ergonomic resource modules (`slots`, `targets`, `handles`, `forms`, `atoms`), (b) `slhx.syms` for proc-macro validation, (c) runtime id-lowering tables. `slhx_build` interprets tool-specific conventions (`data-slhx-*`, `h-for`, `h-key`, form controls) from the Surface. [north_star] +001 `hemx_build` generates three artifacts from the generic Surface IR: (a) `hemx.generated.rs` containing ergonomic resource modules (`slots`, `targets`, `handles`, `forms`, `atoms`), (b) `hemx.syms` for proc-macro validation, (c) runtime id-lowering tables. `hemx_build` interprets tool-specific conventions (`data-hemx-*`, `h-for`, `h-key`, form controls) from the Surface. [north_star] ### req: codegen/002 002 Generated view modules expose ergonomic root-level target objects and commands that hide render/lower details: text slots provide `set(text)`, singleton partial slots provide `replace(view)`/`clear()`, keyed collection slots provide `append(view)`, `prepend(view)`, `replace(view)`, `remove(key_or_view)`, and forms provide `clear()`/`clear(field)`/`focus(field)`. String-keyed target objects accept displayable domain ids without caller-side `.to_string()` noise. Commands return `impl IntoEffect`, compose in plain Rust, preserve generated lowering, and fail to generate when the template lacks enough facts to infer the slot, key, form, or renderable view type. ### req: codegen/003 -003 Generated module `handles` exports typed constants: `Handle` where `I` is `Form`, a param type, or `()`. Users rarely reference handles directly; they are consumed by `#[slhx::handler]` for validation. +003 Generated module `handles` exports typed constants: `Handle` where `I` is `Form`, a param type, or `()`. Users rarely reference handles directly; they are consumed by `#[hemx::handler]` for validation. ### req: codegen/004 -004 Generated module `forms` exports `FormContract` metadata (field names, HTML control kinds, required). `#[slhx::handler]` compares the `Form` type against the contract. Domain types (`Email`, `TodoId`) remain user-authored; no auto-generated structs. +004 Generated module `forms` exports `FormContract` metadata (field names, HTML control kinds, required). `#[hemx::handler]` compares the `Form` type against the contract. Domain types (`Email`, `TodoId`) remain user-authored; no auto-generated structs. ### req: codegen/005 005 Generated module `atoms` exports `Atom` for values that must be addressable, bootstrapped, or synced. Ordinary Rust fields on app/components are not automatically atoms. ### req: codegen/006 -006 `slhx-build` discovers `data-slhx-on` event names from hemplate Surface inputs and emits generated `slhx::EventName` constants. Event constants are metadata for checked Rust authoring and diagnostics; they do not create a trigger mini-language or new browser runtime semantics. [north_star] +006 `hemx-build` discovers `data-hemx-on` event names from hemplate Surface inputs and emits generated `hemx::EventName` constants. Event constants are metadata for checked Rust authoring and diagnostics; they do not create a trigger mini-language or new browser runtime semantics. [north_star] --- @@ -303,7 +303,7 @@ a `data-*` handle param is statically known or runtime-extracted. 003 `Insert`, `Remove`, and `Move` operate on keyed collection resources. They require a key type checked by generated `KeyedSlot` wrappers. ### req: effect_algebra/004 -004 `Navigate` changes browser history or represents a server redirect. Route matching remains outside slhx core. +004 `Navigate` changes browser history or represents a server redirect. Route matching remains outside hemx core. ### req: effect_algebra/005 005 `Emit` dispatches a native `CustomEvent` and is the only raw JS interop primitive in core. @@ -331,7 +331,7 @@ in core. `Effect::event` lowers to the canonical `Emit` opcode. ### req: scope/001 001 `Scope` is a first-class primitive. Keyed loops (`h-for`) create keyed -dynamic scopes and require `h-key` for slhx-addressable nodes. Conditional +dynamic scopes and require `h-key` for hemx-addressable nodes. Conditional branches (`h-if`, `h-else-if`, `h-else`, `h-match`, `h-case`) create optional presence scopes. Component instances, modals, tabs, and nested forms are scoped resources. Concrete runtime targets are addressed through `ResourceRef` @@ -342,10 +342,10 @@ resources. Concrete runtime targets are addressed through `ResourceRef` ## list ### req: list/001 -001 Any `data-slhx-slot` or `data-slhx-handle` inside a hemplate `h-for` scope requires a stable key. Preferred syntax: ``. Without a key, slhx-addressable nodes inside the loop are rejected at build time. Keyed identity is `ResourceRef { resource: ResourceId, scope: Some(ScopeKey::KeyValue(...)) }`. +001 Any `data-hemx-slot` or `data-hemx-handle` inside a hemplate `h-for` scope requires a stable key. Preferred syntax: ``. Without a key, hemx-addressable nodes inside the loop are rejected at build time. Keyed identity is `ResourceRef { resource: ResourceId, scope: Some(ScopeKey::KeyValue(...)) }`. ### req: list/002 -002 Slots inside a keyed loop receive a composite identity. hemplate records `key_expr` in the Surface; slhx implements keyed slot lookups. +002 Slots inside a keyed loop receive a composite identity. hemplate records `key_expr` in the Surface; hemx implements keyed slot lookups. ### req: list/003 003 Generated helpers for keyed slots are `append(view)`, `prepend(view)`, `replace(view)`, and `remove(key_or_view)` when the template and view type provide an unambiguous `h-key`. Compatibility functions such as `append(keyed_slot, key, view)` may exist as explicit low-level forms. Mismatch between key type and slot key type is a compile-time error, and missing/ambiguous keys are build errors with template spans. @@ -355,7 +355,7 @@ resources. Concrete runtime targets are addressed through `ResourceRef` ## form ### req: form/001 -001 Forms are source of truth in HTML. hemplate Surface exports form shape (controls, names, required, types). slhx checks compatibility with Rust `Form` types through user-authored `#[slhx::form("...")]` domain structs and generated form metadata. No auto-generated structs; domain types (e.g. `Email`) are first-class. The Surface describes; Rust owns; slhx checks. +001 Forms are source of truth in HTML. hemplate Surface exports form shape (controls, names, required, types). hemx checks compatibility with Rust `Form` types through user-authored `#[hemx::form("...")]` domain structs and generated form metadata. No auto-generated structs; domain types (e.g. `Email`) are first-class. The Surface describes; Rust owns; hemx checks. ### req: form/002 002 The handle id is carried as `__h` in POST `application/x-www-form-urlencoded`. A JSON body is allowed at the integration boundary (`application/json`) only if the handler accepts it; core uses form encoding. @@ -364,7 +364,7 @@ resources. Concrete runtime targets are addressed through `ResourceRef` 003 Handler receives `form: Form`. Validation errors target `(FormId, field_name)` or generated control ids. The runtime maps them to originating form controls via control ids derived from Surface `NodeId`, not via slot ids. ### req: form/004 -004 Form compatibility checks validate field presence, optionality, multiplicity, and parser availability. Parser availability means the submitted value type implements `slhx::FormValue` (blanket-provided for `FromStr`, or explicitly implemented for custom parsers). Domain validation remains Rust logic (`TryFrom`, custom validators, or handler code). +004 Form compatibility checks validate field presence, optionality, multiplicity, and parser availability. Parser availability means the submitted value type implements `hemx::FormValue` (blanket-provided for `FromStr`, or explicitly implemented for custom parsers). Domain validation remains Rust logic (`TryFrom`, custom validators, or handler code). ### req: form/005 005 HTML control facts are lower bounds, not complete domain semantics. @@ -385,39 +385,39 @@ what a valid business email is. 002 Form effects target generated form/control ids, not CSS selectors. ### req: form_effects/003 -003 Templates may declare error display targets with `data-slhx-error-for="field"`. Generated form error effects render into those targets when present and fall back to control validity APIs otherwise. +003 Templates may declare error display targets with `data-hemx-error-for="field"`. Generated form error effects render into those targets when present and fall back to control validity APIs otherwise. --- ## wire ### req: wire/001 -001 Authoring HTML uses symbolic `data-slhx-*` attributes. Rendered runtime HTML lowers these to compact numeric metadata: `data-hid`, `data-sid`, optional `data-key`, optional atom ids, optional form/control ids, and `data-slhx-st` for state bootstrap. The browser never sees handler or slot names. `data-slhx-root` marks a scoped root boundary. +001 Authoring HTML uses symbolic `data-hemx-*` attributes. Rendered runtime HTML lowers these to compact numeric metadata: `data-hid`, `data-sid`, optional `data-key`, optional atom ids, optional form/control ids, and `data-hemx-st` for state bootstrap. The browser never sees handler or slot names. `data-hemx-root` marks a scoped root boundary. ### req: wire/002 002 POST bodies carry `application/x-www-form-urlencoded` with distinguished field `__h` (handle id). Server routes by numeric id, not by URL path. ### req: wire/003 -003 HTTP interaction responses may be `text/html` fragments containing `