From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/askama_derive/src/lib.rs | 121 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 vendor/askama_derive/src/lib.rs (limited to 'vendor/askama_derive/src') diff --git a/vendor/askama_derive/src/lib.rs b/vendor/askama_derive/src/lib.rs new file mode 100644 index 000000000..35070fe80 --- /dev/null +++ b/vendor/askama_derive/src/lib.rs @@ -0,0 +1,121 @@ +#![deny(elided_lifetimes_in_paths)] + +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 proc_macro::TokenStream; +use proc_macro2::Span; + +use std::collections::HashMap; +use std::path::PathBuf; + +#[proc_macro_derive(Template, attributes(template))] +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(), + } +} + +/// Takes a `syn::DeriveInput` and generates source code for it +/// +/// Reads the metadata from the `template()` attribute to get the template +/// metadata, then fetches the source from the filesystem. The source is +/// 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 { + let config_toml = read_config_file()?; + let config = Config::new(&config_toml)?; + 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 mut sources = HashMap::new(); + find_used_templates(&input, &mut sources, source)?; + + let mut parsed = HashMap::new(); + for (path, src) in &sources { + parsed.insert(path, parse(src, input.syntax)?); + } + + let mut contexts = HashMap::new(); + for (path, nodes) in &parsed { + contexts.insert(*path, Context::new(input.config, path, nodes)?); + } + + let ctx = &contexts[&input.path]; + let heritage = if !ctx.blocks.is_empty() || ctx.extends.is_some() { + Some(Heritage::new(ctx, &contexts)) + } else { + None + }; + + if input.print == Print::Ast || input.print == Print::All { + eprintln!("{:?}", parsed[&input.path]); + } + + let code = generator::generate(&input, &contexts, &heritage, INTEGRATIONS)?; + if input.print == Print::Code || input.print == Print::All { + eprintln!("{}", code); + } + Ok(code) +} + +fn find_used_templates( + input: &TemplateInput<'_>, + map: &mut HashMap, + source: String, +) -> Result<(), CompileError> { + let mut dependency_graph = Vec::new(); + let mut check = vec![(input.path.clone(), source)]; + while let Some((path, source)) = check.pop() { + for n in parse(&source, input.syntax)? { + match n { + Node::Extends(Expr::StrLit(extends)) => { + 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!( + "cyclic dependecy in graph {:#?}", + dependency_graph + .iter() + .map(|e| format!("{:#?} --> {:#?}", e.0, e.1)) + .collect::>() + ))); + } + dependency_graph.push(dependency_path); + let source = get_template_source(&extends)?; + check.push((extends, source)); + } + Node::Import(_, import, _) => { + let import = input.config.find_template(import, Some(&path))?; + let source = get_template_source(&import)?; + check.push((import, source)); + } + _ => {} + } + } + map.insert(path, source); + } + Ok(()) +} + +const INTEGRATIONS: Integrations = Integrations { + actix: cfg!(feature = "actix-web"), + axum: cfg!(feature = "axum"), + gotham: cfg!(feature = "gotham"), + iron: cfg!(feature = "iron"), + mendes: cfg!(feature = "mendes"), + rocket: cfg!(feature = "rocket"), + tide: cfg!(feature = "tide"), + warp: cfg!(feature = "warp"), +}; -- cgit v1.2.3