nargo_template/renderers/
dejavu.rs1#![warn(missing_docs)]
2
3use std::{collections::HashMap, path::Path};
4
5use async_trait::async_trait;
6use oak_core::Parser;
7use oak_dejavu::{DejavuLanguage, DejavuLexer, DejavuParser};
8
9use super::TemplateRenderer;
10
11pub struct DejaVuRenderer {
13 templates: HashMap<String, String>,
14 language: DejavuLanguage,
15}
16
17impl DejaVuRenderer {
18 pub fn new() -> Self {
20 let language = DejavuLanguage::default();
22
23 Self { templates: HashMap::new(), language }
24 }
25
26 pub fn with_template_config(template_config: oak_dejavu::language::TemplateConfig) -> Self {
28 let language = DejavuLanguage { syntax_mode: oak_dejavu::language::SyntaxMode::Template, template: template_config };
29
30 Self { templates: HashMap::new(), language }
31 }
32
33 fn render_content(&self, content: &str, context: &serde_json::Value) -> crate::TemplateResult<String> {
35 let lexer = DejavuLexer::new(&self.language);
37 let parser = DejavuParser::new(&self.language);
38
39 let mut session = oak_core::parser::ParseSession::<DejavuLanguage>::new(16);
41
42 let _parse_result = parser.parse(content, &[], &mut session);
44
45 let mut result = content.to_string();
51
52 if let serde_json::Value::Object(map) = context {
54 for (key, value) in map {
55 let placeholder = format!("{{{{ {} }}}}", key);
56 let value_str = match value {
57 serde_json::Value::String(s) => s.clone(),
58 serde_json::Value::Number(n) => n.to_string(),
59 serde_json::Value::Bool(b) => b.to_string(),
60 _ => value.to_string(),
61 };
62 result = result.replace(&placeholder, &value_str);
63 }
64 }
65
66 Ok(result)
67 }
68}
69
70impl Default for DejaVuRenderer {
71 fn default() -> Self {
72 Self::new()
73 }
74}
75
76#[async_trait]
77impl TemplateRenderer for DejaVuRenderer {
78 fn render(&self, template_name: &str, context: &serde_json::Value) -> crate::TemplateResult<String> {
79 let template_content = self.templates.get(template_name).ok_or_else(|| std::io::Error::new(std::io::ErrorKind::NotFound, format!("Template '{}' not found", template_name)))?;
80
81 self.render_content(template_content, context)
82 }
83
84 fn register_template(&mut self, name: &str, content: &str) -> crate::TemplateResult<()> {
85 self.templates.insert(name.to_string(), content.to_string());
86 Ok(())
87 }
88
89 fn register_template_file(&mut self, name: &str, path: &Path) -> crate::TemplateResult<()> {
90 let content = std::fs::read_to_string(path).map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to read template file '{}': {}", path.display(), e)))?;
91 self.register_template(name, &content)
92 }
93
94 fn register_templates_from_dir(&mut self, dir: &Path, extension: Option<&str>) -> crate::TemplateResult<()> {
95 let dir_path = dir;
96 let ext = extension.unwrap_or("dejavu");
97
98 for entry in walkdir::WalkDir::new(dir_path) {
99 let entry = entry?;
100 let path = entry.path();
101
102 if path.is_file() {
103 if let Some(file_ext) = path.extension() {
104 if file_ext == ext || file_ext == "doki" {
105 let relative_path = path.strip_prefix(dir_path).map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
106 let template_name = relative_path.with_extension("").to_string_lossy().replace(std::path::MAIN_SEPARATOR, "/");
107
108 self.register_template_file(&template_name, path)?;
109 }
110 }
111 }
112 }
113
114 Ok(())
115 }
116}