execjs 2.8.1 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6bd129488d607b71ba6aec4c087036583727f4114d632107be2297b96a6a20f2
4
- data.tar.gz: fea27c5987305700a3c5adbbe8f2e282dc5d49e6c579d2c91369886739342c26
3
+ metadata.gz: 62270ddc7b87cd04ea4c4c652a0a58a22b067051a07e31c2f48b05246566bfbc
4
+ data.tar.gz: b5ba2f65f36600db563faeb4e526e67f01927879d239e16e96e4861fa83121da
5
5
  SHA512:
6
- metadata.gz: 99fe4da9a1203aa378e4f73879db38d7f9737dedc92141c820e099229eac5d00e311ab56379d5a92ef41fa1323cedf2614ee2e971e0e5602096f30732aed1808
7
- data.tar.gz: df6fb1647179df49bef56c5570fbc7148bfa1e290945e398482e369572764b60c1293c2220c6e3101d6bd9880d47d4084f2b1325c5f39d321a186ef4ec2ac639
6
+ metadata.gz: 79e1992e371a9e182eed6aaa4b0efef15db4909f44cd981a701c83f954a9e0b7a59fb1459e5a9b332d2cd3f0f8aa3f9273789badfefe89fe5f3bcfc918d02c50
7
+ data.tar.gz: aec6e50425979484e5913f5c64c3acb1417a1ac2c72659f01defec23704bee3a0be558800fd486df1bb8eb575b0daa7b86cd15bcbfd04c1242b400fe37f70667
data/README.md CHANGED
@@ -11,11 +11,13 @@ ExecJS supports these runtimes:
11
11
  Rhino embedded within JRuby
12
12
  * [Duktape.rb](https://github.com/judofyr/duktape.rb) - Duktape JavaScript interpreter
13
13
  * [Node.js](http://nodejs.org/)
14
+ * [Bun.sh](https://bun.sh) - JavaScript runtime & toolkit designed for speed
14
15
  * Apple JavaScriptCore - Included with Mac OS X
15
16
  * [Microsoft Windows Script Host](http://msdn.microsoft.com/en-us/library/9bbdkx3k.aspx) (JScript)
16
17
  * [Google V8](http://code.google.com/p/v8/)
17
- * [mini_racer](https://github.com/discourse/mini_racer) - Google V8
18
+ * [mini_racer](https://github.com/rubyjs/mini_racer) - Google V8
18
19
  embedded within Ruby
20
+ * [GraalVM JavaScript](https://www.graalvm.org/javascript/) - used on TruffleRuby
19
21
 
20
22
  A short example:
21
23
 
@@ -6,21 +6,21 @@ 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(source), '(execjs)')
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(source)}})()", '(execjs)')
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(source)})", '(execjs)')
23
+ @ctx.eval_string("(#{source.encode(Encoding::UTF_8)})", '(execjs)')
24
24
  rescue Exception => e
25
25
  raise wrap_error(e)
26
26
  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(source)
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(source)
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(source)
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 generate_compile_method(@runner_path)
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")
@@ -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,7 +4,7 @@ module ExecJS
4
4
  class MiniRacerRuntime < Runtime
5
5
  class Context < Runtime::Context
6
6
  def initialize(runtime, source = "", options={})
7
- source = encode(source)
7
+ source = source.encode(Encoding::UTF_8)
8
8
  @context = ::MiniRacer::Context.new
9
9
  @context.eval("delete this.console");
10
10
  translate do
@@ -13,7 +13,7 @@ module ExecJS
13
13
  end
14
14
 
15
15
  def exec(source, options = {})
16
- source = encode(source)
16
+ source = source.encode(Encoding::UTF_8)
17
17
 
18
18
  if /\S/ =~ source
19
19
  eval "(function(){#{source}})()"
@@ -21,7 +21,7 @@ module ExecJS
21
21
  end
22
22
 
23
23
  def eval(source, options = {})
24
- source = encode(source)
24
+ source = source.encode(Encoding::UTF_8)
25
25
 
26
26
  if /\S/ =~ source
27
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(source)
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(source)
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(source)
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
- unbox @rhino_context.eval(properties).call(*args)
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
@@ -1,11 +1,7 @@
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
 
@@ -4,6 +4,7 @@ require "execjs/duktape_runtime"
4
4
  require "execjs/external_runtime"
5
5
  require "execjs/ruby_rhino_runtime"
6
6
  require "execjs/mini_racer_runtime"
7
+ require "execjs/graaljs_runtime"
7
8
 
8
9
  module ExecJS
9
10
  module Runtimes
@@ -13,6 +14,8 @@ module ExecJS
13
14
 
14
15
  RubyRhino = RubyRhinoRuntime.new
15
16
 
17
+ GraalJS = GraalJSRuntime.new
18
+
16
19
  MiniRacer = MiniRacerRuntime.new
17
20
 
18
21
  Node = ExternalRuntime.new(
@@ -22,6 +25,13 @@ module ExecJS
22
25
  encoding: 'UTF-8'
23
26
  )
24
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
+
25
35
  JavaScriptCore = ExternalRuntime.new(
26
36
  name: "JavaScriptCore",
27
37
  command: [
@@ -82,8 +92,10 @@ module ExecJS
82
92
  def self.runtimes
83
93
  @runtimes ||= [
84
94
  RubyRhino,
95
+ GraalJS,
85
96
  Duktape,
86
97
  MiniRacer,
98
+ Bun,
87
99
  Node,
88
100
  JavaScriptCore,
89
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
+ });
@@ -3,6 +3,13 @@
3
3
  var output;
4
4
  try {
5
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
+
6
13
  result = program();
7
14
  if (typeof result == 'undefined' && result !== null) {
8
15
  print('["ok"]');
@@ -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"]');
@@ -1,3 +1,3 @@
1
1
  module ExecJS
2
- VERSION = "2.8.1"
2
+ VERSION = "2.9.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: execjs
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.1
4
+ version: 2.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Stephenson
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-05-14 00:00:00.000000000 Z
12
+ date: 2023-09-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -38,13 +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
45
  - lib/execjs/ruby_rhino_runtime.rb
46
46
  - lib/execjs/runtime.rb
47
47
  - lib/execjs/runtimes.rb
48
+ - lib/execjs/support/bun_runner.js
48
49
  - lib/execjs/support/jsc_runner.js
49
50
  - lib/execjs/support/jscript_runner.js
50
51
  - lib/execjs/support/json2.js
@@ -71,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
72
  - !ruby/object:Gem::Version
72
73
  version: '0'
73
74
  requirements: []
74
- rubygems_version: 3.2.15
75
+ rubygems_version: 3.3.7
75
76
  signing_key:
76
77
  specification_version: 4
77
78
  summary: Run JavaScript code from Ruby
@@ -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