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.
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