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
|
||||
rvm:
|
||||
- 1.9.3
|
||||
- 2.0.0
|
||||
- 2.1
|
||||
- 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
|
||||
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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module ExecJS
|
||||
VERSION = "2.3.0"
|
||||
VERSION = "2.4.0"
|
||||
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
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue