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
-
#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
218 219 220 221 |
# File 'lib/theme_check/liquid_node.rb', line 218 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
209 210 211 |
# File 'lib/theme_check/liquid_node.rb', line 209 def block_end_markup source[block_end_start_index...block_end_end_index] end |
#block_end_start_index ⇒ Object
213 214 215 216 |
# File 'lib/theme_check/liquid_node.rb', line 213 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
205 206 207 |
# File 'lib/theme_check/liquid_node.rb', line 205 def block_start_end_index @block_start_end_index ||= position.end_index + end_token.size end |
#block_start_markup ⇒ Object
191 192 193 |
# File 'lib/theme_check/liquid_node.rb', line 191 def block_start_markup source[block_start_start_index...block_start_end_index] end |
#block_start_start_index ⇒ Object
195 196 197 198 199 200 201 202 203 |
# File 'lib/theme_check/liquid_node.rb', line 195 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
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
# File 'lib/theme_check/liquid_node.rb', line 327 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 |
#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
267 268 269 |
# File 'lib/theme_check/liquid_node.rb', line 267 def inner_markup_end_column inner_markup_position.end_column end |
#inner_markup_end_index ⇒ Object
251 252 253 |
# File 'lib/theme_check/liquid_node.rb', line 251 def inner_markup_end_index inner_markup_position.end_index end |
#inner_markup_end_row ⇒ Object
263 264 265 |
# File 'lib/theme_check/liquid_node.rb', line 263 def inner_markup_end_row inner_markup_position.end_row end |
#inner_markup_start_column ⇒ Object
259 260 261 |
# File 'lib/theme_check/liquid_node.rb', line 259 def inner_markup_start_column inner_markup_position.start_column end |
#inner_markup_start_index ⇒ Object
247 248 249 |
# File 'lib/theme_check/liquid_node.rb', line 247 def inner_markup_start_index inner_markup_position.start_index end |
#inner_markup_start_row ⇒ Object
255 256 257 |
# File 'lib/theme_check/liquid_node.rb', line 255 def inner_markup_start_row inner_markup_position.start_row end |
#inside_liquid_tag? ⇒ Boolean
Is this node inside a ‘liquid … %` block?
274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/theme_check/liquid_node.rb', line 274 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
243 244 245 |
# File 'lib/theme_check/liquid_node.rb', line 243 def outer_markup_end_column outer_markup_position.end_column end |
#outer_markup_end_index ⇒ Object
227 228 229 |
# File 'lib/theme_check/liquid_node.rb', line 227 def outer_markup_end_index outer_markup_position.end_index end |
#outer_markup_end_row ⇒ Object
239 240 241 |
# File 'lib/theme_check/liquid_node.rb', line 239 def outer_markup_end_row outer_markup_position.end_row end |
#outer_markup_start_column ⇒ Object
235 236 237 |
# File 'lib/theme_check/liquid_node.rb', line 235 def outer_markup_start_column outer_markup_position.start_column end |
#outer_markup_start_index ⇒ Object
223 224 225 |
# File 'lib/theme_check/liquid_node.rb', line 223 def outer_markup_start_index outer_markup_position.start_index end |
#outer_markup_start_row ⇒ Object
231 232 233 |
# File 'lib/theme_check/liquid_node.rb', line 231 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
187 188 189 |
# File 'lib/theme_check/liquid_node.rb', line 187 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
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
# File 'lib/theme_check/liquid_node.rb', line 311 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 -}}
301 302 303 304 305 306 307 308 309 |
# File 'lib/theme_check/liquid_node.rb', line 301 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 {{-
290 291 292 293 294 295 296 297 298 |
# File 'lib/theme_check/liquid_node.rb', line 290 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 |