better_html 1.0.16 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 -10
  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 +33 -31
  32. data/lib/better_html/test_helper/safe_lodash_tester.rb +36 -35
  33. data/lib/better_html/test_helper/safety_error.rb +2 -0
  34. data/lib/better_html/tokenizer/base_erb.rb +14 -10
  35. data/lib/better_html/tokenizer/html_erb.rb +3 -2
  36. data/lib/better_html/tokenizer/html_lodash.rb +22 -14
  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 +39 -147
  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 -46
  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 -129
  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 -146
  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 -29
@@ -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,5 +1,7 @@
1
- require 'better_html/parser'
2
- require 'parser/current'
1
+ # frozen_string_literal: true
2
+
3
+ require "better_html/parser"
4
+ require "parser/current"
3
5
 
4
6
  module BetterHtml
5
7
  module TestHelper
@@ -14,15 +16,17 @@ module BetterHtml
14
16
  end
15
17
  end
16
18
 
17
- def self.parse(code)
18
- parser = ::Parser::CurrentRuby.new(Builder.new)
19
- parser.diagnostics.ignore_warnings = true
20
- parser.diagnostics.all_errors_are_fatal = false
21
- 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
22
25
 
23
- buf = ::Parser::Source::Buffer.new('(string)')
24
- buf.source = code.sub(BLOCK_EXPR, '')
25
- parser.parse(buf)
26
+ buf = ::Parser::Source::Buffer.new("(string)")
27
+ buf.source = code.sub(BLOCK_EXPR, "")
28
+ parser.parse(buf)
29
+ end
26
30
  end
27
31
 
28
32
  def child_nodes
@@ -65,6 +69,7 @@ module BetterHtml
65
69
 
66
70
  def static_return_value?
67
71
  return false if (possible_values = return_values.to_a).empty?
72
+
68
73
  possible_values.all?(&:static_value?)
69
74
  end
70
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 '<%=' ?",