erb_lint 0.1.3 → 0.9.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/exe/erb_lint +10 -0
  3. data/exe/erblint +5 -4
  4. data/lib/erb_lint/all.rb +2 -0
  5. data/lib/erb_lint/cache.rb +88 -0
  6. data/lib/erb_lint/cached_offense.rb +58 -0
  7. data/lib/erb_lint/cli.rb +117 -22
  8. data/lib/erb_lint/corrector.rb +6 -17
  9. data/lib/erb_lint/file_loader.rb +2 -8
  10. data/lib/erb_lint/linter.rb +28 -2
  11. data/lib/erb_lint/linter_registry.rb +11 -1
  12. data/lib/erb_lint/linters/allowed_script_type.rb +8 -7
  13. data/lib/erb_lint/linters/closing_erb_tag_indent.rb +3 -3
  14. data/lib/erb_lint/linters/comment_syntax.rb +52 -0
  15. data/lib/erb_lint/linters/deprecated_classes.rb +2 -2
  16. data/lib/erb_lint/linters/erb_safety.rb +1 -1
  17. data/lib/erb_lint/linters/extra_newline.rb +1 -1
  18. data/lib/erb_lint/linters/final_newline.rb +4 -4
  19. data/lib/erb_lint/linters/hard_coded_string.rb +7 -4
  20. data/lib/erb_lint/linters/no_javascript_tag_helper.rb +6 -4
  21. data/lib/erb_lint/linters/no_unused_disable.rb +47 -0
  22. data/lib/erb_lint/linters/parser_errors.rb +1 -1
  23. data/lib/erb_lint/linters/partial_instance_variable.rb +2 -2
  24. data/lib/erb_lint/linters/require_input_autocomplete.rb +4 -4
  25. data/lib/erb_lint/linters/require_script_nonce.rb +2 -2
  26. data/lib/erb_lint/linters/right_trim.rb +1 -1
  27. data/lib/erb_lint/linters/rubocop.rb +32 -83
  28. data/lib/erb_lint/linters/rubocop_text.rb +2 -1
  29. data/lib/erb_lint/linters/self_closing_tag.rb +22 -5
  30. data/lib/erb_lint/linters/space_around_erb_tag.rb +8 -8
  31. data/lib/erb_lint/linters/space_in_html_tag.rb +7 -7
  32. data/lib/erb_lint/linters/space_indentation.rb +1 -1
  33. data/lib/erb_lint/linters/strict_locals.rb +50 -0
  34. data/lib/erb_lint/linters/trailing_whitespace.rb +1 -1
  35. data/lib/erb_lint/offense.rb +30 -3
  36. data/lib/erb_lint/processed_source.rb +1 -1
  37. data/lib/erb_lint/reporter.rb +3 -2
  38. data/lib/erb_lint/reporters/compact_reporter.rb +3 -2
  39. data/lib/erb_lint/reporters/gitlab_reporter.rb +55 -0
  40. data/lib/erb_lint/reporters/json_reporter.rb +4 -4
  41. data/lib/erb_lint/reporters/junit_reporter.rb +63 -0
  42. data/lib/erb_lint/reporters/multiline_reporter.rb +6 -1
  43. data/lib/erb_lint/runner.rb +36 -3
  44. data/lib/erb_lint/runner_config.rb +2 -1
  45. data/lib/erb_lint/runner_config_resolver.rb +1 -1
  46. data/lib/erb_lint/utils/block_map.rb +4 -4
  47. data/lib/erb_lint/utils/inline_configs.rb +15 -0
  48. data/lib/erb_lint/utils/severity_levels.rb +8 -2
  49. data/lib/erb_lint/version.rb +1 -1
  50. metadata +21 -28
  51. data/lib/erb_lint/utils/offset_corrector.rb +0 -72
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ERBLint
4
+ module Linters
5
+ # Detects comment syntax that isn't valid ERB.
6
+ class CommentSyntax < Linter
7
+ include LinterRegistry
8
+
9
+ def initialize(file_loader, config)
10
+ super
11
+ end
12
+
13
+ def run(processed_source)
14
+ file_content = processed_source.file_content
15
+ return if file_content.empty?
16
+
17
+ processed_source.ast.descendants(:erb).each do |erb_node|
18
+ indicator_node, _, code_node, _ = *erb_node
19
+ next if code_node.nil?
20
+
21
+ indicator_node_str = indicator_node&.deconstruct&.last
22
+ next if indicator_node_str == "#"
23
+
24
+ code_node_str = code_node.deconstruct.last
25
+ next unless code_node_str.start_with?(" #")
26
+
27
+ range = find_range(erb_node, code_node_str)
28
+ source_range = processed_source.to_source_range(range)
29
+
30
+ correct_erb_tag = indicator_node_str == "=" ? "<%#=" : "<%#"
31
+
32
+ add_offense(
33
+ source_range,
34
+ <<~EOF.chomp,
35
+ Bad ERB comment syntax. Should be #{correct_erb_tag} without a space between.
36
+ Leaving a space between ERB tags and the Ruby comment character can cause parser errors.
37
+ EOF
38
+ )
39
+ end
40
+ end
41
+
42
+ def find_range(node, str)
43
+ match = node.loc.source.match(Regexp.new(Regexp.quote(str.strip)))
44
+ return unless match
45
+
46
+ range_begin = match.begin(0) + node.loc.begin_pos
47
+ range_end = match.end(0) + node.loc.begin_pos
48
+ (range_begin...range_end)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -49,7 +49,7 @@ module ERBLint
49
49
  process_nested_offenses(
50
50
  source: sub_source,
51
51
  offset: offset + content_node.loc.begin_pos,
52
- parent_source: parent_source
52
+ parent_source: parent_source,
53
53
  )
54
54
  end
55
55
  end
@@ -99,7 +99,7 @@ module ERBLint
99
99
 
100
100
  add_offense(
101
101
  range,
102
- format(message, class_name, violated_rule[:class_expr], suggestion)
102
+ format(message, class_name, violated_rule[:class_expr], suggestion),
103
103
  )
104
104
  end
105
105
  end
@@ -26,7 +26,7 @@ module ERBLint
26
26
  tester.errors.each do |error|
27
27
  add_offense(
28
28
  error.location,
29
- error.message
29
+ error.message,
30
30
  )
31
31
  end
32
32
  end
@@ -15,7 +15,7 @@ module ERBLint
15
15
  add_offense(
16
16
  processed_source
17
17
  .to_source_range((matches.begin(index) + 2)...matches.end(index)),
18
- "Extra blank line detected."
18
+ "Extra blank line detected.",
19
19
  )
20
20
  end
21
21
  end
@@ -29,22 +29,22 @@ module ERBLint
29
29
  add_offense(
30
30
  processed_source.to_source_range(file_content.size...file_content.size),
31
31
  "Missing a trailing newline at the end of the file.",
32
- :insert
32
+ :insert,
33
33
  )
34
34
  else
35
35
  add_offense(
36
36
  processed_source.to_source_range(
37
- (file_content.size - final_newline.size + 1)...file_content.size
37
+ (file_content.size - final_newline.size + 1)...file_content.size,
38
38
  ),
39
39
  "Remove multiple trailing newline at the end of the file.",
40
- :remove
40
+ :remove,
41
41
  )
42
42
  end
43
43
  elsif !@new_lines_should_be_present && !final_newline.empty?
44
44
  add_offense(
45
45
  processed_source.to_source_range(match.begin(0)...match.end(0)),
46
46
  "Remove #{final_newline.size} trailing newline at the end of the file.",
47
- :remove
47
+ :remove,
48
48
  )
49
49
  end
50
50
  end
@@ -17,7 +17,7 @@ module ERBLint
17
17
  ALLOWED_CORRECTORS = ["I18nCorrector", "RuboCop::Corrector::I18n::HardCodedString"]
18
18
 
19
19
  NON_TEXT_TAGS = Set.new(["script", "style", "xmp", "iframe", "noembed", "noframes", "listing"])
20
- TEXT_NOT_ALLOWED = Set.new([
20
+ NO_TRANSLATION_NEEDED = Set.new([
21
21
  "&nbsp;",
22
22
  "&amp;",
23
23
  "&lt;",
@@ -40,6 +40,9 @@ module ERBLint
40
40
  "&ensp;",
41
41
  "&emsp;",
42
42
  "&thinsp;",
43
+ "&times;",
44
+ "&laquo;",
45
+ "&raquo;",
43
46
  ])
44
47
 
45
48
  class ConfigSchema < LinterConfig
@@ -66,7 +69,7 @@ module ERBLint
66
69
 
67
70
  add_offense(
68
71
  source_range,
69
- message(source_range.source)
72
+ message(source_range.source),
70
73
  )
71
74
  end
72
75
  end
@@ -83,7 +86,7 @@ module ERBLint
83
86
  def autocorrect(processed_source, offense)
84
87
  string = offense.source_range.source
85
88
  return unless (klass = load_corrector)
86
- return unless string.strip.length > 1
89
+ return if string.strip.length <= 1
87
90
 
88
91
  node = ::RuboCop::AST::StrNode.new(:str, [string])
89
92
  corrector = klass.new(node, processed_source.filename, corrector_i18n_load_path, offense.source_range)
@@ -96,7 +99,7 @@ module ERBLint
96
99
 
97
100
  def check_string?(str)
98
101
  string = str.gsub(/\s*/, "")
99
- string.length > 1 && !TEXT_NOT_ALLOWED.include?(string)
102
+ string.length > 1 && !NO_TRANSLATION_NEEDED.include?(string)
100
103
  end
101
104
 
102
105
  def load_corrector
@@ -38,9 +38,9 @@ module ERBLint
38
38
 
39
39
  add_offense(
40
40
  erb_node.loc,
41
- "Avoid using 'javascript_tag do' as it confuses tests "\
41
+ "Avoid using 'javascript_tag do' as it confuses tests " \
42
42
  "that validate html, use inline <script> instead",
43
- [erb_node, send_node]
43
+ [erb_node, send_node],
44
44
  )
45
45
  end
46
46
  end
@@ -82,8 +82,10 @@ module ERBLint
82
82
  corrector.replace(end_node.loc, end_content)
83
83
  elsif script_content
84
84
  script_content = "\n//<![CDATA[\n#{script_content}\n//]]>\n" if @config.correction_style == :cdata
85
- corrector.replace(begin_node.loc,
86
- "<script#{arguments}>#{script_content}</script>")
85
+ corrector.replace(
86
+ begin_node.loc,
87
+ "<script#{arguments}>#{script_content}</script>",
88
+ )
87
89
  end
88
90
  rescue Utils::RubyToERB::Error, Utils::BlockMap::ParseError
89
91
  nil
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb_lint/utils/inline_configs"
4
+
5
+ module ERBLint
6
+ module Linters
7
+ # Checks for unused disable comments.
8
+ class NoUnusedDisable < Linter
9
+ include LinterRegistry
10
+
11
+ def run(processed_source, offenses)
12
+ disabled_rules_and_line_number = {}
13
+
14
+ processed_source.source_buffer.source_lines.each_with_index do |line, index|
15
+ rule_disables = Utils::InlineConfigs.disabled_rules(line)
16
+ next unless rule_disables
17
+
18
+ rule_disables.split(",").each do |rule|
19
+ disabled_rules_and_line_number[rule.strip] =
20
+ (disabled_rules_and_line_number[rule.strip] ||= []).push(index + 1)
21
+ end
22
+ end
23
+
24
+ offenses.each do |offense|
25
+ rule_name = offense.linter.class.simple_name
26
+ line_numbers = disabled_rules_and_line_number[rule_name]
27
+ next unless line_numbers
28
+
29
+ line_numbers.reject do |line_number|
30
+ if (offense.source_range.line_span.first..offense.source_range.line_span.last).include?(line_number)
31
+ disabled_rules_and_line_number[rule_name].delete(line_number)
32
+ end
33
+ end
34
+ end
35
+
36
+ disabled_rules_and_line_number.each do |rule, line_numbers|
37
+ line_numbers.each do |line_number|
38
+ add_offense(
39
+ processed_source.source_buffer.line_range(line_number),
40
+ "Unused erblint:disable comment for #{rule}",
41
+ )
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -9,7 +9,7 @@ module ERBLint
9
9
  processed_source.parser.parser_errors.each do |error|
10
10
  add_offense(
11
11
  error.loc,
12
- "#{error.message} (at #{error.loc.source})"
12
+ "#{error.message} (at #{error.loc.source})",
13
13
  )
14
14
  end
15
15
  end
@@ -13,9 +13,9 @@ module ERBLint
13
13
 
14
14
  add_offense(
15
15
  processed_source.to_source_range(
16
- processed_source.file_content =~ instance_variable_regex..processed_source.file_content.size
16
+ processed_source.file_content =~ instance_variable_regex..processed_source.file_content.size,
17
17
  ),
18
- "Instance variable detected in partial."
18
+ "Instance variable detected in partial.",
19
19
  )
20
20
  end
21
21
  end
@@ -62,9 +62,9 @@ module ERBLint
62
62
 
63
63
  add_offense(
64
64
  tag_node.to_a[1].loc,
65
- "Input tag is missing an autocomplete attribute. If no "\
65
+ "Input tag is missing an autocomplete attribute. If no " \
66
66
  "autocomplete behaviour is desired, use the value `off` or `nope`.",
67
- [autocomplete_attribute]
67
+ [autocomplete_attribute],
68
68
  )
69
69
  end
70
70
  end
@@ -96,9 +96,9 @@ module ERBLint
96
96
 
97
97
  add_offense(
98
98
  erb_node.loc,
99
- "Input field helper is missing an autocomplete attribute. If no "\
99
+ "Input field helper is missing an autocomplete attribute. If no " \
100
100
  "autocomplete behaviour is desired, use the value `off` or `nope`.",
101
- [erb_node, send_node]
101
+ [erb_node, send_node],
102
102
  )
103
103
  end
104
104
  end
@@ -29,7 +29,7 @@ module ERBLint
29
29
  add_offense(
30
30
  tag_node.to_a[1].loc,
31
31
  "Missing a nonce attribute. Use request.content_security_policy_nonce",
32
- [nonce_attribute]
32
+ [nonce_attribute],
33
33
  )
34
34
  end
35
35
  end
@@ -67,7 +67,7 @@ module ERBLint
67
67
  add_offense(
68
68
  erb_node.loc,
69
69
  "Missing a nonce attribute. Use nonce: true",
70
- [erb_node, send_node]
70
+ [erb_node, send_node],
71
71
  )
72
72
  end
73
73
  end
@@ -19,7 +19,7 @@ module ERBLint
19
19
 
20
20
  add_offense(
21
21
  trim_node.loc,
22
- "Prefer #{@config.enforced_style}%> instead of #{trim_node.loc.source}%> for trimming on the right."
22
+ "Prefer #{@config.enforced_style}%> instead of #{trim_node.loc.source}%> for trimming on the right.",
23
23
  )
24
24
  end
25
25
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "better_html"
4
4
  require "tempfile"
5
- require "erb_lint/utils/offset_corrector"
6
5
 
7
6
  module ERBLint
8
7
  module Linters
@@ -13,6 +12,7 @@ module ERBLint
13
12
  class ConfigSchema < LinterConfig
14
13
  property :only, accepts: array_of?(String)
15
14
  property :rubocop_config, accepts: Hash, default: -> { {} }
15
+ property :config_file_path, accepts: String
16
16
  end
17
17
 
18
18
  self.config_schema = ConfigSchema
@@ -24,7 +24,8 @@ module ERBLint
24
24
  def initialize(file_loader, config)
25
25
  super
26
26
  @only_cops = @config.only
27
- custom_config = config_from_hash(@config.rubocop_config)
27
+ custom_config = config_from_path(@config.config_file_path) if @config.config_file_path
28
+ custom_config ||= config_from_hash(@config.rubocop_config)
28
29
  @rubocop_config = ::RuboCop::ConfigLoader.merge_with_default(custom_config, "")
29
30
  end
30
31
 
@@ -34,30 +35,14 @@ module ERBLint
34
35
  end
35
36
  end
36
37
 
37
- if ::RuboCop::Version::STRING.to_f >= 0.87
38
- def autocorrect(_processed_source, offense)
39
- return unless offense.context
38
+ def autocorrect(_processed_source, offense)
39
+ return unless offense.context
40
40
 
41
- rubocop_correction = offense.context[:rubocop_correction]
42
- return unless rubocop_correction
41
+ rubocop_correction = offense.context[:rubocop_correction]
42
+ return unless rubocop_correction
43
43
 
44
- lambda do |corrector|
45
- corrector.import!(rubocop_correction, offset: offense.context[:offset])
46
- end
47
- end
48
- else
49
- def autocorrect(processed_source, offense)
50
- return unless offense.context
51
-
52
- lambda do |corrector|
53
- passthrough = Utils::OffsetCorrector.new(
54
- processed_source,
55
- corrector,
56
- offense.context[:offset],
57
- offense.context[:bound_range],
58
- )
59
- offense.context[:rubocop_correction].call(passthrough)
60
- end
44
+ lambda do |corrector|
45
+ corrector.import!(rubocop_correction, offset: offense.context[:offset])
61
46
  end
62
47
  end
63
48
 
@@ -83,39 +68,18 @@ module ERBLint
83
68
  activate_team(processed_source, source, offset, code_node, build_team)
84
69
  end
85
70
 
86
- if ::RuboCop::Version::STRING.to_f >= 0.87
87
- def activate_team(processed_source, source, offset, code_node, team)
88
- report = team.investigate(source)
89
- report.offenses.each do |rubocop_offense|
90
- next if rubocop_offense.disabled?
71
+ def activate_team(processed_source, source, offset, code_node, team)
72
+ report = team.investigate(source)
73
+ report.offenses.each do |rubocop_offense|
74
+ next if rubocop_offense.disabled?
91
75
 
92
- correction = rubocop_offense.corrector if rubocop_offense.corrected?
76
+ correction = rubocop_offense.corrector if rubocop_offense.corrected?
93
77
 
94
- offense_range = processed_source
95
- .to_source_range(rubocop_offense.location)
96
- .offset(offset)
78
+ offense_range = processed_source
79
+ .to_source_range(rubocop_offense.location)
80
+ .offset(offset)
97
81
 
98
- add_offense(rubocop_offense, offense_range, correction, offset, code_node.loc.range)
99
- end
100
- end
101
- else
102
- def activate_team(processed_source, source, offset, code_node, team)
103
- team.inspect_file(source)
104
- team.cops.each do |cop|
105
- correction_offset = 0
106
- cop.offenses.reject(&:disabled?).each do |rubocop_offense|
107
- if rubocop_offense.corrected?
108
- correction = cop.corrections[correction_offset]
109
- correction_offset += 1
110
- end
111
-
112
- offense_range = processed_source
113
- .to_source_range(rubocop_offense.location)
114
- .offset(offset)
115
-
116
- add_offense(rubocop_offense, offense_range, correction, offset, code_node.loc.range)
117
- end
118
- end
82
+ add_offense(rubocop_offense, offense_range, correction, offset, code_node.loc.range)
119
83
  end
120
84
  end
121
85
 
@@ -129,24 +93,30 @@ module ERBLint
129
93
  end
130
94
 
131
95
  def rubocop_processed_source(content, filename)
132
- ::RuboCop::ProcessedSource.new(
96
+ source = ::RuboCop::ProcessedSource.new(
133
97
  content,
134
98
  @rubocop_config.target_ruby_version,
135
- filename
99
+ filename,
136
100
  )
101
+ if ::RuboCop::Version::STRING.to_f >= 1.38
102
+ registry = RuboCop::Cop::Registry.global
103
+ source.registry = registry
104
+ source.config = @rubocop_config
105
+ end
106
+ source
137
107
  end
138
108
 
139
109
  def cop_classes
140
110
  if @only_cops.present?
141
- selected_cops = ::RuboCop::Cop::Cop.all.select { |cop| cop.match?(@only_cops) }
111
+ selected_cops = ::RuboCop::Cop::Registry.all.select { |cop| cop.match?(@only_cops) }
142
112
  ::RuboCop::Cop::Registry.new(selected_cops)
143
113
  else
144
- ::RuboCop::Cop::Registry.new(::RuboCop::Cop::Cop.all)
114
+ ::RuboCop::Cop::Registry.new(::RuboCop::Cop::Registry.all)
145
115
  end
146
116
  end
147
117
 
148
118
  def build_team
149
- ::RuboCop::Cop::Team.new(
119
+ ::RuboCop::Cop::Team.mobilize(
150
120
  cop_classes,
151
121
  @rubocop_config,
152
122
  extra_details: true,
@@ -158,34 +128,13 @@ module ERBLint
158
128
  end
159
129
 
160
130
  def config_from_hash(hash)
161
- inherit_from = hash&.delete("inherit_from")
162
- resolve_inheritance(hash, inherit_from)
163
-
164
131
  tempfile_from(".erblint-rubocop", hash.to_yaml) do |tempfile|
165
- ::RuboCop::ConfigLoader.load_file(tempfile.path)
132
+ config_from_path(tempfile.path)
166
133
  end
167
134
  end
168
135
 
169
- def resolve_inheritance(hash, inherit_from)
170
- base_configs(inherit_from)
171
- .reverse_each do |base_config|
172
- base_config.each do |k, v|
173
- hash[k] = hash.key?(k) ? ::RuboCop::ConfigLoader.merge(v, hash[k]) : v if v.is_a?(Hash)
174
- end
175
- end
176
- end
177
-
178
- def base_configs(inherit_from)
179
- regex = URI::DEFAULT_PARSER.make_regexp(["http", "https"])
180
- configs = Array(inherit_from).compact.map do |base_name|
181
- if base_name =~ /\A#{regex}\z/
182
- ::RuboCop::ConfigLoader.load_file(::RuboCop::RemoteConfig.new(base_name, Dir.pwd))
183
- else
184
- config_from_hash(@file_loader.yaml(base_name))
185
- end
186
- end
187
-
188
- configs.compact
136
+ def config_from_path(path)
137
+ ::RuboCop::ConfigLoader.load_file(path)
189
138
  end
190
139
 
191
140
  def add_offense(rubocop_offense, offense_range, correction, offset, bound_range)
@@ -10,6 +10,7 @@ module ERBLint
10
10
  class ConfigSchema < LinterConfig
11
11
  property :only, accepts: array_of?(String)
12
12
  property :rubocop_config, accepts: Hash
13
+ property :config_file_path, accepts: String
13
14
  end
14
15
 
15
16
  self.config_schema = ConfigSchema
@@ -28,7 +29,7 @@ module ERBLint
28
29
  end
29
30
 
30
31
  def cop_classes
31
- selected_cops = ::RuboCop::Cop::Cop.all.select { |cop| cop.match?(@only_cops) }
32
+ selected_cops = ::RuboCop::Cop::Registry.all.select { |cop| cop.match?(@only_cops) }
32
33
 
33
34
  ::RuboCop::Cop::Registry.new(selected_cops)
34
35
  end
@@ -11,8 +11,25 @@ module ERBLint
11
11
  end
12
12
  self.config_schema = ConfigSchema
13
13
 
14
- SELF_CLOSING_TAGS = ["area", "base", "br", "col", "command", "embed", "hr", "input", "keygen", "link",
15
- "menuitem", "meta", "param", "source", "track", "wbr", "img",]
14
+ SELF_CLOSING_TAGS = [
15
+ "area",
16
+ "base",
17
+ "br",
18
+ "col",
19
+ "command",
20
+ "embed",
21
+ "hr",
22
+ "input",
23
+ "keygen",
24
+ "link",
25
+ "menuitem",
26
+ "meta",
27
+ "param",
28
+ "source",
29
+ "track",
30
+ "wbr",
31
+ "img",
32
+ ]
16
33
 
17
34
  def run(processed_source)
18
35
  processed_source.ast.descendants(:tag).each do |tag_node|
@@ -24,7 +41,7 @@ module ERBLint
24
41
  add_offense(
25
42
  start_solidus.loc,
26
43
  "Tag `#{tag.name}` is a void element, it must not start with `</`.",
27
- ""
44
+ "",
28
45
  )
29
46
  end
30
47
 
@@ -32,7 +49,7 @@ module ERBLint
32
49
  add_offense(
33
50
  tag_node.loc.end.offset(-1),
34
51
  "Tag `#{tag.name}` is self-closing, it must end with `/>`.",
35
- "/"
52
+ "/",
36
53
  )
37
54
  end
38
55
 
@@ -42,7 +59,7 @@ module ERBLint
42
59
  add_offense(
43
60
  end_solidus.loc,
44
61
  "Tag `#{tag.name}` is a void element, it must end with `>` and not `/>`.",
45
- ""
62
+ "",
46
63
  )
47
64
  end
48
65
  end
@@ -23,17 +23,17 @@ module ERBLint
23
23
  if start_spaces.size != 1 && !start_spaces.include?("\n")
24
24
  add_offense(
25
25
  code_node.loc.resize(start_spaces.size),
26
- "Use 1 space after `<%#{indicator}#{ltrim&.loc&.source}` "\
26
+ "Use 1 space after `<%#{indicator}#{ltrim&.loc&.source}` " \
27
27
  "instead of #{start_spaces.size} space#{"s" if start_spaces.size > 1}.",
28
- " "
28
+ " ",
29
29
  )
30
30
  elsif start_spaces.count("\n") > 1
31
31
  lines = start_spaces.split("\n", -1)
32
32
  add_offense(
33
33
  code_node.loc.resize(start_spaces.size),
34
- "Use 1 newline after `<%#{indicator&.loc&.source}#{ltrim&.loc&.source}` "\
34
+ "Use 1 newline after `<%#{indicator&.loc&.source}#{ltrim&.loc&.source}` " \
35
35
  "instead of #{start_spaces.count("\n")}.",
36
- "#{lines.first}\n#{lines.last}"
36
+ "#{lines.first}\n#{lines.last}",
37
37
  )
38
38
  end
39
39
 
@@ -41,17 +41,17 @@ module ERBLint
41
41
  if end_spaces.size != 1 && !end_spaces.include?("\n")
42
42
  add_offense(
43
43
  code_node.loc.end.adjust(begin_pos: -end_spaces.size),
44
- "Use 1 space before `#{rtrim&.loc&.source}%>` "\
44
+ "Use 1 space before `#{rtrim&.loc&.source}%>` " \
45
45
  "instead of #{end_spaces.size} space#{"s" if start_spaces.size > 1}.",
46
- " "
46
+ " ",
47
47
  )
48
48
  elsif end_spaces.count("\n") > 1
49
49
  lines = end_spaces.split("\n", -1)
50
50
  add_offense(
51
51
  code_node.loc.end.adjust(begin_pos: -end_spaces.size),
52
- "Use 1 newline before `#{rtrim&.loc&.source}%>` "\
52
+ "Use 1 newline before `#{rtrim&.loc&.source}%>` " \
53
53
  "instead of #{end_spaces.count("\n")}.",
54
- "#{lines.first}\n#{lines.last}"
54
+ "#{lines.first}\n#{lines.last}",
55
55
  )
56
56
  end
57
57
  end
@@ -50,7 +50,7 @@ module ERBLint
50
50
  add_offense(
51
51
  processed_source.to_source_range(range),
52
52
  "Extra space detected where there should be no space.",
53
- ""
53
+ "",
54
54
  )
55
55
  end
56
56
 
@@ -69,24 +69,24 @@ module ERBLint
69
69
  if non_space && !non_space.captures.empty?
70
70
  add_offense(
71
71
  processed_source.to_source_range(range),
72
- "Non-whitespace character(s) detected: "\
72
+ "Non-whitespace character(s) detected: " \
73
73
  "#{non_space.captures.map(&:inspect).join(", ")}.",
74
- expected
74
+ expected,
75
75
  )
76
76
  elsif newlines && accept_newline
77
77
  if expected != chars
78
78
  add_offense(
79
79
  processed_source.to_source_range(range),
80
- "#{chars.empty? ? "No" : "Extra"} space detected where there should be "\
80
+ "#{chars.empty? ? "No" : "Extra"} space detected where there should be " \
81
81
  "a single space or a single line break.",
82
- expected
82
+ expected,
83
83
  )
84
84
  end
85
85
  else
86
86
  add_offense(
87
87
  processed_source.to_source_range(range),
88
88
  "#{chars.empty? ? "No" : "Extra"} space detected where there should be a single space.",
89
- expected
89
+ expected,
90
90
  )
91
91
  end
92
92
  end
@@ -103,7 +103,7 @@ module ERBLint
103
103
 
104
104
  single_space_or_newline(
105
105
  processed_source,
106
- attribute.loc.end_pos...next_attribute.loc.begin_pos
106
+ attribute.loc.end_pos...next_attribute.loc.begin_pos,
107
107
  )
108
108
  end
109
109
  end
@@ -23,7 +23,7 @@ module ERBLint
23
23
  add_offense(
24
24
  processed_source.to_source_range(document_pos...(document_pos + spaces.length)),
25
25
  "Indent with spaces instead of tabs.",
26
- spaces.gsub("\t", " " * @config.tab_width)
26
+ spaces.gsub("\t", " " * @config.tab_width),
27
27
  )
28
28
  end
29
29