erb_lint 0.1.0 → 0.1.3
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/erblint +1 -1
- data/lib/erb_lint/all.rb +15 -15
- data/lib/erb_lint/cli.rb +20 -23
- data/lib/erb_lint/corrector.rb +1 -1
- data/lib/erb_lint/linter.rb +4 -4
- data/lib/erb_lint/linter_config.rb +10 -5
- data/lib/erb_lint/linter_registry.rb +2 -2
- data/lib/erb_lint/linters/allowed_script_type.rb +9 -8
- data/lib/erb_lint/linters/closing_erb_tag_indent.rb +2 -2
- data/lib/erb_lint/linters/deprecated_classes.rb +8 -7
- data/lib/erb_lint/linters/erb_safety.rb +2 -2
- data/lib/erb_lint/linters/extra_newline.rb +1 -1
- data/lib/erb_lint/linters/final_newline.rb +2 -2
- data/lib/erb_lint/linters/hard_coded_string.rb +39 -36
- data/lib/erb_lint/linters/no_javascript_tag_helper.rb +11 -9
- data/lib/erb_lint/linters/partial_instance_variable.rb +1 -1
- data/lib/erb_lint/linters/require_input_autocomplete.rb +8 -10
- data/lib/erb_lint/linters/require_script_nonce.rb +10 -10
- data/lib/erb_lint/linters/right_trim.rb +1 -1
- data/lib/erb_lint/linters/rubocop.rb +12 -10
- data/lib/erb_lint/linters/rubocop_text.rb +1 -1
- data/lib/erb_lint/linters/self_closing_tag.rb +6 -7
- data/lib/erb_lint/linters/space_around_erb_tag.rb +8 -7
- data/lib/erb_lint/linters/space_in_html_tag.rb +7 -6
- 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 +1 -0
- data/lib/erb_lint/reporter.rb +4 -2
- data/lib/erb_lint/reporters/compact_reporter.rb +9 -2
- data/lib/erb_lint/reporters/multiline_reporter.rb +2 -1
- data/lib/erb_lint/runner.rb +1 -1
- data/lib/erb_lint/runner_config.rb +8 -7
- data/lib/erb_lint/runner_config_resolver.rb +5 -4
- data/lib/erb_lint/stats.rb +10 -6
- data/lib/erb_lint/utils/block_map.rb +3 -2
- data/lib/erb_lint/utils/offset_corrector.rb +2 -2
- data/lib/erb_lint/utils/ruby_to_erb.rb +6 -5
- data/lib/erb_lint/utils/severity_levels.rb +2 -2
- data/lib/erb_lint/version.rb +1 -1
- data/lib/erb_lint.rb +1 -1
- metadata +17 -17
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "better_html"
|
4
|
+
require "better_html/tree/tag"
|
5
5
|
|
6
6
|
module ERBLint
|
7
7
|
module Linters
|
@@ -13,7 +13,6 @@ module ERBLint
|
|
13
13
|
"date",
|
14
14
|
"datetime-local",
|
15
15
|
"email",
|
16
|
-
"hidden",
|
17
16
|
"month",
|
18
17
|
"number",
|
19
18
|
"password",
|
@@ -33,7 +32,6 @@ module ERBLint
|
|
33
32
|
:text_field_tag,
|
34
33
|
:utf8_enforcer_tag,
|
35
34
|
:month_field_tag,
|
36
|
-
:hidden_field_tag,
|
37
35
|
:number_field_tag,
|
38
36
|
:password_field_tag,
|
39
37
|
:search_field_tag,
|
@@ -56,8 +54,8 @@ module ERBLint
|
|
56
54
|
parser.nodes_with_type(:tag).each do |tag_node|
|
57
55
|
tag = BetterHtml::Tree::Tag.from_node(tag_node)
|
58
56
|
|
59
|
-
autocomplete_attribute = tag.attributes[
|
60
|
-
type_attribute = tag.attributes[
|
57
|
+
autocomplete_attribute = tag.attributes["autocomplete"]
|
58
|
+
type_attribute = tag.attributes["type"]
|
61
59
|
|
62
60
|
next if !html_input_tag?(tag) || autocomplete_present?(autocomplete_attribute)
|
63
61
|
next unless html_type_requires_autocomplete_attribute?(type_attribute)
|
@@ -65,7 +63,7 @@ module ERBLint
|
|
65
63
|
add_offense(
|
66
64
|
tag_node.to_a[1].loc,
|
67
65
|
"Input tag is missing an autocomplete attribute. If no "\
|
68
|
-
|
66
|
+
"autocomplete behaviour is desired, use the value `off` or `nope`.",
|
69
67
|
[autocomplete_attribute]
|
70
68
|
)
|
71
69
|
end
|
@@ -76,7 +74,7 @@ module ERBLint
|
|
76
74
|
end
|
77
75
|
|
78
76
|
def html_input_tag?(tag)
|
79
|
-
!tag.closing? && tag.name ==
|
77
|
+
!tag.closing? && tag.name == "input"
|
80
78
|
end
|
81
79
|
|
82
80
|
def html_type_requires_autocomplete_attribute?(type_attribute)
|
@@ -99,7 +97,7 @@ module ERBLint
|
|
99
97
|
add_offense(
|
100
98
|
erb_node.loc,
|
101
99
|
"Input field helper is missing an autocomplete attribute. If no "\
|
102
|
-
|
100
|
+
"autocomplete behaviour is desired, use the value `off` or `nope`.",
|
103
101
|
[erb_node, send_node]
|
104
102
|
)
|
105
103
|
end
|
@@ -110,7 +108,7 @@ module ERBLint
|
|
110
108
|
end
|
111
109
|
|
112
110
|
def code_comment?(indicator_node)
|
113
|
-
indicator_node&.loc&.source ==
|
111
|
+
indicator_node&.loc&.source == "#"
|
114
112
|
end
|
115
113
|
|
116
114
|
def extract_ruby_node(source)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "better_html"
|
4
|
+
require "better_html/tree/tag"
|
5
5
|
|
6
6
|
module ERBLint
|
7
7
|
module Linters
|
@@ -22,7 +22,7 @@ module ERBLint
|
|
22
22
|
def find_html_script_tags(parser)
|
23
23
|
parser.nodes_with_type(:tag).each do |tag_node|
|
24
24
|
tag = BetterHtml::Tree::Tag.from_node(tag_node)
|
25
|
-
nonce_attribute = tag.attributes[
|
25
|
+
nonce_attribute = tag.attributes["nonce"]
|
26
26
|
|
27
27
|
next if !html_javascript_tag?(tag) || nonce_present?(nonce_attribute)
|
28
28
|
|
@@ -40,16 +40,16 @@ module ERBLint
|
|
40
40
|
|
41
41
|
def html_javascript_tag?(tag)
|
42
42
|
!tag.closing? &&
|
43
|
-
(tag.name ==
|
43
|
+
(tag.name == "script" && !html_javascript_type_attribute?(tag))
|
44
44
|
end
|
45
45
|
|
46
46
|
def html_javascript_type_attribute?(tag)
|
47
|
-
type_attribute = tag.attributes[
|
47
|
+
type_attribute = tag.attributes["type"]
|
48
48
|
|
49
49
|
type_attribute &&
|
50
50
|
type_attribute.value_node.present? &&
|
51
|
-
type_attribute.value_node.to_a[1] !=
|
52
|
-
type_attribute.value_node.to_a[1] !=
|
51
|
+
type_attribute.value_node.to_a[1] != "text/javascript" &&
|
52
|
+
type_attribute.value_node.to_a[1] != "application/javascript"
|
53
53
|
end
|
54
54
|
|
55
55
|
def find_rails_helper_script_tags(parser)
|
@@ -74,12 +74,12 @@ module ERBLint
|
|
74
74
|
|
75
75
|
def tag_helper?(send_node)
|
76
76
|
send_node&.method_name?(:javascript_tag) ||
|
77
|
-
|
78
|
-
|
77
|
+
send_node&.method_name?(:javascript_include_tag) ||
|
78
|
+
send_node&.method_name?(:javascript_pack_tag)
|
79
79
|
end
|
80
80
|
|
81
81
|
def code_comment?(indicator_node)
|
82
|
-
indicator_node&.loc&.source ==
|
82
|
+
indicator_node&.loc&.source == "#"
|
83
83
|
end
|
84
84
|
|
85
85
|
def extract_ruby_node(source)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "better_html"
|
4
|
+
require "tempfile"
|
5
|
+
require "erb_lint/utils/offset_corrector"
|
6
6
|
|
7
7
|
module ERBLint
|
8
8
|
module Linters
|
@@ -25,7 +25,7 @@ module ERBLint
|
|
25
25
|
super
|
26
26
|
@only_cops = @config.only
|
27
27
|
custom_config = config_from_hash(@config.rubocop_config)
|
28
|
-
@rubocop_config = ::RuboCop::ConfigLoader.merge_with_default(custom_config,
|
28
|
+
@rubocop_config = ::RuboCop::ConfigLoader.merge_with_default(custom_config, "")
|
29
29
|
end
|
30
30
|
|
31
31
|
def run(processed_source)
|
@@ -37,6 +37,7 @@ module ERBLint
|
|
37
37
|
if ::RuboCop::Version::STRING.to_f >= 0.87
|
38
38
|
def autocorrect(_processed_source, offense)
|
39
39
|
return unless offense.context
|
40
|
+
|
40
41
|
rubocop_correction = offense.context[:rubocop_correction]
|
41
42
|
return unless rubocop_correction
|
42
43
|
|
@@ -68,13 +69,13 @@ module ERBLint
|
|
68
69
|
|
69
70
|
def inspect_content(processed_source, erb_node)
|
70
71
|
indicator, _, code_node, = *erb_node
|
71
|
-
return if indicator&.children&.first ==
|
72
|
+
return if indicator&.children&.first == "#"
|
72
73
|
|
73
74
|
original_source = code_node.loc.source
|
74
|
-
trimmed_source = original_source.sub(BLOCK_EXPR,
|
75
|
+
trimmed_source = original_source.sub(BLOCK_EXPR, "").sub(SUFFIX_EXPR, "")
|
75
76
|
alignment_column = code_node.loc.column
|
76
77
|
offset = code_node.loc.begin_pos - alignment_column
|
77
|
-
aligned_source = "#{
|
78
|
+
aligned_source = "#{" " * alignment_column}#{trimmed_source}"
|
78
79
|
|
79
80
|
source = rubocop_processed_source(aligned_source, processed_source.filename)
|
80
81
|
return unless source.valid_syntax?
|
@@ -150,16 +151,17 @@ module ERBLint
|
|
150
151
|
@rubocop_config,
|
151
152
|
extra_details: true,
|
152
153
|
display_cop_names: true,
|
154
|
+
autocorrect: true,
|
153
155
|
auto_correct: true,
|
154
156
|
stdin: "",
|
155
157
|
)
|
156
158
|
end
|
157
159
|
|
158
160
|
def config_from_hash(hash)
|
159
|
-
inherit_from = hash&.delete(
|
161
|
+
inherit_from = hash&.delete("inherit_from")
|
160
162
|
resolve_inheritance(hash, inherit_from)
|
161
163
|
|
162
|
-
tempfile_from(
|
164
|
+
tempfile_from(".erblint-rubocop", hash.to_yaml) do |tempfile|
|
163
165
|
::RuboCop::ConfigLoader.load_file(tempfile.path)
|
164
166
|
end
|
165
167
|
end
|
@@ -174,7 +176,7 @@ module ERBLint
|
|
174
176
|
end
|
175
177
|
|
176
178
|
def base_configs(inherit_from)
|
177
|
-
regex = URI::DEFAULT_PARSER.make_regexp(
|
179
|
+
regex = URI::DEFAULT_PARSER.make_regexp(["http", "https"])
|
178
180
|
configs = Array(inherit_from).compact.map do |base_name|
|
179
181
|
if base_name =~ /\A#{regex}\z/
|
180
182
|
::RuboCop::ConfigLoader.load_file(::RuboCop::RemoteConfig.new(base_name, Dir.pwd))
|
@@ -11,10 +11,8 @@ module ERBLint
|
|
11
11
|
end
|
12
12
|
self.config_schema = ConfigSchema
|
13
13
|
|
14
|
-
SELF_CLOSING_TAGS =
|
15
|
-
|
16
|
-
link menuitem meta param source track wbr img
|
17
|
-
)
|
14
|
+
SELF_CLOSING_TAGS = ["area", "base", "br", "col", "command", "embed", "hr", "input", "keygen", "link",
|
15
|
+
"menuitem", "meta", "param", "source", "track", "wbr", "img",]
|
18
16
|
|
19
17
|
def run(processed_source)
|
20
18
|
processed_source.ast.descendants(:tag).each do |tag_node|
|
@@ -26,7 +24,7 @@ module ERBLint
|
|
26
24
|
add_offense(
|
27
25
|
start_solidus.loc,
|
28
26
|
"Tag `#{tag.name}` is a void element, it must not start with `</`.",
|
29
|
-
|
27
|
+
""
|
30
28
|
)
|
31
29
|
end
|
32
30
|
|
@@ -34,16 +32,17 @@ module ERBLint
|
|
34
32
|
add_offense(
|
35
33
|
tag_node.loc.end.offset(-1),
|
36
34
|
"Tag `#{tag.name}` is self-closing, it must end with `/>`.",
|
37
|
-
|
35
|
+
"/"
|
38
36
|
)
|
39
37
|
end
|
40
38
|
|
41
39
|
next unless @config.enforced_style == :never && tag.self_closing?
|
40
|
+
|
42
41
|
end_solidus = tag_node.children.last
|
43
42
|
add_offense(
|
44
43
|
end_solidus.loc,
|
45
44
|
"Tag `#{tag.name}` is a void element, it must end with `>` and not `/>`.",
|
46
|
-
|
45
|
+
""
|
47
46
|
)
|
48
47
|
end
|
49
48
|
end
|
@@ -15,7 +15,8 @@ module ERBLint
|
|
15
15
|
processed_source.ast.descendants(:erb).each do |erb_node|
|
16
16
|
indicator_node, ltrim, code_node, rtrim = *erb_node
|
17
17
|
indicator = indicator_node&.loc&.source
|
18
|
-
next if indicator ==
|
18
|
+
next if indicator == "#" || indicator == "%"
|
19
|
+
|
19
20
|
code = code_node.children.first
|
20
21
|
|
21
22
|
start_spaces = code.match(START_SPACES)&.captures&.first || ""
|
@@ -23,15 +24,15 @@ module ERBLint
|
|
23
24
|
add_offense(
|
24
25
|
code_node.loc.resize(start_spaces.size),
|
25
26
|
"Use 1 space after `<%#{indicator}#{ltrim&.loc&.source}` "\
|
26
|
-
|
27
|
-
|
27
|
+
"instead of #{start_spaces.size} space#{"s" if start_spaces.size > 1}.",
|
28
|
+
" "
|
28
29
|
)
|
29
30
|
elsif start_spaces.count("\n") > 1
|
30
31
|
lines = start_spaces.split("\n", -1)
|
31
32
|
add_offense(
|
32
33
|
code_node.loc.resize(start_spaces.size),
|
33
34
|
"Use 1 newline after `<%#{indicator&.loc&.source}#{ltrim&.loc&.source}` "\
|
34
|
-
|
35
|
+
"instead of #{start_spaces.count("\n")}.",
|
35
36
|
"#{lines.first}\n#{lines.last}"
|
36
37
|
)
|
37
38
|
end
|
@@ -41,15 +42,15 @@ module ERBLint
|
|
41
42
|
add_offense(
|
42
43
|
code_node.loc.end.adjust(begin_pos: -end_spaces.size),
|
43
44
|
"Use 1 space before `#{rtrim&.loc&.source}%>` "\
|
44
|
-
|
45
|
-
|
45
|
+
"instead of #{end_spaces.size} space#{"s" if start_spaces.size > 1}.",
|
46
|
+
" "
|
46
47
|
)
|
47
48
|
elsif end_spaces.count("\n") > 1
|
48
49
|
lines = end_spaces.split("\n", -1)
|
49
50
|
add_offense(
|
50
51
|
code_node.loc.end.adjust(begin_pos: -end_spaces.size),
|
51
52
|
"Use 1 newline before `#{rtrim&.loc&.source}%>` "\
|
52
|
-
|
53
|
+
"instead of #{end_spaces.count("\n")}.",
|
53
54
|
"#{lines.first}\n#{lines.last}"
|
54
55
|
)
|
55
56
|
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
|
|
@@ -60,24 +60,24 @@ module ERBLint
|
|
60
60
|
|
61
61
|
def single_space(processed_source, range, accept_newline: false)
|
62
62
|
chars = processed_source.file_content[range]
|
63
|
-
return if chars ==
|
63
|
+
return if chars == " "
|
64
64
|
|
65
65
|
newlines = chars.include?("\n")
|
66
|
-
expected = newlines && accept_newline ? "\n#{chars.split("\n", -1).last}" :
|
66
|
+
expected = newlines && accept_newline ? "\n#{chars.split("\n", -1).last}" : " "
|
67
67
|
non_space = chars.match(/([^[[:space:]]])/m)
|
68
68
|
|
69
69
|
if non_space && !non_space.captures.empty?
|
70
70
|
add_offense(
|
71
71
|
processed_source.to_source_range(range),
|
72
72
|
"Non-whitespace character(s) detected: "\
|
73
|
-
"#{non_space.captures.map(&:inspect).join(
|
73
|
+
"#{non_space.captures.map(&:inspect).join(", ")}.",
|
74
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? ?
|
80
|
+
"#{chars.empty? ? "No" : "Extra"} space detected where there should be "\
|
81
81
|
"a single space or a single line break.",
|
82
82
|
expected
|
83
83
|
)
|
@@ -85,7 +85,7 @@ module ERBLint
|
|
85
85
|
else
|
86
86
|
add_offense(
|
87
87
|
processed_source.to_source_range(range),
|
88
|
-
"#{chars.empty? ?
|
88
|
+
"#{chars.empty? ? "No" : "Extra"} space detected where there should be a single space.",
|
89
89
|
expected
|
90
90
|
)
|
91
91
|
end
|
@@ -98,6 +98,7 @@ module ERBLint
|
|
98
98
|
no_space(processed_source, equal.loc.end_pos...value.loc.begin_pos) if equal && value
|
99
99
|
|
100
100
|
next if index >= attributes.children.size - 1
|
101
|
+
|
101
102
|
next_attribute = attributes.children[index + 1]
|
102
103
|
|
103
104
|
single_space_or_newline(
|
@@ -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",
|
26
|
+
spaces.gsub("\t", " " * @config.tab_width)
|
27
27
|
)
|
28
28
|
end
|
29
29
|
|
data/lib/erb_lint/offense.rb
CHANGED
data/lib/erb_lint/reporter.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require
|
2
|
+
|
3
|
+
require "active_support/core_ext/class"
|
4
|
+
require "active_support/core_ext/module/delegation"
|
4
5
|
|
5
6
|
module ERBLint
|
6
7
|
class Reporter
|
@@ -34,6 +35,7 @@ module ERBLint
|
|
34
35
|
private
|
35
36
|
|
36
37
|
attr_reader :stats, :autocorrect
|
38
|
+
|
37
39
|
delegate :processed_files, to: :stats
|
38
40
|
end
|
39
41
|
end
|
@@ -4,8 +4,7 @@ module ERBLint
|
|
4
4
|
module Reporters
|
5
5
|
class CompactReporter < Reporter
|
6
6
|
def preview
|
7
|
-
puts "
|
8
|
-
"#{stats.linters} #{'autocorrectable ' if autocorrect}linters..."
|
7
|
+
puts "#{linting} #{stats.files} files with #{linters}..."
|
9
8
|
end
|
10
9
|
|
11
10
|
def show
|
@@ -21,6 +20,14 @@ module ERBLint
|
|
21
20
|
|
22
21
|
private
|
23
22
|
|
23
|
+
def linting
|
24
|
+
"Linting" + (autocorrect ? " and autocorrecting" : "")
|
25
|
+
end
|
26
|
+
|
27
|
+
def linters
|
28
|
+
"#{stats.linters} linters" + (autocorrect ? " (#{stats.autocorrectable_linters} autocorrectable)" : "")
|
29
|
+
end
|
30
|
+
|
24
31
|
def format_offense(filename, offense)
|
25
32
|
[
|
26
33
|
"#{filename}:",
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require_relative "compact_reporter"
|
3
4
|
|
4
5
|
module ERBLint
|
@@ -9,7 +10,7 @@ module ERBLint
|
|
9
10
|
def format_offense(filename, offense)
|
10
11
|
<<~EOF
|
11
12
|
|
12
|
-
#{offense.message}#{Rainbow(
|
13
|
+
#{offense.message}#{Rainbow(" (not autocorrected)").red if autocorrect}
|
13
14
|
In file: #{filename}:#{offense.line_number}
|
14
15
|
EOF
|
15
16
|
end
|
data/lib/erb_lint/runner.rb
CHANGED
@@ -8,7 +8,7 @@ module ERBLint
|
|
8
8
|
def initialize(file_loader, config)
|
9
9
|
@file_loader = file_loader
|
10
10
|
@config = config || RunnerConfig.default
|
11
|
-
raise ArgumentError,
|
11
|
+
raise ArgumentError, "expect `config` to be a RunnerConfig instance" unless @config.is_a?(RunnerConfig)
|
12
12
|
|
13
13
|
linter_classes = LinterRegistry.linters.select { |klass| @config.for_linter(klass).enabled? }
|
14
14
|
@linters = linter_classes.map do |linter_class|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "erb_lint/runner_config_resolver"
|
4
4
|
|
5
5
|
module ERBLint
|
6
6
|
class RunnerConfig
|
@@ -9,7 +9,7 @@ module ERBLint
|
|
9
9
|
def initialize(config = nil, file_loader = nil)
|
10
10
|
@config = (config || {}).dup.deep_stringify_keys
|
11
11
|
|
12
|
-
resolver.resolve_inheritance_from_gems(@config, @config.delete(
|
12
|
+
resolver.resolve_inheritance_from_gems(@config, @config.delete("inherit_gem"))
|
13
13
|
resolver.resolve_inheritance(@config, file_loader) if file_loader
|
14
14
|
@config.delete("inherit_from")
|
15
15
|
end
|
@@ -24,15 +24,16 @@ module ERBLint
|
|
24
24
|
elsif klass.is_a?(Class) && klass <= ERBLint::Linter
|
25
25
|
klass.simple_name
|
26
26
|
else
|
27
|
-
raise ArgumentError,
|
27
|
+
raise ArgumentError, "expected String or linter class"
|
28
28
|
end
|
29
29
|
linter_klass = LinterRegistry.find_by_name(klass_name)
|
30
30
|
raise Error, "#{klass_name}: linter not found (is it loaded?)" unless linter_klass
|
31
|
+
|
31
32
|
linter_klass.config_schema.new(config_hash_for_linter(klass_name))
|
32
33
|
end
|
33
34
|
|
34
35
|
def global_exclude
|
35
|
-
@config[
|
36
|
+
@config["exclude"] || []
|
36
37
|
end
|
37
38
|
|
38
39
|
def merge(other_config)
|
@@ -75,13 +76,13 @@ module ERBLint
|
|
75
76
|
private
|
76
77
|
|
77
78
|
def linters_config
|
78
|
-
@config[
|
79
|
+
@config["linters"] || {}
|
79
80
|
end
|
80
81
|
|
81
82
|
def config_hash_for_linter(klass_name)
|
82
83
|
config_hash = linters_config[klass_name] || {}
|
83
|
-
config_hash[
|
84
|
-
config_hash[
|
84
|
+
config_hash["exclude"] ||= []
|
85
|
+
config_hash["exclude"].concat(global_exclude) if config_hash["exclude"].is_a?(Array)
|
85
86
|
config_hash
|
86
87
|
end
|
87
88
|
|
@@ -24,10 +24,11 @@
|
|
24
24
|
module ERBLint
|
25
25
|
class RunnerConfigResolver
|
26
26
|
def resolve_inheritance(hash, file_loader)
|
27
|
-
inherited_files = Array(hash[
|
27
|
+
inherited_files = Array(hash["inherit_from"])
|
28
28
|
base_configs(file_loader, inherited_files).reverse_each do |base_config|
|
29
29
|
base_config.each do |k, v|
|
30
30
|
next unless v.is_a?(Hash)
|
31
|
+
|
31
32
|
v = v.deep_merge(hash[k]) if hash.key?(k)
|
32
33
|
hash[k] = v
|
33
34
|
end
|
@@ -36,12 +37,12 @@ module ERBLint
|
|
36
37
|
|
37
38
|
def resolve_inheritance_from_gems(hash, gems)
|
38
39
|
(gems || {}).each_pair do |gem_name, config_path|
|
39
|
-
raise(ArgumentError, "can't inherit configuration from the erb-lint gem") if gem_name ==
|
40
|
+
raise(ArgumentError, "can't inherit configuration from the erb-lint gem") if gem_name == "erb-lint"
|
40
41
|
|
41
|
-
hash[
|
42
|
+
hash["inherit_from"] = Array(hash["inherit_from"])
|
42
43
|
Array(config_path).reverse_each do |path|
|
43
44
|
# Put gem configuration first so local configuration overrides it.
|
44
|
-
hash[
|
45
|
+
hash["inherit_from"].unshift(gem_config_path(gem_name, path))
|
45
46
|
end
|
46
47
|
end
|
47
48
|
end
|
data/lib/erb_lint/stats.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module ERBLint
|
3
4
|
class Stats
|
4
5
|
attr_accessor :ignored,
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
:found,
|
7
|
+
:corrected,
|
8
|
+
:exceptions,
|
9
|
+
:linters,
|
10
|
+
:autocorrectable_linters,
|
11
|
+
:files,
|
12
|
+
:processed_files
|
11
13
|
|
12
14
|
def initialize(
|
13
15
|
ignored: 0,
|
@@ -15,6 +17,7 @@ module ERBLint
|
|
15
17
|
corrected: 0,
|
16
18
|
exceptions: 0,
|
17
19
|
linters: 0,
|
20
|
+
autocorrectable_linters: 0,
|
18
21
|
files: 0,
|
19
22
|
processed_files: {}
|
20
23
|
)
|
@@ -23,6 +26,7 @@ module ERBLint
|
|
23
26
|
@corrected = corrected
|
24
27
|
@exceptions = exceptions
|
25
28
|
@linters = linters
|
29
|
+
@autocorrectable_linters = autocorrectable_linters
|
26
30
|
@files = files
|
27
31
|
@processed_files = processed_files
|
28
32
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "better_html/ast/node"
|
4
|
+
require "better_html/test_helper/ruby_node"
|
5
5
|
|
6
6
|
module ERBLint
|
7
7
|
module Utils
|
@@ -194,6 +194,7 @@ module ERBLint
|
|
194
194
|
|
195
195
|
def find_entry(range)
|
196
196
|
return unless range
|
197
|
+
|
197
198
|
@entries.find do |entry|
|
198
199
|
entry.contains_ruby_range?(Range.new(range.begin_pos, range.end_pos))
|
199
200
|
end
|
@@ -63,8 +63,8 @@ module ERBLint
|
|
63
63
|
node_or_range
|
64
64
|
else
|
65
65
|
raise TypeError,
|
66
|
-
|
67
|
-
|
66
|
+
"Expected a Parser::Source::Range, Comment or " \
|
67
|
+
"Rubocop::AST::Node, got #{node_or_range.class}"
|
68
68
|
end
|
69
69
|
end
|
70
70
|
end
|
@@ -9,14 +9,15 @@ module ERBLint
|
|
9
9
|
def html_options_to_tag_attributes(hash_node)
|
10
10
|
hash_node.children.map do |pair_node|
|
11
11
|
key_node, value_node = *pair_node
|
12
|
-
key = ruby_to_erb(key_node,
|
13
|
-
value = ruby_to_erb(value_node,
|
14
|
-
[key, "\"#{value}\""].join(
|
15
|
-
end.join(
|
12
|
+
key = ruby_to_erb(key_node, "=") { |s| s.tr("_", "-") }
|
13
|
+
value = ruby_to_erb(value_node, "=") { |s| escape_quote(s) }
|
14
|
+
[key, "\"#{value}\""].join("=")
|
15
|
+
end.join(" ")
|
16
16
|
end
|
17
17
|
|
18
18
|
def ruby_to_erb(node, indicator = nil, &block)
|
19
19
|
return node if node.nil? || node.is_a?(String)
|
20
|
+
|
20
21
|
case node.type
|
21
22
|
when :str, :sym
|
22
23
|
s = node.children.first.to_s
|
@@ -43,7 +44,7 @@ module ERBLint
|
|
43
44
|
end
|
44
45
|
|
45
46
|
def escape_quote(str)
|
46
|
-
str.gsub('"',
|
47
|
+
str.gsub('"', """)
|
47
48
|
end
|
48
49
|
end
|
49
50
|
end
|
@@ -3,10 +3,10 @@
|
|
3
3
|
module ERBLint
|
4
4
|
module Utils
|
5
5
|
module SeverityLevels
|
6
|
-
SEVERITY_NAMES =
|
6
|
+
SEVERITY_NAMES = [:info, :refactor, :convention, :warning, :error, :fatal].freeze
|
7
7
|
|
8
8
|
SEVERITY_CODE_TABLE = { I: :info, R: :refactor, C: :convention,
|
9
|
-
W: :warning, E: :error, F: :fatal }.freeze
|
9
|
+
W: :warning, E: :error, F: :fatal, }.freeze
|
10
10
|
|
11
11
|
def severity_level_for_name(name)
|
12
12
|
SEVERITY_NAMES.index(name || :error) + 1
|