Class: SimpleCov::Formatter::AIFormatter::ASTResolver

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/simplecov-ai/ast_resolver.rb

Overview

Employs statically-parsed Abstract Syntax Tree processing via the ‘parser` gem to correlate raw line-based deficits with high-level semantically meaningful concepts like Classes and Methods. This negates the line-number volatility often experienced by Large Language Models when patching test coverage.

Defined Under Namespace

Classes: SemanticNode

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.resolve(file_path) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/simplecov-ai/ast_resolver.rb', line 54

def self.resolve(file_path)
  return [] unless File.exist?(file_path)

  begin
    source = File.read(file_path)
    ast, comments = Parser::CurrentRuby.parse_with_comments(source)
    new.traverse(ast, comments)
  rescue Parser::SyntaxError
    []
  end
end

Instance Method Details

#traverse(node, comments, context = '') ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/simplecov-ai/ast_resolver.rb', line 77

def traverse(node, comments, context = '')
  return [] unless node.is_a?(Parser::AST::Node)

  nodes = T.let([], T::Array[SemanticNode])
  current_context = context

  case node.type
  when :class, :module
    const_node = T.cast(node.children[0], Parser::AST::Node)
    const_node_loc = T.cast(const_node.loc, Parser::Source::Map::Constant)
    const_node_name = T.cast(const_node_loc.name, Parser::Source::Range)
    name = T.cast(const_node_name.source, String)
    current_context = context.empty? ? name : "#{context}::#{name}"
    nodes << build_node(node, comments, current_context, node.type.to_s.capitalize)
  when :def
    name = T.cast(node.children.first, Symbol).to_s
    current_context = context.empty? ? "##{name}" : "#{context}##{name}"
    nodes << build_node(node, comments, current_context, 'Instance Method')
  when :defs
    name = T.cast(node.children[1], Symbol).to_s
    current_context = context.empty? ? ".#{name}" : "#{context}.#{name}"
    nodes << build_node(node, comments, current_context, 'Singleton Method')
  end

  node.children.each do |child|
    case child
    when Parser::AST::Node
      nodes.concat(traverse(child, comments, current_context))
    end
  end

  nodes
end