feat(build): emit checked component refs

Generate ComponentRef constants for component-scoped APIs, include global component refs only when global_exports(true) is enabled, and document/use the checked component token.

req: component/003
This commit is contained in:
slhx agent
2026-05-26 00:35:59 +02:00
parent a421865852
commit efabd3ff66
5 changed files with 73 additions and 6 deletions
+29
View File
@@ -330,6 +330,7 @@ impl Resources {
// req: build/001 req: component/003
if global_exports {
self.push_component_refs(&mut out, 0);
self.push_resource_modules(&mut out, None, 0);
self.push_lowering_api(&mut out, None, 0);
}
@@ -346,11 +347,31 @@ impl Resources {
out
}
fn push_component_refs(&self, out: &mut String, indent: usize) {
let pad = " ".repeat(indent);
let inner = " ".repeat(indent + 1);
out.push_str(&format!("{pad}#[allow(non_upper_case_globals)]\n{pad}pub mod components {{\n"));
for component in self.component_names() {
out.push_str(&format!(
"{inner}pub const {component}: ::slhx::ComponentRef = ::slhx::ComponentRef::new({});\n",
rust_str(&component)
));
}
out.push_str(&format!("{pad}}}\n"));
}
fn push_resource_modules(&self, out: &mut String, component: Option<&str>, indent: usize) {
let pad = " ".repeat(indent);
let inner = " ".repeat(indent + 1);
let mut handle_ids = Vec::new();
if let Some(component) = component {
out.push_str(&format!(
"{pad}pub const COMPONENT: ::slhx::ComponentRef = ::slhx::ComponentRef::new({});\n",
rust_str(component)
));
}
out.push_str(&format!("{pad}#[allow(non_upper_case_globals)]\n{pad}pub mod slots {{\n"));
for res in self.slots.values().filter(|res| component_matches(res, component)) {
if res.keyed {
@@ -1035,6 +1056,8 @@ mod tests {
app().template_dir(&templates).out_dir(&out).global_exports(true).run().unwrap();
let generated = std::fs::read_to_string(out.join("slhx.generated.rs")).unwrap();
assert!(generated.contains("pub mod components"));
assert!(generated.contains("pub const todo: ::slhx::ComponentRef = ::slhx::ComponentRef::new(\"todo\")"));
assert!(generated.contains("pub mod slots"));
assert!(generated.contains("pub const todos"));
assert!(generated.contains("pub mod handles"));
@@ -1084,9 +1107,11 @@ mod tests {
app().template_dir(&templates).out_dir(&out).run().unwrap();
let generated = std::fs::read_to_string(out.join("slhx.generated.rs")).unwrap();
assert!(!generated.contains("\n#[allow(non_upper_case_globals)]\npub mod components"));
assert!(!generated.contains("\n#[allow(non_upper_case_globals)]\npub mod slots"));
assert!(!generated.contains("\npub fn lower_html"));
assert!(generated.contains("pub mod todo"));
assert!(generated.contains(" pub const COMPONENT: ::slhx::ComponentRef = ::slhx::ComponentRef::new(\"todo\")"));
assert!(generated.contains(" pub mod slots"));
assert!(generated.contains(" pub fn lower_html"));
@@ -1201,6 +1226,8 @@ mod slhx {{
impl<T> Form<T> {{ pub const fn new(_: u32) -> Self {{ Self(::std::marker::PhantomData) }} }}
#[derive(Clone, Copy)] pub struct CssClass(&'static str);
impl CssClass {{ pub const fn new(name: &'static str) -> Self {{ Self(name) }} pub const fn as_str(self) -> &'static str {{ self.0 }} }}
#[derive(Clone, Copy)] pub struct ComponentRef(&'static str);
impl ComponentRef {{ pub const fn new(name: &'static str) -> Self {{ Self(name) }} pub const fn as_str(self) -> &'static str {{ self.0 }} }}
pub struct FormContract {{ pub fields: &'static [FormField] }}
pub struct FormField {{ pub name: &'static str, pub kind: FormControlKind, pub required: bool }}
pub enum FormControlKind {{ Text, Number {{ min: Option<&'static str>, max: Option<&'static str>, step: Option<&'static str> }}, Checkbox, Radio, Select {{ multiple: bool }}, TextArea, File, Hidden, Submit, Other {{ tag: &'static str, input_type: Option<&'static str> }} }}
@@ -1292,6 +1319,8 @@ mod slhx {{
impl<T> Atom<T> {{ pub const fn new(_: u32) -> Self {{ Self(::std::marker::PhantomData) }} }}
#[derive(Clone, Copy)] pub struct Form<T>(::std::marker::PhantomData<T>);
impl<T> Form<T> {{ pub const fn new(_: u32) -> Self {{ Self(::std::marker::PhantomData) }} }}
#[derive(Clone, Copy)] pub struct ComponentRef(&'static str);
impl ComponentRef {{ pub const fn new(name: &'static str) -> Self {{ Self(name) }} pub const fn as_str(self) -> &'static str {{ self.0 }} }}
pub struct FormContract {{ pub fields: &'static [FormField] }}
pub struct FormField {{ pub name: &'static str, pub kind: FormControlKind, pub required: bool }}
pub enum FormControlKind {{ Text, Number {{ min: Option<&'static str>, max: Option<&'static str>, step: Option<&'static str> }}, Checkbox, Radio, Select {{ multiple: bool }}, TextArea, File, Hidden, Submit, Other {{ tag: &'static str, input_type: Option<&'static str> }} }}