use include_dir::{include_dir, Dir}; use std::path::Path; use anyhow::{Result, Context}; use tera::{Tera, Context as TeraContext}; use std::fs; // Embed all template files at compile time static TEMPLATES_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/templates"); pub struct TemplateEngine { #[allow(dead_code)] tera: Tera, } impl TemplateEngine { #[allow(dead_code)] pub fn new() -> Result { let mut tera = Tera::default(); // Load all templates from embedded directory for file in TEMPLATES_DIR.files() { let path = file.path().to_string_lossy(); let contents = file.contents_utf8() .context("Template must be valid UTF-8")?; tera.add_raw_template(&path, contents)?; } Ok(Self { tera }) } #[allow(dead_code)] pub fn render_to_file( &self, template_name: &str, output_path: &Path, context: &TeraContext, ) -> Result<()> { let rendered = self.tera.render(template_name, context)?; if let Some(parent) = output_path.parent() { fs::create_dir_all(parent)?; } fs::write(output_path, rendered)?; Ok(()) } #[allow(dead_code)] pub fn extract_static_file(&self, template_path: &str, output_path: &Path) -> Result<()> { let file = TEMPLATES_DIR .get_file(template_path) .context(format!("Template not found: {}", template_path))?; if let Some(parent) = output_path.parent() { fs::create_dir_all(parent)?; } fs::write(output_path, file.contents())?; Ok(()) } #[allow(dead_code)] pub fn list_templates(&self) -> Vec { TEMPLATES_DIR .files() .map(|f| f.path().to_string_lossy().to_string()) .collect() } } #[cfg(test)] mod tests { use super::*; use tempfile::TempDir; #[test] fn test_template_engine_creation() { let engine = TemplateEngine::new(); assert!(engine.is_ok()); } #[test] fn test_list_templates() { let engine = TemplateEngine::new().unwrap(); let templates = engine.list_templates(); assert!(!templates.is_empty()); } #[test] fn test_render_template() { let _engine = TemplateEngine::new().unwrap(); let temp = TempDir::new().unwrap(); let _output = temp.path().join("test.txt"); let mut context = TeraContext::new(); context.insert("project_name", "TestRobot"); // This will fail until we add templates, but shows the pattern // engine.render_to_file("README.md", &output, &context).unwrap(); } }