mirror of
https://github.com/rails/execjs
synced 2023-03-27 23:21:20 -04:00
Improve Syntax and Runtime error backtraces
This commit is contained in:
parent
e20941f927
commit
53f8bf9292
7 changed files with 103 additions and 41 deletions
|
@ -24,12 +24,12 @@ module ExecJS
|
|||
|
||||
def exec(source, options = {})
|
||||
source = encode(source)
|
||||
source = "#{@source}\n#{source}" if @source
|
||||
source = "#{@source}\n#{source}" if @source != ""
|
||||
source = @runtime.compile_source(source)
|
||||
|
||||
tmpfile = write_to_tempfile(source)
|
||||
begin
|
||||
extract_result(@runtime.exec_runtime(tmpfile.path))
|
||||
extract_result(@runtime.exec_runtime(tmpfile.path), tmpfile.path)
|
||||
ensure
|
||||
File.unlink(tmpfile)
|
||||
end
|
||||
|
@ -57,14 +57,25 @@ module ExecJS
|
|||
tmpfile
|
||||
end
|
||||
|
||||
def extract_result(output)
|
||||
status, value = output.empty? ? [] : ::JSON.parse(output, create_additions: false)
|
||||
def extract_result(output, filename)
|
||||
status, value, stack = output.empty? ? [] : ::JSON.parse(output, create_additions: false)
|
||||
if status == "ok"
|
||||
value
|
||||
elsif value =~ /SyntaxError:/
|
||||
raise RuntimeError, value
|
||||
else
|
||||
raise ProgramError, value
|
||||
stack ||= ""
|
||||
real_filename = File.realpath(filename)
|
||||
stack = stack.split("\n").map do |line|
|
||||
line.sub(" at ", "")
|
||||
.sub(real_filename, "(execjs)")
|
||||
.sub(filename, "(execjs)")
|
||||
.strip
|
||||
end
|
||||
stack.reject! { |line| ["eval code", "eval@[native code]"].include?(line) }
|
||||
stack.shift unless stack[0].to_s.include?("(execjs)")
|
||||
error_class = value =~ /SyntaxError:/ ? RuntimeError : ProgramError
|
||||
error = error_class.new(value)
|
||||
error.set_backtrace(stack + caller)
|
||||
raise error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -158,7 +169,7 @@ module ExecJS
|
|||
if $?.success?
|
||||
output
|
||||
else
|
||||
raise RuntimeError, output
|
||||
raise exec_runtime_error(output)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -181,7 +192,7 @@ module ExecJS
|
|||
if $?.success?
|
||||
output
|
||||
else
|
||||
raise RuntimeError, output
|
||||
raise exec_runtime_error(output)
|
||||
end
|
||||
end
|
||||
else
|
||||
|
@ -193,13 +204,20 @@ module ExecJS
|
|||
if $?.success?
|
||||
output
|
||||
else
|
||||
raise RuntimeError, output
|
||||
raise exec_runtime_error(output)
|
||||
end
|
||||
end
|
||||
end
|
||||
# Internally exposed for Context.
|
||||
public :exec_runtime
|
||||
|
||||
def exec_runtime_error(output)
|
||||
error = RuntimeError.new(output)
|
||||
lineno = output.split("\n")[0][/:(\d+)$/, 1] || 1
|
||||
error.set_backtrace(["(execjs):#{lineno}"] + caller)
|
||||
error
|
||||
end
|
||||
|
||||
def which(command)
|
||||
Array(command).find do |name|
|
||||
name, args = name.split(/\s+/, 2)
|
||||
|
|
|
@ -12,11 +12,7 @@ module ExecJS
|
|||
begin
|
||||
@v8_context.eval(source)
|
||||
rescue ::V8::JSError => e
|
||||
if e.value["name"] == "SyntaxError"
|
||||
raise RuntimeError, e.value.to_s
|
||||
else
|
||||
raise ProgramError, e.value.to_s
|
||||
end
|
||||
raise wrap_error(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -37,11 +33,7 @@ module ExecJS
|
|||
begin
|
||||
unbox @v8_context.eval("(#{source})")
|
||||
rescue ::V8::JSError => e
|
||||
if e.value["name"] == "SyntaxError"
|
||||
raise RuntimeError, e.value.to_s
|
||||
else
|
||||
raise ProgramError, e.value.to_s
|
||||
end
|
||||
raise wrap_error(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -52,11 +44,7 @@ module ExecJS
|
|||
begin
|
||||
unbox @v8_context.eval(properties).call(*args)
|
||||
rescue ::V8::JSError => e
|
||||
if e.value["name"] == "SyntaxError"
|
||||
raise RuntimeError, e.value.to_s
|
||||
else
|
||||
raise ProgramError, e.value.to_s
|
||||
end
|
||||
raise wrap_error(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -96,6 +84,20 @@ module ExecJS
|
|||
result
|
||||
end
|
||||
end
|
||||
|
||||
def wrap_error(e)
|
||||
error_class = e.value["name"] == "SyntaxError" ? RuntimeError : ProgramError
|
||||
|
||||
stack = e.value["stack"] || ""
|
||||
stack = stack.split("\n")
|
||||
stack.shift
|
||||
stack = [e.message[/<eval>:\d+:\d+/, 0]].compact if stack.empty?
|
||||
stack = stack.map { |line| line.sub(" at ", "").sub("<eval>", "(execjs)").strip }
|
||||
|
||||
error = error_class.new(e.value.to_s)
|
||||
error.set_backtrace(stack + caller)
|
||||
error
|
||||
end
|
||||
end
|
||||
|
||||
def name
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
try {
|
||||
print(JSON.stringify(['ok', result]));
|
||||
} catch (err) {
|
||||
print('["err"]');
|
||||
print(JSON.stringify(['err', '' + err, err.stack]));
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
print(JSON.stringify(['err', '' + err]));
|
||||
print(JSON.stringify(['err', '' + err, err.stack]));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
try {
|
||||
print(JSON.stringify(['ok', result]));
|
||||
} catch (err) {
|
||||
print('["err"]');
|
||||
print(JSON.stringify(['err', err.name + ': ' + err.message, err.stack]));
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
print(JSON.stringify(['err', err.name + ': ' + err.message]));
|
||||
print(JSON.stringify(['err', err.name + ': ' + err.message, err.stack]));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
try {
|
||||
print(JSON.stringify(['ok', result]));
|
||||
} catch (err) {
|
||||
print('["err"]');
|
||||
print(JSON.stringify(['err', '' + err, err.stack]));
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
print(JSON.stringify(['err', '' + err]));
|
||||
print(JSON.stringify(['err', '' + err, err.stack]));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
try {
|
||||
print(JSON.stringify(['ok', result]));
|
||||
} catch (err) {
|
||||
print('["err"]');
|
||||
print(JSON.stringify(['err', '' + err, err.stack]));
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
print(JSON.stringify(['err', '' + err]));
|
||||
print(JSON.stringify(['err', '' + err, err.stack]));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -253,38 +253,80 @@ class TestExecJS < Test
|
|||
end
|
||||
|
||||
def test_exec_syntax_error
|
||||
assert_raises ExecJS::RuntimeError do
|
||||
begin
|
||||
ExecJS.exec(")")
|
||||
flunk
|
||||
rescue ExecJS::RuntimeError => e
|
||||
assert e
|
||||
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
def test_eval_syntax_error
|
||||
assert_raises ExecJS::RuntimeError do
|
||||
begin
|
||||
ExecJS.eval(")")
|
||||
flunk
|
||||
rescue ExecJS::RuntimeError => e
|
||||
assert e
|
||||
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
def test_compile_syntax_error
|
||||
assert_raises ExecJS::RuntimeError do
|
||||
begin
|
||||
ExecJS.compile(")")
|
||||
flunk
|
||||
rescue ExecJS::RuntimeError => e
|
||||
assert e
|
||||
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
def test_exec_thrown_exception
|
||||
def test_exec_thrown_error
|
||||
begin
|
||||
ExecJS.exec("throw new Error('hello')")
|
||||
flunk
|
||||
rescue ExecJS::ProgramError => e
|
||||
assert e
|
||||
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
def test_eval_thrown_error
|
||||
begin
|
||||
ExecJS.eval("(function(){ throw new Error('hello') })()")
|
||||
flunk
|
||||
rescue ExecJS::ProgramError => e
|
||||
assert e
|
||||
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
def test_compile_thrown_error
|
||||
begin
|
||||
ExecJS.compile("throw new Error('hello')")
|
||||
flunk
|
||||
rescue ExecJS::ProgramError => e
|
||||
assert e
|
||||
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
def test_exec_thrown_string
|
||||
assert_raises ExecJS::ProgramError do
|
||||
ExecJS.exec("throw 'hello'")
|
||||
end
|
||||
end
|
||||
|
||||
def test_eval_thrown_exception
|
||||
def test_eval_thrown_string
|
||||
assert_raises ExecJS::ProgramError do
|
||||
ExecJS.exec("throw 'hello'")
|
||||
ExecJS.eval("(function(){ throw 'hello' })()")
|
||||
end
|
||||
end
|
||||
|
||||
def test_compile_thrown_exception
|
||||
def test_compile_thrown_string
|
||||
assert_raises ExecJS::ProgramError do
|
||||
ExecJS.exec("throw 'hello'")
|
||||
ExecJS.compile("throw 'hello'")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue