Class: RBI::Rewriters::SortNodes

Inherits:
Visitor
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/rbi/rewriters/sort_nodes.rb

Instance Method Summary collapse

Methods inherited from Visitor

#visit_all, #visit_file

Instance Method Details

#visit(node) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/rbi/rewriters/sort_nodes.rb', line 10

def visit(node)
  sort_node_names!(node) if node

  return unless node.is_a?(Tree)

  visit_all(node.nodes)
  original_order = node.nodes.map.with_index.to_h

  # The child nodes could contain private/protected markers. If so, they should not be moved in the file.
  # Otherwise, some methods could see their privacy change. To avoid that problem, divide the array of child
  # nodes into chunks based on whether any Visibility nodes appear, and sort the chunks independently. This
  # applies the ordering rules from the node_rank method as much as possible, while preserving visibility.
  sorted_nodes = node.nodes.chunk do |n|
    n.is_a?(Visibility)
  end.flat_map do |_, nodes|
    nodes.sort! do |a, b|
      # First we try to compare the nodes by their node rank (based on the node type)
      res = node_rank(a) <=> node_rank(b)
      next res if res != 0 # we can sort the nodes by their rank, let's stop here

      # Then, if the nodes ranks are the same (res == 0), we try to compare the nodes by their name
      res = node_name(a) <=> node_name(b)
      next res if res && res != 0 # we can sort the nodes by their name, let's stop here

      # Finally, if the two nodes have the same rank and the same name or at least one node is anonymous then,
      T.must(original_order[a]) <=> T.must(original_order[b]) # we keep the original order
    end
  end

  node.nodes.replace(sorted_nodes)
end