|
|
|
@ -13,6 +13,7 @@ use crate::renderer::errors::RenderError;
|
|
|
|
|
use crate::renderer::errors::WalkError;
|
|
|
|
|
use crate::renderer::inline_partial_tree::extract_inline_partials;
|
|
|
|
|
use crate::renderer::inline_partial_tree::InlinePartialTreeElement;
|
|
|
|
|
use crate::renderer::iteration_context::IterationContext;
|
|
|
|
|
use crate::renderer::parameters_context::ParametersContext;
|
|
|
|
|
use crate::renderer::walking::walk_path;
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
@ -150,58 +151,93 @@ impl<'a> DustRenderer<'a> {
|
|
|
|
|
match val {
|
|
|
|
|
Err(WalkError::CantWalk) => return Ok("".to_owned()),
|
|
|
|
|
Ok(final_val) => {
|
|
|
|
|
let loop_elements = final_val.get_loop_elements();
|
|
|
|
|
if loop_elements.is_empty() {
|
|
|
|
|
return Ok("".to_owned());
|
|
|
|
|
return if final_val.is_truthy() {
|
|
|
|
|
final_val.render(&Self::preprocess_filters(&reference.filters))
|
|
|
|
|
} else {
|
|
|
|
|
return final_val.render(&Self::preprocess_filters(&reference.filters));
|
|
|
|
|
}
|
|
|
|
|
Ok("".to_owned())
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
DustTag::DTSection(container) => {
|
|
|
|
|
let val = walk_path(breadcrumbs, &container.path.keys);
|
|
|
|
|
let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val);
|
|
|
|
|
if loop_elements.is_empty() {
|
|
|
|
|
// Oddly enough if the value is falsey (like
|
|
|
|
|
// an empty array or null), Dust uses the
|
|
|
|
|
// original context before walking the path as
|
|
|
|
|
// the context for rendering the else block
|
|
|
|
|
return self.render_maybe_body(&container.else_contents, breadcrumbs, blocks);
|
|
|
|
|
} else {
|
|
|
|
|
match &container.contents {
|
|
|
|
|
None => return Ok("".to_owned()),
|
|
|
|
|
Some(body) => {
|
|
|
|
|
let rendered_results: Result<Vec<String>, RenderError> = loop_elements
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|array_elem| {
|
|
|
|
|
let mut new_breadcumbs = breadcrumbs.clone();
|
|
|
|
|
new_breadcumbs.push(array_elem);
|
|
|
|
|
self.render_body(&body, &new_breadcumbs, blocks)
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
let rendered_slice: &[String] = &rendered_results?;
|
|
|
|
|
return Ok(rendered_slice.join(""));
|
|
|
|
|
}
|
|
|
|
|
match val {
|
|
|
|
|
Err(WalkError::CantWalk) => {
|
|
|
|
|
return self.render_maybe_body(
|
|
|
|
|
&container.else_contents,
|
|
|
|
|
breadcrumbs,
|
|
|
|
|
blocks,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
Ok(final_val) => {
|
|
|
|
|
return if final_val.is_truthy() {
|
|
|
|
|
match &container.contents {
|
|
|
|
|
// If the body is empty, just shortcut
|
|
|
|
|
// to an empty string now rather than
|
|
|
|
|
// generating intermediate contexts
|
|
|
|
|
// and iterating for nothing.
|
|
|
|
|
None => Ok("".to_owned()),
|
|
|
|
|
Some(body) => {
|
|
|
|
|
let loop_elements: Vec<&dyn ContextElement> =
|
|
|
|
|
final_val.get_loop_elements();
|
|
|
|
|
if loop_elements.is_empty() {
|
|
|
|
|
// Scalar value
|
|
|
|
|
let mut new_breadcrumbs = breadcrumbs.clone();
|
|
|
|
|
new_breadcrumbs.push(final_val);
|
|
|
|
|
self.render_body(body, &new_breadcrumbs, blocks)
|
|
|
|
|
} else {
|
|
|
|
|
// Array-like value
|
|
|
|
|
let total_length = loop_elements.len();
|
|
|
|
|
let rendered_results: Result<Vec<String>, RenderError> =
|
|
|
|
|
loop_elements
|
|
|
|
|
.into_iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.map(|(i, array_elem)| {
|
|
|
|
|
let injected_context =
|
|
|
|
|
IterationContext::new(i, total_length);
|
|
|
|
|
let mut new_breadcrumbs = breadcrumbs.clone();
|
|
|
|
|
new_breadcrumbs.push(&injected_context);
|
|
|
|
|
new_breadcrumbs.push(array_elem);
|
|
|
|
|
self.render_body(
|
|
|
|
|
&body,
|
|
|
|
|
&new_breadcrumbs,
|
|
|
|
|
blocks,
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
let rendered_slice: &[String] = &rendered_results?;
|
|
|
|
|
return Ok(rendered_slice.join(""));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Oddly enough if the value is falsey (like
|
|
|
|
|
// an empty array or null), Dust uses the
|
|
|
|
|
// original context before walking the path as
|
|
|
|
|
// the context for rendering the else block
|
|
|
|
|
return self.render_maybe_body(
|
|
|
|
|
&container.else_contents,
|
|
|
|
|
breadcrumbs,
|
|
|
|
|
blocks,
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
DustTag::DTExists(container) => {
|
|
|
|
|
let val = walk_path(breadcrumbs, &container.path.keys);
|
|
|
|
|
let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val);
|
|
|
|
|
return if loop_elements.is_empty() {
|
|
|
|
|
self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
|
|
|
|
|
} else {
|
|
|
|
|
return if val.map(|v| v.is_truthy()).unwrap_or(false) {
|
|
|
|
|
self.render_maybe_body(&container.contents, breadcrumbs, blocks)
|
|
|
|
|
} else {
|
|
|
|
|
self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
DustTag::DTNotExists(container) => {
|
|
|
|
|
let val = walk_path(breadcrumbs, &container.path.keys);
|
|
|
|
|
let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val);
|
|
|
|
|
return if !loop_elements.is_empty() {
|
|
|
|
|
self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
|
|
|
|
|
} else {
|
|
|
|
|
return if !val.map(|v| v.is_truthy()).unwrap_or(false) {
|
|
|
|
|
self.render_maybe_body(&container.contents, breadcrumbs, blocks)
|
|
|
|
|
} else {
|
|
|
|
|
self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
DustTag::DTPartial(partial) => {
|
|
|
|
|