-
Notifications
You must be signed in to change notification settings - Fork 3
/
lib.rs
98 lines (87 loc) · 3.2 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use minijinja::machinery::TemplateConfig;
use minijinja::{machinery, AutoEscape, Environment};
use std::collections::{BTreeMap, HashMap};
use std::sync::Arc;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn set_panic_hook() {
// When the `console_error_panic_hook` feature is enabled, we can call the
// `set_panic_hook` function at least once during initialization, and then
// we will get better error messages if our code ever panics.
//
// For more details see
// https://github.com/rustwasm/console_error_panic_hook#readme
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
}
#[wasm_bindgen]
pub struct JsExposedEnv {
env: Environment<'static>,
}
fn annotate_error(err: minijinja::Error) -> JsError {
JsError::new(&format!("{:#}", err))
}
#[wasm_bindgen]
impl JsExposedEnv {
pub fn render(&self, template: &str, context: JsValue) -> Result<String, JsError> {
let tmpl = self.env.get_template(template).map_err(annotate_error)?;
let context: serde_json::Value = serde_wasm_bindgen::from_value(context)?;
Ok(tmpl.render(context).map_err(annotate_error)?)
}
}
#[wasm_bindgen]
pub fn create_env(templates: JsValue, pycompat: bool) -> Result<JsExposedEnv, JsError> {
let templates: HashMap<String, String> = serde_wasm_bindgen::from_value(templates)?;
let mut env = Environment::new();
minijinja_contrib::add_to_environment(&mut env);
if pycompat {
env.set_unknown_method_callback(minijinja_contrib::pycompat::unknown_method_callback);
}
env.set_debug(true);
for (name, template) in templates.into_iter() {
env.add_template_owned(name, template)
.map_err(annotate_error)?;
}
Ok(JsExposedEnv { env })
}
#[wasm_bindgen]
pub fn tokenize(template: &str) -> Result<JsValue, JsError> {
let mut rv = Vec::new();
for result in machinery::tokenize(template, false, Default::default(), Default::default()) {
let (token, span) = result?;
rv.push((token, span));
}
Ok(serde_wasm_bindgen::to_value(&rv)?)
}
#[wasm_bindgen]
pub fn parse(template: &str) -> Result<JsValue, JsError> {
let ast = machinery::parse(template, "<string>", Default::default(), Default::default())
.map_err(annotate_error)?;
Ok(serde_wasm_bindgen::to_value(&ast)?)
}
fn convert_instructions<'a, 'source>(
instructions: &'a machinery::Instructions<'source>,
) -> Vec<&'a machinery::Instruction<'source>> {
(0..instructions.len())
.map(|idx| instructions.get(idx).unwrap())
.collect::<Vec<_>>()
}
#[wasm_bindgen]
pub fn instructions(template: &str) -> Result<JsValue, JsError> {
let tmpl = machinery::CompiledTemplate::new(
"<string>",
template,
&TemplateConfig {
syntax_config: Default::default(),
ws_config: Default::default(),
default_auto_escape: Arc::new(|_| AutoEscape::None),
},
)
.map_err(annotate_error)?;
let mut all = BTreeMap::new();
all.insert("<root>", convert_instructions(&tmpl.instructions));
for (block_name, instr) in tmpl.blocks.iter() {
all.insert(&block_name, convert_instructions(instr));
}
Ok(serde_wasm_bindgen::to_value(&all)?)
}