feat(build): accept precomputed surface facts
Allow slhx-build callers to feed hemplate SurfaceDocument facts directly, preserving the existing .heml parse fallback while covering the build-from-surface path. req: surface/008 req: build/001
This commit is contained in:
+49
-8
@@ -14,6 +14,7 @@ pub struct AppBuilder {
|
||||
out_dir: Option<PathBuf>,
|
||||
template_dir: PathBuf,
|
||||
global_exports: bool,
|
||||
surfaces: Vec<(PathBuf, SurfaceDocument)>,
|
||||
}
|
||||
|
||||
impl AppBuilder {
|
||||
@@ -32,6 +33,11 @@ impl AppBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn surface(mut self, path: impl Into<PathBuf>, surface: SurfaceDocument) -> Self {
|
||||
self.surfaces.push((path.into(), surface));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn run(self) -> io::Result<()> {
|
||||
println!("cargo:rerun-if-changed={}", self.template_dir.display());
|
||||
|
||||
@@ -46,14 +52,21 @@ impl AppBuilder {
|
||||
std::fs::create_dir_all(&out_dir)?;
|
||||
|
||||
let mut resources = Resources::default();
|
||||
for path in collect_heml(&self.template_dir)? {
|
||||
let source = std::fs::read_to_string(&path)?;
|
||||
let doc = build_ast(Arc::new(source)).map_err(|err| parse_error(&path, err))?;
|
||||
let Some(doc) = doc else {
|
||||
continue;
|
||||
};
|
||||
let surface = extract_surface(&doc);
|
||||
resources.add_surface(&self.template_dir, &path, &surface)?;
|
||||
if self.surfaces.is_empty() {
|
||||
for path in collect_heml(&self.template_dir)? {
|
||||
let source = std::fs::read_to_string(&path)?;
|
||||
let doc = build_ast(Arc::new(source)).map_err(|err| parse_error(&path, err))?;
|
||||
let Some(doc) = doc else {
|
||||
continue;
|
||||
};
|
||||
let surface = extract_surface(&doc);
|
||||
resources.add_surface(&self.template_dir, &path, &surface)?;
|
||||
}
|
||||
} else {
|
||||
// req: surface/008
|
||||
for (path, surface) in &self.surfaces {
|
||||
resources.add_surface(&self.template_dir, path, surface)?;
|
||||
}
|
||||
}
|
||||
for path in collect_stylesheets(&self.template_dir)? {
|
||||
let source = std::fs::read_to_string(&path)?;
|
||||
@@ -74,6 +87,7 @@ pub fn app() -> AppBuilder {
|
||||
out_dir: None,
|
||||
template_dir: PathBuf::from("templates"),
|
||||
global_exports: false,
|
||||
surfaces: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1090,6 +1104,33 @@ mod tests {
|
||||
let _ = std::fs::remove_dir_all(&base);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn app_can_consume_precomputed_surface_facts() {
|
||||
// req: surface/008 req: build/001
|
||||
let base = test_dir("slhx-build-precomputed-surface-test");
|
||||
let templates = base.join("templates");
|
||||
let out = base.join("out");
|
||||
let _ = std::fs::remove_dir_all(&base);
|
||||
std::fs::create_dir_all(&templates).unwrap();
|
||||
let path = templates.join("todo.heml");
|
||||
let source = Arc::new(
|
||||
r#"<button data-slhx-handle="create" data-slhx-on="click">Create</button><div data-slhx-slot="todos"></div>"#
|
||||
.to_string(),
|
||||
);
|
||||
let ast = build_ast(source).unwrap().unwrap();
|
||||
let surface = extract_surface(&ast);
|
||||
|
||||
app().template_dir(&templates).out_dir(&out).surface(&path, surface).run().unwrap();
|
||||
|
||||
let generated = std::fs::read_to_string(out.join("slhx.generated.rs")).unwrap();
|
||||
assert!(generated.contains("pub mod todo"));
|
||||
assert!(generated.contains("pub const create: ::slhx::Handle<()> = ::slhx::Handle::new("));
|
||||
assert!(generated.contains("pub const todos: ::slhx::Slot<::std::string::String> = ::slhx::Slot::new("));
|
||||
assert!(generated.contains("pub const click: ::slhx::EventName = ::slhx::EventName::new(\"click\")"));
|
||||
|
||||
let _ = std::fs::remove_dir_all(&base);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn global_resource_exports_are_explicit_opt_in() {
|
||||
// req: component/003
|
||||
|
||||
Reference in New Issue
Block a user