haml_lint 0.40.0 → 0.51.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/bin/haml-lint +1 -1
  3. data/config/default.yml +9 -27
  4. data/config/forced_rubocop_config.yml +180 -0
  5. data/lib/haml_lint/adapter/haml_4.rb +20 -0
  6. data/lib/haml_lint/adapter/haml_5.rb +11 -0
  7. data/lib/haml_lint/adapter/haml_6.rb +59 -0
  8. data/lib/haml_lint/adapter.rb +2 -0
  9. data/lib/haml_lint/cli.rb +8 -3
  10. data/lib/haml_lint/configuration_loader.rb +49 -13
  11. data/lib/haml_lint/document.rb +89 -8
  12. data/lib/haml_lint/exceptions.rb +6 -0
  13. data/lib/haml_lint/extensions/haml_util_unescape_interpolation_tracking.rb +35 -0
  14. data/lib/haml_lint/file_finder.rb +2 -2
  15. data/lib/haml_lint/lint.rb +10 -1
  16. data/lib/haml_lint/linter/final_newline.rb +4 -3
  17. data/lib/haml_lint/linter/implicit_div.rb +1 -1
  18. data/lib/haml_lint/linter/indentation.rb +3 -3
  19. data/lib/haml_lint/linter/no_placeholders.rb +18 -0
  20. data/lib/haml_lint/linter/repeated_id.rb +2 -1
  21. data/lib/haml_lint/linter/rubocop.rb +353 -59
  22. data/lib/haml_lint/linter/space_before_script.rb +8 -10
  23. data/lib/haml_lint/linter/trailing_empty_lines.rb +22 -0
  24. data/lib/haml_lint/linter/unnecessary_string_output.rb +1 -1
  25. data/lib/haml_lint/linter/view_length.rb +1 -1
  26. data/lib/haml_lint/linter.rb +60 -10
  27. data/lib/haml_lint/linter_registry.rb +3 -5
  28. data/lib/haml_lint/logger.rb +2 -2
  29. data/lib/haml_lint/options.rb +26 -2
  30. data/lib/haml_lint/rake_task.rb +2 -2
  31. data/lib/haml_lint/reporter/hash_reporter.rb +1 -3
  32. data/lib/haml_lint/reporter/offense_count_reporter.rb +1 -1
  33. data/lib/haml_lint/reporter/utils.rb +33 -4
  34. data/lib/haml_lint/ruby_extraction/ad_hoc_chunk.rb +24 -0
  35. data/lib/haml_lint/ruby_extraction/base_chunk.rb +114 -0
  36. data/lib/haml_lint/ruby_extraction/chunk_extractor.rb +672 -0
  37. data/lib/haml_lint/ruby_extraction/coordinator.rb +181 -0
  38. data/lib/haml_lint/ruby_extraction/haml_comment_chunk.rb +34 -0
  39. data/lib/haml_lint/ruby_extraction/implicit_end_chunk.rb +17 -0
  40. data/lib/haml_lint/ruby_extraction/interpolation_chunk.rb +26 -0
  41. data/lib/haml_lint/ruby_extraction/non_ruby_filter_chunk.rb +32 -0
  42. data/lib/haml_lint/ruby_extraction/placeholder_marker_chunk.rb +40 -0
  43. data/lib/haml_lint/ruby_extraction/ruby_filter_chunk.rb +33 -0
  44. data/lib/haml_lint/ruby_extraction/ruby_source.rb +5 -0
  45. data/lib/haml_lint/ruby_extraction/script_chunk.rb +251 -0
  46. data/lib/haml_lint/ruby_extraction/tag_attributes_chunk.rb +63 -0
  47. data/lib/haml_lint/ruby_extraction/tag_script_chunk.rb +30 -0
  48. data/lib/haml_lint/ruby_parser.rb +11 -1
  49. data/lib/haml_lint/runner.rb +35 -3
  50. data/lib/haml_lint/spec/matchers/report_lint.rb +22 -7
  51. data/lib/haml_lint/spec/normalize_indent.rb +2 -2
  52. data/lib/haml_lint/spec/shared_linter_context.rb +9 -1
  53. data/lib/haml_lint/spec/shared_rubocop_autocorrect_context.rb +158 -0
  54. data/lib/haml_lint/spec.rb +1 -0
  55. data/lib/haml_lint/tree/filter_node.rb +10 -0
  56. data/lib/haml_lint/tree/node.rb +13 -4
  57. data/lib/haml_lint/tree/script_node.rb +7 -1
  58. data/lib/haml_lint/tree/silent_script_node.rb +16 -1
  59. data/lib/haml_lint/tree/tag_node.rb +5 -9
  60. data/lib/haml_lint/utils.rb +135 -5
  61. data/lib/haml_lint/version.rb +1 -1
  62. data/lib/haml_lint/version_comparer.rb +25 -0
  63. data/lib/haml_lint.rb +12 -0
  64. metadata +29 -15
  65. 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, Metrics/PerceivedComplexity
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
- unless index = tag_with_text.rindex(text)
22
- # For tags with inline text that contain interpolation, the parser
23
- # converts them to inline script by surrounding them in string quotes,
24
- # e.g. `%p Hello #{name}` becomes `%p= "Hello #{name}"`, causing the
25
- # above search to fail. Check for this case by removing added quotes.
26
- unless (text_without_quotes = strip_surrounding_quotes(text)) &&
27
- (index = tag_with_text.rindex(text_without_quotes))
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 # rubocop:disable Lint/SuppressedException
38
+ rescue ::Parser::SyntaxError
39
39
  # Gracefully ignore syntax errors, as that's managed by a different linter
40
40
  end
41
41
 
@@ -11,7 +11,7 @@ module HamlLint
11
11
 
12
12
  def visit_root(root)
13
13
  max = config['max']
14
- line_count = document.source_lines.count
14
+ line_count = document.last_non_empty_line
15
15
  node = root.children.first
16
16
 
17
17
  if line_count > max && !node.disabled?(self)
@@ -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
- @document = document
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 node [#line] node to extract the line number from
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(node, message)
60
- @lints << HamlLint::Lint.new(self, @document.file, node.line, message,
61
- config.fetch('severity', :warning).to_sym)
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
- begin
31
- HamlLint::Linter.const_get(linter_name)
32
- rescue NameError
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
@@ -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
@@ -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
@@ -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(STDOUT)
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
- # Note: we're abusing Rake's argument handling a bit here. We call the
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
- report_hash = {
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
- .map { |linter, lints_for_this_linter| [linter, lints_for_this_linter.size] }.to_h
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
- log.log ' detected'
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 "\n#{pluralize('file', count: report.files.count)} inspected, ", false
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