haml_lint 0.75.0 → 0.76.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/haml_lint/lint.rb +7 -2
- data/lib/haml_lint/linter/alignment_tabs.rb +20 -3
- data/lib/haml_lint/linter/consecutive_silent_scripts.rb +68 -1
- data/lib/haml_lint/linter/html_attributes.rb +71 -2
- data/lib/haml_lint/linter/rubocop.rb +5 -3
- data/lib/haml_lint/linter/unnecessary_string_output.rb +74 -10
- data/lib/haml_lint/linter.rb +5 -2
- data/lib/haml_lint/reporter/hash_reporter.rb +2 -0
- data/lib/haml_lint/reporter/utils.rb +2 -0
- data/lib/haml_lint/spec/matchers/report_lint.rb +15 -4
- data/lib/haml_lint/tree/tag_node.rb +12 -0
- data/lib/haml_lint/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 188328ae96f24b3a739665a5d3ccc7271a753afbe0ae63a1fbe3f33897492caa
|
|
4
|
+
data.tar.gz: 52b39c0992433545f610c7c18af3d06b224027edea3a9cdb97f71c7c1cf4f8c5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 31c53c1177acc7679c9f3c5b633a2b14278252f447ddea3b03c9d49e82d6e3d4587d44803e7b2b5ca677b726702c1a716cb02c848b8d2b71ed7bd402b78d8519
|
|
7
|
+
data.tar.gz: 253e971535ea2d8c38340e2e13a882fbe215cded72f5faa96b26dd88bb39024efe5b03d8334cc7692de4edbab2a7e49db9d4bb55a6a55e10319b52e3770a9ea4
|
data/lib/haml_lint/lint.rb
CHANGED
|
@@ -6,6 +6,9 @@ module HamlLint
|
|
|
6
6
|
# @return [Boolean] If the error was corrected by auto-correct
|
|
7
7
|
attr_reader :corrected
|
|
8
8
|
|
|
9
|
+
# @return [Boolean] If the error could be corrected by auto-correct
|
|
10
|
+
attr_reader :correctable
|
|
11
|
+
|
|
9
12
|
# @return [String] file path to which the lint applies
|
|
10
13
|
attr_reader :filename
|
|
11
14
|
|
|
@@ -28,13 +31,14 @@ module HamlLint
|
|
|
28
31
|
# @param line [Fixnum]
|
|
29
32
|
# @param message [String]
|
|
30
33
|
# @param severity [Symbol]
|
|
31
|
-
def initialize(linter, filename, line, message, severity = :warning, corrected: false) # rubocop:disable Metrics/ParameterLists
|
|
34
|
+
def initialize(linter, filename, line, message, severity = :warning, corrected: false, correctable: false) # rubocop:disable Metrics/ParameterLists
|
|
32
35
|
@linter = linter
|
|
33
36
|
@filename = filename
|
|
34
37
|
@line = line || 0
|
|
35
38
|
@message = message
|
|
36
39
|
@severity = Severity.new(severity)
|
|
37
40
|
@corrected = corrected
|
|
41
|
+
@correctable = correctable
|
|
38
42
|
end
|
|
39
43
|
|
|
40
44
|
# Return whether this lint has a severity of error.
|
|
@@ -45,7 +49,8 @@ module HamlLint
|
|
|
45
49
|
end
|
|
46
50
|
|
|
47
51
|
def inspect
|
|
48
|
-
"#{self.class.name}(corrected=#{corrected},
|
|
52
|
+
"#{self.class.name}(corrected=#{corrected}, correctable=#{correctable}, " \
|
|
53
|
+
"filename=#{filename}, line=#{line}, " \
|
|
49
54
|
"linter=#{linter.class.name}, message=#{message}, severity=#{severity})"
|
|
50
55
|
end
|
|
51
56
|
end
|
|
@@ -3,12 +3,29 @@
|
|
|
3
3
|
module HamlLint
|
|
4
4
|
# Checks for tabs that are placed for alignment of tag content
|
|
5
5
|
class Linter::AlignmentTabs < Linter
|
|
6
|
+
include LinterRegistry
|
|
7
|
+
|
|
8
|
+
supports_autocorrect(true)
|
|
9
|
+
autocorrect_safe(false)
|
|
10
|
+
|
|
6
11
|
REGEX = /[^\s*]\t+/
|
|
12
|
+
# Same as +REGEX+, but captures the character preceding the alignment tabs
|
|
13
|
+
# so it can be kept while the tabs themselves are collapsed to a space.
|
|
14
|
+
CORRECTION_REGEX = /([^\s*])\t+/
|
|
7
15
|
|
|
8
16
|
def visit_tag(node)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
17
|
+
return unless REGEX.match?(node.source_code)
|
|
18
|
+
|
|
19
|
+
record_lint(node, 'Avoid using tabs for alignment', corrected: correct(node))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
# @return [Boolean] whether a correction was applied
|
|
25
|
+
def correct(node)
|
|
26
|
+
index = node.line - 1
|
|
27
|
+
line = autocorrected_lines[index]
|
|
28
|
+
correct_line(index, line.gsub(CORRECTION_REGEX) { "#{::Regexp.last_match(1)} " })
|
|
12
29
|
end
|
|
13
30
|
end
|
|
14
31
|
end
|
|
@@ -6,6 +6,9 @@ module HamlLint
|
|
|
6
6
|
class Linter::ConsecutiveSilentScripts < Linter
|
|
7
7
|
include LinterRegistry
|
|
8
8
|
|
|
9
|
+
supports_autocorrect(true)
|
|
10
|
+
autocorrect_safe(false)
|
|
11
|
+
|
|
9
12
|
SILENT_SCRIPT_DETECTOR = ->(child) do
|
|
10
13
|
child.type == :silent_script && child.children.empty?
|
|
11
14
|
end
|
|
@@ -18,12 +21,21 @@ module HamlLint
|
|
|
18
21
|
SILENT_SCRIPT_DETECTOR,
|
|
19
22
|
config['max_consecutive'] + 1,
|
|
20
23
|
) do |group|
|
|
24
|
+
reported_nodes.concat(group)
|
|
21
25
|
record_lint(group.first,
|
|
22
26
|
"#{group.count} consecutive Ruby scripts can be merged " \
|
|
23
|
-
'into a single `:ruby` filter'
|
|
27
|
+
'into a single `:ruby` filter',
|
|
28
|
+
corrected: collect_merge(group))
|
|
24
29
|
end
|
|
25
30
|
end
|
|
26
31
|
|
|
32
|
+
def after_visit_root(_node)
|
|
33
|
+
super
|
|
34
|
+
return if merges.empty?
|
|
35
|
+
|
|
36
|
+
apply_autocorrect(merged_source)
|
|
37
|
+
end
|
|
38
|
+
|
|
27
39
|
private
|
|
28
40
|
|
|
29
41
|
def possible_group(node)
|
|
@@ -37,5 +49,60 @@ module HamlLint
|
|
|
37
49
|
def reported_nodes
|
|
38
50
|
@reported_nodes ||= []
|
|
39
51
|
end
|
|
52
|
+
|
|
53
|
+
def reset_autocorrect_state
|
|
54
|
+
super
|
|
55
|
+
@merges = []
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Queues a group of consecutive silent scripts to be replaced by an
|
|
59
|
+
# equivalent `:ruby` filter block. Skips (and reports without correcting)
|
|
60
|
+
# groups that aren't a run of single-line scripts on contiguous lines.
|
|
61
|
+
#
|
|
62
|
+
# @return [Boolean] whether a correction was queued
|
|
63
|
+
def collect_merge(group)
|
|
64
|
+
return false unless autocorrect?
|
|
65
|
+
return false unless mergeable?(group)
|
|
66
|
+
|
|
67
|
+
merges << {
|
|
68
|
+
start: group.first.line - 1,
|
|
69
|
+
finish: group.last.line - 1,
|
|
70
|
+
lines: ruby_filter_lines(group),
|
|
71
|
+
}
|
|
72
|
+
true
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @return [Boolean] whether every script is a single line and the group
|
|
76
|
+
# occupies a contiguous run of lines
|
|
77
|
+
def mergeable?(group)
|
|
78
|
+
group.none? { |node| node.script.include?("\n") } &&
|
|
79
|
+
group.each_cons(2).all? { |a, b| b.line == a.line + 1 }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Builds the replacement lines: a `:ruby` filter marker at the group's
|
|
83
|
+
# indentation, followed by each script's body indented one level deeper.
|
|
84
|
+
#
|
|
85
|
+
# @return [Array<String>]
|
|
86
|
+
def ruby_filter_lines(group)
|
|
87
|
+
indent = document.source_lines[group.first.line - 1][/\A\s*/]
|
|
88
|
+
inner = indent + (indent.include?("\t") ? "\t" : ' ')
|
|
89
|
+
["#{indent}:ruby", *group.map { |node| "#{inner}#{node.script.strip}" }]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Applies the queued range replacements from the bottom up (so earlier line
|
|
93
|
+
# indices stay valid) and returns the rebuilt source.
|
|
94
|
+
#
|
|
95
|
+
# @return [String]
|
|
96
|
+
def merged_source
|
|
97
|
+
lines = document.source_lines.dup
|
|
98
|
+
merges.sort_by { |merge| -merge[:start] }.each do |merge|
|
|
99
|
+
lines[merge[:start]..merge[:finish]] = merge[:lines]
|
|
100
|
+
end
|
|
101
|
+
lines.join("\n")
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def merges
|
|
105
|
+
@merges ||= []
|
|
106
|
+
end
|
|
40
107
|
end
|
|
41
108
|
end
|
|
@@ -6,11 +6,80 @@ module HamlLint
|
|
|
6
6
|
class Linter::HtmlAttributes < Linter
|
|
7
7
|
include LinterRegistry
|
|
8
8
|
|
|
9
|
+
supports_autocorrect(true)
|
|
10
|
+
autocorrect_safe(false)
|
|
11
|
+
|
|
12
|
+
MESSAGE = "Prefer the hash attributes syntax (%tag{ lang: 'en' }) " \
|
|
13
|
+
'over HTML attributes syntax (%tag(lang=en))'
|
|
14
|
+
|
|
9
15
|
def visit_tag(node)
|
|
10
16
|
return unless node.html_attributes?
|
|
11
17
|
|
|
12
|
-
record_lint(node,
|
|
13
|
-
|
|
18
|
+
record_lint(node, MESSAGE, corrected: correct(node))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# Rewrites the HTML attribute group `(...)` as a Ruby hash group `{...}`,
|
|
24
|
+
# preserving each attribute's value (static strings, booleans, and Ruby
|
|
25
|
+
# expressions alike).
|
|
26
|
+
#
|
|
27
|
+
# The conversion is skipped (the lint is still reported) when it can't be
|
|
28
|
+
# performed losslessly: when the tag already has a `{...}` hash group, when
|
|
29
|
+
# the `.class`/`#id` shorthand is present (its `class`/`id` are merged into
|
|
30
|
+
# the parsed attributes and can't be told apart from the HTML ones), or when
|
|
31
|
+
# the attribute list spans multiple lines.
|
|
32
|
+
#
|
|
33
|
+
# @return [Boolean] whether a correction was applied
|
|
34
|
+
def correct(node)
|
|
35
|
+
return false unless correctable?(node)
|
|
36
|
+
return false unless pairs = hash_pairs(node)
|
|
37
|
+
|
|
38
|
+
hash_source = "{ #{pairs.join(', ')} }"
|
|
39
|
+
return false unless parse_ruby(hash_source)
|
|
40
|
+
|
|
41
|
+
index = node.line - 1
|
|
42
|
+
line = autocorrected_lines[index]
|
|
43
|
+
html_source = node.dynamic_attributes_source[:html]
|
|
44
|
+
return false unless line.include?(html_source)
|
|
45
|
+
|
|
46
|
+
correct_line(index, line.sub(html_source) { hash_source })
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Whether the tag's HTML attributes can be losslessly converted in place.
|
|
50
|
+
#
|
|
51
|
+
# @return [Boolean]
|
|
52
|
+
def correctable?(node)
|
|
53
|
+
return false if node.hash_attributes?
|
|
54
|
+
return false unless node.static_attributes_source.empty?
|
|
55
|
+
|
|
56
|
+
html_source = node.dynamic_attributes_source[:html]
|
|
57
|
+
!html_source.nil? && !html_source.include?("\n")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Builds the `key => value` fragments for the tag's HTML attributes, or +nil+
|
|
61
|
+
# when one of the static values can't be safely serialized.
|
|
62
|
+
#
|
|
63
|
+
# @return [Array<String>, nil]
|
|
64
|
+
def hash_pairs(node)
|
|
65
|
+
pairs = node.static_attributes.map do |key, value|
|
|
66
|
+
return nil unless serializable?(value)
|
|
67
|
+
|
|
68
|
+
"#{key.inspect} => #{value.inspect}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
node.dynamic_attributes_sources.each do |literal|
|
|
72
|
+
inner = literal.strip.delete_prefix('{').delete_suffix('}').sub(/,\s*\z/, '').strip
|
|
73
|
+
pairs << inner unless inner.empty?
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
pairs
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# @return [Boolean] whether the static attribute value round-trips through
|
|
80
|
+
# +#inspect+ as a Ruby literal
|
|
81
|
+
def serializable?(value)
|
|
82
|
+
value.is_a?(String) || [true, false, nil].include?(value) || value.is_a?(Numeric)
|
|
14
83
|
end
|
|
15
84
|
end
|
|
16
85
|
end
|
|
@@ -282,7 +282,7 @@ module HamlLint
|
|
|
282
282
|
end
|
|
283
283
|
end
|
|
284
284
|
record_lint(line, offense.message, offense.severity.name,
|
|
285
|
-
corrected: autocorrected)
|
|
285
|
+
corrected: autocorrected, correctable: offense.correctable?)
|
|
286
286
|
end
|
|
287
287
|
end
|
|
288
288
|
|
|
@@ -291,13 +291,15 @@ module HamlLint
|
|
|
291
291
|
# @param line [#line] line number of the lint
|
|
292
292
|
# @param message [String] error/warning to display to the user
|
|
293
293
|
# @param severity [Symbol] RuboCop severity level for the offense
|
|
294
|
-
|
|
294
|
+
# @param corrected [Boolean] whether RuboCop auto-corrected the offense
|
|
295
|
+
# @param correctable [Boolean] whether RuboCop is able to auto-correct the offense
|
|
296
|
+
def record_lint(line, message, severity, corrected:, correctable: false)
|
|
295
297
|
# TODO: actual handling for RuboCop's new :info severity
|
|
296
298
|
return if severity == :info
|
|
297
299
|
|
|
298
300
|
@lints << HamlLint::Lint.new(self, @document.file, line, message,
|
|
299
301
|
SEVERITY_MAP.fetch(severity, :warning),
|
|
300
|
-
corrected: corrected)
|
|
302
|
+
corrected: corrected, correctable: correctable)
|
|
301
303
|
end
|
|
302
304
|
|
|
303
305
|
# rubocop:disable Style/MutableConstant
|
|
@@ -11,35 +11,99 @@ module HamlLint
|
|
|
11
11
|
class Linter::UnnecessaryStringOutput < Linter
|
|
12
12
|
include LinterRegistry
|
|
13
13
|
|
|
14
|
+
supports_autocorrect(true)
|
|
15
|
+
autocorrect_safe(false)
|
|
16
|
+
|
|
14
17
|
MESSAGE = '`= "..."` should be rewritten as `...`'
|
|
15
18
|
|
|
16
19
|
def visit_tag(node)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
return unless tag_has_inline_script?(node) && inline_content_is_string?(node)
|
|
21
|
+
|
|
22
|
+
plain = safe_plain_text(node.script)
|
|
23
|
+
corrected = plain ? correct_tag(node, plain) : false
|
|
24
|
+
record_lint(node, MESSAGE, corrected: corrected)
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
def visit_script(node)
|
|
23
28
|
# Some script nodes created by the Haml parser aren't actually script
|
|
24
29
|
# nodes declared via the `=` marker. Check for it.
|
|
25
30
|
return unless /\A\s*=/.match?(node.source_code)
|
|
31
|
+
return unless plain = safe_plain_text(node.script)
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
record_lint(node, MESSAGE)
|
|
29
|
-
end
|
|
33
|
+
record_lint(node, MESSAGE, corrected: correct_script(node, plain))
|
|
30
34
|
end
|
|
31
35
|
|
|
32
36
|
private
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
# Rewrites `%tag= "..."` as `%tag ...`, dropping the `=` marker and the
|
|
39
|
+
# surrounding quotes.
|
|
40
|
+
#
|
|
41
|
+
# @return [Boolean] whether a correction was applied
|
|
42
|
+
def correct_tag(node, plain)
|
|
43
|
+
marker = node.inline_marker_source.rstrip
|
|
44
|
+
# Only unwrap plain escaped output (`= "..."`); leave `!=`, `~`, and the
|
|
45
|
+
# whitespace-removal markers (`<`/`>`) untouched, as they change rendering.
|
|
46
|
+
return false unless /\A=\s*["']/.match?(marker)
|
|
47
|
+
|
|
48
|
+
index = node.line - 1
|
|
49
|
+
line = autocorrected_lines[index]
|
|
50
|
+
return false unless line.rstrip.end_with?(marker)
|
|
51
|
+
|
|
52
|
+
prefix = line.rstrip[0...(line.rstrip.length - marker.length)]
|
|
53
|
+
correct_line(index, "#{prefix} #{plain}")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Rewrites a standalone `= "..."` script as plain text, preserving the
|
|
57
|
+
# node's indentation.
|
|
58
|
+
#
|
|
59
|
+
# @return [Boolean] whether a correction was applied
|
|
60
|
+
def correct_script(node, plain)
|
|
61
|
+
index = node.line - 1
|
|
62
|
+
line = autocorrected_lines[index]
|
|
63
|
+
indentation = line[/\A\s*/]
|
|
64
|
+
correct_line(index, "#{indentation}#{plain}")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Returns the Haml plain-text equivalent of a Ruby string literal script, or
|
|
68
|
+
# +nil+ when the script is not a string literal that can be safely unwrapped
|
|
69
|
+
# (i.e. unwrapping would change the rendered output).
|
|
70
|
+
#
|
|
71
|
+
# @return [String, nil]
|
|
72
|
+
def safe_plain_text(script)
|
|
73
|
+
return if script.include?("\n")
|
|
74
|
+
return unless tree = parse_ruby(script)
|
|
36
75
|
return unless %i[str dstr].include?(tree.type)
|
|
76
|
+
return unless safely_unwrappable?(tree)
|
|
77
|
+
|
|
78
|
+
plain_text_from(tree)
|
|
79
|
+
rescue ::Parser::SyntaxError
|
|
80
|
+
# Gracefully ignore syntax errors, as that's managed by a different linter
|
|
81
|
+
nil
|
|
82
|
+
end
|
|
37
83
|
|
|
84
|
+
# Whether unwrapping the string literal into Haml plain text would preserve
|
|
85
|
+
# the rendered output.
|
|
86
|
+
#
|
|
87
|
+
# @return [Boolean]
|
|
88
|
+
def safely_unwrappable?(tree)
|
|
38
89
|
!starts_with_reserved_character?(tree.children.first) &&
|
|
39
90
|
!contains_escape_sequence?(tree) &&
|
|
40
91
|
!contains_significant_whitespace?(tree)
|
|
41
|
-
|
|
42
|
-
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Reconstructs the Haml plain-text form of a string literal. Literal segments
|
|
95
|
+
# keep their text (with any `#{` escaped so Haml won't interpolate it), while
|
|
96
|
+
# interpolation segments are emitted verbatim in their `#{...}` form.
|
|
97
|
+
#
|
|
98
|
+
# @return [String]
|
|
99
|
+
def plain_text_from(tree)
|
|
100
|
+
string_segments(tree).map do |segment|
|
|
101
|
+
if segment.type == :str
|
|
102
|
+
segment.children.first.gsub('#{') { '\#{' }
|
|
103
|
+
else
|
|
104
|
+
segment.location.expression.source
|
|
105
|
+
end
|
|
106
|
+
end.join
|
|
43
107
|
end
|
|
44
108
|
|
|
45
109
|
# Returns whether a string starts with a character that would otherwise be
|
data/lib/haml_lint/linter.rb
CHANGED
|
@@ -212,11 +212,14 @@ module HamlLint
|
|
|
212
212
|
#
|
|
213
213
|
# @param node_or_line [#line] line number or node to extract the line number from
|
|
214
214
|
# @param message [String] error/warning to display to the user
|
|
215
|
-
|
|
215
|
+
# @param corrected [Boolean] whether the lint was fixed by auto-correct
|
|
216
|
+
# @param correctable [Boolean] whether the lint can be fixed by auto-correct;
|
|
217
|
+
# defaults to whether this linter supports auto-correct at all
|
|
218
|
+
def record_lint(node_or_line, message, corrected: false, correctable: supports_autocorrect?)
|
|
216
219
|
line = node_or_line.is_a?(Integer) ? node_or_line : node_or_line.line
|
|
217
220
|
@lints << HamlLint::Lint.new(self, @document.file, line, message,
|
|
218
221
|
config.fetch('severity', :warning).to_sym,
|
|
219
|
-
corrected: corrected)
|
|
222
|
+
corrected: corrected, correctable: correctable)
|
|
220
223
|
end
|
|
221
224
|
|
|
222
225
|
# Parse Ruby code into an abstract syntax tree.
|
|
@@ -11,10 +11,11 @@ module HamlLint
|
|
|
11
11
|
expected_message = options[:message]
|
|
12
12
|
expected_severity = options[:severity]
|
|
13
13
|
expected_corrected = options[:corrected]
|
|
14
|
+
expected_correctable = options[:correctable]
|
|
14
15
|
|
|
15
16
|
match do |linter|
|
|
16
17
|
has_lints?(linter, expected_line, count, expected_message, expected_severity,
|
|
17
|
-
expected_corrected)
|
|
18
|
+
expected_corrected, expected_correctable)
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
failure_message do |linter|
|
|
@@ -66,14 +67,15 @@ module HamlLint
|
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
def has_lints?(linter, expected_line, count, expected_message, expected_severity, # rubocop:disable Metrics/ParameterLists,Naming
|
|
69
|
-
expected_corrected)
|
|
70
|
+
expected_corrected, expected_correctable)
|
|
70
71
|
if expected_line
|
|
71
72
|
has_expected_line_lints?(linter,
|
|
72
73
|
expected_line,
|
|
73
74
|
count,
|
|
74
75
|
expected_message,
|
|
75
76
|
expected_severity,
|
|
76
|
-
expected_corrected
|
|
77
|
+
expected_corrected,
|
|
78
|
+
expected_correctable)
|
|
77
79
|
elsif count
|
|
78
80
|
linter.lints.count == count
|
|
79
81
|
elsif expected_message
|
|
@@ -88,7 +90,8 @@ module HamlLint
|
|
|
88
90
|
count,
|
|
89
91
|
expected_message,
|
|
90
92
|
expected_severity,
|
|
91
|
-
expected_corrected
|
|
93
|
+
expected_corrected,
|
|
94
|
+
expected_correctable)
|
|
92
95
|
if count
|
|
93
96
|
multiple_lints_match_line?(linter, expected_line, count)
|
|
94
97
|
elsif expected_message
|
|
@@ -97,6 +100,8 @@ module HamlLint
|
|
|
97
100
|
lint_on_line_matches_severity?(linter, expected_line, expected_severity)
|
|
98
101
|
elsif !expected_corrected.nil?
|
|
99
102
|
lint_on_line_matches_corrected?(linter, expected_line, expected_corrected)
|
|
103
|
+
elsif !expected_correctable.nil?
|
|
104
|
+
lint_on_line_matches_correctable?(linter, expected_line, expected_correctable)
|
|
100
105
|
else
|
|
101
106
|
lint_lines(linter).include?(expected_line)
|
|
102
107
|
end
|
|
@@ -126,6 +131,12 @@ module HamlLint
|
|
|
126
131
|
.any? { |lint| lint.line == expected_line && lint.corrected == expected_corrected }
|
|
127
132
|
end
|
|
128
133
|
|
|
134
|
+
def lint_on_line_matches_correctable?(linter, expected_line, expected_correctable)
|
|
135
|
+
linter
|
|
136
|
+
.lints
|
|
137
|
+
.any? { |lint| lint.line == expected_line && lint.correctable == expected_correctable }
|
|
138
|
+
end
|
|
139
|
+
|
|
129
140
|
def lint_messages_match?(linter, expected_message)
|
|
130
141
|
# Using === to support regex to match anywhere in the string
|
|
131
142
|
lint_messages(linter).all? { |message| expected_message === message } # rubocop:disable Style/CaseEquality
|
|
@@ -155,6 +155,18 @@ module HamlLint::Tree
|
|
|
155
155
|
dynamic_attributes_source[:html][/\A\((.*)\)\z/, 1] if html_attributes?
|
|
156
156
|
end
|
|
157
157
|
|
|
158
|
+
# The tag's static (non-Ruby) attributes parsed into a Ruby hash. Keys are
|
|
159
|
+
# strings and values are their literal parsed values (e.g. `true` for a
|
|
160
|
+
# boolean attribute such as `(required)`).
|
|
161
|
+
#
|
|
162
|
+
# @note When the tag uses the `.class`/`#id` shorthand, the resulting
|
|
163
|
+
# `class`/`id` entries are merged into this hash as well.
|
|
164
|
+
#
|
|
165
|
+
# @return [Hash]
|
|
166
|
+
def static_attributes
|
|
167
|
+
@value[:attributes]
|
|
168
|
+
end
|
|
169
|
+
|
|
158
170
|
# ID of the HTML tag.
|
|
159
171
|
#
|
|
160
172
|
# @return [String]
|
data/lib/haml_lint/version.rb
CHANGED