@miaskiewicz/turbo-dom 0.5.7 → 0.6.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.
- package/Cargo.lock +3177 -394
- package/Cargo.toml +53 -3
- package/README.md +176 -224
- package/package.json +5 -3
- package/pkg/package.json +1 -1
- package/pkg/turbo_dom_parser_bg.wasm +0 -0
- package/pkg-web/package.json +1 -1
- package/pkg-web/turbo_dom_parser_bg.wasm +0 -0
- package/src/core.rs +387 -44
- package/src/lib.rs +43 -10
- package/src/runtime/buffer.mjs +0 -1
- package/src/runtime/cascade.mjs +18 -24
- package/src/runtime/color.mjs +1 -1
- package/src/runtime/css-shorthand-table.mjs +238 -0
- package/src/runtime/css-shorthand.mjs +2794 -0
- package/src/runtime/cssom.mjs +3 -4
- package/src/runtime/custom-elements.mjs +398 -0
- package/src/runtime/dom.mjs +924 -238
- package/src/runtime/html-serialize.mjs +15 -7
- package/src/runtime/index.d.ts +100 -0
- package/src/runtime/index.mjs +5 -0
- package/src/runtime/parser.mjs +2 -4
- package/src/runtime/selectors.mjs +1080 -402
- package/src/runtime/stubs.mjs +1 -19
- package/src/runtime/window.mjs +15 -7
- package/src/spike.rs +26 -6
- package/turbo-dom-parser.darwin-arm64.node +0 -0
- package/turbo-dom-parser.linux-arm64-gnu.node +0 -0
- package/turbo-dom-parser.linux-x64-gnu.node +0 -0
- package/turbo-dom-parser.linux-x64-musl.node +0 -0
- package/turbo-dom-parser.win32-x64-msvc.node +0 -0
package/src/runtime/stubs.mjs
CHANGED
|
@@ -38,24 +38,6 @@ export function makeCanvasStub() {
|
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
// CustomElementRegistry — define/get/whenDefined. No upgrade of generic elements,
|
|
42
|
-
// but enough that defining and awaiting elements doesn't throw.
|
|
43
|
-
export function makeCustomElements() {
|
|
44
|
-
const defs = new Map();
|
|
45
|
-
const waiters = new Map();
|
|
46
|
-
return {
|
|
47
|
-
define(name, ctor) {
|
|
48
|
-
if (defs.has(name)) throw new Error(`'${name}' already defined`);
|
|
49
|
-
defs.set(name, ctor);
|
|
50
|
-
const w = waiters.get(name); if (w) { w.forEach((r) => r(ctor)); waiters.delete(name); }
|
|
51
|
-
},
|
|
52
|
-
get(name) { return defs.get(name); },
|
|
53
|
-
getName(ctor) { for (const [n, c] of defs) if (c === ctor) return n; return null; },
|
|
54
|
-
whenDefined(name) { if (defs.has(name)) return Promise.resolve(defs.get(name)); return new Promise((res) => { const a = waiters.get(name) || []; a.push(res); waiters.set(name, a); }); },
|
|
55
|
-
upgrade() {},
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
41
|
export class Storage {
|
|
60
42
|
constructor() { this.__map = new Map(); }
|
|
61
43
|
get length() { return this.__map.size; }
|
|
@@ -86,7 +68,7 @@ function evalMediaQuery(query, win) {
|
|
|
86
68
|
else if (feat === 'max-width') matched = matched && W <= parseFloat(val);
|
|
87
69
|
else if (feat === 'min-height') matched = matched && H >= parseFloat(val);
|
|
88
70
|
else if (feat === 'max-height') matched = matched && H <= parseFloat(val);
|
|
89
|
-
else matched = matched && val === (
|
|
71
|
+
else matched = matched && val === (H >= W ? 'portrait' : 'landscape'); // orientation: portrait iff height >= width (turbo-dom#138)
|
|
90
72
|
}
|
|
91
73
|
return any && matched;
|
|
92
74
|
}
|
package/src/runtime/window.mjs
CHANGED
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
import {
|
|
8
8
|
Storage, makeMatchMedia,
|
|
9
9
|
IntersectionObserver, ResizeObserver,
|
|
10
|
-
FileReader, makeCanvasStub,
|
|
10
|
+
FileReader, makeCanvasStub,
|
|
11
11
|
makeLocation, makeHistory,
|
|
12
12
|
} from './stubs.mjs';
|
|
13
13
|
import { makeGetComputedStyle } from './cascade.mjs';
|
|
14
|
+
import { makeCustomElements, constructCustomElement } from './custom-elements.mjs';
|
|
14
15
|
import { CSSStyleSheet } from './cssom.mjs';
|
|
15
16
|
import {
|
|
16
|
-
Node, Element, SVGElement, Text, Comment, Document, DocumentFragment, DocumentType, Event, CustomEvent,
|
|
17
|
+
Node, Element, SVGElement, MathMLElement, Text, Comment, Document, DocumentFragment, DocumentType, Event, CustomEvent,
|
|
17
18
|
MutationObserver, DOMParser, XMLSerializer, ShadowRoot,
|
|
18
19
|
} from './dom.mjs';
|
|
19
20
|
import {
|
|
@@ -65,7 +66,13 @@ class TurboFormData {
|
|
|
65
66
|
// Element (which made `instanceof HTMLAnchorElement` true for ALL elements).
|
|
66
67
|
function tagClass(matcher) {
|
|
67
68
|
const test = typeof matcher === 'string' ? (n) => n === matcher : (n) => matcher.test(n);
|
|
68
|
-
|
|
69
|
+
// a customized built-in's super() (custom-elements.mjs) returns the element being
|
|
70
|
+
// constructed or upgraded; anything else is Chrome's TypeError
|
|
71
|
+
const C = function () {
|
|
72
|
+
const custom = new.target ? constructCustomElement(new.target) : null;
|
|
73
|
+
if (custom !== null) return custom;
|
|
74
|
+
throw new TypeError('Illegal constructor');
|
|
75
|
+
};
|
|
69
76
|
// share Element.prototype so prototype-level spies/reads resolve (e.g.
|
|
70
77
|
// vi.spyOn(HTMLAnchorElement.prototype, 'click')); instanceof is decided by
|
|
71
78
|
// the tag matcher below, not the prototype chain.
|
|
@@ -118,7 +125,6 @@ class MessageChannel {
|
|
|
118
125
|
// self-replaces onto the per-env base, so each env gets its own instance; only
|
|
119
126
|
// the factory objects/closures are shared, saving ~28 allocations per test file.
|
|
120
127
|
const SHARED_LAZY = {
|
|
121
|
-
customElements: () => makeCustomElements(), // fresh registry per env, built on first access
|
|
122
128
|
localStorage: () => new Storage(),
|
|
123
129
|
sessionStorage: () => new Storage(),
|
|
124
130
|
getComputedStyle: () => makeGetComputedStyle(),
|
|
@@ -172,8 +178,8 @@ export function createWindow(document, { url = 'http://localhost/' } = {}) {
|
|
|
172
178
|
closed: false,
|
|
173
179
|
// origin is lazy (per-env, captures url) — window.origin is rarely read, so the
|
|
174
180
|
// eager `new URL(url)` parse per createWindow was usually wasted.
|
|
175
|
-
// customElements is lazy (
|
|
176
|
-
//
|
|
181
|
+
// customElements is lazy (per-env `lazy` below: the registry upgrades this document's
|
|
182
|
+
// elements) — rarely used, so building it eagerly per createWindow would be wasted.
|
|
177
183
|
Image: function Image(w, h) { const img = document.createElement('img'); if (w != null) img.setAttribute('width', w); if (h != null) img.setAttribute('height', h); return img; },
|
|
178
184
|
Audio: function Audio(src) { const a = document.createElement('audio'); if (src) a.setAttribute('src', src); return a; },
|
|
179
185
|
getSelection: () => document.getSelection(),
|
|
@@ -192,6 +198,8 @@ export function createWindow(document, { url = 'http://localhost/' } = {}) {
|
|
|
192
198
|
history: () => makeHistory(windowProxy.location),
|
|
193
199
|
// per-env so matchMedia can evaluate queries against THIS window's viewport
|
|
194
200
|
matchMedia: () => makeMatchMedia(windowProxy),
|
|
201
|
+
// the document's custom element registry (custom-elements.mjs), built on first access
|
|
202
|
+
customElements: () => makeCustomElements(document),
|
|
195
203
|
};
|
|
196
204
|
|
|
197
205
|
windowProxy = new Proxy(base, {
|
|
@@ -370,7 +378,7 @@ const STATIC_BASE = {
|
|
|
370
378
|
DataTransfer,
|
|
371
379
|
// every element is a plain Element → `el instanceof HTMLElement` is true.
|
|
372
380
|
// Tag-specific interfaces match by localName via Symbol.hasInstance.
|
|
373
|
-
HTMLElement: Element, SVGElement,
|
|
381
|
+
HTMLElement: Element, SVGElement, MathMLElement,
|
|
374
382
|
// SVG interface globals. Libs (and test setup mocks) do
|
|
375
383
|
// `Object.defineProperty(SVGSVGElement.prototype, 'viewBox', …)` and
|
|
376
384
|
// `el instanceof SVGSVGElement`; an undefined global is a hard ReferenceError.
|
package/src/spike.rs
CHANGED
|
@@ -48,7 +48,9 @@ pub fn destroy(doc: u32) {
|
|
|
48
48
|
DOCS.with(|d| {
|
|
49
49
|
let mut v = d.borrow_mut();
|
|
50
50
|
if (doc as usize) < v.len() {
|
|
51
|
-
v[doc as usize] = Doc {
|
|
51
|
+
v[doc as usize] = Doc {
|
|
52
|
+
soa: core::parse_html_soa(""),
|
|
53
|
+
};
|
|
52
54
|
}
|
|
53
55
|
});
|
|
54
56
|
}
|
|
@@ -97,7 +99,11 @@ pub fn node_type(doc: u32, h: u32) -> u8 {
|
|
|
97
99
|
pub fn tag_id(doc: u32, h: u32) -> i32 {
|
|
98
100
|
with_doc(doc, |d| {
|
|
99
101
|
let i = h as usize;
|
|
100
|
-
if d.soa.node_type[i] == ELEMENT_NODE {
|
|
102
|
+
if d.soa.node_type[i] == ELEMENT_NODE {
|
|
103
|
+
d.soa.tag_id[i] as i32
|
|
104
|
+
} else {
|
|
105
|
+
-1
|
|
106
|
+
}
|
|
101
107
|
})
|
|
102
108
|
}
|
|
103
109
|
#[wasm_bindgen]
|
|
@@ -127,7 +133,9 @@ pub fn text_id(doc: u32, h: u32) -> i32 {
|
|
|
127
133
|
#[wasm_bindgen]
|
|
128
134
|
#[must_use]
|
|
129
135
|
pub fn get_attr_id(doc: u32, h: u32, name: &str) -> i32 {
|
|
130
|
-
with_doc(doc, |d|
|
|
136
|
+
with_doc(doc, |d| {
|
|
137
|
+
attr_value_id(&d.soa, h as usize, name).map_or(-1, |v| v as i32)
|
|
138
|
+
})
|
|
131
139
|
}
|
|
132
140
|
|
|
133
141
|
/// NAIVE getAttribute: returns the value String (per-call UTF-8 marshal).
|
|
@@ -178,9 +186,17 @@ fn attr_value_id(soa: &Soa, i: usize, name: &str) -> Option<u32> {
|
|
|
178
186
|
pub fn node_record(doc: u32, h: u32) -> Vec<i32> {
|
|
179
187
|
with_doc(doc, |d| {
|
|
180
188
|
let i = h as usize;
|
|
181
|
-
let tag = if d.soa.node_type[i] == ELEMENT_NODE {
|
|
189
|
+
let tag = if d.soa.node_type[i] == ELEMENT_NODE {
|
|
190
|
+
d.soa.tag_id[i] as i32
|
|
191
|
+
} else {
|
|
192
|
+
-1
|
|
193
|
+
};
|
|
182
194
|
let start = d.soa.attr_start[i];
|
|
183
|
-
let count = if start < 0 {
|
|
195
|
+
let count = if start < 0 {
|
|
196
|
+
0
|
|
197
|
+
} else {
|
|
198
|
+
d.soa.attr_count[i] as usize
|
|
199
|
+
};
|
|
184
200
|
let mut out = Vec::with_capacity(3 + count * 2);
|
|
185
201
|
out.push(tag);
|
|
186
202
|
out.push(d.soa.parent[i]);
|
|
@@ -223,7 +239,11 @@ struct Compound<'a> {
|
|
|
223
239
|
|
|
224
240
|
fn parse_compound(sel: &str) -> Compound<'_> {
|
|
225
241
|
let s = sel.trim();
|
|
226
|
-
let mut c = Compound {
|
|
242
|
+
let mut c = Compound {
|
|
243
|
+
tag: None,
|
|
244
|
+
id: None,
|
|
245
|
+
classes: Vec::new(),
|
|
246
|
+
};
|
|
227
247
|
let mut i = 0;
|
|
228
248
|
let bytes = s.as_bytes();
|
|
229
249
|
// leading type selector
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|