haml_lint 0.40.0 → 0.51.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/bin/haml-lint +1 -1
- data/config/default.yml +9 -27
- data/config/forced_rubocop_config.yml +180 -0
- data/lib/haml_lint/adapter/haml_4.rb +20 -0
- data/lib/haml_lint/adapter/haml_5.rb +11 -0
- data/lib/haml_lint/adapter/haml_6.rb +59 -0
- data/lib/haml_lint/adapter.rb +2 -0
- data/lib/haml_lint/cli.rb +8 -3
- data/lib/haml_lint/configuration_loader.rb +49 -13
- data/lib/haml_lint/document.rb +89 -8
- data/lib/haml_lint/exceptions.rb +6 -0
- data/lib/haml_lint/extensions/haml_util_unescape_interpolation_tracking.rb +35 -0
- data/lib/haml_lint/file_finder.rb +2 -2
- data/lib/haml_lint/lint.rb +10 -1
- data/lib/haml_lint/linter/final_newline.rb +4 -3
- data/lib/haml_lint/linter/implicit_div.rb +1 -1
- data/lib/haml_lint/linter/indentation.rb +3 -3
- data/lib/haml_lint/linter/no_placeholders.rb +18 -0
- data/lib/haml_lint/linter/repeated_id.rb +2 -1
- data/lib/haml_lint/linter/rubocop.rb +353 -59
- data/lib/haml_lint/linter/space_before_script.rb +8 -10
- data/lib/haml_lint/linter/trailing_empty_lines.rb +22 -0
- data/lib/haml_lint/linter/unnecessary_string_output.rb +1 -1
- data/lib/haml_lint/linter/view_length.rb +1 -1
- data/lib/haml_lint/linter.rb +60 -10
- data/lib/haml_lint/linter_registry.rb +3 -5
- data/lib/haml_lint/logger.rb +2 -2
- data/lib/haml_lint/options.rb +26 -2
- data/lib/haml_lint/rake_task.rb +2 -2
- data/lib/haml_lint/reporter/hash_reporter.rb +1 -3
- data/lib/haml_lint/reporter/offense_count_reporter.rb +1 -1
- data/lib/haml_lint/reporter/utils.rb +33 -4
- data/lib/haml_lint/ruby_extraction/ad_hoc_chunk.rb +24 -0
- data/lib/haml_lint/ruby_extraction/base_chunk.rb +114 -0
- data/lib/haml_lint/ruby_extraction/chunk_extractor.rb +672 -0
- data/lib/haml_lint/ruby_extraction/coordinator.rb +181 -0
- data/lib/haml_lint/ruby_extraction/haml_comment_chunk.rb +34 -0
- data/lib/haml_lint/ruby_extraction/implicit_end_chunk.rb +17 -0
- data/lib/haml_lint/ruby_extraction/interpolation_chunk.rb +26 -0
- data/lib/haml_lint/ruby_extraction/non_ruby_filter_chunk.rb +32 -0
- data/lib/haml_lint/ruby_extraction/placeholder_marker_chunk.rb +40 -0
- data/lib/haml_lint/ruby_extraction/ruby_filter_chunk.rb +33 -0
- data/lib/haml_lint/ruby_extraction/ruby_source.rb +5 -0
- data/lib/haml_lint/ruby_extraction/script_chunk.rb +251 -0
- data/lib/haml_lint/ruby_extraction/tag_attributes_chunk.rb +63 -0
- data/lib/haml_lint/ruby_extraction/tag_script_chunk.rb +30 -0
- data/lib/haml_lint/ruby_parser.rb +11 -1
- data/lib/haml_lint/runner.rb +35 -3
- data/lib/haml_lint/spec/matchers/report_lint.rb +22 -7
- data/lib/haml_lint/spec/normalize_indent.rb +2 -2
- data/lib/haml_lint/spec/shared_linter_context.rb +9 -1
- data/lib/haml_lint/spec/shared_rubocop_autocorrect_context.rb +158 -0
- data/lib/haml_lint/spec.rb +1 -0
- data/lib/haml_lint/tree/filter_node.rb +10 -0
- data/lib/haml_lint/tree/node.rb +13 -4
- data/lib/haml_lint/tree/script_node.rb +7 -1
- data/lib/haml_lint/tree/silent_script_node.rb +16 -1
- data/lib/haml_lint/tree/tag_node.rb +5 -9
- data/lib/haml_lint/utils.rb +135 -5
- data/lib/haml_lint/version.rb +1 -1
- data/lib/haml_lint/version_comparer.rb +25 -0
- data/lib/haml_lint.rb +12 -0
- metadata +29 -15
- data/lib/haml_lint/ruby_extractor.rb +0 -222
@@ -9,7 +9,7 @@ module HamlLint
|
|
9
9
|
|
10
10
|
ALLOWED_SEPARATORS = [' ', '#'].freeze
|
11
11
|
|
12
|
-
def visit_tag(node) # rubocop:disable Metrics/CyclomaticComplexity
|
12
|
+
def visit_tag(node) # rubocop:disable Metrics/CyclomaticComplexity
|
13
13
|
# If this tag has inline script
|
14
14
|
return unless node.contains_script?
|
15
15
|
|
@@ -18,15 +18,13 @@ module HamlLint
|
|
18
18
|
|
19
19
|
tag_with_text = tag_with_inline_text(node)
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
return
|
29
|
-
end
|
21
|
+
# For tags with inline text that contain interpolation, the parser
|
22
|
+
# converts them to inline script by surrounding them in string quotes,
|
23
|
+
# e.g. `%p Hello #{name}` becomes `%p= "Hello #{name}"`, causing the
|
24
|
+
# above search to fail. Check for this case by removing added quotes.
|
25
|
+
if !(index = tag_with_text.rindex(text)) && !((text_without_quotes = strip_surrounding_quotes(text)) &&
|
26
|
+
(index = tag_with_text.rindex(text_without_quotes)))
|
27
|
+
return
|
30
28
|
end
|
31
29
|
|
32
30
|
return if tag_with_text[index] == '#' # Ignore code comments
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HamlLint
|
4
|
+
# Checks for trailing empty lines.
|
5
|
+
class Linter::TrailingEmptyLines < Linter
|
6
|
+
include LinterRegistry
|
7
|
+
|
8
|
+
DummyNode = Struct.new(:line)
|
9
|
+
|
10
|
+
def visit_root(root)
|
11
|
+
return if document.source.empty?
|
12
|
+
line_number = document.last_non_empty_line
|
13
|
+
|
14
|
+
node = root.node_for_line(line_number)
|
15
|
+
return if node.disabled?(self)
|
16
|
+
|
17
|
+
return unless document.source.end_with?("\n\n")
|
18
|
+
|
19
|
+
record_lint(line_number, 'Files should not end with trailing empty lines')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -35,7 +35,7 @@ module HamlLint
|
|
35
35
|
return unless tree = parse_ruby(script_node.script)
|
36
36
|
%i[str dstr].include?(tree.type) &&
|
37
37
|
!starts_with_reserved_character?(tree.children.first)
|
38
|
-
rescue ::Parser::SyntaxError
|
38
|
+
rescue ::Parser::SyntaxError
|
39
39
|
# Gracefully ignore syntax errors, as that's managed by a different linter
|
40
40
|
end
|
41
41
|
|
data/lib/haml_lint/linter.rb
CHANGED
@@ -24,11 +24,8 @@ module HamlLint
|
|
24
24
|
# Runs the linter against the given Haml document.
|
25
25
|
#
|
26
26
|
# @param document [HamlLint::Document]
|
27
|
-
def run(document)
|
28
|
-
|
29
|
-
@lints = []
|
30
|
-
visit(document.tree)
|
31
|
-
@lints
|
27
|
+
def run(document, autocorrect: nil) # rubocop:disable Metrics
|
28
|
+
run_or_raise(document, autocorrect: autocorrect)
|
32
29
|
rescue Parser::SyntaxError => e
|
33
30
|
location = e.diagnostic.location
|
34
31
|
@lints <<
|
@@ -39,6 +36,35 @@ module HamlLint
|
|
39
36
|
e.to_s,
|
40
37
|
:error
|
41
38
|
)
|
39
|
+
rescue StandardError => e
|
40
|
+
msg = "Couldn't process the file".dup
|
41
|
+
if @autocorrect
|
42
|
+
# Those lints related to auto-correction were not saved, so don't display them
|
43
|
+
@lints = []
|
44
|
+
msg << " for autocorrect '#{@autocorrect}'. "
|
45
|
+
else
|
46
|
+
msg << ' for linting. '
|
47
|
+
end
|
48
|
+
|
49
|
+
msg << "#{e.class.name}: #{e.message}"
|
50
|
+
if ENV['HAML_LINT_DEBUG'] == 'true'
|
51
|
+
msg << "(DEBUG: Backtrace follows)\n#{e.backtrace.join("\n")}\n------"
|
52
|
+
end
|
53
|
+
|
54
|
+
@lints << HamlLint::Lint.new(self, document.file, nil, msg, :error)
|
55
|
+
@lints
|
56
|
+
end
|
57
|
+
|
58
|
+
# Runs the linter against the given Haml document, raises if the file cannot be processed due to
|
59
|
+
# Syntax or HAML-Lint internal errors. (For testing purposes)
|
60
|
+
#
|
61
|
+
# @param document [HamlLint::Document]
|
62
|
+
def run_or_raise(document, autocorrect: nil)
|
63
|
+
@document = document
|
64
|
+
@lints = []
|
65
|
+
@autocorrect = autocorrect
|
66
|
+
visit(document.tree)
|
67
|
+
@lints
|
42
68
|
end
|
43
69
|
|
44
70
|
# Returns the simple name for this linter.
|
@@ -48,25 +74,49 @@ module HamlLint
|
|
48
74
|
self.class.name.to_s.split('::').last
|
49
75
|
end
|
50
76
|
|
77
|
+
# Returns true if this linter supports autocorrect, false otherwise
|
78
|
+
#
|
79
|
+
# @return [Boolean]
|
80
|
+
def self.supports_autocorrect?
|
81
|
+
@supports_autocorrect || false
|
82
|
+
end
|
83
|
+
|
84
|
+
def supports_autocorrect?
|
85
|
+
self.class.supports_autocorrect?
|
86
|
+
end
|
87
|
+
|
51
88
|
private
|
52
89
|
|
53
90
|
attr_reader :config, :document
|
54
91
|
|
92
|
+
# Linters can call supports_autocorrect(true) in their top-level scope to indicate that
|
93
|
+
# they supports autocorrect.
|
94
|
+
#
|
95
|
+
# @params value [Boolean] The new value for supports_autocorrect
|
96
|
+
private_class_method def self.supports_autocorrect(value)
|
97
|
+
@supports_autocorrect = value
|
98
|
+
end
|
99
|
+
|
55
100
|
# Record a lint for reporting back to the user.
|
56
101
|
#
|
57
|
-
# @param
|
102
|
+
# @param node_or_line [#line] line number or node to extract the line number from
|
58
103
|
# @param message [String] error/warning to display to the user
|
59
|
-
def record_lint(
|
60
|
-
|
61
|
-
|
104
|
+
def record_lint(node_or_line, message, corrected: false)
|
105
|
+
line = node_or_line.is_a?(Integer) ? node_or_line : node_or_line.line
|
106
|
+
@lints << HamlLint::Lint.new(self, @document.file, line, message,
|
107
|
+
config.fetch('severity', :warning).to_sym,
|
108
|
+
corrected: corrected)
|
62
109
|
end
|
63
110
|
|
64
111
|
# Parse Ruby code into an abstract syntax tree.
|
65
112
|
#
|
66
113
|
# @return [AST::Node]
|
67
114
|
def parse_ruby(source)
|
115
|
+
self.class.ruby_parser.parse(source)
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.ruby_parser # rubocop:disable Lint/IneffectiveAccessModifier
|
68
119
|
@ruby_parser ||= HamlLint::RubyParser.new
|
69
|
-
@ruby_parser.parse(source)
|
70
120
|
end
|
71
121
|
|
72
122
|
# Remove the surrounding double quotes from a string, ignoring any
|
@@ -27,11 +27,9 @@ module HamlLint
|
|
27
27
|
# @return [Array<Class>]
|
28
28
|
def extract_linters_from(linter_names)
|
29
29
|
linter_names.map do |linter_name|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
raise NoSuchLinter, "Linter #{linter_name} does not exist"
|
34
|
-
end
|
30
|
+
HamlLint::Linter.const_get(linter_name)
|
31
|
+
rescue NameError
|
32
|
+
raise NoSuchLinter, "Linter #{linter_name} does not exist"
|
35
33
|
end
|
36
34
|
end
|
37
35
|
end
|
data/lib/haml_lint/logger.rb
CHANGED
@@ -30,7 +30,7 @@ module HamlLint
|
|
30
30
|
#
|
31
31
|
# @param output [String] the output to send
|
32
32
|
# @param newline [true,false] whether to append a newline
|
33
|
-
def log(output, newline = true)
|
33
|
+
def log(output, newline = true) # rubocop:disable Style/OptionalBooleanParameter
|
34
34
|
@out.print(output)
|
35
35
|
@out.print("\n") if newline
|
36
36
|
end
|
@@ -97,7 +97,7 @@ module HamlLint
|
|
97
97
|
|
98
98
|
private
|
99
99
|
|
100
|
-
def color(code, output, newline = true)
|
100
|
+
def color(code, output, newline = true) # rubocop:disable Style/OptionalBooleanParameter
|
101
101
|
log(color_enabled ? "\033[#{code}m#{output}\033[0m" : output, newline)
|
102
102
|
end
|
103
103
|
end
|
data/lib/haml_lint/options.rb
CHANGED
@@ -32,7 +32,7 @@ module HamlLint
|
|
32
32
|
|
33
33
|
private
|
34
34
|
|
35
|
-
def add_linter_options(parser)
|
35
|
+
def add_linter_options(parser) # rubocop:disable Metrics/MethodLength
|
36
36
|
parser.on('--auto-gen-config', 'Generate a configuration file acting as a TODO list') do
|
37
37
|
@options[:auto_gen_config] = true
|
38
38
|
end
|
@@ -55,6 +55,20 @@ module HamlLint
|
|
55
55
|
parser.on('-p', '--parallel', 'Run linters in parallel using available CPUs') do
|
56
56
|
@options[:parallel] = true
|
57
57
|
end
|
58
|
+
|
59
|
+
parser.on('-a', '--auto-correct', 'Auto-correct offenses (only when it’s safe)') do
|
60
|
+
@options[:autocorrect] = :safe
|
61
|
+
end
|
62
|
+
|
63
|
+
parser.on('-A', '--auto-correct-all', 'Auto-correct offenses (safe and unsafe)') do
|
64
|
+
@options[:autocorrect] = :all
|
65
|
+
end
|
66
|
+
|
67
|
+
parser.on('--auto-correct-only', "Only do auto-correct, don't lint. " \
|
68
|
+
'Also activates safe auto-correct if no auto-correct is selected') do
|
69
|
+
@options[:autocorrect_only] = true
|
70
|
+
@options[:autocorrect] ||= :safe
|
71
|
+
end
|
58
72
|
end
|
59
73
|
|
60
74
|
def add_report_options(parser)
|
@@ -99,7 +113,7 @@ module HamlLint
|
|
99
113
|
end
|
100
114
|
end
|
101
115
|
|
102
|
-
def add_info_options(parser)
|
116
|
+
def add_info_options(parser) # rubocop:disable Metrics/MethodLength
|
103
117
|
parser.on('--show-linters', 'Display available linters') do
|
104
118
|
@options[:show_linters] = true
|
105
119
|
end
|
@@ -108,6 +122,16 @@ module HamlLint
|
|
108
122
|
@options[:show_reporters] = true
|
109
123
|
end
|
110
124
|
|
125
|
+
parser.on('-d', '--debug', 'Add some debug information to messages') do
|
126
|
+
@options[:debug] = true
|
127
|
+
end
|
128
|
+
|
129
|
+
parser.on('--internal-debug', 'Add lots of (internal) debug information.' \
|
130
|
+
" Also affects some lint's line numbers to skip sourcemap") do
|
131
|
+
@options[:debug] = true
|
132
|
+
@options[:internal_debug] = true
|
133
|
+
end
|
134
|
+
|
111
135
|
parser.on_tail('-h', '--help', 'Display help documentation') do
|
112
136
|
@options[:help] = parser.help
|
113
137
|
end
|
data/lib/haml_lint/rake_task.rb
CHANGED
@@ -104,7 +104,7 @@ module HamlLint
|
|
104
104
|
# @param task_args [Rake::TaskArguments]
|
105
105
|
def run_cli(task_args)
|
106
106
|
cli_args = parse_args
|
107
|
-
logger = quiet ? HamlLint::Logger.silent : HamlLint::Logger.new(
|
107
|
+
logger = quiet ? HamlLint::Logger.silent : HamlLint::Logger.new($stdout)
|
108
108
|
result = HamlLint::CLI.new(logger).run(Array(cli_args) + files_to_lint(task_args))
|
109
109
|
|
110
110
|
fail "#{HamlLint::APP_NAME} failed with exit code #{result}" unless result == 0
|
@@ -115,7 +115,7 @@ module HamlLint
|
|
115
115
|
#
|
116
116
|
# @param task_args [Rake::TaskArguments]
|
117
117
|
def files_to_lint(task_args)
|
118
|
-
#
|
118
|
+
# NOTE: we're abusing Rake's argument handling a bit here. We call the
|
119
119
|
# first argument `files` but it's actually only the first file--we pull
|
120
120
|
# the rest out of the `extras` from the task arguments. This is so we
|
121
121
|
# can specify an arbitrary list of files separated by commas on the
|
@@ -14,7 +14,7 @@ module HamlLint
|
|
14
14
|
lints = report.lints
|
15
15
|
grouped = lints.group_by(&:filename)
|
16
16
|
|
17
|
-
|
17
|
+
{
|
18
18
|
metadata: metadata,
|
19
19
|
files: grouped.map { |l| map_file(l) },
|
20
20
|
summary: {
|
@@ -23,8 +23,6 @@ module HamlLint
|
|
23
23
|
inspected_file_count: report.files.length,
|
24
24
|
},
|
25
25
|
}
|
26
|
-
|
27
|
-
report_hash
|
28
26
|
end
|
29
27
|
|
30
28
|
private
|
@@ -10,7 +10,7 @@ module HamlLint
|
|
10
10
|
return if total_count.zero?
|
11
11
|
|
12
12
|
lints.group_by { |l| lint_type_group(l) }
|
13
|
-
.
|
13
|
+
.transform_values(&:size)
|
14
14
|
.sort_by { |_linter, lint_count| -lint_count }
|
15
15
|
.each do |linter, lint_count|
|
16
16
|
log.log "#{lint_count.to_s.ljust(total_count.to_s.length + 2)} #{linter}"
|
@@ -56,6 +56,10 @@ module HamlLint
|
|
56
56
|
# @param lint [HamlLint::Lint] the lint to print
|
57
57
|
# @return [void]
|
58
58
|
def print_message(lint)
|
59
|
+
if lint.corrected
|
60
|
+
log.success('[Corrected] ', false)
|
61
|
+
end
|
62
|
+
|
59
63
|
if lint.linter
|
60
64
|
log.success("#{lint.linter.name}: ", false)
|
61
65
|
end
|
@@ -70,10 +74,15 @@ module HamlLint
|
|
70
74
|
def print_summary(report)
|
71
75
|
return unless log.summary_enabled
|
72
76
|
|
77
|
+
log.log('')
|
73
78
|
print_summary_files(report)
|
74
|
-
print_summary_lints(report)
|
75
79
|
|
76
|
-
|
80
|
+
print_summary_lints(report, is_append: true)
|
81
|
+
|
82
|
+
log.log ' detected', false
|
83
|
+
|
84
|
+
print_summary_corrected_lints(report, is_append: true)
|
85
|
+
log.log ''
|
77
86
|
end
|
78
87
|
|
79
88
|
# Prints a summary of the number of files linted in a report.
|
@@ -81,14 +90,17 @@ module HamlLint
|
|
81
90
|
# @param report [HamlLint::Report] the report to print
|
82
91
|
# @return [void]
|
83
92
|
def print_summary_files(report)
|
84
|
-
log.log "
|
93
|
+
log.log "#{pluralize('file', count: report.files.count)} inspected", false
|
85
94
|
end
|
86
95
|
|
87
96
|
# Prints a summary of the number of lints found in a report.
|
88
97
|
#
|
89
98
|
# @param report [HamlLint::Report] the report to print
|
99
|
+
# @param is_append [Boolean] if this is appending to a line. Will preffix with ", ".
|
90
100
|
# @return [void]
|
91
|
-
def print_summary_lints(report)
|
101
|
+
def print_summary_lints(report, is_append:)
|
102
|
+
log.log ', ', false if is_append
|
103
|
+
|
92
104
|
lint_count = report.lints.size
|
93
105
|
lint_message = pluralize('lint', count: lint_count)
|
94
106
|
|
@@ -98,6 +110,23 @@ module HamlLint
|
|
98
110
|
log.error lint_message, false
|
99
111
|
end
|
100
112
|
end
|
113
|
+
|
114
|
+
# Prints a summary of the number of lints corrected in a report.
|
115
|
+
#
|
116
|
+
# @param report [HamlLint::Report] the report to print
|
117
|
+
# @param is_append [Boolean] if this is appending to a line. Will preffix with ", ".
|
118
|
+
# @return [void]
|
119
|
+
def print_summary_corrected_lints(report, is_append:)
|
120
|
+
lint_count = report.lints.count(&:corrected)
|
121
|
+
return if lint_count == 0
|
122
|
+
|
123
|
+
log.log ', ', false if is_append
|
124
|
+
|
125
|
+
lint_message = pluralize('lint', count: lint_count)
|
126
|
+
|
127
|
+
log.info lint_message, false
|
128
|
+
log.log ' corrected', false
|
129
|
+
end
|
101
130
|
end
|
102
131
|
end
|
103
132
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HamlLint::RubyExtraction
|
4
|
+
# This chunk just adds its code to the ruby, but does not attempt to transfer their correction
|
5
|
+
# in any way.
|
6
|
+
#
|
7
|
+
# Used for piece of code that just need to be in the generated ruby for reasons specific to
|
8
|
+
# the use cases, such as needing a `begin` to do add indentation.
|
9
|
+
class AdHocChunk < BaseChunk
|
10
|
+
def initialize(*args, **kwargs)
|
11
|
+
super(*args, **kwargs.merge(end_marker_indent: nil))
|
12
|
+
end
|
13
|
+
|
14
|
+
def wrap_in_markers
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def transfer_correction(coordinator, all_corrected_ruby_lines, haml_lines); end
|
19
|
+
|
20
|
+
def skip_line_indexes_in_source_map
|
21
|
+
(0...@ruby_lines.size).to_a
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HamlLint::RubyExtraction
|
4
|
+
# This is the base class for all of the Chunks of HamlLint::RubyExtraction.
|
5
|
+
# A Chunk represents a part of the HAML file that HamlLint::Linter::RuboCop
|
6
|
+
# is processing and will insert some Ruby code in a file passed to RuboCop.
|
7
|
+
#
|
8
|
+
# There are chunks for most HAML concepts, even if they don't represent Ruby
|
9
|
+
# code. For example, there is a chunk that represents a `%div` tag, which
|
10
|
+
# uses a `begin` in the generated Ruby to add indentation for the children
|
11
|
+
# of the %div in the Ruby file just like there is in the HAML file.
|
12
|
+
class BaseChunk
|
13
|
+
COMMA_CHANGES_LINES = true
|
14
|
+
|
15
|
+
# @return [HamlLint::Tree::Node] Haml node that this comes from
|
16
|
+
attr_reader :node
|
17
|
+
|
18
|
+
# @return [Integer] First line index of the auto-correctable code in the Haml source
|
19
|
+
# Usually same as node.line - 1, but some cases, such as interpolation in a filter will
|
20
|
+
# will be different.
|
21
|
+
attr_reader :haml_line_index
|
22
|
+
|
23
|
+
# @return [Integer] Line number of the line marker in the ruby source placed before
|
24
|
+
# this auto-correctable code
|
25
|
+
attr_reader :start_marker_line_number
|
26
|
+
|
27
|
+
# @return [Integer] The indentation (number of spaces) to use to index the marker
|
28
|
+
# that follows this chunk. Unlike the marker before, this one can vary.
|
29
|
+
attr_reader :end_marker_indent
|
30
|
+
|
31
|
+
# @return [Array<String>] The ruby lines that this chunk will insert
|
32
|
+
attr_reader :ruby_lines
|
33
|
+
|
34
|
+
def initialize(node,
|
35
|
+
ruby_lines,
|
36
|
+
end_marker_indent:, haml_line_index: node.line - 1)
|
37
|
+
ruby_lines = [ruby_lines] if ruby_lines.is_a?(String)
|
38
|
+
@node = node
|
39
|
+
@ruby_lines = ruby_lines
|
40
|
+
@haml_line_index = haml_line_index
|
41
|
+
@end_marker_indent = end_marker_indent
|
42
|
+
end
|
43
|
+
|
44
|
+
# To be overridden in subclasses.
|
45
|
+
# Return a new chunk which is the result of fusing self with the given following chunk.
|
46
|
+
# If no fusion is possible, returns nil
|
47
|
+
def fuse(_following_chunk)
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
# Overwrites haml_lines to match the Ruby code that was corrected by RuboCop which is in
|
52
|
+
# all_corrected_ruby_lines. This can change non-ruby parts to, especially for
|
53
|
+
# indentation.
|
54
|
+
#
|
55
|
+
# This will be called on ruby chunks in the reverse order they were created. Two benefits
|
56
|
+
# of this approach:
|
57
|
+
# * No need to track when lines in haml_lines are moved to apply changes later in the file
|
58
|
+
# * When fixing indentation of lines that follow a corrected line, those following lines will
|
59
|
+
# already have been corrected and so require nothing.
|
60
|
+
# Can be overridden by subclasses to make it do nothing
|
61
|
+
def transfer_correction(coordinator, _all_corrected_ruby_lines, haml_lines)
|
62
|
+
to_ruby_lines = coordinator.extract_from_corrected_lines(@start_marker_line_number, @ruby_lines.size)
|
63
|
+
transfer_correction_logic(coordinator, to_ruby_lines, haml_lines)
|
64
|
+
end
|
65
|
+
|
66
|
+
# To be overriden by subclasses.
|
67
|
+
#
|
68
|
+
# Logic to transfer the corrections that turned from_ruby_lines into to_ruby_lines.
|
69
|
+
#
|
70
|
+
# This method only received the ruby code that belongs to this chunk. (It was
|
71
|
+
# extracted using #extract_from by #transfer_correction)
|
72
|
+
def transfer_correction_logic(_coordinator, _to_ruby_lines, _haml_lines)
|
73
|
+
raise "Implement #transfer_correction_logic in #{self.class.name}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def start_marker_indent
|
77
|
+
ruby_lines.first[/ */].size
|
78
|
+
end
|
79
|
+
|
80
|
+
def haml_end_line_index
|
81
|
+
# the .max is needed to handle cases with 0 nb_haml_lines
|
82
|
+
[@haml_line_index + nb_haml_lines - 1, @haml_line_index].max
|
83
|
+
end
|
84
|
+
|
85
|
+
def nb_haml_lines
|
86
|
+
@ruby_lines.size - skip_line_indexes_in_source_map.size
|
87
|
+
end
|
88
|
+
|
89
|
+
def full_assemble(coordinator)
|
90
|
+
if wrap_in_markers
|
91
|
+
@start_marker_line_number = coordinator.add_marker(start_marker_indent,
|
92
|
+
haml_line_index: haml_line_index)
|
93
|
+
assemble_in(coordinator)
|
94
|
+
coordinator.add_marker(@end_marker_indent, haml_line_index: haml_end_line_index)
|
95
|
+
else
|
96
|
+
assemble_in(coordinator)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def assemble_in(coordinator)
|
101
|
+
coordinator.add_lines(@ruby_lines,
|
102
|
+
haml_line_index: haml_line_index,
|
103
|
+
skip_indexes_in_source_map: skip_line_indexes_in_source_map)
|
104
|
+
end
|
105
|
+
|
106
|
+
def skip_line_indexes_in_source_map
|
107
|
+
[]
|
108
|
+
end
|
109
|
+
|
110
|
+
def wrap_in_markers
|
111
|
+
true
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|