Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 29 additions & 20 deletions askama_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
use askama_shared::heritage::{Context, Heritage};
use askama_shared::input::{Print, Source, TemplateInput};
use askama_shared::parser::{parse, Expr, Node};
use askama_shared::{
generator, get_template_source, read_config_file, CompileError, Config, Integrations,
};
use askama_shared::{generator, get_template_source, read_config_file, Config, Integrations};
use proc_macro::TokenStream;
use proc_macro2::Span;

use std::borrow::Cow;
use std::collections::HashMap;
use std::path::PathBuf;

Expand All @@ -19,9 +18,7 @@ pub fn derive_template(input: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(input).unwrap();
match build_template(&ast) {
Ok(source) => source.parse().unwrap(),
Err(e) => syn::Error::new(Span::call_site(), e)
.to_compile_error()
.into(),
Err(err) => err.to_compile_error().into(),
}
}

Expand All @@ -32,26 +29,36 @@ pub fn derive_template(input: TokenStream) -> TokenStream {
/// parsed, and the parse tree is fed to the code generator. Will print
/// the parse tree and/or generated source according to the `print` key's
/// value as passed to the `template()` attribute.
fn build_template(ast: &syn::DeriveInput) -> Result<String, CompileError> {
let config_toml = read_config_file()?;
let config = Config::new(&config_toml)?;
fn build_template(ast: &syn::DeriveInput) -> Result<String, syn::Error> {
let config_toml = read_config_file().map_err(|msg| syn::Error::new(Span::call_site(), msg))?;
let config =
Config::new(&config_toml).map_err(|msg| syn::Error::new(Span::call_site(), msg))?;
let input = TemplateInput::new(ast, &config)?;
let source: String = match input.source {
Source::Source(ref s) => s.clone(),
Source::Path(_) => get_template_source(&input.path)?,
let (source, span) = match &input.source {
Source::Source(s, span) => (s.clone(), *span),
Source::Path(_, span) => {
let s = get_template_source(&input.path).map_err(|msg| syn::Error::new(*span, msg))?;
(s, *span)
}
};

let mut sources = HashMap::new();
find_used_templates(&input, &mut sources, source)?;
find_used_templates(&input, &mut sources, source).map_err(|msg| syn::Error::new(span, msg))?;

let mut parsed = HashMap::new();
for (path, src) in &sources {
parsed.insert(path.as_path(), parse(src, input.syntax)?);
parsed.insert(
path.as_path(),
parse(src, input.syntax).map_err(|msg| syn::Error::new(span, msg))?,
);
}

let mut contexts = HashMap::new();
for (path, nodes) in &parsed {
contexts.insert(*path, Context::new(input.config, path, nodes)?);
contexts.insert(
*path,
Context::new(input.config, path, nodes).map_err(|msg| syn::Error::new(span, msg))?,
);
}

let ctx = &contexts[input.path.as_path()];
Expand All @@ -65,7 +72,8 @@ fn build_template(ast: &syn::DeriveInput) -> Result<String, CompileError> {
eprintln!("{:?}", parsed[input.path.as_path()]);
}

let code = generator::generate(&input, &contexts, heritage.as_ref(), INTEGRATIONS)?;
let code = generator::generate(&input, &contexts, heritage.as_ref(), INTEGRATIONS)
.map_err(|msg| syn::Error::new(span, msg))?;
if input.print == Print::Code || input.print == Print::All {
eprintln!("{}", code);
}
Expand All @@ -76,7 +84,7 @@ fn find_used_templates(
input: &TemplateInput<'_>,
map: &mut HashMap<PathBuf, String>,
source: String,
) -> Result<(), CompileError> {
) -> Result<(), Cow<'static, str>> {
let mut dependency_graph = Vec::new();
let mut check = vec![(input.path.clone(), source)];
while let Some((path, source)) = check.pop() {
Expand All @@ -86,13 +94,14 @@ fn find_used_templates(
let extends = input.config.find_template(extends, Some(&path))?;
let dependency_path = (path.clone(), extends.clone());
if dependency_graph.contains(&dependency_path) {
return Err(CompileError::String(format!(
return Err(format!(
"cyclic dependecy in graph {:#?}",
dependency_graph
.iter()
.map(|e| format!("{:#?} --> {:#?}", e.0, e.1))
.collect::<Vec<String>>()
)));
.collect::<Vec<String>>(),
)
.into());
}
dependency_graph.push(dependency_path);
let source = get_template_source(&extends)?;
Expand Down
Loading