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.
- checksums.yaml +4 -4
- data/exe/erb_lint +10 -0
- data/exe/erblint +5 -4
- data/lib/erb_lint/all.rb +2 -0
- data/lib/erb_lint/cache.rb +88 -0
- data/lib/erb_lint/cached_offense.rb +58 -0
- data/lib/erb_lint/cli.rb +117 -22
- data/lib/erb_lint/corrector.rb +6 -17
- data/lib/erb_lint/file_loader.rb +2 -8
- data/lib/erb_lint/linter.rb +28 -2
- data/lib/erb_lint/linter_registry.rb +11 -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 +52 -0
- 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 +7 -4
- data/lib/erb_lint/linters/no_javascript_tag_helper.rb +6 -4
- data/lib/erb_lint/linters/no_unused_disable.rb +47 -0
- 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 +32 -83
- data/lib/erb_lint/linters/rubocop_text.rb +2 -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/strict_locals.rb +50 -0
- data/lib/erb_lint/linters/trailing_whitespace.rb +1 -1
- data/lib/erb_lint/offense.rb +30 -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/json_reporter.rb +4 -4
- data/lib/erb_lint/reporters/junit_reporter.rb +63 -0
- data/lib/erb_lint/reporters/multiline_reporter.rb +6 -1
- data/lib/erb_lint/runner.rb +36 -3
- data/lib/erb_lint/runner_config.rb +2 -1
- data/lib/erb_lint/runner_config_resolver.rb +1 -1
- data/lib/erb_lint/utils/block_map.rb +4 -4
- data/lib/erb_lint/utils/inline_configs.rb +15 -0
- data/lib/erb_lint/utils/severity_levels.rb +8 -2
- data/lib/erb_lint/version.rb +1 -1
- metadata +21 -28
- 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
|
@@ -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,9 @@ module ERBLint
|
|
40
40
|
" ",
|
41
41
|
" ",
|
42
42
|
" ",
|
43
|
+
"×",
|
44
|
+
"«",
|
45
|
+
"»",
|
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
|
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 && !
|
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(
|
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
|
@@ -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
|
@@ -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 =
|
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
|
-
|
38
|
-
|
39
|
-
return unless offense.context
|
38
|
+
def autocorrect(_processed_source, offense)
|
39
|
+
return unless offense.context
|
40
40
|
|
41
|
-
|
42
|
-
|
41
|
+
rubocop_correction = offense.context[:rubocop_correction]
|
42
|
+
return unless rubocop_correction
|
43
43
|
|
44
|
-
|
45
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
76
|
+
correction = rubocop_offense.corrector if rubocop_offense.corrected?
|
93
77
|
|
94
|
-
|
95
|
-
|
96
|
-
|
78
|
+
offense_range = processed_source
|
79
|
+
.to_source_range(rubocop_offense.location)
|
80
|
+
.offset(offset)
|
97
81
|
|
98
|
-
|
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::
|
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::
|
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.
|
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
|
-
|
132
|
+
config_from_path(tempfile.path)
|
166
133
|
end
|
167
134
|
end
|
168
135
|
|
169
|
-
def
|
170
|
-
|
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::
|
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 = [
|
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
|
|