Class: BetterHtml::TestHelper::SafeLodashTester::Tester

Inherits:
Object
  • Object
show all
Defined in:
lib/better_html/test_helper/safe_lodash_tester.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(buffer, config: BetterHtml.config) ⇒ Tester

Returns a new instance of Tester.



54
55
56
57
58
59
60
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 54

def initialize(buffer, config: BetterHtml.config)
  @buffer = buffer
  @config = config
  @errors = Errors.new
  @parser = BetterHtml::Parser.new(buffer, template_language: :lodash)
  validate!
end

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



52
53
54
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 52

def errors
  @errors
end

Instance Method Details

#add_error(message, location:) ⇒ Object



62
63
64
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 62

def add_error(message, location:)
  @errors.add(SafetyError.new(message, location: location))
end

#add_no_statement_error(loc) ⇒ Object



130
131
132
133
134
135
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 130

def add_no_statement_error(loc)
  add_error(
    "javascript statement not allowed here; did you mean '[%=' ?",
    location: loc
  )
end

#lodash_nodes(node) ⇒ Object



85
86
87
88
89
90
91
92
93
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 85

def lodash_nodes(node)
  Enumerator.new do |yielder|
    next if node.nil?
    node.descendants(:lodash).each do |lodash_node|
      indicator_node, code_node = *lodash_node
      yielder.yield(lodash_node, indicator_node, code_node)
    end
  end
end

#validate!Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 66

def validate!
  @parser.nodes_with_type(:tag).each do |tag_node|
    tag = Tree::Tag.from_node(tag_node)
    validate_tag_attributes(tag)
    validate_no_statements(tag_node)

    if tag.name == 'script' && !tag.closing?
      add_error(
        "No script tags allowed nested in lodash templates",
        location: tag_node.loc
      )
    end
  end

  @parser.nodes_with_type(:cdata, :comment).each do |node|
    validate_no_statements(node)
  end
end

#validate_no_statements(node) ⇒ Object



124
125
126
127
128
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 124

def validate_no_statements(node)
  lodash_nodes(node).each do |lodash_node, indicator_node, code_node|
    add_no_statement_error(lodash_node.loc) if indicator_node.nil?
  end
end

#validate_tag_attributes(tag) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 95

def validate_tag_attributes(tag)
  tag.attributes.each do |attribute|
    lodash_nodes(attribute.value_node).each do |lodash_node, indicator_node, code_node|
      next if indicator_node.nil?

      if indicator_node.loc.source == '='
        validate_tag_expression(attribute, lodash_node)
      elsif indicator_node.loc.source == '!'
        add_error(
          "lodash interpolation with '[%!' inside html attribute is never safe",
          location: lodash_node.loc
        )
      end
    end
  end
end

#validate_tag_expression(attribute, lodash_node) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 112

def validate_tag_expression(attribute, lodash_node)
  _, code_node = *lodash_node
  source = code_node.loc.source.strip
  if @config.javascript_attribute_name?(attribute.name) && !@config.lodash_safe_javascript_expression?(source)
    add_error(
      "lodash interpolation in javascript attribute "\
      "`#{attribute.name}` must call `JSON.stringify(#{source})`",
      location: lodash_node.loc
    )
  end
end