Class: ThemeCheck::LiquidNode

Inherits:
Node
  • Object
show all
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

Instance Method Summary collapse

Constructor Details

#initialize(value, parent, theme_file) ⇒ LiquidNode

Returns a new instance of LiquidNode.

Raises:

  • (ArgumentError)


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

#block? ⇒ Boolean

A block of type of node?

Returns:

  • (Boolean)


113
114
115
# File 'lib/theme_check/liquid_node.rb', line 113

def block?
  block_tag? || block_body? || document?
end

#block_body? ⇒ Boolean

The body of blocks

Returns:

  • (Boolean)


108
109
110
# File 'lib/theme_check/liquid_node.rb', line 108

def block_body?
  @value.is_a?(Liquid::BlockBody)
end

#block_tag? ⇒ Boolean

A tag %...endtag % node?

Returns:

  • (Boolean)


103
104
105
# File 'lib/theme_check/liquid_node.rb', line 103

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?

Returns:

  • (Boolean)


92
93
94
# File 'lib/theme_check/liquid_node.rb', line 92

def comment?
  @value.is_a?(Liquid::Comment)
end

#document? ⇒ Boolean Also known as: root?

Top level node of every liquid_file.

Returns:

  • (Boolean)


97
98
99
# File 'lib/theme_check/liquid_node.rb', line 97

def document?
  @value.is_a?(Liquid::Document)
end

#end_index ⇒ Object



73
74
75
# File 'lib/theme_check/liquid_node.rb', line 73

def end_index
  position.end_index
end

#end_token ⇒ Object



176
177
178
179
180
181
182
183
# File 'lib/theme_check/liquid_node.rb', line 176

def end_token
  return "" if inside_liquid_tag?
  output = ""
  output += "-" if whitespace_trimmed_end?
  output += "}}" if variable?
  output += "%}" if tag?
  output
end

#inside_liquid_tag? ⇒ Boolean

Is this node inside a {% liquid ... %} block?

Returns:

  • (Boolean)


130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/theme_check/liquid_node.rb', line 130

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.



60
61
62
63
64
65
66
67
# File 'lib/theme_check/liquid_node.rb', line 60

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.

Returns:

  • (Boolean)


78
79
80
# File 'lib/theme_check/liquid_node.rb', line 78

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
# File 'lib/theme_check/liquid_node.rb', line 45

def markup
  if tag?
    tag_markup
  elsif @value.instance_variable_defined?(:@markup)
    @value.instance_variable_get(:@markup)
  end
end

#markup=(markup) ⇒ Object



53
54
55
56
57
# File 'lib/theme_check/liquid_node.rb', line 53

def markup=(markup)
  if @value.instance_variable_defined?(:@markup)
    @value.instance_variable_set(:@markup, markup)
  end
end

#source ⇒ Object



123
124
125
# File 'lib/theme_check/liquid_node.rb', line 123

def source
  theme_file&.source
end

#start_index ⇒ Object



69
70
71
# File 'lib/theme_check/liquid_node.rb', line 69

def start_index
  position.start_index
end

#start_token ⇒ Object



167
168
169
170
171
172
173
174
# File 'lib/theme_check/liquid_node.rb', line 167

def start_token
  return "" if inside_liquid_tag?
  output = ""
  output += "{{" if variable?
  output += "{%" if tag?
  output += "-" if whitespace_trimmed_start?
  output
end

#tag? ⇒ Boolean

A tag % node?

Returns:

  • (Boolean)


83
84
85
# File 'lib/theme_check/liquid_node.rb', line 83

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.



119
120
121
# File 'lib/theme_check/liquid_node.rb', line 119

def type_name
  @type_name ||= StringHelpers.underscore(StringHelpers.demodulize(@value.class.name)).to_sym
end

#variable? ⇒ Boolean

Returns:

  • (Boolean)


87
88
89
# File 'lib/theme_check/liquid_node.rb', line 87

def variable?
  @value.is_a?(Liquid::Variable)
end

#whitespace_trimmed_end? ⇒ Boolean

Is this node inside a tag or variable ends starts by removing whitespace. i.e. -%} or -}}

Returns:

  • (Boolean)


157
158
159
160
161
162
163
164
165
# File 'lib/theme_check/liquid_node.rb', line 157

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 {{-

Returns:

  • (Boolean)


146
147
148
149
150
151
152
153
154
# File 'lib/theme_check/liquid_node.rb', line 146

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