Module: SimpleCov::Formatter::AIFormatter::MarkdownBuilder::SnippetFormatter

Extended by:
T::Sig
Included in:
DeficitFormatter
Defined in:
lib/simplecov-ai/markdown_builder/snippet_formatter.rb

Overview

Handles extraction and formatting of source code snippets for the markdown digest.

Constant Summary collapse

ESTIMATED_CHARS_PER_LINE =

Approximate maximum characters per line for truncation calculation

T.let(80, Integer)
TRUNCATION_ELLIPSIS =

Suffix added to truncated snippets

T.let('...', String)
OCCURRENCE_TEMPLATE =

Template for identical snippet occurrences indicator

T.let('(Occurrence %d of %d).', String)

Instance Method Summary collapse

Instance Method Details

#build_occurrence_index(node, source_lines) ⇒ Object



172
173
174
175
176
177
178
179
180
181
# File 'lib/simplecov-ai/markdown_builder/snippet_formatter.rb', line 172

def build_occurrence_index(node, source_lines)
  index = T.let({}, T::Hash[String, T::Array[Integer]])
  (node.start_line..node.end_line).each do |line_number|
    content = source_lines.at(line_number - 1)&.strip
    next if content.nil? || content.empty?

    (index[content] ||= []) << line_number
  end
  index
end

#byte_slice(line_text, start_col, end_col) ⇒ Object



42
43
44
45
46
47
48
49
50
# File 'lib/simplecov-ai/markdown_builder/snippet_formatter.rb', line 42

def byte_slice(line_text, start_col, end_col)
  bytes = line_text.b
  return nil unless bytes.length >= end_col

  slice = bytes[start_col...end_col]
  return '' unless slice

  slice.force_encoding(line_text.encoding).scrub
end

#calculate_occurrence(line_num, source_lines, node) ⇒ Object



141
142
143
144
145
146
147
148
149
150
# File 'lib/simplecov-ai/markdown_builder/snippet_formatter.rb', line 141

def calculate_occurrence(line_num, source_lines, node)
  return '' if node.nil?

  snippet = source_lines.at(line_num - 1).to_s.strip
  positions = occurrence_index(node, source_lines).fetch(snippet, [])
  return '' unless positions.size > 1

  ordinal = T.must(positions.index(line_num)) + 1
  Kernel.format(OCCURRENCE_TEMPLATE, ordinal, positions.size)
end

#extract_branch_text(branch, source_lines, columns) ⇒ Object



79
80
81
82
83
84
# File 'lib/simplecov-ai/markdown_builder/snippet_formatter.rb', line 79

def extract_branch_text(branch, source_lines, columns)
  inline_text = extract_inline_branch(branch, columns, source_lines)
  return inline_text if inline_text

  fetch_snippet_text((branch.start_line..branch.end_line).to_a, source_lines)
end

#extract_inline_branch(branch, columns, source_lines) ⇒ Object



97
98
99
100
101
102
103
104
105
# File 'lib/simplecov-ai/markdown_builder/snippet_formatter.rb', line 97

def extract_inline_branch(branch, columns, source_lines)
  return nil unless columns && branch.start_line == branch.end_line

  line_text = source_lines.at(branch.start_line - 1)
  return nil unless line_text

  start_col, end_col = columns
  byte_slice(line_text, start_col, end_col)&.strip
end

#fetch_snippet_text(line_nums, source_lines) ⇒ Object



25
26
27
28
29
30
# File 'lib/simplecov-ai/markdown_builder/snippet_formatter.rb', line 25

def fetch_snippet_text(line_nums, source_lines)
  line_nums.select(&:positive?)
           .filter_map { |line_number| source_lines.at(line_number - 1)&.strip }
           .reject(&:empty?)
           .join(' ')
end

#first_source_line(branch, source_lines) ⇒ Object



113
114
115
116
117
118
119
# File 'lib/simplecov-ai/markdown_builder/snippet_formatter.rb', line 113

def first_source_line(branch, source_lines)
  (branch.start_line..branch.end_line).each do |line_number|
    text = fetch_snippet_text([line_number], source_lines)
    return text unless text.empty?
  end
  ''
end

#line_label(start_line, end_line) ⇒ Object



127
128
129
# File 'lib/simplecov-ai/markdown_builder/snippet_formatter.rb', line 127

def line_label(start_line, end_line)
  start_line == end_line ? start_line.to_s : "#{start_line}-#{end_line}"
end

#occurrence_index(node, source_lines) ⇒ Object



160
161
162
163
164
165
166
# File 'lib/simplecov-ai/markdown_builder/snippet_formatter.rb', line 160

def occurrence_index(node, source_lines)
  cache = (@occurrence_index ||= T.let(
    {}.compare_by_identity,
    T.nilable(T::Hash[ASTResolver::SemanticNode, T::Hash[String, T::Array[Integer]]])
  ))
  cache[node] ||= build_occurrence_index(node, source_lines)
end

#truncate_snippet(snippet_text, max_snippet_lines) ⇒ Object



58
59
60
61
62
63
64
65
# File 'lib/simplecov-ai/markdown_builder/snippet_formatter.rb', line 58

def truncate_snippet(snippet_text, max_snippet_lines)
  max_chars = max_snippet_lines * ESTIMATED_CHARS_PER_LINE
  if snippet_text.length > max_chars
    "#{snippet_text[0, max_chars]}#{TRUNCATION_ELLIPSIS}"
  else
    snippet_text
  end
end