Class: RBI::Rewriters::SortNodes

Inherits:
Visitor
  • Object
show all
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

: (Node? node) -> void



9
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
# File 'lib/rbi/rewriters/sort_nodes.rb', line 9

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