Add rigid_parse to render

This commit is contained in:
Charles-P. Clermont
2025-10-27 16:33:31 +01:00
committed by Guilherme Carreiro
parent c78bf20010
commit e58ac0e75b
2 changed files with 85 additions and 16 deletions
+59 -16
View File
@@ -35,22 +35,7 @@ module Liquid
def initialize(tag_name, markup, options)
super
raise SyntaxError, options[:locale].t("errors.syntax.render") unless markup =~ SYNTAX
template_name = Regexp.last_match(1)
with_or_for = Regexp.last_match(3)
variable_name = Regexp.last_match(4)
@alias_name = Regexp.last_match(6)
@variable_name_expr = variable_name ? parse_expression(variable_name) : nil
@template_name_expr = parse_expression(template_name)
@is_for_loop = (with_or_for == FOR)
@attributes = {}
markup.scan(TagAttributes) do |key, value|
@attributes[key] = parse_expression(value)
end
parse_with_selected_parser(markup)
end
def for_loop?
@@ -99,6 +84,64 @@ module Liquid
output
end
# render (string) (with|for expression)? (as id)? (key: value)*
def rigid_parse(markup)
p = @parse_context.new_parser(markup)
template_name = rigid_template_name(p)
with_or_for = p.id?("for") || p.id?("with") || nil
if with_or_for
variable_name = p.expression
end
alias_name = nil
if p.consume?(:as)
alias_name = p.consume(:id)
end
@template_name_expr = parse_expression(template_name)
@variable_name_expr = variable_name ? parse_expression(variable_name) : nil
@alias_name = alias_name
@is_for_loop = (with_or_for == FOR)
# optional comma
p.consume?(:comma)
@attributes = {}
while p.look(:id)
key = p.consume
p.consume(:colon)
@attributes[key] = parse_expression(p.expression)
p.consume?(:comma) # optional comma
end
end
def rigid_template_name(p)
p.consume(:string)
end
def strict_parse(markup)
lax_parse(markup)
end
def lax_parse(markup)
raise SyntaxError, options[:locale].t("errors.syntax.render") unless markup =~ SYNTAX
template_name = Regexp.last_match(1)
with_or_for = Regexp.last_match(3)
variable_name = Regexp.last_match(4)
@alias_name = Regexp.last_match(6)
@variable_name_expr = variable_name ? parse_expression(variable_name) : nil
@template_name_expr = parse_expression(template_name)
@is_for_loop = (with_or_for == FOR)
@attributes = {}
markup.scan(TagAttributes) do |key, value|
@attributes[key] = parse_expression(value)
end
end
class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children
[
+26
View File
@@ -105,6 +105,32 @@ class RenderTagTest < Minitest::Test
assert_syntax_error("{% assign name = 'snippet' %}{% render name %}")
end
def test_rigid_parsing_errors
[:lax, :strict].each do |mode|
with_error_mode(mode) do
assert_template_result(
'hello value1 value2',
'{% render "snippet" !!! arg1: "value1" ~~~ arg2: "value2" %}',
partials: { 'snippet' => 'hello {{ arg1 }} {{ arg2 }}' },
)
end
end
[:rigid].each do |mode|
assert_syntax_error(
'{% render "snippet" !!! arg1: "value1" ~~~ arg2: "value2" %}',
error_mode: mode,
)
end
end
def test_optional_commas
partials = { 'snippet' => 'hello {{ arg1 }} {{ arg2 }}' }
assert_template_result('hello value1 value2', '{% render "snippet", arg1: "value1", arg2: "value2" %}', partials: partials)
assert_template_result('hello value1 value2', '{% render "snippet" arg1: "value1", arg2: "value2" %}', partials: partials)
assert_template_result('hello value1 value2', '{% render "snippet" arg1: "value1" arg2: "value2" %}', partials: partials)
end
def test_include_tag_caches_second_read_of_same_partial
file_system = StubFileSystem.new('snippet' => 'echo')
assert_equal(