feat(build): emit checked param tokens

Generate ParamName constants for handle data parameters so public code can refer to checked param metadata instead of stringly typed names.

req: codegen/003
This commit is contained in:
slhx agent
2026-05-26 01:28:51 +02:00
parent 280464017b
commit ba3f40a3f0
4 changed files with 57 additions and 2 deletions
+18
View File
@@ -425,6 +425,22 @@ impl Resources {
));
out.push_str(&format!("{pad}}}\n\n"));
out.push_str(&format!("{pad}#[allow(non_upper_case_globals)]\n{pad}pub mod params {{\n"));
let mut emitted_params = BTreeSet::new();
for res in self.handles.values().filter(|res| component_matches(res, component)) {
if let Some(params) = self.handle_params.get(&res.ident) {
for param in params {
if emitted_params.insert(param.as_str()) {
out.push_str(&format!(
"{inner}pub const {param}: ::slhx::ParamName = ::slhx::ParamName::new({});\n",
rust_str(param)
));
}
}
}
}
out.push_str(&format!("{pad}}}\n\n"));
out.push_str(&format!("{pad}#[allow(non_upper_case_globals)]\n{pad}pub mod atoms {{\n"));
for res in self.atoms.values().filter(|res| component_matches(res, component)) {
out.push_str(&format!(
@@ -1076,6 +1092,8 @@ mod tests {
assert!(generated.contains("pub const todos"));
assert!(generated.contains("pub mod handles"));
assert!(generated.contains("pub const create: ::slhx::Handle<::slhx::Form<::std::string::String>>"));
assert!(generated.contains("pub mod params"));
assert!(generated.contains("pub const todo_id: ::slhx::ParamName = ::slhx::ParamName::new(\"todo_id\")"));
assert!(generated.contains("pub mod forms"));
assert!(generated.contains("pub mod atoms"));
assert!(generated.contains("pub const filter"));
+29
View File
@@ -186,6 +186,35 @@ impl core::fmt::Display for CssClass {
}
}
/// A generated, checked parameter token.
/// req: codegen/003
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct ParamName {
name: &'static str,
}
impl ParamName {
pub const fn new(name: &'static str) -> Self {
Self { name }
}
pub const fn as_str(self) -> &'static str {
self.name
}
}
impl AsRef<str> for ParamName {
fn as_ref(&self) -> &str {
self.name
}
}
impl core::fmt::Display for ParamName {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(self.name)
}
}
/// A generated, checked component token.
/// req: component/003
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+9 -1
View File
@@ -1,7 +1,7 @@
use slhx_core::{
event, navigate, redirect, replace, Atom, AtomSnapshot, AtomState, BuildFingerprint,
ComponentRef, CssClass, CssClasses, Effect, EffectBatch, Form, Handle, IntoEffect, KeyedSlot,
NavigateMode, Payload, ResourceKind, SafeHtml, ScopeKey, Slot,
NavigateMode, ParamName, Payload, ResourceKind, SafeHtml, ScopeKey, Slot,
};
#[test]
@@ -93,6 +93,14 @@ fn slot_html_requires_explicit_safe_html() {
assert_eq!(payload, Payload::Html(String::from("<strong>ok</strong>")));
}
#[test]
fn param_names_format_generated_param_names() {
// req: codegen/003
let param = ParamName::new("todo_id");
assert_eq!(param.as_str(), "todo_id");
assert_eq!(param.to_string(), "todo_id");
}
#[test]
fn component_refs_format_generated_component_names() {
// req: component/003
+1 -1
View File
@@ -50,7 +50,7 @@ pub mod prelude {
pub use slhx_core::{
navigate, push, redirect, replace, Atom, BuildFingerprint, ComponentRef, CssClass,
CssClasses, Effect, EventName, Form, FormModel, FormValue, Handle, IntoEffect, KeyedSlot,
Slot,
ParamName, Slot,
};
pub use crate::{render_html, RenderKeyedSlotExt, RenderSlotExt};
pub use slhx_derive::{app, component, form, handler, surface};