From c37045ecf6db73cf5f805d7e7cddfa62fbd1240b Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Fri, 8 Jul 2022 14:34:50 +0200 Subject: [PATCH 01/32] GraalVM 22.2+ needs `gu install js` for JavaScript to be available --- .github/workflows/ci.yml | 4 ++++ lib/execjs/graaljs_runtime.rb | 1 + 2 files changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26fb819..7a5bc80 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,10 @@ jobs: - name: Set TRUFFLERUBYOPT run: echo "TRUFFLERUBYOPT=--jvm --polyglot" >> $GITHUB_ENV if: startsWith(matrix.ruby, 'truffleruby+graalvm') + - name: Install GraalVM js component + run: if ! gu list | grep '^js '; then gu install js; fi + if: startsWith(matrix.ruby, 'truffleruby+graalvm') + - name: Run test run: rake - name: Install gem diff --git a/lib/execjs/graaljs_runtime.rb b/lib/execjs/graaljs_runtime.rb index acb931a..484f18f 100644 --- a/lib/execjs/graaljs_runtime.rb +++ b/lib/execjs/graaljs_runtime.rb @@ -136,6 +136,7 @@ def available? unless Polyglot.languages.include? "js" warn "The language 'js' is not available, you likely need to `export TRUFFLERUBYOPT='--jvm --polyglot'`", uplevel: 0 if $VERBOSE + warn "You also need to install the 'js' component with 'gu install js' on GraalVM 22.2+", uplevel: 0 if $VERBOSE warn "Note that you need TruffleRuby+GraalVM and not just the TruffleRuby standalone to use #{self.class}", uplevel: 0 if $VERBOSE return @available = false end From 19b1e4f9f61e8530f406a0c1dfb64b872b95ef9b Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Fri, 8 Jul 2022 15:05:47 +0200 Subject: [PATCH 02/32] Convert Ruby Strings to TruffleString when passing them to JavaScript * To work around JavaScript not yet preferring JS String methods to Ruby String methods inside JS code (GR-39371). --- lib/execjs/graaljs_runtime.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/execjs/graaljs_runtime.rb b/lib/execjs/graaljs_runtime.rb index 484f18f..fe2b5db 100644 --- a/lib/execjs/graaljs_runtime.rb +++ b/lib/execjs/graaljs_runtime.rb @@ -51,7 +51,7 @@ def call(source, *args) def translate convert_js_to_ruby yield rescue ForeignException => e - if e.message.start_with?('SyntaxError:') + if e.message && e.message.start_with?('SyntaxError:') error_class = ExecJS::RuntimeError else error_class = ExecJS::ProgramError @@ -96,8 +96,10 @@ def convert_js_to_ruby(value) def convert_ruby_to_js(value) case value - when nil, true, false, Integer, Float, String + when nil, true, false, Integer, Float value + when String + Truffle::Interop.as_truffle_string value when Symbol value.to_s when Array From 9e0855ddcdfc573b6271fb96e865d76e3433745f Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 19 Jul 2022 17:17:52 +0200 Subject: [PATCH 03/32] Convert Symbol explicitly to a JS String and add test --- lib/execjs/graaljs_runtime.rb | 4 +--- test/test_execjs.rb | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/execjs/graaljs_runtime.rb b/lib/execjs/graaljs_runtime.rb index fe2b5db..86121b0 100644 --- a/lib/execjs/graaljs_runtime.rb +++ b/lib/execjs/graaljs_runtime.rb @@ -98,10 +98,8 @@ def convert_ruby_to_js(value) case value when nil, true, false, Integer, Float value - when String + when String, Symbol Truffle::Interop.as_truffle_string value - when Symbol - value.to_s when Array value.map { |e| convert_ruby_to_js(e) } when Hash diff --git a/test/test_execjs.rb b/test/test_execjs.rb index dbf9703..f5b25b5 100644 --- a/test/test_execjs.rb +++ b/test/test_execjs.rb @@ -172,6 +172,9 @@ def test_symbol assert_equal "symbol", context.call("echo", :symbol) assert_equal ["symbol"], context.call("echo", [:symbol]) assert_equal({"key" => "value"}, context.call("echo", {key: :value})) + + context = ExecJS.compile("function myslice(str) { return str.slice(1); }") + assert_equal "ymbol", context.call("myslice", :symbol) end def test_additional_options From 1c1770d8b0a959b22bd514fd31bf227827aaf4b0 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Wed, 11 Jan 2023 12:59:15 +0100 Subject: [PATCH 04/32] Avoid anonymous eval This makes it hard to track down the source of allocations and such when profiling. --- lib/execjs/external_runtime.rb | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/execjs/external_runtime.rb b/lib/execjs/external_runtime.rb index 164587c..8e49a25 100644 --- a/lib/execjs/external_runtime.rb +++ b/lib/execjs/external_runtime.rb @@ -103,7 +103,13 @@ def initialize(options) @popen_options[:internal_encoding] = ::Encoding.default_internal || 'UTF-8' if @runner_path - instance_eval generate_compile_method(@runner_path) + instance_eval <<~RUBY, __FILE__, __LINE__ + def compile_source(source) + <<-RUNNER + #{IO.read(@runner_path)} + RUNNER + end + RUBY end end @@ -143,15 +149,6 @@ def locate_executable(command) end protected - def generate_compile_method(path) - <<-RUBY - def compile_source(source) - <<-RUNNER - #{IO.read(path)} - RUNNER - end - RUBY - end def json2_source @json2_source ||= IO.read(ExecJS.root + "/support/json2.js") From 28aa138a6959685c3c5c379d8734fb80aa483b43 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Mon, 27 Feb 2023 19:11:49 +0100 Subject: [PATCH 05/32] Mention GraalVM JavaScript in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cf22749..9d6a064 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ ExecJS supports these runtimes: * [Google V8](http://code.google.com/p/v8/) * [mini_racer](https://github.com/discourse/mini_racer) - Google V8 embedded within Ruby +* [GraalVM JavaScript](https://www.graalvm.org/javascript/) - used on TruffleRuby A short example: From b4d2c763c4004082909a1173af731c5b131c8640 Mon Sep 17 00:00:00 2001 From: Sebastian Cohnen Date: Thu, 25 May 2023 19:42:52 +0200 Subject: [PATCH 06/32] updates link to mini_racer GH repository --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d6a064..f791177 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ ExecJS supports these runtimes: * Apple JavaScriptCore - Included with Mac OS X * [Microsoft Windows Script Host](http://msdn.microsoft.com/en-us/library/9bbdkx3k.aspx) (JScript) * [Google V8](http://code.google.com/p/v8/) -* [mini_racer](https://github.com/discourse/mini_racer) - Google V8 +* [mini_racer](https://github.com/rubyjs/mini_racer) - Google V8 embedded within Ruby * [GraalVM JavaScript](https://www.graalvm.org/javascript/) - used on TruffleRuby From 5fd5de40847a926c97f33b009c3d38e1228bd00b Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Thu, 1 Jun 2023 15:51:12 +0900 Subject: [PATCH 07/32] rubygems-update 3.4+ requires ruby >= 2.6 https://github.com/rails/execjs/actions/runs/5083574091/jobs/9134753115 --- .github/workflows/ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a5bc80..1f46f4a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,9 +18,8 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} + rubygems: ${{ (matrix.ruby_version < '2.6' && '3.2.3') || 'latest' }} - - name: Update Rubygems - run: gem update --system - name: Install bundler run: gem install bundler -v '2.2.16' - name: Install dependencies @@ -54,8 +53,7 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} - - name: Update Rubygems - run: gem update --system + rubygems: ${{ (matrix.ruby_version < '2.6' && '3.2.3') || 'latest' }} - name: Install bundler run: gem install bundler -v '2.2.16' - name: Install dependencies From a0d234cdb9d6d4aa1247c170e8c16193ea25f12f Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Thu, 1 Jun 2023 17:11:21 +0900 Subject: [PATCH 08/32] Skip `eval code@` line thrown by Apple JavaScriptCore This fixes CI failures on macos: https://github.com/rails/execjs/actions/runs/5141287879/jobs/9253613193 --- lib/execjs/external_runtime.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/execjs/external_runtime.rb b/lib/execjs/external_runtime.rb index 8e49a25..798d809 100644 --- a/lib/execjs/external_runtime.rb +++ b/lib/execjs/external_runtime.rb @@ -78,7 +78,7 @@ def extract_result(output, filename) .sub(filename, "(execjs)") .strip end - stack.reject! { |line| ["eval code", "eval@[native code]"].include?(line) } + stack.reject! { |line| ["eval code", "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) From 2a2673d1833c2fa89732c584ae62b781a7d6b853 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Thu, 1 Jun 2023 18:13:25 +0900 Subject: [PATCH 09/32] CI against stable version of truffleruby+graalvm because 23.0.0-preview1 aborts with `gu: command not found` https://github.com/rails/execjs/actions/runs/5142014882/jobs/9255214275 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f46f4a..8d085f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: [ '3.0', '2.7', '2.6', '2.5', 'jruby', 'truffleruby', 'truffleruby+graalvm' ] + ruby: [ '3.0', '2.7', '2.6', '2.5', 'jruby', 'truffleruby', 'truffleruby+graalvm-22.3.1' ] runs-on: ubuntu-latest steps: - name: Checkout From 85d1fc43eb4b711ae8953acc157868d6729eca90 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Thu, 1 Jun 2023 18:32:43 +0900 Subject: [PATCH 10/32] CI against ruby 3.1 and 3.2 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d085f8..a755342 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: [ '3.0', '2.7', '2.6', '2.5', 'jruby', 'truffleruby', 'truffleruby+graalvm-22.3.1' ] + ruby: [ '3.2', '3.1', '3.0', '2.7', '2.6', '2.5', 'jruby', 'truffleruby', 'truffleruby+graalvm-22.3.1' ] runs-on: ubuntu-latest steps: - name: Checkout @@ -40,7 +40,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: [ '3.0', '2.7', '2.6', '2.5' ] + ruby: [ '3.2', '3.1', '3.0', '2.7', '2.6', '2.5' ] runs-on: macos-latest steps: - name: Checkout From f49db2167accbc1b8ec117e12dd397ed8a5a2534 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Thu, 1 Jun 2023 19:20:52 +0900 Subject: [PATCH 11/32] "Node.js 12 actions are deprecated. Please update the following actions to use Node.js 16: actions/checkout@v2." --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a755342..7329012 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install Node run: sudo apt-get install -y nodejs - name: Set up Ruby @@ -44,7 +44,7 @@ jobs: runs-on: macos-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install V8 run: | brew update From 0195abbfc3e9d8cfcb35a0c3b2dcc66379a9d92d Mon Sep 17 00:00:00 2001 From: Jason Meller Date: Sun, 10 Sep 2023 10:59:44 -0400 Subject: [PATCH 12/32] Add Bun as an available runtime --- .github/workflows/ci.yml | 4 ++++ README.md | 1 + lib/execjs/runtimes.rb | 8 ++++++++ lib/execjs/support/bun_runner.js | 29 +++++++++++++++++++++++++++++ test/fixtures/uglify.js | 2 +- test/test_execjs.rb | 15 +++++++++------ 6 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 lib/execjs/support/bun_runner.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7329012..2ac3dde 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,10 @@ jobs: uses: actions/checkout@v3 - name: Install Node run: sudo apt-get install -y nodejs + - name: Install Bun + - uses: oven-sh/setup-bun@v1 + with: + bun-version: latest - name: Set up Ruby uses: ruby/setup-ruby@v1 with: diff --git a/README.md b/README.md index f791177..438f48f 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ ExecJS supports these runtimes: Rhino embedded within JRuby * [Duktape.rb](https://github.com/judofyr/duktape.rb) - Duktape JavaScript interpreter * [Node.js](http://nodejs.org/) +* [Bun.sh](https://bun.sh) - JavaScript runtime & toolkit designed for speed * Apple JavaScriptCore - Included with Mac OS X * [Microsoft Windows Script Host](http://msdn.microsoft.com/en-us/library/9bbdkx3k.aspx) (JScript) * [Google V8](http://code.google.com/p/v8/) diff --git a/lib/execjs/runtimes.rb b/lib/execjs/runtimes.rb index 615ecd6..9360e80 100644 --- a/lib/execjs/runtimes.rb +++ b/lib/execjs/runtimes.rb @@ -25,6 +25,13 @@ module Runtimes encoding: 'UTF-8' ) + Bun = ExternalRuntime.new( + name: "Bun.sh", + command: ["bun"], + runner_path: ExecJS.root + "/support/bun_runner.js", + encoding: 'UTF-8' + ) + JavaScriptCore = ExternalRuntime.new( name: "JavaScriptCore", command: [ @@ -89,6 +96,7 @@ def self.runtimes Duktape, MiniRacer, Node, + Bun, JavaScriptCore, SpiderMonkey, JScript, diff --git a/lib/execjs/support/bun_runner.js b/lib/execjs/support/bun_runner.js new file mode 100644 index 0000000..ddbdedf --- /dev/null +++ b/lib/execjs/support/bun_runner.js @@ -0,0 +1,29 @@ +(function(program, execJS) { (function() {execJS(program) }).call({}); })(function(self, global, process, module, exports, require, console, setTimeout, setInterval, clearTimeout, clearInterval, setImmediate, clearImmediate) { #{source} +}, function(program) { + // Force BunJS to use sloppy mode see https://github.com/oven-sh/bun/issues/4527#issuecomment-1709520894 + exports.abc = function(){} + var __process__ = process; + var printFinal = function(string) { + process.stdout.write('' + string, function() { + __process__.exit(0); + }); + }; + try { + delete this.process; + delete this.console; + result = program(); + process = __process__; + if (typeof result == 'undefined' && result !== null) { + printFinal('["ok"]'); + } else { + try { + printFinal(JSON.stringify(['ok', result])); + } catch (err) { + printFinal(JSON.stringify(['err', '' + err, err.stack])); + } + } + } catch (err) { + process = __process__; + printFinal(JSON.stringify(['err', '' + err, err.stack])); + } +}); diff --git a/test/fixtures/uglify.js b/test/fixtures/uglify.js index ca48b66..71ec85c 100644 --- a/test/fixtures/uglify.js +++ b/test/fixtures/uglify.js @@ -307,7 +307,7 @@ if(!String.prototype.trim) { function definePropertyWorks() { try { Object.defineProperty({}, "property", {}); - return "property" in object; + return true; } catch (exception) { return false; } diff --git a/test/test_execjs.rb b/test/test_execjs.rb index f5b25b5..a2b698d 100644 --- a/test/test_execjs.rb +++ b/test/test_execjs.rb @@ -296,6 +296,9 @@ def test_console_is_undefined end def test_timers_are_undefined + # See Bug https://github.com/oven-sh/bun/issues/4806 + skip if ENV["EXECJS_RUNTIME"] == "Bun" + assert ExecJS.eval("typeof setTimeout == 'undefined'") assert ExecJS.eval("typeof setInterval == 'undefined'") assert ExecJS.eval("typeof clearTimeout == 'undefined'") @@ -327,7 +330,7 @@ def test_exec_syntax_error flunk rescue ExecJS::RuntimeError => e assert e - assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n") + assert e.backtrace.join("\n").include?("(execjs):") end end @@ -337,7 +340,7 @@ def test_eval_syntax_error flunk rescue ExecJS::RuntimeError => e assert e - assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n") + assert e.backtrace.join("\n").include?("(execjs):") end end @@ -347,7 +350,7 @@ def test_compile_syntax_error flunk rescue ExecJS::RuntimeError => e assert e - assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n") + assert e.backtrace[0].include?("(execjs):"), e.backtrace.join("\n") end end @@ -357,7 +360,7 @@ def test_exec_thrown_error flunk rescue ExecJS::ProgramError => e assert e - assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n") + assert e.backtrace.join("\n").include?("(execjs):") end end @@ -367,7 +370,7 @@ def test_eval_thrown_error flunk rescue ExecJS::ProgramError => e assert e - assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n") + assert e.backtrace.join("\n").include?("(execjs):") end end @@ -377,7 +380,7 @@ def test_compile_thrown_error flunk rescue ExecJS::ProgramError => e assert e - assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n") + assert e.backtrace.join("\n").include?("(execjs):") end end From f565d6e412ceb4c0fbd047315ce4ef361384fe98 Mon Sep 17 00:00:00 2001 From: Jason Meller Date: Sun, 10 Sep 2023 12:53:05 -0400 Subject: [PATCH 13/32] Put bun before node --- lib/execjs/runtimes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/execjs/runtimes.rb b/lib/execjs/runtimes.rb index 9360e80..fd9d5c8 100644 --- a/lib/execjs/runtimes.rb +++ b/lib/execjs/runtimes.rb @@ -95,8 +95,8 @@ def self.runtimes GraalJS, Duktape, MiniRacer, - Node, Bun, + Node, JavaScriptCore, SpiderMonkey, JScript, From d89ee741905c6b8dbbf7d9410287653b2f028dc7 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Mon, 11 Sep 2023 13:40:46 +0200 Subject: [PATCH 14/32] Fix GitHub Actions --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ac3dde..9c38d4f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: - name: Install Node run: sudo apt-get install -y nodejs - name: Install Bun - - uses: oven-sh/setup-bun@v1 + uses: oven-sh/setup-bun@v1 with: bun-version: latest - name: Set up Ruby From 4e31ac13a2a662d55b34da3a32cddd8de3d4b0f5 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Mon, 11 Sep 2023 14:37:22 +0200 Subject: [PATCH 15/32] Release 2.9.0 --- lib/execjs/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/execjs/version.rb b/lib/execjs/version.rb index 3e48d23..40d4418 100644 --- a/lib/execjs/version.rb +++ b/lib/execjs/version.rb @@ -1,3 +1,3 @@ module ExecJS - VERSION = "2.8.1" + VERSION = "2.9.0" end From 1dfec33733b0813e29d0b0d303d09a93354891cb Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Wed, 13 Sep 2023 10:26:25 +0200 Subject: [PATCH 16/32] Add a README section on how to manually select runtimes Fix: #86 --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 438f48f..a83657c 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,22 @@ context.call("CoffeeScript.compile", "square = (x) -> x * x", bare: true) # => "var square;\nsquare = function(x) {\n return x * x;\n};" ``` +# Forcing a specific runtime + +If you'd like to use a specific runtime rather than the autodected one, you can assign `ExecJS.runtime`: + +```ruby +ExecJS.runtime = ExecJS::Runtimes::Node +``` + +Alternatively, you can define it via the `EXECJS_RUNTIME` environment variable: + +```bash +EXECJS_RUNTIME=Node ruby ... +``` + +You can find the list of possible runtimes in [`lib/execjs/runtimes.rb`](https://github.com/rails/execjs/blob/master/lib/execjs/runtimes.rb). + # Installation ``` From 6c1c228ab4b198ff38b2d9175802d7f314e8ac47 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Wed, 13 Sep 2023 13:04:21 +0200 Subject: [PATCH 17/32] Update the required ruby version Fix: https://github.com/rails/execjs/issues/128 --- execjs.gemspec | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/execjs.gemspec b/execjs.gemspec index 6862dac..e83912b 100644 --- a/execjs.gemspec +++ b/execjs.gemspec @@ -18,6 +18,5 @@ Gem::Specification.new do |s| s.authors = ["Sam Stephenson", "Josh Peek"] s.email = ["sstephenson@gmail.com", "josh@joshpeek.com"] - # We only support MRI 2+ but this is needed to work with JRuby 1.7. - s.required_ruby_version = '>= 1.9.3' + s.required_ruby_version = '>= 2.5.0' end From 5cce03a1614a9477ea5c079b336be80206ee013f Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Sat, 16 Sep 2023 18:56:31 +0200 Subject: [PATCH 18/32] Handle Bun priting loaded env variables on STDERR Fix: https://github.com/rails/execjs/issues/130 --- lib/execjs/external_runtime.rb | 4 ++-- test/test_execjs.rb | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/execjs/external_runtime.rb b/lib/execjs/external_runtime.rb index 798d809..a0325f4 100644 --- a/lib/execjs/external_runtime.rb +++ b/lib/execjs/external_runtime.rb @@ -194,7 +194,7 @@ def shell_escape(*args) require 'shellwords' def exec_runtime(filename) - command = "#{Shellwords.join(binary.split(' ') << filename)} 2>&1" + command = "#{Shellwords.join(binary.split(' ') << filename)}" io = IO.popen(command, **@popen_options) output = io.read io.close @@ -207,7 +207,7 @@ def exec_runtime(filename) end else def exec_runtime(filename) - io = IO.popen(binary.split(' ') << filename, **(@popen_options.merge({err: [:child, :out]}))) + io = IO.popen(binary.split(' ') << filename, **@popen_options) output = io.read io.close diff --git a/test/test_execjs.rb b/test/test_execjs.rb index a2b698d..4b0976f 100644 --- a/test/test_execjs.rb +++ b/test/test_execjs.rb @@ -56,6 +56,16 @@ def test_call_with_complex_properties assert_equal 2, context.call("(function(bar) { return foo + bar })", 1) end + def test_call_with_env_file + Dir.mktmpdir do |dir| + Dir.chdir(dir) do + # Bun prints on STDOUT when loading .env files + File.write(".env", "FOO=BAR") + assert_equal 2, ExecJS.eval("1 + 1") + end + end + end + def test_call_with_this # Known bug: https://github.com/cowboyd/therubyrhino/issues/39 skip if ExecJS.runtime.is_a?(ExecJS::RubyRhinoRuntime) From 0b9901e99d9d49c9a739cfa54389e197941ec115 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Sat, 16 Sep 2023 19:24:17 +0200 Subject: [PATCH 19/32] Release 2.9.1 --- lib/execjs/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/execjs/version.rb b/lib/execjs/version.rb index 40d4418..37766b5 100644 --- a/lib/execjs/version.rb +++ b/lib/execjs/version.rb @@ -1,3 +1,3 @@ module ExecJS - VERSION = "2.9.0" + VERSION = "2.9.1" end From c1d830ebf24ab5dc250532cdb51d58a4be0b825f Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 19 Sep 2023 16:25:46 +0200 Subject: [PATCH 20/32] Use the latest truffleruby+graalvm release in CI --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c38d4f..7cb9bd9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: [ '3.2', '3.1', '3.0', '2.7', '2.6', '2.5', 'jruby', 'truffleruby', 'truffleruby+graalvm-22.3.1' ] + ruby: [ '3.2', '3.1', '3.0', '2.7', '2.6', '2.5', 'jruby', 'truffleruby', 'truffleruby+graalvm' ] runs-on: ubuntu-latest steps: - name: Checkout @@ -32,8 +32,8 @@ jobs: - name: Set TRUFFLERUBYOPT run: echo "TRUFFLERUBYOPT=--jvm --polyglot" >> $GITHUB_ENV if: startsWith(matrix.ruby, 'truffleruby+graalvm') - - name: Install GraalVM js component - run: if ! gu list | grep '^js '; then gu install js; fi + - name: Install GraalJS + run: truffleruby-polyglot-get js if: startsWith(matrix.ruby, 'truffleruby+graalvm') - name: Run test From 63ec8256c643f901e5f883e1d05511e605c114fb Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 19 Sep 2023 16:41:42 +0200 Subject: [PATCH 21/32] Update documentation to install GraalJS for TruffleRuby 23.1 --- lib/execjs/graaljs_runtime.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/execjs/graaljs_runtime.rb b/lib/execjs/graaljs_runtime.rb index 86121b0..f42c906 100644 --- a/lib/execjs/graaljs_runtime.rb +++ b/lib/execjs/graaljs_runtime.rb @@ -136,8 +136,7 @@ def available? unless Polyglot.languages.include? "js" warn "The language 'js' is not available, you likely need to `export TRUFFLERUBYOPT='--jvm --polyglot'`", uplevel: 0 if $VERBOSE - warn "You also need to install the 'js' component with 'gu install js' on GraalVM 22.2+", uplevel: 0 if $VERBOSE - warn "Note that you need TruffleRuby+GraalVM and not just the TruffleRuby standalone to use #{self.class}", uplevel: 0 if $VERBOSE + warn "You also need to install the 'js' component, see https://github.com/oracle/truffleruby/blob/master/doc/user/polyglot.md#installing-other-languages", uplevel: 0 if $VERBOSE return @available = false end From 85c6b87a475f8e08a0f642e15b66173e67fe7745 Mon Sep 17 00:00:00 2001 From: Reese Armstrong Date: Thu, 5 Oct 2023 16:39:19 -0500 Subject: [PATCH 22/32] Add async/await & promise support to Bun runner --- lib/execjs/support/bun_runner.js | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/execjs/support/bun_runner.js b/lib/execjs/support/bun_runner.js index ddbdedf..f5bd11a 100644 --- a/lib/execjs/support/bun_runner.js +++ b/lib/execjs/support/bun_runner.js @@ -1,4 +1,4 @@ -(function(program, execJS) { (function() {execJS(program) }).call({}); })(function(self, global, process, module, exports, require, console, setTimeout, setInterval, clearTimeout, clearInterval, setImmediate, clearImmediate) { #{source} +(function(program, execJS) { (function() {execJS(program) }).call({}); })(async function(self, global, process, module, exports, require, console, setTimeout, setInterval, clearTimeout, clearInterval, setImmediate, clearImmediate) { #{source} }, function(program) { // Force BunJS to use sloppy mode see https://github.com/oven-sh/bun/issues/4527#issuecomment-1709520894 exports.abc = function(){} @@ -11,17 +11,21 @@ try { delete this.process; delete this.console; - result = program(); - process = __process__; - if (typeof result == 'undefined' && result !== null) { - printFinal('["ok"]'); - } else { - try { - printFinal(JSON.stringify(['ok', result])); - } catch (err) { - printFinal(JSON.stringify(['err', '' + err, err.stack])); + (program()).then((result) => { + process = __process__; + if (typeof result == 'undefined' && result !== null) { + printFinal('["ok"]'); + } else { + try { + printFinal(JSON.stringify(['ok', result])); + } catch (err) { + printFinal(JSON.stringify(['err', '' + err, err.stack])); + } } - } + }).catch((err) => { + process = __process__; + printFinal(JSON.stringify(['err', '' + err, err.stack])); + }) } catch (err) { process = __process__; printFinal(JSON.stringify(['err', '' + err, err.stack])); From 427e1261be99312fa8ada502616fd8cfadec5495 Mon Sep 17 00:00:00 2001 From: tomocrafter Date: Wed, 18 Oct 2023 16:54:53 +0900 Subject: [PATCH 23/32] Use Bun.write(Bun.stdout, '') for output --- lib/execjs/support/bun_runner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/execjs/support/bun_runner.js b/lib/execjs/support/bun_runner.js index ddbdedf..08605af 100644 --- a/lib/execjs/support/bun_runner.js +++ b/lib/execjs/support/bun_runner.js @@ -4,7 +4,7 @@ exports.abc = function(){} var __process__ = process; var printFinal = function(string) { - process.stdout.write('' + string, function() { + Bun.write(Bun.stdout, '' + string).then(function() { __process__.exit(0); }); }; From bd090eacb23bc10bf4afeafb184c54a4c8f442f9 Mon Sep 17 00:00:00 2001 From: m-nakamura145 Date: Wed, 3 Jan 2024 21:49:10 +0900 Subject: [PATCH 24/32] Add Ruby 3.3 to CI matrix --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7cb9bd9..a9b79b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: [ '3.2', '3.1', '3.0', '2.7', '2.6', '2.5', 'jruby', 'truffleruby', 'truffleruby+graalvm' ] + ruby: [ '3.3', '3.2', '3.1', '3.0', '2.7', '2.6', '2.5', 'jruby', 'truffleruby', 'truffleruby+graalvm' ] runs-on: ubuntu-latest steps: - name: Checkout @@ -44,7 +44,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: [ '3.2', '3.1', '3.0', '2.7', '2.6', '2.5' ] + ruby: [ '3.3', '3.2', '3.1', '3.0', '2.7', '2.6', '2.5' ] runs-on: macos-latest steps: - name: Checkout From 3e59f173893c4dba76ade9034615c33d9b594881 Mon Sep 17 00:00:00 2001 From: Kuyseng CHHOEUN Date: Wed, 10 Jan 2024 15:12:03 +0700 Subject: [PATCH 25/32] Fix spelling and grammar in README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a83657c..5603f0f 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ context.call("CoffeeScript.compile", "square = (x) -> x * x", bare: true) # Forcing a specific runtime -If you'd like to use a specific runtime rather than the autodected one, you can assign `ExecJS.runtime`: +If you'd like to use a specific runtime rather than the autodetected one, you can assign `ExecJS.runtime`: ```ruby ExecJS.runtime = ExecJS::Runtimes::Node @@ -65,7 +65,7 @@ $ gem install execjs **Why can't I use CommonJS `require()` inside ExecJS?** -ExecJS provides a lowest common denominator interface to any JavaScript runtime. +ExecJS provides the lowest common denominator interface to any JavaScript runtime. Use ExecJS when it doesn't matter which JavaScript interpreter your code runs in. If you want to access the Node API, you should check another library like [commonjs.rb](https://github.com/cowboyd/commonjs.rb) designed to provide a @@ -92,7 +92,7 @@ You shouldn't use `ExecJS.eval` on any inputs you wouldn't feel comfortable Ruby ## Contributing to ExecJS -ExecJS is work of dozens of contributors. You're encouraged to submit pull requests, propose +ExecJS is the work of dozens of contributors. You're encouraged to submit pull requests, propose features and discuss issues. See [CONTRIBUTING](CONTRIBUTING.md). From 46f73426dcf64362d197f6d1241e9907f40719a3 Mon Sep 17 00:00:00 2001 From: m-nakamura145 Date: Mon, 5 Feb 2024 21:47:55 +0900 Subject: [PATCH 26/32] Bump actions/checkout --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9b79b8..abf2107 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Node run: sudo apt-get install -y nodejs - name: Install Bun @@ -48,7 +48,7 @@ jobs: runs-on: macos-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install V8 run: | brew update From 4dd71a27fcb7a1d3dd5be42c18e36147fe98cd1b Mon Sep 17 00:00:00 2001 From: Matt Menefee Date: Tue, 6 Feb 2024 01:22:12 -0600 Subject: [PATCH 27/32] Update link to CoffeeScript source in README.md Update the link to the CoffeeScript source in README.md and replace the use of "open-uri" with "net/http", as that is more conventional in 2024. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5603f0f..f3c043f 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ A longer example, demonstrating how to invoke the CoffeeScript compiler: ``` ruby require "execjs" -require "open-uri" -source = open("http://coffeescript.org/extras/coffee-script.js").read +require "net/http" +source = Net::HTTP.get(URI("https://coffeescript.org/browser-compiler-legacy/coffeescript.js")) context = ExecJS.compile(source) context.call("CoffeeScript.compile", "square = (x) -> x * x", bare: true) From 3ab72a6224c1624d965116da63e55dc2dbbafb3f Mon Sep 17 00:00:00 2001 From: Reese Armstrong Date: Thu, 29 Feb 2024 18:29:54 +0000 Subject: [PATCH 28/32] refactor and add test case --- lib/execjs/support/bun_runner.js | 26 +++++++++++--------------- test/test_execjs.rb | 9 +++++++++ 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/lib/execjs/support/bun_runner.js b/lib/execjs/support/bun_runner.js index f5bd11a..ec381d2 100644 --- a/lib/execjs/support/bun_runner.js +++ b/lib/execjs/support/bun_runner.js @@ -1,5 +1,5 @@ (function(program, execJS) { (function() {execJS(program) }).call({}); })(async function(self, global, process, module, exports, require, console, setTimeout, setInterval, clearTimeout, clearInterval, setImmediate, clearImmediate) { #{source} -}, function(program) { +}, async function(program) { // Force BunJS to use sloppy mode see https://github.com/oven-sh/bun/issues/4527#issuecomment-1709520894 exports.abc = function(){} var __process__ = process; @@ -11,21 +11,17 @@ try { delete this.process; delete this.console; - (program()).then((result) => { - process = __process__; - if (typeof result == 'undefined' && result !== null) { - printFinal('["ok"]'); - } else { - try { - printFinal(JSON.stringify(['ok', result])); - } catch (err) { - printFinal(JSON.stringify(['err', '' + err, err.stack])); - } + result = await program(); + process = __process__; + if (typeof result == 'undefined' && result !== null) { + printFinal('["ok"]'); + } else { + try { + printFinal(JSON.stringify(['ok', result])); + } catch (err) { + printFinal(JSON.stringify(['err', '' + err, err.stack])); } - }).catch((err) => { - process = __process__; - printFinal(JSON.stringify(['err', '' + err, err.stack])); - }) + } } catch (err) { process = __process__; printFinal(JSON.stringify(['err', '' + err, err.stack])); diff --git a/test/test_execjs.rb b/test/test_execjs.rb index 4b0976f..b0c4d07 100644 --- a/test/test_execjs.rb +++ b/test/test_execjs.rb @@ -450,6 +450,15 @@ def test_uglify context.call("uglify", "function foo(bar) {\n return bar;\n}") end + def test_async_bun + skip unless ENV["EXECJS_RUNTIME"] == "Bun" + source = <<-JS + async function testAsync() { return (await new Promise((resolve) => { resolve("it works!") } )) } + JS + context = ExecJS.compile(source) + assert_equal "it works!", context.call("testAsync") + end + private def assert_output(expected, actual) From 3ecf76890d973bb2c217cf80f88378f7ae6d0c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gaya?= Date: Tue, 15 Oct 2024 14:29:22 +0200 Subject: [PATCH 29/32] prevent runtime autodetect on require --- lib/execjs.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/execjs.rb b/lib/execjs.rb index e6a3d09..8c55449 100644 --- a/lib/execjs.rb +++ b/lib/execjs.rb @@ -2,5 +2,7 @@ require "execjs/runtimes" module ExecJS - self.runtime ||= Runtimes.autodetect + def self.runtime + @runtime ||= Runtimes.autodetect + end end From 7594b6bb38ac3e8fff82ef5d00a3b22e53ebb4a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gaya?= Date: Tue, 15 Oct 2024 15:08:33 +0200 Subject: [PATCH 30/32] autodetect runtime for tests --- test/test_execjs.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_execjs.rb b/test/test_execjs.rb index b0c4d07..f2a5e23 100644 --- a/test/test_execjs.rb +++ b/test/test_execjs.rb @@ -5,6 +5,7 @@ begin require "execjs" + ExecJS.runtime rescue ExecJS::RuntimeUnavailable => e warn e exit 2 From 06feba503e961f0c1613e0b66a69937e3ce02e95 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Wed, 23 Oct 2024 15:47:03 +0200 Subject: [PATCH 31/32] Release 2.10.0 --- lib/execjs/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/execjs/version.rb b/lib/execjs/version.rb index 37766b5..0dec38f 100644 --- a/lib/execjs/version.rb +++ b/lib/execjs/version.rb @@ -1,3 +1,3 @@ module ExecJS - VERSION = "2.9.1" + VERSION = "2.10.0" end From 45c4ac3179caeb9913ce2231fa7c15ba37fd57d5 Mon Sep 17 00:00:00 2001 From: viralpraxis Date: Thu, 12 Jun 2025 23:30:52 +0400 Subject: [PATCH 32/32] Drop obsolete `ExecJS.runtime` attr_reader This `attr_reader` is redifined right after the `module.rb` is evaluated by `lib/execjs.rb`: https://github.com/rails/execjs/blob/master/lib/execjs.rb#L5-L7 --- lib/execjs/module.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/execjs/module.rb b/lib/execjs/module.rb index b89dc22..8cfb704 100644 --- a/lib/execjs/module.rb +++ b/lib/execjs/module.rb @@ -8,8 +8,6 @@ class ProgramError < Error; end class RuntimeUnavailable < RuntimeError; end class << self - attr_reader :runtime - def runtime=(runtime) raise RuntimeUnavailable, "#{runtime.name} is unavailable on this system" unless runtime.available? @runtime = runtime