Class: ThemeCheck::LiquidNode
- Defined in:
- lib/theme_check/liquid_node.rb
Overview
A node from the Liquid AST, the result of parsing a liquid file.
Constant Summary collapse
- WHITESPACE =
/\s/
Instance Attribute Summary collapse
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
-
#theme_file ⇒ Object
readonly
Returns the value of attribute theme_file.
-
#value ⇒ Object
readonly
Returns the value of attribute value.
Instance Method Summary collapse
- #assigned_or_echoed_variable? ⇒ Boolean
-
#block? ⇒ Boolean
A block of type of node?.
-
#block_body? ⇒ Boolean
The body of blocks.
- #block_end_end_index ⇒ Object
- #block_end_markup ⇒ Object
- #block_end_start_index ⇒ Object
- #block_start_end_index ⇒ Object
- #block_start_markup ⇒ Object
- #block_start_start_index ⇒ Object
-
#block_tag? ⇒ Boolean
A tag %…endtag % node?.
-
#children ⇒ Object
Array of children nodes.
-
#comment? ⇒ Boolean
A comment % block node?.
-
#document? ⇒ Boolean
(also: #root?)
Top level node of every liquid_file.
- #end_column ⇒ Object
- #end_index ⇒ Object
- #end_row ⇒ Object
- #end_token ⇒ Object
- #filters ⇒ Object
-
#initialize(value, parent, theme_file) ⇒ LiquidNode
constructor
A new instance of LiquidNode.
- #inner_json ⇒ Object
- #inner_markup ⇒ Object
- #inner_markup_end_column ⇒ Object
- #inner_markup_end_index ⇒ Object
- #inner_markup_end_row ⇒ Object
- #inner_markup_start_column ⇒ Object
- #inner_markup_start_index ⇒ Object
- #inner_markup_start_row ⇒ Object
-
#inside_liquid_tag? ⇒ Boolean
Is this node inside a ‘liquid … %` block?.
-
#line_number ⇒ Object
Most nodes have a line number, but it’s not guaranteed.
-
#literal? ⇒ Boolean
Literals are hard-coded values in the liquid file.
-
#markup ⇒ Object
The original source code of the node.
- #markup=(markup) ⇒ Object
-
#outer_markup ⇒ Object
The original source code of the node.
- #outer_markup_end_column ⇒ Object
- #outer_markup_end_index ⇒ Object
- #outer_markup_end_row ⇒ Object
- #outer_markup_start_column ⇒ Object
- #outer_markup_start_index ⇒ Object
- #outer_markup_start_row ⇒ Object
- #schema? ⇒ Boolean
- #source ⇒ Object
- #start_column ⇒ Object
- #start_index ⇒ Object
- #start_row ⇒ Object
- #start_token ⇒ Object
-
#tag? ⇒ Boolean
A tag % node?.
-
#type_name ⇒ Object
The ‘:under_score_name` of this type of node.
- #variable? ⇒ Boolean
- #variable_lookup? ⇒ Boolean
-
#whitespace_trimmed_end? ⇒ Boolean
Is this node inside a tag or variable ends starts by removing whitespace.
-
#whitespace_trimmed_start? ⇒ Boolean
Is this node inside a tag or variable that starts by removing whitespace.
Constructor Details
#initialize(value, parent, theme_file) ⇒ LiquidNode
Returns a new instance of LiquidNode.
8 9 10 11 12 13 14 15 |
# File 'lib/theme_check/liquid_node.rb', line 8 def initialize(value, parent, theme_file) raise ArgumentError, "Expected a Liquid AST Node" if value.is_a?(LiquidNode) @value = value @parent = parent @theme_file = theme_file @tag_markup = nil @line_number_offset = 0 end |
Instance Attribute Details
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
6 7 8 |
# File 'lib/theme_check/liquid_node.rb', line 6 def parent @parent end |
#theme_file ⇒ Object (readonly)
Returns the value of attribute theme_file.
6 7 8 |
# File 'lib/theme_check/liquid_node.rb', line 6 def theme_file @theme_file end |
#value ⇒ Object (readonly)
Returns the value of attribute value.
6 7 8 |
# File 'lib/theme_check/liquid_node.rb', line 6 def value @value end |
Instance Method Details
#assigned_or_echoed_variable? ⇒ Boolean
143 144 145 |
# File 'lib/theme_check/liquid_node.rb', line 143 def assigned_or_echoed_variable? variable? && start_token == "" end |
#block? ⇒ Boolean
A block of type of node?
173 174 175 |
# File 'lib/theme_check/liquid_node.rb', line 173 def block? block_tag? || block_body? || document? end |
#block_body? ⇒ Boolean
The body of blocks
168 169 170 |
# File 'lib/theme_check/liquid_node.rb', line 168 def block_body? @value.is_a?(Liquid::BlockBody) end |
#block_end_end_index ⇒ Object
223 224 225 226 |
# File 'lib/theme_check/liquid_node.rb', line 223 def block_end_end_index return block_end_start_index unless tag? && block? @block_end_end_index ||= block_end_match&.end(0) || block_start_end_index end |
#block_end_markup ⇒ Object
214 215 216 |
# File 'lib/theme_check/liquid_node.rb', line 214 def block_end_markup source[block_end_start_index...block_end_end_index] end |
#block_end_start_index ⇒ Object
218 219 220 221 |
# File 'lib/theme_check/liquid_node.rb', line 218 def block_end_start_index return block_start_end_index unless tag? && block? @block_end_start_index ||= block_end_match&.begin(0) || block_start_end_index end |
#block_start_end_index ⇒ Object
210 211 212 |
# File 'lib/theme_check/liquid_node.rb', line 210 def block_start_end_index @block_start_end_index ||= position.end_index + end_token.size end |
#block_start_markup ⇒ Object
196 197 198 |
# File 'lib/theme_check/liquid_node.rb', line 196 def block_start_markup source[block_start_start_index...block_start_end_index] end |
#block_start_start_index ⇒ Object
200 201 202 203 204 205 206 207 208 |
# File 'lib/theme_check/liquid_node.rb', line 200 def block_start_start_index @block_start_start_index ||= if inside_liquid_tag? backtrack_on_whitespace(source, start_index, /[ \t]/) elsif tag? backtrack_on_whitespace(source, start_index) - start_token.length else position.start_index - start_token.length end end |
#block_tag? ⇒ Boolean
A tag %…endtag % node?
163 164 165 |
# File 'lib/theme_check/liquid_node.rb', line 163 def block_tag? @value.is_a?(Liquid::Block) end |
#children ⇒ Object
Array of children nodes.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/theme_check/liquid_node.rb', line 18 def children @children ||= begin nodes = if comment? [] elsif defined?(@value.class::ParseTreeVisitor) @value.class::ParseTreeVisitor.new(@value, {}).children elsif @value.respond_to?(:nodelist) Array(@value.nodelist) else [] end # Work around a bug in Liquid::Variable::ParseTreeVisitor that doesn't return # the args in a hash as children nodes. nodes = nodes.flat_map do |node| case node when Hash node.values else node end end nodes.map { |node| LiquidNode.new(node, self, @theme_file) } end end |
#comment? ⇒ Boolean
A comment % block node?
152 153 154 |
# File 'lib/theme_check/liquid_node.rb', line 152 def comment? @value.is_a?(Liquid::Comment) end |
#document? ⇒ Boolean Also known as: root?
Top level node of every liquid_file.
157 158 159 |
# File 'lib/theme_check/liquid_node.rb', line 157 def document? @value.is_a?(Liquid::Document) end |
#end_column ⇒ Object
125 126 127 |
# File 'lib/theme_check/liquid_node.rb', line 125 def end_column position.end_column end |
#end_index ⇒ Object
117 118 119 |
# File 'lib/theme_check/liquid_node.rb', line 117 def end_index position.end_index end |
#end_row ⇒ Object
121 122 123 |
# File 'lib/theme_check/liquid_node.rb', line 121 def end_row position.end_row end |
#end_token ⇒ Object
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
# File 'lib/theme_check/liquid_node.rb', line 332 def end_token if inside_liquid_tag? && source[end_index] == "\n" "\n" elsif inside_liquid_tag? "" elsif variable? && source[end_index...end_index + 3] == "-}}" "-}}" elsif variable? && source[end_index...end_index + 2] == "}}" "}}" elsif tag? && whitespace_trimmed_end? "-%}" elsif tag? "%}" else # this could happen because we're in an assign statement (variable) "" end end |
#filters ⇒ Object
187 188 189 190 |
# File 'lib/theme_check/liquid_node.rb', line 187 def filters raise TypeError, "Attempting to lookup filters of #{type_name}. Only variables have filters." unless variable? @value.filters end |
#inner_json ⇒ Object
81 82 83 84 85 86 87 |
# File 'lib/theme_check/liquid_node.rb', line 81 def inner_json return nil unless schema? @inner_json ||= JSON.parse(inner_markup) rescue JSON::ParserError # Handled by ValidSchema @inner_json = nil end |
#inner_markup ⇒ Object
76 77 78 79 |
# File 'lib/theme_check/liquid_node.rb', line 76 def inner_markup return '' unless block? @inner_markup ||= source[block_start_end_index...block_end_start_index] end |
#inner_markup_end_column ⇒ Object
272 273 274 |
# File 'lib/theme_check/liquid_node.rb', line 272 def inner_markup_end_column inner_markup_position.end_column end |
#inner_markup_end_index ⇒ Object
256 257 258 |
# File 'lib/theme_check/liquid_node.rb', line 256 def inner_markup_end_index inner_markup_position.end_index end |
#inner_markup_end_row ⇒ Object
268 269 270 |
# File 'lib/theme_check/liquid_node.rb', line 268 def inner_markup_end_row inner_markup_position.end_row end |
#inner_markup_start_column ⇒ Object
264 265 266 |
# File 'lib/theme_check/liquid_node.rb', line 264 def inner_markup_start_column inner_markup_position.start_column end |
#inner_markup_start_index ⇒ Object
252 253 254 |
# File 'lib/theme_check/liquid_node.rb', line 252 def inner_markup_start_index inner_markup_position.start_index end |
#inner_markup_start_row ⇒ Object
260 261 262 |
# File 'lib/theme_check/liquid_node.rb', line 260 def inner_markup_start_row inner_markup_position.start_row end |
#inside_liquid_tag? ⇒ Boolean
Is this node inside a ‘liquid … %` block?
279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/theme_check/liquid_node.rb', line 279 def inside_liquid_tag? # What we're doing here is starting at the start of the tag and # backtrack on all the whitespace until we land on something. If # that something is {% or %-, then we can safely assume that # we're inside a full tag and not a liquid tag. @inside_liquid_tag ||= if tag? && start_index && source i = 1 i += 1 while source[start_index - i] =~ WHITESPACE && i < start_index first_two_backtracked_characters = source[(start_index - i - 1)..(start_index - i)] first_two_backtracked_characters != "{%" && first_two_backtracked_characters != "%-" else false end end |
#line_number ⇒ Object
Most nodes have a line number, but it’s not guaranteed.
96 97 98 99 100 101 102 103 |
# File 'lib/theme_check/liquid_node.rb', line 96 def line_number if tag? && @value.respond_to?(:line_number) markup # initialize the line_number_offset @value.line_number - @line_number_offset elsif @value.respond_to?(:line_number) @value.line_number end end |
#literal? ⇒ Boolean
Literals are hard-coded values in the liquid file.
130 131 132 |
# File 'lib/theme_check/liquid_node.rb', line 130 def literal? @value.is_a?(String) || @value.is_a?(Integer) end |
#markup ⇒ Object
The original source code of the node. Doesn’t contain wrapping braces.
45 46 47 48 49 50 51 52 53 |
# File 'lib/theme_check/liquid_node.rb', line 45 def markup if tag? tag_markup elsif literal? value.to_s elsif @value.instance_variable_defined?(:@markup) @value.instance_variable_get(:@markup) end end |
#markup=(markup) ⇒ Object
89 90 91 92 93 |
# File 'lib/theme_check/liquid_node.rb', line 89 def markup=(markup) if @value.instance_variable_defined?(:@markup) @value.instance_variable_set(:@markup, markup) end end |
#outer_markup ⇒ Object
The original source code of the node. Does contain wrapping braces.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/theme_check/liquid_node.rb', line 56 def outer_markup if literal? markup elsif variable_lookup? '' elsif variable? start_token + markup + end_token elsif tag? && block? start_index = block_start_start_index end_index = block_start_end_index end_index += inner_markup.size end_index = find_block_delimiter(end_index)&.end(0) source[start_index...end_index] elsif tag? source[block_start_start_index...block_start_end_index] else inner_markup end end |
#outer_markup_end_column ⇒ Object
248 249 250 |
# File 'lib/theme_check/liquid_node.rb', line 248 def outer_markup_end_column outer_markup_position.end_column end |
#outer_markup_end_index ⇒ Object
232 233 234 |
# File 'lib/theme_check/liquid_node.rb', line 232 def outer_markup_end_index outer_markup_position.end_index end |
#outer_markup_end_row ⇒ Object
244 245 246 |
# File 'lib/theme_check/liquid_node.rb', line 244 def outer_markup_end_row outer_markup_position.end_row end |
#outer_markup_start_column ⇒ Object
240 241 242 |
# File 'lib/theme_check/liquid_node.rb', line 240 def outer_markup_start_column outer_markup_position.start_column end |
#outer_markup_start_index ⇒ Object
228 229 230 |
# File 'lib/theme_check/liquid_node.rb', line 228 def outer_markup_start_index outer_markup_position.start_index end |
#outer_markup_start_row ⇒ Object
236 237 238 |
# File 'lib/theme_check/liquid_node.rb', line 236 def outer_markup_start_row outer_markup_position.start_row end |
#schema? ⇒ Boolean
177 178 179 |
# File 'lib/theme_check/liquid_node.rb', line 177 def schema? @value.is_a?(ThemeCheck::Tags::Schema) end |
#source ⇒ Object
192 193 194 |
# File 'lib/theme_check/liquid_node.rb', line 192 def source theme_file&.source end |
#start_column ⇒ Object
113 114 115 |
# File 'lib/theme_check/liquid_node.rb', line 113 def start_column position.start_column end |
#start_index ⇒ Object
105 106 107 |
# File 'lib/theme_check/liquid_node.rb', line 105 def start_index position.start_index end |
#start_row ⇒ Object
109 110 111 |
# File 'lib/theme_check/liquid_node.rb', line 109 def start_row position.start_row end |
#start_token ⇒ Object
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
# File 'lib/theme_check/liquid_node.rb', line 316 def start_token if inside_liquid_tag? "" elsif variable? && source[start_index - 3..start_index - 1] == "{{-" "{{-" elsif variable? && source[start_index - 2..start_index - 1] == "{{" "{{" elsif tag? && whitespace_trimmed_start? "{%-" elsif tag? "{%" else "" end end |
#tag? ⇒ Boolean
A tag % node?
135 136 137 |
# File 'lib/theme_check/liquid_node.rb', line 135 def tag? @value.is_a?(Liquid::Tag) end |
#type_name ⇒ Object
The ‘:under_score_name` of this type of node. Used to dispatch to the `on_<type_name>` and `after_<type_name>` check methods.
183 184 185 |
# File 'lib/theme_check/liquid_node.rb', line 183 def type_name @type_name ||= StringHelpers.underscore(StringHelpers.demodulize(@value.class.name)).to_sym end |
#variable? ⇒ Boolean
139 140 141 |
# File 'lib/theme_check/liquid_node.rb', line 139 def variable? @value.is_a?(Liquid::Variable) end |
#variable_lookup? ⇒ Boolean
147 148 149 |
# File 'lib/theme_check/liquid_node.rb', line 147 def variable_lookup? @value.is_a?(Liquid::VariableLookup) end |
#whitespace_trimmed_end? ⇒ Boolean
Is this node inside a tag or variable ends starts by removing whitespace. i.e. -%} or -}}
306 307 308 309 310 311 312 313 314 |
# File 'lib/theme_check/liquid_node.rb', line 306 def whitespace_trimmed_end? @whitespace_trimmed_end ||= if end_index && source && !inside_liquid_tag? i = 0 i += 1 while source[end_index + i] =~ WHITESPACE && i < source.size source[end_index + i] == "-" else false end end |
#whitespace_trimmed_start? ⇒ Boolean
Is this node inside a tag or variable that starts by removing whitespace. i.e. {%- or {{-
295 296 297 298 299 300 301 302 303 |
# File 'lib/theme_check/liquid_node.rb', line 295 def whitespace_trimmed_start? @whitespace_trimmed_start ||= if start_index && source && !inside_liquid_tag? i = 1 i += 1 while source[start_index - i] =~ WHITESPACE && i < start_index source[start_index - i] == "-" else false end end |