1
0
Fork 0
mirror of https://github.com/rails/execjs synced 2023-03-27 23:21:20 -04:00

Merge branch 'master' into duktape

This commit is contained in:
Joshua Peek 2015-03-09 16:35:36 -07:00
commit 2280734851
14 changed files with 46331 additions and 64 deletions

View file

@ -1,6 +1,6 @@
sudo: false
language: ruby
rvm:
- 1.9.3
- 2.0.0
- 2.1
- 2.2

View file

@ -64,7 +64,7 @@ older stock runtimes like JSC on OSX and JScript on Windows may not. You should
only count on ES3 features being available. Prefer feature checking these APIs
rather than hard coding support for specific runtimes.
**Can I ExecJS be used to sandbox scripts?**
**Can ExecJS be used to sandbox scripts?**
No, ExecJS shouldn't be used for any security related sandboxing. Since runtimes
are automatically detected, each runtime has different sandboxing properties.

View file

@ -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,22 @@ 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)
lines = output.split("\n")
lineno = lines[0][/:(\d+)$/, 1] if lines[0]
lineno ||= 1
error.set_backtrace(["(execjs):#{lineno}"] + caller)
error
end
def which(command)
Array(command).find do |name|
name, args = name.split(/\s+/, 2)

View file

@ -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

View file

@ -10,7 +10,7 @@ module ExecJS
fix_memory_limit! @rhino_context
@rhino_context.eval(source)
rescue Exception => e
reraise_error(e)
raise wrap_error(e)
end
def exec(source, options = {})
@ -28,13 +28,13 @@ module ExecJS
unbox @rhino_context.eval("(#{source})")
end
rescue Exception => e
reraise_error(e)
raise wrap_error(e)
end
def call(properties, *args)
unbox @rhino_context.eval(properties).call(*args)
rescue Exception => e
reraise_error(e)
raise wrap_error(e)
end
def unbox(value)
@ -58,17 +58,18 @@ module ExecJS
end
end
def reraise_error(e)
case e
when ::Rhino::JSError
if e.message == "syntax error"
raise RuntimeError, e.message
else
raise ProgramError, e.message
end
else
raise e
end
def wrap_error(e)
return e unless e.is_a?(::Rhino::JSError)
error_class = e.message == "syntax error" ? RuntimeError : ProgramError
stack = e.backtrace
stack = stack.map { |line| line.sub(" at ", "").sub("<eval>", "(execjs)").strip }
stack.unshift("(execjs):1") if e.javascript_backtrace.empty?
error = error_class.new(e.value.to_s)
error.set_backtrace(stack)
error
end
private

View file

@ -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]));
}
});

View file

@ -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]));
}
});

View file

@ -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]));
}
});

View file

@ -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]));
}
});

View file

@ -1,3 +1,3 @@
module ExecJS
VERSION = "2.3.0"
VERSION = "2.4.0"
end

43557
test/fixtures/babel.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2613
test/fixtures/uglify.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -253,41 +253,98 @@ 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
def test_babel
skip if ExecJS.runtime.is_a?(ExecJS::RubyRhinoRuntime)
assert source = File.read(File.expand_path("../fixtures/babel.js", __FILE__))
source = <<-JS
var self = this;
#{source}
babel.eval = function(code) {
return eval(babel.transform(code)["code"]);
}
JS
context = ExecJS.compile(source)
assert_equal 64, context.call("babel.eval", "((x) => x * x)(8)")
end
def test_coffeescript
# Skip coffeescript on Duktape for now
skip if ExecJS.runtime.is_a?(ExecJS::DuktapeRuntime)
@ -296,4 +353,21 @@ class TestExecJS < Test
context = ExecJS.compile(source)
assert_equal 64, context.call("CoffeeScript.eval", "((x) -> x * x)(8)")
end
def test_uglify
assert source = File.read(File.expand_path("../fixtures/uglify.js", __FILE__))
source = <<-JS
#{source}
function uglify(source) {
var ast = UglifyJS.parse(source);
var stream = UglifyJS.OutputStream();
ast.print(stream);
return stream.toString();
}
JS
context = ExecJS.compile(source)
assert_equal "function foo(bar){return bar}",
context.call("uglify", "function foo(bar) {\n return bar;\n}")
end
end