use std::path::PathBuf;
use crate::template::{
engine::TemplateEngine,
loaders::{FileSystemLoader, LoaderError, TemplateLoader},
};
use super::{Template, TemplateBackend, TemplateError, validate_template_source};
#[derive(Debug)]
pub struct Jinja2 {
dirs: Vec<PathBuf>,
app_dirs: bool,
engine: TemplateEngine,
}
impl Jinja2 {
#[must_use]
pub fn new(dirs: Vec<PathBuf>, app_dirs: bool) -> Self {
Self {
dirs,
app_dirs,
engine: TemplateEngine::new(),
}
}
#[must_use]
pub fn dirs(&self) -> &[PathBuf] {
&self.dirs
}
#[must_use]
pub const fn app_dirs(&self) -> bool {
self.app_dirs
}
#[must_use]
pub fn engine(&self) -> &TemplateEngine {
&self.engine
}
fn search_dirs(&self) -> Vec<PathBuf> {
let mut dirs = self.dirs.clone();
if self.app_dirs {
dirs.extend(self.dirs.iter().map(|dir| dir.join("jinja2")));
}
dirs
}
fn loader(&self) -> FileSystemLoader {
FileSystemLoader::new(self.search_dirs())
}
}
impl Default for Jinja2 {
fn default() -> Self {
Self::new(Vec::new(), false)
}
}
impl TemplateBackend for Jinja2 {
fn from_string(&self, template_string: &str) -> Result<Template, TemplateError> {
validate_template_source("<string>", template_string)?;
Ok(Template::new("<string>", template_string))
}
fn get_template(&self, template_name: &str) -> Result<Template, TemplateError> {
let (source, _) = self
.loader()
.get_template(template_name)
.map_err(map_loader_error)?;
validate_template_source(template_name, &source)?;
Ok(Template::new(template_name, source))
}
}
fn map_loader_error(error: LoaderError) -> TemplateError {
match error {
LoaderError::NotFound(name) => TemplateError::NotFound(name),
LoaderError::Io(error) => {
TemplateError::RenderError(format!("failed to load template: {error}"))
}
}
}