diff --git a/lib/liquid/locales/en.yml b/lib/liquid/locales/en.yml index 60307ac7..cd1607b3 100644 --- a/lib/liquid/locales/en.yml +++ b/lib/liquid/locales/en.yml @@ -2,6 +2,7 @@ errors: syntax: 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]" capture: "Syntax Error in 'capture' - Valid syntax: capture [var]" case: "Syntax Error in 'case' - Valid syntax: case [condition]" diff --git a/lib/liquid/tags/doc.rb b/lib/liquid/tags/doc.rb index e798ec65..c345e4c2 100644 --- a/lib/liquid/tags/doc.rb +++ b/lib/liquid/tags/doc.rb @@ -25,45 +25,44 @@ module Liquid # {% enddoc %} # {{ foo }}, {{ bar }}! class Doc < Block - def render_to_output_buffer(_context, output) - output + TAG_UNEXPECTED_ARGS = /\A\s*\z/ + + def initialize(tag_name, markup, parse_context) + super + ensure_valid_markup(tag_name, markup, parse_context) end - def unknown_tag(_tag, _markup, _tokens) - end + def parse(tokens) + while (token = tokens.shift) + tag_name = token =~ BlockBody::FullTokenPossiblyInvalid && Regexp.last_match(2) - def blank? - true - end + raise_nested_doc_error if tag_name == @tag_name - def parse_body(body, tokenizer) - while (token = tokenizer.send(:shift)) - tag_name = if tokenizer.for_liquid_tag - 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 + if tag_name == block_delimiter + parse_context.trim_whitespace = (token[-3] == WhitespaceControl) + return end end raise_tag_never_closed(block_name) end + def render_to_output_buffer(_context, output) + output + end + + def blank? + true + end + 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 raise SyntaxError, parse_context.locale.t("errors.syntax.doc_invalid_nested") end diff --git a/test/unit/tags/doc_tag_unit_test.rb b/test/unit/tags/doc_tag_unit_test.rb index d277ef05..861c1b6c 100644 --- a/test/unit/tags/doc_tag_unit_test.rb +++ b/test/unit/tags/doc_tag_unit_test.rb @@ -20,32 +20,26 @@ class DocTagUnitTest < Minitest::Test assert_template_result('', template) end - def test_doc_tag_inside_liquid_tag - template = <<~LIQUID.chomp - {% liquid - doc - Assigns foo to 1. - enddoc - assign foo = 1 - %} - LIQUID + def test_doc_tag_does_not_support_extra_arguments + error = assert_raises(Liquid::SyntaxError) do + template = <<~LIQUID.chomp + {% doc extra %} + {% enddoc %} + 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 - def test_doc_tag_inside_liquid_tag_with_control_flow_nodes - template = <<~LIQUID.chomp - {% liquid - if 1 != 1 - doc - else - echo 123 - enddoc - endif - %} - LIQUID - - assert_template_result('', template) + def test_doc_tag_must_support_valid_tags + assert_match_syntax_error("Liquid syntax error (line 1): 'doc' tag was never closed", '{% doc %} foo') + assert_match_syntax_error("Liquid syntax error (line 1): Syntax Error in 'doc' - Valid syntax: {% doc %}{% enddoc %}", '{% doc } foo {% enddoc %}') + assert_match_syntax_error("Liquid syntax error (line 1): Syntax Error in 'doc' - Valid syntax: {% doc %}{% enddoc %}", '{% doc } foo %}{% enddoc %}') end def test_doc_tag_ignores_liquid_nodes @@ -103,37 +97,23 @@ class DocTagUnitTest < Minitest::Test assert_template_result('', template) end - def test_doc_tag_raises_an_error_for_unclosed_assign - error = assert_raises(Liquid::SyntaxError) do - template = <<~LIQUID.chomp - {% doc %} - {% assign foo = "1" - {% enddoc %} - LIQUID + def test_doc_tag_ignores_unclosed_assign + template = <<~LIQUID.chomp + {% doc %} + {% assign foo = "1" + {% enddoc %} + LIQUID - Liquid::Template.parse(template) - end - - exp_error = "Liquid syntax error: 'doc' tag was never closed" - act_error = error.message - - assert_equal(exp_error, act_error) + assert_template_result('', template) end - def test_doc_tag_raises_an_error_for_malformed_syntax - error = assert_raises(Liquid::SyntaxError) do - template = <<~LIQUID.chomp - {% doc %} - {% {{ {%- enddoc %} - LIQUID + def test_doc_tag_ignores_malformed_syntax + template = <<~LIQUID.chomp + {% doc %} + {% {{ {%- enddoc %} + LIQUID - Liquid::Template.parse(template) - end - - exp_error = "Liquid syntax error: 'doc' tag was never closed" - act_error = error.message - - assert_equal(exp_error, act_error) + assert_template_result('', template) end 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!") - - # 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) {%- doc %}Whitespace control!{% enddoc -%} Hello! @@ -189,6 +156,5 @@ class DocTagUnitTest < Minitest::Test assert_template_result('', "{% doc %}123{% enddoc\txyz %}") assert_template_result('', "{% doc %}123{% enddoc\nxyz %}") assert_template_result('', "{% doc %}123{% enddoc\n xyz enddoc %}") - assert_template_result('', "{%doc}{% assign a = 1 %}{%enddoc}{% endif %}") end end