execjs 2.7.0 → 2.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +20 -4
- data/lib/execjs/duktape_runtime.rb +5 -4
- data/lib/execjs/external_runtime.rb +17 -19
- data/lib/execjs/graaljs_runtime.rb +147 -0
- data/lib/execjs/mini_racer_runtime.rb +4 -3
- data/lib/execjs/ruby_rhino_runtime.rb +9 -4
- data/lib/execjs/runtime.rb +16 -5
- data/lib/execjs/runtimes.rb +20 -7
- data/lib/execjs/support/bun_runner.js +29 -0
- data/lib/execjs/support/jsc_runner.js +8 -0
- data/lib/execjs/support/node_runner.js +21 -7
- data/lib/execjs/support/v8_runner.js +8 -1
- data/lib/execjs/version.rb +1 -1
- metadata +9 -10
- data/lib/execjs/encoding.rb +0 -26
- data/lib/execjs/ruby_racer_runtime.rb +0 -114
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2cff0ab13dcd1bc38d12b1ca38d99773ba123ad75573c8b8f4789232677df308
|
4
|
+
data.tar.gz: a84d80b533fa677491bdb26d28bfedd44443deb5ff772d9eeb7db7e9e0d0ab36
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbac63f192c113786e7df0bce663a0e40a241b54534e01f18047d356d7ccb1514e4aeb8a610a336f85271def9b5956404091caccf6f0c984a20a723f67a364ce
|
7
|
+
data.tar.gz: 2f6dfe9ff9154500ea26a0c94a829eacb8b63ac84744791eff8f0b8643182f30118b1f1ed42f08486a4cc05c4e61c0cb8d800df53dcbccdbba5dadb786027b7a
|
data/README.md
CHANGED
@@ -7,17 +7,17 @@ returns the result to you as a Ruby object.
|
|
7
7
|
|
8
8
|
ExecJS supports these runtimes:
|
9
9
|
|
10
|
-
* [therubyracer](https://github.com/cowboyd/therubyracer) - Google V8
|
11
|
-
embedded within Ruby
|
12
10
|
* [therubyrhino](https://github.com/cowboyd/therubyrhino) - Mozilla
|
13
11
|
Rhino embedded within JRuby
|
14
12
|
* [Duktape.rb](https://github.com/judofyr/duktape.rb) - Duktape JavaScript interpreter
|
15
13
|
* [Node.js](http://nodejs.org/)
|
14
|
+
* [Bun.sh](https://bun.sh) - JavaScript runtime & toolkit designed for speed
|
16
15
|
* Apple JavaScriptCore - Included with Mac OS X
|
17
16
|
* [Microsoft Windows Script Host](http://msdn.microsoft.com/en-us/library/9bbdkx3k.aspx) (JScript)
|
18
17
|
* [Google V8](http://code.google.com/p/v8/)
|
19
|
-
* [mini_racer](https://github.com/
|
18
|
+
* [mini_racer](https://github.com/rubyjs/mini_racer) - Google V8
|
20
19
|
embedded within Ruby
|
20
|
+
* [GraalVM JavaScript](https://www.graalvm.org/javascript/) - used on TruffleRuby
|
21
21
|
|
22
22
|
A short example:
|
23
23
|
|
@@ -39,6 +39,22 @@ context.call("CoffeeScript.compile", "square = (x) -> x * x", bare: true)
|
|
39
39
|
# => "var square;\nsquare = function(x) {\n return x * x;\n};"
|
40
40
|
```
|
41
41
|
|
42
|
+
# Forcing a specific runtime
|
43
|
+
|
44
|
+
If you'd like to use a specific runtime rather than the autodected one, you can assign `ExecJS.runtime`:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
ExecJS.runtime = ExecJS::Runtimes::Node
|
48
|
+
```
|
49
|
+
|
50
|
+
Alternatively, you can define it via the `EXECJS_RUNTIME` environment variable:
|
51
|
+
|
52
|
+
```bash
|
53
|
+
EXECJS_RUNTIME=Node ruby ...
|
54
|
+
```
|
55
|
+
|
56
|
+
You can find the list of possible runtimes in [`lib/execjs/runtimes.rb`](https://github.com/rails/execjs/blob/master/lib/execjs/runtimes.rb).
|
57
|
+
|
42
58
|
# Installation
|
43
59
|
|
44
60
|
```
|
@@ -76,7 +92,7 @@ You shouldn't use `ExecJS.eval` on any inputs you wouldn't feel comfortable Ruby
|
|
76
92
|
|
77
93
|
## Contributing to ExecJS
|
78
94
|
|
79
|
-
ExecJS is work of
|
95
|
+
ExecJS is work of dozens of contributors. You're encouraged to submit pull requests, propose
|
80
96
|
features and discuss issues.
|
81
97
|
|
82
98
|
See [CONTRIBUTING](CONTRIBUTING.md).
|
@@ -6,27 +6,28 @@ module ExecJS
|
|
6
6
|
class Context < Runtime::Context
|
7
7
|
def initialize(runtime, source = "", options = {})
|
8
8
|
@ctx = Duktape::Context.new(complex_object: nil)
|
9
|
-
@ctx.exec_string(encode(
|
9
|
+
@ctx.exec_string(source.encode(Encoding::UTF_8), '(execjs)')
|
10
10
|
rescue Exception => e
|
11
11
|
raise wrap_error(e)
|
12
12
|
end
|
13
13
|
|
14
14
|
def exec(source, options = {})
|
15
15
|
return unless /\S/ =~ source
|
16
|
-
@ctx.eval_string("(function(){#{encode(
|
16
|
+
@ctx.eval_string("(function(){#{source.encode(Encoding::UTF_8)}})()", '(execjs)')
|
17
17
|
rescue Exception => e
|
18
18
|
raise wrap_error(e)
|
19
19
|
end
|
20
20
|
|
21
21
|
def eval(source, options = {})
|
22
22
|
return unless /\S/ =~ source
|
23
|
-
@ctx.eval_string("(#{encode(
|
23
|
+
@ctx.eval_string("(#{source.encode(Encoding::UTF_8)})", '(execjs)')
|
24
24
|
rescue Exception => e
|
25
25
|
raise wrap_error(e)
|
26
26
|
end
|
27
27
|
|
28
28
|
def call(identifier, *args)
|
29
|
-
@ctx.
|
29
|
+
@ctx.exec_string("__execjs_duktape_call = #{identifier}", '(execjs)')
|
30
|
+
@ctx.call_prop("__execjs_duktape_call", *args)
|
30
31
|
rescue Exception => e
|
31
32
|
raise wrap_error(e)
|
32
33
|
end
|
@@ -1,11 +1,12 @@
|
|
1
|
-
require "tmpdir"
|
2
1
|
require "execjs/runtime"
|
2
|
+
require "tmpdir"
|
3
|
+
require "json"
|
3
4
|
|
4
5
|
module ExecJS
|
5
6
|
class ExternalRuntime < Runtime
|
6
7
|
class Context < Runtime::Context
|
7
8
|
def initialize(runtime, source = "", options = {})
|
8
|
-
source = encode(
|
9
|
+
source = source.encode(Encoding::UTF_8)
|
9
10
|
|
10
11
|
@runtime = runtime
|
11
12
|
@source = source
|
@@ -15,7 +16,7 @@ module ExecJS
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def eval(source, options = {})
|
18
|
-
source = encode(
|
19
|
+
source = source.encode(Encoding::UTF_8)
|
19
20
|
|
20
21
|
if /\S/ =~ source
|
21
22
|
exec("return eval(#{::JSON.generate("(#{source})", quirks_mode: true)})")
|
@@ -23,7 +24,7 @@ module ExecJS
|
|
23
24
|
end
|
24
25
|
|
25
26
|
def exec(source, options = {})
|
26
|
-
source = encode(
|
27
|
+
source = source.encode(Encoding::UTF_8)
|
27
28
|
source = "#{@source}\n#{source}" if @source != ""
|
28
29
|
source = @runtime.compile_source(source)
|
29
30
|
|
@@ -77,7 +78,7 @@ module ExecJS
|
|
77
78
|
.sub(filename, "(execjs)")
|
78
79
|
.strip
|
79
80
|
end
|
80
|
-
stack.reject! { |line| ["eval code", "eval@[native code]"].include?(line) }
|
81
|
+
stack.reject! { |line| ["eval code", "eval code@", "eval@[native code]"].include?(line) }
|
81
82
|
stack.shift unless stack[0].to_s.include?("(execjs)")
|
82
83
|
error_class = value =~ /SyntaxError:/ ? RuntimeError : ProgramError
|
83
84
|
error = error_class.new(value)
|
@@ -102,7 +103,13 @@ module ExecJS
|
|
102
103
|
@popen_options[:internal_encoding] = ::Encoding.default_internal || 'UTF-8'
|
103
104
|
|
104
105
|
if @runner_path
|
105
|
-
instance_eval
|
106
|
+
instance_eval <<~RUBY, __FILE__, __LINE__
|
107
|
+
def compile_source(source)
|
108
|
+
<<-RUNNER
|
109
|
+
#{IO.read(@runner_path)}
|
110
|
+
RUNNER
|
111
|
+
end
|
112
|
+
RUBY
|
106
113
|
end
|
107
114
|
end
|
108
115
|
|
@@ -142,15 +149,6 @@ module ExecJS
|
|
142
149
|
end
|
143
150
|
|
144
151
|
protected
|
145
|
-
def generate_compile_method(path)
|
146
|
-
<<-RUBY
|
147
|
-
def compile_source(source)
|
148
|
-
<<-RUNNER
|
149
|
-
#{IO.read(path)}
|
150
|
-
RUNNER
|
151
|
-
end
|
152
|
-
RUBY
|
153
|
-
end
|
154
152
|
|
155
153
|
def json2_source
|
156
154
|
@json2_source ||= IO.read(ExecJS.root + "/support/json2.js")
|
@@ -173,7 +171,7 @@ module ExecJS
|
|
173
171
|
begin
|
174
172
|
command = binary.split(" ") << filename
|
175
173
|
`#{shell_escape(*command)} 2>&1 > #{path}`
|
176
|
-
output = File.open(path, 'rb',
|
174
|
+
output = File.open(path, 'rb', **@popen_options) { |f| f.read }
|
177
175
|
ensure
|
178
176
|
File.unlink(path) if path
|
179
177
|
end
|
@@ -196,8 +194,8 @@ module ExecJS
|
|
196
194
|
require 'shellwords'
|
197
195
|
|
198
196
|
def exec_runtime(filename)
|
199
|
-
command = "#{Shellwords.join(binary.split(' ') << filename)}
|
200
|
-
io = IO.popen(command,
|
197
|
+
command = "#{Shellwords.join(binary.split(' ') << filename)}"
|
198
|
+
io = IO.popen(command, **@popen_options)
|
201
199
|
output = io.read
|
202
200
|
io.close
|
203
201
|
|
@@ -209,7 +207,7 @@ module ExecJS
|
|
209
207
|
end
|
210
208
|
else
|
211
209
|
def exec_runtime(filename)
|
212
|
-
io = IO.popen(binary.split(' ') << filename,
|
210
|
+
io = IO.popen(binary.split(' ') << filename, **@popen_options)
|
213
211
|
output = io.read
|
214
212
|
io.close
|
215
213
|
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require "execjs/runtime"
|
2
|
+
|
3
|
+
module ExecJS
|
4
|
+
class GraalJSRuntime < Runtime
|
5
|
+
class Context < Runtime::Context
|
6
|
+
def initialize(runtime, source = "", options = {})
|
7
|
+
@context = Polyglot::InnerContext.new
|
8
|
+
@context.eval('js', 'delete this.console')
|
9
|
+
@js_object = @context.eval('js', 'Object')
|
10
|
+
|
11
|
+
source = source.encode(Encoding::UTF_8)
|
12
|
+
unless source.empty?
|
13
|
+
translate do
|
14
|
+
eval_in_context(source)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def exec(source, options = {})
|
20
|
+
source = source.encode(Encoding::UTF_8)
|
21
|
+
source = "(function(){#{source}})()" if /\S/.match?(source)
|
22
|
+
|
23
|
+
translate do
|
24
|
+
eval_in_context(source)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def eval(source, options = {})
|
29
|
+
source = source.encode(Encoding::UTF_8)
|
30
|
+
source = "(#{source})" if /\S/.match?(source)
|
31
|
+
|
32
|
+
translate do
|
33
|
+
eval_in_context(source)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(source, *args)
|
38
|
+
source = source.encode(Encoding::UTF_8)
|
39
|
+
source = "(#{source})" if /\S/.match?(source)
|
40
|
+
|
41
|
+
translate do
|
42
|
+
function = eval_in_context(source)
|
43
|
+
function.call(*convert_ruby_to_js(args))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
ForeignException = defined?(Polyglot::ForeignException) ? Polyglot::ForeignException : ::RuntimeError
|
50
|
+
|
51
|
+
def translate
|
52
|
+
convert_js_to_ruby yield
|
53
|
+
rescue ForeignException => e
|
54
|
+
if e.message && e.message.start_with?('SyntaxError:')
|
55
|
+
error_class = ExecJS::RuntimeError
|
56
|
+
else
|
57
|
+
error_class = ExecJS::ProgramError
|
58
|
+
end
|
59
|
+
|
60
|
+
backtrace = (e.backtrace || []).map { |line| line.sub('(eval)', '(execjs)') }
|
61
|
+
raise error_class, e.message, backtrace
|
62
|
+
end
|
63
|
+
|
64
|
+
def convert_js_to_ruby(value)
|
65
|
+
case value
|
66
|
+
when true, false, Integer, Float
|
67
|
+
value
|
68
|
+
else
|
69
|
+
if value.nil?
|
70
|
+
nil
|
71
|
+
elsif value.respond_to?(:call)
|
72
|
+
nil
|
73
|
+
elsif value.respond_to?(:to_str)
|
74
|
+
value.to_str
|
75
|
+
elsif value.respond_to?(:to_ary)
|
76
|
+
value.to_ary.map do |e|
|
77
|
+
if e.respond_to?(:call)
|
78
|
+
nil
|
79
|
+
else
|
80
|
+
convert_js_to_ruby(e)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
else
|
84
|
+
object = value
|
85
|
+
h = {}
|
86
|
+
object.instance_variables.each do |member|
|
87
|
+
v = object[member]
|
88
|
+
unless v.respond_to?(:call)
|
89
|
+
h[member.to_s] = convert_js_to_ruby(v)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
h
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def convert_ruby_to_js(value)
|
98
|
+
case value
|
99
|
+
when nil, true, false, Integer, Float
|
100
|
+
value
|
101
|
+
when String, Symbol
|
102
|
+
Truffle::Interop.as_truffle_string value
|
103
|
+
when Array
|
104
|
+
value.map { |e| convert_ruby_to_js(e) }
|
105
|
+
when Hash
|
106
|
+
h = @js_object.new
|
107
|
+
value.each_pair do |k,v|
|
108
|
+
h[convert_ruby_to_js(k)] = convert_ruby_to_js(v)
|
109
|
+
end
|
110
|
+
h
|
111
|
+
else
|
112
|
+
raise TypeError, "Unknown how to convert to JS: #{value.inspect}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class_eval <<-'RUBY', "(execjs)", 1
|
117
|
+
def eval_in_context(code); @context.eval('js', code); end
|
118
|
+
RUBY
|
119
|
+
end
|
120
|
+
|
121
|
+
def name
|
122
|
+
"GraalVM (Graal.js)"
|
123
|
+
end
|
124
|
+
|
125
|
+
def available?
|
126
|
+
return @available if defined?(@available)
|
127
|
+
|
128
|
+
unless RUBY_ENGINE == "truffleruby"
|
129
|
+
return @available = false
|
130
|
+
end
|
131
|
+
|
132
|
+
unless defined?(Polyglot::InnerContext)
|
133
|
+
warn "TruffleRuby #{RUBY_ENGINE_VERSION} does not have support for inner contexts, use a more recent version", uplevel: 0 if $VERBOSE
|
134
|
+
return @available = false
|
135
|
+
end
|
136
|
+
|
137
|
+
unless Polyglot.languages.include? "js"
|
138
|
+
warn "The language 'js' is not available, you likely need to `export TRUFFLERUBYOPT='--jvm --polyglot'`", uplevel: 0 if $VERBOSE
|
139
|
+
warn "You also need to install the 'js' component with 'gu install js' on GraalVM 22.2+", uplevel: 0 if $VERBOSE
|
140
|
+
warn "Note that you need TruffleRuby+GraalVM and not just the TruffleRuby standalone to use #{self.class}", uplevel: 0 if $VERBOSE
|
141
|
+
return @available = false
|
142
|
+
end
|
143
|
+
|
144
|
+
@available = true
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -4,15 +4,16 @@ module ExecJS
|
|
4
4
|
class MiniRacerRuntime < Runtime
|
5
5
|
class Context < Runtime::Context
|
6
6
|
def initialize(runtime, source = "", options={})
|
7
|
-
source = encode(
|
7
|
+
source = source.encode(Encoding::UTF_8)
|
8
8
|
@context = ::MiniRacer::Context.new
|
9
|
+
@context.eval("delete this.console");
|
9
10
|
translate do
|
10
11
|
@context.eval(source)
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
14
15
|
def exec(source, options = {})
|
15
|
-
source = encode(
|
16
|
+
source = source.encode(Encoding::UTF_8)
|
16
17
|
|
17
18
|
if /\S/ =~ source
|
18
19
|
eval "(function(){#{source}})()"
|
@@ -20,7 +21,7 @@ module ExecJS
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def eval(source, options = {})
|
23
|
-
source = encode(
|
24
|
+
source = source.encode(Encoding::UTF_8)
|
24
25
|
|
25
26
|
if /\S/ =~ source
|
26
27
|
translate do
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require "execjs/runtime"
|
2
|
+
require "json"
|
2
3
|
|
3
4
|
module ExecJS
|
4
5
|
class RubyRhinoRuntime < Runtime
|
5
6
|
class Context < Runtime::Context
|
6
7
|
def initialize(runtime, source = "", options = {})
|
7
|
-
source = encode(
|
8
|
+
source = source.encode(Encoding::UTF_8)
|
8
9
|
|
9
10
|
@rhino_context = ::Rhino::Context.new
|
10
11
|
fix_memory_limit! @rhino_context
|
@@ -14,7 +15,7 @@ module ExecJS
|
|
14
15
|
end
|
15
16
|
|
16
17
|
def exec(source, options = {})
|
17
|
-
source = encode(
|
18
|
+
source = source.encode(Encoding::UTF_8)
|
18
19
|
|
19
20
|
if /\S/ =~ source
|
20
21
|
eval "(function(){#{source}})()", options
|
@@ -22,7 +23,7 @@ module ExecJS
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def eval(source, options = {})
|
25
|
-
source = encode(
|
26
|
+
source = source.encode(Encoding::UTF_8)
|
26
27
|
|
27
28
|
if /\S/ =~ source
|
28
29
|
unbox @rhino_context.eval("(#{source})")
|
@@ -32,7 +33,11 @@ module ExecJS
|
|
32
33
|
end
|
33
34
|
|
34
35
|
def call(properties, *args)
|
35
|
-
|
36
|
+
# Might no longer be necessary if therubyrhino handles Symbols directly:
|
37
|
+
# https://github.com/rubyjs/therubyrhino/issues/43
|
38
|
+
converted_args = JSON.parse(JSON.generate(args), create_additions: false)
|
39
|
+
|
40
|
+
unbox @rhino_context.eval(properties).call(*converted_args)
|
36
41
|
rescue Exception => e
|
37
42
|
raise wrap_error(e)
|
38
43
|
end
|
data/lib/execjs/runtime.rb
CHANGED
@@ -1,23 +1,34 @@
|
|
1
|
-
require "execjs/encoding"
|
2
|
-
|
3
1
|
module ExecJS
|
4
2
|
# Abstract base class for runtimes
|
5
3
|
class Runtime
|
6
4
|
class Context
|
7
|
-
include Encoding
|
8
|
-
|
9
5
|
def initialize(runtime, source = "", options = {})
|
10
6
|
end
|
11
7
|
|
8
|
+
# Evaluates the +source+ in the context of a function body and returns the
|
9
|
+
# returned value.
|
10
|
+
#
|
11
|
+
# context.exec("return 1") # => 1
|
12
|
+
# context.exec("1") # => nil (nothing was returned)
|
12
13
|
def exec(source, options = {})
|
13
14
|
raise NotImplementedError
|
14
15
|
end
|
15
16
|
|
17
|
+
# Evaluates the +source+ as an expression and returns the result.
|
18
|
+
#
|
19
|
+
# context.eval("1") # => 1
|
20
|
+
# context.eval("return 1") # => Raises SyntaxError
|
16
21
|
def eval(source, options = {})
|
17
22
|
raise NotImplementedError
|
18
23
|
end
|
19
24
|
|
20
|
-
|
25
|
+
# Evaluates +source+ as an expression (which should be of type
|
26
|
+
# +function+), and calls the function with the given arguments.
|
27
|
+
# The function will be evaluated with the global object as +this+.
|
28
|
+
#
|
29
|
+
# context.call("function(a, b) { return a + b }", 1, 1) # => 2
|
30
|
+
# context.call("CoffeeScript.compile", "1 + 1")
|
31
|
+
def call(source, *args)
|
21
32
|
raise NotImplementedError
|
22
33
|
end
|
23
34
|
end
|
data/lib/execjs/runtimes.rb
CHANGED
@@ -2,9 +2,9 @@ require "execjs/module"
|
|
2
2
|
require "execjs/disabled_runtime"
|
3
3
|
require "execjs/duktape_runtime"
|
4
4
|
require "execjs/external_runtime"
|
5
|
-
require "execjs/ruby_racer_runtime"
|
6
5
|
require "execjs/ruby_rhino_runtime"
|
7
6
|
require "execjs/mini_racer_runtime"
|
7
|
+
require "execjs/graaljs_runtime"
|
8
8
|
|
9
9
|
module ExecJS
|
10
10
|
module Runtimes
|
@@ -12,22 +12,32 @@ module ExecJS
|
|
12
12
|
|
13
13
|
Duktape = DuktapeRuntime.new
|
14
14
|
|
15
|
-
RubyRacer = RubyRacerRuntime.new
|
16
|
-
|
17
15
|
RubyRhino = RubyRhinoRuntime.new
|
18
16
|
|
17
|
+
GraalJS = GraalJSRuntime.new
|
18
|
+
|
19
19
|
MiniRacer = MiniRacerRuntime.new
|
20
20
|
|
21
21
|
Node = ExternalRuntime.new(
|
22
22
|
name: "Node.js (V8)",
|
23
|
-
command: ["
|
23
|
+
command: ["node", "nodejs"],
|
24
24
|
runner_path: ExecJS.root + "/support/node_runner.js",
|
25
25
|
encoding: 'UTF-8'
|
26
26
|
)
|
27
27
|
|
28
|
+
Bun = ExternalRuntime.new(
|
29
|
+
name: "Bun.sh",
|
30
|
+
command: ["bun"],
|
31
|
+
runner_path: ExecJS.root + "/support/bun_runner.js",
|
32
|
+
encoding: 'UTF-8'
|
33
|
+
)
|
34
|
+
|
28
35
|
JavaScriptCore = ExternalRuntime.new(
|
29
36
|
name: "JavaScriptCore",
|
30
|
-
command:
|
37
|
+
command: [
|
38
|
+
"/System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Helpers/jsc",
|
39
|
+
"/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc",
|
40
|
+
],
|
31
41
|
runner_path: ExecJS.root + "/support/jsc_runner.js"
|
32
42
|
)
|
33
43
|
|
@@ -64,7 +74,9 @@ module ExecJS
|
|
64
74
|
end
|
65
75
|
|
66
76
|
def self.from_environment
|
67
|
-
|
77
|
+
env = ENV["EXECJS_RUNTIME"]
|
78
|
+
if env && !env.empty?
|
79
|
+
name = env
|
68
80
|
raise RuntimeUnavailable, "#{name} runtime is not defined" unless const_defined?(name)
|
69
81
|
runtime = const_get(name)
|
70
82
|
|
@@ -79,10 +91,11 @@ module ExecJS
|
|
79
91
|
|
80
92
|
def self.runtimes
|
81
93
|
@runtimes ||= [
|
82
|
-
RubyRacer,
|
83
94
|
RubyRhino,
|
95
|
+
GraalJS,
|
84
96
|
Duktape,
|
85
97
|
MiniRacer,
|
98
|
+
Bun,
|
86
99
|
Node,
|
87
100
|
JavaScriptCore,
|
88
101
|
SpiderMonkey,
|
@@ -0,0 +1,29 @@
|
|
1
|
+
(function(program, execJS) { (function() {execJS(program) }).call({}); })(function(self, global, process, module, exports, require, console, setTimeout, setInterval, clearTimeout, clearInterval, setImmediate, clearImmediate) { #{source}
|
2
|
+
}, function(program) {
|
3
|
+
// Force BunJS to use sloppy mode see https://github.com/oven-sh/bun/issues/4527#issuecomment-1709520894
|
4
|
+
exports.abc = function(){}
|
5
|
+
var __process__ = process;
|
6
|
+
var printFinal = function(string) {
|
7
|
+
process.stdout.write('' + string, function() {
|
8
|
+
__process__.exit(0);
|
9
|
+
});
|
10
|
+
};
|
11
|
+
try {
|
12
|
+
delete this.process;
|
13
|
+
delete this.console;
|
14
|
+
result = program();
|
15
|
+
process = __process__;
|
16
|
+
if (typeof result == 'undefined' && result !== null) {
|
17
|
+
printFinal('["ok"]');
|
18
|
+
} else {
|
19
|
+
try {
|
20
|
+
printFinal(JSON.stringify(['ok', result]));
|
21
|
+
} catch (err) {
|
22
|
+
printFinal(JSON.stringify(['err', '' + err, err.stack]));
|
23
|
+
}
|
24
|
+
}
|
25
|
+
} catch (err) {
|
26
|
+
process = __process__;
|
27
|
+
printFinal(JSON.stringify(['err', '' + err, err.stack]));
|
28
|
+
}
|
29
|
+
});
|
@@ -2,6 +2,14 @@
|
|
2
2
|
}, function(program) {
|
3
3
|
var output;
|
4
4
|
try {
|
5
|
+
delete this.console;
|
6
|
+
delete this.setTimeout;
|
7
|
+
delete this.setInterval;
|
8
|
+
delete this.clearTimeout;
|
9
|
+
delete this.clearInterval;
|
10
|
+
delete this.setImmediate;
|
11
|
+
delete this.clearImmediate;
|
12
|
+
|
5
13
|
result = program();
|
6
14
|
if (typeof result == 'undefined' && result !== null) {
|
7
15
|
print('["ok"]');
|
@@ -1,20 +1,34 @@
|
|
1
|
-
(function(program, execJS) { execJS(program) })(function(global, module, exports, require, console, setTimeout, setInterval, clearTimeout, clearInterval, setImmediate, clearImmediate) { #{source}
|
1
|
+
(function(program, execJS) { execJS(program) })(function(global, process, module, exports, require, console, setTimeout, setInterval, clearTimeout, clearInterval, setImmediate, clearImmediate) { #{source}
|
2
2
|
}, function(program) {
|
3
|
-
var
|
4
|
-
|
3
|
+
var __process__ = process;
|
4
|
+
|
5
|
+
var printFinal = function(string) {
|
6
|
+
process.stdout.write('' + string, function() {
|
7
|
+
__process__.exit(0);
|
8
|
+
});
|
5
9
|
};
|
6
10
|
try {
|
11
|
+
delete this.process;
|
12
|
+
delete this.console;
|
13
|
+
delete this.setTimeout;
|
14
|
+
delete this.setInterval;
|
15
|
+
delete this.clearTimeout;
|
16
|
+
delete this.clearInterval;
|
17
|
+
delete this.setImmediate;
|
18
|
+
delete this.clearImmediate;
|
7
19
|
result = program();
|
20
|
+
this.process = __process__;
|
8
21
|
if (typeof result == 'undefined' && result !== null) {
|
9
|
-
|
22
|
+
printFinal('["ok"]');
|
10
23
|
} else {
|
11
24
|
try {
|
12
|
-
|
25
|
+
printFinal(JSON.stringify(['ok', result]));
|
13
26
|
} catch (err) {
|
14
|
-
|
27
|
+
printFinal(JSON.stringify(['err', '' + err, err.stack]));
|
15
28
|
}
|
16
29
|
}
|
17
30
|
} catch (err) {
|
18
|
-
|
31
|
+
this.process = __process__;
|
32
|
+
printFinal(JSON.stringify(['err', '' + err, err.stack]));
|
19
33
|
}
|
20
34
|
});
|
@@ -1,7 +1,14 @@
|
|
1
|
-
(function(program, execJS) { execJS(program) })(function() { #{source}
|
1
|
+
(function(program, execJS) { execJS(program) })(function(console, setTimeout, setInterval, clearTimeout, clearInterval, setImmediate, clearImmediate) { #{source}
|
2
2
|
}, function(program) {
|
3
3
|
var output;
|
4
4
|
try {
|
5
|
+
delete this.console;
|
6
|
+
delete this.setTimeout;
|
7
|
+
delete this.setInterval;
|
8
|
+
delete this.clearTimeout;
|
9
|
+
delete this.clearInterval;
|
10
|
+
delete this.setImmediate;
|
11
|
+
delete this.clearImmediate;
|
5
12
|
result = program();
|
6
13
|
if (typeof result == 'undefined' && result !== null) {
|
7
14
|
print('["ok"]');
|
data/lib/execjs/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: execjs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Stephenson
|
8
8
|
- Josh Peek
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-09-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -38,14 +38,14 @@ files:
|
|
38
38
|
- lib/execjs.rb
|
39
39
|
- lib/execjs/disabled_runtime.rb
|
40
40
|
- lib/execjs/duktape_runtime.rb
|
41
|
-
- lib/execjs/encoding.rb
|
42
41
|
- lib/execjs/external_runtime.rb
|
42
|
+
- lib/execjs/graaljs_runtime.rb
|
43
43
|
- lib/execjs/mini_racer_runtime.rb
|
44
44
|
- lib/execjs/module.rb
|
45
|
-
- lib/execjs/ruby_racer_runtime.rb
|
46
45
|
- lib/execjs/ruby_rhino_runtime.rb
|
47
46
|
- lib/execjs/runtime.rb
|
48
47
|
- lib/execjs/runtimes.rb
|
48
|
+
- lib/execjs/support/bun_runner.js
|
49
49
|
- lib/execjs/support/jsc_runner.js
|
50
50
|
- lib/execjs/support/jscript_runner.js
|
51
51
|
- lib/execjs/support/json2.js
|
@@ -57,7 +57,7 @@ homepage: https://github.com/rails/execjs
|
|
57
57
|
licenses:
|
58
58
|
- MIT
|
59
59
|
metadata: {}
|
60
|
-
post_install_message:
|
60
|
+
post_install_message:
|
61
61
|
rdoc_options: []
|
62
62
|
require_paths:
|
63
63
|
- lib
|
@@ -65,16 +65,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 2.5.0
|
69
69
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
70
|
requirements:
|
71
71
|
- - ">="
|
72
72
|
- !ruby/object:Gem::Version
|
73
73
|
version: '0'
|
74
74
|
requirements: []
|
75
|
-
|
76
|
-
|
77
|
-
signing_key:
|
75
|
+
rubygems_version: 3.3.7
|
76
|
+
signing_key:
|
78
77
|
specification_version: 4
|
79
78
|
summary: Run JavaScript code from Ruby
|
80
79
|
test_files: []
|
data/lib/execjs/encoding.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
module ExecJS
|
2
|
-
# Encodes strings as UTF-8
|
3
|
-
module Encoding
|
4
|
-
if RUBY_ENGINE == 'jruby' || RUBY_ENGINE == 'rbx'
|
5
|
-
# workaround for jruby bug http://jira.codehaus.org/browse/JRUBY-6588
|
6
|
-
# workaround for rbx bug https://github.com/rubinius/rubinius/issues/1729
|
7
|
-
def encode(string)
|
8
|
-
if string.encoding.name == 'ASCII-8BIT'
|
9
|
-
data = string.dup
|
10
|
-
data.force_encoding('UTF-8')
|
11
|
-
|
12
|
-
unless data.valid_encoding?
|
13
|
-
raise ::Encoding::UndefinedConversionError, "Could not encode ASCII-8BIT data #{string.dump} as UTF-8"
|
14
|
-
end
|
15
|
-
else
|
16
|
-
data = string.encode('UTF-8')
|
17
|
-
end
|
18
|
-
data
|
19
|
-
end
|
20
|
-
else
|
21
|
-
def encode(string)
|
22
|
-
string.encode('UTF-8')
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,114 +0,0 @@
|
|
1
|
-
require "execjs/runtime"
|
2
|
-
|
3
|
-
module ExecJS
|
4
|
-
class RubyRacerRuntime < Runtime
|
5
|
-
class Context < Runtime::Context
|
6
|
-
def initialize(runtime, source = "", options = {})
|
7
|
-
source = encode(source)
|
8
|
-
|
9
|
-
lock do
|
10
|
-
@v8_context = ::V8::Context.new
|
11
|
-
|
12
|
-
begin
|
13
|
-
@v8_context.eval(source)
|
14
|
-
rescue ::V8::JSError => e
|
15
|
-
raise wrap_error(e)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def exec(source, options = {})
|
21
|
-
source = encode(source)
|
22
|
-
|
23
|
-
if /\S/ =~ source
|
24
|
-
eval "(function(){#{source}})()", options
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def eval(source, options = {})
|
29
|
-
source = encode(source)
|
30
|
-
|
31
|
-
if /\S/ =~ source
|
32
|
-
lock do
|
33
|
-
begin
|
34
|
-
unbox @v8_context.eval("(#{source})")
|
35
|
-
rescue ::V8::JSError => e
|
36
|
-
raise wrap_error(e)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def call(properties, *args)
|
43
|
-
lock do
|
44
|
-
begin
|
45
|
-
unbox @v8_context.eval(properties).call(*args)
|
46
|
-
rescue ::V8::JSError => e
|
47
|
-
raise wrap_error(e)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def unbox(value)
|
53
|
-
case value
|
54
|
-
when ::V8::Function
|
55
|
-
nil
|
56
|
-
when ::V8::Array
|
57
|
-
value.map { |v| unbox(v) }
|
58
|
-
when ::V8::Object
|
59
|
-
value.inject({}) do |vs, (k, v)|
|
60
|
-
vs[k] = unbox(v) unless v.is_a?(::V8::Function)
|
61
|
-
vs
|
62
|
-
end
|
63
|
-
when String
|
64
|
-
value.force_encoding('UTF-8')
|
65
|
-
else
|
66
|
-
value
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
def lock
|
72
|
-
result, exception = nil, nil
|
73
|
-
V8::C::Locker() do
|
74
|
-
begin
|
75
|
-
result = yield
|
76
|
-
rescue Exception => e
|
77
|
-
exception = e
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
if exception
|
82
|
-
raise exception
|
83
|
-
else
|
84
|
-
result
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def wrap_error(e)
|
89
|
-
error_class = e.value["name"] == "SyntaxError" ? RuntimeError : ProgramError
|
90
|
-
|
91
|
-
stack = e.value["stack"] || ""
|
92
|
-
stack = stack.split("\n")
|
93
|
-
stack.shift
|
94
|
-
stack = [e.message[/<eval>:\d+:\d+/, 0]].compact if stack.empty?
|
95
|
-
stack = stack.map { |line| line.sub(" at ", "").sub("<eval>", "(execjs)").strip }
|
96
|
-
|
97
|
-
error = error_class.new(e.value.to_s)
|
98
|
-
error.set_backtrace(stack + caller)
|
99
|
-
error
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def name
|
104
|
-
"therubyracer (V8)"
|
105
|
-
end
|
106
|
-
|
107
|
-
def available?
|
108
|
-
require "v8"
|
109
|
-
true
|
110
|
-
rescue LoadError
|
111
|
-
false
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|