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 = {})
|
def exec(source, options = {})
|
||||||
source = encode(source)
|
source = encode(source)
|
||||||
source = "#{@source}\n#{source}" if @source
|
source = "#{@source}\n#{source}" if @source != ""
|
||||||
source = @runtime.compile_source(source)
|
source = @runtime.compile_source(source)
|
||||||
|
|
||||||
tmpfile = write_to_tempfile(source)
|
tmpfile = write_to_tempfile(source)
|
||||||
begin
|
begin
|
||||||
extract_result(@runtime.exec_runtime(tmpfile.path))
|
extract_result(@runtime.exec_runtime(tmpfile.path), tmpfile.path)
|
||||||
ensure
|
ensure
|
||||||
File.unlink(tmpfile)
|
File.unlink(tmpfile)
|
||||||
end
|
end
|
||||||
|
@ -57,14 +57,25 @@ module ExecJS
|
||||||
tmpfile
|
tmpfile
|
||||||
end
|
end
|
||||||
|
|
||||||
def extract_result(output)
|
def extract_result(output, filename)
|
||||||
status, value = output.empty? ? [] : ::JSON.parse(output, create_additions: false)
|
status, value, stack = output.empty? ? [] : ::JSON.parse(output, create_additions: false)
|
||||||
if status == "ok"
|
if status == "ok"
|
||||||
value
|
value
|
||||||
elsif value =~ /SyntaxError:/
|
|
||||||
raise RuntimeError, value
|
|
||||||
else
|
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
|
end
|
||||||
end
|
end
|
||||||
|
@ -158,7 +169,7 @@ module ExecJS
|
||||||
if $?.success?
|
if $?.success?
|
||||||
output
|
output
|
||||||
else
|
else
|
||||||
raise RuntimeError, output
|
raise exec_runtime_error(output)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -181,7 +192,7 @@ module ExecJS
|
||||||
if $?.success?
|
if $?.success?
|
||||||
output
|
output
|
||||||
else
|
else
|
||||||
raise RuntimeError, output
|
raise exec_runtime_error(output)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -193,13 +204,20 @@ module ExecJS
|
||||||
if $?.success?
|
if $?.success?
|
||||||
output
|
output
|
||||||
else
|
else
|
||||||
raise RuntimeError, output
|
raise exec_runtime_error(output)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# Internally exposed for Context.
|
# Internally exposed for Context.
|
||||||
public :exec_runtime
|
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)
|
def which(command)
|
||||||
Array(command).find do |name|
|
Array(command).find do |name|
|
||||||
name, args = name.split(/\s+/, 2)
|
name, args = name.split(/\s+/, 2)
|
||||||
|
|
|
@ -12,11 +12,7 @@ module ExecJS
|
||||||
begin
|
begin
|
||||||
@v8_context.eval(source)
|
@v8_context.eval(source)
|
||||||
rescue ::V8::JSError => e
|
rescue ::V8::JSError => e
|
||||||
if e.value["name"] == "SyntaxError"
|
raise wrap_error(e)
|
||||||
raise RuntimeError, e.value.to_s
|
|
||||||
else
|
|
||||||
raise ProgramError, e.value.to_s
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -37,11 +33,7 @@ module ExecJS
|
||||||
begin
|
begin
|
||||||
unbox @v8_context.eval("(#{source})")
|
unbox @v8_context.eval("(#{source})")
|
||||||
rescue ::V8::JSError => e
|
rescue ::V8::JSError => e
|
||||||
if e.value["name"] == "SyntaxError"
|
raise wrap_error(e)
|
||||||
raise RuntimeError, e.value.to_s
|
|
||||||
else
|
|
||||||
raise ProgramError, e.value.to_s
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -52,11 +44,7 @@ module ExecJS
|
||||||
begin
|
begin
|
||||||
unbox @v8_context.eval(properties).call(*args)
|
unbox @v8_context.eval(properties).call(*args)
|
||||||
rescue ::V8::JSError => e
|
rescue ::V8::JSError => e
|
||||||
if e.value["name"] == "SyntaxError"
|
raise wrap_error(e)
|
||||||
raise RuntimeError, e.value.to_s
|
|
||||||
else
|
|
||||||
raise ProgramError, e.value.to_s
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -96,6 +84,20 @@ module ExecJS
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
def name
|
def name
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
try {
|
try {
|
||||||
print(JSON.stringify(['ok', result]));
|
print(JSON.stringify(['ok', result]));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print('["err"]');
|
print(JSON.stringify(['err', '' + err, err.stack]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print(JSON.stringify(['err', '' + err]));
|
print(JSON.stringify(['err', '' + err, err.stack]));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
try {
|
try {
|
||||||
print(JSON.stringify(['ok', result]));
|
print(JSON.stringify(['ok', result]));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print('["err"]');
|
print(JSON.stringify(['err', err.name + ': ' + err.message, err.stack]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} 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 {
|
try {
|
||||||
print(JSON.stringify(['ok', result]));
|
print(JSON.stringify(['ok', result]));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print('["err"]');
|
print(JSON.stringify(['err', '' + err, err.stack]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print(JSON.stringify(['err', '' + err]));
|
print(JSON.stringify(['err', '' + err, err.stack]));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
try {
|
try {
|
||||||
print(JSON.stringify(['ok', result]));
|
print(JSON.stringify(['ok', result]));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print('["err"]');
|
print(JSON.stringify(['err', '' + err, err.stack]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print(JSON.stringify(['err', '' + err]));
|
print(JSON.stringify(['err', '' + err, err.stack]));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -253,38 +253,80 @@ class TestExecJS < Test
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_exec_syntax_error
|
def test_exec_syntax_error
|
||||||
assert_raises ExecJS::RuntimeError do
|
begin
|
||||||
ExecJS.exec(")")
|
ExecJS.exec(")")
|
||||||
|
flunk
|
||||||
|
rescue ExecJS::RuntimeError => e
|
||||||
|
assert e
|
||||||
|
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_eval_syntax_error
|
def test_eval_syntax_error
|
||||||
assert_raises ExecJS::RuntimeError do
|
begin
|
||||||
ExecJS.eval(")")
|
ExecJS.eval(")")
|
||||||
|
flunk
|
||||||
|
rescue ExecJS::RuntimeError => e
|
||||||
|
assert e
|
||||||
|
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compile_syntax_error
|
def test_compile_syntax_error
|
||||||
assert_raises ExecJS::RuntimeError do
|
begin
|
||||||
ExecJS.compile(")")
|
ExecJS.compile(")")
|
||||||
|
flunk
|
||||||
|
rescue ExecJS::RuntimeError => e
|
||||||
|
assert e
|
||||||
|
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
|
||||||
end
|
end
|
||||||
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
|
assert_raises ExecJS::ProgramError do
|
||||||
ExecJS.exec("throw 'hello'")
|
ExecJS.exec("throw 'hello'")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_eval_thrown_exception
|
def test_eval_thrown_string
|
||||||
assert_raises ExecJS::ProgramError do
|
assert_raises ExecJS::ProgramError do
|
||||||
ExecJS.exec("throw 'hello'")
|
ExecJS.eval("(function(){ throw 'hello' })()")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compile_thrown_exception
|
def test_compile_thrown_string
|
||||||
assert_raises ExecJS::ProgramError do
|
assert_raises ExecJS::ProgramError do
|
||||||
ExecJS.exec("throw 'hello'")
|
ExecJS.compile("throw 'hello'")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue