@@ -3,6 +3,8 @@ module Scanners
3
3
4
4
class Liquid < Scanner
5
5
6
+ require 'csv'
7
+
6
8
register_for :liquid
7
9
8
10
DIRECTIVE_KEYWORDS = /endlist|list|endfor|for|endwrap|wrap|endif|if|endunless|unless|elsif|assignlist|assign|cycle|capture|end|capture|fill|endiflist|iflist|else/
@@ -11,20 +13,20 @@ class Liquid < Scanner
11
13
12
14
DIRECTIVE_PREPOSITIONS = /contains|in|#{ MATH } /
13
15
14
- FILTER_KEYWORDS = /#{ FILTER_WITH_VALUE_KEYWORDS } |textilize|capitalize|downcase|upcase|first|last|sort|map|size|escape_once|escape|strip_html|strip_newlines|newline_to_br/
15
-
16
16
FILTER_WITH_VALUE_KEYWORDS = /date|replace_first|replace|remove_first|remove_first|remove|minus|times|divided_by|modulo|mod|split|join|truncatewords|truncate|prepend|append/
17
17
18
- SELECTOR_KEYWORDS = /in|with|snippet|script|content_item|folder|widget|wrapper|category|asset_folder|asset /
18
+ FILTER_KEYWORDS = /#{ FILTER_WITH_VALUE_KEYWORDS } |textilize|capitalize|downcase|upcase|first|last|sort|map|size|escape_once|escape|strip_html|strip_newlines|newline_to_br /
19
19
20
- DIRECTIVE_KEYS = /#{ SELECTOR_KEYWORDS } |tabs|items_per_tab /
20
+ SELECTOR_KEYWORDS = /in|with|snippet|script|content_item|folder|widget|wrapper|category|asset_folder|asset /
21
21
22
22
LIQUID_DIRECTIVE_BLOCK = /
23
23
{{1,2}%
24
24
(.*?)
25
25
%}{1,2}
26
26
/x
27
27
28
+ KEY_VALUE_REGEX = /(\w +)(:)(\w +|".*"|'.*?')/
29
+
28
30
def setup
29
31
@html_scanner = CodeRay . scanner ( :html , tokens : @tokens , keep_tokens : true , keep_state : true )
30
32
end
@@ -35,43 +37,69 @@ def scan_spaces(encoder)
35
37
end
36
38
end
37
39
38
- def scan_key_value_pair ( encoder , options , match )
39
- scan_spaces ( encoder )
40
- if match =~ /#{ SELECTOR_KEYWORDS } /
41
- encoder . text_token match , :directive
40
+ def scan_string ( encoder , substring )
41
+ if substring and string_array = substring . match ( /('|")(.+)('|")/ )
42
+ delimiter = string_array . captures [ 0 ]
43
+ contents = string_array . captures [ 1 ]
44
+ delimiter_2 = string_array . captures [ 2 ]
45
+
46
+ encoder . begin_group :string
47
+ encoder . text_token delimiter , :delimiter
48
+ encoder . text_token contents , :contents
49
+ encoder . text_token delimiter , :delimiter
50
+ encoder . end_group :string
51
+
52
+ true
42
53
else
43
- encoder . text_token match , :key
54
+ false
44
55
end
45
- if delimiter = scan ( /:/ )
46
- encoder . text_token delimiter , :delimiter
47
- scan_spaces ( encoder )
56
+ end
57
+
58
+ def scan_csv_list ( encoder , list )
59
+ CSV . parse ( list ) do |row |
60
+ column_index = 0
61
+ row . each do |value |
62
+ column_index += 1
63
+ unless scan_string ( encoder , value )
64
+ encoder . text_token value , :value
65
+ end
66
+ unless column_index >= row . length
67
+ encoder . text_token ',' , :delimiter
68
+ end
69
+ end
48
70
end
49
- if value = scan ( /\w +/ )
50
- encoder . text_token value , :value
51
- elsif value = scan ( /('\S +')|("\w +")/ )
52
- encoder . text_token value , :string
71
+ end
72
+
73
+ def scan_key_value_pair ( encoder , options , match )
74
+ scan_spaces ( encoder )
75
+ if match = check ( /#{ KEY_VALUE_REGEX } / )
76
+ key = scan ( /\w +/ )
77
+ delimiter , values = scan ( /(:)(\S +)|(".*?")|('.*?')/ ) . match ( /(:)(\S +)|(".*?")|('.*?')/ ) . captures
78
+
79
+ if key =~ /#{ SELECTOR_KEYWORDS } /
80
+ encoder . text_token key , :directive
81
+ else
82
+ encoder . text_token key , :key
83
+ end
84
+
85
+ encoder . text_token delimiter , :delimiter
86
+ scan_csv_list ( encoder , values )
87
+ true
88
+ else
89
+ false
53
90
end
54
91
end
55
92
56
93
def scan_selector ( encoder , options , match )
57
94
scan_spaces ( encoder )
58
- Rails . logger . debug 'DEBUG: Looking for a selector'
59
- if match = scan ( /#{ DIRECTIVE_KEYS } / )
60
- if peek ( 1 ) == ':'
61
- Rails . logger . debug "DEBUG: Peek: #{ peek ( 5 ) } "
62
- Rails . logger . debug 'DEBUG: Selector keyword found'
63
- scan_key_value_pair ( encoder , options , match )
64
- else
65
- encoder . text_token match , :variable
66
- end
95
+ if scan_key_value_pair ( encoder , options , match )
67
96
scan_selector ( encoder , options , match )
68
97
else
69
98
false
70
99
end
71
100
end
72
101
73
102
def scan_directive ( encoder , options , match )
74
- Rails . logger . debug 'DEBUG: Scanning directive'
75
103
encoder . text_token match , :tag
76
104
state = :liquid
77
105
scan_spaces ( encoder )
@@ -106,9 +134,7 @@ def scan_directive(encoder, options, match)
106
134
def scan_output_filters ( encoder , options , match )
107
135
encoder . text_token match , :operator
108
136
scan_spaces ( encoder )
109
- if match = scan ( /#{ FILTER_WITH_VALUE_KEYWORDS } / )
110
- scan_key_value_pair ( encoder , options , match )
111
- elsif directive = scan ( /#{ FILTER_KEYWORDS } / )
137
+ if !scan_key_value_pair ( encoder , options , match ) and directive = scan ( /#{ FILTER_KEYWORDS } / )
112
138
encoder . text_token directive , :directive
113
139
end
114
140
if next_filter = scan ( /\s \| \s / )
@@ -117,7 +143,6 @@ def scan_output_filters(encoder, options, match)
117
143
end
118
144
119
145
def scan_output ( encoder , options , match )
120
- Rails . logger . debug 'DEBUG: Scanning output'
121
146
encoder . text_token match , :tag
122
147
state = :liquid
123
148
scan_spaces ( encoder )
@@ -135,12 +160,10 @@ def scan_output(encoder, options, match)
135
160
end
136
161
137
162
def scan_tokens ( encoder , options )
138
- Rails . logger . debug "DEBUG: Scan started: #{ self . string } "
139
163
state = :initial
140
164
141
165
until eos?
142
166
if ( match = scan_until ( /(?=({{2,3}|{{1,2}%))/ ) || scan_rest ) and not match . empty? and state != :liquid
143
- Rails . logger . debug "DEBUG: HTML scanning: #{ match } "
144
167
@html_scanner . tokenize ( match , tokens : encoder )
145
168
state = :initial
146
169
scan_spaces ( encoder )
0 commit comments