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
29
# File 'lib/yard-sorbet/node_utils.rb', line 21

def self.bfs_traverse(node, &_blk)
  queue = [node]
  until queue.empty?
    n = T.must(queue.shift)
    yield n
    n.children.each { queue.push(_1) }
    queue.pop if n.is_a?(YARD::Parser::Ruby::MethodCallNode) && SKIP_METHOD_CONTENTS.include?(n.method_name(true))
  end
end

.delete_node(node) ⇒ void

This method returns an undefined value.

Parameters:

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


32
33
34
# File 'lib/yard-sorbet/node_utils.rb', line 32

def self.delete_node(node)
  node.parent.children.delete(node)
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:



38
39
40
# File 'lib/yard-sorbet/node_utils.rb', line 38

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

.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)



45
46
47
48
49
# File 'lib/yard-sorbet/node_utils.rb', line 45

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)


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

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:



63
64
65
66
67
68
69
70
# File 'lib/yard-sorbet/node_utils.rb', line 63

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