slim_lint 0.35.0 → 0.37.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/lib/slim_lint/corrector.rb +66 -0
- data/lib/slim_lint/document.rb +9 -2
- data/lib/slim_lint/lint.rb +33 -6
- data/lib/slim_lint/linter/comment_control_statement.rb +5 -1
- data/lib/slim_lint/linter/control_statement_spacing.rb +11 -2
- data/lib/slim_lint/linter/empty_control_statement.rb +3 -1
- data/lib/slim_lint/linter/empty_lines.rb +3 -1
- data/lib/slim_lint/linter/quote_consistency.rb +30 -2
- data/lib/slim_lint/linter/redundant_div.rb +3 -1
- data/lib/slim_lint/linter/tag_case.rb +5 -1
- data/lib/slim_lint/linter/trailing_blank_lines.rb +5 -2
- data/lib/slim_lint/linter/trailing_whitespace.rb +3 -1
- data/lib/slim_lint/linter/zwsp.rb +3 -1
- data/lib/slim_lint/linter.rb +22 -2
- data/lib/slim_lint/options.rb +15 -3
- data/lib/slim_lint/report.rb +1 -1
- data/lib/slim_lint/reporter/default_reporter.rb +2 -1
- data/lib/slim_lint/runner.rb +22 -3
- data/lib/slim_lint/version.rb +1 -1
- data/lib/slim_lint.rb +1 -0
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1ab51b789afce474d3a969052cf00dc0760a2d98706aa74d2d5f2daf2c58ad44
|
|
4
|
+
data.tar.gz: ad86883e7bb179a3f7f7c01c2aad5e07d57c359f790ca3541d3da78f3af17516
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7223d666bd6ae4e0c266431a5ab8edd34a89a7862ca6a7b7aca9f7171fcea57016a622ea95794372f11579ad62136e97279d54988f4c5e70f7bc3305f71c916e
|
|
7
|
+
data.tar.gz: 5de9a96b2055eeeae3f5af80053bf0af37f85d7821c874de7584da6a8a0837811dfe84aca1461c1b7c27c541bef306d08adb73d516a7efb3400790858b1b6d17
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SlimLint
|
|
4
|
+
# Applies the corrections attached to a set of lints to a document's
|
|
5
|
+
# source, producing the corrected source text.
|
|
6
|
+
class Corrector
|
|
7
|
+
# @param document [SlimLint::Document] document the lints were reported against
|
|
8
|
+
def initialize(document)
|
|
9
|
+
@document = document
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Applies every correctable lint's correction to the document's source
|
|
13
|
+
# and marks each applied lint as corrected.
|
|
14
|
+
#
|
|
15
|
+
# A correction maps the current text of its line to the corrected text:
|
|
16
|
+
# returning `nil` removes the line entirely, and returning a string
|
|
17
|
+
# containing embedded newlines replaces the line with multiple lines.
|
|
18
|
+
# Corrections are applied from the last line to the first so that a
|
|
19
|
+
# correction which adds or removes lines never invalidates the line
|
|
20
|
+
# numbers of corrections still waiting to be applied.
|
|
21
|
+
#
|
|
22
|
+
# @param lints [Array<SlimLint::Lint>]
|
|
23
|
+
# @return [String] the corrected source
|
|
24
|
+
def correct(lints)
|
|
25
|
+
# `-1` keeps a trailing empty element when the source ends with a
|
|
26
|
+
# newline, so the array can be joined back with "\n" to exactly
|
|
27
|
+
# reproduce the source (including its trailing newline, or lack of one).
|
|
28
|
+
lines = @document.source.split("\n", -1)
|
|
29
|
+
|
|
30
|
+
correction_groups(lints).each do |line_number, line_lints|
|
|
31
|
+
index = line_number - 1
|
|
32
|
+
next unless index.between?(0, lines.length - 1)
|
|
33
|
+
|
|
34
|
+
lines[index, 1] = apply_corrections(lines[index], line_lints)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
@document.source_prefix + lines.join("\n")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
# Groups correctable lints by line number, ordered from the last line to
|
|
43
|
+
# the first, so that a correction which adds or removes lines never
|
|
44
|
+
# invalidates the line numbers of corrections still waiting to be applied.
|
|
45
|
+
#
|
|
46
|
+
# @param lints [Array<SlimLint::Lint>]
|
|
47
|
+
# @return [Array<(Integer, Array<SlimLint::Lint>)>]
|
|
48
|
+
def correction_groups(lints)
|
|
49
|
+
lints.select(&:correctable?).group_by(&:line).sort_by { |line_number, _| -line_number }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @param line [String] current text of the line
|
|
53
|
+
# @param line_lints [Array<SlimLint::Lint>] lints reported on this line
|
|
54
|
+
# @return [Array<String>] replacement line(s) for this line, possibly empty
|
|
55
|
+
def apply_corrections(line, line_lints)
|
|
56
|
+
line_lints.each do |lint|
|
|
57
|
+
break if line.nil?
|
|
58
|
+
|
|
59
|
+
line = lint.correction.call(line)
|
|
60
|
+
lint.corrected = true
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
line.nil? ? [] : line.split("\n", -1)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
data/lib/slim_lint/document.rb
CHANGED
|
@@ -15,6 +15,12 @@ module SlimLint
|
|
|
15
15
|
# @return [String] original source code
|
|
16
16
|
attr_reader :source
|
|
17
17
|
|
|
18
|
+
# @return [String] source code before optional frontmatter removal
|
|
19
|
+
attr_reader :original_source
|
|
20
|
+
|
|
21
|
+
# @return [String] source removed before linting, such as frontmatter
|
|
22
|
+
attr_reader :source_prefix
|
|
23
|
+
|
|
18
24
|
# @return [Array<String>] original source code as an array of lines
|
|
19
25
|
attr_reader :source_lines
|
|
20
26
|
|
|
@@ -36,8 +42,9 @@ module SlimLint
|
|
|
36
42
|
# @param source [String] Slim code to parse
|
|
37
43
|
# @raise [SlimLint::Exceptions::ParseError] if there was a problem parsing the document
|
|
38
44
|
def process_source(source)
|
|
39
|
-
@
|
|
40
|
-
@source = strip_frontmatter(
|
|
45
|
+
@original_source = process_encoding(source)
|
|
46
|
+
@source = strip_frontmatter(@original_source)
|
|
47
|
+
@source_prefix = @original_source[0, @original_source.length - @source.length] || ''
|
|
41
48
|
@source_lines = @source.split("\n")
|
|
42
49
|
|
|
43
50
|
engine = SlimLint::Engine.new(file: @file)
|
data/lib/slim_lint/lint.rb
CHANGED
|
@@ -18,6 +18,15 @@ module SlimLint
|
|
|
18
18
|
# @return [Symbol] whether this lint is a warning or an error
|
|
19
19
|
attr_reader :severity
|
|
20
20
|
|
|
21
|
+
# @return [Proc, nil] maps a line of source to its corrected version
|
|
22
|
+
# (`nil` to remove the line, or a string with embedded newlines to
|
|
23
|
+
# replace it with multiple lines), or `nil` if this lint has no known
|
|
24
|
+
# automatic correction
|
|
25
|
+
attr_reader :correction
|
|
26
|
+
|
|
27
|
+
# @return [Boolean] whether this lint's correction has been applied
|
|
28
|
+
attr_accessor :corrected
|
|
29
|
+
|
|
21
30
|
# Creates a new lint.
|
|
22
31
|
#
|
|
23
32
|
# @param linter [SlimLint::Linter]
|
|
@@ -25,12 +34,16 @@ module SlimLint
|
|
|
25
34
|
# @param line [Fixnum]
|
|
26
35
|
# @param message [String]
|
|
27
36
|
# @param severity [Symbol]
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@
|
|
32
|
-
@
|
|
33
|
-
@
|
|
37
|
+
# @param correction [Proc, nil] maps a line of source to its corrected version
|
|
38
|
+
def initialize(linter, filename, line, message, severity = :warning, # rubocop:disable Metrics/ParameterLists
|
|
39
|
+
correction: nil)
|
|
40
|
+
@linter = linter
|
|
41
|
+
@filename = filename
|
|
42
|
+
@line = line || 0
|
|
43
|
+
@message = message
|
|
44
|
+
@severity = severity
|
|
45
|
+
@correction = correction
|
|
46
|
+
@corrected = false
|
|
34
47
|
end
|
|
35
48
|
|
|
36
49
|
# Return whether this lint has a severity of error.
|
|
@@ -39,5 +52,19 @@ module SlimLint
|
|
|
39
52
|
def error?
|
|
40
53
|
@severity == :error
|
|
41
54
|
end
|
|
55
|
+
|
|
56
|
+
# Return whether this lint has a known automatic correction.
|
|
57
|
+
#
|
|
58
|
+
# @return [Boolean]
|
|
59
|
+
def correctable?
|
|
60
|
+
!@correction.nil?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Return whether this lint's correction has been applied.
|
|
64
|
+
#
|
|
65
|
+
# @return [Boolean]
|
|
66
|
+
def corrected?
|
|
67
|
+
@corrected
|
|
68
|
+
end
|
|
42
69
|
end
|
|
43
70
|
end
|
|
@@ -4,6 +4,7 @@ module SlimLint
|
|
|
4
4
|
# Searches for control statements with only comments.
|
|
5
5
|
class Linter::CommentControlStatement < Linter
|
|
6
6
|
include LinterRegistry
|
|
7
|
+
support_autocorrect
|
|
7
8
|
|
|
8
9
|
on [:slim, :control] do |sexp|
|
|
9
10
|
_, _, code = sexp
|
|
@@ -16,7 +17,10 @@ module SlimLint
|
|
|
16
17
|
|
|
17
18
|
report_lint(sexp,
|
|
18
19
|
"Slim code comments (`/#{comment}`) are preferred over " \
|
|
19
|
-
"control statement comments (`-##{comment}`)"
|
|
20
|
+
"control statement comments (`-##{comment}`)",
|
|
21
|
+
correction: ->(line) {
|
|
22
|
+
line.sub(/-\s*#{Regexp.escape(code.to_s)}/, "/#{comment}")
|
|
23
|
+
})
|
|
20
24
|
end
|
|
21
25
|
end
|
|
22
26
|
end
|
|
@@ -4,10 +4,17 @@ module SlimLint
|
|
|
4
4
|
# Checks for missing or superfluous spacing before and after control statements.
|
|
5
5
|
class Linter::ControlStatementSpacing < Linter
|
|
6
6
|
include LinterRegistry
|
|
7
|
+
support_autocorrect
|
|
7
8
|
|
|
8
9
|
MESSAGE_OUTPUT = 'Please add a space before and after the `=`'
|
|
9
10
|
MESSAGE_CONTROL = 'Please add a space after the `-`'
|
|
10
11
|
|
|
12
|
+
# Matches the tag/attribute-shortcut selector, the `=`-based operator
|
|
13
|
+
# (`=`, `==`, `=<`, `=>`, `=<>`, `==<`, `==>`, `==<>`), and the whitespace
|
|
14
|
+
# surrounding the operator, so it can be normalized to a single space on
|
|
15
|
+
# either side without touching the Ruby code that follows.
|
|
16
|
+
OUTPUT_SPACING = /^(\s*)(\S+?)(\s*)(=[=<>]*)(\s*)/
|
|
17
|
+
|
|
11
18
|
on [:html, :tag, anything, [],
|
|
12
19
|
[:slim, :output, anything, capture(:ruby, anything)]] do |sexp|
|
|
13
20
|
# Fetch original Slim code that contains an element with a control statement.
|
|
@@ -20,7 +27,8 @@ module SlimLint
|
|
|
20
27
|
|
|
21
28
|
next if line =~ /[^ ] ==?<?>? [^ ]/
|
|
22
29
|
|
|
23
|
-
report_lint(sexp, MESSAGE_OUTPUT
|
|
30
|
+
report_lint(sexp, MESSAGE_OUTPUT,
|
|
31
|
+
correction: ->(source_line) { source_line.sub(OUTPUT_SPACING, '\1\2 \4 ') })
|
|
24
32
|
end
|
|
25
33
|
|
|
26
34
|
on [:slim, :control] do |sexp|
|
|
@@ -30,7 +38,8 @@ module SlimLint
|
|
|
30
38
|
|
|
31
39
|
next if line =~ /^ *- [^ ]/
|
|
32
40
|
|
|
33
|
-
report_lint(sexp, MESSAGE_CONTROL
|
|
41
|
+
report_lint(sexp, MESSAGE_CONTROL,
|
|
42
|
+
correction: ->(source_line) { source_line.sub(/^(\s*)-\s*/, '\1- ') })
|
|
34
43
|
end
|
|
35
44
|
|
|
36
45
|
private
|
|
@@ -4,12 +4,14 @@ module SlimLint
|
|
|
4
4
|
# Searches for control statements with no code.
|
|
5
5
|
class Linter::EmptyControlStatement < Linter
|
|
6
6
|
include LinterRegistry
|
|
7
|
+
support_autocorrect
|
|
7
8
|
|
|
8
9
|
on [:slim, :control] do |sexp|
|
|
9
10
|
_, _, code = sexp
|
|
10
11
|
next unless code[/\A\s*\Z/]
|
|
11
12
|
|
|
12
|
-
report_lint(sexp, 'Empty control statement can be removed'
|
|
13
|
+
report_lint(sexp, 'Empty control statement can be removed',
|
|
14
|
+
correction: ->(_line) { nil })
|
|
13
15
|
end
|
|
14
16
|
end
|
|
15
17
|
end
|
|
@@ -5,6 +5,7 @@ module SlimLint
|
|
|
5
5
|
# and for the first blank line in file.
|
|
6
6
|
class Linter::EmptyLines < Linter
|
|
7
7
|
include LinterRegistry
|
|
8
|
+
support_autocorrect
|
|
8
9
|
|
|
9
10
|
on_start do |_sexp|
|
|
10
11
|
dummy_node = Struct.new(:line)
|
|
@@ -14,7 +15,8 @@ module SlimLint
|
|
|
14
15
|
if line.blank?
|
|
15
16
|
if was_empty
|
|
16
17
|
report_lint(dummy_node.new(i + 1),
|
|
17
|
-
'Extra empty line detected'
|
|
18
|
+
'Extra empty line detected',
|
|
19
|
+
correction: ->(_line) { nil })
|
|
18
20
|
end
|
|
19
21
|
was_empty = true
|
|
20
22
|
else
|
|
@@ -4,6 +4,7 @@ module SlimLint
|
|
|
4
4
|
# Checks for consistent quote usage in HTML attributes
|
|
5
5
|
class Linter::QuoteConsistency < Linter
|
|
6
6
|
include LinterRegistry
|
|
7
|
+
support_autocorrect
|
|
7
8
|
|
|
8
9
|
MSG = 'Inconsistent quote style. %s'
|
|
9
10
|
|
|
@@ -19,15 +20,42 @@ module SlimLint
|
|
|
19
20
|
|
|
20
21
|
if enforced_style == :single_quotes && double_quotes.any?
|
|
21
22
|
report_lint(node,
|
|
22
|
-
format(MSG, "Use single quotes for attribute values (')")
|
|
23
|
+
format(MSG, "Use single quotes for attribute values (')"),
|
|
24
|
+
correction: ->(source_line) { correct_quotes(source_line, '"', "'") })
|
|
23
25
|
elsif enforced_style == :double_quotes && single_quotes.any?
|
|
24
26
|
report_lint(node,
|
|
25
|
-
format(MSG, 'Use double quotes for attribute values (")')
|
|
27
|
+
format(MSG, 'Use double quotes for attribute values (")'),
|
|
28
|
+
correction: ->(source_line) { correct_quotes(source_line, "'", '"') })
|
|
26
29
|
end
|
|
27
30
|
end
|
|
28
31
|
|
|
29
32
|
private
|
|
30
33
|
|
|
34
|
+
def correct_quotes(source_line, from, to)
|
|
35
|
+
state = { quote: nil, corrected: [] }
|
|
36
|
+
source_line.scan(/\\.|['"]|[^\\'"]+/).each do |token|
|
|
37
|
+
correct_quote_token(token, state, from, to)
|
|
38
|
+
end
|
|
39
|
+
state[:corrected].join
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def correct_quote_token(token, state, from, to)
|
|
43
|
+
return state[:corrected] << token if token.length > 1 || token.start_with?('\\')
|
|
44
|
+
|
|
45
|
+
if state[:quote]
|
|
46
|
+
close_quote_token(token, state, from, to)
|
|
47
|
+
else
|
|
48
|
+
state[:quote] = token
|
|
49
|
+
state[:corrected] << (token == from ? to : token)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def close_quote_token(token, state, from, to)
|
|
54
|
+
replacement = token == state[:quote] && token == from ? to : token
|
|
55
|
+
state[:corrected] << replacement
|
|
56
|
+
state[:quote] = nil if token == state[:quote]
|
|
57
|
+
end
|
|
58
|
+
|
|
31
59
|
def enforced_style
|
|
32
60
|
config['enforced_style']&.to_sym || :single_quotes
|
|
33
61
|
end
|
|
@@ -5,6 +5,7 @@ module SlimLint
|
|
|
5
5
|
# already implies a div.
|
|
6
6
|
class Linter::RedundantDiv < Linter
|
|
7
7
|
include LinterRegistry
|
|
8
|
+
support_autocorrect
|
|
8
9
|
|
|
9
10
|
MESSAGE = '`div` is redundant when %s attribute shortcut is present'
|
|
10
11
|
|
|
@@ -16,7 +17,8 @@ module SlimLint
|
|
|
16
17
|
attr = captures[:attr_name]
|
|
17
18
|
next unless %w[class id].include?(attr)
|
|
18
19
|
|
|
19
|
-
report_lint(sexp, MESSAGE % attr
|
|
20
|
+
report_lint(sexp, MESSAGE % attr,
|
|
21
|
+
correction: ->(line) { line.sub(/\bdiv(?=[.#])/, '') })
|
|
20
22
|
end
|
|
21
23
|
end
|
|
22
24
|
end
|
|
@@ -4,12 +4,16 @@ module SlimLint
|
|
|
4
4
|
# Searches for tags with uppercase characters.
|
|
5
5
|
class Linter::TagCase < Linter
|
|
6
6
|
include LinterRegistry
|
|
7
|
+
support_autocorrect
|
|
7
8
|
|
|
8
9
|
on [:html, :tag] do |sexp|
|
|
9
10
|
_, _, name = sexp
|
|
10
11
|
next unless name[/[A-Z]/]
|
|
11
12
|
|
|
12
|
-
report_lint(sexp, "Tag `#{name}` should be written as `#{name.downcase}`"
|
|
13
|
+
report_lint(sexp, "Tag `#{name}` should be written as `#{name.downcase}`",
|
|
14
|
+
correction: ->(line) {
|
|
15
|
+
line.sub(/\b#{Regexp.escape(name.to_s)}\b/, name.downcase)
|
|
16
|
+
})
|
|
13
17
|
end
|
|
14
18
|
end
|
|
15
19
|
end
|
|
@@ -4,6 +4,7 @@ module SlimLint
|
|
|
4
4
|
# This linter looks for trailing blank lines and a final newline.
|
|
5
5
|
class Linter::TrailingBlankLines < Linter
|
|
6
6
|
include LinterRegistry
|
|
7
|
+
support_autocorrect
|
|
7
8
|
|
|
8
9
|
on_start do |_sexp|
|
|
9
10
|
dummy_node = Struct.new(:line)
|
|
@@ -11,10 +12,12 @@ module SlimLint
|
|
|
11
12
|
|
|
12
13
|
if !document.source.end_with?("\n")
|
|
13
14
|
report_lint(dummy_node.new(document.source_lines.size),
|
|
14
|
-
'No blank line in the end of file'
|
|
15
|
+
'No blank line in the end of file',
|
|
16
|
+
correction: ->(line) { "#{line}\n" })
|
|
15
17
|
elsif document.source.lines.last.blank?
|
|
16
18
|
report_lint(dummy_node.new(document.source.lines.size),
|
|
17
|
-
'Multiple empty lines in the end of file'
|
|
19
|
+
'Multiple empty lines in the end of file',
|
|
20
|
+
correction: ->(_line) { nil })
|
|
18
21
|
end
|
|
19
22
|
end
|
|
20
23
|
end
|
|
@@ -4,6 +4,7 @@ module SlimLint
|
|
|
4
4
|
# Checks for trailing whitespace.
|
|
5
5
|
class Linter::TrailingWhitespace < Linter
|
|
6
6
|
include LinterRegistry
|
|
7
|
+
support_autocorrect
|
|
7
8
|
|
|
8
9
|
on_start do |_sexp|
|
|
9
10
|
dummy_node = Struct.new(:line)
|
|
@@ -12,7 +13,8 @@ module SlimLint
|
|
|
12
13
|
next unless line =~ /\s+$/
|
|
13
14
|
|
|
14
15
|
report_lint(dummy_node.new(index + 1),
|
|
15
|
-
'Line contains trailing whitespace'
|
|
16
|
+
'Line contains trailing whitespace',
|
|
17
|
+
correction: lambda(&:rstrip))
|
|
16
18
|
end
|
|
17
19
|
end
|
|
18
20
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
module SlimLint
|
|
4
4
|
class Linter::Zwsp < Linter
|
|
5
5
|
include LinterRegistry
|
|
6
|
+
support_autocorrect
|
|
6
7
|
|
|
7
8
|
MSG = 'Remove zero-width space'
|
|
8
9
|
|
|
@@ -11,7 +12,8 @@ module SlimLint
|
|
|
11
12
|
document.source_lines.each_with_index do |line, index|
|
|
12
13
|
next unless line.include?("\u200b")
|
|
13
14
|
|
|
14
|
-
report_lint(dummy_node.new(index + 1), MSG
|
|
15
|
+
report_lint(dummy_node.new(index + 1), MSG,
|
|
16
|
+
correction: ->(source_line) { source_line.delete("\u200b") })
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
end
|
data/lib/slim_lint/linter.rb
CHANGED
|
@@ -15,6 +15,21 @@ module SlimLint
|
|
|
15
15
|
# lints for the subject instead of the linter itself.
|
|
16
16
|
attr_reader :lints
|
|
17
17
|
|
|
18
|
+
class << self
|
|
19
|
+
# Declares that this linter can automatically correct (some of) the
|
|
20
|
+
# offenses it reports.
|
|
21
|
+
def support_autocorrect
|
|
22
|
+
@supports_autocorrect = true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Returns whether this linter declared autocorrect support.
|
|
26
|
+
#
|
|
27
|
+
# @return [Boolean]
|
|
28
|
+
def supports_autocorrect?
|
|
29
|
+
@supports_autocorrect || false
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
18
33
|
# Initializes a linter with the specified configuration.
|
|
19
34
|
#
|
|
20
35
|
# @param config [Hash] configuration for this linter
|
|
@@ -49,10 +64,15 @@ module SlimLint
|
|
|
49
64
|
#
|
|
50
65
|
# @param node [#line] node to extract the line number from
|
|
51
66
|
# @param message [String] error/warning to display to the user
|
|
52
|
-
|
|
67
|
+
# @param correction [Proc, nil] maps the offending line of source to its
|
|
68
|
+
# corrected version, for linters that declared {support_autocorrect}.
|
|
69
|
+
# Return `nil` to remove the line entirely, or a string containing
|
|
70
|
+
# embedded newlines to replace it with multiple lines.
|
|
71
|
+
def report_lint(node, message, correction: nil)
|
|
53
72
|
return if disabled_for_line?(node.line)
|
|
54
73
|
|
|
55
|
-
@lints << SlimLint::Lint.new(self, @document.file, node.line, message
|
|
74
|
+
@lints << SlimLint::Lint.new(self, @document.file, node.line, message,
|
|
75
|
+
correction: correction)
|
|
56
76
|
end
|
|
57
77
|
|
|
58
78
|
# Parse Ruby code into an abstract syntax tree.
|
data/lib/slim_lint/options.rb
CHANGED
|
@@ -5,6 +5,10 @@ require 'optparse'
|
|
|
5
5
|
module SlimLint
|
|
6
6
|
# Handles option parsing for the command line application.
|
|
7
7
|
class Options
|
|
8
|
+
# Path scanned by default when no files or directories are given on the
|
|
9
|
+
# command line.
|
|
10
|
+
DEFAULT_FILES = ['.'].freeze
|
|
11
|
+
|
|
8
12
|
# Parses command line options into an options hash.
|
|
9
13
|
#
|
|
10
14
|
# @param args [Array<String>] arguments passed via the command line
|
|
@@ -13,15 +17,18 @@ module SlimLint
|
|
|
13
17
|
@options = {}
|
|
14
18
|
|
|
15
19
|
OptionParser.new do |parser|
|
|
16
|
-
parser.banner = "Usage: #{APP_NAME} [options] [file1, file2, ...]"
|
|
20
|
+
parser.banner = "Usage: #{APP_NAME} [options] [file1, file2, ...]\n\n" \
|
|
21
|
+
'If no files or directories are given, the current ' \
|
|
22
|
+
'directory is scanned by default.'
|
|
17
23
|
|
|
18
24
|
add_linter_options parser
|
|
19
25
|
add_file_options parser
|
|
20
26
|
add_info_options parser
|
|
21
27
|
end.parse!(args)
|
|
22
28
|
|
|
23
|
-
# Any remaining arguments are assumed to be files
|
|
24
|
-
|
|
29
|
+
# Any remaining arguments are assumed to be files; fall back to
|
|
30
|
+
# DEFAULT_FILES when none are given
|
|
31
|
+
@options[:files] = args.empty? ? DEFAULT_FILES : args
|
|
25
32
|
|
|
26
33
|
@options
|
|
27
34
|
rescue OptionParser::InvalidOption => e
|
|
@@ -48,6 +55,11 @@ module SlimLint
|
|
|
48
55
|
'Specify which reporter you want to use to generate the output') do |reporter|
|
|
49
56
|
@options[:reporter] = load_reporter_class(reporter.capitalize)
|
|
50
57
|
end
|
|
58
|
+
|
|
59
|
+
parser.on('-a', '--autocorrect',
|
|
60
|
+
'Automatically correct offenses that support it') do
|
|
61
|
+
@options[:autocorrect] = true
|
|
62
|
+
end
|
|
51
63
|
end
|
|
52
64
|
|
|
53
65
|
# Returns the class of the specified Reporter.
|
data/lib/slim_lint/report.rb
CHANGED
data/lib/slim_lint/runner.rb
CHANGED
|
@@ -20,7 +20,8 @@ module SlimLint
|
|
|
20
20
|
if options[:stdin_file_path].nil?
|
|
21
21
|
files = extract_applicable_files(config, options)
|
|
22
22
|
lints = files.map do |file|
|
|
23
|
-
collect_lints(File.read(file), file, linter_selector, config
|
|
23
|
+
collect_lints(File.read(file), file, linter_selector, config,
|
|
24
|
+
autocorrect: options[:autocorrect])
|
|
24
25
|
end.flatten
|
|
25
26
|
else
|
|
26
27
|
files = [options[:stdin_file_path]]
|
|
@@ -53,16 +54,34 @@ module SlimLint
|
|
|
53
54
|
# @param file [String] path to file to lint
|
|
54
55
|
# @param linter_selector [SlimLint::LinterSelector]
|
|
55
56
|
# @param config [SlimLint::Configuration]
|
|
56
|
-
|
|
57
|
+
# @param autocorrect [Boolean] whether to write corrections back to the file
|
|
58
|
+
def collect_lints(file_content, file_name, linter_selector, config, autocorrect: false)
|
|
57
59
|
begin
|
|
58
60
|
document = SlimLint::Document.new(file_content, file: file_name, config: config)
|
|
59
61
|
rescue SlimLint::Exceptions::ParseError => e
|
|
60
62
|
return [SlimLint::Lint.new(nil, file_name, e.lineno, e.error, :error)]
|
|
61
63
|
end
|
|
62
64
|
|
|
63
|
-
linter_selector.linters_for_file(file_name).map do |linter|
|
|
65
|
+
lints = linter_selector.linters_for_file(file_name).map do |linter|
|
|
64
66
|
linter.run(document)
|
|
65
67
|
end.flatten
|
|
68
|
+
|
|
69
|
+
correct_lints(document, file_name, lints) if autocorrect
|
|
70
|
+
|
|
71
|
+
lints
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Applies any available corrections to the given file's lints and writes
|
|
75
|
+
# the result back to disk if anything changed.
|
|
76
|
+
#
|
|
77
|
+
# @param document [SlimLint::Document]
|
|
78
|
+
# @param file_name [String] path to file to correct
|
|
79
|
+
# @param lints [Array<SlimLint::Lint>]
|
|
80
|
+
def correct_lints(document, file_name, lints)
|
|
81
|
+
corrected_source = SlimLint::Corrector.new(document).correct(lints)
|
|
82
|
+
return if corrected_source == document.original_source
|
|
83
|
+
|
|
84
|
+
File.write(file_name, corrected_source)
|
|
66
85
|
end
|
|
67
86
|
|
|
68
87
|
# Returns the list of files that should be linted given the specified
|
data/lib/slim_lint/version.rb
CHANGED
data/lib/slim_lint.rb
CHANGED
|
@@ -30,6 +30,7 @@ require_relative 'slim_lint/sexp_visitor'
|
|
|
30
30
|
require_relative 'slim_lint/lint'
|
|
31
31
|
require_relative 'slim_lint/ruby_parser'
|
|
32
32
|
require_relative 'slim_lint/linter'
|
|
33
|
+
require_relative 'slim_lint/corrector'
|
|
33
34
|
require_relative 'slim_lint/reporter'
|
|
34
35
|
require_relative 'slim_lint/report'
|
|
35
36
|
require_relative 'slim_lint/linter_selector'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: slim_lint
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.37.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shane da Silva
|
|
@@ -109,6 +109,7 @@ files:
|
|
|
109
109
|
- lib/slim_lint/configuration.rb
|
|
110
110
|
- lib/slim_lint/configuration_loader.rb
|
|
111
111
|
- lib/slim_lint/constants.rb
|
|
112
|
+
- lib/slim_lint/corrector.rb
|
|
112
113
|
- lib/slim_lint/document.rb
|
|
113
114
|
- lib/slim_lint/engine.rb
|
|
114
115
|
- lib/slim_lint/exceptions.rb
|
|
@@ -167,7 +168,11 @@ files:
|
|
|
167
168
|
homepage: https://github.com/sds/slim-lint
|
|
168
169
|
licenses:
|
|
169
170
|
- MIT
|
|
170
|
-
metadata:
|
|
171
|
+
metadata:
|
|
172
|
+
bug_tracker_uri: https://github.com/sds/slim-lint/issues
|
|
173
|
+
changelog_uri: https://github.com/sds/slim-lint/blob/main/CHANGELOG.md
|
|
174
|
+
source_code_uri: https://github.com/sds/slim-lint
|
|
175
|
+
rubygems_mfa_required: 'true'
|
|
171
176
|
rdoc_options: []
|
|
172
177
|
require_paths:
|
|
173
178
|
- lib
|