mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-18 02:10:41 -07:00
Parse expressions in Liquid::Variable#parse.
This commit is contained in:
+54
-29
@@ -35,15 +35,16 @@ module Liquid
|
||||
|
||||
def lax_parse(markup)
|
||||
@filters = []
|
||||
if markup =~ /\s*(#{QuotedFragment})(.*)/om
|
||||
@name = Regexp.last_match(1)
|
||||
if Regexp.last_match(2) =~ /#{FilterSeparator}\s*(.*)/om
|
||||
filters = Regexp.last_match(1).scan(FilterParser)
|
||||
if markup =~ /(#{QuotedFragment})(.*)/om
|
||||
name_markup, filter_markup = $1, $2
|
||||
@name = Expression.parse(name_markup)
|
||||
if filter_markup =~ /#{FilterSeparator}\s*(.*)/om
|
||||
filters = $1.scan(FilterParser)
|
||||
filters.each do |f|
|
||||
if f =~ /\w+/
|
||||
filtername = Regexp.last_match(0)
|
||||
filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten
|
||||
@filters << [filtername, filterargs]
|
||||
@filters << parse_filter_expressions(filtername, filterargs)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -53,7 +54,7 @@ module Liquid
|
||||
def strict_parse(markup)
|
||||
# Very simple valid cases
|
||||
if markup =~ EasyParse
|
||||
@name = $1
|
||||
@name = Expression.parse($1)
|
||||
@filters = []
|
||||
return
|
||||
end
|
||||
@@ -61,11 +62,11 @@ module Liquid
|
||||
@filters = []
|
||||
p = Parser.new(markup)
|
||||
# Could be just filters with no input
|
||||
@name = p.look(:pipe) ? ''.freeze : p.expression
|
||||
@name = p.look(:pipe) ? nil : Expression.parse(p.expression)
|
||||
while p.consume?(:pipe)
|
||||
filtername = p.consume(:id)
|
||||
filterargs = p.consume?(:colon) ? parse_filterargs(p) : []
|
||||
@filters << [filtername, filterargs]
|
||||
@filters << parse_filter_expressions(filtername, filterargs)
|
||||
end
|
||||
p.consume(:end_of_string)
|
||||
end
|
||||
@@ -81,28 +82,52 @@ module Liquid
|
||||
end
|
||||
|
||||
def render(context)
|
||||
return ''.freeze if @name.nil?
|
||||
@filters.inject(context[@name]) do |output, filter|
|
||||
filterargs = []
|
||||
keyword_args = {}
|
||||
filter[1].to_a.each do |a|
|
||||
if matches = a.match(/\A#{TagAttributes}\z/o)
|
||||
keyword_args[matches[1]] = context[matches[2]]
|
||||
else
|
||||
filterargs << context[a]
|
||||
end
|
||||
return ''.freeze unless @name
|
||||
@filters.inject(context.evaluate(@name)) do |output, (filter_name, filter_args, filter_kwargs)|
|
||||
filter_args = evaluate_filter_expressions(context, filter_args, filter_kwargs)
|
||||
output = context.invoke(filter_name, output, *filter_args)
|
||||
end.tap{ |obj| taint_check(obj) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_filter_expressions(filter_name, unparsed_args)
|
||||
filter_args = []
|
||||
keyword_args = {}
|
||||
unparsed_args.each do |a|
|
||||
if matches = a.match(/\A#{TagAttributes}\z/o)
|
||||
keyword_args[matches[1]] = Expression.parse(matches[2])
|
||||
else
|
||||
filter_args << Expression.parse(a)
|
||||
end
|
||||
filterargs << keyword_args unless keyword_args.empty?
|
||||
output = context.invoke(filter[0], output, *filterargs)
|
||||
end.tap do |obj|
|
||||
if obj.tainted?
|
||||
case Template.taint_mode
|
||||
when :warn
|
||||
@warnings ||= []
|
||||
@warnings << "variable '#{@name}' is tainted and was not escaped"
|
||||
when :error
|
||||
raise TaintedError, "Error - variable '#{@name}' is tainted and was not escaped"
|
||||
end
|
||||
end
|
||||
result = [filter_name, filter_args]
|
||||
result << keyword_args unless keyword_args.empty?
|
||||
result
|
||||
end
|
||||
|
||||
def evaluate_filter_expressions(context, filter_args, filter_kwargs)
|
||||
parsed_args = filter_args.map{ |expr| context.evaluate(expr) }
|
||||
if filter_kwargs
|
||||
parsed_kwargs = {}
|
||||
filter_kwargs.each do |key, expr|
|
||||
parsed_kwargs[key] = context.evaluate(expr)
|
||||
end
|
||||
parsed_args << parsed_kwargs
|
||||
end
|
||||
parsed_args
|
||||
end
|
||||
|
||||
def taint_check(obj)
|
||||
if obj.tainted?
|
||||
@markup =~ QuotedFragment
|
||||
name = Regexp.last_match(0)
|
||||
case Template.taint_mode
|
||||
when :warn
|
||||
@warnings ||= []
|
||||
@warnings << "variable '#{name}' is tainted and was not escaped"
|
||||
when :error
|
||||
raise TaintedError, "Error - variable '#{name}' is tainted and was not escaped"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user