diff --git a/tools/lib/template_parser.py b/tools/lib/template_parser.py index 2d76393717..1d39707f9a 100644 --- a/tools/lib/template_parser.py +++ b/tools/lib/template_parser.py @@ -81,6 +81,9 @@ def tokenize(text: str, template_format: str | None = None) -> list[Token]: def looking_at_handlebars_partial_block() -> bool: return template_format == "handlebars" and looking_at("{{#>") + def looking_at_handlebars_triple_stache() -> bool: + return template_format == "handlebars" and (looking_at("{{{") or looking_at("{{~{")) + def looking_at_html_start() -> bool: return looking_at("<") and not looking_at(" list[Token]: s = get_handlebars_tag(text, state.i) tag = "else" kind = "handlebars_else" + elif looking_at_handlebars_triple_stache(): + s = get_handlebars_triple_stache_tag(text, state.i) + start_offset = end_offset = 3 + if s.startswith("{{~{"): + start_offset += 1 + if s.endswith("}~}}"): + end_offset += 1 + tag = s[start_offset:-end_offset].strip() + if not tag.endswith("_html"): + raise TemplateParserError( + "Unescaped variables in triple staches {{{ }}} must be suffixed with `_html`" + ) + kind = "handlebars_triple_stache" elif looking_at_handlebars_start(): s = get_handlebars_tag(text, state.i) tag = s[3:-2].split()[0].strip("#").removeprefix("*") @@ -321,6 +337,7 @@ def tag_flavor(token: Token) -> str | None: "template_var", "text", "whitespace", + "handlebars_triple_stache", ): return None @@ -632,6 +649,18 @@ def get_handlebars_tag(text: str, i: int) -> str: return s +def get_handlebars_triple_stache_tag(text: str, i: int) -> str: + end = i + 3 + while end < len(text) - 3 and text[end] != "}": + end += 1 + if text[end : end + 3] == "}}}": + return text[i : end + 3] + elif end + 4 <= len(text) and text[end : end + 4] == "}~}}": + return text[i : end + 4] + else: + raise TokenizationError('Tag missing "}}}"', text[i : end + 3]) + + def get_spaces(text: str, i: int) -> str: s = "" while i < len(text) and text[i] in " ": diff --git a/tools/tests/test_pretty_print.py b/tools/tests/test_pretty_print.py index 86facc5869..cf69128664 100644 --- a/tools/tests/test_pretty_print.py +++ b/tools/tests/test_pretty_print.py @@ -179,7 +179,7 @@ BAD_HTML8 = """ {{#each test}} {{#with this}} {{#if foobar}} -
{{{test}}}
+
{{{test_html}}}
{{/if}} {{#if foobar2}} {{> teststuff}} @@ -192,7 +192,7 @@ GOOD_HTML8 = """ {{#each test}} {{#with this}} {{#if foobar}} -
{{{test}}}
+
{{{test_html}}}
{{/if}} {{#if foobar2}} {{> teststuff}} diff --git a/tools/tests/test_template_parser.py b/tools/tests/test_template_parser.py index cef4857c3c..23239a0a5b 100644 --- a/tools/tests/test_template_parser.py +++ b/tools/tests/test_template_parser.py @@ -147,6 +147,54 @@ class ParserTest(unittest.TestCase): template_format="handlebars", ) + def test_validate_triple_stache_var_1(self) -> None: + my_html = """ + {{{ foo}} + """ + self._assert_validate_error( + 'Tag missing "}}}" at line 2 col 13:"{{{ foo}}\n"', + text=my_html, + template_format="handlebars", + ) + + def test_validate_triple_stache_var_2(self) -> None: + my_html = """ + {{{ foo}~} + """ + self._assert_validate_error( + 'Tag missing "}}}" at line 2 col 13:"{{{ foo}~}"', + text=my_html, + template_format="handlebars", + ) + + def test_validate_triple_stache_var_3(self) -> None: + my_html = """ + {{{ foo }}} + """ + self._assert_validate_error( + "Unescaped variables in triple staches {{{ }}} must be suffixed with `_html`", + text=my_html, + template_format="handlebars", + ) + + def test_validate_triple_stache_var_4(self) -> None: + my_html = """ + {{{ foo_html }~}} + """ + validate(text=my_html, template_format="handlebars") + + def test_validate_triple_stache_var_5(self) -> None: + my_html = "{{{ foo_html}}}" + validate(text=my_html, template_format="handlebars") + + def test_validate_triple_stache_var_6(self) -> None: + my_html = "{{~{ bar_html}}}" + validate(text=my_html, template_format="handlebars") + + def test_validate_triple_stache_var_7(self) -> None: + my_html = "{{~{ bar_html}~}}" + validate(text=my_html, template_format="handlebars") + def test_validate_incomplete_django_tag_1(self) -> None: my_html = """ {% foo