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
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "hemx"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
hemplate = { path = "../../hemplate/hemplate" }
|
||||
hemx-core = { path = "../hemx-core" }
|
||||
hemx-derive = { path = "../hemx-derive" }
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
//! Public authoring facade for hemx applications.
|
||||
//!
|
||||
//! Most application code should depend on this crate, use the proc-macros from
|
||||
//! here, and import generated resources through `#[hemx::surface]`.
|
||||
|
||||
use hemx_core::{Effect, KeyedSlot, SafeHtml, Slot};
|
||||
|
||||
pub use hemx_core::{
|
||||
navigate, push, redirect, replace, Atom, ComponentRef, CssClass, CssClasses, EventName, Form,
|
||||
FormContract, FormControlKind, FormError, FormField, FormModel, FormValue, FromForm,
|
||||
GeneratedTarget, Handle, IntoEffect, ParamName,
|
||||
};
|
||||
pub use hemx_derive::{app, component, form, handler, surface};
|
||||
|
||||
/// Advanced/raw hemx primitives used by generated code, integrations, and tests.
|
||||
///
|
||||
/// Beginner-facing application code should prefer generated targets, generated
|
||||
/// handles/forms/classes, `Html`, `IntoEffect`, and tuple composition. req: dx/001 req: public_api/005
|
||||
pub mod advanced {
|
||||
pub use hemx_core::*;
|
||||
}
|
||||
|
||||
/// Rendered, checked HTML produced by hemplate/hemx rendering helpers.
|
||||
///
|
||||
/// Raw trusted HTML construction remains an advanced boundary; beginner-facing
|
||||
/// code should receive `Html` values from generated render helpers. req: public_api/005
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct Html(SafeHtml);
|
||||
|
||||
impl Html {
|
||||
pub fn as_str(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
|
||||
pub fn into_string(self) -> String {
|
||||
self.0.into_string()
|
||||
}
|
||||
|
||||
pub fn join(fragments: impl IntoIterator<Item = Html>) -> Self {
|
||||
Self(SafeHtml::join(fragments.into_iter().map(Into::into)))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Html> for SafeHtml {
|
||||
fn from(value: Html) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Html {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for Html {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.write_str(self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod __private {
|
||||
use super::{Html, SafeHtml};
|
||||
|
||||
pub fn html_trusted(value: impl Into<String>) -> Html {
|
||||
Html(SafeHtml::trusted(value))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(view: &impl hemplate::Hemplate) -> Html {
|
||||
let mut html = String::new();
|
||||
view.render_into(&mut html)
|
||||
.expect("hemplate view renders into hemx effect payload");
|
||||
__private::html_trusted(html)
|
||||
}
|
||||
|
||||
/// A hemplate partial that carries the stable key for a generated keyed target.
|
||||
///
|
||||
/// Generated keyed target helpers use this to keep ordinary handler code at the
|
||||
/// level of `ui::row.replace(row)` instead of `ui::row.replace(row.id, &row)`.
|
||||
/// req: canonical_authoring/003 req: codegen/002
|
||||
pub trait KeyedPartial {
|
||||
fn hemx_key(&self) -> String;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn render_html(view: &impl hemplate::Hemplate) -> Html {
|
||||
render(view)
|
||||
}
|
||||
|
||||
/// Compatibility shim for raw slot rendering.
|
||||
///
|
||||
/// Prefer generated target objects such as `targets::list.put(&view)` so
|
||||
/// generated resource lowering stays attached to the view boundary. req: dx/006
|
||||
#[doc(hidden)]
|
||||
pub trait RenderSlotExt {
|
||||
fn render(self, view: &impl hemplate::Hemplate) -> Effect;
|
||||
|
||||
fn render_view(self, view: &impl hemplate::Hemplate) -> Effect
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.render(view)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RenderSlotExt for Slot<T> {
|
||||
fn render(self, view: &impl hemplate::Hemplate) -> Effect {
|
||||
self.html(render(view))
|
||||
}
|
||||
}
|
||||
|
||||
/// Compatibility shim for raw keyed slot rendering.
|
||||
///
|
||||
/// Prefer generated target objects such as `targets::row.append(&view)` so
|
||||
/// generated resource lowering stays attached to the view boundary. req: dx/006
|
||||
#[doc(hidden)]
|
||||
pub trait RenderKeyedSlotExt<K> {
|
||||
fn append(self, key: K, view: &impl hemplate::Hemplate) -> Effect;
|
||||
fn prepend(self, key: K, view: &impl hemplate::Hemplate) -> Effect;
|
||||
fn replace(self, key: K, view: &impl hemplate::Hemplate) -> Effect;
|
||||
|
||||
fn append_view(self, key: K, view: &impl hemplate::Hemplate) -> Effect
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.append(key, view)
|
||||
}
|
||||
|
||||
fn prepend_view(self, key: K, view: &impl hemplate::Hemplate) -> Effect
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.prepend(key, view)
|
||||
}
|
||||
|
||||
fn replace_view(self, key: K, view: &impl hemplate::Hemplate) -> Effect
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.replace(key, view)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, T> RenderKeyedSlotExt<K> for KeyedSlot<K, T>
|
||||
where
|
||||
K: ToString,
|
||||
{
|
||||
fn append(self, key: K, view: &impl hemplate::Hemplate) -> Effect {
|
||||
self.append_html(key, render(view))
|
||||
}
|
||||
|
||||
fn prepend(self, key: K, view: &impl hemplate::Hemplate) -> Effect {
|
||||
self.prepend_html(key, render(view))
|
||||
}
|
||||
|
||||
fn replace(self, key: K, view: &impl hemplate::Hemplate) -> Effect {
|
||||
self.replace_html(key, render(view))
|
||||
}
|
||||
}
|
||||
|
||||
pub mod prelude {
|
||||
pub use crate::render;
|
||||
pub use crate::Html;
|
||||
pub use hemx_core::{
|
||||
navigate, push, redirect, replace, Atom, ComponentRef, CssClass, CssClasses, EventName,
|
||||
Form, FormModel, FormValue, Handle, IntoEffect, ParamName,
|
||||
};
|
||||
pub use hemx_derive::{app, component, form, handler, surface};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
struct InlineView;
|
||||
|
||||
impl hemplate::Hemplate for InlineView {
|
||||
fn render_into(&self, out: &mut String) -> Result<(), hemplate::error::HemplateError> {
|
||||
out.push_str("<strong>ok</strong>");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_is_the_short_safe_html_helper() {
|
||||
// req: dx/006 req: html_safety/002
|
||||
assert_eq!(crate::render(&InlineView).as_str(), "<strong>ok</strong>");
|
||||
assert_eq!(
|
||||
crate::render_html(&InlineView).as_str(),
|
||||
"<strong>ok</strong>"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prelude_exports_html_for_page_composition() {
|
||||
// req: dx/006 req: public_api/005 req: html_safety/002
|
||||
use crate::prelude::*;
|
||||
|
||||
let html = Html::join([render(&InlineView)]);
|
||||
|
||||
assert_eq!(html.as_str(), "<strong>ok</strong>");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user