mirror of
https://github.com/kemko/liquid.git
synced 2026-01-11 20:45:47 +03:00
Compare commits
3 Commits
tokenizer-
...
lax-parse-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e25e5d5e8 | ||
|
|
77bdccf5ec | ||
|
|
87e3234b58 |
2
Gemfile
2
Gemfile
@@ -9,6 +9,6 @@ group :test do
|
||||
gem 'rubocop', '>=0.32.0'
|
||||
|
||||
platform :mri do
|
||||
gem 'liquid-c', github: 'Shopify/liquid-c', ref: '11d38237d9f491588a58c83dc3d364a7d0d1d55b'
|
||||
gem 'liquid-c', github: 'Shopify/liquid-c', ref: '2570693d8d03faa0df9160ec74348a7149436df3'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -35,8 +35,7 @@ module Liquid
|
||||
QuotedFragment = /#{QuotedString}|(?:[^\s,\|'"]|#{QuotedString})+/o
|
||||
TagAttributes = /(\w+)\s*\:\s*(#{QuotedFragment})/o
|
||||
AnyStartingTag = /\{\{|\{\%/
|
||||
tag_contents = /(?:#{QuotedString}|.)*?/m
|
||||
PartialTemplateParser = /#{TagStart}#{tag_contents}#{TagEnd}|#{VariableStart}#{tag_contents}#{VariableIncompleteEnd}/om
|
||||
PartialTemplateParser = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/om
|
||||
TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/om
|
||||
VariableParser = /\[[^\]]+\]|#{VariableSegment}+\??/o
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ module Liquid
|
||||
def parse_with_selected_parser(markup)
|
||||
case parse_context.error_mode
|
||||
when :strict then strict_parse_with_error_context(markup)
|
||||
when :lax then lax_parse(markup)
|
||||
when :lax, :lax_warn then lax_parse(markup)
|
||||
when :warn
|
||||
begin
|
||||
return strict_parse_with_error_context(markup)
|
||||
|
||||
@@ -10,7 +10,16 @@ module Liquid
|
||||
# {{ user | link }}
|
||||
#
|
||||
class Variable
|
||||
FilterParser = /(?:\s+|#{QuotedFragment}|#{ArgumentSeparator})+/o
|
||||
capture_ignored_variable_prefix = /([\s,\|'"]+?)??/
|
||||
capture_expression = /(#{QuotedFragment})/o
|
||||
capture_ignored_filter_prefix = /([^\|]+?)??/
|
||||
capture_filters = /(#{FilterSeparator}.*)/o
|
||||
VariableSyntax = /\A\s*#{capture_ignored_variable_prefix}\s*#{capture_expression}\s*(?:#{capture_ignored_filter_prefix}\s*#{capture_filters})?\z/om
|
||||
|
||||
capture_lax_separator = /(['"\|]+?)/
|
||||
capture_filter = /((?:\s+|#{QuotedFragment}|#{ArgumentSeparator})+)/o
|
||||
FilterParser = /\s*(?:#{FilterSeparator}|#{capture_lax_separator})\s*#{capture_filter}/o
|
||||
|
||||
attr_accessor :filters, :name, :line_number
|
||||
attr_reader :parse_context
|
||||
alias_method :options, :parse_context
|
||||
@@ -35,16 +44,19 @@ module Liquid
|
||||
|
||||
def lax_parse(markup)
|
||||
@filters = []
|
||||
return unless markup =~ /(#{QuotedFragment})(.*)/om
|
||||
return unless markup =~ VariableSyntax
|
||||
|
||||
name_markup = $1
|
||||
filter_markup = $2
|
||||
add_syntax_warning("variable prefixed with ignored characters: #{$1.inspect}") if $1
|
||||
name_markup = $2
|
||||
add_syntax_warning("variable filter separator prefixed with ignored characters: #{$3.inspect}") if $3
|
||||
filters_markup = $4
|
||||
@name = Expression.parse(name_markup)
|
||||
if filter_markup =~ /#{FilterSeparator}\s*(.*)/om
|
||||
filters = $1.scan(FilterParser)
|
||||
filters.each do |f|
|
||||
next unless f =~ /\w+/
|
||||
filtername = Regexp.last_match(0)
|
||||
if filters_markup
|
||||
filters_markup.scan(FilterParser) do |lax_sep, f|
|
||||
add_syntax_warning("unterminated quote or multiple pipe characters used as a filter separator: #{lax_sep.inspect}") if lax_sep
|
||||
next unless f =~ /\A\s*(\W+)??(\w+)/
|
||||
add_syntax_warning("ignored characters before filter name: #{$1.inspect}") if $1
|
||||
filtername = $2
|
||||
filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten
|
||||
@filters << parse_filter_expressions(filtername, filterargs)
|
||||
end
|
||||
@@ -81,6 +93,13 @@ module Liquid
|
||||
|
||||
private
|
||||
|
||||
def add_syntax_warning(warning)
|
||||
return unless parse_context.error_mode == :lax_warn
|
||||
error = SyntaxError.new(warning)
|
||||
error.line_number = parse_context.line_number
|
||||
parse_context.warnings << error
|
||||
end
|
||||
|
||||
def parse_filter_expressions(filter_name, unparsed_args)
|
||||
filter_args = []
|
||||
keyword_args = {}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
require 'test_helper'
|
||||
|
||||
class AssignTagTest < Minitest::Test
|
||||
include Liquid
|
||||
|
||||
def test_assign
|
||||
assert_template_result('monkey', "{% assign foo = 'monkey' %}{{ foo }}")
|
||||
end
|
||||
|
||||
def test_string_with_end_tag
|
||||
assert_template_result("{% quoted %}", "{% assign string = '{% quoted %}' %}{{ string }}")
|
||||
end
|
||||
end
|
||||
@@ -90,8 +90,31 @@ class VariableTest < Minitest::Test
|
||||
assert_equal 'worked', Template.parse("{{\ntest\n}}").render!('test' => 'worked')
|
||||
end
|
||||
|
||||
def test_string_with_curly_brackets
|
||||
json = '{ "key": { "nested": "value" }}'
|
||||
assert_template_result(json, "{{ '#{json}' }}")
|
||||
def test_lax_warnings_for_variable_ignored_prefix
|
||||
ignored_chars = %(|,'")
|
||||
template = Liquid::Template.parse("{{ #{ignored_chars}test }}", error_mode: :lax_warn)
|
||||
assert_equal "works", template.render!('test' => 'works')
|
||||
assert_equal [Liquid::SyntaxError.new("variable prefixed with ignored characters: #{ignored_chars.inspect}")], template.warnings
|
||||
end
|
||||
|
||||
def test_lax_warnings_for_ignored_variable_filter_prefix
|
||||
ignored_chars = ",wat? lax!"
|
||||
template = Liquid::Template.parse("{{ test#{ignored_chars} | noop }}", error_mode: :lax_warn)
|
||||
assert_equal "works", template.render!('test' => 'works')
|
||||
assert_equal [Liquid::SyntaxError.new("variable filter separator prefixed with ignored characters: #{ignored_chars.inspect}")], template.warnings
|
||||
end
|
||||
|
||||
def test_lax_warnings_for_weird_filter_chars
|
||||
template = Liquid::Template.parse("{{ test | upcase \" prepend: 'it ' || append: ' surprisingly' }}", error_mode: :lax_warn)
|
||||
assert_equal "it WORKS surprisingly", template.render!('test' => 'works')
|
||||
expected_warnings = ['"', '||'].map{ |sep| Liquid::SyntaxError.new("unterminated quote or multiple pipe characters used as a filter separator: #{sep.inspect}") }
|
||||
assert_equal expected_warnings, template.warnings
|
||||
end
|
||||
|
||||
def test_lax_warnings_for_ignored_filter_name_prefix
|
||||
ignored_chars = "'': '"
|
||||
template = Liquid::Template.parse("{{ test | '': 'prepend ' }}", error_mode: :lax_warn)
|
||||
assert_equal "prepend wat", template.render!('test' => 'wat')
|
||||
assert_equal [Liquid::SyntaxError.new("ignored characters before filter name: #{ignored_chars.inspect}")], template.warnings
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user