From e46de3b6ab3815dd86aca6154cda160ce6244005 Mon Sep 17 00:00:00 2001 From: "Charles-P. Clermont" Date: Tue, 30 Sep 2025 09:18:40 -0400 Subject: [PATCH] --wip-- [skip ci] --- lib/liquid/parser_switching.rb | 18 ++++++++- lib/liquid/tags/cycle.rb | 54 +++++++++++++++++++------ lib/liquid/template.rb | 1 + test/integration/tags/cycle_tag_test.rb | 15 +++++++ 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/lib/liquid/parser_switching.rb b/lib/liquid/parser_switching.rb index 78afd58a..55f21b79 100644 --- a/lib/liquid/parser_switching.rb +++ b/lib/liquid/parser_switching.rb @@ -2,10 +2,17 @@ module Liquid module ParserSwitching + # We want "rigid" which is like strict but more strict only in some cases. + # We want to make it so strict behaves as is + # We want "rigid" to be stricter (prob beta flag) + # It shouldn't be slower to run rigid than strict, it's not rigid -> strict -> lax + # It's rigid -> lax or it's strict -> lax def strict_parse_with_error_mode_fallback(markup) - strict_parse_with_error_context(markup) + rigid_parse_with_error_context(markup) rescue SyntaxError => e case parse_context.error_mode + when :rigid + raise when :strict raise when :warn @@ -16,6 +23,7 @@ module Liquid def parse_with_selected_parser(markup) case parse_context.error_mode + when :rigid then rigid_parse_with_error_context(markup) when :strict then strict_parse_with_error_context(markup) when :lax then lax_parse(markup) when :warn @@ -30,6 +38,14 @@ module Liquid private + def rigid_parse_with_error_context(markup) + respond_to?(:rigid_parse) ? rigid_parse(markup) : strict_parse(markup) + rescue SyntaxError => e + e.line_number = line_number + e.markup_context = markup_context(markup) + raise e + end + def strict_parse_with_error_context(markup) strict_parse(markup) rescue SyntaxError => e diff --git a/lib/liquid/tags/cycle.rb b/lib/liquid/tags/cycle.rb index c2d94d5f..e575265c 100644 --- a/lib/liquid/tags/cycle.rb +++ b/lib/liquid/tags/cycle.rb @@ -22,18 +22,7 @@ module Liquid def initialize(tag_name, markup, options) super - case markup - when NamedSyntax - @variables = variables_from_string(Regexp.last_match(2)) - @name = parse_expression(Regexp.last_match(1)) - @is_named = true - when SimpleSyntax - @variables = variables_from_string(markup) - @name = @variables.to_s - @is_named = !@name.match?(/\w+:0x\h{8}/) - else - raise SyntaxError, options[:locale].t("errors.syntax.cycle") - end + parse_with_selected_parser(markup) end def named? @@ -65,6 +54,47 @@ module Liquid private + # cycle [name:] expression(, expression)* + def rigid_parse(markup) + $stderr.puts "using rigid" + p = @parse_context.new_parser(markup) + + if p.look(:id) && p.peek(1) == :colon + @name = p.consume(:id) + @is_named = true + p.consume(:colon) + end + + @variables = [] + while (var = p.expression) + @variables << var + break unless p.consume?(:comma) + end + + raise_syntax_error(options) if @variables.empty? + end + + # Temporarily until we migrate + def strict_parse(markup) + $stderr.puts "using rigid" + lax_parse(markup) + end + + def lax_parse(markup) + case markup + when NamedSyntax + @variables = variables_from_string(Regexp.last_match(2)) + @name = parse_expression(Regexp.last_match(1)) + @is_named = true + when SimpleSyntax + @variables = variables_from_string(markup) + @name = @variables.to_s + @is_named = !@name.match?(/\w+:0x\h{8}/) + else + raise SyntaxError, options[:locale].t("errors.syntax.cycle") + end + end + def variables_from_string(markup) markup.split(',').collect do |var| var =~ /\s*(#{QuotedFragment})\s*/o diff --git a/lib/liquid/template.rb b/lib/liquid/template.rb index a6d80e0a..8602745e 100644 --- a/lib/liquid/template.rb +++ b/lib/liquid/template.rb @@ -25,6 +25,7 @@ module Liquid # :lax acts like liquid 2.5 and silently ignores malformed tags in most cases. # :warn is the default and will give deprecation warnings when invalid syntax is used. # :strict will enforce correct syntax. + # :rigid will is stricter even. def error_mode=(mode) Deprecations.warn("Template.error_mode=", "Environment#error_mode=") Environment.default.error_mode = mode diff --git a/test/integration/tags/cycle_tag_test.rb b/test/integration/tags/cycle_tag_test.rb index a034db17..8cd6daac 100644 --- a/test/integration/tags/cycle_tag_test.rb +++ b/test/integration/tags/cycle_tag_test.rb @@ -45,4 +45,19 @@ class CycleTagTest < Minitest::Test assert_template_result("11", template) end + + def test_cycle_tag_with_error_mode + # QuotedFragment is more permissive than what Parser#expression allows. + [:lax, :strict].each do |mode| + with_error_mode(mode) do + assert_template_result("a", "{% cycle .5: 'a', 'b' %}") + assert_template_result("b", "{% assign 5 = 'b' %}{% cycle .5, .4 %}") + end + end + + with_error_mode(:rigid) do + assert_raises(Liquid::SyntaxError) { Template.parse("{% cycle .5: 'a', 'b' %}") } + assert_raises(Liquid::SyntaxError) { Template.parse("{% cycle .5, .4 %}") } + end + end end