Update the implementation to make {% doc %} as strict as {% raw %}

This commit is contained in:
Guilherme Carreiro
2025-02-20 09:37:24 +01:00
parent d519cbb2b9
commit d0f7d46247
3 changed files with 57 additions and 91 deletions
+1
View File
@@ -2,6 +2,7 @@
errors: errors:
syntax: syntax:
tag_unexpected_args: "Syntax Error in '%{tag}' - Valid syntax: %{tag}" tag_unexpected_args: "Syntax Error in '%{tag}' - Valid syntax: %{tag}"
block_tag_unexpected_args: "Syntax Error in '%{tag}' - Valid syntax: {% %{tag} %}{% end%{tag} %}"
assign: "Syntax Error in 'assign' - Valid syntax: assign [var] = [source]" assign: "Syntax Error in 'assign' - Valid syntax: assign [var] = [source]"
capture: "Syntax Error in 'capture' - Valid syntax: capture [var]" capture: "Syntax Error in 'capture' - Valid syntax: capture [var]"
case: "Syntax Error in 'case' - Valid syntax: case [condition]" case: "Syntax Error in 'case' - Valid syntax: case [condition]"
+26 -27
View File
@@ -25,45 +25,44 @@ module Liquid
# {% enddoc %} # {% enddoc %}
# {{ foo }}, {{ bar }}! # {{ foo }}, {{ bar }}!
class Doc < Block class Doc < Block
def render_to_output_buffer(_context, output) TAG_UNEXPECTED_ARGS = /\A\s*\z/
output
def initialize(tag_name, markup, parse_context)
super
ensure_valid_markup(tag_name, markup, parse_context)
end end
def unknown_tag(_tag, _markup, _tokens) def parse(tokens)
end while (token = tokens.shift)
tag_name = token =~ BlockBody::FullTokenPossiblyInvalid && Regexp.last_match(2)
def blank? raise_nested_doc_error if tag_name == @tag_name
true
end
def parse_body(body, tokenizer) if tag_name == block_delimiter
while (token = tokenizer.send(:shift)) parse_context.trim_whitespace = (token[-3] == WhitespaceControl)
tag_name = if tokenizer.for_liquid_tag return
next if token.empty? || token.match?(BlockBody::WhitespaceOrNothing)
tag_name_match = BlockBody::LiquidTagToken.match(token)
next if tag_name_match.nil?
tag_name_match[1]
else
token =~ BlockBody::FullToken
Regexp.last_match(2)
end
raise_nested_doc_error if tag_name == "doc"
if tag_name == "enddoc"
parse_context.trim_whitespace = (token[-3] == WhitespaceControl) unless tokenizer.for_liquid_tag
return false
end end
end end
raise_tag_never_closed(block_name) raise_tag_never_closed(block_name)
end end
def render_to_output_buffer(_context, output)
output
end
def blank?
true
end
private private
def ensure_valid_markup(tag_name, markup, parse_context)
unless TAG_UNEXPECTED_ARGS.match?(markup)
raise SyntaxError, parse_context.locale.t("errors.syntax.block_tag_unexpected_args", tag: tag_name)
end
end
def raise_nested_doc_error def raise_nested_doc_error
raise SyntaxError, parse_context.locale.t("errors.syntax.doc_invalid_nested") raise SyntaxError, parse_context.locale.t("errors.syntax.doc_invalid_nested")
end end
+30 -64
View File
@@ -20,32 +20,26 @@ class DocTagUnitTest < Minitest::Test
assert_template_result('', template) assert_template_result('', template)
end end
def test_doc_tag_inside_liquid_tag def test_doc_tag_does_not_support_extra_arguments
template = <<~LIQUID.chomp error = assert_raises(Liquid::SyntaxError) do
{% liquid template = <<~LIQUID.chomp
doc {% doc extra %}
Assigns foo to 1. {% enddoc %}
enddoc LIQUID
assign foo = 1
%}
LIQUID
assert_template_result('', template) Liquid::Template.parse(template)
end
exp_error = "Liquid syntax error: Syntax Error in 'doc' - Valid syntax: {% doc %}{% enddoc %}"
act_error = error.message
assert_equal(exp_error, act_error)
end end
def test_doc_tag_inside_liquid_tag_with_control_flow_nodes def test_doc_tag_must_support_valid_tags
template = <<~LIQUID.chomp assert_match_syntax_error("Liquid syntax error (line 1): 'doc' tag was never closed", '{% doc %} foo')
{% liquid assert_match_syntax_error("Liquid syntax error (line 1): Syntax Error in 'doc' - Valid syntax: {% doc %}{% enddoc %}", '{% doc } foo {% enddoc %}')
if 1 != 1 assert_match_syntax_error("Liquid syntax error (line 1): Syntax Error in 'doc' - Valid syntax: {% doc %}{% enddoc %}", '{% doc } foo %}{% enddoc %}')
doc
else
echo 123
enddoc
endif
%}
LIQUID
assert_template_result('', template)
end end
def test_doc_tag_ignores_liquid_nodes def test_doc_tag_ignores_liquid_nodes
@@ -103,37 +97,23 @@ class DocTagUnitTest < Minitest::Test
assert_template_result('', template) assert_template_result('', template)
end end
def test_doc_tag_raises_an_error_for_unclosed_assign def test_doc_tag_ignores_unclosed_assign
error = assert_raises(Liquid::SyntaxError) do template = <<~LIQUID.chomp
template = <<~LIQUID.chomp {% doc %}
{% doc %} {% assign foo = "1"
{% assign foo = "1" {% enddoc %}
{% enddoc %} LIQUID
LIQUID
Liquid::Template.parse(template) assert_template_result('', template)
end
exp_error = "Liquid syntax error: 'doc' tag was never closed"
act_error = error.message
assert_equal(exp_error, act_error)
end end
def test_doc_tag_raises_an_error_for_malformed_syntax def test_doc_tag_ignores_malformed_syntax
error = assert_raises(Liquid::SyntaxError) do template = <<~LIQUID.chomp
template = <<~LIQUID.chomp {% doc %}
{% doc %} {% {{ {%- enddoc %}
{% {{ {%- enddoc %} LIQUID
LIQUID
Liquid::Template.parse(template) assert_template_result('', template)
end
exp_error = "Liquid syntax error: 'doc' tag was never closed"
act_error = error.message
assert_equal(exp_error, act_error)
end end
def test_doc_tag_preserves_error_line_numbers def test_doc_tag_preserves_error_line_numbers
@@ -157,19 +137,6 @@ class DocTagUnitTest < Minitest::Test
assert_template_result("Hello!", " {%- doc -%}123{%- enddoc -%}Hello!") assert_template_result("Hello!", " {%- doc -%}123{%- enddoc -%}Hello!")
assert_template_result("Hello!", "{%- doc -%}123{%- enddoc -%} Hello!") assert_template_result("Hello!", "{%- doc -%}123{%- enddoc -%} Hello!")
assert_template_result("Hello!", " {%- doc -%}123{%- enddoc -%} Hello!") assert_template_result("Hello!", " {%- doc -%}123{%- enddoc -%} Hello!")
# Whitespace control within liquid tags
assert_template_result("Hello!World!", <<~LIQUID.chomp)
Hello!
{%- liquid
doc
this is inside a liquid tag
enddoc
-%}
World!
LIQUID
# Multiline whitespace control
assert_template_result("Hello!", <<~LIQUID.chomp) assert_template_result("Hello!", <<~LIQUID.chomp)
{%- doc %}Whitespace control!{% enddoc -%} {%- doc %}Whitespace control!{% enddoc -%}
Hello! Hello!
@@ -189,6 +156,5 @@ class DocTagUnitTest < Minitest::Test
assert_template_result('', "{% doc %}123{% enddoc\txyz %}") assert_template_result('', "{% doc %}123{% enddoc\txyz %}")
assert_template_result('', "{% doc %}123{% enddoc\nxyz %}") assert_template_result('', "{% doc %}123{% enddoc\nxyz %}")
assert_template_result('', "{% doc %}123{% enddoc\n xyz enddoc %}") assert_template_result('', "{% doc %}123{% enddoc\n xyz enddoc %}")
assert_template_result('', "{%doc}{% assign a = 1 %}{%enddoc}{% endif %}")
end end
end end