mirror of
https://github.com/Shopify/liquid.git
synced 2026-10-03 09:05:13 -07:00
Merge pull request #1215 from Shopify/nested-liquid-tag
Fix liquid tag nested in outer block
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'English'
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
class BlockBody
|
class BlockBody
|
||||||
LiquidTagToken = /\A\s*(\w+)\s*(.*?)\z/o
|
LiquidTagToken = /\A\s*(\w+)\s*(.*?)\z/o
|
||||||
@@ -51,6 +53,21 @@ module Liquid
|
|||||||
yield nil, nil
|
yield nil, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @api private
|
||||||
|
def self.unknown_tag_in_liquid_tag(end_tag_name, end_tag_markup)
|
||||||
|
yield end_tag_name, end_tag_markup
|
||||||
|
ensure
|
||||||
|
Usage.increment("liquid_tag_contains_outer_tag") unless $ERROR_INFO.is_a?(SyntaxError)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def parse_liquid_tag(markup, parse_context, &block)
|
||||||
|
liquid_tag_tokenizer = Tokenizer.new(markup, line_number: parse_context.line_number, for_liquid_tag: true)
|
||||||
|
parse_for_liquid_tag(liquid_tag_tokenizer, parse_context) do |end_tag_name, end_tag_markup|
|
||||||
|
next unless end_tag_name
|
||||||
|
self.class.unknown_tag_in_liquid_tag(end_tag_name, end_tag_markup, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private def parse_for_document(tokenizer, parse_context, &block)
|
private def parse_for_document(tokenizer, parse_context, &block)
|
||||||
while (token = tokenizer.shift)
|
while (token = tokenizer.shift)
|
||||||
next if token.empty?
|
next if token.empty?
|
||||||
@@ -70,8 +87,8 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
if tag_name == 'liquid'
|
if tag_name == 'liquid'
|
||||||
liquid_tag_tokenizer = Tokenizer.new(markup, line_number: parse_context.line_number, for_liquid_tag: true)
|
parse_liquid_tag(markup, parse_context, &block)
|
||||||
next parse_for_liquid_tag(liquid_tag_tokenizer, parse_context, &block)
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
unless (tag = registered_tags[tag_name])
|
unless (tag = registered_tags[tag_name])
|
||||||
|
|||||||
@@ -81,6 +81,18 @@ class LiquidTagTest < Minitest::Test
|
|||||||
assert_match_syntax_error("syntax error (line 3): Unknown tag 'error'", "{% liquid echo ''\n \n error %}")
|
assert_match_syntax_error("syntax error (line 3): Unknown tag 'error'", "{% liquid echo ''\n \n error %}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_nested_liquid_tag
|
||||||
|
assert_usage_increment("liquid_tag_contains_outer_tag", times: 0) do
|
||||||
|
assert_template_result('good', <<~LIQUID)
|
||||||
|
{%- if true %}
|
||||||
|
{%- liquid
|
||||||
|
echo "good"
|
||||||
|
%}
|
||||||
|
{%- endif -%}
|
||||||
|
LIQUID
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_cannot_open_blocks_living_past_a_liquid_tag
|
def test_cannot_open_blocks_living_past_a_liquid_tag
|
||||||
assert_match_syntax_error("syntax error (line 3): 'if' tag was never closed", <<~LIQUID)
|
assert_match_syntax_error("syntax error (line 3): 'if' tag was never closed", <<~LIQUID)
|
||||||
{%- liquid
|
{%- liquid
|
||||||
@@ -91,12 +103,14 @@ class LiquidTagTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_quirk_can_close_blocks_created_before_a_liquid_tag
|
def test_quirk_can_close_blocks_created_before_a_liquid_tag
|
||||||
|
assert_usage_increment("liquid_tag_contains_outer_tag") do
|
||||||
assert_template_result("42", <<~LIQUID)
|
assert_template_result("42", <<~LIQUID)
|
||||||
{%- if true -%}
|
{%- if true -%}
|
||||||
42
|
42
|
||||||
{%- liquid endif -%}
|
{%- liquid endif -%}
|
||||||
LIQUID
|
LIQUID
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_liquid_tag_in_raw
|
def test_liquid_tag_in_raw
|
||||||
assert_template_result("{% liquid echo 'test' %}\n", <<~LIQUID)
|
assert_template_result("{% liquid echo 'test' %}\n", <<~LIQUID)
|
||||||
|
|||||||
@@ -58,6 +58,23 @@ module Minitest
|
|||||||
assert_match(match, exception.message)
|
assert_match(match, exception.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def assert_usage_increment(name, times: 1)
|
||||||
|
old_method = Liquid::Usage.method(:increment)
|
||||||
|
calls = 0
|
||||||
|
begin
|
||||||
|
Liquid::Usage.singleton_class.send(:remove_method, :increment)
|
||||||
|
Liquid::Usage.define_singleton_method(:increment) do |got_name|
|
||||||
|
calls += 1 if got_name == name
|
||||||
|
old_method.call(got_name)
|
||||||
|
end
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
Liquid::Usage.singleton_class.send(:remove_method, :increment)
|
||||||
|
Liquid::Usage.define_singleton_method(:increment, old_method)
|
||||||
|
end
|
||||||
|
assert_equal(times, calls, "Number of calls to Usage.increment with #{name.inspect}")
|
||||||
|
end
|
||||||
|
|
||||||
def with_global_filter(*globals)
|
def with_global_filter(*globals)
|
||||||
original_global_filters = Liquid::StrainerFactory.instance_variable_get(:@global_filters)
|
original_global_filters = Liquid::StrainerFactory.instance_variable_get(:@global_filters)
|
||||||
Liquid::StrainerFactory.instance_variable_set(:@global_filters, [])
|
Liquid::StrainerFactory.instance_variable_set(:@global_filters, [])
|
||||||
|
|||||||
Reference in New Issue
Block a user