Skip to content

Commit c680e11

Browse files
committed
optionally remove empty nodes from AST
1 parent 6e3e26b commit c680e11

File tree

5 files changed

+117
-28
lines changed

5 files changed

+117
-28
lines changed

lib/liquid/block_body.rb

+15-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def freeze
5959
end
6060
new_tag = tag.parse(tag_name, markup, tokenizer, parse_context)
6161

62-
next if new_tag.is_a?(Comment)
62+
next if parse_context.omit_blank_nodes && blank_node?(new_tag)
6363

6464
@blank &&= new_tag.blank?
6565
@nodelist << new_tag
@@ -157,7 +157,7 @@ def self.rescue_render_node(context, output, line_number, exc, blank_tag)
157157
end
158158
new_tag = tag.parse(tag_name, markup, tokenizer, parse_context)
159159

160-
next if new_tag.is_a?(Comment)
160+
next if parse_context.omit_blank_nodes && blank_node?(new_tag)
161161

162162
@blank &&= new_tag.blank?
163163
@nodelist << new_tag
@@ -275,5 +275,18 @@ def raise_missing_tag_terminator(token, parse_context)
275275
def raise_missing_variable_terminator(token, parse_context)
276276
BlockBody.raise_missing_variable_terminator(token, parse_context)
277277
end
278+
279+
def blank_node?(node)
280+
case node
281+
when Comment
282+
return true
283+
when BlockBody
284+
return true if node.nodelist.empty?
285+
when Tag
286+
return node.nodelist.all? { |n| blank_node?(n) }
287+
end
288+
289+
false
290+
end
278291
end
279292
end

lib/liquid/parse_context.rb

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module Liquid
44
class ParseContext
55
attr_accessor :locale, :line_number, :trim_whitespace, :depth
6-
attr_reader :partial, :warnings, :error_mode, :environment
6+
attr_reader :partial, :warnings, :error_mode, :environment, :omit_blank_nodes
77

88
def initialize(options = Const::EMPTY_HASH)
99
@environment = options.fetch(:environment, Environment.default)
@@ -12,6 +12,10 @@ def initialize(options = Const::EMPTY_HASH)
1212
@locale = @template_options[:locale] ||= I18n.new
1313
@warnings = []
1414

15+
# remove blank nodes such as
16+
# comment tags, empty if tags, etc from the AST
17+
@omit_blank_nodes = options.fetch(:omit_blank_nodes, false)
18+
1519
self.depth = 0
1620
self.partial = false
1721
end

performance/tests/tribble/404.liquid

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
<div id="page" class="innerpage clearfix">
21

32
<div id="text-page">
43
<div class="entry">

test/unit/block_unit_test.rb

+97-2
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,107 @@ def test_variable_many_embedded_fragments
4949

5050
def test_with_block
5151
template = Liquid::Template.parse(" {% comment %} {% endcomment %} ")
52-
assert_equal([String, String], block_types(template.root.nodelist))
53-
assert_equal(2, template.root.nodelist.size)
52+
assert_equal([String, Comment, String], block_types(template.root.nodelist))
53+
assert_equal(3, template.root.nodelist.size)
54+
end
55+
56+
def test_remove_empty_for_blocks_with_optimization_option
57+
source = <<~LIQUID.chomp
58+
{% for i in (1..1000000) %}
59+
{% endfor %}
60+
LIQUID
61+
62+
assert_root_nodelist_size(source, 0, omit_blank_nodes: true)
63+
64+
source = <<~LIQUID.chomp
65+
{% for i in (1..1000000) %}
66+
{% else %}
67+
{% endfor %}
68+
LIQUID
69+
70+
assert_root_nodelist_size(source, 0, omit_blank_nodes: true)
71+
72+
source = <<~LIQUID.chomp
73+
{% for i in list %}
74+
i
75+
{% endfor %}
76+
LIQUID
77+
78+
assert_root_nodelist_size(source, 1, omit_blank_nodes: true)
79+
80+
source = <<~LIQUID.chomp
81+
{% for i in list %}
82+
{% else %}
83+
1
84+
{% endfor %}
85+
LIQUID
86+
87+
assert_root_nodelist_size(source, 1, omit_blank_nodes: true)
88+
end
89+
90+
def test_remove_comment_nodes_with_optimization_option
91+
source = <<~LIQUID.chomp
92+
{% comment %}
93+
{% if true %}
94+
{% endif %}
95+
{% endcomment %}
96+
LIQUID
97+
98+
assert_root_nodelist_size(source, 0, omit_blank_nodes: true)
99+
100+
source = <<~LIQUID.chomp
101+
{% liquid
102+
comment
103+
if true
104+
endif
105+
endcomment
106+
%}
107+
LIQUID
108+
109+
assert_root_nodelist_size(source, 0, omit_blank_nodes: true)
110+
end
111+
112+
def test_remove_if_nodes_with_optimization_option
113+
source = <<~LIQUID.chomp
114+
{% if true %}
115+
{% endif %}
116+
LIQUID
117+
118+
assert_root_nodelist_size(source, 0, omit_blank_nodes: true)
119+
120+
source = <<~LIQUID.chomp
121+
{% unless true %}
122+
{% endunless %}
123+
LIQUID
124+
125+
assert_root_nodelist_size(source, 0, omit_blank_nodes: true)
126+
127+
source = <<~LIQUID.chomp
128+
{% if false %}
129+
{% else %}
130+
{% endif %}
131+
LIQUID
132+
133+
assert_root_nodelist_size(source, 0, omit_blank_nodes: true)
134+
135+
source = <<~LIQUID.chomp
136+
{% if false %}
137+
{% else %}
138+
Hello!
139+
{% endif %}
140+
LIQUID
141+
142+
assert_root_nodelist_size(source, 1, omit_blank_nodes: true)
54143
end
55144

56145
private
57146

147+
def assert_root_nodelist_size(source, expected_size, parse_options = {})
148+
template = Liquid::Template.parse(source, parse_options)
149+
150+
assert_equal(expected_size, template.root.nodelist.size)
151+
end
152+
58153
def block_types(nodelist)
59154
nodelist.collect(&:class)
60155
end

test/unit/tags/comment_tag_unit_test.rb

-22
Original file line numberDiff line numberDiff line change
@@ -199,26 +199,4 @@ def test_dont_override_liquid_tag_whitespace_control
199199
World!
200200
LIQUID
201201
end
202-
203-
def test_comment_tag_node_is_not_in_nodelist
204-
template = Liquid::Template.parse(<<~LIQUID.chomp)
205-
{% comment %}
206-
{% if true %}
207-
{% endif %}
208-
{% endcomment %}
209-
LIQUID
210-
211-
assert_equal(0, template.root.nodelist.size)
212-
213-
template = Liquid::Template.parse(<<~LIQUID.chomp)
214-
{% liquid
215-
comment
216-
if true
217-
endif
218-
endcomment
219-
%}
220-
LIQUID
221-
222-
assert_equal(0, template.root.nodelist.size)
223-
end
224202
end

0 commit comments

Comments
 (0)