erb_lint 0.2.0 → 0.3.1
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/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 +70 -6
- data/lib/erb_lint/linter.rb +1 -1
- data/lib/erb_lint/linters/comment_syntax.rb +52 -0
- data/lib/erb_lint/linters/rubocop.rb +7 -1
- data/lib/erb_lint/offense.rb +20 -0
- data/lib/erb_lint/reporters/json_reporter.rb +4 -4
- data/lib/erb_lint/runner.rb +4 -0
- data/lib/erb_lint/runner_config.rb +1 -0
- data/lib/erb_lint/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bd25c794b1028b09ecec8ce3b5e77600d36364d59b85f2e4b24a18d6bb08853
|
4
|
+
data.tar.gz: e41f353e930401a024d880fc6973beb1e462f2f5372edb094523eacde0030d72
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94ed5b3479803ff2b51af6390c0e39c2fb37ef98e23fc2523ac204b638d8ff043665926081794ff27d77a60faae8ee7747cb4ef3d04125b7b3f7c2ae55ea268f
|
7
|
+
data.tar.gz: 9b423110f202bb9728ec57dbd60f04aa86e2901ecfa915d9ddc49fd58fac27b3daddea78780612c3f474ece4c41c01977bea72ad8353a9a113d5cee8c4a51914
|
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
@@ -30,10 +30,27 @@ module ERBLint
|
|
30
30
|
def run(args = ARGV)
|
31
31
|
dupped_args = args.dup
|
32
32
|
load_options(dupped_args)
|
33
|
+
|
34
|
+
if cache? && autocorrect?
|
35
|
+
failure!("cannot run autocorrect mode with cache")
|
36
|
+
end
|
37
|
+
|
33
38
|
@files = @options[:stdin] || dupped_args
|
34
39
|
|
35
40
|
load_config
|
36
41
|
|
42
|
+
cache_dir = @options[:cache_dir]
|
43
|
+
@cache = Cache.new(@config, cache_dir) if cache? || clear_cache?
|
44
|
+
|
45
|
+
if clear_cache?
|
46
|
+
if cache.cache_dir_exists?
|
47
|
+
cache.clear
|
48
|
+
success!("cache directory cleared")
|
49
|
+
else
|
50
|
+
failure!("cache directory doesn't exist, skipping deletion.")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
37
54
|
if !@files.empty? && lint_files.empty?
|
38
55
|
if allow_no_files?
|
39
56
|
success!("no files found...\n")
|
@@ -65,7 +82,7 @@ module ERBLint
|
|
65
82
|
lint_files.each do |filename|
|
66
83
|
runner.clear_offenses
|
67
84
|
begin
|
68
|
-
file_content =
|
85
|
+
file_content = run_on_file(runner, filename)
|
69
86
|
rescue => e
|
70
87
|
@stats.exceptions += 1
|
71
88
|
puts "Exception occurred when processing: #{relative_filename(filename)}"
|
@@ -77,6 +94,8 @@ module ERBLint
|
|
77
94
|
end
|
78
95
|
end
|
79
96
|
|
97
|
+
cache&.close
|
98
|
+
|
80
99
|
reporter.show
|
81
100
|
|
82
101
|
if stdin? && autocorrect?
|
@@ -99,13 +118,43 @@ module ERBLint
|
|
99
118
|
|
100
119
|
private
|
101
120
|
|
121
|
+
attr_reader :cache, :config
|
122
|
+
|
123
|
+
def run_on_file(runner, filename)
|
124
|
+
file_content = read_content(filename)
|
125
|
+
|
126
|
+
if cache? && !autocorrect?
|
127
|
+
run_using_cache(runner, filename, file_content)
|
128
|
+
else
|
129
|
+
file_content = run_with_corrections(runner, filename, file_content)
|
130
|
+
end
|
131
|
+
|
132
|
+
log_offense_stats(runner, filename)
|
133
|
+
file_content
|
134
|
+
end
|
135
|
+
|
136
|
+
def run_using_cache(runner, filename, file_content)
|
137
|
+
if (cache_result_offenses = cache.get(filename, file_content))
|
138
|
+
runner.restore_offenses(cache_result_offenses)
|
139
|
+
else
|
140
|
+
run_with_corrections(runner, filename, file_content)
|
141
|
+
cache.set(filename, file_content, runner.offenses.map(&:to_cached_offense_hash).to_json)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
102
145
|
def autocorrect?
|
103
146
|
@options[:autocorrect]
|
104
147
|
end
|
105
148
|
|
106
|
-
def
|
107
|
-
|
149
|
+
def cache?
|
150
|
+
@options[:cache]
|
151
|
+
end
|
108
152
|
|
153
|
+
def clear_cache?
|
154
|
+
@options[:clear_cache]
|
155
|
+
end
|
156
|
+
|
157
|
+
def run_with_corrections(runner, filename, file_content)
|
109
158
|
7.times do
|
110
159
|
processed_source = ERBLint::ProcessedSource.new(filename, file_content)
|
111
160
|
runner.run(processed_source)
|
@@ -127,6 +176,11 @@ module ERBLint
|
|
127
176
|
file_content = corrector.corrected_content
|
128
177
|
runner.clear_offenses
|
129
178
|
end
|
179
|
+
|
180
|
+
file_content
|
181
|
+
end
|
182
|
+
|
183
|
+
def log_offense_stats(runner, filename)
|
130
184
|
offenses_filename = relative_filename(filename)
|
131
185
|
offenses = runner.offenses || []
|
132
186
|
|
@@ -138,8 +192,6 @@ module ERBLint
|
|
138
192
|
|
139
193
|
@stats.processed_files[offenses_filename] ||= []
|
140
194
|
@stats.processed_files[offenses_filename] |= offenses
|
141
|
-
|
142
|
-
file_content
|
143
195
|
end
|
144
196
|
|
145
197
|
def read_content(filename)
|
@@ -266,7 +318,7 @@ module ERBLint
|
|
266
318
|
end
|
267
319
|
end
|
268
320
|
|
269
|
-
opts.on("--format FORMAT", format_options_help) do |format|
|
321
|
+
opts.on("-f", "--format FORMAT", format_options_help) do |format|
|
270
322
|
unless Reporter.available_format?(format)
|
271
323
|
error_message = invalid_format_error_message(format)
|
272
324
|
failure!(error_message)
|
@@ -283,6 +335,18 @@ module ERBLint
|
|
283
335
|
@options[:enabled_linters] = known_linter_names
|
284
336
|
end
|
285
337
|
|
338
|
+
opts.on("--cache", "Enable caching") do |config|
|
339
|
+
@options[:cache] = config
|
340
|
+
end
|
341
|
+
|
342
|
+
opts.on("--cache-dir DIR", "Set the cache directory") do |dir|
|
343
|
+
@options[:cache_dir] = dir
|
344
|
+
end
|
345
|
+
|
346
|
+
opts.on("--clear-cache", "Clear cache") do |config|
|
347
|
+
@options[:clear_cache] = config
|
348
|
+
end
|
349
|
+
|
286
350
|
opts.on("--enable-linters LINTER[,LINTER,...]", Array,
|
287
351
|
"Only use specified linter", "Known linters are: #{known_linter_names.join(", ")}") do |linters|
|
288
352
|
linters.each do |linter|
|
data/lib/erb_lint/linter.rb
CHANGED
@@ -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
|
@@ -131,11 +131,17 @@ module ERBLint
|
|
131
131
|
end
|
132
132
|
|
133
133
|
def rubocop_processed_source(content, filename)
|
134
|
-
::RuboCop::ProcessedSource.new(
|
134
|
+
source = ::RuboCop::ProcessedSource.new(
|
135
135
|
content,
|
136
136
|
@rubocop_config.target_ruby_version,
|
137
137
|
filename
|
138
138
|
)
|
139
|
+
if ::RuboCop::Version::STRING.to_f >= 1.38
|
140
|
+
registry = RuboCop::Cop::Registry.global
|
141
|
+
source.registry = registry
|
142
|
+
source.config = @rubocop_config
|
143
|
+
end
|
144
|
+
source
|
139
145
|
end
|
140
146
|
|
141
147
|
def cop_classes
|
data/lib/erb_lint/offense.rb
CHANGED
@@ -17,6 +17,10 @@ module ERBLint
|
|
17
17
|
@severity = severity
|
18
18
|
end
|
19
19
|
|
20
|
+
def to_cached_offense_hash
|
21
|
+
ERBLint::CachedOffense.new_from_offense(self).to_h
|
22
|
+
end
|
23
|
+
|
20
24
|
def inspect
|
21
25
|
"#<#{self.class.name} linter=#{linter.class.name} "\
|
22
26
|
"source_range=#{source_range.begin_pos}...#{source_range.end_pos} "\
|
@@ -43,5 +47,21 @@ module ERBLint
|
|
43
47
|
def column
|
44
48
|
source_range.column
|
45
49
|
end
|
50
|
+
|
51
|
+
def simple_name
|
52
|
+
linter.class.simple_name
|
53
|
+
end
|
54
|
+
|
55
|
+
def last_line
|
56
|
+
source_range.last_line
|
57
|
+
end
|
58
|
+
|
59
|
+
def last_column
|
60
|
+
source_range.last_column
|
61
|
+
end
|
62
|
+
|
63
|
+
def length
|
64
|
+
source_range.length
|
65
|
+
end
|
46
66
|
end
|
47
67
|
end
|
@@ -56,14 +56,14 @@ module ERBLint
|
|
56
56
|
|
57
57
|
def format_offense(offense)
|
58
58
|
{
|
59
|
-
linter: offense.
|
59
|
+
linter: offense.simple_name,
|
60
60
|
message: offense.message.to_s,
|
61
61
|
location: {
|
62
62
|
start_line: offense.line_number,
|
63
63
|
start_column: offense.column,
|
64
|
-
last_line: offense.
|
65
|
-
last_column: offense.
|
66
|
-
length: offense.
|
64
|
+
last_line: offense.last_line,
|
65
|
+
last_column: offense.last_column,
|
66
|
+
length: offense.length,
|
67
67
|
},
|
68
68
|
}
|
69
69
|
end
|
data/lib/erb_lint/runner.rb
CHANGED
data/lib/erb_lint/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: erb_lint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Chan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-11-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -147,6 +147,8 @@ files:
|
|
147
147
|
- exe/erblint
|
148
148
|
- lib/erb_lint.rb
|
149
149
|
- lib/erb_lint/all.rb
|
150
|
+
- lib/erb_lint/cache.rb
|
151
|
+
- lib/erb_lint/cached_offense.rb
|
150
152
|
- lib/erb_lint/cli.rb
|
151
153
|
- lib/erb_lint/corrector.rb
|
152
154
|
- lib/erb_lint/file_loader.rb
|
@@ -155,6 +157,7 @@ files:
|
|
155
157
|
- lib/erb_lint/linter_registry.rb
|
156
158
|
- lib/erb_lint/linters/allowed_script_type.rb
|
157
159
|
- lib/erb_lint/linters/closing_erb_tag_indent.rb
|
160
|
+
- lib/erb_lint/linters/comment_syntax.rb
|
158
161
|
- lib/erb_lint/linters/deprecated_classes.rb
|
159
162
|
- lib/erb_lint/linters/erb_safety.rb
|
160
163
|
- lib/erb_lint/linters/extra_newline.rb
|