]> git.proxmox.com Git - rustc.git/blob - vendor/handlebars-3.5.5/src/partial.rs
New upstream version 1.70.0+dfsg2
[rustc.git] / vendor / handlebars-3.5.5 / src / partial.rs
1 use std::collections::HashMap;
2
3 use serde_json::value::Value as Json;
4
5 use crate::context::{merge_json, Context};
6 use crate::error::RenderError;
7 use crate::json::path::Path;
8 use crate::output::Output;
9 use crate::registry::Registry;
10 use crate::render::{Decorator, Evaluable, RenderContext, Renderable};
11 use crate::template::Template;
12
13 fn render_partial<'reg: 'rc, 'rc>(
14 t: &'reg Template,
15 d: &Decorator<'reg, 'rc>,
16 r: &'reg Registry<'reg>,
17 ctx: &'rc Context,
18 local_rc: &mut RenderContext<'reg, 'rc>,
19 out: &mut dyn Output,
20 ) -> Result<(), RenderError> {
21 // partial context path
22 if let Some(ref param_ctx) = d.param(0) {
23 if let (Some(p), Some(block)) = (param_ctx.context_path(), local_rc.block_mut()) {
24 *block.base_path_mut() = p.clone();
25 }
26 }
27
28 // @partial-block
29 if let Some(t) = d.template() {
30 local_rc.set_partial("@partial-block".to_owned(), t);
31 }
32
33 let result = if d.hash().is_empty() {
34 t.render(r, ctx, local_rc, out)
35 } else {
36 let hash_ctx = d
37 .hash()
38 .iter()
39 .map(|(k, v)| (k, v.value()))
40 .collect::<HashMap<&&str, &Json>>();
41 let current_path = Path::current();
42 let partial_context =
43 merge_json(local_rc.evaluate2(ctx, &current_path)?.as_json(), &hash_ctx);
44 let ctx = Context::wraps(&partial_context)?;
45 let mut partial_rc = local_rc.new_for_block();
46 t.render(r, &ctx, &mut partial_rc, out)
47 };
48
49 local_rc.remove_partial("@partial-block");
50
51 result
52 }
53
54 pub fn expand_partial<'reg: 'rc, 'rc>(
55 d: &Decorator<'reg, 'rc>,
56 r: &'reg Registry<'reg>,
57 ctx: &'rc Context,
58 rc: &mut RenderContext<'reg, 'rc>,
59 out: &mut dyn Output,
60 ) -> Result<(), RenderError> {
61 // try eval inline partials first
62 if let Some(t) = d.template() {
63 t.eval(r, ctx, rc)?;
64 }
65
66 let tname = d.name();
67 if rc.is_current_template(tname) {
68 return Err(RenderError::new("Cannot include self in >"));
69 }
70
71 let partial = rc.get_partial(tname);
72
73 match partial {
74 Some(t) => {
75 let mut local_rc = rc.clone();
76 render_partial(&t, d, r, ctx, &mut local_rc, out)?;
77 }
78 None => {
79 if let Some(t) = r.get_template(tname).or_else(|| d.template()) {
80 let mut local_rc = rc.clone();
81 render_partial(t, d, r, ctx, &mut local_rc, out)?;
82 }
83 }
84 }
85
86 Ok(())
87 }
88
89 #[cfg(test)]
90 mod test {
91 use crate::context::Context;
92 use crate::error::RenderError;
93 use crate::output::Output;
94 use crate::registry::Registry;
95 use crate::render::{Helper, RenderContext};
96
97 #[test]
98 fn test() {
99 let mut handlebars = Registry::new();
100 assert!(handlebars
101 .register_template_string("t0", "{{> t1}}")
102 .is_ok());
103 assert!(handlebars
104 .register_template_string("t1", "{{this}}")
105 .is_ok());
106 assert!(handlebars
107 .register_template_string("t2", "{{#> t99}}not there{{/t99}}")
108 .is_ok());
109 assert!(handlebars
110 .register_template_string("t3", "{{#*inline \"t31\"}}{{this}}{{/inline}}{{> t31}}")
111 .is_ok());
112 assert!(handlebars
113 .register_template_string(
114 "t4",
115 "{{#> t5}}{{#*inline \"nav\"}}navbar{{/inline}}{{/t5}}"
116 )
117 .is_ok());
118 assert!(handlebars
119 .register_template_string("t5", "include {{> nav}}")
120 .is_ok());
121 assert!(handlebars
122 .register_template_string("t6", "{{> t1 a}}")
123 .is_ok());
124 assert!(handlebars
125 .register_template_string(
126 "t7",
127 "{{#*inline \"t71\"}}{{a}}{{/inline}}{{> t71 a=\"world\"}}"
128 )
129 .is_ok());
130 assert!(handlebars.register_template_string("t8", "{{a}}").is_ok());
131 assert!(handlebars
132 .register_template_string("t9", "{{> t8 a=2}}")
133 .is_ok());
134
135 assert_eq!(handlebars.render("t0", &1).ok().unwrap(), "1".to_string());
136 assert_eq!(
137 handlebars.render("t2", &1).ok().unwrap(),
138 "not there".to_string()
139 );
140 assert_eq!(handlebars.render("t3", &1).ok().unwrap(), "1".to_string());
141 assert_eq!(
142 handlebars.render("t4", &1).ok().unwrap(),
143 "include navbar".to_string()
144 );
145 assert_eq!(
146 handlebars
147 .render("t6", &btreemap! {"a".to_string() => "2".to_string()})
148 .ok()
149 .unwrap(),
150 "2".to_string()
151 );
152 assert_eq!(
153 handlebars.render("t7", &1).ok().unwrap(),
154 "world".to_string()
155 );
156 assert_eq!(handlebars.render("t9", &1).ok().unwrap(), "2".to_string());
157 }
158
159 #[test]
160 fn test_include_partial_block() {
161 let t0 = "hello {{> @partial-block}}";
162 let t1 = "{{#> t0}}inner {{this}}{{/t0}}";
163
164 let mut handlebars = Registry::new();
165 assert!(handlebars.register_template_string("t0", t0).is_ok());
166 assert!(handlebars.register_template_string("t1", t1).is_ok());
167
168 let r0 = handlebars.render("t1", &true);
169 assert_eq!(r0.ok().unwrap(), "hello inner true".to_string());
170 }
171
172 #[test]
173 fn test_self_inclusion() {
174 let t0 = "hello {{> t1}} {{> t0}}";
175 let t1 = "some template";
176 let mut handlebars = Registry::new();
177 assert!(handlebars.register_template_string("t0", t0).is_ok());
178 assert!(handlebars.register_template_string("t1", t1).is_ok());
179
180 let r0 = handlebars.render("t0", &true);
181 assert!(r0.is_err());
182 }
183
184 #[test]
185 fn test_issue_143() {
186 let main_template = "one{{> two }}three{{> two }}";
187 let two_partial = "--- two ---";
188
189 let mut handlebars = Registry::new();
190 assert!(handlebars
191 .register_template_string("template", main_template)
192 .is_ok());
193 assert!(handlebars
194 .register_template_string("two", two_partial)
195 .is_ok());
196
197 let r0 = handlebars.render("template", &true);
198 assert_eq!(r0.ok().unwrap(), "one--- two ---three--- two ---");
199 }
200
201 #[test]
202 fn test_hash_context_outscope() {
203 let main_template = "In: {{> p a=2}} Out: {{a}}";
204 let p_partial = "{{a}}";
205
206 let mut handlebars = Registry::new();
207 assert!(handlebars
208 .register_template_string("template", main_template)
209 .is_ok());
210 assert!(handlebars.register_template_string("p", p_partial).is_ok());
211
212 let r0 = handlebars.render("template", &true);
213 assert_eq!(r0.ok().unwrap(), "In: 2 Out: ");
214 }
215
216 #[test]
217 fn test_partial_context_hash() {
218 let mut hbs = Registry::new();
219 hbs.register_template_string("one", "This is a test. {{> two name=\"fred\" }}")
220 .unwrap();
221 hbs.register_template_string("two", "Lets test {{name}}")
222 .unwrap();
223 assert_eq!(
224 "This is a test. Lets test fred",
225 hbs.render("one", &0).unwrap()
226 );
227 }
228
229 #[test]
230 fn test_partial_subexpression_context_hash() {
231 let mut hbs = Registry::new();
232 hbs.register_template_string("one", "This is a test. {{> (x @root) name=\"fred\" }}")
233 .unwrap();
234 hbs.register_template_string("two", "Lets test {{name}}")
235 .unwrap();
236
237 hbs.register_helper(
238 "x",
239 Box::new(
240 |_: &Helper<'_, '_>,
241 _: &Registry<'_>,
242 _: &Context,
243 _: &mut RenderContext<'_, '_>,
244 out: &mut dyn Output|
245 -> Result<(), RenderError> {
246 out.write("two")?;
247 Ok(())
248 },
249 ),
250 );
251 assert_eq!(
252 "This is a test. Lets test fred",
253 hbs.render("one", &0).unwrap()
254 );
255 }
256
257 #[test]
258 fn test_nested_partial_scope() {
259 let t = "{{#*inline \"pp\"}}{{a}} {{b}}{{/inline}}{{#each c}}{{> pp a=2}}{{/each}}";
260 let data = json!({"c": [{"b": true}, {"b": false}]});
261
262 let mut handlebars = Registry::new();
263 assert!(handlebars.register_template_string("t", t).is_ok());
264 let r0 = handlebars.render("t", &data);
265 assert_eq!(r0.ok().unwrap(), "2 true2 false");
266 }
267
268 #[test]
269 fn test_up_to_partial_level() {
270 let outer = r#"{{>inner name="fruit:" vegetables=fruits}}"#;
271 let inner = "{{#each vegetables}}{{../name}} {{this}},{{/each}}";
272
273 let data = json!({ "fruits": ["carrot", "tomato"] });
274
275 let mut handlebars = Registry::new();
276 handlebars.register_template_string("outer", outer).unwrap();
277 handlebars.register_template_string("inner", inner).unwrap();
278
279 assert_eq!(
280 handlebars.render("outer", &data).unwrap(),
281 "fruit: carrot,fruit: tomato,"
282 );
283 }
284 }