Module: YARDSorbet::NodeUtils

Extended by:
T::Sig
Defined in:
lib/yard-sorbet/node_utils.rb

Overview

Helper methods for working with YARD AST Nodes

Constant Summary collapse

ATTRIBUTE_METHODS =

Command node types that can have type signatures

T.let(%i[attr attr_accessor attr_reader attr_writer].freeze, T::Array[Symbol])
SKIP_METHOD_CONTENTS =

Skip these method contents during BFS node traversal, they can have their own nested types via T.Proc

T.let(%i[params returns].freeze, T::Array[Symbol])
SigableNode =

Node types that can have type signatures

T.type_alias { T.any(YARD::Parser::Ruby::MethodDefinitionNode, YARD::Parser::Ruby::MethodCallNode) }

Class Method Summary collapse

Class Method Details

.bfs_traverse(node, &_blk) {|YARD::Parser::Ruby::AstNode| ... } ⇒ void

Note:

This will skip over some node types.

This method returns an undefined value.

Traverse AST nodes in breadth-first order

Parameters:

  • node (YARD::Parser::Ruby::AstNode)
  • _blk (T.proc.params(n: YARD::Parser::Ruby::AstNode).void)

Yields:

  • (YARD::Parser::Ruby::AstNode)


21
22
23
24
25
26
27
28
# File 'lib/yard-sorbet/node_utils.rb', line 21

def self.bfs_traverse(node, &_blk)
  queue = Queue.new << node
  until queue.empty?
    n = queue.deq(true)
    yield n
    enqueue_children(queue, n)
  end
end

.delete_node(node) ⇒ void

This method returns an undefined value.

Parameters:

  • node (YARD::Parser::Ruby::AstNode)


31
# File 'lib/yard-sorbet/node_utils.rb', line 31

def self.delete_node(node) = node.parent.children.delete(node)

.enqueue_children(queue, node) ⇒ void

This method returns an undefined value.

Enqueue the eligible children of a node in the BFS queue

Parameters:

  • queue (Queue)
  • node (YARD::Parser::Ruby::AstNode)


35
36
37
38
39
40
41
42
43
44
# File 'lib/yard-sorbet/node_utils.rb', line 35

def self.enqueue_children(queue, node)
  last_child = node.children.last
  node.children.each do |child|
    next if child == last_child &&
            node.is_a?(YARD::Parser::Ruby::MethodCallNode) &&
            SKIP_METHOD_CONTENTS.include?(node.method_name(true))

    queue.enq(child)
  end
end

.get_method_node(node) ⇒ SigableNode

Gets the node that a sorbet sig can be attached do, bypassing visisbility modifiers and the like

Parameters:

  • node (YARD::Parser::Ruby::AstNode)

Returns:



48
# File 'lib/yard-sorbet/node_utils.rb', line 48

def self.get_method_node(node) = sigable_node?(node) ? node : node.jump(:def, :defs)

.sibling_node(node) ⇒ YARD::Parser::Ruby::AstNode

Find and return the adjacent node (ascending)

Parameters:

  • node (YARD::Parser::Ruby::AstNode)

Returns:

  • (YARD::Parser::Ruby::AstNode)

Raises:

  • (IndexError)

    if the node does not have an adjacent sibling (ascending)



53
54
55
56
57
# File 'lib/yard-sorbet/node_utils.rb', line 53

def self.sibling_node(node)
  siblings = node.parent.children
  node_index = siblings.find_index { _1.equal?(node) }
  siblings.fetch(node_index + 1)
end

.sigable_node?(node) ⇒ Boolean

Parameters:

  • node (YARD::Parser::Ruby::AstNode)

Returns:

  • (Boolean)


60
61
62
63
64
65
66
# File 'lib/yard-sorbet/node_utils.rb', line 60

def self.sigable_node?(node)
  case node
  when YARD::Parser::Ruby::MethodDefinitionNode then true
  when YARD::Parser::Ruby::MethodCallNode then ATTRIBUTE_METHODS.include?(node.method_name(true))
  else false
  end
end

.validated_attribute_names(attr_node) ⇒ Array<String>

Parameters:

  • attr_node (YARD::Parser::Ruby::MethodCallNode)

Returns:

  • (Array<String>)

See Also:



71
72
73
74
75
76
77
78
# File 'lib/yard-sorbet/node_utils.rb', line 71

def self.validated_attribute_names(attr_node)
  attr_node.parameters(false).map do |obj|
    case obj
    when YARD::Parser::Ruby::LiteralNode then obj[0][0].source
    else raise YARD::Parser::UndocumentableError, obj.source
    end
  end
end