vika_cli/templates/
engine.rs1use crate::error::{Result, TemplateError};
2use crate::templates::registry::TemplateId;
3use crate::templates::resolver::TemplateResolver;
4use serde::Serialize;
5use std::path::Path;
6use tera::{Context, Tera};
7
8pub struct TemplateEngine {
10 tera: Tera,
11 resolver: TemplateResolver,
12}
13
14impl TemplateEngine {
15 pub fn new(project_root: Option<&Path>) -> Result<Self> {
19 let resolver = TemplateResolver::new(project_root);
20 let mut tera = Tera::default();
21
22 for template_id in TemplateId::all() {
24 let template_content = resolver.resolve(template_id)?;
25 let template_name = template_id.filename();
26
27 tera.add_raw_template(&template_name, &template_content)
28 .map_err(|e| {
29 crate::error::GenerationError::Template(TemplateError::InvalidSyntax {
30 name: template_name.to_string(),
31 message: e.to_string(),
32 })
33 })?;
34 }
35
36 Ok(Self { tera, resolver })
37 }
38
39 pub fn render<T: Serialize>(&self, template_id: TemplateId, context: &T) -> Result<String> {
41 let template_name = template_id.filename();
42
43 let json_value = serde_json::to_value(context).map_err(|e| {
44 crate::error::GenerationError::Template(TemplateError::RenderFailed {
45 name: template_name.to_string(),
46 message: format!("Failed to serialize context: {}", e),
47 })
48 })?;
49 let tera_context = Context::from_serialize(&json_value).map_err(|e| {
50 crate::error::GenerationError::Template(TemplateError::RenderFailed {
51 name: template_name.to_string(),
52 message: format!("Failed to create Tera context: {}", e),
53 })
54 })?;
55
56 self.tera
57 .render(&template_name, &tera_context)
58 .map_err(|e| {
59 crate::error::GenerationError::Template(TemplateError::RenderFailed {
60 name: template_name.to_string(),
61 message: e.to_string(),
62 })
63 })
64 .map_err(Into::into)
65 }
66
67 pub fn is_overridden(&self, template_id: TemplateId) -> bool {
69 self.resolver.is_overridden(template_id)
70 }
71
72 pub fn list_templates(&self) -> Result<Vec<(String, bool)>> {
74 self.resolver.list_templates()
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use crate::templates::context::TypeContext;
82
83 #[test]
84 fn test_template_engine_new() {
85 let engine = TemplateEngine::new(None);
86 assert!(engine.is_ok());
87 }
88
89 #[test]
90 fn test_template_engine_render_enum() {
91 let engine = TemplateEngine::new(None).unwrap();
92 let context = TypeContext::enum_type(
93 "TestEnum".to_string(),
94 vec!["A".to_string(), "B".to_string()],
95 None,
96 );
97 let result = engine.render(TemplateId::TypeEnum, &context);
98 assert!(result.is_ok());
99 let output = result.unwrap();
100 assert!(output.contains("TestEnum"));
101 assert!(output.contains("A"));
102 assert!(output.contains("B"));
103 }
104}