class RuboCop::Cop::Sorbet::SignatureBuildOrder

Constants

ORDER

Public Instance Methods

autocorrect(node) click to toggle source
# File lib/rubocop/cop/sorbet/signatures/signature_build_order.rb, line 54
def autocorrect(node)
  return nil unless can_autocorrect?

  lambda do |corrector|
    tree = call_chain(node_reparsed_with_modern_features(node))
      .sort_by { |call| ORDER[call.method_name] }
      .reduce(nil) do |receiver, caller|
        caller.updated(nil, [receiver] + caller.children.drop(1))
      end

    corrector.replace(
      node.source_range,
      Unparser.unparse(tree),
    )
  end
end
on_signature(node) click to toggle source
# File lib/rubocop/cop/sorbet/signatures/signature_build_order.rb, line 34
def on_signature(node)
  calls = call_chain(node.children[2]).map(&:method_name)
  return unless calls.any?

  expected_order = calls.sort_by { |call| ORDER[call] }
  return if expected_order == calls

  message = "Sig builders must be invoked in the following order: #{expected_order.join(', ')}."

  unless can_autocorrect?
    message += ' For autocorrection, add the `unparser` gem to your project.'
  end

  add_offense(
    node.children[2],
    message: message,
  )
  node
end

Private Instance Methods

call_chain(sig_child_node) click to toggle source
# File lib/rubocop/cop/sorbet/signatures/signature_build_order.rb, line 96
def call_chain(sig_child_node)
  call_node = root_call(sig_child_node).first
  return [] unless call_node

  calls = []
  while call_node != sig_child_node
    calls << call_node
    call_node = call_node.parent
  end

  calls << sig_child_node

  calls
end
can_autocorrect?() click to toggle source
# File lib/rubocop/cop/sorbet/signatures/signature_build_order.rb, line 92
def can_autocorrect?
  defined?(::Unparser)
end
node_reparsed_with_modern_features(node) click to toggle source

This method exists to reparse the current node with modern features enabled. Modern features include “index send” emitting, which is necessary to unparse “index sends” (i.e. `[]` calls) back to index accessors (i.e. as `foo“). Otherwise, we would get the unparsed node as `foo.[](bar)`.

# File lib/rubocop/cop/sorbet/signatures/signature_build_order.rb, line 83
def node_reparsed_with_modern_features(node)
  # Create a new parser with a modern builder class instance
  parser = Parser::CurrentRuby.new(ModernBuilder.new)
  # Create a new source buffer with the node source
  buffer = Parser::Source::Buffer.new(processed_source.path, source: node.source)
  # Re-parse the buffer
  parser.parse(buffer)
end