mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
Check for invalid conditionals on templates
This commit is contained in:
parent
156970c1b4
commit
4d7fcf585a
3 changed files with 42 additions and 7 deletions
|
@ -21,6 +21,9 @@ card-template-rendering-conditional-not-open = Found '{ $found }', but missing '
|
|||
# when the user referenced a field that doesn't exist
|
||||
# eg, Found '{{Field}}', but there is not field called 'Field'
|
||||
card-template-rendering-no-such-field = Found '{ $found }', but there is no field called '{ $field }'
|
||||
# when the user referenced a field that doesn't exist in a conditional, excepting card numbers like 'c1'
|
||||
# eg, Found '{{#Field}}', but neither is it a card number nor is there a field called 'Field'
|
||||
card-template-rendering-no-such-conditional = Found '{ $found }', but neither is it a card number nor is there a field called '{ $key }'
|
||||
# This message is shown when the front side of the card is blank,
|
||||
# either due to a badly-designed template, or because required fields
|
||||
# are missing.
|
||||
|
|
|
@ -119,6 +119,7 @@ pub enum TemplateError {
|
|||
filters: String,
|
||||
field: String,
|
||||
},
|
||||
NoSuchConditional(String),
|
||||
}
|
||||
|
||||
impl From<io::Error> for AnkiError {
|
||||
|
|
|
@ -297,6 +297,12 @@ fn localized_template_error(tr: &I18n, err: TemplateError) -> String {
|
|||
TemplateError::FieldNotFound { field, filters } => tr
|
||||
.card_template_rendering_no_such_field(format!("{{{{{}{}}}}}", filters, field), field)
|
||||
.into(),
|
||||
TemplateError::NoSuchConditional(condition) => tr
|
||||
.card_template_rendering_no_such_conditional(
|
||||
format!("{{{{{}}}}}", condition),
|
||||
&condition[1..],
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -467,12 +473,12 @@ fn render_into(
|
|||
}
|
||||
}
|
||||
Conditional { key, children } => {
|
||||
if context.nonempty_fields.contains(key.as_str()) {
|
||||
if context.evaluate_conditional(key.as_str(), false)? {
|
||||
render_into(rendered_nodes, children.as_ref(), context, tr)?;
|
||||
}
|
||||
}
|
||||
NegatedConditional { key, children } => {
|
||||
if !context.nonempty_fields.contains(key.as_str()) {
|
||||
if context.evaluate_conditional(key.as_str(), true)? {
|
||||
render_into(rendered_nodes, children.as_ref(), context, tr)?;
|
||||
}
|
||||
}
|
||||
|
@ -482,6 +488,24 @@ fn render_into(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
impl<'a> RenderContext<'a> {
|
||||
fn evaluate_conditional(&self, key: &str, negated: bool) -> TemplateResult<bool> {
|
||||
if self.nonempty_fields.contains(key) {
|
||||
Ok(true ^ negated)
|
||||
} else if self.fields.contains_key(key)
|
||||
|| (key.starts_with('c') && key[1..].parse::<u32>().is_ok())
|
||||
{
|
||||
Ok(false ^ negated)
|
||||
} else {
|
||||
let prefix = if negated { "^" } else { "#" };
|
||||
Err(TemplateError::NoSuchConditional(format!(
|
||||
"{}{}",
|
||||
prefix, key
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Append to last node if last node is a string, else add new node.
|
||||
fn append_str_to_nodes(nodes: &mut Vec<RenderedNode>, text: &str) {
|
||||
if let Some(RenderedNode::Text {
|
||||
|
@ -1015,7 +1039,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn render_single() {
|
||||
let map: HashMap<_, _> = vec![("F", "f"), ("B", "b"), ("E", " ")]
|
||||
let map: HashMap<_, _> = vec![("F", "f"), ("B", "b"), ("E", " "), ("c1", "1")]
|
||||
.into_iter()
|
||||
.map(|r| (r.0, r.1.into()))
|
||||
.collect();
|
||||
|
@ -1044,10 +1068,8 @@ mod test {
|
|||
// missing
|
||||
tmpl = PT::from_text("{{^M}}A{{/M}}").unwrap();
|
||||
assert_eq!(
|
||||
tmpl.render(&ctx, &tr).unwrap(),
|
||||
vec![FN::Text {
|
||||
text: "A".to_owned()
|
||||
},]
|
||||
tmpl.render(&ctx, &tr).unwrap_err(),
|
||||
TemplateError::NoSuchConditional("^M".to_string())
|
||||
);
|
||||
|
||||
// nested
|
||||
|
@ -1059,6 +1081,15 @@ mod test {
|
|||
},]
|
||||
);
|
||||
|
||||
// card conditionals
|
||||
tmpl = PT::from_text("{{^c2}}1{{#c1}}2{{/c1}}{{/c2}}").unwrap();
|
||||
assert_eq!(
|
||||
tmpl.render(&ctx, &tr).unwrap(),
|
||||
vec![FN::Text {
|
||||
text: "12".to_owned()
|
||||
},]
|
||||
);
|
||||
|
||||
// unknown filters
|
||||
tmpl = PT::from_text("{{one:two:B}}").unwrap();
|
||||
assert_eq!(
|
||||
|
|
Loading…
Reference in a new issue