class RuboCop::Cop::Sorbet::EmptyLineAfterSig

def foo; end
sig { void }
# good
def foo; end
sig { void }
# bad
@example
Checks for blank lines after signatures.

def contains_only_rubocop_directives?(range)

def contains_only_rubocop_directives?(range)
  range.source.lines.all? { |line| line.strip.start_with?("# rubocop:") }
end

def lines_between(node1, node2, buffer: processed_source.buffer)

def lines_between(node1, node2, buffer: processed_source.buffer)
  end_of_node1_pos   = node1.source_range.end_pos
  start_of_node2_pos = node2.source_range.begin_pos
  string_in_between = buffer.slice(end_of_node1_pos...start_of_node2_pos)
  # Fallbacks handle same line edge case
  begin_offset = string_in_between.index("\n")  || 0
  end_offset   = string_in_between.rindex("\n") || string_in_between.length - 1
  Parser::Source::Range.new(
    buffer,
    end_of_node1_pos + begin_offset + 1, # +1 to exclude post-node1 newline
    end_of_node1_pos + end_offset   + 1, # +1 to include pre-node2  newline
  )
end

def next_sibling(node)

def next_sibling(node)
  node.parent&.children&.at(node.sibling_index + 1)
end

def on_signature(sig)

def on_signature(sig)
  sig_or_signable_method_definition?(next_sibling(sig)) do |definition|
    range = lines_between(sig, definition)
    next if range.empty? || range.single_line? || contains_only_rubocop_directives?(range)
    add_offense(range) do |corrector|
      lines = range.source.lines
      rubocop_lines, other_lines = lines.partition { |line| line.strip.start_with?("# rubocop:") }
      unless other_lines.empty?
        corrector.insert_before(
          range_by_whole_lines(sig.source_range),
          other_lines.join
            .sub(/\A\n+/, "") # remove initial newline(s)
            .gsub(/\n{2,}/, "\n"), # remove empty line(s)
        )
      end
      corrector.replace(range, rubocop_lines.empty? ? "" : rubocop_lines.join)
    end
  end
end