diff options
Diffstat (limited to '')
| -rw-r--r-- | askama_shared/src/generator.rs | 111 | ||||
| -rw-r--r-- | askama_shared/src/input.rs | 112 | 
2 files changed, 125 insertions, 98 deletions
diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs index 7eb5fbe..a09631c 100644 --- a/askama_shared/src/generator.rs +++ b/askama_shared/src/generator.rs @@ -28,9 +28,10 @@ pub fn derive_template(input: TokenStream) -> TokenStream {  /// 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 template_args = TemplateArgs::new(ast)?;      let config_toml = read_config_file()?;      let config = Config::new(&config_toml)?; -    let input = TemplateInput::new(ast, &config)?; +    let input = TemplateInput::new(ast, &config, template_args)?;      let source: String = match input.source {          Source::Source(ref s) => s.clone(),          Source::Path(_) => get_template_source(&input.path)?, @@ -74,6 +75,114 @@ fn build_template(ast: &syn::DeriveInput) -> Result<String, CompileError> {      Ok(code)  } +#[derive(Default)] +pub(crate) struct TemplateArgs { +    pub(crate) source: Option<Source>, +    pub(crate) print: Print, +    pub(crate) escaping: Option<String>, +    pub(crate) ext: Option<String>, +    pub(crate) syntax: Option<String>, +} + +impl TemplateArgs { +    fn new(ast: &'_ syn::DeriveInput) -> Result<Self, CompileError> { +        // Check that an attribute called `template()` exists once and that it is +        // the proper type (list). +        let mut template_args = None; +        for attr in &ast.attrs { +            let ident = match attr.path.get_ident() { +                Some(ident) => ident, +                None => continue, +            }; + +            if ident == "template" { +                if template_args.is_some() { +                    return Err("duplicated 'template' attribute".into()); +                } + +                match attr.parse_meta() { +                    Ok(syn::Meta::List(syn::MetaList { nested, .. })) => { +                        template_args = Some(nested); +                    } +                    Ok(_) => return Err("'template' attribute must be a list".into()), +                    Err(e) => return Err(format!("unable to parse attribute: {}", e).into()), +                } +            } +        } +        let template_args = +            template_args.ok_or_else(|| CompileError::from("no attribute 'template' found"))?; + +        let mut args = Self::default(); +        // Loop over the meta attributes and find everything that we +        // understand. Return a CompileError if something is not right. +        // `source` contains an enum that can represent `path` or `source`. +        for item in template_args { +            let pair = match item { +                syn::NestedMeta::Meta(syn::Meta::NameValue(ref pair)) => pair, +                _ => { +                    return Err(format!( +                        "unsupported attribute argument {:?}", +                        item.to_token_stream() +                    ) +                    .into()) +                } +            }; +            let ident = match pair.path.get_ident() { +                Some(ident) => ident, +                None => unreachable!("not possible in syn::Meta::NameValue(…)"), +            }; + +            if ident == "path" { +                if let syn::Lit::Str(ref s) = pair.lit { +                    if args.source.is_some() { +                        return Err("must specify 'source' or 'path', not both".into()); +                    } +                    args.source = Some(Source::Path(s.value())); +                } else { +                    return Err("template path must be string literal".into()); +                } +            } else if ident == "source" { +                if let syn::Lit::Str(ref s) = pair.lit { +                    if args.source.is_some() { +                        return Err("must specify 'source' or 'path', not both".into()); +                    } +                    args.source = Some(Source::Source(s.value())); +                } else { +                    return Err("template source must be string literal".into()); +                } +            } else if ident == "print" { +                if let syn::Lit::Str(ref s) = pair.lit { +                    args.print = s.value().parse()?; +                } else { +                    return Err("print value must be string literal".into()); +                } +            } else if ident == "escape" { +                if let syn::Lit::Str(ref s) = pair.lit { +                    args.escaping = Some(s.value()); +                } else { +                    return Err("escape value must be string literal".into()); +                } +            } else if ident == "ext" { +                if let syn::Lit::Str(ref s) = pair.lit { +                    args.ext = Some(s.value()); +                } else { +                    return Err("ext value must be string literal".into()); +                } +            } else if ident == "syntax" { +                if let syn::Lit::Str(ref s) = pair.lit { +                    args.syntax = Some(s.value()) +                } else { +                    return Err("syntax value must be string literal".into()); +                } +            } else { +                return Err(format!("unsupported attribute key {:?} found", ident).into()); +            } +        } + +        Ok(args) +    } +} +  fn find_used_templates(      input: &TemplateInput<'_>,      map: &mut HashMap<PathBuf, String>, diff --git a/askama_shared/src/input.rs b/askama_shared/src/input.rs index c70b250..6c49156 100644 --- a/askama_shared/src/input.rs +++ b/askama_shared/src/input.rs @@ -1,10 +1,10 @@ +use crate::generator::TemplateArgs;  use crate::{CompileError, Config, Syntax};  use std::path::{Path, PathBuf};  use std::str::FromStr;  use mime::Mime; -use quote::ToTokens;  pub(crate) struct TemplateInput<'a> {      pub(crate) ast: &'a syn::DeriveInput, @@ -27,103 +27,15 @@ impl TemplateInput<'_> {      pub(crate) fn new<'n>(          ast: &'n syn::DeriveInput,          config: &'n Config<'_>, +        args: TemplateArgs,      ) -> Result<TemplateInput<'n>, CompileError> { -        // Check that an attribute called `template()` exists once and that it is -        // the proper type (list). -        let mut template_args = None; -        for attr in &ast.attrs { -            let ident = match attr.path.get_ident() { -                Some(ident) => ident, -                None => continue, -            }; - -            if ident == "template" { -                if template_args.is_some() { -                    return Err("duplicated 'template' attribute".into()); -                } - -                match attr.parse_meta() { -                    Ok(syn::Meta::List(syn::MetaList { nested, .. })) => { -                        template_args = Some(nested); -                    } -                    Ok(_) => return Err("'template' attribute must be a list".into()), -                    Err(e) => return Err(format!("unable to parse attribute: {}", e).into()), -                } -            } -        } -        let template_args = -            template_args.ok_or_else(|| CompileError::from("no attribute 'template' found"))?; - -        // Loop over the meta attributes and find everything that we -        // understand. Return a CompileError if something is not right. -        // `source` contains an enum that can represent `path` or `source`. -        let mut source = None; -        let mut print = Print::None; -        let mut escaping = None; -        let mut ext = None; -        let mut syntax = None; -        for item in template_args { -            let pair = match item { -                syn::NestedMeta::Meta(syn::Meta::NameValue(ref pair)) => pair, -                _ => { -                    return Err(format!( -                        "unsupported attribute argument {:?}", -                        item.to_token_stream() -                    ) -                    .into()) -                } -            }; -            let ident = match pair.path.get_ident() { -                Some(ident) => ident, -                None => unreachable!("not possible in syn::Meta::NameValue(…)"), -            }; - -            if ident == "path" { -                if let syn::Lit::Str(ref s) = pair.lit { -                    if source.is_some() { -                        return Err("must specify 'source' or 'path', not both".into()); -                    } -                    source = Some(Source::Path(s.value())); -                } else { -                    return Err("template path must be string literal".into()); -                } -            } else if ident == "source" { -                if let syn::Lit::Str(ref s) = pair.lit { -                    if source.is_some() { -                        return Err("must specify 'source' or 'path', not both".into()); -                    } -                    source = Some(Source::Source(s.value())); -                } else { -                    return Err("template source must be string literal".into()); -                } -            } else if ident == "print" { -                if let syn::Lit::Str(ref s) = pair.lit { -                    print = s.value().parse()?; -                } else { -                    return Err("print value must be string literal".into()); -                } -            } else if ident == "escape" { -                if let syn::Lit::Str(ref s) = pair.lit { -                    escaping = Some(s.value()); -                } else { -                    return Err("escape value must be string literal".into()); -                } -            } else if ident == "ext" { -                if let syn::Lit::Str(ref s) = pair.lit { -                    ext = Some(s.value()); -                } else { -                    return Err("ext value must be string literal".into()); -                } -            } else if ident == "syntax" { -                if let syn::Lit::Str(ref s) = pair.lit { -                    syntax = Some(s.value()) -                } else { -                    return Err("syntax value must be string literal".into()); -                } -            } else { -                return Err(format!("unsupported attribute key {:?} found", ident).into()); -            } -        } +        let TemplateArgs { +            source, +            print, +            escaping, +            ext, +            syntax, +        } = args;          // Validate the `source` and `ext` value together, since they are          // related. In case `source` was used instead of `path`, the value @@ -261,6 +173,12 @@ impl FromStr for Print {      }  } +impl Default for Print { +    fn default() -> Self { +        Self::None +    } +} +  #[doc(hidden)]  pub fn extension_to_mime_type(ext: &str) -> Mime {      let basic_type = mime_guess::from_ext(ext).first_or_octet_stream();  | 
