dommy 0.14.0 → 0.15.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/README.md +15 -1
- data/lib/dommy/attr.rb +56 -32
- data/lib/dommy/backend.rb +255 -213
- data/lib/dommy/blob.rb +7 -0
- data/lib/dommy/bridge/methods.rb +12 -2
- data/lib/dommy/browser.rb +4 -4
- data/lib/dommy/callable_invoker.rb +27 -31
- data/lib/dommy/character_data.rb +1 -1
- data/lib/dommy/class_list.rb +31 -14
- data/lib/dommy/css.rb +3 -0
- data/lib/dommy/custom_elements.rb +11 -15
- data/lib/dommy/document.rb +199 -158
- data/lib/dommy/element.rb +223 -499
- data/lib/dommy/event.rb +7 -29
- data/lib/dommy/event_source.rb +4 -4
- data/lib/dommy/fetch.rb +8 -12
- data/lib/dommy/form_data.rb +13 -10
- data/lib/dommy/form_entry_list.rb +5 -5
- data/lib/dommy/fragment.rb +3 -6
- data/lib/dommy/html_canvas_element.rb +1 -1
- data/lib/dommy/html_collection.rb +27 -20
- data/lib/dommy/html_elements/base.rb +279 -15
- data/lib/dommy/html_elements/embedded.rb +2 -2
- data/lib/dommy/html_elements/forms/form.rb +25 -23
- data/lib/dommy/html_elements/forms/input.rb +21 -18
- data/lib/dommy/html_elements/forms/select.rb +7 -7
- data/lib/dommy/html_elements/interactive.rb +11 -8
- data/lib/dommy/html_elements/media.rb +2 -2
- data/lib/dommy/html_elements/metadata.rb +14 -10
- data/lib/dommy/html_elements/tables.rb +13 -33
- data/lib/dommy/html_elements.rb +5 -2
- data/lib/dommy/hyperlink_utils.rb +4 -4
- data/lib/dommy/interaction/field_interactor.rb +1 -1
- data/lib/dommy/interaction/form_submission.rb +2 -2
- data/lib/dommy/interaction/key_sender.rb +1 -1
- data/lib/dommy/internal/accessibility_tree.rb +4 -4
- data/lib/dommy/internal/accessibility_visibility.rb +2 -2
- data/lib/dommy/internal/accessible_description.rb +2 -2
- data/lib/dommy/internal/accessible_name.rb +23 -28
- data/lib/dommy/internal/an_plus_b.rb +125 -0
- data/lib/dommy/internal/aria_role.rb +26 -17
- data/lib/dommy/internal/aria_state.rb +7 -7
- data/lib/dommy/internal/backend_prefilter.rb +20 -13
- data/lib/dommy/internal/child_list.rb +75 -0
- data/lib/dommy/internal/complex_match.rb +127 -0
- data/lib/dommy/internal/css/cascaded_declarations.rb +10 -19
- data/lib/dommy/internal/css/computed_style_builder.rb +22 -1
- data/lib/dommy/internal/css/custom_properties.rb +22 -51
- data/lib/dommy/internal/css/parser.rb +53 -41
- data/lib/dommy/internal/css/rule_index.rb +23 -12
- data/lib/dommy/internal/css/style_cache.rb +2 -2
- data/lib/dommy/internal/css/ua_stylesheet.rb +3 -2
- data/lib/dommy/internal/css_source.rb +223 -0
- data/lib/dommy/internal/css_syntax.rb +153 -0
- data/lib/dommy/internal/directionality.rb +2 -2
- data/lib/dommy/internal/document_generations.rb +38 -18
- data/lib/dommy/internal/dom_matching.rb +5 -5
- data/lib/dommy/internal/element_aria.rb +59 -23
- data/lib/dommy/internal/element_css_inline_style.rb +26 -0
- data/lib/dommy/internal/element_editing.rb +41 -0
- data/lib/dommy/internal/element_nonce.rb +28 -0
- data/lib/dommy/internal/element_popover.rb +109 -0
- data/lib/dommy/internal/element_shadow.rb +13 -10
- data/lib/dommy/internal/element_state.rb +35 -23
- data/lib/dommy/internal/element_top_layer.rb +6 -50
- data/lib/dommy/internal/html_or_svg_or_mathml_element.rb +75 -0
- data/lib/dommy/internal/infra.rb +27 -0
- data/lib/dommy/internal/input_type.rb +16 -4
- data/lib/dommy/internal/literal_lookup.rb +103 -0
- data/lib/dommy/internal/mutation_coordinator.rb +3 -1
- data/lib/dommy/internal/node_adopter.rb +113 -93
- data/lib/dommy/internal/node_factory.rb +7 -49
- data/lib/dommy/internal/node_traversal.rb +12 -13
- data/lib/dommy/internal/node_wrapper_cache.rb +29 -111
- data/lib/dommy/internal/observable_callback.rb +2 -5
- data/lib/dommy/internal/parent_node.rb +2 -2
- data/lib/dommy/internal/post_insertion_steps.rb +7 -7
- data/lib/dommy/internal/reflected_attributes.rb +45 -25
- data/lib/dommy/internal/rendered_text/collector.rb +11 -4
- data/lib/dommy/internal/selector_arguments.rb +0 -15
- data/lib/dommy/internal/selector_index.rb +19 -10
- data/lib/dommy/internal/selector_match.rb +190 -0
- data/lib/dommy/internal/selector_matcher.rb +80 -250
- data/lib/dommy/internal/selector_parser.rb +162 -99
- data/lib/dommy/internal/shadow_root_registry.rb +7 -6
- data/lib/dommy/internal/sibling_positions.rb +59 -0
- data/lib/dommy/internal/svg_uri_reference.rb +33 -0
- data/lib/dommy/internal/template_content_registry.rb +4 -4
- data/lib/dommy/internal/web_idl.rb +11 -0
- data/lib/dommy/internal/window_constructors.rb +8 -8
- data/lib/dommy/internal/xml_serialization.rb +6 -42
- data/lib/dommy/js/dom_interfaces.rb +1 -0
- data/lib/dommy/js/host_callbacks.rb +10 -0
- data/lib/dommy/js/host_runtime.js +24 -1
- data/lib/dommy/js/module_loader.rb +12 -2
- data/lib/dommy/js/module_preload.rb +116 -0
- data/lib/dommy/js/runtime.rb +9 -0
- data/lib/dommy/js/script_boot.rb +6 -2
- data/lib/dommy/js/webidl_tables.js +25 -1
- data/lib/dommy/mathml_elements.rb +13 -0
- data/lib/dommy/mutation_observer.rb +1 -7
- data/lib/dommy/navigation.rb +2 -2
- data/lib/dommy/navigator.rb +1 -5
- data/lib/dommy/node.rb +63 -34
- data/lib/dommy/notification.rb +1 -5
- data/lib/dommy/parser.rb +5 -16
- data/lib/dommy/promise.rb +12 -26
- data/lib/dommy/range.rb +15 -13
- data/lib/dommy/shadow_root.rb +8 -6
- data/lib/dommy/streams.rb +2 -6
- data/lib/dommy/style_declaration.rb +22 -6
- data/lib/dommy/svg_elements.rb +25 -11
- data/lib/dommy/tree_walker.rb +2 -8
- data/lib/dommy/url.rb +1 -5
- data/lib/dommy/url_pattern.rb +1 -9
- data/lib/dommy/validity_state.rb +1 -1
- data/lib/dommy/version.rb +1 -1
- data/lib/dommy/web_socket.rb +5 -5
- data/lib/dommy/window.rb +6 -6
- data/lib/dommy.rb +8 -9
- metadata +20 -4
- data/lib/dommy/backend/makiri_adapter.rb +0 -408
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b0d28c900db6681f80910f285f05e95985648e6bf824990f23d4f4b4b47bdaf9
|
|
4
|
+
data.tar.gz: 509faf8cfe617d13f1ff69507254c3ef7987d77a9bdf796fa7ce44836d63c798
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d52a0dec8dca36a172c0ff93e89ab75126049a6b85eeea2a7527c99a162cc087b98cdf11afa7a98d0cd5024bce642ac612f955babf15a3b02af63cbddc336981
|
|
7
|
+
data.tar.gz: f8de49a82844eee7f75e5b5db13a798b7210b70a9bc1e902b85c37819fc79e98c71a2dd8d60abeeaa4f16de9a2679c15f27d48d57f7005b2345ac5a1e0fce7b5
|
data/README.md
CHANGED
|
@@ -79,7 +79,7 @@ file = Dommy::File.new(["pdf body"], "doc.pdf", "type" => "application/pdf")
|
|
|
79
79
|
|
|
80
80
|
# Seed a file input for tests
|
|
81
81
|
input = win.document.query_selector("input[type='file']")
|
|
82
|
-
input.
|
|
82
|
+
input.files = [file]
|
|
83
83
|
|
|
84
84
|
# FormData picks it up
|
|
85
85
|
fd = Dommy::FormData.new(win.document.query_selector("form"))
|
|
@@ -106,6 +106,20 @@ response = win.__js_call__("fetch", ["/api"]).await
|
|
|
106
106
|
> [!WARNING]
|
|
107
107
|
> Most Dommy accessors (`Blob#text`, `localStorage.get_item`) return synchronous Ruby values — not Promises. `.await` is only for the JS-bridged async surface (e.g., `fetch()`, `window.__js_call__`). Methods like `Response#text()` are Promise-returning and require `.await`.
|
|
108
108
|
|
|
109
|
+
### Preloading ES modules across page loads
|
|
110
|
+
|
|
111
|
+
With JavaScript on (dommy-js-quickjs), a test suite boots the same bundles — Turbo, Stimulus, an app's vendored libraries — page after page, and parsing them is most of what booting costs. Turn preloading on, and a page's ES modules of 10 KB or more are compiled to bytecode once per process and read as bytecode by every later page of the same origin:
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
# spec/rails_helper.rb or test/test_helper.rb
|
|
115
|
+
Dommy::Js::ModulePreload.enabled = true
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
With Turbo served as an ES module (importmap-rails), a page boots in about 11 ms instead of 24 ms from the third load on: the first registers the module, the second compiles it.
|
|
119
|
+
|
|
120
|
+
> [!NOTE]
|
|
121
|
+
> A preloaded module is not fetched again for the rest of the process. Turn it on when your module URLs carry a digest (importmap-rails, Propshaft, jsbundling with digested assets); a URL whose content changes without its name changing would keep running what it served first.
|
|
122
|
+
|
|
109
123
|
## Test helpers
|
|
110
124
|
|
|
111
125
|
Dommy ships test-side modules you can `include` into RSpec / Minitest. Matchers accept a `Dommy::Document` / element or a raw HTML string (auto-parsed), matching Capybara's `expect(rendered).to ...` ergonomics.
|
data/lib/dommy/attr.rb
CHANGED
|
@@ -9,9 +9,13 @@ module Dommy
|
|
|
9
9
|
# We represent two states:
|
|
10
10
|
# - "owned" — the Attr is attached to an Element. value reads/writes
|
|
11
11
|
# go through the element's Makiri attribute slot.
|
|
12
|
-
# - "detached" — created via `document.createAttribute(name)`
|
|
13
|
-
#
|
|
12
|
+
# - "detached" — created via `document.createAttribute(name)` or removed
|
|
13
|
+
# from its element. Value is stored locally; `setAttributeNode`
|
|
14
14
|
# transfers it to an element.
|
|
15
|
+
#
|
|
16
|
+
# Its node document is its own in either state, as the DOM has it: set
|
|
17
|
+
# when it is created, appended or adopted (with its element or by itself),
|
|
18
|
+
# and kept when it is removed.
|
|
15
19
|
class Attr
|
|
16
20
|
include Node
|
|
17
21
|
include EventTarget
|
|
@@ -25,9 +29,7 @@ module Dommy
|
|
|
25
29
|
def initialize(name, owner: nil, value: "", namespace_uri: nil, prefix: nil, local_name: nil, document: nil)
|
|
26
30
|
qname = name.to_s
|
|
27
31
|
@owner = owner
|
|
28
|
-
|
|
29
|
-
# element). Owned attrs derive it from their owner instead.
|
|
30
|
-
@document = document
|
|
32
|
+
@document = document || owner&.document
|
|
31
33
|
@detached_value = value.to_s
|
|
32
34
|
if namespace_uri && !namespace_uri.to_s.empty?
|
|
33
35
|
# Namespaced attributes preserve case and carry prefix / localName.
|
|
@@ -53,19 +55,13 @@ module Dommy
|
|
|
53
55
|
@owner
|
|
54
56
|
end
|
|
55
57
|
|
|
56
|
-
# Node.baseURI — the node document's base URL.
|
|
57
|
-
# element when attached, else the document the attr was created in.
|
|
58
|
+
# Node.baseURI — the node document's base URL.
|
|
58
59
|
def base_uri
|
|
59
|
-
return @owner.base_uri if @owner.respond_to?(:base_uri)
|
|
60
|
-
|
|
61
60
|
@document&.base_uri
|
|
62
61
|
end
|
|
63
62
|
|
|
64
|
-
# Node.ownerDocument — the
|
|
65
|
-
# it follows the element across adoptNode), else the creation document.
|
|
63
|
+
# Node.ownerDocument — the node document.
|
|
66
64
|
def owner_document
|
|
67
|
-
return @owner.document if @owner.respond_to?(:document)
|
|
68
|
-
|
|
69
65
|
@document
|
|
70
66
|
end
|
|
71
67
|
|
|
@@ -85,7 +81,9 @@ module Dommy
|
|
|
85
81
|
if @namespace_uri
|
|
86
82
|
@owner.set_attribute_ns(@namespace_uri, @name, new_value.to_s)
|
|
87
83
|
else
|
|
88
|
-
|
|
84
|
+
# This attribute, in no namespace — not the first with its
|
|
85
|
+
# qualified name, which may be another namespace's.
|
|
86
|
+
@owner.__internal_set_attribute_value__(@local_name, new_value.to_s)
|
|
89
87
|
end
|
|
90
88
|
else
|
|
91
89
|
@detached_value = new_value.to_s
|
|
@@ -122,6 +120,15 @@ module Dommy
|
|
|
122
120
|
when "specified"
|
|
123
121
|
# Legacy/useless attribute — always true (WHATWG DOM).
|
|
124
122
|
true
|
|
123
|
+
when "parentNode", "parentElement", "firstChild", "lastChild", "previousSibling", "nextSibling"
|
|
124
|
+
# An Attr is no part of a tree: it has no parent, children or
|
|
125
|
+
# siblings, and its element is no parent of it.
|
|
126
|
+
nil
|
|
127
|
+
when "childNodes"
|
|
128
|
+
NodeList.new
|
|
129
|
+
when "isConnected"
|
|
130
|
+
# Its root is itself, never a document.
|
|
131
|
+
false
|
|
125
132
|
else
|
|
126
133
|
Bridge::ABSENT
|
|
127
134
|
end
|
|
@@ -139,8 +146,8 @@ module Dommy
|
|
|
139
146
|
end
|
|
140
147
|
|
|
141
148
|
include Bridge::Methods
|
|
142
|
-
js_methods %w[cloneNode isSameNode getRootNode hasChildNodes normalize
|
|
143
|
-
appendChild insertBefore removeChild replaceChild
|
|
149
|
+
js_methods %w[cloneNode isSameNode isEqualNode contains getRootNode hasChildNodes normalize
|
|
150
|
+
compareDocumentPosition appendChild insertBefore removeChild replaceChild
|
|
144
151
|
lookupNamespaceURI lookupPrefix isDefaultNamespace
|
|
145
152
|
addEventListener removeEventListener dispatchEvent]
|
|
146
153
|
def __js_call__(method, args)
|
|
@@ -154,9 +161,13 @@ module Dommy
|
|
|
154
161
|
when "cloneNode"
|
|
155
162
|
Attr.new(@name, owner: nil, value: value,
|
|
156
163
|
namespace_uri: @namespace_uri, prefix: @prefix, local_name: @local_name,
|
|
157
|
-
document: @document
|
|
164
|
+
document: @document)
|
|
158
165
|
when "isSameNode"
|
|
159
166
|
is_same_node(args[0])
|
|
167
|
+
when "isEqualNode"
|
|
168
|
+
is_equal_node(args[0])
|
|
169
|
+
when "contains"
|
|
170
|
+
contains?(args[0])
|
|
160
171
|
when "getRootNode"
|
|
161
172
|
get_root_node(args[0])
|
|
162
173
|
when "compareDocumentPosition"
|
|
@@ -178,14 +189,29 @@ module Dommy
|
|
|
178
189
|
end
|
|
179
190
|
end
|
|
180
191
|
|
|
192
|
+
# Node.contains — an Attr has no descendants, so only itself.
|
|
193
|
+
def contains?(other)
|
|
194
|
+
equal?(other)
|
|
195
|
+
end
|
|
196
|
+
|
|
181
197
|
# Internal: called by Element when the attr is being transferred
|
|
182
|
-
# to (or detached from) an Element.
|
|
198
|
+
# to (or detached from) an Element. Appending it sets its node document
|
|
199
|
+
# to the element's; removing it leaves the node document as it is.
|
|
183
200
|
def __internal_attach__(element)
|
|
184
201
|
@owner = element
|
|
202
|
+
@document = element.document
|
|
185
203
|
@detached_value = ""
|
|
186
204
|
nil
|
|
187
205
|
end
|
|
188
206
|
|
|
207
|
+
# Internal: "adopt" (DOM §4.5) sets the node document — of the Attr
|
|
208
|
+
# adopted by itself, which stays on its element, or of each attribute of
|
|
209
|
+
# an adopted element.
|
|
210
|
+
def __internal_adopt__(document)
|
|
211
|
+
@document = document
|
|
212
|
+
self
|
|
213
|
+
end
|
|
214
|
+
|
|
189
215
|
def __internal_detach__
|
|
190
216
|
cached = value
|
|
191
217
|
@owner = nil
|
|
@@ -238,13 +264,17 @@ module Dommy
|
|
|
238
264
|
attr
|
|
239
265
|
end
|
|
240
266
|
|
|
267
|
+
# The element was adopted into `document`, and its attributes with it.
|
|
268
|
+
def __internal_adopt__(document)
|
|
269
|
+
@attrs.each_value { |attr| attr.__internal_adopt__(document) if attr.owner_element.equal?(@element) }
|
|
270
|
+
nil
|
|
271
|
+
end
|
|
272
|
+
|
|
241
273
|
def get_named_item(name)
|
|
242
274
|
# getNamedItem / getAttribute lowercase the qualified name only for an HTML
|
|
243
275
|
# element in an HTML document; other elements match case-sensitively.
|
|
244
276
|
key = @element.__internal_normalize_attr_key__(name)
|
|
245
|
-
node = Backend.
|
|
246
|
-
Backend.attribute_ns_info(a)[:qualified_name] == key
|
|
247
|
-
end
|
|
277
|
+
node = Backend.attr_by_qualified_name(@element.__dommy_backend_node__, key)
|
|
248
278
|
node && attr_for(node)
|
|
249
279
|
end
|
|
250
280
|
|
|
@@ -254,10 +284,8 @@ module Dommy
|
|
|
254
284
|
|
|
255
285
|
def remove_named_item(name)
|
|
256
286
|
key = @element.__internal_normalize_attr_key__(name)
|
|
257
|
-
node = Backend.
|
|
258
|
-
|
|
259
|
-
end
|
|
260
|
-
return nil unless node
|
|
287
|
+
node = Backend.attr_by_qualified_name(@element.__dommy_backend_node__, key)
|
|
288
|
+
raise DOMException::NotFoundError, "no attribute named #{key.inspect}" unless node
|
|
261
289
|
|
|
262
290
|
removed = attr_for(node)
|
|
263
291
|
@element.remove_attribute(key)
|
|
@@ -297,7 +325,7 @@ module Dommy
|
|
|
297
325
|
if ns
|
|
298
326
|
@element.set_attribute_ns(ns, attr.name, value)
|
|
299
327
|
else
|
|
300
|
-
@element.
|
|
328
|
+
@element.__internal_set_attribute_value__(local, value)
|
|
301
329
|
end
|
|
302
330
|
@attrs[key] = attr
|
|
303
331
|
old
|
|
@@ -316,11 +344,7 @@ module Dommy
|
|
|
316
344
|
# ----- Namespaced named-item access (getNamedItemNS etc.) -----
|
|
317
345
|
|
|
318
346
|
def get_named_item_ns(namespace, local_name)
|
|
319
|
-
node = Backend.
|
|
320
|
-
info = Backend.attribute_ns_info(a)
|
|
321
|
-
info[:local_name] == local_name.to_s &&
|
|
322
|
-
(info[:namespace_uri] || nil) == (namespace.to_s.empty? ? nil : namespace.to_s)
|
|
323
|
-
end
|
|
347
|
+
node = Backend.attr_by_ns(@element.__dommy_backend_node__, namespace, local_name)
|
|
324
348
|
node && attr_for(node)
|
|
325
349
|
end
|
|
326
350
|
|
|
@@ -331,7 +355,7 @@ module Dommy
|
|
|
331
355
|
|
|
332
356
|
def remove_named_item_ns(namespace, local_name)
|
|
333
357
|
existing = get_named_item_ns(namespace, local_name)
|
|
334
|
-
|
|
358
|
+
raise DOMException::NotFoundError, "no attribute #{local_name.inspect} in that namespace" unless existing
|
|
335
359
|
|
|
336
360
|
@element.remove_attribute_ns(namespace, local_name)
|
|
337
361
|
existing
|