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.
- checksums.yaml +4 -4
- data/lib/erb_lint/cache.rb +2 -2
- data/lib/erb_lint/cached_offense.rb +1 -1
- data/lib/erb_lint/cli.rb +15 -7
- data/lib/erb_lint/linter.rb +1 -1
- data/lib/erb_lint/linters/allowed_script_type.rb +8 -7
- data/lib/erb_lint/linters/closing_erb_tag_indent.rb +3 -3
- data/lib/erb_lint/linters/comment_syntax.rb +1 -1
- data/lib/erb_lint/linters/deprecated_classes.rb +2 -2
- data/lib/erb_lint/linters/erb_safety.rb +1 -1
- data/lib/erb_lint/linters/extra_newline.rb +1 -1
- data/lib/erb_lint/linters/final_newline.rb +4 -4
- data/lib/erb_lint/linters/hard_coded_string.rb +5 -4
- data/lib/erb_lint/linters/no_javascript_tag_helper.rb +6 -4
- data/lib/erb_lint/linters/no_unused_disable.rb +4 -2
- data/lib/erb_lint/linters/parser_errors.rb +1 -1
- data/lib/erb_lint/linters/partial_instance_variable.rb +2 -2
- data/lib/erb_lint/linters/require_input_autocomplete.rb +4 -4
- data/lib/erb_lint/linters/require_script_nonce.rb +2 -2
- data/lib/erb_lint/linters/right_trim.rb +1 -1
- data/lib/erb_lint/linters/rubocop.rb +3 -3
- data/lib/erb_lint/linters/rubocop_text.rb +1 -1
- data/lib/erb_lint/linters/self_closing_tag.rb +22 -5
- data/lib/erb_lint/linters/space_around_erb_tag.rb +8 -8
- data/lib/erb_lint/linters/space_in_html_tag.rb +7 -7
- data/lib/erb_lint/linters/space_indentation.rb +1 -1
- data/lib/erb_lint/linters/trailing_whitespace.rb +1 -1
- data/lib/erb_lint/offense.rb +3 -3
- data/lib/erb_lint/processed_source.rb +1 -1
- data/lib/erb_lint/reporter.rb +3 -2
- data/lib/erb_lint/reporters/compact_reporter.rb +3 -2
- data/lib/erb_lint/reporters/gitlab_reporter.rb +55 -0
- data/lib/erb_lint/reporters/junit_reporter.rb +112 -0
- data/lib/erb_lint/reporters/multiline_reporter.rb +6 -1
- data/lib/erb_lint/runner.rb +1 -1
- data/lib/erb_lint/runner_config.rb +1 -1
- data/lib/erb_lint/utils/block_map.rb +4 -4
- data/lib/erb_lint/utils/offset_corrector.rb +2 -5
- data/lib/erb_lint/utils/severity_levels.rb +8 -2
- data/lib/erb_lint/version.rb +1 -1
- metadata +10 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba9ef5f8b8a251d649dd1cffba1094d770471a630d0fa66b402621883ea3b050
|
4
|
+
data.tar.gz: db969c9e8bacc58b20fa9ad568c98263225c8bbf41f2d32f1b5d9f44a4c58aab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1d9e86c1862a41bb8cc2d1ae520af38ced2390e3d06c3d9bc9550a434993de502167c87adf93a780fec7f87d4921e77367e8bf8c546bf59c6f88908d0208039
|
7
|
+
data.tar.gz: 468ef87d28e39aa2fb0166cdfc98bee1f1f7349d21a9a5e2c08a81f5aab47c067d1d440d6466cf28077f5d72984b9d0018bdc23af2e3b91a6127bfc46f850f5a
|
data/lib/erb_lint/cache.rb
CHANGED
@@ -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
|
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(
|
352
|
-
"
|
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
|
|
data/lib/erb_lint/linter.rb
CHANGED
@@ -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,
|
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
|
@@ -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
|
-
|
20
|
+
NO_TRANSLATION_NEEDED = Set.new([
|
21
21
|
" ",
|
22
22
|
"&",
|
23
23
|
"<",
|
@@ -40,6 +40,7 @@ module ERBLint
|
|
40
40
|
" ",
|
41
41
|
" ",
|
42
42
|
" ",
|
43
|
+
"×",
|
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
|
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 && !
|
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(
|
86
|
-
|
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(
|
39
|
-
|
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
|
@@ -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::
|
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::
|
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::
|
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 = [
|
15
|
-
|
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
|
|
data/lib/erb_lint/offense.rb
CHANGED
@@ -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
|
|
data/lib/erb_lint/reporter.rb
CHANGED
@@ -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
|
-
#{
|
18
|
+
#{details}
|
14
19
|
In file: #{filename}:#{offense.line_number}
|
15
20
|
EOF
|
16
21
|
end
|
data/lib/erb_lint/runner.rb
CHANGED
@@ -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
|
-
"
|
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 = {
|
9
|
-
|
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
|
data/lib/erb_lint/version.rb
CHANGED
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
|
+
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:
|
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: '
|
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: '
|
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.
|
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: []
|