From 2dfc3a39eb4943eb5e320c631e7ae9e50ec6357d Mon Sep 17 00:00:00 2001
From: Dirkjan Ochtman <dirkjan@ochtman.nl>
Date: Thu, 10 Jan 2019 17:20:18 +0100
Subject: Allow configuration of escape modes

---
 askama_shared/src/lib.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

(limited to 'askama_shared/src')

diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs
index a0c9321..0daad1b 100644
--- a/askama_shared/src/lib.rs
+++ b/askama_shared/src/lib.rs
@@ -4,6 +4,7 @@ extern crate serde_derive;
 
 use toml;
 
+use std::collections::HashSet;
 use std::env;
 use std::fs;
 use std::path::{Path, PathBuf};
@@ -23,6 +24,7 @@ pub struct Config<'a> {
     pub dirs: Vec<PathBuf>,
     pub syntaxes: BTreeMap<String, Syntax<'a>>,
     pub default_syntax: &'a str,
+    pub escapers: Vec<(HashSet<String>, String)>,
 }
 
 impl<'a> Config<'a> {
@@ -63,10 +65,28 @@ impl<'a> Config<'a> {
             panic!("default syntax \"{}\" not found", default_syntax)
         }
 
+        let mut escapers = Vec::new();
+        if let Some(configured) = raw.escaper {
+            for escaper in configured {
+                escapers.push((
+                    escaper
+                        .extensions
+                        .iter()
+                        .map(|ext| ext.to_string())
+                        .collect(),
+                    escaper.path.to_string(),
+                ));
+            }
+        }
+        for (extensions, path) in DEFAULT_ESCAPERS {
+            escapers.push((str_set(extensions), path.to_string()));
+        }
+
         Config {
             dirs,
             syntaxes,
             default_syntax,
+            escapers,
         }
     }
 
@@ -156,6 +176,7 @@ struct RawConfig<'d> {
     #[serde(borrow)]
     general: Option<General<'d>>,
     syntax: Option<Vec<RawSyntax<'d>>>,
+    escaper: Option<Vec<RawEscaper<'d>>>,
 }
 
 #[derive(Deserialize)]
@@ -176,6 +197,12 @@ struct RawSyntax<'a> {
     comment_end: Option<&'a str>,
 }
 
+#[derive(Deserialize)]
+struct RawEscaper<'a> {
+    path: &'a str,
+    extensions: Vec<&'a str>,
+}
+
 pub fn read_config_file() -> String {
     let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
     let filename = root.join(CONFIG_FILE_NAME);
@@ -187,8 +214,19 @@ pub fn read_config_file() -> String {
     }
 }
 
+fn str_set<T>(vals: &[T]) -> HashSet<String>
+where
+    T: ToString,
+{
+    vals.iter().map(|s| s.to_string()).collect()
+}
+
 static CONFIG_FILE_NAME: &str = "askama.toml";
 static DEFAULT_SYNTAX_NAME: &str = "default";
+static DEFAULT_ESCAPERS: &[(&[&str], &str)] = &[
+    (&["html", "htm", "xml"], "::askama::Html"),
+    (&["none", "txt", ""], "::askama::Text"),
+];
 
 #[cfg(test)]
 mod tests {
@@ -350,4 +388,23 @@ mod tests {
 
         let _config = Config::new(raw_config);
     }
+
+    #[test]
+    fn escape_modes() {
+        let config = Config::new(
+            r#"
+            [[escaper]]
+            path = "::askama::Js"
+            extensions = ["js"]
+        "#,
+        );
+        assert_eq!(
+            config.escapers,
+            vec![
+                (str_set(&["js"]), "::askama::Js".into()),
+                (str_set(&["html", "htm", "xml"]), "::askama::Html".into()),
+                (str_set(&["none", "txt", ""]), "::askama::Text".into()),
+            ]
+        );
+    }
 }
-- 
cgit