@miaskiewicz/turbo-dom 0.6.0 → 0.7.1
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 +60 -5
- package/Cargo.toml +1 -1
- package/README.md +54 -37
- package/package.json +1 -1
- 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/runtime/css-shorthand.mjs +10 -1
- 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/Cargo.lock
CHANGED
|
@@ -113,6 +113,15 @@ version = "0.22.1"
|
|
|
113
113
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
114
114
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
|
115
115
|
|
|
116
|
+
[[package]]
|
|
117
|
+
name = "bincode"
|
|
118
|
+
version = "1.3.3"
|
|
119
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
120
|
+
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
|
121
|
+
dependencies = [
|
|
122
|
+
"serde",
|
|
123
|
+
]
|
|
124
|
+
|
|
116
125
|
[[package]]
|
|
117
126
|
name = "bindgen"
|
|
118
127
|
version = "0.72.1"
|
|
@@ -717,6 +726,12 @@ dependencies = [
|
|
|
717
726
|
"winapi",
|
|
718
727
|
]
|
|
719
728
|
|
|
729
|
+
[[package]]
|
|
730
|
+
name = "fst"
|
|
731
|
+
version = "0.4.7"
|
|
732
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
733
|
+
checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
|
|
734
|
+
|
|
720
735
|
[[package]]
|
|
721
736
|
name = "futures-core"
|
|
722
737
|
version = "0.3.32"
|
|
@@ -950,6 +965,29 @@ dependencies = [
|
|
|
950
965
|
"markup5ever",
|
|
951
966
|
]
|
|
952
967
|
|
|
968
|
+
[[package]]
|
|
969
|
+
name = "hyphenation"
|
|
970
|
+
version = "0.8.4"
|
|
971
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
972
|
+
checksum = "bcf4dd4c44ae85155502a52c48739c8a48185d1449fff1963cffee63c28a50f0"
|
|
973
|
+
dependencies = [
|
|
974
|
+
"bincode",
|
|
975
|
+
"fst",
|
|
976
|
+
"hyphenation_commons",
|
|
977
|
+
"pocket-resources",
|
|
978
|
+
"serde",
|
|
979
|
+
]
|
|
980
|
+
|
|
981
|
+
[[package]]
|
|
982
|
+
name = "hyphenation_commons"
|
|
983
|
+
version = "0.8.4"
|
|
984
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
985
|
+
checksum = "5febe7a2ade5c7d98eb8b75f946c046b335324b06a14ea0998271504134c05bf"
|
|
986
|
+
dependencies = [
|
|
987
|
+
"fst",
|
|
988
|
+
"serde",
|
|
989
|
+
]
|
|
990
|
+
|
|
953
991
|
[[package]]
|
|
954
992
|
name = "icu_calendar"
|
|
955
993
|
version = "2.2.1"
|
|
@@ -1979,6 +2017,12 @@ dependencies = [
|
|
|
1979
2017
|
"miniz_oxide",
|
|
1980
2018
|
]
|
|
1981
2019
|
|
|
2020
|
+
[[package]]
|
|
2021
|
+
name = "pocket-resources"
|
|
2022
|
+
version = "0.3.2"
|
|
2023
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2024
|
+
checksum = "c135f38778ad324d9e9ee68690bac2c1a51f340fdf96ca13e2ab3914eb2e51d8"
|
|
2025
|
+
|
|
1982
2026
|
[[package]]
|
|
1983
2027
|
name = "pollster"
|
|
1984
2028
|
version = "0.3.0"
|
|
@@ -2747,7 +2791,7 @@ dependencies = [
|
|
|
2747
2791
|
|
|
2748
2792
|
[[package]]
|
|
2749
2793
|
name = "turbo-dom"
|
|
2750
|
-
version = "0.
|
|
2794
|
+
version = "0.7.1"
|
|
2751
2795
|
dependencies = [
|
|
2752
2796
|
"cssparser",
|
|
2753
2797
|
"html5ever",
|
|
@@ -2763,26 +2807,30 @@ dependencies = [
|
|
|
2763
2807
|
|
|
2764
2808
|
[[package]]
|
|
2765
2809
|
name = "turbo-dom-browser-env"
|
|
2766
|
-
version = "0.
|
|
2810
|
+
version = "0.7.1"
|
|
2767
2811
|
dependencies = [
|
|
2768
2812
|
"cssparser",
|
|
2769
2813
|
"lightningcss",
|
|
2770
2814
|
"psl",
|
|
2815
|
+
"rustc-hash 2.1.2",
|
|
2771
2816
|
"serde",
|
|
2772
2817
|
"serde_json",
|
|
2773
2818
|
"sha2",
|
|
2774
2819
|
"turbo-dom",
|
|
2820
|
+
"turbo-dom-layout",
|
|
2775
2821
|
"turbo-dom-v8",
|
|
2776
2822
|
"url",
|
|
2823
|
+
"xml",
|
|
2777
2824
|
]
|
|
2778
2825
|
|
|
2779
2826
|
[[package]]
|
|
2780
2827
|
name = "turbo-dom-layout"
|
|
2781
|
-
version = "0.
|
|
2828
|
+
version = "0.7.1"
|
|
2782
2829
|
dependencies = [
|
|
2783
2830
|
"core-foundation",
|
|
2784
2831
|
"core-text",
|
|
2785
2832
|
"encoding_rs",
|
|
2833
|
+
"hyphenation",
|
|
2786
2834
|
"jpeg-decoder",
|
|
2787
2835
|
"png 0.18.1",
|
|
2788
2836
|
"resvg",
|
|
@@ -2795,12 +2843,13 @@ dependencies = [
|
|
|
2795
2843
|
"thiserror 2.0.18",
|
|
2796
2844
|
"turbo-dom",
|
|
2797
2845
|
"turbo-dom-layout",
|
|
2846
|
+
"unicode-bidi",
|
|
2798
2847
|
"unicode-linebreak",
|
|
2799
2848
|
]
|
|
2800
2849
|
|
|
2801
2850
|
[[package]]
|
|
2802
2851
|
name = "turbo-dom-parser"
|
|
2803
|
-
version = "0.
|
|
2852
|
+
version = "0.7.1"
|
|
2804
2853
|
dependencies = [
|
|
2805
2854
|
"html5ever",
|
|
2806
2855
|
"markup5ever_rcdom",
|
|
@@ -2816,7 +2865,7 @@ dependencies = [
|
|
|
2816
2865
|
|
|
2817
2866
|
[[package]]
|
|
2818
2867
|
name = "turbo-dom-raster"
|
|
2819
|
-
version = "0.
|
|
2868
|
+
version = "0.7.1"
|
|
2820
2869
|
dependencies = [
|
|
2821
2870
|
"base64",
|
|
2822
2871
|
"core-foundation",
|
|
@@ -3343,6 +3392,12 @@ version = "0.6.3"
|
|
|
3343
3392
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3344
3393
|
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
|
|
3345
3394
|
|
|
3395
|
+
[[package]]
|
|
3396
|
+
name = "xml"
|
|
3397
|
+
version = "1.4.0"
|
|
3398
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3399
|
+
checksum = "2f45bb2c13fec6a6cb4c0f76a7e94839e110a14ec803ec2940777a94c347bc52"
|
|
3400
|
+
|
|
3346
3401
|
[[package]]
|
|
3347
3402
|
name = "xml-rs"
|
|
3348
3403
|
version = "0.8.29"
|
package/Cargo.toml
CHANGED
|
@@ -43,7 +43,7 @@ manual_midpoint = "allow"
|
|
|
43
43
|
|
|
44
44
|
[package]
|
|
45
45
|
name = "turbo-dom-parser"
|
|
46
|
-
version = "0.
|
|
46
|
+
version = "0.7.1"
|
|
47
47
|
edition = "2021"
|
|
48
48
|
description = "html5ever-backed native parser for turbo-dom (Layer 1)"
|
|
49
49
|
# Ships to npm only (napi/wasm addon); never published to crates.io.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# turbo-dom
|
|
2
2
|
|
|
3
|
-
Release **0.
|
|
3
|
+
Release **0.7.1**. turbo-dom is the shared browser-engine base of three projects:
|
|
4
4
|
|
|
5
5
|
- **[turbo-test](https://github.com/miaskiewicz/turbo-test)**, a vitest-compatible test runner. It runs tests in V8 over this repository's DOM.
|
|
6
6
|
- **[turbo-html2pdf](https://github.com/miaskiewicz/turbo-html2pdf)**, which renders HTML to PDF and uses this repository's layout engine.
|
|
@@ -9,7 +9,7 @@ Release **0.6.0**. turbo-dom is the shared browser-engine base of three projects
|
|
|
9
9
|
turbo-dom is also a standalone npm package: a fast, spec-correct DOM environment for
|
|
10
10
|
**vitest** and **jest**, usable in place of jsdom or happy-dom.
|
|
11
11
|
|
|
12
|
-
Up to 0.5.x, each consumer kept its own copy of these pieces.
|
|
12
|
+
Up to 0.5.x, each consumer kept its own copy of these pieces. Since 0.6.0 each piece lives
|
|
13
13
|
in this repository once and is published from here. The consumers depend on the
|
|
14
14
|
published crates and keep no copies.
|
|
15
15
|
[docs/CONSOLIDATION.md](docs/CONSOLIDATION.md) has the architecture, the dependency graph
|
|
@@ -19,11 +19,11 @@ and the publish order.
|
|
|
19
19
|
|
|
20
20
|
| package | registry | version | what it is | used by |
|
|
21
21
|
|---|---|---|---|---|
|
|
22
|
-
| [`@miaskiewicz/turbo-dom`](https://www.npmjs.com/package/@miaskiewicz/turbo-dom) | npm | 0.
|
|
23
|
-
| [`turbo-dom`](crates/turbo-dom) | crates.io | 0.
|
|
24
|
-
| [`turbo-dom-layout`](crates/turbo-dom-layout) | crates.io | 0.
|
|
25
|
-
| [`turbo-dom-raster`](crates/turbo-dom-raster) | crates.io | 0.
|
|
26
|
-
| [`turbo-dom-browser-env`](crates/turbo-dom-browser-env) | crates.io | 0.
|
|
22
|
+
| [`@miaskiewicz/turbo-dom`](https://www.npmjs.com/package/@miaskiewicz/turbo-dom) | npm | 0.7.0 | lazy JS DOM runtime + native html5ever parser (N-API, WASM fallback) | vitest / jest users |
|
|
23
|
+
| [`turbo-dom`](crates/turbo-dom) | crates.io | 0.7.0 | pure-Rust DOM (`rtdom`), the one selector engine, CSSOM, partial cascade | all three consumers |
|
|
24
|
+
| [`turbo-dom-layout`](crates/turbo-dom-layout) | crates.io | 0.7.0 | HTML/CSS layout (block / inline / flex / grid / table), fonts, images, CSSOM-View geometry | turbo-html2pdf, turbo-surf |
|
|
25
|
+
| [`turbo-dom-raster`](crates/turbo-dom-raster) | crates.io | 0.7.0 | synthetic screenshots (PNG / SVG), canvas op-log replay, WebGL readback | turbo-surf |
|
|
26
|
+
| [`turbo-dom-browser-env`](crates/turbo-dom-browser-env) | crates.io | 0.7.0 | the `rtdom` <-> V8 browser environment (window, document, CSSOM, forms, events) | turbo-test, turbo-surf |
|
|
27
27
|
| [`turbo-dom-v8`](crates/turbo-dom-v8) | crates.io | 150.4.0 | turbo-dom's rusty_v8 fork, generated from the upstream crate plus reviewed patches | turbo-dom-browser-env, turbo-surf |
|
|
28
28
|
|
|
29
29
|
The root `turbo-dom-parser` crate is `publish = false`. It ships inside the npm package.
|
|
@@ -105,10 +105,10 @@ parseBuffer, parseFragment })` or set it as `globalThis.__TURBO_DOM_PARSER__`. T
|
|
|
105
105
|
|
|
106
106
|
```toml
|
|
107
107
|
[dependencies]
|
|
108
|
-
turbo-dom = "0.
|
|
109
|
-
turbo-dom-layout = "0.
|
|
110
|
-
turbo-dom-raster = "0.
|
|
111
|
-
turbo-dom-browser-env = "0.
|
|
108
|
+
turbo-dom = "0.7"
|
|
109
|
+
turbo-dom-layout = "0.7" # bundled fonts on by default
|
|
110
|
+
turbo-dom-raster = "0.7"
|
|
111
|
+
turbo-dom-browser-env = "0.7" # needs a V8 archive, see its README
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
```rust
|
|
@@ -133,6 +133,7 @@ Each crate's README covers its API: [turbo-dom](crates/turbo-dom/README.md),
|
|
|
133
133
|
| crate | feature | default | effect |
|
|
134
134
|
|---|---|---|---|
|
|
135
135
|
| `turbo-dom-layout` | `bundled-fonts` | on | embeds OFL faces (Inter/Roboto, Liberation Serif/PT Serif, Fira Code/IBM Plex Mono) so a document lays out with no caller fonts |
|
|
136
|
+
| | `hyphenation` | on | `hyphens: auto` for English (`en` / `en-*`, not en-GB) with the embedded en-US TeX patterns (~90 KB); off, `auto` acts as `manual` |
|
|
136
137
|
| | `svg` | off | routes `image/svg+xml` through the SVG rasterizer in the image pipeline (implies `svg-rasterize`) |
|
|
137
138
|
| | `svg-rasterize` | off | the shared resvg rasterizer only (`svg::rasterize`) |
|
|
138
139
|
| | `serde` | off | `Serialize` for the CSSOM-View metrics records |
|
|
@@ -157,35 +158,47 @@ upstream rusty_v8's features (for example `simdutf`).
|
|
|
157
158
|
upstream html5ever has not adopted yet. The Rust `rtdom` tree passes its direct
|
|
158
159
|
html5lib-tests gate at 100% (`npm run conformance:rtdom`).
|
|
159
160
|
- **Chrome parity:** behaviour fixes are backed by Chrome 156 controls. These are
|
|
160
|
-
fixtures recorded from headless Chrome and asserted in tests.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
fixtures recorded from headless Chrome and asserted in tests. Every corpus output change
|
|
162
|
+
is declared in [`tools/parity/expected/`](tools/parity/expected) (checkpoint `b-0.7.0`).
|
|
163
|
+
0.7.0 adds vertical writing modes, UAX #9 bidi, Chrome's line box model on the PDF path,
|
|
164
|
+
the full `border-radius` model with `overflow` clipping, background tiling and gradient
|
|
165
|
+
length stops, native form-control appearance, size / layout containment, replaced media
|
|
166
|
+
boxes, XML documents (with DTD ATTLIST defaults), processing instructions, CSS
|
|
167
|
+
animations in `getAnimations()`, a browser-env cascade with specificity, `@layer`,
|
|
168
|
+
`@supports` and `@scope`, real canvas `measureText` and an opt-in V8 startup snapshot
|
|
169
|
+
install (see [CHANGELOG.md](CHANGELOG.md)).
|
|
164
170
|
- **Open gaps (tracked as issues):**
|
|
165
|
-
-
|
|
166
|
-
|
|
167
|
-
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
`
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
171
|
+
- glyph stems in raster screenshots lack Chrome's stem darkening, so glyph edges are
|
|
172
|
+
up to ~0.5px thinner per side (#266).
|
|
173
|
+
- Known difference, not tracked: `hyphens: auto` covers English only, and Chrome on
|
|
174
|
+
macOS hyphenates with the system dictionary, whose points differ for some words.
|
|
175
|
+
- **The npm runtime has no layout.** Geometry is synthetic: `getBoundingClientRect()`,
|
|
176
|
+
`offsetWidth/Height`, `clientWidth/Height` and `scrollWidth/Height` return a non-zero
|
|
177
|
+
size that is stable for a given DOM state (blocks fill the parent's width, the root
|
|
178
|
+
takes `innerWidth` or 1024; heights stack children or 18px per line), while every
|
|
179
|
+
position (`top` / `left`, `offsetTop/Left`, `scrollTop/Left`) is 0.
|
|
180
|
+
`getComputedStyle` is a partial cascade: top-level `<style>` rules (and rules injected
|
|
181
|
+
with `insertRule`) plus inline styles, ordered by Selectors 4 specificity and source
|
|
182
|
+
order, with a fixed set of inherited properties. Colours read back as `rgb()` /
|
|
183
|
+
`rgba()` and a bare `0` as `0px`; a property no rule sets reads `''` (never an initial
|
|
184
|
+
value). Not resolved: rules inside any at-rule block (`@media`, `@supports`, `@layer`,
|
|
185
|
+
`@container`, `@scope`) are skipped, rules with state pseudo-classes (`:hover`, ...)
|
|
186
|
+
never match, a pseudo-element argument is ignored (the element's own style comes
|
|
187
|
+
back) and `::before`-style rules never apply. Values come back as written: no unit
|
|
188
|
+
conversion (`2em` stays `2em`), and `var(...)` and `inherit` / `initial` / `unset` are
|
|
189
|
+
returned verbatim, not resolved. Shadow DOM is supported: `attachShadow`, declarative
|
|
190
|
+
shadow roots, slots and `assignedNodes()`, event retargeting, scoped styles with
|
|
191
|
+
`:host` / `::slotted()`, and inheritance across the host boundary. Layout belongs to
|
|
192
|
+
`turbo-dom-layout`, and through it to turbo-html2pdf and turbo-surf.
|
|
181
193
|
|
|
182
194
|
## Benchmarks — pending re-run
|
|
183
195
|
|
|
184
|
-
0.6.0
|
|
185
|
-
|
|
186
|
-
2026-06-07, darwin-arm64, JS runtime vs happy-dom and jsdom) are kept
|
|
187
|
-
labelled in [docs/BENCHMARKS-history.md](docs/BENCHMARKS-history.md). They
|
|
188
|
-
|
|
196
|
+
0.6.0 and 0.7.0 have not been benchmarked against jsdom / happy-dom yet. All four
|
|
197
|
+
repositories will be re-run together on a quiet machine. Until then, the last measured
|
|
198
|
+
numbers (v0.1.55, 2026-06-07, darwin-arm64, JS runtime vs happy-dom and jsdom) are kept
|
|
199
|
+
unchanged and labelled in [docs/BENCHMARKS-history.md](docs/BENCHMARKS-history.md). They
|
|
200
|
+
predate the consolidation. 0.7.0's browser-env performance work (measured on a real
|
|
201
|
+
React/MUI suite) is listed in [CHANGELOG.md](CHANGELOG.md).
|
|
189
202
|
|
|
190
203
|
## Development
|
|
191
204
|
|
|
@@ -230,7 +243,11 @@ the host-font policy itself read system fonts.
|
|
|
230
243
|
**CI runners.** Pull requests and pushes to `main` run on Linux (x64 and arm64) and on
|
|
231
244
|
Windows x64: the napi build, and the V8 / browser-env matrix with the default and
|
|
232
245
|
simdutf archives. macOS arm64 builds and jobs run only in the release workflow.
|
|
233
|
-
`publish.yml` calls `ci.yml` with `darwin: true`.
|
|
246
|
+
`publish.yml` calls `ci.yml` with `darwin: true`. Linux binaries build on ubuntu-22.04 and a
|
|
247
|
+
guard (`scripts/check-glibc-ceiling.sh`) rejects any addon that needs glibc above 2.35. The
|
|
248
|
+
guard also fails when an expected addon is missing or unreadable. A newer push to a pull
|
|
249
|
+
request cancels its superseded CI run. `main`, tag and publish runs each get their own
|
|
250
|
+
concurrency group, so they are never cancelled or dropped while pending.
|
|
234
251
|
|
|
235
252
|
## Releasing
|
|
236
253
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miaskiewicz/turbo-dom",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Faster, more spec-correct DOM for test runners \u2014 native html5ever (Rust/WASM) parser + lazy copy-on-write DOM. A drop-in-style alternative to jsdom/happy-dom for vitest & jest.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "index.js",
|
package/pkg/package.json
CHANGED
|
Binary file
|
package/pkg-web/package.json
CHANGED
|
Binary file
|
|
@@ -14,6 +14,8 @@ import { SHORTHAND_TABLE, LONGHAND_ALIASES } from './css-shorthand-table.mjs';
|
|
|
14
14
|
|
|
15
15
|
// ---------------------------------------------------------------- numbers ----
|
|
16
16
|
const f32 = Math.fround;
|
|
17
|
+
/** The largest finite f32. */
|
|
18
|
+
const F32_MAX = 3.4028234663852886e38;
|
|
17
19
|
/** Blink's CSS number serialization: six significant digits (printf `%g`). */
|
|
18
20
|
export function cssNumber(value) {
|
|
19
21
|
const v = f32(value);
|
|
@@ -583,7 +585,14 @@ function read(tokens, state, close) {
|
|
|
583
585
|
out.push({ kind: 'percentage', value, text: `${cssNumber(Number(token.raw))}%` });
|
|
584
586
|
break;
|
|
585
587
|
}
|
|
586
|
-
case 'dimension':
|
|
588
|
+
case 'dimension': {
|
|
589
|
+
// A length past f32's range (`1e39px`) is the largest float, as Chrome clamps it
|
|
590
|
+
// (`3.40282e+38px`), never infinite (#262; the Rust port's tokenizer likewise).
|
|
591
|
+
const number = Math.max(-F32_MAX, Math.min(F32_MAX, token.value));
|
|
592
|
+
const unit = token.unit.toLowerCase();
|
|
593
|
+
out.push({ kind: 'dimension', value: f32(number), unit, text: `${cssNumber(number)}${unit}` });
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
587
596
|
case 'hash': out.push({ kind: 'hash', value: token.value, text: `#${token.value}` }); break;
|
|
588
597
|
case 'string': out.push({ kind: 'string', value: token.value, text: quoted(token.value) }); break;
|
|
589
598
|
case 'url': out.push({ kind: 'url', value: token.value, text: `url(${quoted(token.value)})` }); break;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|