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:
commit
2280734851
14 changed files with 46331 additions and 64 deletions
|
@ -1,6 +1,6 @@
|
||||||
|
sudo: false
|
||||||
language: ruby
|
language: ruby
|
||||||
rvm:
|
rvm:
|
||||||
- 1.9.3
|
|
||||||
- 2.0.0
|
- 2.0.0
|
||||||
- 2.1
|
- 2.1
|
||||||
- 2.2
|
- 2.2
|
||||||
|
|
|
@ -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
|
only count on ES3 features being available. Prefer feature checking these APIs
|
||||||
rather than hard coding support for specific runtimes.
|
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
|
No, ExecJS shouldn't be used for any security related sandboxing. Since runtimes
|
||||||
are automatically detected, each runtime has different sandboxing properties.
|
are automatically detected, each runtime has different sandboxing properties.
|
||||||
|
|
|
@ -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,22 @@ 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)
|
||||||
|
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)
|
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
|
||||||
|
|
|
@ -10,7 +10,7 @@ module ExecJS
|
||||||
fix_memory_limit! @rhino_context
|
fix_memory_limit! @rhino_context
|
||||||
@rhino_context.eval(source)
|
@rhino_context.eval(source)
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
reraise_error(e)
|
raise wrap_error(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
def exec(source, options = {})
|
def exec(source, options = {})
|
||||||
|
@ -28,13 +28,13 @@ module ExecJS
|
||||||
unbox @rhino_context.eval("(#{source})")
|
unbox @rhino_context.eval("(#{source})")
|
||||||
end
|
end
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
reraise_error(e)
|
raise wrap_error(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(properties, *args)
|
def call(properties, *args)
|
||||||
unbox @rhino_context.eval(properties).call(*args)
|
unbox @rhino_context.eval(properties).call(*args)
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
reraise_error(e)
|
raise wrap_error(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
def unbox(value)
|
def unbox(value)
|
||||||
|
@ -58,17 +58,18 @@ module ExecJS
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def reraise_error(e)
|
def wrap_error(e)
|
||||||
case e
|
return e unless e.is_a?(::Rhino::JSError)
|
||||||
when ::Rhino::JSError
|
|
||||||
if e.message == "syntax error"
|
error_class = e.message == "syntax error" ? RuntimeError : ProgramError
|
||||||
raise RuntimeError, e.message
|
|
||||||
else
|
stack = e.backtrace
|
||||||
raise ProgramError, e.message
|
stack = stack.map { |line| line.sub(" at ", "").sub("<eval>", "(execjs)").strip }
|
||||||
end
|
stack.unshift("(execjs):1") if e.javascript_backtrace.empty?
|
||||||
else
|
|
||||||
raise e
|
error = error_class.new(e.value.to_s)
|
||||||
end
|
error.set_backtrace(stack)
|
||||||
|
error
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -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]));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
module ExecJS
|
module ExecJS
|
||||||
VERSION = "2.3.0"
|
VERSION = "2.4.0"
|
||||||
end
|
end
|
||||||
|
|
43557
test/fixtures/babel.js
vendored
Normal file
43557
test/fixtures/babel.js
vendored
Normal file
File diff suppressed because one or more lines are too long
12
test/fixtures/coffee-script.js
vendored
12
test/fixtures/coffee-script.js
vendored
File diff suppressed because one or more lines are too long
2613
test/fixtures/uglify.js
vendored
Normal file
2613
test/fixtures/uglify.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -253,41 +253,98 @@ 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
|
||||||
|
|
||||||
|
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
|
def test_coffeescript
|
||||||
# Skip coffeescript on Duktape for now
|
# Skip coffeescript on Duktape for now
|
||||||
skip if ExecJS.runtime.is_a?(ExecJS::DuktapeRuntime)
|
skip if ExecJS.runtime.is_a?(ExecJS::DuktapeRuntime)
|
||||||
|
@ -296,4 +353,21 @@ class TestExecJS < Test
|
||||||
context = ExecJS.compile(source)
|
context = ExecJS.compile(source)
|
||||||
assert_equal 64, context.call("CoffeeScript.eval", "((x) -> x * x)(8)")
|
assert_equal 64, context.call("CoffeeScript.eval", "((x) -> x * x)(8)")
|
||||||
end
|
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
|
end
|
||||||
|
|
Loading…
Reference in a new issue