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.
@@ -29,7 +29,10 @@ module Dommy
29
29
  @mutex.synchronize { @cache.clear }
30
30
  end
31
31
 
32
- def size = @cache.size
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
@@ -3,7 +3,7 @@
3
3
  module Dommy
4
4
  module Js
5
5
  module Quickjs
6
- VERSION = "0.9.0"
6
+ VERSION = "0.10.0"
7
7
  end
8
8
  end
9
9
  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
@@ -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.9.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.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.18.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.9.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.9.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: 3.6.9
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: []
@@ -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