Module: RailVerdict::RailsContext::Resolvers::AssociationExtractor

Defined in:
lib/rail_verdict/rails_context/resolvers/association_extractor.rb

Constant Summary collapse

MACROS =
%w[belongs_to has_one has_many has_and_belongs_to_many].freeze

Class Method Summary collapse

Class Method Details

.extract(repository_root:, path:) ⇒ Object



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
40
41
42
43
44
# File 'lib/rail_verdict/rails_context/resolvers/association_extractor.rb', line 9

def self.extract(repository_root:, path:)
  full = File.join(repository_root, path)
  return [] unless File.file?(full)
  return [] if File.size(full) > Limits::MAX_FILE_BYTES rescue nil

  text = File.binread(full)
  return [] if text.bytesize > Limits::MAX_FILE_BYTES

  text.force_encoding(Encoding::UTF_8)
  return [] unless text.valid_encoding?
  return [] if text.include?("\x00")

  results = []
  text.each_line do |line|
    stripped = line.strip
    next if stripped.start_with?("#")

    MACROS.each do |macro|
      match = stripped.match(/\A#{Regexp.escape(macro)}\s+[:"]?([a-z_][a-z0-9_]*)["']?/)
      next unless match

      after = stripped[match[0].length..].to_s.strip
      next if after.start_with?("->") || after.include?("proc") || after.include?("lambda")

      name = match[1].to_s
      next if name.empty?

      results << { "name" => name, "macro" => macro, "confidence" => "exact", "provenance" => "literal:#{macro} :#{name}" }
      break if results.length >= Limits::MAX_ASSOCIATIONS
    end
    break if results.length >= Limits::MAX_ASSOCIATIONS
  end
  results
rescue StandardError
  []
end