better_html 1.0.14 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -0
  3. data/Rakefile +19 -14
  4. data/ext/better_html_ext/better_html.h +1 -0
  5. data/ext/better_html_ext/extconf.rb +16 -0
  6. data/ext/better_html_ext/html_tokenizer.c +12 -0
  7. data/ext/better_html_ext/html_tokenizer.h +7 -0
  8. data/ext/better_html_ext/parser.c +793 -0
  9. data/ext/better_html_ext/parser.h +93 -0
  10. data/ext/better_html_ext/tokenizer.c +717 -0
  11. data/ext/better_html_ext/tokenizer.h +80 -0
  12. data/lib/better_html/ast/iterator.rb +14 -9
  13. data/lib/better_html/ast/node.rb +4 -2
  14. data/lib/better_html/better_erb/erubi_implementation.rb +43 -39
  15. data/lib/better_html/better_erb/runtime_checks.rb +140 -133
  16. data/lib/better_html/better_erb/validated_output_buffer.rb +30 -22
  17. data/lib/better_html/better_erb.rb +58 -54
  18. data/lib/better_html/config.rb +7 -4
  19. data/lib/better_html/errors.rb +4 -2
  20. data/lib/better_html/helpers.rb +7 -3
  21. data/lib/better_html/html_attributes.rb +6 -2
  22. data/lib/better_html/parser.rb +21 -14
  23. data/lib/better_html/railtie.rb +8 -4
  24. data/lib/better_html/test_helper/ruby_node.rb +15 -9
  25. data/lib/better_html/test_helper/safe_erb/allowed_script_type.rb +8 -4
  26. data/lib/better_html/test_helper/safe_erb/base.rb +12 -9
  27. data/lib/better_html/test_helper/safe_erb/no_javascript_tag_helper.rb +7 -3
  28. data/lib/better_html/test_helper/safe_erb/no_statements.rb +7 -3
  29. data/lib/better_html/test_helper/safe_erb/script_interpolation.rb +9 -4
  30. data/lib/better_html/test_helper/safe_erb/tag_interpolation.rb +23 -20
  31. data/lib/better_html/test_helper/safe_erb_tester.rb +35 -33
  32. data/lib/better_html/test_helper/safe_lodash_tester.rb +36 -34
  33. data/lib/better_html/test_helper/safety_error.rb +2 -0
  34. data/lib/better_html/tokenizer/base_erb.rb +19 -15
  35. data/lib/better_html/tokenizer/html_erb.rb +3 -2
  36. data/lib/better_html/tokenizer/html_lodash.rb +22 -13
  37. data/lib/better_html/tokenizer/javascript_erb.rb +3 -1
  38. data/lib/better_html/tokenizer/location.rb +17 -6
  39. data/lib/better_html/tokenizer/token.rb +2 -0
  40. data/lib/better_html/tokenizer/token_array.rb +8 -8
  41. data/lib/better_html/tree/attribute.rb +10 -6
  42. data/lib/better_html/tree/attributes_list.rb +9 -5
  43. data/lib/better_html/tree/tag.rb +10 -6
  44. data/lib/better_html/version.rb +3 -1
  45. data/lib/better_html.rb +19 -17
  46. data/lib/tasks/better_html_tasks.rake +1 -0
  47. metadata +43 -148
  48. data/lib/better_html/better_erb/erubis_implementation.rb +0 -44
  49. data/test/better_html/better_erb/implementation_test.rb +0 -406
  50. data/test/better_html/errors_test.rb +0 -13
  51. data/test/better_html/helpers_test.rb +0 -49
  52. data/test/better_html/parser_test.rb +0 -314
  53. data/test/better_html/test_helper/ruby_node_test.rb +0 -288
  54. data/test/better_html/test_helper/safe_erb/allowed_script_type_test.rb +0 -45
  55. data/test/better_html/test_helper/safe_erb/no_javascript_tag_helper_test.rb +0 -37
  56. data/test/better_html/test_helper/safe_erb/no_statements_test.rb +0 -128
  57. data/test/better_html/test_helper/safe_erb/script_interpolation_test.rb +0 -149
  58. data/test/better_html/test_helper/safe_erb/tag_interpolation_test.rb +0 -303
  59. data/test/better_html/test_helper/safe_lodash_tester_test.rb +0 -90
  60. data/test/better_html/tokenizer/html_erb_test.rb +0 -180
  61. data/test/better_html/tokenizer/html_lodash_test.rb +0 -98
  62. data/test/better_html/tokenizer/location_test.rb +0 -75
  63. data/test/better_html/tokenizer/token_array_test.rb +0 -145
  64. data/test/better_html/tokenizer/token_test.rb +0 -15
  65. data/test/dummy/README.rdoc +0 -28
  66. data/test/dummy/Rakefile +0 -6
  67. data/test/dummy/app/assets/javascripts/application.js +0 -13
  68. data/test/dummy/app/assets/stylesheets/application.css +0 -15
  69. data/test/dummy/app/controllers/application_controller.rb +0 -5
  70. data/test/dummy/app/helpers/application_helper.rb +0 -2
  71. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  72. data/test/dummy/bin/bundle +0 -3
  73. data/test/dummy/bin/rails +0 -4
  74. data/test/dummy/bin/rake +0 -4
  75. data/test/dummy/bin/setup +0 -29
  76. data/test/dummy/config/application.rb +0 -26
  77. data/test/dummy/config/boot.rb +0 -5
  78. data/test/dummy/config/database.yml +0 -25
  79. data/test/dummy/config/environment.rb +0 -5
  80. data/test/dummy/config/environments/development.rb +0 -41
  81. data/test/dummy/config/environments/production.rb +0 -79
  82. data/test/dummy/config/environments/test.rb +0 -42
  83. data/test/dummy/config/initializers/assets.rb +0 -11
  84. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  85. data/test/dummy/config/initializers/cookies_serializer.rb +0 -3
  86. data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  87. data/test/dummy/config/initializers/inflections.rb +0 -16
  88. data/test/dummy/config/initializers/mime_types.rb +0 -4
  89. data/test/dummy/config/initializers/session_store.rb +0 -3
  90. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  91. data/test/dummy/config/locales/en.yml +0 -23
  92. data/test/dummy/config/routes.rb +0 -56
  93. data/test/dummy/config/secrets.yml +0 -22
  94. data/test/dummy/config.ru +0 -4
  95. data/test/dummy/public/404.html +0 -67
  96. data/test/dummy/public/422.html +0 -67
  97. data/test/dummy/public/500.html +0 -66
  98. data/test/dummy/public/favicon.ico +0 -0
  99. data/test/test_helper.rb +0 -30
@@ -1,10 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BetterHtml
2
4
  class BetterErb
3
5
  class ValidatedOutputBuffer
4
- def self.wrap(output, context, code, auto_escape)
5
- Context.new(output, context, code, auto_escape)
6
- end
7
-
8
6
  class Context
9
7
  def initialize(output, context, code, auto_escape)
10
8
  @output = output
@@ -15,6 +13,7 @@ module BetterHtml
15
13
 
16
14
  def safe_quoted_value_append=(value)
17
15
  return if value.nil?
16
+
18
17
  value = properly_escaped(value)
19
18
 
20
19
  if value.include?(@context[:quote_character])
@@ -22,7 +21,7 @@ module BetterHtml
22
21
  "into a quoted attribute value. The value cannot contain the character #{@context[:quote_character]}."
23
22
  end
24
23
 
25
- @output.safe_append= value
24
+ @output.safe_append = value
26
25
  end
27
26
 
28
27
  def safe_unquoted_value_append=(value)
@@ -40,6 +39,7 @@ module BetterHtml
40
39
 
41
40
  def safe_attribute_name_append=(value)
42
41
  return if value.nil?
42
+
43
43
  value = value.to_s
44
44
 
45
45
  unless value =~ /\A[a-z0-9\-]*\z/
@@ -47,7 +47,7 @@ module BetterHtml
47
47
  "into a attribute name around '#{@context[:attribute_name]}<%=#{@code}%>'."
48
48
  end
49
49
 
50
- @output.safe_append= value
50
+ @output.safe_append = value
51
51
  end
52
52
 
53
53
  def safe_after_attribute_name_append=(value)
@@ -59,7 +59,7 @@ module BetterHtml
59
59
  "try <#{@context[:tag_name]} <%= html_attributes(attr: value) %>>."
60
60
  end
61
61
 
62
- @output.safe_append= value.to_s
62
+ @output.safe_append = value.to_s
63
63
  end
64
64
 
65
65
  def safe_after_equal_append=(value)
@@ -76,11 +76,12 @@ module BetterHtml
76
76
  "try <#{@context[:tag_name]} <%= html_attributes(attr: value) %>>."
77
77
  end
78
78
 
79
- @output.safe_append= value.to_s
79
+ @output.safe_append = value.to_s
80
80
  end
81
81
 
82
82
  def safe_tag_name_append=(value)
83
83
  return if value.nil?
84
+
84
85
  value = value.to_s
85
86
 
86
87
  unless value =~ /\A[a-z0-9\:\-]*\z/
@@ -88,7 +89,7 @@ module BetterHtml
88
89
  "into a tag name around: <#{@context[:tag_name]}<%=#{@code}%>>."
89
90
  end
90
91
 
91
- @output.safe_append= value
92
+ @output.safe_append = value
92
93
  end
93
94
 
94
95
  def safe_rawtext_append=(value)
@@ -96,23 +97,25 @@ module BetterHtml
96
97
 
97
98
  value = properly_escaped(value)
98
99
 
99
- if @context[:tag_name].downcase == 'script' &&
100
- (value =~ /<script/i || value =~ /<\/script/i)
100
+ if @context[:tag_name].downcase == "script" &&
101
+ (value =~ /<script/i || value =~ %r{</script}i)
101
102
  # https://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements
102
103
  raise UnsafeHtmlError, "Detected invalid characters as part of the interpolation "\
103
104
  "into a script tag around: <#{@context[:tag_name]}>#{@context[:rawtext_text]}<%=#{@code}%>. "\
104
105
  "A script tag cannot contain <script or </script anywhere inside of it."
105
106
  elsif value =~ /<#{Regexp.escape(@context[:tag_name].downcase)}/i ||
106
- value =~ /<\/#{Regexp.escape(@context[:tag_name].downcase)}/i
107
+ value =~ %r{</#{Regexp.escape(@context[:tag_name].downcase)}}i
107
108
  raise UnsafeHtmlError, "Detected invalid characters as part of the interpolation "\
108
- "into a #{@context[:tag_name].downcase} tag around: <#{@context[:tag_name]}>#{@context[:rawtext_text]}<%=#{@code}%>."
109
+ "into a #{@context[:tag_name].downcase} tag around: " \
110
+ "<#{@context[:tag_name]}>#{@context[:rawtext_text]}<%=#{@code}%>."
109
111
  end
110
112
 
111
- @output.safe_append= value
113
+ @output.safe_append = value
112
114
  end
113
115
 
114
116
  def safe_comment_append=(value)
115
117
  return if value.nil?
118
+
116
119
  value = properly_escaped(value)
117
120
 
118
121
  # in a <!-- ...here --> we disallow -->
@@ -121,12 +124,13 @@ module BetterHtml
121
124
  "into a html comment around: <!--#{@context[:comment_text]}<%=#{@code}%>."
122
125
  end
123
126
 
124
- @output.safe_append= value
127
+ @output.safe_append = value
125
128
  end
126
129
 
127
130
  def safe_none_append=(value)
128
131
  return if value.nil?
129
- @output.safe_append= properly_escaped(value)
132
+
133
+ @output.safe_append = properly_escaped(value)
130
134
  end
131
135
 
132
136
  private
@@ -135,13 +139,11 @@ module BetterHtml
135
139
  if value.is_a?(ValidatedOutputBuffer)
136
140
  # in html context, never escape a ValidatedOutputBuffer
137
141
  value.to_s
138
- else
142
+ elsif @auto_escape
139
143
  # in html context, follow auto_escape rule
140
- if @auto_escape
141
- auto_escape_html_safe_value(value.to_s)
142
- else
143
- value.to_s
144
- end
144
+ auto_escape_html_safe_value(value.to_s)
145
+ else
146
+ value.to_s
145
147
  end
146
148
  end
147
149
 
@@ -150,6 +152,12 @@ module BetterHtml
150
152
  end
151
153
  end
152
154
 
155
+ class << self
156
+ def wrap(output, context, code, auto_escape)
157
+ Context.new(output, context, code, auto_escape)
158
+ end
159
+ end
160
+
153
161
  def html_safe?
154
162
  true
155
163
  end
@@ -1,74 +1,78 @@
1
- require 'action_view'
2
- if ActionView.version < Gem::Version.new("5.1")
3
- require 'better_html/better_erb/erubis_implementation'
4
- else
5
- require 'better_html/better_erb/erubi_implementation'
6
- end
7
- require 'better_html/better_erb/validated_output_buffer'
1
+ # frozen_string_literal: true
8
2
 
3
+ require "action_view"
9
4
 
10
- class BetterHtml::BetterErb
11
- cattr_accessor :content_types
12
- if ActionView.version < Gem::Version.new("5.1")
13
- self.content_types = {
14
- 'html.erb' => BetterHtml::BetterErb::ErubisImplementation
15
- }
16
- else
17
- self.content_types = {
18
- 'html.erb' => BetterHtml::BetterErb::ErubiImplementation
19
- }
20
- end
5
+ require "better_html_ext"
6
+ require "better_html/better_erb/erubi_implementation"
7
+ require "better_html/better_erb/validated_output_buffer"
8
+
9
+ module BetterHtml
10
+ class ParserError < RuntimeError
11
+ attr_reader :position, :line, :column
21
12
 
22
- def self.prepend!
23
- ActionView::Template::Handlers::ERB.prepend(ConditionalImplementation)
13
+ def initialize(message, position, line, column)
14
+ super(message)
15
+ @position = position
16
+ @line = line
17
+ @column = column
18
+ end
24
19
  end
20
+ end
25
21
 
26
- private
22
+ module BetterHtml
23
+ class BetterErb
24
+ cattr_accessor :content_types
27
25
 
28
- module ConditionalImplementation
26
+ self.content_types = {
27
+ "html.erb" => BetterHtml::BetterErb::ErubiImplementation,
28
+ }
29
29
 
30
- def call(template, source = nil)
31
- generate(template, source)
30
+ class << self
31
+ def prepend!
32
+ ActionView::Template::Handlers::ERB.prepend(ConditionalImplementation)
33
+ end
32
34
  end
33
35
 
34
- private
36
+ module ConditionalImplementation
37
+ def call(template, source = nil)
38
+ generate(template, source)
39
+ end
40
+
41
+ private
35
42
 
36
- def generate(template, source)
37
- # First, convert to BINARY, so in case the encoding is
38
- # wrong, we can still find an encoding tag
39
- # (<%# encoding %>) inside the String using a regular
40
- # expression
43
+ def generate(template, source)
44
+ # First, convert to BINARY, so in case the encoding is
45
+ # wrong, we can still find an encoding tag
46
+ # (<%# encoding %>) inside the String using a regular
47
+ # expression
41
48
 
42
- source ||= template.source
43
- filename = template.identifier.split("/").last
44
- exts = filename.split(".")
45
- exts = exts[1..exts.length].join(".")
46
- template_source = source.dup.force_encoding(Encoding::ASCII_8BIT)
49
+ source ||= template.source
50
+ filename = template.identifier.split("/").last
51
+ exts = filename.split(".")
52
+ exts = exts[1..exts.length].join(".")
53
+ template_source = source.dup.force_encoding(Encoding::ASCII_8BIT)
47
54
 
48
- erb = template_source.gsub(ActionView::Template::Handlers::ERB::ENCODING_TAG, '')
49
- encoding = $2
55
+ erb = template_source.gsub(ActionView::Template::Handlers::ERB::ENCODING_TAG, "")
56
+ encoding = Regexp.last_match(2)
50
57
 
51
- erb.force_encoding valid_encoding(source.dup, encoding)
58
+ erb.force_encoding(valid_encoding(source.dup, encoding))
52
59
 
53
- # Always make sure we return a String in the default_internal
54
- erb.encode!
60
+ # Always make sure we return a String in the default_internal
61
+ erb.encode!
55
62
 
56
- excluded_template = !!BetterHtml.config.template_exclusion_filter&.call(template.identifier)
57
- klass = BetterHtml::BetterErb.content_types[exts] unless excluded_template
58
- klass ||= self.class.erb_implementation
63
+ excluded_template = !!BetterHtml.config.template_exclusion_filter&.call(template.identifier)
64
+ klass = BetterHtml::BetterErb.content_types[exts] unless excluded_template
65
+ klass ||= self.class.erb_implementation
59
66
 
60
- escape = if ActionView::VERSION::MAJOR <= 5
61
- self.class.escape_whitelist.include?(template.type)
62
- else
63
- self.class.escape_ignore_list.include?(template.type)
67
+ escape = self.class.escape_ignore_list.include?(template.type)
68
+ generator = klass.new(
69
+ erb,
70
+ escape: escape,
71
+ trim: (self.class.erb_trim_mode == "-")
72
+ )
73
+ generator.validate! if generator.respond_to?(:validate!)
74
+ generator.src
64
75
  end
65
- generator = klass.new(
66
- erb,
67
- :escape => escape,
68
- :trim => (self.class.erb_trim_mode == "-")
69
- )
70
- generator.validate! if generator.respond_to?(:validate!)
71
- generator.src
72
76
  end
73
77
  end
74
78
  end
@@ -1,4 +1,6 @@
1
- require 'smart_properties'
1
+ # frozen_string_literal: true
2
+
3
+ require "smart_properties"
2
4
 
3
5
  module BetterHtml
4
6
  class Config
@@ -8,17 +10,18 @@ module BetterHtml
8
10
  property :partial_attribute_name_pattern, default: -> { /\A[a-zA-Z0-9\-\:]+\z/ }
9
11
  property :allow_single_quoted_attributes, default: true
10
12
  property :allow_unquoted_attributes, default: false
11
- property :javascript_safe_methods, default: -> { ['to_json'] }
13
+ property :javascript_safe_methods, default: -> { ["to_json"] }
12
14
  property :javascript_attribute_names, default: -> { [/\Aon/i] }
13
15
  property :template_exclusion_filter
14
16
  property :lodash_safe_javascript_expression, default: -> { [/\AJSON\.stringify\(/] }
17
+ property :disable_parser_validation, default: false
15
18
 
16
19
  def javascript_attribute_name?(name)
17
- javascript_attribute_names.any?{ |other| other === name.to_s }
20
+ javascript_attribute_names.any? { |other| other === name.to_s } # rubocop:disable Style/CaseEquality
18
21
  end
19
22
 
20
23
  def lodash_safe_javascript_expression?(code)
21
- lodash_safe_javascript_expression.any?{ |other| other === code }
24
+ lodash_safe_javascript_expression.any? { |other| other === code } # rubocop:disable Style/CaseEquality
22
25
  end
23
26
 
24
27
  def javascript_safe_method?(name)
@@ -1,5 +1,7 @@
1
- require 'active_support/core_ext/string/output_safety'
2
- require 'action_view'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/output_safety"
4
+ require "action_view"
3
5
 
4
6
  module BetterHtml
5
7
  class InterpolatorError < RuntimeError; end
@@ -1,5 +1,9 @@
1
- module BetterHtml::Helpers
2
- def html_attributes(args)
3
- BetterHtml::HtmlAttributes.new(args)
1
+ # frozen_string_literal: true
2
+
3
+ module BetterHtml
4
+ module Helpers
5
+ def html_attributes(args)
6
+ BetterHtml::HtmlAttributes.new(args)
7
+ end
4
8
  end
5
9
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BetterHtml
2
4
  class HtmlAttributes
3
5
  def initialize(data)
@@ -7,10 +9,12 @@ module BetterHtml
7
9
  def to_s
8
10
  @data.map do |key, value|
9
11
  unless key =~ BetterHtml.config.partial_attribute_name_pattern
10
- raise ArgumentError, "Attribute names must match the pattern #{BetterHtml.config.partial_attribute_name_pattern.inspect}"
12
+ raise ArgumentError,
13
+ "Attribute names must match the pattern #{BetterHtml.config.partial_attribute_name_pattern.inspect}"
11
14
  end
15
+
12
16
  if value.nil?
13
- "#{key}"
17
+ key.to_s
14
18
  else
15
19
  value = value.to_s
16
20
  escaped_value = value.html_safe? ? value : CGI.escapeHTML(value)
@@ -1,10 +1,12 @@
1
- require_relative 'tokenizer/javascript_erb'
2
- require_relative 'tokenizer/html_erb'
3
- require_relative 'tokenizer/html_lodash'
4
- require_relative 'tokenizer/location'
5
- require_relative 'tokenizer/token_array'
6
- require_relative 'ast/node'
7
- require 'parser/source/buffer'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "tokenizer/javascript_erb"
4
+ require_relative "tokenizer/html_erb"
5
+ require_relative "tokenizer/html_lodash"
6
+ require_relative "tokenizer/location"
7
+ require_relative "tokenizer/token_array"
8
+ require_relative "ast/node"
9
+ require "parser/source/buffer"
8
10
 
9
11
  module BetterHtml
10
12
  class Parser
@@ -21,7 +23,8 @@ module BetterHtml
21
23
  end
22
24
 
23
25
  def initialize(buffer, template_language: :html)
24
- raise ArgumentError, 'first argument must be Parser::Source::Buffer' unless buffer.is_a?(::Parser::Source::Buffer)
26
+ raise ArgumentError, "first argument must be Parser::Source::Buffer" unless buffer.is_a?(::Parser::Source::Buffer)
27
+
25
28
  @buffer = buffer
26
29
  @template_language = template_language
27
30
  @erb = case template_language
@@ -38,7 +41,7 @@ module BetterHtml
38
41
 
39
42
  def nodes_with_type(*type)
40
43
  types = Array.wrap(type)
41
- ast.children.select{ |node| node.is_a?(::AST::Node) && types.include?(node.type) }
44
+ ast.children.select { |node| node.is_a?(::AST::Node) && types.include?(node.type) }
42
45
  end
43
46
 
44
47
  def ast
@@ -76,7 +79,8 @@ module BetterHtml
76
79
  when :text, *INTERPOLATION_TYPES
77
80
  children << build_text_node(tokens)
78
81
  else
79
- raise RuntimeError, "Unhandled token #{tokens.current.type} line #{tokens.current.loc.line} column #{tokens.current.loc.column}, #{children.inspect}"
82
+ raise "Unhandled token #{tokens.current.type} line #{tokens.current.loc.line} column " \
83
+ "#{tokens.current.loc.column}, #{children.inspect}"
80
84
  end
81
85
  end
82
86
 
@@ -141,6 +145,7 @@ module BetterHtml
141
145
  attributes_tokens = []
142
146
  while tokens.any?
143
147
  break if tokens.size == 1 && tokens.last.type == :solidus
148
+
144
149
  if tokens.current.type == :attribute_name
145
150
  attributes_tokens << build_attribute_node(tokens)
146
151
  elsif tokens.current.type == :attribute_quoted_value_start
@@ -148,7 +153,7 @@ module BetterHtml
148
153
  elsif tokens.current.type == :erb_begin
149
154
  attributes_tokens << build_erb_node(tokens)
150
155
  else
151
- # todo: warn about ignored things
156
+ # TODO: warn about ignored things
152
157
  tokens.shift
153
158
  end
154
159
  end
@@ -179,8 +184,7 @@ module BetterHtml
179
184
  def build_attribute_value_node(tokens)
180
185
  children = shift_all_with_interpolation(tokens,
181
186
  :attribute_quoted_value_start, :attribute_quoted_value,
182
- :attribute_quoted_value_end, :attribute_unquoted_value
183
- )
187
+ :attribute_quoted_value_end, :attribute_unquoted_value)
184
188
 
185
189
  build_node(:attribute_value, children)
186
190
  end
@@ -201,6 +205,7 @@ module BetterHtml
201
205
  def build_location(enumerable)
202
206
  enumerable = enumerable.compact
203
207
  raise ArgumentError, "cannot build location for #{enumerable.inspect}" unless enumerable.first && enumerable.last
208
+
204
209
  Tokenizer::Location.new(@buffer, enumerable.first.loc.begin_pos, enumerable.last.loc.end_pos)
205
210
  end
206
211
 
@@ -289,9 +294,11 @@ module BetterHtml
289
294
 
290
295
  def wrap_token(object)
291
296
  return unless object
297
+
292
298
  if object.is_a?(::AST::Node)
293
299
  object
294
- elsif [:text, :tag_name, :attribute_name, :attribute_quoted_value, :attribute_unquoted_value].include?(object.type)
300
+ elsif [:text, :tag_name, :attribute_name, :attribute_quoted_value,
301
+ :attribute_unquoted_value,].include?(object.type)
295
302
  object.loc.source
296
303
  elsif [:attribute_quoted_value_start, :attribute_quoted_value_end].include?(object.type)
297
304
  BetterHtml::AST::Node.new(:quote, [object.loc.source], loc: object.loc)
@@ -1,7 +1,11 @@
1
- require 'better_html/better_erb'
1
+ # frozen_string_literal: true
2
2
 
3
- class BetterHtml::Railtie < Rails::Railtie
4
- initializer "better_html.better_erb.initialization" do
5
- BetterHtml::BetterErb.prepend!
3
+ require "better_html/better_erb"
4
+
5
+ module BetterHtml
6
+ class Railtie < Rails::Railtie
7
+ initializer "better_html.better_erb.initialization" do
8
+ BetterHtml::BetterErb.prepend!
9
+ end
6
10
  end
7
11
  end
@@ -1,4 +1,7 @@
1
- require 'parser/current'
1
+ # frozen_string_literal: true
2
+
3
+ require "better_html/parser"
4
+ require "parser/current"
2
5
 
3
6
  module BetterHtml
4
7
  module TestHelper
@@ -13,15 +16,17 @@ module BetterHtml
13
16
  end
14
17
  end
15
18
 
16
- def self.parse(code)
17
- parser = ::Parser::CurrentRuby.new(Builder.new)
18
- parser.diagnostics.ignore_warnings = true
19
- parser.diagnostics.all_errors_are_fatal = false
20
- parser.diagnostics.consumer = nil
19
+ class << self
20
+ def parse(code)
21
+ parser = ::Parser::CurrentRuby.new(Builder.new)
22
+ parser.diagnostics.ignore_warnings = true
23
+ parser.diagnostics.all_errors_are_fatal = false
24
+ parser.diagnostics.consumer = nil
21
25
 
22
- buf = ::Parser::Source::Buffer.new('(string)')
23
- buf.source = code.sub(BLOCK_EXPR, '')
24
- parser.parse(buf)
26
+ buf = ::Parser::Source::Buffer.new("(string)")
27
+ buf.source = code.sub(BLOCK_EXPR, "")
28
+ parser.parse(buf)
29
+ end
25
30
  end
26
31
 
27
32
  def child_nodes
@@ -64,6 +69,7 @@ module BetterHtml
64
69
 
65
70
  def static_return_value?
66
71
  return false if (possible_values = return_values.to_a).empty?
72
+
67
73
  possible_values.all?(&:static_value?)
68
74
  end
69
75
 
@@ -1,10 +1,12 @@
1
- require_relative 'base'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
2
4
 
3
5
  module BetterHtml
4
6
  module TestHelper
5
7
  module SafeErb
6
8
  class AllowedScriptType < Base
7
- VALID_JAVASCRIPT_TAG_TYPES = ['text/javascript', 'text/template', 'text/html']
9
+ VALID_JAVASCRIPT_TAG_TYPES = ["application/ld+json", "text/javascript", "text/template", "text/html"]
8
10
 
9
11
  def validate
10
12
  script_tags.each do |tag, _|
@@ -15,11 +17,13 @@ module BetterHtml
15
17
  private
16
18
 
17
19
  def validate_type(tag)
18
- return unless type_attribute = tag.attributes['type']
20
+ type_attribute = tag.attributes["type"]
21
+
22
+ return unless type_attribute
19
23
  return if VALID_JAVASCRIPT_TAG_TYPES.include?(type_attribute.value)
20
24
 
21
25
  add_error(
22
- "#{type_attribute.value} is not a valid type, valid types are #{VALID_JAVASCRIPT_TAG_TYPES.join(', ')}",
26
+ "#{type_attribute.value} is not a valid type, valid types are #{VALID_JAVASCRIPT_TAG_TYPES.join(", ")}",
23
27
  location: type_attribute.loc
24
28
  )
25
29
  end
@@ -1,7 +1,9 @@
1
- require 'better_html/errors'
2
- require 'better_html/tree/tag'
3
- require 'better_html/test_helper/safety_error'
4
- require 'ast'
1
+ # frozen_string_literal: true
2
+
3
+ require "better_html/errors"
4
+ require "better_html/tree/tag"
5
+ require "better_html/test_helper/safety_error"
6
+ require "ast"
5
7
 
6
8
  module BetterHtml
7
9
  module TestHelper
@@ -24,6 +26,7 @@ module BetterHtml
24
26
  def erb_nodes(root_node)
25
27
  Enumerator.new do |yielder|
26
28
  next if root_node.nil?
29
+
27
30
  root_node.descendants(:erb).each do |erb_node|
28
31
  indicator_node, _, code_node, _ = *erb_node
29
32
  yielder.yield(erb_node, indicator_node, code_node)
@@ -37,12 +40,12 @@ module BetterHtml
37
40
  tag = Tree::Tag.from_node(tag_node)
38
41
  next if tag.closing?
39
42
 
40
- if tag.name == 'script'
41
- index = ast.to_a.find_index(tag_node)
42
- next_node = ast.to_a[index + 1]
43
+ next unless tag.name == "script"
44
+
45
+ index = ast.to_a.find_index(tag_node)
46
+ next_node = ast.to_a[index + 1]
43
47
 
44
- yielder.yield(tag, next_node&.type == :text ? next_node : nil)
45
- end
48
+ yielder.yield(tag, next_node&.type == :text ? next_node : nil)
46
49
  end
47
50
  end
48
51
  end
@@ -1,5 +1,7 @@
1
- require_relative 'base'
2
- require 'better_html/test_helper/ruby_node'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require "better_html/test_helper/ruby_node"
3
5
 
4
6
  module BetterHtml
5
7
  module TestHelper
@@ -14,7 +16,8 @@ module BetterHtml
14
16
  def no_javascript_tag_helper(node)
15
17
  erb_nodes(node).each do |erb_node, indicator_node, code_node|
16
18
  indicator = indicator_node&.loc&.source
17
- next if indicator == '#' || indicator == '%'
19
+ next if indicator == "#" || indicator == "%"
20
+
18
21
  source = code_node.loc.source
19
22
 
20
23
  ruby_node = begin
@@ -23,6 +26,7 @@ module BetterHtml
23
26
  nil
24
27
  end
25
28
  next unless ruby_node
29
+
26
30
  ruby_node.descendants(:send, :csend).each do |send_node|
27
31
  next unless send_node.method_name?(:javascript_tag)
28
32
 
@@ -1,4 +1,6 @@
1
- require_relative 'base'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
2
4
 
3
5
  module BetterHtml
4
6
  module TestHelper
@@ -6,7 +8,7 @@ module BetterHtml
6
8
  class NoStatements < Base
7
9
  def validate
8
10
  script_tags.each do |tag, content_node|
9
- no_statements(content_node) unless content_node.present? && tag.attributes['type']&.value == "text/html"
11
+ no_statements(content_node) unless content_node.present? && tag.attributes["type"]&.value == "text/html"
10
12
  end
11
13
 
12
14
  if @parser.template_language == :javascript
@@ -25,8 +27,10 @@ module BetterHtml
25
27
  def no_statements(node)
26
28
  erb_nodes(node).each do |erb_node, indicator_node, code_node|
27
29
  next unless indicator_node.nil?
30
+
28
31
  source = code_node.loc.source
29
- next if /\A\s*end/m === source
32
+
33
+ next if /\A\s*end/m.match?(source)
30
34
 
31
35
  add_error(
32
36
  "erb statement not allowed here; did you mean '<%=' ?",