erb_lint 0.0.31 → 0.0.36
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/lib/erb_lint.rb +9 -0
- data/lib/erb_lint/cli.rb +45 -41
- data/lib/erb_lint/corrector.rb +14 -3
- data/lib/erb_lint/file_loader.rb +8 -2
- data/lib/erb_lint/linter.rb +1 -0
- data/lib/erb_lint/linter_registry.rb +12 -3
- data/lib/erb_lint/linters/hard_coded_string.rb +1 -1
- data/lib/erb_lint/linters/no_javascript_tag_helper.rb +1 -0
- data/lib/erb_lint/linters/rubocop.rb +62 -31
- data/lib/erb_lint/linters/rubocop_text.rb +2 -2
- data/lib/erb_lint/offense.rb +8 -0
- data/lib/erb_lint/reporter.rb +38 -0
- data/lib/erb_lint/reporters/compact_reporter.rb +60 -0
- data/lib/erb_lint/reporters/multiline_reporter.rb +22 -0
- data/lib/erb_lint/runner.rb +0 -1
- data/lib/erb_lint/runner_config.rb +19 -13
- data/lib/erb_lint/stats.rb +27 -0
- data/lib/erb_lint/utils/offset_corrector.rb +18 -1
- data/lib/erb_lint/version.rb +1 -1
- metadata +41 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63f417288a7c49d68dcd0a04bbf07d4c8fc31c424cec244ddebab39ed3e5fab4
|
4
|
+
data.tar.gz: 22649a4264e1c570fe4a39e4112ea402d5ae04da3aaf7c35d3ce685c6fff7e21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0c1a2bdef25b71c750708c661aea9504551f3bcc53e7ed2017056f15d2789be58e4f758fe3735885ff4da6d43c0501f99542ce764737a8c072c24f228239155
|
7
|
+
data.tar.gz: 0653d4ec366580de6a08aff33263e9415f96ecb4bc9e579db20979f8ffb0d238cc6db9e361877ca529eef2fdf45c98233ec1ddf39cb4c01d6560a2e30fa6b489
|
data/lib/erb_lint.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'rubocop'
|
4
|
+
|
3
5
|
require 'erb_lint/corrector'
|
4
6
|
require 'erb_lint/file_loader'
|
5
7
|
require 'erb_lint/linter_config'
|
@@ -10,8 +12,15 @@ require 'erb_lint/processed_source'
|
|
10
12
|
require 'erb_lint/runner_config'
|
11
13
|
require 'erb_lint/runner'
|
12
14
|
require 'erb_lint/version'
|
15
|
+
require 'erb_lint/stats'
|
16
|
+
require 'erb_lint/reporter'
|
13
17
|
|
14
18
|
# Load linters
|
15
19
|
Dir[File.expand_path('erb_lint/linters/**/*.rb', File.dirname(__FILE__))].each do |file|
|
16
20
|
require file
|
17
21
|
end
|
22
|
+
|
23
|
+
# Load reporters
|
24
|
+
Dir[File.expand_path('erb_lint/reporters/**/*.rb', File.dirname(__FILE__))].each do |file|
|
25
|
+
require file
|
26
|
+
end
|
data/lib/erb_lint/cli.rb
CHANGED
@@ -14,16 +14,8 @@ module ERBLint
|
|
14
14
|
DEFAULT_LINT_ALL_GLOB = "**/*.html{+*,}.erb"
|
15
15
|
|
16
16
|
class ExitWithFailure < RuntimeError; end
|
17
|
-
class ExitWithSuccess < RuntimeError; end
|
18
17
|
|
19
|
-
class
|
20
|
-
attr_accessor :found, :corrected, :exceptions
|
21
|
-
def initialize
|
22
|
-
@found = 0
|
23
|
-
@corrected = 0
|
24
|
-
@exceptions = 0
|
25
|
-
end
|
26
|
-
end
|
18
|
+
class ExitWithSuccess < RuntimeError; end
|
27
19
|
|
28
20
|
def initialize
|
29
21
|
@options = {}
|
@@ -33,8 +25,9 @@ module ERBLint
|
|
33
25
|
end
|
34
26
|
|
35
27
|
def run(args = ARGV)
|
36
|
-
|
37
|
-
|
28
|
+
dupped_args = args.dup
|
29
|
+
load_options(dupped_args)
|
30
|
+
@files = dupped_args
|
38
31
|
|
39
32
|
load_config
|
40
33
|
|
@@ -50,9 +43,12 @@ module ERBLint
|
|
50
43
|
failure!('no linter available with current configuration')
|
51
44
|
end
|
52
45
|
|
53
|
-
|
54
|
-
|
55
|
-
|
46
|
+
@options[:format] ||= :multiline
|
47
|
+
@stats.files = lint_files.size
|
48
|
+
@stats.linters = enabled_linter_classes.size
|
49
|
+
|
50
|
+
reporter = Reporter.create_reporter(@options[:format], @stats, autocorrect?)
|
51
|
+
reporter.preview
|
56
52
|
|
57
53
|
runner = ERBLint::Runner.new(file_loader, @config)
|
58
54
|
|
@@ -71,20 +67,7 @@ module ERBLint
|
|
71
67
|
end
|
72
68
|
end
|
73
69
|
|
74
|
-
|
75
|
-
corrected_found_diff = @stats.found - @stats.corrected
|
76
|
-
if corrected_found_diff > 0
|
77
|
-
warn(Rainbow(
|
78
|
-
"#{@stats.corrected} error(s) corrected and #{corrected_found_diff} error(s) remaining in ERB files"
|
79
|
-
).red)
|
80
|
-
else
|
81
|
-
puts Rainbow("#{@stats.corrected} error(s) corrected in ERB files").green
|
82
|
-
end
|
83
|
-
elsif @stats.found > 0
|
84
|
-
warn(Rainbow("#{@stats.found} error(s) were found in ERB files").red)
|
85
|
-
else
|
86
|
-
puts Rainbow("No errors were found in ERB files").green
|
87
|
-
end
|
70
|
+
reporter.show
|
88
71
|
|
89
72
|
@stats.found == 0 && @stats.exceptions == 0
|
90
73
|
rescue OptionParser::InvalidOption, OptionParser::InvalidArgument, ExitWithFailure => e
|
@@ -125,15 +108,12 @@ module ERBLint
|
|
125
108
|
file_content = corrector.corrected_content
|
126
109
|
runner.clear_offenses
|
127
110
|
end
|
111
|
+
offenses_filename = relative_filename(filename)
|
112
|
+
offenses = runner.offenses || []
|
128
113
|
|
129
|
-
@stats.found +=
|
130
|
-
|
131
|
-
|
132
|
-
#{offense.message}#{Rainbow(' (not autocorrected)').red if autocorrect?}
|
133
|
-
In file: #{relative_filename(filename)}:#{offense.line_range.begin}
|
134
|
-
|
135
|
-
EOF
|
136
|
-
end
|
114
|
+
@stats.found += offenses.size
|
115
|
+
@stats.processed_files[offenses_filename] ||= []
|
116
|
+
@stats.processed_files[offenses_filename] |= offenses
|
137
117
|
end
|
138
118
|
|
139
119
|
def correct(processed_source, offenses)
|
@@ -149,14 +129,15 @@ module ERBLint
|
|
149
129
|
def load_config
|
150
130
|
if File.exist?(config_filename)
|
151
131
|
config = RunnerConfig.new(file_loader.yaml(config_filename), file_loader)
|
152
|
-
@config = RunnerConfig.
|
132
|
+
@config = RunnerConfig.default_for(config)
|
153
133
|
else
|
154
134
|
warn(Rainbow("#{config_filename} not found: using default config").yellow)
|
155
135
|
@config = RunnerConfig.default
|
156
136
|
end
|
157
|
-
@config.merge!(runner_config_override)
|
158
137
|
rescue Psych::SyntaxError => e
|
159
138
|
failure!("error parsing config: #{e.message}")
|
139
|
+
ensure
|
140
|
+
@config.merge!(runner_config_override)
|
160
141
|
end
|
161
142
|
|
162
143
|
def file_loader
|
@@ -170,11 +151,11 @@ module ERBLint
|
|
170
151
|
def lint_files
|
171
152
|
@lint_files ||=
|
172
153
|
if @options[:lint_all]
|
173
|
-
pattern = File.expand_path(
|
154
|
+
pattern = File.expand_path(glob, Dir.pwd)
|
174
155
|
Dir[pattern].select { |filename| !excluded?(filename) }
|
175
156
|
else
|
176
157
|
@files
|
177
|
-
.map { |f| Dir.exist?(f) ? Dir[File.join(f,
|
158
|
+
.map { |f| Dir.exist?(f) ? Dir[File.join(f, glob)] : f }
|
178
159
|
.map { |f| f.include?('*') ? Dir[f] : f }
|
179
160
|
.flatten
|
180
161
|
.map { |f| File.expand_path(f, Dir.pwd) }
|
@@ -182,6 +163,10 @@ module ERBLint
|
|
182
163
|
end
|
183
164
|
end
|
184
165
|
|
166
|
+
def glob
|
167
|
+
@config.to_hash["glob"] || DEFAULT_LINT_ALL_GLOB
|
168
|
+
end
|
169
|
+
|
185
170
|
def excluded?(filename)
|
186
171
|
@config.global_exclude.any? do |path|
|
187
172
|
File.fnmatch?(path, filename)
|
@@ -252,7 +237,16 @@ module ERBLint
|
|
252
237
|
end
|
253
238
|
end
|
254
239
|
|
255
|
-
opts.on("--
|
240
|
+
opts.on("--format FORMAT", format_options_help) do |format|
|
241
|
+
unless Reporter.available_format?(format)
|
242
|
+
error_message = invalid_format_error_message(format)
|
243
|
+
failure!(error_message)
|
244
|
+
end
|
245
|
+
|
246
|
+
@options[:format] = format
|
247
|
+
end
|
248
|
+
|
249
|
+
opts.on("--lint-all", "Lint all files matching configured glob [default: #{DEFAULT_LINT_ALL_GLOB}]") do |config|
|
256
250
|
@options[:lint_all] = config
|
257
251
|
end
|
258
252
|
|
@@ -283,5 +277,15 @@ module ERBLint
|
|
283
277
|
end
|
284
278
|
end
|
285
279
|
end
|
280
|
+
|
281
|
+
def format_options_help
|
282
|
+
"Report offenses in the given format: "\
|
283
|
+
"(#{Reporter.available_formats.join(', ')}) (default: multiline)"
|
284
|
+
end
|
285
|
+
|
286
|
+
def invalid_format_error_message(given_format)
|
287
|
+
formats = Reporter.available_formats.map { |format| " - #{format}\n" }
|
288
|
+
"#{given_format}: is not a valid format. Available formats:\n#{formats.join}"
|
289
|
+
end
|
286
290
|
end
|
287
291
|
end
|
data/lib/erb_lint/corrector.rb
CHANGED
@@ -17,11 +17,22 @@ module ERBLint
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def corrector
|
20
|
-
|
20
|
+
BASE.new(@processed_source.source_buffer, corrections)
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
corrector
|
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
|
35
|
+
end
|
25
36
|
end
|
26
37
|
end
|
27
38
|
end
|
data/lib/erb_lint/file_loader.rb
CHANGED
@@ -9,8 +9,14 @@ module ERBLint
|
|
9
9
|
@base_path = base_path
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
if RUBY_VERSION >= "2.6"
|
13
|
+
def yaml(filename)
|
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
|
14
20
|
end
|
15
21
|
|
16
22
|
private
|
data/lib/erb_lint/linter.rb
CHANGED
@@ -14,6 +14,7 @@ module ERBLint
|
|
14
14
|
# `ERBLint::Linters::Foo.simple_name` #=> "Foo"
|
15
15
|
# `ERBLint::Linters::Compass::Bar.simple_name` #=> "Compass::Bar"
|
16
16
|
def inherited(linter)
|
17
|
+
super
|
17
18
|
linter.simple_name = if linter.name.start_with?('ERBLint::Linters::')
|
18
19
|
name_parts = linter.name.split('::')
|
19
20
|
name_parts[2..-1].join('::')
|
@@ -4,19 +4,28 @@ module ERBLint
|
|
4
4
|
# Stores all linters available to the application.
|
5
5
|
module LinterRegistry
|
6
6
|
CUSTOM_LINTERS_DIR = '.erb-linters'
|
7
|
-
@
|
7
|
+
@loaded_linters = []
|
8
8
|
|
9
9
|
class << self
|
10
|
-
|
10
|
+
def clear
|
11
|
+
@linters = nil
|
12
|
+
end
|
11
13
|
|
12
14
|
def included(linter_class)
|
13
|
-
@
|
15
|
+
@loaded_linters << linter_class
|
14
16
|
end
|
15
17
|
|
16
18
|
def find_by_name(name)
|
17
19
|
linters.detect { |linter| linter.simple_name == name }
|
18
20
|
end
|
19
21
|
|
22
|
+
def linters
|
23
|
+
@linters ||= begin
|
24
|
+
load_custom_linters
|
25
|
+
@loaded_linters
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
20
29
|
def load_custom_linters(directory = CUSTOM_LINTERS_DIR)
|
21
30
|
ruby_files = Dir.glob(File.expand_path(File.join(directory, '**', '*.rb')))
|
22
31
|
ruby_files.each { |file| require file }
|
@@ -63,7 +63,7 @@ module ERBLint
|
|
63
63
|
string = offense.source_range.source
|
64
64
|
return unless (klass = load_corrector)
|
65
65
|
return unless string.strip.length > 1
|
66
|
-
node = RuboCop::AST::StrNode.new(:str, [string])
|
66
|
+
node = ::RuboCop::AST::StrNode.new(:str, [string])
|
67
67
|
corrector = klass.new(node, processed_source.filename, corrector_i18n_load_path, offense.source_range)
|
68
68
|
corrector.autocorrect(tag_start: '<%= ', tag_end: ' %>')
|
69
69
|
rescue MissingCorrector, MissingI18nLoadPath
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'better_html'
|
4
|
-
require 'rubocop'
|
5
4
|
require 'tempfile'
|
6
5
|
require 'erb_lint/utils/offset_corrector'
|
7
6
|
|
@@ -26,7 +25,7 @@ module ERBLint
|
|
26
25
|
super
|
27
26
|
@only_cops = @config.only
|
28
27
|
custom_config = config_from_hash(@config.rubocop_config)
|
29
|
-
@rubocop_config = RuboCop::ConfigLoader.merge_with_default(custom_config, '')
|
28
|
+
@rubocop_config = ::RuboCop::ConfigLoader.merge_with_default(custom_config, '')
|
30
29
|
end
|
31
30
|
|
32
31
|
def run(processed_source)
|
@@ -35,17 +34,29 @@ module ERBLint
|
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
offense.context[:offset]
|
46
|
-
|
47
|
-
|
48
|
-
|
37
|
+
if ::RuboCop::Version::STRING.to_f >= 0.87
|
38
|
+
def autocorrect(_processed_source, offense)
|
39
|
+
return unless offense.context
|
40
|
+
rubocop_correction = offense.context[:rubocop_correction]
|
41
|
+
return unless rubocop_correction
|
42
|
+
|
43
|
+
lambda do |corrector|
|
44
|
+
corrector.import!(rubocop_correction, offset: offense.context[:offset])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
else
|
48
|
+
def autocorrect(processed_source, offense)
|
49
|
+
return unless offense.context
|
50
|
+
|
51
|
+
lambda do |corrector|
|
52
|
+
passthrough = Utils::OffsetCorrector.new(
|
53
|
+
processed_source,
|
54
|
+
corrector,
|
55
|
+
offense.context[:offset],
|
56
|
+
offense.context[:bound_range],
|
57
|
+
)
|
58
|
+
offense.context[:rubocop_correction].call(passthrough)
|
59
|
+
end
|
49
60
|
end
|
50
61
|
end
|
51
62
|
|
@@ -62,22 +73,23 @@ module ERBLint
|
|
62
73
|
original_source = code_node.loc.source
|
63
74
|
trimmed_source = original_source.sub(BLOCK_EXPR, '').sub(SUFFIX_EXPR, '')
|
64
75
|
alignment_column = code_node.loc.column
|
76
|
+
offset = code_node.loc.begin_pos - alignment_column
|
65
77
|
aligned_source = "#{' ' * alignment_column}#{trimmed_source}"
|
66
78
|
|
67
79
|
source = rubocop_processed_source(aligned_source, processed_source.filename)
|
68
80
|
return unless source.valid_syntax?
|
69
81
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
82
|
+
activate_team(processed_source, source, offset, code_node, build_team)
|
83
|
+
end
|
84
|
+
|
85
|
+
if ::RuboCop::Version::STRING.to_f >= 0.87
|
86
|
+
def activate_team(processed_source, source, offset, code_node, team)
|
87
|
+
report = team.investigate(source)
|
88
|
+
report.offenses.each do |rubocop_offense|
|
89
|
+
next if rubocop_offense.disabled?
|
90
|
+
|
91
|
+
correction = rubocop_offense.corrector if rubocop_offense.corrected?
|
79
92
|
|
80
|
-
offset = code_node.loc.begin_pos - alignment_column
|
81
93
|
offense_range = processed_source
|
82
94
|
.to_source_range(rubocop_offense.location)
|
83
95
|
.offset(offset)
|
@@ -85,6 +97,25 @@ module ERBLint
|
|
85
97
|
add_offense(rubocop_offense, offense_range, correction, offset, code_node.loc.range)
|
86
98
|
end
|
87
99
|
end
|
100
|
+
else
|
101
|
+
def activate_team(processed_source, source, offset, code_node, team)
|
102
|
+
team.inspect_file(source)
|
103
|
+
team.cops.each do |cop|
|
104
|
+
correction_offset = 0
|
105
|
+
cop.offenses.reject(&:disabled?).each do |rubocop_offense|
|
106
|
+
if rubocop_offense.corrected?
|
107
|
+
correction = cop.corrections[correction_offset]
|
108
|
+
correction_offset += 1
|
109
|
+
end
|
110
|
+
|
111
|
+
offense_range = processed_source
|
112
|
+
.to_source_range(rubocop_offense.location)
|
113
|
+
.offset(offset)
|
114
|
+
|
115
|
+
add_offense(rubocop_offense, offense_range, correction, offset, code_node.loc.range)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
88
119
|
end
|
89
120
|
|
90
121
|
def tempfile_from(filename, content)
|
@@ -97,7 +128,7 @@ module ERBLint
|
|
97
128
|
end
|
98
129
|
|
99
130
|
def rubocop_processed_source(content, filename)
|
100
|
-
RuboCop::ProcessedSource.new(
|
131
|
+
::RuboCop::ProcessedSource.new(
|
101
132
|
content,
|
102
133
|
@rubocop_config.target_ruby_version,
|
103
134
|
filename
|
@@ -106,15 +137,15 @@ module ERBLint
|
|
106
137
|
|
107
138
|
def cop_classes
|
108
139
|
if @only_cops.present?
|
109
|
-
selected_cops = RuboCop::Cop::Cop.all.select { |cop| cop.match?(@only_cops) }
|
110
|
-
RuboCop::Cop::Registry.new(selected_cops)
|
140
|
+
selected_cops = ::RuboCop::Cop::Cop.all.select { |cop| cop.match?(@only_cops) }
|
141
|
+
::RuboCop::Cop::Registry.new(selected_cops)
|
111
142
|
else
|
112
|
-
RuboCop::Cop::Registry.new(RuboCop::Cop::Cop.all)
|
143
|
+
::RuboCop::Cop::Registry.new(::RuboCop::Cop::Cop.all)
|
113
144
|
end
|
114
145
|
end
|
115
146
|
|
116
147
|
def build_team
|
117
|
-
RuboCop::Cop::Team.new(
|
148
|
+
::RuboCop::Cop::Team.new(
|
118
149
|
cop_classes,
|
119
150
|
@rubocop_config,
|
120
151
|
extra_details: true,
|
@@ -129,7 +160,7 @@ module ERBLint
|
|
129
160
|
resolve_inheritance(hash, inherit_from)
|
130
161
|
|
131
162
|
tempfile_from('.erblint-rubocop', hash.to_yaml) do |tempfile|
|
132
|
-
RuboCop::ConfigLoader.load_file(tempfile.path)
|
163
|
+
::RuboCop::ConfigLoader.load_file(tempfile.path)
|
133
164
|
end
|
134
165
|
end
|
135
166
|
|
@@ -137,7 +168,7 @@ module ERBLint
|
|
137
168
|
base_configs(inherit_from)
|
138
169
|
.reverse_each do |base_config|
|
139
170
|
base_config.each do |k, v|
|
140
|
-
hash[k] = hash.key?(k) ? RuboCop::ConfigLoader.merge(v, hash[k]) : v if v.is_a?(Hash)
|
171
|
+
hash[k] = hash.key?(k) ? ::RuboCop::ConfigLoader.merge(v, hash[k]) : v if v.is_a?(Hash)
|
141
172
|
end
|
142
173
|
end
|
143
174
|
end
|
@@ -146,7 +177,7 @@ module ERBLint
|
|
146
177
|
regex = URI::DEFAULT_PARSER.make_regexp(%w(http https))
|
147
178
|
configs = Array(inherit_from).compact.map do |base_name|
|
148
179
|
if base_name =~ /\A#{regex}\z/
|
149
|
-
RuboCop::ConfigLoader.load_file(RuboCop::RemoteConfig.new(base_name, Dir.pwd))
|
180
|
+
::RuboCop::ConfigLoader.load_file(::RuboCop::RemoteConfig.new(base_name, Dir.pwd))
|
150
181
|
else
|
151
182
|
config_from_hash(@file_loader.yaml(base_name))
|
152
183
|
end
|
@@ -28,9 +28,9 @@ module ERBLint
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def cop_classes
|
31
|
-
selected_cops = RuboCop::Cop::Cop.all.select { |cop| cop.match?(@only_cops) }
|
31
|
+
selected_cops = ::RuboCop::Cop::Cop.all.select { |cop| cop.match?(@only_cops) }
|
32
32
|
|
33
|
-
RuboCop::Cop::Registry.new(selected_cops)
|
33
|
+
::RuboCop::Cop::Registry.new(selected_cops)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
data/lib/erb_lint/offense.rb
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/core_ext/class'
|
3
|
+
|
4
|
+
module ERBLint
|
5
|
+
class Reporter
|
6
|
+
def self.create_reporter(format, *args)
|
7
|
+
reporter_klass = "#{ERBLint::Reporters}::#{format.to_s.camelize}Reporter".constantize
|
8
|
+
reporter_klass.new(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.available_format?(format)
|
12
|
+
available_formats.include?(format.to_s)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.available_formats
|
16
|
+
descendants
|
17
|
+
.map(&:to_s)
|
18
|
+
.map(&:demodulize)
|
19
|
+
.map(&:underscore)
|
20
|
+
.map { |klass_name| klass_name.sub("_reporter", "") }
|
21
|
+
.sort
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(stats, autocorrect)
|
25
|
+
@stats = stats
|
26
|
+
@autocorrect = autocorrect
|
27
|
+
end
|
28
|
+
|
29
|
+
def preview; end
|
30
|
+
|
31
|
+
def show; end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_reader :stats, :autocorrect
|
36
|
+
delegate :processed_files, to: :stats
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ERBLint
|
4
|
+
module Reporters
|
5
|
+
class CompactReporter < Reporter
|
6
|
+
def preview
|
7
|
+
puts "Linting #{stats.files} files with "\
|
8
|
+
"#{stats.linters} #{'autocorrectable ' if autocorrect}linters..."
|
9
|
+
end
|
10
|
+
|
11
|
+
def show
|
12
|
+
processed_files.each do |filename, offenses|
|
13
|
+
offenses.each do |offense|
|
14
|
+
puts format_offense(filename, offense)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
footer
|
19
|
+
summary
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def format_offense(filename, offense)
|
25
|
+
[
|
26
|
+
"#{filename}:",
|
27
|
+
"#{offense.line_number}:",
|
28
|
+
"#{offense.column}: ",
|
29
|
+
offense.message.to_s,
|
30
|
+
].join
|
31
|
+
end
|
32
|
+
|
33
|
+
def footer; end
|
34
|
+
|
35
|
+
def summary
|
36
|
+
if stats.corrected > 0
|
37
|
+
report_corrected_offenses
|
38
|
+
elsif stats.found > 0
|
39
|
+
warn(Rainbow("#{stats.found} error(s) were found in ERB files").red)
|
40
|
+
else
|
41
|
+
puts Rainbow("No errors were found in ERB files").green
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def report_corrected_offenses
|
46
|
+
corrected_found_diff = stats.found - stats.corrected
|
47
|
+
|
48
|
+
if corrected_found_diff > 0
|
49
|
+
message = Rainbow(
|
50
|
+
"#{stats.corrected} error(s) corrected and #{corrected_found_diff} error(s) remaining in ERB files"
|
51
|
+
).red
|
52
|
+
|
53
|
+
warn(message)
|
54
|
+
else
|
55
|
+
puts Rainbow("#{stats.corrected} error(s) corrected in ERB files").green
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "compact_reporter"
|
3
|
+
|
4
|
+
module ERBLint
|
5
|
+
module Reporters
|
6
|
+
class MultilineReporter < CompactReporter
|
7
|
+
private
|
8
|
+
|
9
|
+
def format_offense(filename, offense)
|
10
|
+
<<~EOF
|
11
|
+
|
12
|
+
#{offense.message}#{Rainbow(' (not autocorrected)').red if autocorrect}
|
13
|
+
In file: #{filename}:#{offense.line_number}
|
14
|
+
EOF
|
15
|
+
end
|
16
|
+
|
17
|
+
def footer
|
18
|
+
puts
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/erb_lint/runner.rb
CHANGED
@@ -10,7 +10,6 @@ module ERBLint
|
|
10
10
|
@config = config || RunnerConfig.default
|
11
11
|
raise ArgumentError, 'expect `config` to be a RunnerConfig instance' unless @config.is_a?(RunnerConfig)
|
12
12
|
|
13
|
-
LinterRegistry.load_custom_linters
|
14
13
|
linter_classes = LinterRegistry.linters.select { |klass| @config.for_linter(klass).enabled? }
|
15
14
|
@linters = linter_classes.map do |linter_class|
|
16
15
|
linter_class.new(@file_loader, @config.for_linter(linter_class))
|
@@ -45,24 +45,30 @@ module ERBLint
|
|
45
45
|
end
|
46
46
|
|
47
47
|
class << self
|
48
|
-
def default
|
48
|
+
def default(default_enabled: nil)
|
49
|
+
default_enabled = default_enabled.nil? ? true : default_enabled
|
49
50
|
new(
|
50
51
|
linters: {
|
51
|
-
AllowedScriptType: { enabled:
|
52
|
-
ClosingErbTagIndent: { enabled:
|
53
|
-
ExtraNewline: { enabled:
|
54
|
-
FinalNewline: { enabled:
|
55
|
-
NoJavascriptTagHelper: { enabled:
|
56
|
-
ParserErrors: { enabled:
|
57
|
-
RightTrim: { enabled:
|
58
|
-
SelfClosingTag: { enabled:
|
59
|
-
SpaceAroundErbTag: { enabled:
|
60
|
-
SpaceIndentation: { enabled:
|
61
|
-
SpaceInHtmlTag: { enabled:
|
62
|
-
TrailingWhitespace: { enabled:
|
52
|
+
AllowedScriptType: { enabled: default_enabled },
|
53
|
+
ClosingErbTagIndent: { enabled: default_enabled },
|
54
|
+
ExtraNewline: { enabled: default_enabled },
|
55
|
+
FinalNewline: { enabled: default_enabled },
|
56
|
+
NoJavascriptTagHelper: { enabled: default_enabled },
|
57
|
+
ParserErrors: { enabled: default_enabled },
|
58
|
+
RightTrim: { enabled: default_enabled },
|
59
|
+
SelfClosingTag: { enabled: default_enabled },
|
60
|
+
SpaceAroundErbTag: { enabled: default_enabled },
|
61
|
+
SpaceIndentation: { enabled: default_enabled },
|
62
|
+
SpaceInHtmlTag: { enabled: default_enabled },
|
63
|
+
TrailingWhitespace: { enabled: default_enabled },
|
63
64
|
},
|
64
65
|
)
|
65
66
|
end
|
67
|
+
|
68
|
+
def default_for(config)
|
69
|
+
default_linters_enabled = config.to_hash.dig("EnableDefaultLinters")
|
70
|
+
default(default_enabled: default_linters_enabled).merge(config)
|
71
|
+
end
|
66
72
|
end
|
67
73
|
|
68
74
|
private
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ERBLint
|
3
|
+
class Stats
|
4
|
+
attr_accessor :found,
|
5
|
+
:corrected,
|
6
|
+
:exceptions,
|
7
|
+
:linters,
|
8
|
+
:files,
|
9
|
+
:processed_files
|
10
|
+
|
11
|
+
def initialize(
|
12
|
+
found: 0,
|
13
|
+
corrected: 0,
|
14
|
+
exceptions: 0,
|
15
|
+
linters: 0,
|
16
|
+
files: 0,
|
17
|
+
processed_files: {}
|
18
|
+
)
|
19
|
+
@found = found
|
20
|
+
@corrected = corrected
|
21
|
+
@exceptions = exceptions
|
22
|
+
@linters = linters
|
23
|
+
@files = files
|
24
|
+
@processed_files = processed_files
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -38,7 +38,9 @@ module ERBLint
|
|
38
38
|
@corrector.remove_trailing(range_with_offset(range), size)
|
39
39
|
end
|
40
40
|
|
41
|
-
def range_with_offset(
|
41
|
+
def range_with_offset(node_or_range)
|
42
|
+
range = to_range(node_or_range)
|
43
|
+
|
42
44
|
@processed_source.to_source_range(
|
43
45
|
bound(@offset + range.begin_pos)..bound(@offset + (range.end_pos - 1))
|
44
46
|
)
|
@@ -50,6 +52,21 @@ module ERBLint
|
|
50
52
|
@bound_range.max,
|
51
53
|
].min
|
52
54
|
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def to_range(node_or_range)
|
59
|
+
case node_or_range
|
60
|
+
when ::RuboCop::AST::Node, ::Parser::Source::Comment
|
61
|
+
node_or_range.loc.expression
|
62
|
+
when ::Parser::Source::Range
|
63
|
+
node_or_range
|
64
|
+
else
|
65
|
+
raise TypeError,
|
66
|
+
'Expected a Parser::Source::Range, Comment or ' \
|
67
|
+
"Rubocop::AST::Node, got #{node_or_range.class}"
|
68
|
+
end
|
69
|
+
end
|
53
70
|
end
|
54
71
|
end
|
55
72
|
end
|
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.0.
|
4
|
+
version: 0.0.36
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Chan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: better_html
|
@@ -42,16 +42,30 @@ dependencies:
|
|
42
42
|
name: rubocop
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0
|
47
|
+
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: parser
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.7.1.4
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
68
|
+
version: 2.7.1.4
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: activesupport
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,6 +136,20 @@ dependencies:
|
|
122
136
|
- - ">="
|
123
137
|
- !ruby/object:Gem::Version
|
124
138
|
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop-shopify
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
125
153
|
description: ERB Linter tool.
|
126
154
|
email:
|
127
155
|
- justin.the.c@gmail.com
|
@@ -157,9 +185,13 @@ files:
|
|
157
185
|
- lib/erb_lint/linters/trailing_whitespace.rb
|
158
186
|
- lib/erb_lint/offense.rb
|
159
187
|
- lib/erb_lint/processed_source.rb
|
188
|
+
- lib/erb_lint/reporter.rb
|
189
|
+
- lib/erb_lint/reporters/compact_reporter.rb
|
190
|
+
- lib/erb_lint/reporters/multiline_reporter.rb
|
160
191
|
- lib/erb_lint/runner.rb
|
161
192
|
- lib/erb_lint/runner_config.rb
|
162
193
|
- lib/erb_lint/runner_config_resolver.rb
|
194
|
+
- lib/erb_lint/stats.rb
|
163
195
|
- lib/erb_lint/utils/block_map.rb
|
164
196
|
- lib/erb_lint/utils/offset_corrector.rb
|
165
197
|
- lib/erb_lint/utils/ruby_to_erb.rb
|
@@ -167,7 +199,8 @@ files:
|
|
167
199
|
homepage: https://github.com/Shopify/erb-lint
|
168
200
|
licenses:
|
169
201
|
- MIT
|
170
|
-
metadata:
|
202
|
+
metadata:
|
203
|
+
allowed_push_host: https://rubygems.org
|
171
204
|
post_install_message:
|
172
205
|
rdoc_options: []
|
173
206
|
require_paths:
|
@@ -176,7 +209,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
176
209
|
requirements:
|
177
210
|
- - ">="
|
178
211
|
- !ruby/object:Gem::Version
|
179
|
-
version: 2.
|
212
|
+
version: 2.5.0
|
180
213
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
181
214
|
requirements:
|
182
215
|
- - ">="
|