Module: Itsi::Server::TypedHandlers::SourceParser

Defined in:
lib/itsi/server/typed_handlers/source_parser.rb

Class Method Summary collapse

Class Method Details

.extract_expr_from_source_location(proc) ⇒ Object

Source Parser interprets endpoint handlers and extracts arity and schema information.



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
45
46
47
48
49
50
51
52
53
54
# File 'lib/itsi/server/typed_handlers/source_parser.rb', line 9

def self.extract_expr_from_source_location(proc)
  source_location = proc.source_location
  source_lines = IO.readlines(source_location.first)

  proc_line = source_location.last - 1
  first_line = source_lines[proc_line]

  until first_line =~ /(?:lambda|proc|->|def|.*?do\s*|.*?\{.*?\|)/ || proc_line.zero?
    proc_line -= 1
    first_line = source_lines[proc_line]
  end
  lines = source_lines[proc_line..]
  lines[0] = lines[0][/(?:lambda|proc|->|def|.*?do\s+|.*?\{.*?\|).*/]
  src_str = lines.first << "\n"
  intermediate = Prism.parse(src_str)

  lines[1..-1].each do |line|
    break if intermediate.success?

    token_count = 0
    line.split(/(?=\s|;|\)|\})/).each do |token|
      src_str << token
      token_count += 1
      intermediate = Prism.parse(src_str)
      next unless intermediate.success? && token_count > 1

      break
    end
  end

  raise "Source Extraction Failed" unless intermediate.success?

  src = intermediate.value.statements.body.first.yield_self do |s|
    s.type == :call_node ? s.block : s
  end
  params = src.parameters
  params = params.parameters if params.respond_to?(:parameters)
  requireds = (params&.requireds || []).map(&:name)
  keywords =  (params&.keywords || []).map do |kw|
    [kw.name, kw.value.slice.gsub(/^_\./, "$.")]
  end.to_h

  [requireds.length, keywords]
rescue StandardError
  [proc.parameters.select { |p| p == :req }&.length || 0, {}]
end