dommy-js-quickjs 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +7 -0
- data/lib/dommy/js/quickjs/backend.rb +100 -93
- data/lib/dommy/js/quickjs/browser_environment.rb +93 -0
- data/lib/dommy/js/quickjs/capybara.rb +101 -19
- data/lib/dommy/js/quickjs/config.rb +62 -0
- data/lib/dommy/js/quickjs/error_translator.rb +137 -0
- data/lib/dommy/js/quickjs/event_loop.rb +149 -0
- data/lib/dommy/js/quickjs/js/browser_globals.js +36 -0
- data/lib/dommy/js/quickjs/js/error_rebuild.js +22 -0
- data/lib/dommy/js/quickjs/js/intl_polyfill.js +56 -0
- data/lib/dommy/js/quickjs/js/timer_globals.js +46 -0
- data/lib/dommy/js/quickjs/js/wasm_stub.js +26 -0
- data/lib/dommy/js/quickjs/js/window_builtins.js +14 -0
- data/lib/dommy/js/quickjs/runtime.rb +243 -442
- data/lib/dommy/js/quickjs/script_cache.rb +4 -1
- data/lib/dommy/js/quickjs/version.rb +1 -1
- data/lib/dommy/js/quickjs/wasm_bridge.rb +14 -8
- data/lib/dommy/js/quickjs.rb +5 -1
- metadata +22 -13
- data/.github/workflows/test.yml +0 -28
- data/Rakefile +0 -117
- data/docs/bridge-redesign.md +0 -559
- data/docs/wpt-conformance.md +0 -752
- data/lib/dommy/js/quickjs/source_guard.rb +0 -304
- data/script/build_jsx_transform.sh +0 -27
- data/script/build_stimulus_tests.sh +0 -52
|
@@ -29,7 +29,10 @@ module Dommy
|
|
|
29
29
|
@mutex.synchronize { @cache.clear }
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
# Under the mutex like the others: one lock guards this cache, and a
|
|
33
|
+
# reader that steps outside it is the kind of inconsistency that only
|
|
34
|
+
# shows up under load.
|
|
35
|
+
def size = @mutex.synchronize { @cache.size }
|
|
33
36
|
end
|
|
34
37
|
end
|
|
35
38
|
end
|
|
@@ -105,9 +105,15 @@ module Dommy
|
|
|
105
105
|
|
|
106
106
|
# Ruby value -> wasm-tagged JS value. Public so the embedder's
|
|
107
107
|
# #on_invoke dispatcher can pack the values it hands back into JS.
|
|
108
|
+
#
|
|
109
|
+
# Deliberately not core's Marshaller, which shares the same WireTags but
|
|
110
|
+
# answers a bigger question: it wraps host objects as DOM proxies, binds
|
|
111
|
+
# callbacks and resolves interfaces against a handle table. A wasm guest
|
|
112
|
+
# has none of that — every non-primitive is an opaque ref it asks about
|
|
113
|
+
# through #get / #call — so what it needs is the tags and nothing else.
|
|
108
114
|
def pack(value)
|
|
109
115
|
case value
|
|
110
|
-
when JSValue then {WireTags::JS_REF => value.ref}
|
|
116
|
+
when JSValue then {Dommy::Bridge::WireTags::JS_REF => value.ref}
|
|
111
117
|
when nil, true, false, Integer, Float, String then value
|
|
112
118
|
when Symbol then value.to_s
|
|
113
119
|
when Array then value.map { |e| pack(e) }
|
|
@@ -122,14 +128,14 @@ module Dommy
|
|
|
122
128
|
def unpack(value)
|
|
123
129
|
case value
|
|
124
130
|
when Hash
|
|
125
|
-
if value.key?(WireTags::JS_REF)
|
|
126
|
-
JSValue.new(value[WireTags::JS_REF])
|
|
127
|
-
elsif value.key?(WireTags::UNDEFINED)
|
|
131
|
+
if value.key?(Dommy::Bridge::WireTags::JS_REF)
|
|
132
|
+
JSValue.new(value[Dommy::Bridge::WireTags::JS_REF])
|
|
133
|
+
elsif value.key?(Dommy::Bridge::WireTags::UNDEFINED)
|
|
128
134
|
nil
|
|
129
|
-
elsif value.key?(WireTags::BYTES)
|
|
130
|
-
value[WireTags::BYTES]
|
|
131
|
-
elsif value.key?(WireTags::ARRAY_BUFFER)
|
|
132
|
-
value[WireTags::ARRAY_BUFFER]
|
|
135
|
+
elsif value.key?(Dommy::Bridge::WireTags::BYTES)
|
|
136
|
+
value[Dommy::Bridge::WireTags::BYTES]
|
|
137
|
+
elsif value.key?(Dommy::Bridge::WireTags::ARRAY_BUFFER)
|
|
138
|
+
value[Dommy::Bridge::WireTags::ARRAY_BUFFER]
|
|
133
139
|
else
|
|
134
140
|
value.each_with_object({}) { |(k, v), h| h[k] = unpack(v) }
|
|
135
141
|
end
|
data/lib/dommy/js/quickjs.rb
CHANGED
|
@@ -14,10 +14,14 @@ end
|
|
|
14
14
|
# The engine-agnostic host layer lives in the `dommy` gem (loaded above via
|
|
15
15
|
# `require "dommy"`): the Runtime port + registry, ScriptBoot/ImportMap/
|
|
16
16
|
# ModuleLoader, Dommy::Browser, AND the JS<->Ruby DOM bridge (HostBridge +
|
|
17
|
-
# WireTags / HandleTable / DomInterfaces / ConstructorResolver /
|
|
17
|
+
# Bridge::WireTags / Js::HandleTable / DomInterfaces / ConstructorResolver /
|
|
18
18
|
# CustomElementBridge, with host_runtime.js / observable_runtime.js). This gem
|
|
19
19
|
# provides only the QuickJS backend that plugs in underneath.
|
|
20
|
+
require_relative "quickjs/config"
|
|
20
21
|
require_relative "quickjs/backend"
|
|
22
|
+
require_relative "quickjs/browser_environment"
|
|
23
|
+
require_relative "quickjs/event_loop"
|
|
24
|
+
require_relative "quickjs/error_translator"
|
|
21
25
|
require_relative "quickjs/wasm_bridge"
|
|
22
26
|
require_relative "quickjs/runtime"
|
|
23
27
|
require_relative "quickjs/script_cache"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dommy-js-quickjs
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- takahashim
|
|
@@ -15,28 +15,34 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.21.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.21.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: dommy
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.
|
|
32
|
+
version: 0.14.0
|
|
33
|
+
- - "<"
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: '0.15'
|
|
33
36
|
type: :runtime
|
|
34
37
|
prerelease: false
|
|
35
38
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
39
|
requirements:
|
|
37
40
|
- - ">="
|
|
38
41
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.
|
|
42
|
+
version: 0.14.0
|
|
43
|
+
- - "<"
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '0.15'
|
|
40
46
|
description: |
|
|
41
47
|
dommy-js-quickjs lets JavaScript drive a Dommy DOM by embedding QuickJS (via
|
|
42
48
|
the quickjs gem) and bridging DOM nodes to JS through an ES Proxy that routes
|
|
@@ -47,24 +53,27 @@ executables: []
|
|
|
47
53
|
extensions: []
|
|
48
54
|
extra_rdoc_files: []
|
|
49
55
|
files:
|
|
50
|
-
- ".github/workflows/test.yml"
|
|
51
56
|
- CHANGELOG.md
|
|
52
57
|
- LICENSE.txt
|
|
53
58
|
- README.md
|
|
54
|
-
- Rakefile
|
|
55
|
-
- docs/bridge-redesign.md
|
|
56
|
-
- docs/wpt-conformance.md
|
|
57
59
|
- lib/dommy/js/quickjs.rb
|
|
58
60
|
- lib/dommy/js/quickjs/backend.rb
|
|
61
|
+
- lib/dommy/js/quickjs/browser_environment.rb
|
|
59
62
|
- lib/dommy/js/quickjs/capybara.rb
|
|
63
|
+
- lib/dommy/js/quickjs/config.rb
|
|
64
|
+
- lib/dommy/js/quickjs/error_translator.rb
|
|
65
|
+
- lib/dommy/js/quickjs/event_loop.rb
|
|
66
|
+
- lib/dommy/js/quickjs/js/browser_globals.js
|
|
67
|
+
- lib/dommy/js/quickjs/js/error_rebuild.js
|
|
68
|
+
- lib/dommy/js/quickjs/js/intl_polyfill.js
|
|
69
|
+
- lib/dommy/js/quickjs/js/timer_globals.js
|
|
70
|
+
- lib/dommy/js/quickjs/js/wasm_stub.js
|
|
71
|
+
- lib/dommy/js/quickjs/js/window_builtins.js
|
|
60
72
|
- lib/dommy/js/quickjs/rack.rb
|
|
61
73
|
- lib/dommy/js/quickjs/runtime.rb
|
|
62
74
|
- lib/dommy/js/quickjs/script_cache.rb
|
|
63
|
-
- lib/dommy/js/quickjs/source_guard.rb
|
|
64
75
|
- lib/dommy/js/quickjs/version.rb
|
|
65
76
|
- lib/dommy/js/quickjs/wasm_bridge.rb
|
|
66
|
-
- script/build_jsx_transform.sh
|
|
67
|
-
- script/build_stimulus_tests.sh
|
|
68
77
|
- sig/dommy/js/quickjs.rbs
|
|
69
78
|
homepage: https://github.com/takahashim/dommy-js-quickjs
|
|
70
79
|
licenses:
|
|
@@ -88,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
88
97
|
- !ruby/object:Gem::Version
|
|
89
98
|
version: '0'
|
|
90
99
|
requirements: []
|
|
91
|
-
rubygems_version:
|
|
100
|
+
rubygems_version: 4.0.20
|
|
92
101
|
specification_version: 4
|
|
93
102
|
summary: QuickJS backend for running JavaScript against a Dommy DOM.
|
|
94
103
|
test_files: []
|
data/.github/workflows/test.yml
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
name: test
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [main]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
test:
|
|
11
|
-
name: Ruby ${{ matrix.ruby }}
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
strategy:
|
|
14
|
-
fail-fast: false
|
|
15
|
-
matrix:
|
|
16
|
-
ruby: ["3.2", "3.3", "3.4", "4.0"]
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- uses: actions/checkout@v6
|
|
20
|
-
|
|
21
|
-
- name: Set up Ruby ${{ matrix.ruby }}
|
|
22
|
-
uses: ruby/setup-ruby@v1
|
|
23
|
-
with:
|
|
24
|
-
ruby-version: ${{ matrix.ruby }}
|
|
25
|
-
bundler-cache: true
|
|
26
|
-
|
|
27
|
-
- name: Run tests
|
|
28
|
-
run: bundle exec rake
|
data/Rakefile
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "bundler/gem_tasks"
|
|
4
|
-
require "minitest/test_task"
|
|
5
|
-
|
|
6
|
-
# The OOM-resilience test forces a real QuickJS out-of-memory. Whether an OOM
|
|
7
|
-
# poisons the VM (vs. unwinding as a recoverable JS exception) depends on the
|
|
8
|
-
# allocator's state, which other JS-heavy tests in the same process perturb — so
|
|
9
|
-
# it runs in its own process to stay deterministic.
|
|
10
|
-
OOM_TEST = "test/dommy/js/test_oom_resilience.rb"
|
|
11
|
-
|
|
12
|
-
Minitest::TestTask.create(:test) do |t|
|
|
13
|
-
t.test_globs = FileList["test/**/test_*.rb"].exclude(OOM_TEST)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
Minitest::TestTask.create(:test_oom) do |t|
|
|
17
|
-
t.test_globs = [OOM_TEST]
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
namespace :test do
|
|
21
|
-
desc "Run the full test suite including the heavy (thousands-of-subtests) WPT files"
|
|
22
|
-
task :all do
|
|
23
|
-
ENV["WPT_HEAVY"] = "1"
|
|
24
|
-
Rake::Task["test"].invoke
|
|
25
|
-
Rake::Task["test_oom"].invoke
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
task default: %i[test test_oom]
|
|
30
|
-
|
|
31
|
-
namespace :wpt do
|
|
32
|
-
desc "Run the vendored WPT corpus against the bridge and report a conformance rate"
|
|
33
|
-
task :conformance, [:filter] do |_t, args|
|
|
34
|
-
$LOAD_PATH.unshift File.expand_path("test", __dir__)
|
|
35
|
-
require "test_helper"
|
|
36
|
-
require "support/wpt_runner"
|
|
37
|
-
|
|
38
|
-
runner = Dommy::Js::WptRunner
|
|
39
|
-
files = runner.manifest
|
|
40
|
-
files = files.grep(/#{args[:filter]}/) if args[:filter]
|
|
41
|
-
|
|
42
|
-
total_pass = total = file_ok = 0
|
|
43
|
-
blocked = []
|
|
44
|
-
by_dir = Hash.new { |h, k| h[k] = [0, 0] } # dir => [pass, total]
|
|
45
|
-
files.each do |rel|
|
|
46
|
-
results = runner.run(rel)
|
|
47
|
-
pass = results.count(&:pass?)
|
|
48
|
-
n = results.size
|
|
49
|
-
total_pass += pass
|
|
50
|
-
total += n
|
|
51
|
-
dir = rel.split("/").first
|
|
52
|
-
by_dir[dir][0] += pass
|
|
53
|
-
by_dir[dir][1] += n
|
|
54
|
-
file_ok += 1 if n.positive? && pass == n
|
|
55
|
-
flag = n.zero? ? "—" : (pass == n ? "✓" : " ")
|
|
56
|
-
printf(" %s %-46s %3d/%-3d\n", flag, rel, pass, n)
|
|
57
|
-
results.reject(&:pass?).first(3).each { |r| puts " #{r.to_s[0, 110]}" }
|
|
58
|
-
rescue => e
|
|
59
|
-
blocked << rel
|
|
60
|
-
puts " ✗ #{rel} (errored: #{e.class}: #{e.message[0, 80]})"
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
pct = ->(p, t) { t.zero? ? 0 : (100.0 * p / t).round(1) }
|
|
64
|
-
puts
|
|
65
|
-
by_dir.sort.each { |dir, (p, t)| printf(" %-8s %4d/%-5d (%.1f%%)\n", dir, p, t, pct.call(p, t)) }
|
|
66
|
-
puts
|
|
67
|
-
puts "WPT conformance: #{total_pass}/#{total} subtests (#{pct.call(total_pass, total)}%) across #{files.size} files; " \
|
|
68
|
-
"#{file_ok} files fully green#{blocked.empty? ? "" : ", #{blocked.size} errored"}"
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
namespace :stimulus do
|
|
73
|
-
desc "Run @hotwired/stimulus's QUnit suite against the bridge and report a conformance rate"
|
|
74
|
-
task :conformance, [:filter] do |_t, args|
|
|
75
|
-
$LOAD_PATH.unshift File.expand_path("test", __dir__)
|
|
76
|
-
require "test_helper"
|
|
77
|
-
require "support/stimulus_conformance"
|
|
78
|
-
|
|
79
|
-
runner = Dommy::Js::StimulusConformance
|
|
80
|
-
unless runner.available?
|
|
81
|
-
abort "Stimulus suite not vendored. Build it: script/build_stimulus_tests.sh"
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
manifest = runner.manifest
|
|
85
|
-
manifest = manifest.select { |t| t["module"].match?(/#{args[:filter]}/i) } if args[:filter]
|
|
86
|
-
|
|
87
|
-
# Run each test in its own VM, grouping the printed output by module.
|
|
88
|
-
by_module = Hash.new { |h, k| h[k] = [] }
|
|
89
|
-
failures = []
|
|
90
|
-
manifest.each do |t|
|
|
91
|
-
r = runner.run_test(t["module"], t["name"])
|
|
92
|
-
by_module[t["module"]] << r
|
|
93
|
-
rescue => e
|
|
94
|
-
puts " ✗ #{t["module"]} :: #{t["name"]} (errored: #{e.class}: #{e.message[0, 70]})"
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
total_pass = total_runnable = total = 0
|
|
98
|
-
by_module.each do |mod, results|
|
|
99
|
-
pass = results.count(&:pass?)
|
|
100
|
-
runnable = results.count(&:runnable?)
|
|
101
|
-
total_pass += pass
|
|
102
|
-
total_runnable += runnable
|
|
103
|
-
total += results.size
|
|
104
|
-
flag = runnable.positive? && pass == runnable ? "✓" : " "
|
|
105
|
-
printf(" %s %-42s %3d/%-3d\n", flag, mod, pass, runnable)
|
|
106
|
-
results.reject { |r| r.pass? || r.skip? || r.todo? }.each do |r|
|
|
107
|
-
failures << r
|
|
108
|
-
puts " #{r.to_s[0, 120]}"
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
pct = total_runnable.zero? ? 0 : (100.0 * total_pass / total_runnable).round(1)
|
|
113
|
-
puts
|
|
114
|
-
puts "Stimulus conformance: #{total_pass}/#{total_runnable} runnable tests (#{pct}%) " \
|
|
115
|
-
"across #{by_module.size} modules; #{total - total_runnable} skipped/todo, #{failures.size} failing"
|
|
116
|
-
end
|
|
117
|
-
end
|