erb_lint 0.4.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/erb_lint/cache.rb +2 -2
  3. data/lib/erb_lint/cached_offense.rb +1 -1
  4. data/lib/erb_lint/cli.rb +15 -7
  5. data/lib/erb_lint/linter.rb +1 -1
  6. data/lib/erb_lint/linters/allowed_script_type.rb +8 -7
  7. data/lib/erb_lint/linters/closing_erb_tag_indent.rb +3 -3
  8. data/lib/erb_lint/linters/comment_syntax.rb +1 -1
  9. data/lib/erb_lint/linters/deprecated_classes.rb +2 -2
  10. data/lib/erb_lint/linters/erb_safety.rb +1 -1
  11. data/lib/erb_lint/linters/extra_newline.rb +1 -1
  12. data/lib/erb_lint/linters/final_newline.rb +4 -4
  13. data/lib/erb_lint/linters/hard_coded_string.rb +5 -4
  14. data/lib/erb_lint/linters/no_javascript_tag_helper.rb +6 -4
  15. data/lib/erb_lint/linters/no_unused_disable.rb +4 -2
  16. data/lib/erb_lint/linters/parser_errors.rb +1 -1
  17. data/lib/erb_lint/linters/partial_instance_variable.rb +2 -2
  18. data/lib/erb_lint/linters/require_input_autocomplete.rb +4 -4
  19. data/lib/erb_lint/linters/require_script_nonce.rb +2 -2
  20. data/lib/erb_lint/linters/right_trim.rb +1 -1
  21. data/lib/erb_lint/linters/rubocop.rb +3 -3
  22. data/lib/erb_lint/linters/rubocop_text.rb +1 -1
  23. data/lib/erb_lint/linters/self_closing_tag.rb +22 -5
  24. data/lib/erb_lint/linters/space_around_erb_tag.rb +8 -8
  25. data/lib/erb_lint/linters/space_in_html_tag.rb +7 -7
  26. data/lib/erb_lint/linters/space_indentation.rb +1 -1
  27. data/lib/erb_lint/linters/trailing_whitespace.rb +1 -1
  28. data/lib/erb_lint/offense.rb +3 -3
  29. data/lib/erb_lint/processed_source.rb +1 -1
  30. data/lib/erb_lint/reporter.rb +3 -2
  31. data/lib/erb_lint/reporters/compact_reporter.rb +3 -2
  32. data/lib/erb_lint/reporters/gitlab_reporter.rb +55 -0
  33. data/lib/erb_lint/reporters/junit_reporter.rb +112 -0
  34. data/lib/erb_lint/reporters/multiline_reporter.rb +6 -1
  35. data/lib/erb_lint/runner.rb +1 -1
  36. data/lib/erb_lint/runner_config.rb +1 -1
  37. data/lib/erb_lint/utils/block_map.rb +4 -4
  38. data/lib/erb_lint/utils/offset_corrector.rb +2 -5
  39. data/lib/erb_lint/utils/severity_levels.rb +8 -2
  40. data/lib/erb_lint/version.rb +1 -1
  41. metadata +10 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b3cff2cda3a196df2b19ff70f2999cea11a467b57bfa9a95fc031354752c6f1
4
- data.tar.gz: 7e85499590c4d58c8f2cd4af0d12d49ffe7fb27f219fdb610c777c2a5b3e2100
3
+ metadata.gz: ba9ef5f8b8a251d649dd1cffba1094d770471a630d0fa66b402621883ea3b050
4
+ data.tar.gz: db969c9e8bacc58b20fa9ad568c98263225c8bbf41f2d32f1b5d9f44a4c58aab
5
5
  SHA512:
6
- metadata.gz: 23c04a0063e05a08c9d3b376542c6cc1f97659d700a4ba7fa5a50997231a485bb8971ba240b25cc998235c1ff5b138e3e4a5fa648351603f06061339c71ec75a
7
- data.tar.gz: 538c54359e677e2a56ae558b3d2f5527138c9f82485a943c9f4c5e06d6a3ebd6d6107f2285913920c7d3d1213e1353162f55b257bf1b7eb6da238af8487d142d
6
+ metadata.gz: a1d9e86c1862a41bb8cc2d1ae520af38ced2390e3d06c3d9bc9550a434993de502167c87adf93a780fec7f87d4921e77367e8bf8c546bf59c6f88908d0208039
7
+ data.tar.gz: 468ef87d28e39aa2fb0166cdfc98bee1f1f7349d21a9a5e2c08a81f5aab47c067d1d440d6466cf28077f5d72984b9d0018bdc23af2e3b91a6127bfc46f850f5a
@@ -16,7 +16,7 @@ module ERBLint
16
16
  file_checksum = checksum(filename, file_content)
17
17
  begin
18
18
  cache_file_contents_as_offenses = JSON.parse(
19
- File.read(File.join(@cache_dir, file_checksum))
19
+ File.read(File.join(@cache_dir, file_checksum)),
20
20
  ).map do |offense_hash|
21
21
  ERBLint::CachedOffense.new(offense_hash)
22
22
  end
@@ -76,7 +76,7 @@ module ERBLint
76
76
  mode = File.stat(filename).mode
77
77
 
78
78
  digester.update(
79
- "#{mode}#{config.to_hash}#{ERBLint::VERSION}#{file_content}"
79
+ "#{mode}#{config.to_hash}#{ERBLint::VERSION}#{file_content}",
80
80
  )
81
81
  digester.hexdigest
82
82
  rescue Errno::ENOENT
@@ -38,7 +38,7 @@ module ERBLint
38
38
  last_line: offense.last_line,
39
39
  last_column: offense.last_column,
40
40
  length: offense.length,
41
- }
41
+ },
42
42
  )
43
43
  end
44
44
 
data/lib/erb_lint/cli.rb CHANGED
@@ -74,7 +74,7 @@ module ERBLint
74
74
  @stats.linters = enabled_linter_classes.size
75
75
  @stats.autocorrectable_linters = enabled_linter_classes.count(&:support_autocorrect?)
76
76
 
77
- reporter = Reporter.create_reporter(@options[:format], @stats, autocorrect?)
77
+ reporter = Reporter.create_reporter(@options[:format], @stats, autocorrect?, @options[:show_linter_names])
78
78
  reporter.preview
79
79
 
80
80
  runner = ERBLint::Runner.new(file_loader, @config, @options[:disable_inline_configs])
@@ -87,7 +87,7 @@ module ERBLint
87
87
  rescue => e
88
88
  @stats.exceptions += 1
89
89
  puts "Exception occurred when processing: #{relative_filename(filename)}"
90
- puts "If this file cannot be processed by erb-lint, "\
90
+ puts "If this file cannot be processed by erb-lint, " \
91
91
  "you can exclude it in your configuration file."
92
92
  puts e.message
93
93
  puts Rainbow(e.backtrace.join("\n")).red
@@ -303,7 +303,7 @@ module ERBLint
303
303
  ERBLint::LinterRegistry.linters.map do |klass|
304
304
  linters[klass.simple_name] = { "enabled" => enabled_linter_classes.include?(klass) }
305
305
  end
306
- end
306
+ end,
307
307
  )
308
308
  end
309
309
 
@@ -348,8 +348,12 @@ module ERBLint
348
348
  @options[:clear_cache] = config
349
349
  end
350
350
 
351
- opts.on("--enable-linters LINTER[,LINTER,...]", Array,
352
- "Only use specified linter", "Known linters are: #{known_linter_names.join(", ")}") do |linters|
351
+ opts.on(
352
+ "--enable-linters LINTER[,LINTER,...]",
353
+ Array,
354
+ "Only use specified linter",
355
+ "Known linters are: #{known_linter_names.join(", ")}",
356
+ ) do |linters|
353
357
  linters.each do |linter|
354
358
  unless known_linter_names.include?(linter)
355
359
  failure!("#{linter}: not a valid linter name (#{known_linter_names.join(", ")})")
@@ -371,6 +375,10 @@ module ERBLint
371
375
  @options[:autocorrect] = config
372
376
  end
373
377
 
378
+ opts.on("--show-linter-names", "Show linter names") do
379
+ @options[:show_linter_names] = true
380
+ end
381
+
374
382
  opts.on("--allow-no-files", "When no matching files found, exit successfully (default: false)") do |config|
375
383
  @options[:allow_no_files] = config
376
384
  end
@@ -382,7 +390,7 @@ module ERBLint
382
390
  opts.on(
383
391
  "-sFILE",
384
392
  "--stdin FILE",
385
- "Pipe source from STDIN. Takes the path to be used to check which rules to apply."
393
+ "Pipe source from STDIN. Takes the path to be used to check which rules to apply.",
386
394
  ) do |file|
387
395
  @options[:stdin] = [file]
388
396
  end
@@ -398,7 +406,7 @@ module ERBLint
398
406
  end
399
407
 
400
408
  def format_options_help
401
- "Report offenses in the given format: "\
409
+ "Report offenses in the given format: " \
402
410
  "(#{Reporter.available_formats.join(", ")}) (default: multiline)"
403
411
  end
404
412
 
@@ -38,7 +38,7 @@ module ERBLint
38
38
  def initialize(file_loader, config)
39
39
  @file_loader = file_loader
40
40
  @config = config
41
- raise ArgumentError, "expect `config` to be #{self.class.config_schema} instance, "\
41
+ raise ArgumentError, "expect `config` to be #{self.class.config_schema} instance, " \
42
42
  "not #{config.class}" unless config.is_a?(self.class.config_schema)
43
43
  @offenses = []
44
44
  end
@@ -12,7 +12,8 @@ module ERBLint
12
12
  include LinterRegistry
13
13
 
14
14
  class ConfigSchema < LinterConfig
15
- property :allowed_types, accepts: array_of?(String),
15
+ property :allowed_types,
16
+ accepts: array_of?(String),
16
17
  default: -> { ["text/javascript"] }
17
18
  property :allow_blank, accepts: [true, false], default: true, reader: :allow_blank?
18
19
  property :disallow_inline_scripts, accepts: [true, false], default: false, reader: :disallow_inline_scripts?
@@ -30,8 +31,8 @@ module ERBLint
30
31
  name_node = tag_node.to_a[1]
31
32
  add_offense(
32
33
  name_node.loc,
33
- "Avoid using inline `<script>` tags altogether. "\
34
- "Instead, move javascript code into a static file."
34
+ "Avoid using inline `<script>` tags altogether. " \
35
+ "Instead, move javascript code into a static file.",
35
36
  )
36
37
  next
37
38
  end
@@ -44,14 +45,14 @@ module ERBLint
44
45
  add_offense(
45
46
  name_node.loc,
46
47
  "Missing a `type=\"text/javascript\"` attribute to `<script>` tag.",
47
- [type_attribute]
48
+ [type_attribute],
48
49
  )
49
50
  elsif type_present && !@config.allowed_types.include?(type_attribute.value)
50
51
  add_offense(
51
52
  type_attribute.loc,
52
- "Avoid using #{type_attribute.value.inspect} as type for `<script>` tag. "\
53
- "Must be one of: #{@config.allowed_types.join(", ")}"\
54
- "#{" (or no type attribute)" if @config.allow_blank?}."
53
+ "Avoid using #{type_attribute.value.inspect} as type for `<script>` tag. " \
54
+ "Must be one of: #{@config.allowed_types.join(", ")}" \
55
+ "#{" (or no type attribute)" if @config.allow_blank?}.",
55
56
  )
56
57
  end
57
58
  end
@@ -25,13 +25,13 @@ module ERBLint
25
25
  add_offense(
26
26
  code_node.loc.end.adjust(begin_pos: -end_spaces.size),
27
27
  "Remove newline before `%>` to match start of tag.",
28
- " "
28
+ " ",
29
29
  )
30
30
  elsif start_with_newline && !end_with_newline
31
31
  add_offense(
32
32
  code_node.loc.end.adjust(begin_pos: -end_spaces.size),
33
33
  "Insert newline before `%>` to match start of tag.",
34
- "\n"
34
+ "\n",
35
35
  )
36
36
  elsif start_with_newline && end_with_newline
37
37
  current_indent = end_spaces.split("\n", -1).last
@@ -39,7 +39,7 @@ module ERBLint
39
39
  add_offense(
40
40
  code_node.loc.end.adjust(begin_pos: -current_indent.size),
41
41
  "Indent `%>` on column #{erb_node.loc.column} to match start of tag.",
42
- " " * erb_node.loc.column
42
+ " " * erb_node.loc.column,
43
43
  )
44
44
  end
45
45
  end
@@ -31,7 +31,7 @@ module ERBLint
31
31
 
32
32
  add_offense(
33
33
  source_range,
34
- <<~EOF.chomp
34
+ <<~EOF.chomp,
35
35
  Bad ERB comment syntax. Should be #{correct_erb_tag} without a space between.
36
36
  Leaving a space between ERB tags and the Ruby comment character can cause parser errors.
37
37
  EOF
@@ -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,7 @@ module ERBLint
40
40
  "&ensp;",
41
41
  "&emsp;",
42
42
  "&thinsp;",
43
+ "&times;",
43
44
  ])
44
45
 
45
46
  class ConfigSchema < LinterConfig
@@ -66,7 +67,7 @@ module ERBLint
66
67
 
67
68
  add_offense(
68
69
  source_range,
69
- message(source_range.source)
70
+ message(source_range.source),
70
71
  )
71
72
  end
72
73
  end
@@ -83,7 +84,7 @@ module ERBLint
83
84
  def autocorrect(processed_source, offense)
84
85
  string = offense.source_range.source
85
86
  return unless (klass = load_corrector)
86
- return unless string.strip.length > 1
87
+ return if string.strip.length <= 1
87
88
 
88
89
  node = ::RuboCop::AST::StrNode.new(:str, [string])
89
90
  corrector = klass.new(node, processed_source.filename, corrector_i18n_load_path, offense.source_range)
@@ -96,7 +97,7 @@ module ERBLint
96
97
 
97
98
  def check_string?(str)
98
99
  string = str.gsub(/\s*/, "")
99
- string.length > 1 && !TEXT_NOT_ALLOWED.include?(string)
100
+ string.length > 1 && !NO_TRANSLATION_NEEDED.include?(string)
100
101
  end
101
102
 
102
103
  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
@@ -35,8 +35,10 @@ module ERBLint
35
35
 
36
36
  disabled_rules_and_line_number.each do |rule, line_numbers|
37
37
  line_numbers.each do |line_number|
38
- add_offense(processed_source.source_buffer.line_range(line_number),
39
- "Unused erblint:disable comment for #{rule}")
38
+ add_offense(
39
+ processed_source.source_buffer.line_range(line_number),
40
+ "Unused erblint:disable comment for #{rule}",
41
+ )
40
42
  end
41
43
  end
42
44
  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
@@ -134,7 +134,7 @@ module ERBLint
134
134
  source = ::RuboCop::ProcessedSource.new(
135
135
  content,
136
136
  @rubocop_config.target_ruby_version,
137
- filename
137
+ filename,
138
138
  )
139
139
  if ::RuboCop::Version::STRING.to_f >= 1.38
140
140
  registry = RuboCop::Cop::Registry.global
@@ -146,10 +146,10 @@ module ERBLint
146
146
 
147
147
  def cop_classes
148
148
  if @only_cops.present?
149
- selected_cops = ::RuboCop::Cop::Cop.all.select { |cop| cop.match?(@only_cops) }
149
+ selected_cops = ::RuboCop::Cop::Registry.all.select { |cop| cop.match?(@only_cops) }
150
150
  ::RuboCop::Cop::Registry.new(selected_cops)
151
151
  else
152
- ::RuboCop::Cop::Registry.new(::RuboCop::Cop::Cop.all)
152
+ ::RuboCop::Cop::Registry.new(::RuboCop::Cop::Registry.all)
153
153
  end
154
154
  end
155
155
 
@@ -29,7 +29,7 @@ module ERBLint
29
29
  end
30
30
 
31
31
  def cop_classes
32
- 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) }
33
33
 
34
34
  ::RuboCop::Cop::Registry.new(selected_cops)
35
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
 
@@ -18,7 +18,7 @@ module ERBLint
18
18
 
19
19
  add_offense(
20
20
  processed_source.to_source_range((document_pos - whitespace.length - 1)...(document_pos - 1)),
21
- "Extra whitespace detected at end of line."
21
+ "Extra whitespace detected at end of line.",
22
22
  )
23
23
  end
24
24
  end
@@ -23,9 +23,9 @@ module ERBLint
23
23
  end
24
24
 
25
25
  def inspect
26
- "#<#{self.class.name} linter=#{linter.class.name} "\
27
- "source_range=#{source_range.begin_pos}...#{source_range.end_pos} "\
28
- "message=#{message}> "\
26
+ "#<#{self.class.name} linter=#{linter.class.name} " \
27
+ "source_range=#{source_range.begin_pos}...#{source_range.end_pos} " \
28
+ "message=#{message}> " \
29
29
  "severity=#{severity}"
30
30
  end
31
31
 
@@ -27,7 +27,7 @@ module ERBLint
27
27
  BetterHtml::Tokenizer::Location.new(
28
28
  source_buffer,
29
29
  range.begin,
30
- range.exclude_end? ? range.end : range.end + 1
30
+ range.exclude_end? ? range.end : range.end + 1,
31
31
  )
32
32
  end
33
33
  end
@@ -23,9 +23,10 @@ module ERBLint
23
23
  .sort
24
24
  end
25
25
 
26
- def initialize(stats, autocorrect)
26
+ def initialize(stats, autocorrect, show_linter_names = false)
27
27
  @stats = stats
28
28
  @autocorrect = autocorrect
29
+ @show_linter_names = show_linter_names
29
30
  end
30
31
 
31
32
  def preview; end
@@ -34,7 +35,7 @@ module ERBLint
34
35
 
35
36
  private
36
37
 
37
- attr_reader :stats, :autocorrect
38
+ attr_reader :stats, :autocorrect, :show_linter_names
38
39
 
39
40
  delegate :processed_files, to: :stats
40
41
  end
@@ -33,8 +33,9 @@ module ERBLint
33
33
  "#{filename}:",
34
34
  "#{offense.line_number}:",
35
35
  "#{offense.column}: ",
36
+ ("[#{offense.simple_name}] " if show_linter_names),
36
37
  offense.message.to_s,
37
- ].join
38
+ ].compact.join
38
39
  end
39
40
 
40
41
  def footer; end
@@ -60,7 +61,7 @@ module ERBLint
60
61
 
61
62
  if corrected_found_diff > 0
62
63
  message = Rainbow(
63
- "#{stats.corrected} error(s) corrected and #{corrected_found_diff} error(s) remaining in ERB files"
64
+ "#{stats.corrected} error(s) corrected and #{corrected_found_diff} error(s) remaining in ERB files",
64
65
  ).red
65
66
 
66
67
  warn(message)
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module ERBLint
6
+ module Reporters
7
+ class GitlabReporter < Reporter
8
+ def preview; end
9
+
10
+ def show
11
+ puts formatted_data
12
+ end
13
+
14
+ private
15
+
16
+ def formatted_data
17
+ formatted_files.to_json
18
+ end
19
+
20
+ def formatted_files
21
+ processed_files.flat_map do |filename, offenses|
22
+ formatted_offenses(filename, offenses)
23
+ end
24
+ end
25
+
26
+ def formatted_offenses(filename, offenses)
27
+ offenses.map do |offense|
28
+ format_offense(filename, offense)
29
+ end
30
+ end
31
+
32
+ def format_offense(filename, offense)
33
+ {
34
+ description: offense.message,
35
+ check_name: offense.simple_name,
36
+ fingerprint: generate_fingerprint(filename, offense),
37
+ severity: offense.severity,
38
+ location: {
39
+ path: filename,
40
+ lines: {
41
+ begin: offense.line_number,
42
+ end: offense.last_line,
43
+ },
44
+ },
45
+ }
46
+ end
47
+
48
+ def generate_fingerprint(filename, offense)
49
+ Digest::MD5.hexdigest(
50
+ "#{offense.simple_name}@#{filename}:#{offense.line_number}:#{offense.last_line}",
51
+ )
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rexml/document"
4
+ require "rexml/formatters/pretty"
5
+
6
+ module ERBLint
7
+ module Reporters
8
+ class JunitReporter < Reporter
9
+ def preview; end
10
+
11
+ def show
12
+ xml = create_junit_xml
13
+ formatted_xml_string = StringIO.new
14
+ REXML::Formatters::Pretty.new.write(xml, formatted_xml_string)
15
+ puts formatted_xml_string.string
16
+ end
17
+
18
+ private
19
+
20
+ CONTEXT = {
21
+ prologue_quote: :quote,
22
+ attribute_quote: :quote,
23
+ }
24
+
25
+ def create_junit_xml
26
+ # create prologue
27
+ xml = REXML::Document.new(nil, CONTEXT)
28
+ xml << REXML::XMLDecl.new("1.0", "UTF-8")
29
+
30
+ xml.add_element(create_testsuite_element)
31
+
32
+ xml
33
+ end
34
+
35
+ def create_testsuite_element
36
+ tests = stats.processed_files.size
37
+ failures = stats.found
38
+ testsuite_element = REXML::Element.new("testsuite", nil, CONTEXT)
39
+ testsuite_element.add_attribute("name", "erblint")
40
+ testsuite_element.add_attribute("tests", tests.to_s)
41
+ testsuite_element.add_attribute("failures", failures.to_s)
42
+
43
+ testsuite_element.add_element(create_properties)
44
+
45
+ processed_files.each do |filename, offenses|
46
+ if offenses.empty?
47
+ testcase_element = REXML::Element.new("testcase", nil, CONTEXT)
48
+ testcase_element.add_attribute("name", filename.to_s)
49
+ testcase_element.add_attribute("file", filename.to_s)
50
+
51
+ testsuite_element.add_element(testcase_element)
52
+ end
53
+
54
+ offenses.each do |offense|
55
+ testsuite_element.add_element(create_testcase(filename, offense))
56
+ end
57
+ end
58
+
59
+ testsuite_element
60
+ end
61
+
62
+ def create_properties
63
+ properties_element = REXML::Element.new("properties", nil, CONTEXT)
64
+
65
+ [
66
+ ["erb_lint_version", ERBLint::VERSION],
67
+ ["ruby_engine", RUBY_ENGINE],
68
+ ["ruby_version", RUBY_VERSION],
69
+ ["ruby_patchlevel", RUBY_PATCHLEVEL.to_s],
70
+ ["ruby_platform", RUBY_PLATFORM],
71
+ ].each do |property_attribute|
72
+ properties_element.add_element(create_property(*property_attribute))
73
+ end
74
+
75
+ properties_element
76
+ end
77
+
78
+ def create_property(name, value)
79
+ property_element = REXML::Element.new("property")
80
+ property_element.add_attribute("name", name)
81
+ property_element.add_attribute("value", value)
82
+
83
+ property_element
84
+ end
85
+
86
+ def create_testcase(filename, offense)
87
+ testcase_element = REXML::Element.new("testcase", nil, CONTEXT)
88
+ testcase_element.add_attribute("name", filename.to_s)
89
+ testcase_element.add_attribute("file", filename.to_s)
90
+ testcase_element.add_attribute("lineno", offense.line_number.to_s)
91
+
92
+ testcase_element.add_element(create_failure(filename, offense))
93
+
94
+ testcase_element
95
+ end
96
+
97
+ def create_failure(filename, offense)
98
+ message = offense.message
99
+ type = offense.simple_name
100
+
101
+ failure_element = REXML::Element.new("failure", nil, CONTEXT)
102
+ failure_element.add_attribute("message", "#{type}: #{message}")
103
+ failure_element.add_attribute("type", type.to_s)
104
+
105
+ cdata_element = REXML::CData.new("#{type}: #{message} at #{filename}:#{offense.line_number}:#{offense.column}")
106
+ failure_element.add_text(cdata_element)
107
+
108
+ failure_element
109
+ end
110
+ end
111
+ end
112
+ end
@@ -8,9 +8,14 @@ module ERBLint
8
8
  private
9
9
 
10
10
  def format_offense(filename, offense)
11
+ details = "#{offense.message}#{Rainbow(" (not autocorrected)").red if autocorrect}"
12
+ if show_linter_names
13
+ details = "[#{offense.simple_name}] " + details
14
+ end
15
+
11
16
  <<~EOF
12
17
 
13
- #{offense.message}#{Rainbow(" (not autocorrected)").red if autocorrect}
18
+ #{details}
14
19
  In file: #{filename}:#{offense.line_number}
15
20
  EOF
16
21
  end
@@ -57,7 +57,7 @@ module ERBLint
57
57
  if no_unused_disable_enabled? && enable_inline_configs?
58
58
  @no_unused_disable = ERBLint::Linters::NoUnusedDisable.new(
59
59
  @file_loader,
60
- @config.for_linter(ERBLint::Linters::NoUnusedDisable)
60
+ @config.for_linter(ERBLint::Linters::NoUnusedDisable),
61
61
  )
62
62
  @no_unused_disable.run(processed_source, @offenses)
63
63
  @offenses.concat(@no_unused_disable.offenses)
@@ -83,7 +83,7 @@ module ERBLint
83
83
  def config_hash_for_linter(klass_name)
84
84
  config_hash = linters_config[klass_name] || {}
85
85
  config_hash["exclude"] ||= []
86
- config_hash["exclude"].concat(global_exclude) if config_hash["exclude"].is_a?(Array)
86
+ config_hash["exclude"].concat(global_exclude).uniq! if config_hash["exclude"].is_a?(Array)
87
87
  config_hash
88
88
  end
89
89
 
@@ -60,7 +60,7 @@ module ERBLint
60
60
  end
61
61
 
62
62
  def inspect
63
- "\#<#{self.class.name} type=#{type.inspect} nodes=#{nodes.inspect}>"
63
+ "#<#{self.class.name} type=#{type.inspect} nodes=#{nodes.inspect}>"
64
64
  end
65
65
 
66
66
  def &(other)
@@ -102,7 +102,7 @@ module ERBLint
102
102
  node.type,
103
103
  extract_map_locations(node)
104
104
  .map { |loc| find_entry(loc) }
105
- .compact.map(&:node)
105
+ .compact.map(&:node),
106
106
  )
107
107
  end
108
108
 
@@ -111,7 +111,7 @@ module ERBLint
111
111
  :begin,
112
112
  (extract_map_locations(node) + rescue_locations(node))
113
113
  .map { |loc| find_entry(loc) }
114
- .compact.map(&:node)
114
+ .compact.map(&:node),
115
115
  )
116
116
  end
117
117
 
@@ -120,7 +120,7 @@ module ERBLint
120
120
  node.type,
121
121
  (extract_map_locations(node) + when_locations(node))
122
122
  .map { |loc| find_entry(loc) }
123
- .compact.map(&:node)
123
+ .compact.map(&:node),
124
124
  )
125
125
  end
126
126
 
@@ -42,15 +42,12 @@ module ERBLint
42
42
  range = to_range(node_or_range)
43
43
 
44
44
  @processed_source.to_source_range(
45
- bound(@offset + range.begin_pos)..bound(@offset + (range.end_pos - 1))
45
+ bound(@offset + range.begin_pos)..bound(@offset + (range.end_pos - 1)),
46
46
  )
47
47
  end
48
48
 
49
49
  def bound(pos)
50
- [
51
- [pos, @bound_range.min].max,
52
- @bound_range.max,
53
- ].min
50
+ pos.clamp(@bound_range.min, @bound_range.max)
54
51
  end
55
52
 
56
53
  private
@@ -5,8 +5,14 @@ module ERBLint
5
5
  module SeverityLevels
6
6
  SEVERITY_NAMES = [:info, :refactor, :convention, :warning, :error, :fatal].freeze
7
7
 
8
- SEVERITY_CODE_TABLE = { I: :info, R: :refactor, C: :convention,
9
- W: :warning, E: :error, F: :fatal, }.freeze
8
+ SEVERITY_CODE_TABLE = {
9
+ I: :info,
10
+ R: :refactor,
11
+ C: :convention,
12
+ W: :warning,
13
+ E: :error,
14
+ F: :fatal,
15
+ }.freeze
10
16
 
11
17
  def severity_level_for_name(name)
12
18
  SEVERITY_NAMES.index(name || :error) + 1
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ERBLint
4
- VERSION = "0.4.0"
4
+ VERSION = "0.6.0"
5
5
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erb_lint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Chan
8
8
  - Shopify Developers
9
- autorequire:
9
+ autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2023-03-27 00:00:00.000000000 Z
12
+ date: 2024-08-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -73,14 +73,14 @@ dependencies:
73
73
  requirements:
74
74
  - - ">="
75
75
  - !ruby/object:Gem::Version
76
- version: '0'
76
+ version: '1'
77
77
  type: :runtime
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
81
  - - ">="
82
82
  - !ruby/object:Gem::Version
83
- version: '0'
83
+ version: '1'
84
84
  - !ruby/object:Gem::Dependency
85
85
  name: smart_properties
86
86
  requirement: !ruby/object:Gem::Requirement
@@ -182,7 +182,9 @@ files:
182
182
  - lib/erb_lint/processed_source.rb
183
183
  - lib/erb_lint/reporter.rb
184
184
  - lib/erb_lint/reporters/compact_reporter.rb
185
+ - lib/erb_lint/reporters/gitlab_reporter.rb
185
186
  - lib/erb_lint/reporters/json_reporter.rb
187
+ - lib/erb_lint/reporters/junit_reporter.rb
186
188
  - lib/erb_lint/reporters/multiline_reporter.rb
187
189
  - lib/erb_lint/runner.rb
188
190
  - lib/erb_lint/runner_config.rb
@@ -199,7 +201,7 @@ licenses:
199
201
  - MIT
200
202
  metadata:
201
203
  allowed_push_host: https://rubygems.org
202
- post_install_message:
204
+ post_install_message:
203
205
  rdoc_options: []
204
206
  require_paths:
205
207
  - lib
@@ -214,8 +216,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
214
216
  - !ruby/object:Gem::Version
215
217
  version: '0'
216
218
  requirements: []
217
- rubygems_version: 3.4.9
218
- signing_key:
219
+ rubygems_version: 3.5.16
220
+ signing_key:
219
221
  specification_version: 4
220
222
  summary: ERB lint tool
221
223
  test_files: []