dommy-js-quickjs 0.12.0 → 0.13.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 +17 -0
- data/lib/dommy/js/quickjs/js/browser_globals.js +86 -29
- data/lib/dommy/js/quickjs/js/intl_polyfill.js +4 -0
- data/lib/dommy/js/quickjs/js/timer_globals.js +44 -23
- data/lib/dommy/js/quickjs/js/wasm_stub.js +4 -0
- data/lib/dommy/js/quickjs/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2e6b8409eac9474ca6bd31c48e4225296f6bdd646d1582fbd7971e40918f3fda
|
|
4
|
+
data.tar.gz: da8deb2816c76b5a98932321957bb60411d338a86cd5a3322feff937d71c43cf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 56fcec71210297cfa232936f6abb9a046bbd4174034567407c9a6d843978edd242eb2a1f0a975ff78b434d16600baf2fdad0dbc849c37d8f7f79b0cf0a57de64
|
|
7
|
+
data.tar.gz: bd4f983f1baf57ea48d10190953f0ab824899395a7650ffc11bebb49d042bf7ba308f119c8aae09a9bbdbb040e048deac390323a2d9e1d425b6738739a7a9dc2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.13.0 — 2026-10-20
|
|
4
|
+
|
|
5
|
+
Requires `dommy >= 0.17.0, < 0.18` and `quickjs ~> 0.22.0`.
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Requires `dommy >= 0.17.0, < 0.18` (was `>= 0.16.0, < 0.17`). dommy 0.17.0 requires makiri `~> 0.16.0`.
|
|
10
|
+
- The bare `self`, `top`, `parent` and `frames` are the window: `self === window` and `top === window` hold. `self`, `parent` and `frames` are [Replaceable]; `top` is readonly, so assigning it in strict code throws.
|
|
11
|
+
- An assignment to the bare `location` navigates, as `window.location = url` does.
|
|
12
|
+
- The bare `history`, `navigator` and `crypto` are readonly: `history = 1` leaves the window's History, and throws in strict code. `indexedDB` and `caches`, which dommy does not implement, are not globals, so `"indexedDB" in globalThis` is false and a page can define its own.
|
|
13
|
+
- A bare global that forwards to the window (`fetch`, `setTimeout`, `localStorage`, …) reaches the window's own member: replacing `window.fetch` replaces the bare `fetch`, and a wrapper that calls a saved `fetch` calls the original instead of itself.
|
|
14
|
+
- The bare `queueMicrotask` reports what its callback throws at the window (`reportError`), as `window.queueMicrotask` does, instead of rejecting a promise nobody holds.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- The shims (`browser_globals.js`, `timer_globals.js`, `intl_polyfill.js`, `wasm_stub.js`) no longer declare their helpers at the top level of the page's realm. A page's own top-level `let group`, `class Collator` or `let __rbDefer` was a redeclaration SyntaxError, and a page's `let __rbTimerOrigins` made every bare `setTimeout` throw `TypeError: not a function`. Each shim now runs in an IIFE; the timers keep their origin map in a local. `test/dommy/js/test_shim_scope.rb` declares every former helper name from a page.
|
|
19
|
+
|
|
3
20
|
## 0.12.0 — 2026-10-10
|
|
4
21
|
|
|
5
22
|
Requires `dommy >= 0.16.0, < 0.17` and `quickjs ~> 0.22.0`.
|
|
@@ -1,16 +1,82 @@
|
|
|
1
1
|
// The bare browser globals frameworks reach for, aliased onto the installed
|
|
2
2
|
// window. This is what lets real frontend bundles (Turbo, …) run unmodified.
|
|
3
|
-
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// `frames` is
|
|
9
|
-
// (`frames[0]` === the first <iframe>'s contentWindow).
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
3
|
+
//
|
|
4
|
+
// The window's names for itself are the window proxy, as everywhere else a
|
|
5
|
+
// window is handed out (`window.self`, `document.defaultView`, a frame's
|
|
6
|
+
// `parent`): globalThis is the one object that is not, since QuickJS makes the
|
|
7
|
+
// global. For the top-level window, parent and top are the window itself
|
|
8
|
+
// (spec), so frame-walking loops terminate. `frames` is indexable by
|
|
9
|
+
// child-frame number (`frames[0]` === the first <iframe>'s contentWindow).
|
|
10
|
+
// They read the live `window`, which a host can rebind. self, parent and
|
|
11
|
+
// frames are [Replaceable]: an assignment replaces the accessor with the
|
|
12
|
+
// value. top is [LegacyUnforgeable]: an assignment leaves it (a strict-mode one
|
|
13
|
+
// throws).
|
|
14
|
+
//
|
|
15
|
+
// Every bare global here that stands for a window member reaches the
|
|
16
|
+
// window's own implementation (dommy's `__rbWindowMember`), not whatever the
|
|
17
|
+
// window answers for the name: the window answers with the bare global
|
|
18
|
+
// itself, and a page that saved the bare `fetch` before wrapping
|
|
19
|
+
// `window.fetch` must get the original back, as from a browser's native
|
|
20
|
+
// function. Each is declared so to dommy (`__rbWindowForward`). Against a
|
|
21
|
+
// dommy without them, they read the window as before.
|
|
22
|
+
//
|
|
23
|
+
// The IIFE keeps the helpers below out of the page's global scope.
|
|
24
|
+
(function () {
|
|
25
|
+
const __rbForward = globalThis.__rbWindowForward || ((fn) => fn);
|
|
26
|
+
const __rbMember = globalThis.__rbWindowMember || ((name) => window[name]);
|
|
27
|
+
// A [Replaceable] attribute: read through `get`, replaced by an assignment.
|
|
28
|
+
const __rbReplaceable = (name, get) => {
|
|
29
|
+
Object.defineProperty(globalThis, name, {
|
|
30
|
+
get,
|
|
31
|
+
set(value) {
|
|
32
|
+
Object.defineProperty(globalThis, name, { value, writable: true, enumerable: true, configurable: true });
|
|
33
|
+
},
|
|
34
|
+
enumerable: true,
|
|
35
|
+
configurable: true,
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
for (const __n of ["self", "parent", "frames"]) {
|
|
39
|
+
__rbReplaceable(__n, __rbForward(function () { return window; }));
|
|
40
|
+
}
|
|
41
|
+
// Getter only, so a strict-mode assignment throws, as on a browser's window.
|
|
42
|
+
Object.defineProperty(globalThis, "top", {
|
|
43
|
+
get: __rbForward(function () { return window; }),
|
|
44
|
+
enumerable: true,
|
|
45
|
+
configurable: true,
|
|
46
|
+
});
|
|
47
|
+
// `location` is the window's own [LegacyUnforgeable] attribute with
|
|
48
|
+
// [PutForwards=href]: an assignment navigates, as `window.location = url`
|
|
49
|
+
// does. A window has one Location for its life (a cross-document navigation
|
|
50
|
+
// makes a new realm), so it is read again only when a host rebinds `window`.
|
|
51
|
+
let __rbLocationWindow = null;
|
|
52
|
+
let __rbLocation = null;
|
|
53
|
+
Object.defineProperty(globalThis, "location", {
|
|
54
|
+
get: __rbForward(function () {
|
|
55
|
+
if (__rbLocationWindow !== window) {
|
|
56
|
+
__rbLocationWindow = window;
|
|
57
|
+
__rbLocation = __rbMember("location");
|
|
58
|
+
}
|
|
59
|
+
return __rbLocation;
|
|
60
|
+
}),
|
|
61
|
+
set(value) { window.location = value; },
|
|
62
|
+
enumerable: true,
|
|
63
|
+
configurable: true,
|
|
64
|
+
});
|
|
65
|
+
// The objects a window keeps for its life, aliased by reference. history,
|
|
66
|
+
// navigator, crypto, indexedDB and caches are plain readonly attributes, so
|
|
67
|
+
// assigning the bare name leaves them (a strict-mode assignment throws);
|
|
68
|
+
// performance, screen and visualViewport are [Replaceable], so an assignment
|
|
69
|
+
// replaces them. A name the window has no object for (dommy implements
|
|
70
|
+
// neither indexedDB nor caches) is left undefined: pinning a read-only
|
|
71
|
+
// `undefined` would make `"indexedDB" in globalThis` claim the feature and
|
|
72
|
+
// refuse the polyfill a page assigns in its place.
|
|
73
|
+
for (const __n of ["history", "navigator", "crypto", "indexedDB", "caches"]) {
|
|
74
|
+
try {
|
|
75
|
+
const value = window[__n];
|
|
76
|
+
if (value == null) continue;
|
|
77
|
+
Object.defineProperty(globalThis, __n, { value, writable: false, enumerable: true, configurable: true });
|
|
78
|
+
} catch (__e) {}
|
|
79
|
+
}
|
|
14
80
|
// Web Storage is read from the window on each access, not copied at boot: the
|
|
15
81
|
// sessionStorage / localStorage getters throw a SecurityError when "obtain a
|
|
16
82
|
// session/local storage bottle map" fails (HTML, Web storage), which it does
|
|
@@ -23,7 +89,7 @@ globalThis.navigator = window.navigator;
|
|
|
23
89
|
// `globalThis` to the host, as window_builtins.js does, reads each of them).
|
|
24
90
|
for (const __n of ["sessionStorage", "localStorage"]) {
|
|
25
91
|
Object.defineProperty(globalThis, __n, {
|
|
26
|
-
get() { return
|
|
92
|
+
get: __rbForward(function () { return __rbMember(__n); }),
|
|
27
93
|
enumerable: false,
|
|
28
94
|
configurable: true,
|
|
29
95
|
});
|
|
@@ -43,7 +109,7 @@ const __rbWindowOperation = (name) => {
|
|
|
43
109
|
return null;
|
|
44
110
|
};
|
|
45
111
|
const __rbForwardWindowMethod = (name) => {
|
|
46
|
-
const forward = function (...args) { return
|
|
112
|
+
const forward = __rbForward(function (...args) { return __rbMember(name).apply(window, args); });
|
|
47
113
|
const operation = __rbWindowOperation(name);
|
|
48
114
|
Object.defineProperty(forward, "name", { value: name });
|
|
49
115
|
Object.defineProperty(forward, "length", { value: operation ? operation.required : 0 });
|
|
@@ -54,11 +120,10 @@ for (const __m of ["getComputedStyle", "matchMedia", "fetch",
|
|
|
54
120
|
__rbForwardWindowMethod(__m);
|
|
55
121
|
}
|
|
56
122
|
|
|
57
|
-
//
|
|
58
|
-
// screen)
|
|
59
|
-
//
|
|
60
|
-
for (const __n of ["performance", "
|
|
61
|
-
"indexedDB", "caches"]) {
|
|
123
|
+
// The [Replaceable] objects frameworks read directly (performance.now(),
|
|
124
|
+
// screen), aliased by reference as plain data properties, which an assignment
|
|
125
|
+
// replaces; methods forward (above) so `this` binds to the window.
|
|
126
|
+
for (const __n of ["performance", "screen", "visualViewport"]) {
|
|
62
127
|
try { globalThis[__n] = window[__n]; } catch (__e) {}
|
|
63
128
|
}
|
|
64
129
|
// Values that change (a resize, a scroll) are read from the window each time
|
|
@@ -66,22 +131,13 @@ for (const __n of ["performance", "crypto", "screen", "visualViewport",
|
|
|
66
131
|
// replaces the accessor with the assigned value, as on a real window.
|
|
67
132
|
for (const __n of ["devicePixelRatio", "innerWidth", "innerHeight",
|
|
68
133
|
"scrollX", "scrollY", "pageXOffset", "pageYOffset"]) {
|
|
69
|
-
try {
|
|
70
|
-
Object.defineProperty(globalThis, __n, {
|
|
71
|
-
get() { return window[__n]; },
|
|
72
|
-
set(value) {
|
|
73
|
-
Object.defineProperty(globalThis, __n, { value, writable: true, enumerable: true, configurable: true });
|
|
74
|
-
},
|
|
75
|
-
enumerable: true,
|
|
76
|
-
configurable: true,
|
|
77
|
-
});
|
|
78
|
-
} catch (__e) {}
|
|
134
|
+
try { __rbReplaceable(__n, __rbForward(function () { return __rbMember(__n); })); } catch (__e) {}
|
|
79
135
|
}
|
|
80
136
|
// `frameElement` is a plain readonly attribute: read from the window each
|
|
81
137
|
// time (a frame's container can change), never replaced by an assignment.
|
|
82
138
|
try {
|
|
83
139
|
Object.defineProperty(globalThis, "frameElement", {
|
|
84
|
-
get() { return
|
|
140
|
+
get: __rbForward(function () { return __rbMember("frameElement"); }),
|
|
85
141
|
enumerable: false,
|
|
86
142
|
configurable: true,
|
|
87
143
|
});
|
|
@@ -91,3 +147,4 @@ for (const __m of ["scrollTo", "scrollBy", "requestIdleCallback", "cancelIdleCal
|
|
|
91
147
|
"alert", "confirm", "prompt", "open", "postMessage"]) {
|
|
92
148
|
try { __rbForwardWindowMethod(__m); } catch (__e) {}
|
|
93
149
|
}
|
|
150
|
+
})();
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
// defined` (nuxt.com, i18n libraries, …). Install a small locale-naive
|
|
4
4
|
// polyfill: it formats reasonably (grouped numbers, ISO-ish dates) so pages run
|
|
5
5
|
// instead of crashing, without pulling in full ICU.
|
|
6
|
+
// The IIFE keeps its helpers and constructors (I, group, Collator, …) out of
|
|
7
|
+
// the page's global scope, where a page's own `let group` would collide.
|
|
8
|
+
(function () {
|
|
6
9
|
if (typeof globalThis.Intl === "undefined") {
|
|
7
10
|
var I = {};
|
|
8
11
|
var group = function (s) {
|
|
@@ -54,3 +57,4 @@ if (typeof globalThis.Intl === "undefined") {
|
|
|
54
57
|
I.getCanonicalLocales = function (locs) { return Array.isArray(locs) ? locs.slice() : locs ? [String(locs)] : []; };
|
|
55
58
|
globalThis.Intl = I;
|
|
56
59
|
}
|
|
60
|
+
})();
|
|
@@ -9,49 +9,70 @@
|
|
|
9
9
|
// and only stringified if the callback actually throws (see
|
|
10
10
|
// __rbFetchTimerOrigin + Runtime#handle_timer_error); a successful callback
|
|
11
11
|
// forgets its origin and the map is size-capped, so this stays cheap.
|
|
12
|
-
|
|
12
|
+
//
|
|
13
|
+
// The IIFE keeps the helpers out of the page's global scope: a page's own
|
|
14
|
+
// `let __rbDefer` would be a redeclaration, and a page's `let` of a name the
|
|
15
|
+
// helpers looked up globally would take its place. __rbDefer keeps its name,
|
|
16
|
+
// which marks the frame ErrorTranslator strips from origin stacks.
|
|
17
|
+
(function () {
|
|
18
|
+
const origins = new Map();
|
|
13
19
|
const __rbDefer = (schedule, fn, delay) => {
|
|
14
20
|
if (typeof fn !== "function") return schedule(fn, delay);
|
|
15
21
|
const origin = new Error();
|
|
16
22
|
let id;
|
|
17
23
|
const wrapped = function () {
|
|
18
24
|
const result = fn.apply(this, arguments);
|
|
19
|
-
|
|
25
|
+
origins.delete(id); // ran cleanly — no need to keep it
|
|
20
26
|
return result;
|
|
21
27
|
};
|
|
22
28
|
id = schedule(wrapped, delay);
|
|
23
|
-
|
|
24
|
-
if (
|
|
29
|
+
origins.set(id, origin);
|
|
30
|
+
if (origins.size > 4096) origins.delete(origins.keys().next().value);
|
|
25
31
|
return id;
|
|
26
32
|
};
|
|
27
33
|
globalThis.__rbFetchTimerOrigin = (id) => {
|
|
28
|
-
const origin =
|
|
34
|
+
const origin = origins.get(id);
|
|
29
35
|
if (!origin) return "";
|
|
30
|
-
|
|
36
|
+
origins.delete(id);
|
|
31
37
|
return origin.stack || "";
|
|
32
38
|
};
|
|
39
|
+
// Each stands for the window's own and reaches it directly (dommy's
|
|
40
|
+
// `__rbWindowMember`), not through whatever the window answers for the name,
|
|
41
|
+
// which is this very function (see browser_globals.js).
|
|
42
|
+
const __rbTimerForward = globalThis.__rbWindowForward || ((fn) => fn);
|
|
43
|
+
const __rbTimerMember = globalThis.__rbWindowMember || ((name) => window[name]);
|
|
33
44
|
// The signatures are the IDL's (HTML "timers"): `setTimeout(handler, timeout
|
|
34
45
|
// = 0, ...arguments)` hands the extra arguments to the handler, and the
|
|
35
46
|
// defaults keep each function's `length` the IDL's (1, 0, 1, 0, 1, 1).
|
|
36
|
-
globalThis.setTimeout = function setTimeout(handler, timeout = 0, ...args) {
|
|
37
|
-
return __rbDefer((f, d) =>
|
|
38
|
-
};
|
|
39
|
-
globalThis.clearTimeout = function clearTimeout(id = 0) { return
|
|
40
|
-
globalThis.setInterval = function setInterval(handler, timeout = 0, ...args) {
|
|
41
|
-
return __rbDefer((f, d) =>
|
|
42
|
-
};
|
|
43
|
-
globalThis.clearInterval = function clearInterval(id = 0) { return
|
|
44
|
-
globalThis.requestAnimationFrame = function requestAnimationFrame(callback) {
|
|
45
|
-
return __rbDefer((f) =>
|
|
46
|
-
};
|
|
47
|
-
globalThis.cancelAnimationFrame = function cancelAnimationFrame(handle) {
|
|
48
|
-
return
|
|
49
|
-
};
|
|
47
|
+
globalThis.setTimeout = __rbTimerForward(function setTimeout(handler, timeout = 0, ...args) {
|
|
48
|
+
return __rbDefer((f, d) => __rbTimerMember("setTimeout").call(window, f, d, ...args), handler, timeout);
|
|
49
|
+
});
|
|
50
|
+
globalThis.clearTimeout = __rbTimerForward(function clearTimeout(id = 0) { return __rbTimerMember("clearTimeout").call(window, id); });
|
|
51
|
+
globalThis.setInterval = __rbTimerForward(function setInterval(handler, timeout = 0, ...args) {
|
|
52
|
+
return __rbDefer((f, d) => __rbTimerMember("setInterval").call(window, f, d, ...args), handler, timeout);
|
|
53
|
+
});
|
|
54
|
+
globalThis.clearInterval = __rbTimerForward(function clearInterval(id = 0) { return __rbTimerMember("clearInterval").call(window, id); });
|
|
55
|
+
globalThis.requestAnimationFrame = __rbTimerForward(function requestAnimationFrame(callback) {
|
|
56
|
+
return __rbDefer((f) => __rbTimerMember("requestAnimationFrame").call(window, f), callback);
|
|
57
|
+
});
|
|
58
|
+
globalThis.cancelAnimationFrame = __rbTimerForward(function cancelAnimationFrame(handle) {
|
|
59
|
+
return __rbTimerMember("cancelAnimationFrame").call(window, handle);
|
|
60
|
+
});
|
|
50
61
|
// queueMicrotask must share the engine's promise-job (microtask) queue so its
|
|
51
62
|
// callbacks are FIFO-ordered with Promise reactions (the WHATWG
|
|
52
63
|
// single-microtask-queue model). Routing through the Ruby scheduler instead
|
|
53
64
|
// would drain on a separate pass, reordering it after all native promise jobs.
|
|
54
|
-
|
|
65
|
+
// What the callback throws is reported at the window (HTML "report an
|
|
66
|
+
// exception"), as window.queueMicrotask's is, rather than rejecting a promise
|
|
67
|
+
// nobody holds.
|
|
68
|
+
globalThis.queueMicrotask = __rbTimerForward(function queueMicrotask(callback) {
|
|
55
69
|
if (typeof callback !== "function") throw new TypeError("queueMicrotask requires a function");
|
|
56
|
-
Promise.resolve().then(() => {
|
|
57
|
-
|
|
70
|
+
Promise.resolve().then(() => {
|
|
71
|
+
try {
|
|
72
|
+
callback();
|
|
73
|
+
} catch (error) {
|
|
74
|
+
__rbTimerMember("reportError").call(window, error);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
})();
|
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
// `Memory` honors `{shared:true}` with a SharedArrayBuffer, which the engine
|
|
8
8
|
// does ship. That is also what WPT's common/sab.js needs: it derives the SAB
|
|
9
9
|
// constructor from `new WebAssembly.Memory({shared:true}).buffer.constructor`.
|
|
10
|
+
// The IIFE keeps its helpers (unsupported, throwUnsupported) out of the
|
|
11
|
+
// page's global scope.
|
|
12
|
+
(function () {
|
|
10
13
|
if (typeof globalThis.WebAssembly === "undefined") {
|
|
11
14
|
var unsupported = function () { return Promise.reject(new Error("WebAssembly is not supported")); };
|
|
12
15
|
var throwUnsupported = function () { throw new Error("WebAssembly is not supported"); };
|
|
@@ -24,3 +27,4 @@ if (typeof globalThis.WebAssembly === "undefined") {
|
|
|
24
27
|
CompileError: Error, LinkError: Error, RuntimeError: Error,
|
|
25
28
|
};
|
|
26
29
|
}
|
|
30
|
+
})();
|
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.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- takahashim
|
|
@@ -29,20 +29,20 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.
|
|
32
|
+
version: 0.17.0
|
|
33
33
|
- - "<"
|
|
34
34
|
- !ruby/object:Gem::Version
|
|
35
|
-
version: '0.
|
|
35
|
+
version: '0.18'
|
|
36
36
|
type: :runtime
|
|
37
37
|
prerelease: false
|
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
|
39
39
|
requirements:
|
|
40
40
|
- - ">="
|
|
41
41
|
- !ruby/object:Gem::Version
|
|
42
|
-
version: 0.
|
|
42
|
+
version: 0.17.0
|
|
43
43
|
- - "<"
|
|
44
44
|
- !ruby/object:Gem::Version
|
|
45
|
-
version: '0.
|
|
45
|
+
version: '0.18'
|
|
46
46
|
description: |
|
|
47
47
|
dommy-js-quickjs lets JavaScript drive a Dommy DOM by embedding QuickJS (via
|
|
48
48
|
the quickjs gem) and bridging DOM nodes to JS through an ES Proxy that routes
|
|
@@ -97,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
97
97
|
- !ruby/object:Gem::Version
|
|
98
98
|
version: '0'
|
|
99
99
|
requirements: []
|
|
100
|
-
rubygems_version:
|
|
100
|
+
rubygems_version: 3.6.9
|
|
101
101
|
specification_version: 4
|
|
102
102
|
summary: QuickJS backend for running JavaScript against a Dommy DOM.
|
|
103
103
|
test_files: []
|