Class: Capybara::Simulated::StackResolver

Inherits:
Object
  • Object
show all
Defined in:
lib/capybara/simulated/stack_resolver.rb

Overview

Annotates a V8 stack-trace string with original-source positions from each frame’s ‘.map` companion file. Resolves once per frame, caches loaded Sourcemap objects process-wide (built bundles are fingerprinted; identical URL → identical map).

Frames whose URL has no ‘.map` (snapshot stubs, eval’d app inline scripts) pass through unchanged.

Constant Summary collapse

FRAME_RE =

Matches ‘(URL:LINE:COL)` inside V8 stack frames. URLs can contain `:` (e.g. `:port`), so the URL class includes `:` and the engine backtracks to find the trailing `:digits:digits)`. `file:` and `csim-eval:` schemes are matched too because both appear in snapshot-warmup frames where the host wraps eval’d content.

/\((?<url>(?:https?:\/\/|file:\/\/|csim-eval:)[^\s()]+):(?<line>\d+):(?<col>\d+)\)/
@@maps =
{}
@@lock =
Mutex.new

Instance Method Summary collapse

Constructor Details

#initialize(browser) ⇒ StackResolver

Returns a new instance of StackResolver.



28
29
30
# File 'lib/capybara/simulated/stack_resolver.rb', line 28

def initialize(browser)
  @browser = browser
end

Instance Method Details

#annotate(text) ⇒ Object

Returns the input stack/text with ‘→ source:line:col` appended to every frame whose URL maps to a `.map`. If no frame resolves, the input is returned unchanged.



35
36
37
38
39
40
41
42
43
44
45
# File 'lib/capybara/simulated/stack_resolver.rb', line 35

def annotate(text)
  return text unless text.is_a?(String) && !text.empty?
  text.gsub(FRAME_RE) {
    m = ::Regexp.last_match
    url  = m[:url]
    line = m[:line].to_i
    col  = m[:col].to_i
    resolved = resolve(url, line, col)
    resolved ? "#{m[0]}#{resolved}" : m[0]
  }
end