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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0eabdfa71b2841fc684663a79233451981e21fcffb175c3ae7a1e0bd8afdc8e4
|
4
|
+
data.tar.gz: c609b033d3354e27c938ef1972b1ac16c654b1900115bb4f6d6595c384d1cfb5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3686f39426c32119e8a725b8320143b31c48f98969bb6f0135827c5ff7c260d5674cfad5190c2bc75111fd5a76d881e47d7aa18b6b48f3f903f698719601623
|
7
|
+
data.tar.gz: 727473a64473dad0adb3912bc7f7b7e5c84d51c60374f72e93f380d378635848a240e8f1f3f16ec8f88874290e5e16821e8445b882c09cec4c78081db9eb2bda
|
data/exe/erb_lint
ADDED
data/exe/erblint
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
4
|
+
lib_path = File.expand_path("#{__dir__}/../lib")
|
5
|
+
$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
|
5
6
|
|
6
|
-
require "
|
7
|
+
require "rainbow"
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
warn(Rainbow("Calling `erblint` is deprecated, please call the renamed executable `erb_lint` instead.").yellow)
|
10
|
+
exec(File.join(__dir__, "erb_lint"), *ARGV)
|
data/lib/erb_lint/all.rb
CHANGED
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ERBLint
|
4
|
+
class Cache
|
5
|
+
CACHE_DIRECTORY = ".erb_lint_cache"
|
6
|
+
|
7
|
+
def initialize(config, cache_dir = nil)
|
8
|
+
@config = config
|
9
|
+
@cache_dir = cache_dir || CACHE_DIRECTORY
|
10
|
+
@hits = []
|
11
|
+
@new_results = []
|
12
|
+
puts "Cache mode is on"
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(filename, file_content)
|
16
|
+
file_checksum = checksum(filename, file_content)
|
17
|
+
begin
|
18
|
+
cache_file_contents_as_offenses = JSON.parse(
|
19
|
+
File.read(File.join(@cache_dir, file_checksum)),
|
20
|
+
).map do |offense_hash|
|
21
|
+
ERBLint::CachedOffense.new(offense_hash)
|
22
|
+
end
|
23
|
+
rescue Errno::ENOENT
|
24
|
+
return false
|
25
|
+
end
|
26
|
+
@hits.push(file_checksum)
|
27
|
+
cache_file_contents_as_offenses
|
28
|
+
end
|
29
|
+
|
30
|
+
def set(filename, file_content, offenses_as_json)
|
31
|
+
file_checksum = checksum(filename, file_content)
|
32
|
+
@new_results.push(file_checksum)
|
33
|
+
|
34
|
+
FileUtils.mkdir_p(@cache_dir)
|
35
|
+
|
36
|
+
File.open(File.join(@cache_dir, file_checksum), "wb") do |f|
|
37
|
+
f.write(offenses_as_json)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def close
|
42
|
+
prune_cache
|
43
|
+
end
|
44
|
+
|
45
|
+
def prune_cache
|
46
|
+
if hits.empty?
|
47
|
+
puts "Cache being created for the first time, skipping prune"
|
48
|
+
return
|
49
|
+
end
|
50
|
+
|
51
|
+
cache_files = Dir.new(@cache_dir).children
|
52
|
+
cache_files.each do |cache_file|
|
53
|
+
next if hits.include?(cache_file) || new_results.include?(cache_file)
|
54
|
+
|
55
|
+
File.delete(File.join(@cache_dir, cache_file))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def cache_dir_exists?
|
60
|
+
File.directory?(@cache_dir)
|
61
|
+
end
|
62
|
+
|
63
|
+
def clear
|
64
|
+
return unless cache_dir_exists?
|
65
|
+
|
66
|
+
puts "Clearing cache by deleting cache directory"
|
67
|
+
FileUtils.rm_r(@cache_dir)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
attr_reader :config, :hits, :new_results
|
73
|
+
|
74
|
+
def checksum(filename, file_content)
|
75
|
+
digester = Digest::SHA1.new
|
76
|
+
mode = File.stat(filename).mode
|
77
|
+
|
78
|
+
digester.update(
|
79
|
+
"#{mode}#{config.to_hash}#{ERBLint::VERSION}#{file_content}",
|
80
|
+
)
|
81
|
+
digester.hexdigest
|
82
|
+
rescue Errno::ENOENT
|
83
|
+
# Spurious files that come and go should not cause a crash, at least not
|
84
|
+
# here.
|
85
|
+
"_"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ERBLint
|
4
|
+
# A Cached version of an Offense with only essential information represented as strings
|
5
|
+
class CachedOffense
|
6
|
+
attr_reader(
|
7
|
+
:message,
|
8
|
+
:line_number,
|
9
|
+
:severity,
|
10
|
+
:column,
|
11
|
+
:simple_name,
|
12
|
+
:last_line,
|
13
|
+
:last_column,
|
14
|
+
:length,
|
15
|
+
)
|
16
|
+
|
17
|
+
def initialize(params)
|
18
|
+
params = params.transform_keys(&:to_sym)
|
19
|
+
|
20
|
+
@message = params[:message]
|
21
|
+
@line_number = params[:line_number]
|
22
|
+
@severity = params[:severity]&.to_sym
|
23
|
+
@column = params[:column]
|
24
|
+
@simple_name = params[:simple_name]
|
25
|
+
@last_line = params[:last_line]
|
26
|
+
@last_column = params[:last_column]
|
27
|
+
@length = params[:length]
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.new_from_offense(offense)
|
31
|
+
new(
|
32
|
+
{
|
33
|
+
message: offense.message,
|
34
|
+
line_number: offense.line_number,
|
35
|
+
severity: offense.severity,
|
36
|
+
column: offense.column,
|
37
|
+
simple_name: offense.simple_name,
|
38
|
+
last_line: offense.last_line,
|
39
|
+
last_column: offense.last_column,
|
40
|
+
length: offense.length,
|
41
|
+
},
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_h
|
46
|
+
{
|
47
|
+
message: message,
|
48
|
+
line_number: line_number,
|
49
|
+
severity: severity,
|
50
|
+
column: column,
|
51
|
+
simple_name: simple_name,
|
52
|
+
last_line: last_line,
|
53
|
+
last_column: last_column,
|
54
|
+
length: length,
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/erb_lint/cli.rb
CHANGED
@@ -13,7 +13,8 @@ module ERBLint
|
|
13
13
|
class CLI
|
14
14
|
include Utils::SeverityLevels
|
15
15
|
|
16
|
-
|
16
|
+
DEPRECATED_CONFIG_FILENAME = ".erb-lint.yml"
|
17
|
+
DEFAULT_CONFIG_FILENAME = ".erb_lint.yml"
|
17
18
|
DEFAULT_LINT_ALL_GLOB = "**/*.html{+*,}.erb"
|
18
19
|
|
19
20
|
class ExitWithFailure < RuntimeError; end
|
@@ -30,12 +31,33 @@ module ERBLint
|
|
30
31
|
def run(args = ARGV)
|
31
32
|
dupped_args = args.dup
|
32
33
|
load_options(dupped_args)
|
34
|
+
|
35
|
+
if cache? && autocorrect?
|
36
|
+
failure!("cannot run autocorrect mode with cache")
|
37
|
+
end
|
38
|
+
|
33
39
|
@files = @options[:stdin] || dupped_args
|
34
40
|
|
35
41
|
load_config
|
36
42
|
|
43
|
+
cache_dir = @options[:cache_dir]
|
44
|
+
@cache = Cache.new(@config, cache_dir) if cache? || clear_cache?
|
45
|
+
|
46
|
+
if clear_cache?
|
47
|
+
if cache.cache_dir_exists?
|
48
|
+
cache.clear
|
49
|
+
success!("cache directory cleared")
|
50
|
+
else
|
51
|
+
failure!("cache directory doesn't exist, skipping deletion.")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
37
55
|
if !@files.empty? && lint_files.empty?
|
38
|
-
|
56
|
+
if allow_no_files?
|
57
|
+
success!("no files found...\n")
|
58
|
+
else
|
59
|
+
failure!("no files found...\n")
|
60
|
+
end
|
39
61
|
elsif lint_files.empty?
|
40
62
|
failure!("no files found or given, specify files or config...\n#{option_parser}")
|
41
63
|
end
|
@@ -48,24 +70,25 @@ module ERBLint
|
|
48
70
|
|
49
71
|
@options[:format] ||= :multiline
|
50
72
|
@options[:fail_level] ||= severity_level_for_name(:refactor)
|
73
|
+
@options[:disable_inline_configs] ||= false
|
51
74
|
@stats.files = lint_files.size
|
52
75
|
@stats.linters = enabled_linter_classes.size
|
53
76
|
@stats.autocorrectable_linters = enabled_linter_classes.count(&:support_autocorrect?)
|
54
77
|
|
55
|
-
reporter = Reporter.create_reporter(@options[:format], @stats, autocorrect
|
78
|
+
reporter = Reporter.create_reporter(@options[:format], @stats, autocorrect?, @options[:show_linter_names])
|
56
79
|
reporter.preview
|
57
80
|
|
58
|
-
runner = ERBLint::Runner.new(file_loader, @config)
|
81
|
+
runner = ERBLint::Runner.new(file_loader, @config, @options[:disable_inline_configs])
|
59
82
|
file_content = nil
|
60
83
|
|
61
84
|
lint_files.each do |filename|
|
62
85
|
runner.clear_offenses
|
63
86
|
begin
|
64
|
-
file_content =
|
87
|
+
file_content = run_on_file(runner, filename)
|
65
88
|
rescue => e
|
66
89
|
@stats.exceptions += 1
|
67
90
|
puts "Exception occurred when processing: #{relative_filename(filename)}"
|
68
|
-
puts "If this file cannot be processed by
|
91
|
+
puts "If this file cannot be processed by erb_lint, " \
|
69
92
|
"you can exclude it in your configuration file."
|
70
93
|
puts e.message
|
71
94
|
puts Rainbow(e.backtrace.join("\n")).red
|
@@ -73,6 +96,8 @@ module ERBLint
|
|
73
96
|
end
|
74
97
|
end
|
75
98
|
|
99
|
+
cache&.close
|
100
|
+
|
76
101
|
reporter.show
|
77
102
|
|
78
103
|
if stdin? && autocorrect?
|
@@ -95,19 +120,49 @@ module ERBLint
|
|
95
120
|
|
96
121
|
private
|
97
122
|
|
123
|
+
attr_reader :cache, :config
|
124
|
+
|
125
|
+
def run_on_file(runner, filename)
|
126
|
+
file_content = read_content(filename)
|
127
|
+
|
128
|
+
if cache? && !autocorrect?
|
129
|
+
run_using_cache(runner, filename, file_content)
|
130
|
+
else
|
131
|
+
file_content = run_with_corrections(runner, filename, file_content)
|
132
|
+
end
|
133
|
+
|
134
|
+
log_offense_stats(runner, filename)
|
135
|
+
file_content
|
136
|
+
end
|
137
|
+
|
138
|
+
def run_using_cache(runner, filename, file_content)
|
139
|
+
if (cache_result_offenses = cache.get(filename, file_content))
|
140
|
+
runner.restore_offenses(cache_result_offenses)
|
141
|
+
else
|
142
|
+
run_with_corrections(runner, filename, file_content)
|
143
|
+
cache.set(filename, file_content, runner.offenses.map(&:to_cached_offense_hash).to_json)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
98
147
|
def autocorrect?
|
99
148
|
@options[:autocorrect]
|
100
149
|
end
|
101
150
|
|
102
|
-
def
|
103
|
-
|
151
|
+
def cache?
|
152
|
+
@options[:cache]
|
153
|
+
end
|
104
154
|
|
155
|
+
def clear_cache?
|
156
|
+
@options[:clear_cache]
|
157
|
+
end
|
158
|
+
|
159
|
+
def run_with_corrections(runner, filename, file_content)
|
105
160
|
7.times do
|
106
161
|
processed_source = ERBLint::ProcessedSource.new(filename, file_content)
|
107
162
|
runner.run(processed_source)
|
108
163
|
break unless autocorrect? && runner.offenses.any?
|
109
164
|
|
110
|
-
corrector =
|
165
|
+
corrector = corrector(processed_source, runner.offenses)
|
111
166
|
break if corrector.corrections.empty?
|
112
167
|
break if processed_source.file_content == corrector.corrected_content
|
113
168
|
|
@@ -123,6 +178,11 @@ module ERBLint
|
|
123
178
|
file_content = corrector.corrected_content
|
124
179
|
runner.clear_offenses
|
125
180
|
end
|
181
|
+
|
182
|
+
file_content
|
183
|
+
end
|
184
|
+
|
185
|
+
def log_offense_stats(runner, filename)
|
126
186
|
offenses_filename = relative_filename(filename)
|
127
187
|
offenses = runner.offenses || []
|
128
188
|
|
@@ -134,8 +194,6 @@ module ERBLint
|
|
134
194
|
|
135
195
|
@stats.processed_files[offenses_filename] ||= []
|
136
196
|
@stats.processed_files[offenses_filename] |= offenses
|
137
|
-
|
138
|
-
file_content
|
139
197
|
end
|
140
198
|
|
141
199
|
def read_content(filename)
|
@@ -144,10 +202,8 @@ module ERBLint
|
|
144
202
|
$stdin.binmode.read.force_encoding(Encoding::UTF_8)
|
145
203
|
end
|
146
204
|
|
147
|
-
def
|
148
|
-
|
149
|
-
failure!(corrector.diagnostics.join(", ")) if corrector.diagnostics.any?
|
150
|
-
corrector
|
205
|
+
def corrector(processed_source, offenses)
|
206
|
+
ERBLint::Corrector.new(processed_source, offenses)
|
151
207
|
end
|
152
208
|
|
153
209
|
def config_filename
|
@@ -158,6 +214,13 @@ module ERBLint
|
|
158
214
|
if File.exist?(config_filename)
|
159
215
|
config = RunnerConfig.new(file_loader.yaml(config_filename), file_loader)
|
160
216
|
@config = RunnerConfig.default_for(config)
|
217
|
+
elsif File.exist?(DEPRECATED_CONFIG_FILENAME)
|
218
|
+
deprecation_message = "The config file has been renamed to `#{DEFAULT_CONFIG_FILENAME}` and " \
|
219
|
+
"`#{DEPRECATED_CONFIG_FILENAME}` is deprecated. " \
|
220
|
+
"Please rename your config file to `#{DEFAULT_CONFIG_FILENAME}`."
|
221
|
+
warn(Rainbow(deprecation_message).yellow)
|
222
|
+
config = RunnerConfig.new(file_loader.yaml(DEPRECATED_CONFIG_FILENAME), file_loader)
|
223
|
+
@config = RunnerConfig.default_for(config)
|
161
224
|
else
|
162
225
|
warn(Rainbow("#{config_filename} not found: using default config").yellow)
|
163
226
|
@config = RunnerConfig.default
|
@@ -165,7 +228,7 @@ module ERBLint
|
|
165
228
|
rescue Psych::SyntaxError => e
|
166
229
|
failure!("error parsing config: #{e.message}")
|
167
230
|
ensure
|
168
|
-
@config
|
231
|
+
@config&.merge!(runner_config_override)
|
169
232
|
end
|
170
233
|
|
171
234
|
def file_loader
|
@@ -246,7 +309,7 @@ module ERBLint
|
|
246
309
|
ERBLint::LinterRegistry.linters.map do |klass|
|
247
310
|
linters[klass.simple_name] = { "enabled" => enabled_linter_classes.include?(klass) }
|
248
311
|
end
|
249
|
-
end
|
312
|
+
end,
|
250
313
|
)
|
251
314
|
end
|
252
315
|
|
@@ -262,7 +325,7 @@ module ERBLint
|
|
262
325
|
end
|
263
326
|
end
|
264
327
|
|
265
|
-
opts.on("--format FORMAT", format_options_help) do |format|
|
328
|
+
opts.on("-f", "--format FORMAT", format_options_help) do |format|
|
266
329
|
unless Reporter.available_format?(format)
|
267
330
|
error_message = invalid_format_error_message(format)
|
268
331
|
failure!(error_message)
|
@@ -279,8 +342,24 @@ module ERBLint
|
|
279
342
|
@options[:enabled_linters] = known_linter_names
|
280
343
|
end
|
281
344
|
|
282
|
-
opts.on("--
|
283
|
-
|
345
|
+
opts.on("--cache", "Enable caching") do |config|
|
346
|
+
@options[:cache] = config
|
347
|
+
end
|
348
|
+
|
349
|
+
opts.on("--cache-dir DIR", "Set the cache directory") do |dir|
|
350
|
+
@options[:cache_dir] = dir
|
351
|
+
end
|
352
|
+
|
353
|
+
opts.on("--clear-cache", "Clear cache") do |config|
|
354
|
+
@options[:clear_cache] = config
|
355
|
+
end
|
356
|
+
|
357
|
+
opts.on(
|
358
|
+
"--enable-linters LINTER[,LINTER,...]",
|
359
|
+
Array,
|
360
|
+
"Only use specified linter",
|
361
|
+
"Known linters are: #{known_linter_names.join(", ")}",
|
362
|
+
) do |linters|
|
284
363
|
linters.each do |linter|
|
285
364
|
unless known_linter_names.include?(linter)
|
286
365
|
failure!("#{linter}: not a valid linter name (#{known_linter_names.join(", ")})")
|
@@ -302,10 +381,22 @@ module ERBLint
|
|
302
381
|
@options[:autocorrect] = config
|
303
382
|
end
|
304
383
|
|
384
|
+
opts.on("--show-linter-names", "Show linter names") do
|
385
|
+
@options[:show_linter_names] = true
|
386
|
+
end
|
387
|
+
|
388
|
+
opts.on("--allow-no-files", "When no matching files found, exit successfully (default: false)") do |config|
|
389
|
+
@options[:allow_no_files] = config
|
390
|
+
end
|
391
|
+
|
392
|
+
opts.on("--disable-inline-configs", "Report all offenses while ignoring inline disable comments") do
|
393
|
+
@options[:disable_inline_configs] = true
|
394
|
+
end
|
395
|
+
|
305
396
|
opts.on(
|
306
397
|
"-sFILE",
|
307
398
|
"--stdin FILE",
|
308
|
-
"Pipe source from STDIN. Takes the path to be used to check which rules to apply."
|
399
|
+
"Pipe source from STDIN. Takes the path to be used to check which rules to apply.",
|
309
400
|
) do |file|
|
310
401
|
@options[:stdin] = [file]
|
311
402
|
end
|
@@ -321,7 +412,7 @@ module ERBLint
|
|
321
412
|
end
|
322
413
|
|
323
414
|
def format_options_help
|
324
|
-
"Report offenses in the given format: "\
|
415
|
+
"Report offenses in the given format: " \
|
325
416
|
"(#{Reporter.available_formats.join(", ")}) (default: multiline)"
|
326
417
|
end
|
327
418
|
|
@@ -333,5 +424,9 @@ module ERBLint
|
|
333
424
|
def stdin?
|
334
425
|
@options[:stdin].present?
|
335
426
|
end
|
427
|
+
|
428
|
+
def allow_no_files?
|
429
|
+
@options[:allow_no_files]
|
430
|
+
end
|
336
431
|
end
|
337
432
|
end
|
data/lib/erb_lint/corrector.rb
CHANGED
@@ -7,31 +7,20 @@ module ERBLint
|
|
7
7
|
def initialize(processed_source, offenses)
|
8
8
|
@processed_source = processed_source
|
9
9
|
@offenses = offenses
|
10
|
+
corrector = RuboCop::Cop::Corrector.new(@processed_source.source_buffer)
|
11
|
+
correct!(corrector)
|
10
12
|
@corrected_content = corrector.rewrite
|
11
13
|
end
|
12
14
|
|
13
15
|
def corrections
|
14
16
|
@corrections ||= @offenses.map do |offense|
|
15
|
-
offense.linter.autocorrect(@processed_source, offense)
|
17
|
+
offense.linter.autocorrect(@processed_source, offense) if offense.linter.class.support_autocorrect?
|
16
18
|
end.compact
|
17
19
|
end
|
18
20
|
|
19
|
-
def corrector
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
if ::RuboCop::Version::STRING.to_f >= 0.87
|
24
|
-
require "rubocop/cop/legacy/corrector"
|
25
|
-
BASE = ::RuboCop::Cop::Legacy::Corrector
|
26
|
-
|
27
|
-
def diagnostics
|
28
|
-
[]
|
29
|
-
end
|
30
|
-
else
|
31
|
-
BASE = ::RuboCop::Cop::Corrector
|
32
|
-
|
33
|
-
def diagnostics
|
34
|
-
corrector.diagnostics
|
21
|
+
def correct!(corrector)
|
22
|
+
corrections.each do |correction|
|
23
|
+
correction.call(corrector)
|
35
24
|
end
|
36
25
|
end
|
37
26
|
end
|
data/lib/erb_lint/file_loader.rb
CHANGED
@@ -9,14 +9,8 @@ module ERBLint
|
|
9
9
|
@base_path = base_path
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
YAML.safe_load(read_content(filename), permitted_classes: [Regexp, Symbol], filename: filename) || {}
|
15
|
-
end
|
16
|
-
else
|
17
|
-
def yaml(filename)
|
18
|
-
YAML.safe_load(read_content(filename), [Regexp, Symbol], [], false, filename) || {}
|
19
|
-
end
|
12
|
+
def yaml(filename)
|
13
|
+
YAML.safe_load(read_content(filename), permitted_classes: [Regexp, Symbol], filename: filename) || {}
|
20
14
|
end
|
21
15
|
|
22
16
|
private
|
data/lib/erb_lint/linter.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "erb_lint/utils/inline_configs"
|
4
|
+
|
3
5
|
module ERBLint
|
4
6
|
# Defines common functionality available to all linters.
|
5
7
|
class Linter
|
@@ -30,13 +32,13 @@ module ERBLint
|
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
attr_reader :offenses
|
35
|
+
attr_reader :offenses, :config
|
34
36
|
|
35
37
|
# Must be implemented by the concrete inheriting class.
|
36
38
|
def initialize(file_loader, config)
|
37
39
|
@file_loader = file_loader
|
38
40
|
@config = config
|
39
|
-
raise ArgumentError, "expect `config` to be #{self.class.config_schema} instance, "\
|
41
|
+
raise ArgumentError, "expect `config` to be #{self.class.config_schema} instance, " \
|
40
42
|
"not #{config.class}" unless config.is_a?(self.class.config_schema)
|
41
43
|
@offenses = []
|
42
44
|
end
|
@@ -53,6 +55,13 @@ module ERBLint
|
|
53
55
|
raise NotImplementedError, "must implement ##{__method__}"
|
54
56
|
end
|
55
57
|
|
58
|
+
def run_and_update_offense_status(processed_source, enable_inline_configs = true)
|
59
|
+
run(processed_source)
|
60
|
+
if @offenses.any? && enable_inline_configs
|
61
|
+
update_offense_status(processed_source)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
56
65
|
def add_offense(source_range, message, context = nil, severity = nil)
|
57
66
|
@offenses << Offense.new(self, source_range, message, context, severity)
|
58
67
|
end
|
@@ -60,5 +69,22 @@ module ERBLint
|
|
60
69
|
def clear_offenses
|
61
70
|
@offenses = []
|
62
71
|
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def update_offense_status(processed_source)
|
76
|
+
@offenses.each do |offense|
|
77
|
+
offense_line_range = offense.source_range.line_range
|
78
|
+
offense_lines = source_for_line_range(processed_source, offense_line_range)
|
79
|
+
|
80
|
+
if Utils::InlineConfigs.rule_disable_comment_for_lines?(self.class.simple_name, offense_lines)
|
81
|
+
offense.disabled = true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def source_for_line_range(processed_source, line_range)
|
87
|
+
processed_source.source_buffer.source_lines[line_range.first - 1..line_range.last - 1].join
|
88
|
+
end
|
63
89
|
end
|
64
90
|
end
|
@@ -3,7 +3,8 @@
|
|
3
3
|
module ERBLint
|
4
4
|
# Stores all linters available to the application.
|
5
5
|
module LinterRegistry
|
6
|
-
|
6
|
+
DEPRECATED_CUSTOM_LINTERS_DIR = ".erb-linters"
|
7
|
+
CUSTOM_LINTERS_DIR = ".erb_linters"
|
7
8
|
@loaded_linters = []
|
8
9
|
|
9
10
|
class << self
|
@@ -28,6 +29,15 @@ module ERBLint
|
|
28
29
|
|
29
30
|
def load_custom_linters(directory = CUSTOM_LINTERS_DIR)
|
30
31
|
ruby_files = Dir.glob(File.expand_path(File.join(directory, "**", "*.rb")))
|
32
|
+
|
33
|
+
deprecated_ruby_files = Dir.glob(File.expand_path(File.join(DEPRECATED_CUSTOM_LINTERS_DIR, "**", "*.rb")))
|
34
|
+
if deprecated_ruby_files.any?
|
35
|
+
deprecation_message = "The '#{DEPRECATED_CUSTOM_LINTERS_DIR}' directory for custom linters is deprecated. " \
|
36
|
+
"Please rename it to '#{CUSTOM_LINTERS_DIR}'"
|
37
|
+
warn(Rainbow(deprecation_message).yellow)
|
38
|
+
ruby_files.concat(deprecated_ruby_files)
|
39
|
+
end
|
40
|
+
|
31
41
|
ruby_files.each { |file| require file }
|
32
42
|
end
|
33
43
|
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
|