diff --git a/.gitattributes b/.gitattributes index 5d4986373..8632b1bcc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,6 +3,9 @@ tests/fixtures/**/expected*.json linguist-generated tests/fixtures/**/audit_signature.txt linguist-generated -# Committed benchmark reports (regenerated by `deno task bench`) -benches/deno/results/report.json linguist-generated -benches/deno/results/report.md linguist-generated +# Committed benchmark reports (regenerated by `deno task bench`): the per-runtime +# siblings (report..{json,md}) and the combined cross-runtime report.{json,md}. +benches/js/results/report.json linguist-generated +benches/js/results/report.md linguist-generated +benches/js/results/report.*.json linguist-generated +benches/js/results/report.*.md linguist-generated diff --git a/.github/ISSUE_TEMPLATE/preapproved.md b/.github/ISSUE_TEMPLATE/preapproved.md index 9e02e4527..f0e3dd694 100644 --- a/.github/ISSUE_TEMPLATE/preapproved.md +++ b/.github/ISSUE_TEMPLATE/preapproved.md @@ -1,8 +1,8 @@ --- name: New issue (bugs only) -title: (bug reports only, make a discussion for everything else) +title: (bugs only, see below) about: bugs --- -tip: use discussions for everything except bugs: -https://github.com/fuzdev/tsv/discussions/new/choose +Please [create a discussion](https://github.com/fuzdev/tsv/discussions/new/choose) +for everything except bugs. diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 6527e76e7..46aa15376 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -69,10 +69,12 @@ jobs: # npm fetches (prettier/svelte/acorn) since those land in DENO_DIR. cache: true # Key on the sidecar pins (fetched at runtime, not lockfile-pinned) so a - # bump invalidates the cached deps. NOT benches/deno/deno.lock: it governs - # `test:deno` but is dominated by bench-only tools (biome/oxc/oxfmt) that - # `check` never fetches, so keying on it would bust the cache on unrelated - # bumps. (There is no root deno.lock — the root config has no external deps.) + # bump invalidates the cached deps. The sidecar's prettier/svelte fetches + # are the only runtime npm `check` does: `test:deno` runs the + # dependency-free divergence suite (node: builtins + relative imports, no + # node_modules — proven by a clean checkout), and the bench's heavy npm + # tree (biome/oxc/oxfmt) is never installed here. No deno.lock files exist + # (the bench resolves npm from package-lock.json; root has no external deps). cache-hash: ${{ hashFiles('crates/tsv_debug/src/deno/sidecar.ts', 'crates/tsv_debug/src/deno/actor.rs') }} - name: Check diff --git a/.gitignore b/.gitignore index 02bd053f6..71c6b759f 100644 --- a/.gitignore +++ b/.gitignore @@ -20,11 +20,19 @@ node_modules # Drift-check generated file (left on failure for inspection) /scripts/.drift_check.gen.ts -# Benchmark results (report.json and report.md are committed; baseline.json lives here too) -/benches/deno/results/*.json -/benches/deno/results/*.md -!/benches/deno/results/report.json -!/benches/deno/results/report.md +# Benchmark results (the per-runtime report..{json,md} siblings and the +# combined report.{json,md} are committed; timestamped runs + baseline.json are +# gitignored) +/benches/js/results/*.json +/benches/js/results/*.md +!/benches/js/results/report.deno.json +!/benches/js/results/report.deno.md +!/benches/js/results/report.node.json +!/benches/js/results/report.node.md +!/benches/js/results/report.bun.json +!/benches/js/results/report.bun.md +!/benches/js/results/report.json +!/benches/js/results/report.md # Env .env* diff --git a/CLAUDE.md b/CLAUDE.md index 52415d493..9be3f6aec 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -192,12 +192,11 @@ See ./docs/fixture_workflow.md. Use `--prettier-only` with `fixtures:validate` d ### JS Bindings -Two binding crates for different use cases: +Three binding crates for different use cases: - `tsv_ffi` (C ABI) — target: Any FFI (Deno, Python, etc.); output: `libtsv_ffi.so` / `.dylib` / `.dll` - `tsv_wasm` (wasm-bindgen) — target: Browser, Deno, Node; output: `.wasm` module (format / parse / all variants via cargo features) - -N-API is a maybe — the decision is deferred; there is currently no `tsv_napi` crate. +- `tsv_napi` (napi-rs) — target: Node.js / Bun native addon; output: `libtsv_napi.{so,dylib,dll}` (loaded via `process.dlopen`). Currently a **measurement-only** binding for the Node benchmark runner (single-platform local build, `deno task build:napi`); the cross-platform publish matrix as `@fuzdev/tsv_napi` is targeted for 0.2. tsv-scoped carve-out from the ecosystem N-API deferral. See ./crates/tsv_napi/CLAUDE.md. `tsv_wasm` produces three npm packages from one crate via the `format` + `parse` cargo features (default = both): `@fuzdev/tsv_format_wasm` (format only), `@fuzdev/tsv_parse_wasm` (parse only), and `@fuzdev/tsv_wasm` (everything + the `tsv` CLI). Each variant has its own output directory. @@ -268,37 +267,66 @@ deno task divergence:audit # audit divergence pattern coverage (--json f The corpus comparison builds with `--profile corpus` (release + `panic = "unwind"`) so panics in our code are caught and reported as errors instead of crashing the process. Benchmarks use `--release` (with `panic = "abort"`) for maximum performance. -Divergence detection identifies known differences documented in `conformance_prettier.md` (safety checks, pattern detection, traceability). See ./benches/deno/CLAUDE.md and ./docs/divergence_detector.md. +Divergence detection identifies known differences documented in `conformance_prettier.md` (safety checks, pattern detection, traceability). See ./benches/js/CLAUDE.md and ./docs/divergence_detector.md. ### Benchmarks +**Cross-runtime.** The same harness runs under **Deno, Node, and Bun** — each emits its +own runtime-labeled sibling report (`report.{deno,node,bun}.{json,md}`), never merged; +`deno task bench:compose` folds them into a compact combined `report.{json,md}` (the +cross-runtime view tsv.fuz.dev consumes). The native row differs by runtime: Deno loads the +**FFI** library via `Deno.dlopen`, Node/Bun load the **N-API** addon (`tsv_napi`) via +`process.dlopen`. Everything else (corpus, registry, timing, report) is runtime-neutral +shared code using `node:` builtins. + ```bash -# Smoke test (fast sanity check that every formatter+parser produces output) +# One-time: install the harness's npm deps (package.json is the source of truth; +# both runtimes consume the same node_modules). Re-run after a dep bump or a plain +# `npm install` (which prunes the oxc-parser-wasm binding — see benches/js/CLAUDE.md). +deno task bench:install + +# Smoke test (Deno; fast sanity check that every formatter+parser produces output) deno task smoke -# Run benchmarks (builds the bench artifact set — `build:bench` — automatically) -deno task bench +# Run benchmarks (builds the runtime's bench artifacts automatically). +# `bench` runs ALL three and FAILS FAST if node or bun is missing — Deno is the +# only hard dep, so without node/bun run the per-runtime tasks you have instead. +deno task bench # ALL three + compose (needs node AND bun installed) +deno task bench:deno # Deno only (no node/bun needed) +deno task bench:node # Node only (needs node) +deno task bench:bun # Bun only (needs bun; reuses the Node artifacts) +deno task bench:compose # Fold existing per-runtime reports → combined report.{json,md} -# Run without rebuilding (if already built). Aborts if the FFI/WASM artifacts -# are older than crate source — rebuild, or set BENCH_STALE_OK=1 to override -deno task bench:run +# Run without rebuilding (if already built; aborts on stale artifacts) +deno task bench:deno:run +deno task bench:node:run +deno task bench:bun:run # Per-file skip detail (off by default — counts always shown, paths/errors opt-in) -deno task bench:run -- --verbose # Include per-file skip detail in report - -# Environment variables -BENCH_LIMIT=10 deno task bench:run # Limit files per language (default: all) -BENCH_FILTER=zzz deno task bench:run # Filter by path pattern (default: none) -BENCH_DURATION=10000 deno task bench:run # Duration per benchmark in ms (default: 5000) -BENCH_WARMUP=10 deno task bench:run # Set warmup iterations (default: 3) -BENCH_MODE=union deno task bench:run # Per-impl iteration (default: intersection) -BENCH_STALE_OK=1 deno task bench:run # Run despite stale artifacts (default: off) -BENCH_FORCED_ASYNC=1 deno task bench:run # Add tsv-forced-async control row (diagnostic; default: off) -``` - -**Prerequisites**: `cargo install wasm-pack` - -Compares three implementations: canonical (prettier + svelte/compiler), native (FFI), WASM. Results are saved to `benches/deno/results/report.{json,md}` (committed). To publish to tsv.fuz.dev: `npm run update-benchmarks` in ~/dev/tsv.fuz.dev. See ./benches/deno/CLAUDE.md. +deno task bench:deno:run -- --verbose + +# Environment variables (apply to any runtime) +BENCH_LIMIT=10 deno task bench:deno:run # Limit files per language (default: all) +BENCH_FILTER=zzz deno task bench:deno:run # Filter by path pattern (default: none) +BENCH_DURATION=10000 deno task bench:deno:run # Duration per benchmark in ms (default: 5000) +BENCH_WARMUP=10 deno task bench:deno:run # Set warmup iterations (default: 3) +BENCH_MODE=union deno task bench:deno:run # Per-impl iteration (default: intersection) +BENCH_STALE_OK=1 deno task bench:deno:run # Run despite stale artifacts (default: off) +BENCH_FORCED_ASYNC=1 deno task bench:deno:run # Add tsv-forced-async control row (diagnostic; default: off) +``` + +**Prerequisites**: `cargo install wasm-pack` and `deno task bench:install` once +(the install needs `npm`, i.e. Node, to populate `node_modules`). Beyond that, +**Deno is the only hard dependency** — `bench:deno` / `smoke` run with just Deno. +Node ≥ 22.18 (native TS type-stripping) is needed for `bench:node` (and the +install); Bun for `bench:bun`. The aggregate `deno task bench` needs both and +fails fast if either is missing; run the per-runtime tasks for the ones you have. + +Compares: canonical (prettier + svelte/compiler), native (FFI under Deno / N-API under Node +and Bun), WASM, and alternatives (oxc-parser, oxfmt, biome-wasm). Each runtime's results save +to `benches/js/results/report..{json,md}` (committed; every row carries a `runtime` +field), plus the combined `report.{json,md}`. To publish to tsv.fuz.dev: `npm run update-benchmarks` in ~/dev/tsv.fuz.dev. See +./benches/js/CLAUDE.md. ### Performance Profiling @@ -379,8 +407,9 @@ tsv/ │ ├── tsv_svelte/ # Svelte: parse(), format(), convert_ast() │ ├── tsv_cli/ # Production CLI (binary: tsv) - pure Rust │ ├── tsv_debug/ # Dev utilities (binary: tsv_debug) - uses Deno -│ ├── tsv_ffi/ # C FFI bindings -│ └── tsv_wasm/ # WebAssembly bindings (published as @fuzdev/tsv_format_wasm + @fuzdev/tsv_parse_wasm + @fuzdev/tsv_wasm; bundles hand-maintained types/tsv_ast.d.ts; npm/cli.js is the tsv bin) +│ ├── tsv_ffi/ # C FFI bindings (Deno's native path) +│ ├── tsv_wasm/ # WebAssembly bindings (published as @fuzdev/tsv_format_wasm + @fuzdev/tsv_parse_wasm + @fuzdev/tsv_wasm; bundles hand-maintained types/tsv_ast.d.ts; npm/cli.js is the tsv bin) +│ └── tsv_napi/ # N-API bindings (Node/Bun native path; measurement-only for the Node bench, 0.2 publish target) ├── scripts/ # Publish orchestrator, npm package patcher, Node artifact tests, AST type drift check ├── tests/ # Integration tests (parser, formatter, CLI) │ └── fixtures/ # Test fixtures organized by language/feature @@ -659,8 +688,8 @@ cargo run -p tsv_debug test262 language/expressions # filter by path pattern # triage tsv's failures (real bug vs shared limitation). See ./docs/conformance_test262.md §Differential. cargo run -p tsv_debug test262 --emit-manifest /tmp/t262.json # path/expected/tsv verdict per graded test deno run --allow-read --allow-env --allow-ffi --allow-net --allow-sys \ - --config benches/deno/deno.json \ - benches/deno/diagnostics/test262_compare.ts --manifest /tmp/t262.json + --config benches/js/deno.json \ + benches/js/diagnostics/test262_compare.ts --manifest /tmp/t262.json ``` See ./docs/conformance_test262.md. @@ -883,6 +912,8 @@ Higher-fidelity models (attached comments, trivia tokens) may be needed for IDE/ - `unicode-ident` — Unicode XID_Start/XID_Continue for identifiers - `unicode-segmentation` — Grapheme clustering for visual width measurement - `unicode-width` — Character display width (CJK, zero-width) +- `bumpalo` — Bump arena for the internal AST (and the binding crates' per-thread `reset()` reuse) +- `napi` / `napi-derive` / `napi-build` — N-API bindings for `tsv_napi` (Node/Bun native addon; tsv-scoped carve-out) ## Canonical References diff --git a/Cargo.lock b/Cargo.lock index 1fd108978..4c1e7eafb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,21 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "convert_case" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "ctor" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01334b89b69ff726750c5ce5073fc8bd860e99aa9a8fc5ca11b04730e3aee97a" + [[package]] name = "equivalent" version = "1.0.2" @@ -85,12 +100,54 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + [[package]] name = "futures-macro" version = "0.3.31" @@ -102,6 +159,12 @@ dependencies = [ "syn", ] +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + [[package]] name = "futures-task" version = "0.3.31" @@ -114,9 +177,13 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", + "futures-io", "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -175,6 +242,16 @@ version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +[[package]] +name = "libloading" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" +dependencies = [ + "cfg-if", + "windows-link", +] + [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -198,6 +275,69 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "napi" +version = "3.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41bda2ac390efb5e8d22025d925ccc3f3807d8c1bea6d19b36127247c4b8f83" +dependencies = [ + "bitflags", + "ctor", + "futures", + "napi-build", + "napi-sys", + "nohash-hasher", + "rustc-hash", +] + +[[package]] +name = "napi-build" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9c366d2c8c60b86fa632df75f745509b52f9128f91a6bad4c796e44abb505e1" + +[[package]] +name = "napi-derive" +version = "3.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61d66f70256ad5aef58659966064471d0ad90e2897bc36a5a5e0389c85aabc1e" +dependencies = [ + "convert_case", + "ctor", + "napi-derive-backend", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "napi-derive-backend" +version = "5.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b4b08f15eed7a2a20c3f4c6314013fc3ac890a3afa9892b594485299ebdb2d" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "semver", + "syn", +] + +[[package]] +name = "napi-sys" +version = "3.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f5bcdf71abd3a50d00b49c1c2c75251cb3c913777d6139cd37dabc093a5e400" +dependencies = [ + "libloading", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "once_cell" version = "1.21.3" @@ -283,6 +423,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + [[package]] name = "rustix" version = "1.1.2" @@ -308,6 +454,12 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.228" @@ -571,6 +723,20 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "tsv_napi" +version = "0.1.0" +dependencies = [ + "bumpalo", + "napi", + "napi-build", + "napi-derive", + "serde_json", + "tsv_css", + "tsv_svelte", + "tsv_ts", +] + [[package]] name = "tsv_svelte" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 69ab8e93c..491925e98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "crates/tsv_debug", "crates/tsv_wasm", "crates/tsv_ffi", + "crates/tsv_napi", ] [workspace.package] @@ -38,6 +39,13 @@ tsv_svelte = { path = "crates/tsv_svelte", default-features = false } # External dependencies argh = "0.1" +# N-API (Node.js/Bun) bindings — the native path for the `tsv_napi` crate, the +# Node-runtime sibling of `tsv_ffi` (Deno's C-FFI path). napi/napi-derive ride +# the 3.x line together; napi-build (build dep) is its own 2.x line. tsv-scoped +# carve-out from the ecosystem N-API deferral — see lore TODO_NAPI_BINDINGS.md. +napi = "3.9.4" +napi-derive = "3.5.7" +napi-build = "2.3.2" # Bump arena for the internal AST: per-parse `Bump`, nodes/collections/decoded # strings allocated as `&'arena ...` (no per-node heap alloc/free, better # traversal locality). Already present transitively (via wasm-bindgen); this diff --git a/benches/deno/deno.json b/benches/deno/deno.json deleted file mode 100644 index 29bde733b..000000000 --- a/benches/deno/deno.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "//canonical-sync": "⚠ The 5 canonical packages (prettier, svelte, acorn, @sveltejs/acorn-typescript, prettier-plugin-svelte) are ALSO pinned as literals in crates/tsv_debug/src/deno/sidecar.ts and MUST match. Bumping any re-baselines the whole fixture corpus — see benches/deno/CLAUDE.md §'Canonical baseline is coupled'. The other imports (oxc, oxfmt, biome, etc.) are free to bump independently.", - "imports": { - "acorn": "npm:acorn@8.16.0", - "svelte": "npm:svelte@5.56.1", - "svelte/compiler": "npm:svelte@5.56.1/compiler", - "@sveltejs/acorn-typescript": "npm:@sveltejs/acorn-typescript@1.0.10", - "prettier": "npm:prettier@3.8.3", - "prettier-plugin-svelte": "npm:prettier-plugin-svelte@4.1.1", - "@biomejs/js-api": "npm:@biomejs/js-api@4.0.0", - "@biomejs/wasm-bundler": "npm:@biomejs/wasm-bundler@2.4.16", - "oxc-parser": "npm:oxc-parser@0.134.0", - "@oxc-parser/binding-wasm32-wasi/parser.wasi-browser.js": "npm:@oxc-parser/binding-wasm32-wasi@0.134.0/parser.wasi-browser.js", - "oxfmt": "npm:oxfmt@0.53.0", - "zod": "npm:zod@^4.4.3", - "@fuzdev/fuz_util": "npm:@fuzdev/fuz_util@0.64.0", - "@std/fs": "jsr:@std/fs@^1.0.24" - }, - "fmt": { - "useTabs": true, - "lineWidth": 100, - "singleQuote": true, - "proseWrap": "preserve" - } -} diff --git a/benches/deno/deno.lock b/benches/deno/deno.lock deleted file mode 100644 index 37fece885..000000000 --- a/benches/deno/deno.lock +++ /dev/null @@ -1,534 +0,0 @@ -{ - "version": "5", - "specifiers": { - "jsr:@std/fs@^1.0.24": "1.0.24", - "jsr:@std/internal@^1.0.14": "1.0.14", - "jsr:@std/path@^1.1.5": "1.1.5", - "npm:@biomejs/js-api@4.0.0": "4.0.0_@biomejs+wasm-bundler@2.4.16", - "npm:@biomejs/wasm-bundler@2.4.16": "2.4.16", - "npm:@fuzdev/fuz_util@0.64.0": "0.64.0_svelte@5.56.1_zod@4.4.3", - "npm:@oxc-parser/binding-wasm32-wasi@0.134.0": "0.134.0", - "npm:@sveltejs/acorn-typescript@1.0.10": "1.0.10_acorn@8.16.0", - "npm:acorn@8.16.0": "8.16.0", - "npm:oxc-parser@0.134.0": "0.134.0", - "npm:oxfmt@0.53.0": "0.53.0_svelte@5.56.1", - "npm:prettier-plugin-svelte@4.1.1": "4.1.1_prettier@3.8.3_svelte@5.56.1", - "npm:prettier@3.8.3": "3.8.3", - "npm:svelte@5.56.1": "5.56.1", - "npm:zod@^4.4.3": "4.4.3" - }, - "jsr": { - "@std/fs@1.0.24": { - "integrity": "f3061b45b81673a2bece689da041df32d174be064c89eb6397fb5718d3fb7877", - "dependencies": [ - "jsr:@std/internal", - "jsr:@std/path" - ] - }, - "@std/internal@1.0.14": { - "integrity": "291516b3d4c35024d6ffbc0a9df5bf4c64116e05b50012cf846710152d2ffdf7" - }, - "@std/path@1.1.5": { - "integrity": "ccea00982ea28c36becaf6e62f855406c76a8c32d462f66f415bbb7d83a271bc", - "dependencies": [ - "jsr:@std/internal" - ] - } - }, - "npm": { - "@biomejs/js-api@4.0.0_@biomejs+wasm-bundler@2.4.16": { - "integrity": "sha512-EOArR/6drRzM1/hwOIz1pZw90FL31Ud4Y7hEHGWVtMNmAwS9SrwZ8hMENGlLVXCeGW/kL46p8kX7eO6x9Nmezg==", - "dependencies": [ - "@biomejs/wasm-bundler" - ], - "optionalPeers": [ - "@biomejs/wasm-bundler" - ] - }, - "@biomejs/wasm-bundler@2.4.16": { - "integrity": "sha512-BV/+7zBokC08DhC9RZMH61TX//GEVuTxUMiDMC6Cg3Lvr0va/3Jp8qDOx4JtHULsA/fFE6CdehP+VETVJotRrg==" - }, - "@emnapi/core@1.10.0": { - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dependencies": [ - "@emnapi/wasi-threads", - "tslib" - ] - }, - "@emnapi/runtime@1.10.0": { - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dependencies": [ - "tslib" - ] - }, - "@emnapi/wasi-threads@1.2.1": { - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dependencies": [ - "tslib" - ] - }, - "@fuzdev/fuz_util@0.64.0_svelte@5.56.1_zod@4.4.3": { - "integrity": "sha512-NM/+olAhneQhIP2faPwPSftf20+qk4v/enFrQQTtrQLLsTeURv4oqhW7vB3S9QXW99T51c3CGyg+8yzoGnzxYg==", - "dependencies": [ - "esm-env", - "svelte", - "zod" - ], - "optionalPeers": [ - "svelte", - "zod" - ] - }, - "@jridgewell/gen-mapping@0.3.13": { - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dependencies": [ - "@jridgewell/sourcemap-codec", - "@jridgewell/trace-mapping" - ] - }, - "@jridgewell/remapping@2.3.5": { - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dependencies": [ - "@jridgewell/gen-mapping", - "@jridgewell/trace-mapping" - ] - }, - "@jridgewell/resolve-uri@3.1.2": { - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" - }, - "@jridgewell/sourcemap-codec@1.5.5": { - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" - }, - "@jridgewell/trace-mapping@0.3.31": { - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dependencies": [ - "@jridgewell/resolve-uri", - "@jridgewell/sourcemap-codec" - ] - }, - "@napi-rs/wasm-runtime@1.1.4_@emnapi+core@1.10.0_@emnapi+runtime@1.10.0": { - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "dependencies": [ - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util" - ] - }, - "@oxc-parser/binding-android-arm-eabi@0.134.0": { - "integrity": "sha512-N9Us7l/X9ZC3LA6eWSzPyduvBPXV1eRyDPwM6/UWpxwwXGsatb8131+d2L8UsmyHrixnKLHBd6UeH8wangV7fw==", - "os": ["android"], - "cpu": ["arm"] - }, - "@oxc-parser/binding-android-arm64@0.134.0": { - "integrity": "sha512-Ic2oPZESeCaD4+9cKRqp1GMYsTO9Q3Yi9HdY2x9x75ozbnC20sybFHzeBklmaVD9PBzd8KbkmNN0gy+SVlm7zw==", - "os": ["android"], - "cpu": ["arm64"] - }, - "@oxc-parser/binding-darwin-arm64@0.134.0": { - "integrity": "sha512-1z9+nVJ1Awq4CPyHAthx5zOUrg5T1zc3dWt6juxwDcuejFGbdYzWJITkS1rv4DCdSTphDU3IW71MzyLV3BjRGQ==", - "os": ["darwin"], - "cpu": ["arm64"] - }, - "@oxc-parser/binding-darwin-x64@0.134.0": { - "integrity": "sha512-MpofofaRZnxmYrY3lE8RTLHmE1KkX2q0elEeJ8sMcLbS8At76BjYSL6axssqhx29prGGDzIZ5lYFD+IXqaTzFA==", - "os": ["darwin"], - "cpu": ["x64"] - }, - "@oxc-parser/binding-freebsd-x64@0.134.0": { - "integrity": "sha512-OqnPQY27vqWAbMnHfLcF8CVOUv2cCvdlTiqyK5qz5WCbH3XOLpYVQATv8S5UrR8bbEJCAqJLsI7W6cRFXAxCoA==", - "os": ["freebsd"], - "cpu": ["x64"] - }, - "@oxc-parser/binding-linux-arm-gnueabihf@0.134.0": { - "integrity": "sha512-0eqWl+PWrcwGC3b8DCB58w3QINAuZfpX2ULTGpI01GUMBc6zDKSpttWxvqPIydxuQEkGQTQRAXLLvc+vTDZbQw==", - "os": ["linux"], - "cpu": ["arm"] - }, - "@oxc-parser/binding-linux-arm-musleabihf@0.134.0": { - "integrity": "sha512-YToasuDmyzpyTC1ztrvkaSXz8tP+YUbx041M/4SGxaRGiyMzsKkQ869KPUTGA57A6aVsb1/DiPX8XZQQeSFkiw==", - "os": ["linux"], - "cpu": ["arm"] - }, - "@oxc-parser/binding-linux-arm64-gnu@0.134.0": { - "integrity": "sha512-qMS7NLc2o8G7LLz53wisol+O7/YbMhtaGVhlfsTVLnrraf9kLFgzpiGjtQALLbdxX8uhx0Zmd4l+vY3s1/K4Gg==", - "os": ["linux"], - "cpu": ["arm64"] - }, - "@oxc-parser/binding-linux-arm64-musl@0.134.0": { - "integrity": "sha512-jUEsnxPXhrCYxswQLYvUOxZEE5UWFMkK5kBnrcPMj7TONz1pD0yKgPmOQCAx2LPoysJ/v2Sjg4RBUVoO2VXoZQ==", - "os": ["linux"], - "cpu": ["arm64"] - }, - "@oxc-parser/binding-linux-ppc64-gnu@0.134.0": { - "integrity": "sha512-FU5xMUsXnMuWKVCGo43c6SJsnqHcsioqm32PHdDY39cIRJa/AZbo7RMYW0W5gYcNZqb8EMhELkMDwbJOFbUhtg==", - "os": ["linux"], - "cpu": ["ppc64"] - }, - "@oxc-parser/binding-linux-riscv64-gnu@0.134.0": { - "integrity": "sha512-tPc7OAhslHVmNebho1RSEGL//7i7Nm39gbQ+gYreBYwzvDVqNwdQH3S13ccM+R1TpimQ+3bIyFMfnilJIGRtjQ==", - "os": ["linux"], - "cpu": ["riscv64"] - }, - "@oxc-parser/binding-linux-riscv64-musl@0.134.0": { - "integrity": "sha512-TtWEC4MUAHodX5a5kGsmK8g5K49V5ewWfwGrXdbw+gXWLXWXuhi+ectNELmOvYIwaqPSTAry1HNS/hfXssaPHQ==", - "os": ["linux"], - "cpu": ["riscv64"] - }, - "@oxc-parser/binding-linux-s390x-gnu@0.134.0": { - "integrity": "sha512-mF4uls8TA8SPXSDLpclJ6z9S+vaeUnNp95iUEfqwv9oVJUAE7B2j4crOj8UvByRXpbO5N+aAlJadQEyFlnXU6g==", - "os": ["linux"], - "cpu": ["s390x"] - }, - "@oxc-parser/binding-linux-x64-gnu@0.134.0": { - "integrity": "sha512-hieAQplyJeCvzqdSAxpOOGvVCBVXo/ioIBxioHfsUrQu93Et7Hy52cCG/GHEnjImVyeqEIViyyjuB0nKghxz/w==", - "os": ["linux"], - "cpu": ["x64"] - }, - "@oxc-parser/binding-linux-x64-musl@0.134.0": { - "integrity": "sha512-OQnJAK4sFuNSLgsh2s/K+14a3kwbmqf2yh1JiADU9XSfDuRooZYbAxmmBVPiyQ97+jBIIA1x2oPZeYNto3Ioow==", - "os": ["linux"], - "cpu": ["x64"] - }, - "@oxc-parser/binding-openharmony-arm64@0.134.0": { - "integrity": "sha512-RYLooe6g31q/PqNFN0NjR80IK/ARGsfLasAXL42LXonL+5Cyy9Or76rjBKQLAjERikJwbRU/sYW9Q5Tnpt1A4Q==", - "os": ["openharmony"], - "cpu": ["arm64"] - }, - "@oxc-parser/binding-wasm32-wasi@0.134.0": { - "integrity": "sha512-h8bmHyvc0PxA811prUjfVpJlQAurOOiRbohY4QNGjCEz+L72G9CmWl28OOz3mevrYlURgUsprNuH8hDJXh1VOw==", - "dependencies": [ - "@emnapi/core", - "@emnapi/runtime", - "@napi-rs/wasm-runtime" - ], - "cpu": ["wasm32"] - }, - "@oxc-parser/binding-win32-arm64-msvc@0.134.0": { - "integrity": "sha512-EPTfanpBMLNnSAWCDYpbJp1stmsf5x6hMsAwymf2J8ylRupIvO6FtKmHBMdc/wt43y08iz6ILlzFGIXe32/Kbw==", - "os": ["win32"], - "cpu": ["arm64"] - }, - "@oxc-parser/binding-win32-ia32-msvc@0.134.0": { - "integrity": "sha512-yAwetF+fTr9lTMtmqvkkWiiMXvH/yjMxGzUDG2rTL/LV1lL37eZ2enUGIlIo0gwhBIKWgabDEidtil+kiqNpgQ==", - "os": ["win32"], - "cpu": ["ia32"] - }, - "@oxc-parser/binding-win32-x64-msvc@0.134.0": { - "integrity": "sha512-4VY39G5tuGlBYiH13XbWqfLcwKygQEv0iyf8vtZ5NyLAGjI8M0MiYyLhj91GkWRznr+5VC0I+5R55HUDV/Rklw==", - "os": ["win32"], - "cpu": ["x64"] - }, - "@oxc-project/types@0.134.0": { - "integrity": "sha512-T0xuRRKrQFmocH8y+jGfpmSkGcheaJExY9lEihmR1Gm2aH+75B8CzgU2rABRQSzzDxLjZ15Sc0bRVLj5lVeNXQ==" - }, - "@oxfmt/binding-android-arm-eabi@0.53.0": { - "integrity": "sha512-XfVM8AmIovBTKXCt14Op5wbfcoM8418nttd+nhMgM3RAVaJg1MtJc73FyWfUt0oxLyBGVwfniNVUsbV/b3VmPg==", - "os": ["android"], - "cpu": ["arm"] - }, - "@oxfmt/binding-android-arm64@0.53.0": { - "integrity": "sha512-btHDfXckwdf9zgyAVznfZkf+GVyB0I1m1hlvaOMRx2xoyz3hphfPX97s89J3wfCN8QBETLtk4lQUaeOkrMuQOg==", - "os": ["android"], - "cpu": ["arm64"] - }, - "@oxfmt/binding-darwin-arm64@0.53.0": { - "integrity": "sha512-k2RjMcSTkHjoOlsVGbL35JVzXL+oQco3GHPl/5kjebVF4oHNfE24In8F5isqBh9LBJucycWHKDXdGrCchdWcHQ==", - "os": ["darwin"], - "cpu": ["arm64"] - }, - "@oxfmt/binding-darwin-x64@0.53.0": { - "integrity": "sha512-65jIBE2H1l5SSs16fmv6/7b6sAx/WpvnsgDhVWK9qSjNFDUro7MPQ6q5UhpY7kl46yltfR046iAnxy/Bzqbiew==", - "os": ["darwin"], - "cpu": ["x64"] - }, - "@oxfmt/binding-freebsd-x64@0.53.0": { - "integrity": "sha512-oYe1gkz7U49PCYrS9147d2fJZj8mDI4Di6AvlsU5fu9p+Tq8S7qqOMSZjUiVTLX8bXuSA9Lk/tIxuegVjkNYRA==", - "os": ["freebsd"], - "cpu": ["x64"] - }, - "@oxfmt/binding-linux-arm-gnueabihf@0.53.0": { - "integrity": "sha512-ailB2vLzGi629tymdAb2VYJyEHref7oqGxP+tRBrtRBxQrb6NV55JMT7xtGZ8uTeG2+Y9zojqW4LhJYxQnz9Pg==", - "os": ["linux"], - "cpu": ["arm"] - }, - "@oxfmt/binding-linux-arm-musleabihf@0.53.0": { - "integrity": "sha512-abh4mWBvOvD966sobqF7r103y2yYx7Rb4WGHLOS4+5igGqLbbPxS9aK5+45D6iUY7dWMsk3Muz9a8gUtufvqJA==", - "os": ["linux"], - "cpu": ["arm"] - }, - "@oxfmt/binding-linux-arm64-gnu@0.53.0": { - "integrity": "sha512-z73PvuhJ8qA+cDbaiqbtopHglA91U4+y5wn2sTJJrnpB957d5P33FEuyP3DQIFd7ofljmDmfVT4G0CVGHZaJWg==", - "os": ["linux"], - "cpu": ["arm64"] - }, - "@oxfmt/binding-linux-arm64-musl@0.53.0": { - "integrity": "sha512-I6bhOTroqc3ThrwZ89l2k3ivKuELhdPLbAcJhRNyjWvlgwb0vjRgEnVL1XLx5Jud04/ypNRZBykAWrSk6l/D+g==", - "os": ["linux"], - "cpu": ["arm64"] - }, - "@oxfmt/binding-linux-ppc64-gnu@0.53.0": { - "integrity": "sha512-w0p3JzB/PkkQjXALMJMqP9YfP3yq4w6zGsu5kezQmUnxRkN3b/Theg2l/nDgBsOcczxS3gL6Gam5XNAVrO6QJQ==", - "os": ["linux"], - "cpu": ["ppc64"] - }, - "@oxfmt/binding-linux-riscv64-gnu@0.53.0": { - "integrity": "sha512-mzBhF6k1Yq1K/dqDmVe/AAafnlJfEpx7yfUiksyeWXJk5iSzZqBSxcsa02zIytYgQFRZ7h6WPZfwHg/DoOE1Kw==", - "os": ["linux"], - "cpu": ["riscv64"] - }, - "@oxfmt/binding-linux-riscv64-musl@0.53.0": { - "integrity": "sha512-AlFCpnRQhogQFzZXWbO6xB6/Udy745L+eQNmDPGg7G/OeWsYmJc4jZYfUN5pQg0reOPWSED2mOQqKZOJM1U8cA==", - "os": ["linux"], - "cpu": ["riscv64"] - }, - "@oxfmt/binding-linux-s390x-gnu@0.53.0": { - "integrity": "sha512-XD4ulY4f1DWbuuZXAqxhVn+gdPmrhnmojWtFN78ctVoupmS845fGhsUrk1HZXKQI+iymbaiz9vAjPsghHNQ7Ag==", - "os": ["linux"], - "cpu": ["s390x"] - }, - "@oxfmt/binding-linux-x64-gnu@0.53.0": { - "integrity": "sha512-xg8KWX0QnxmYWRe60CgHYWXI0ZOtBbqTsXvWiWrcl2XUHJ3fht2QerOk2iWvylzX3zNT2GpvBRxGoR4d3sxPRQ==", - "os": ["linux"], - "cpu": ["x64"] - }, - "@oxfmt/binding-linux-x64-musl@0.53.0": { - "integrity": "sha512-MWExpYBGvl+pIvVB/gj/CcWlN2al8AizT7rUbtaYaWNoQkhWARM6W3qpgoCr72CYSN9PborzPmM5MIRe2BrNdA==", - "os": ["linux"], - "cpu": ["x64"] - }, - "@oxfmt/binding-openharmony-arm64@0.53.0": { - "integrity": "sha512-u4sajgO4nxgmJIgc/y2AqPhkdbOkQH8WugXpA1+pW0ESQhvGZ1oGq61Q4xMbJHJU1hFgtO18QNrcFYDPYH0gwQ==", - "os": ["openharmony"], - "cpu": ["arm64"] - }, - "@oxfmt/binding-win32-arm64-msvc@0.53.0": { - "integrity": "sha512-Yq9sOZoIOJ5xPjO0qOyHJS4CiPuTkB2en9auxZz7Ar2p5RaC7BzLyVVmAA7zz9/L9YnjjY1DwNxN+ivKXimN/A==", - "os": ["win32"], - "cpu": ["arm64"] - }, - "@oxfmt/binding-win32-ia32-msvc@0.53.0": { - "integrity": "sha512-es1fVNZEkBqEcQtBpn19SYFgZF7FawlkCjkT/iImfEAus4gun8fBwB1E9hpV5LcR9B0DBNvRIXhW8BQk3JaE+Q==", - "os": ["win32"], - "cpu": ["ia32"] - }, - "@oxfmt/binding-win32-x64-msvc@0.53.0": { - "integrity": "sha512-QFmJs2bEu9AO4O6qsmEaZNGi6dFq8N+rT8EHAAnZIq/B9SeJDUbc4DzVxQ48MfDsL7D3sCZzo37zuTuspcURgg==", - "os": ["win32"], - "cpu": ["x64"] - }, - "@sveltejs/acorn-typescript@1.0.10_acorn@8.16.0": { - "integrity": "sha512-4WfKk68eTih+MiJD4fSbxN7E8kVBmTMPWHUPYjvl2N0rMs53YLTT8/YjKU5Dtnz5LqDjl7LEw4U7lXR2W3J5WA==", - "dependencies": [ - "acorn" - ] - }, - "@tybys/wasm-util@0.10.2": { - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", - "dependencies": [ - "tslib" - ] - }, - "@types/estree@1.0.9": { - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==" - }, - "@types/trusted-types@2.0.7": { - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==" - }, - "acorn@8.16.0": { - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "bin": true - }, - "aria-query@5.3.1": { - "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==" - }, - "axobject-query@4.1.0": { - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==" - }, - "clsx@2.1.1": { - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" - }, - "devalue@5.8.1": { - "integrity": "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==" - }, - "esm-env@1.2.2": { - "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==" - }, - "esrap@2.2.9": { - "integrity": "sha512-4KijP+NxCWthMCUC3qHbE6n4vCjqgJS1uAYKhuT/GWfFTf1Qyive2TgOjep+gzbSzRfnNyaN/UU9YmdOt8Eg0A==", - "dependencies": [ - "@jridgewell/sourcemap-codec" - ] - }, - "is-reference@3.0.3": { - "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", - "dependencies": [ - "@types/estree" - ] - }, - "locate-character@3.0.0": { - "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" - }, - "magic-string@0.30.21": { - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dependencies": [ - "@jridgewell/sourcemap-codec" - ] - }, - "oxc-parser@0.134.0": { - "integrity": "sha512-Hs8fRG6A94BzMrMkGOtrUS7JQjmslfF+IvIXslf3QURzK3ud0QmFJRiYZjTe4TzAQnTfvlk4AwZnqIbrUjiE4w==", - "dependencies": [ - "@oxc-project/types" - ], - "optionalDependencies": [ - "@oxc-parser/binding-android-arm-eabi", - "@oxc-parser/binding-android-arm64", - "@oxc-parser/binding-darwin-arm64", - "@oxc-parser/binding-darwin-x64", - "@oxc-parser/binding-freebsd-x64", - "@oxc-parser/binding-linux-arm-gnueabihf", - "@oxc-parser/binding-linux-arm-musleabihf", - "@oxc-parser/binding-linux-arm64-gnu", - "@oxc-parser/binding-linux-arm64-musl", - "@oxc-parser/binding-linux-ppc64-gnu", - "@oxc-parser/binding-linux-riscv64-gnu", - "@oxc-parser/binding-linux-riscv64-musl", - "@oxc-parser/binding-linux-s390x-gnu", - "@oxc-parser/binding-linux-x64-gnu", - "@oxc-parser/binding-linux-x64-musl", - "@oxc-parser/binding-openharmony-arm64", - "@oxc-parser/binding-wasm32-wasi", - "@oxc-parser/binding-win32-arm64-msvc", - "@oxc-parser/binding-win32-ia32-msvc", - "@oxc-parser/binding-win32-x64-msvc" - ] - }, - "oxfmt@0.53.0_svelte@5.56.1": { - "integrity": "sha512-9cB5glS3Ip6NMuZ+6NYTao9FCWkDhRtPYCtR3QBu/NxHoFbgzzTvi41N4jxz/GqGfuLKspui1qb/LlSu2IbMcw==", - "dependencies": [ - "svelte", - "tinypool" - ], - "optionalDependencies": [ - "@oxfmt/binding-android-arm-eabi", - "@oxfmt/binding-android-arm64", - "@oxfmt/binding-darwin-arm64", - "@oxfmt/binding-darwin-x64", - "@oxfmt/binding-freebsd-x64", - "@oxfmt/binding-linux-arm-gnueabihf", - "@oxfmt/binding-linux-arm-musleabihf", - "@oxfmt/binding-linux-arm64-gnu", - "@oxfmt/binding-linux-arm64-musl", - "@oxfmt/binding-linux-ppc64-gnu", - "@oxfmt/binding-linux-riscv64-gnu", - "@oxfmt/binding-linux-riscv64-musl", - "@oxfmt/binding-linux-s390x-gnu", - "@oxfmt/binding-linux-x64-gnu", - "@oxfmt/binding-linux-x64-musl", - "@oxfmt/binding-openharmony-arm64", - "@oxfmt/binding-win32-arm64-msvc", - "@oxfmt/binding-win32-ia32-msvc", - "@oxfmt/binding-win32-x64-msvc" - ], - "optionalPeers": [ - "svelte" - ], - "bin": true - }, - "prettier-plugin-svelte@4.1.1_prettier@3.8.3_svelte@5.56.1": { - "integrity": "sha512-wXvbXMjSvb4C9ENWTHXyd+ihakKCsJ6rJhLP6/8HFNj4GkZr48jqL9PoKsl2sk7SyCZRTnJ7O2TTowUpOxP/KA==", - "dependencies": [ - "prettier", - "svelte" - ] - }, - "prettier@3.8.3": { - "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", - "bin": true - }, - "svelte@5.56.1": { - "integrity": "sha512-eArsJmvl3xZVuTYD852PzIEdg2wgDdIZ1NEsIPbzAukHwi284B18No4nK2rCO9AwsWUDza4Cjvmoa4HaojTl5g==", - "dependencies": [ - "@jridgewell/remapping", - "@jridgewell/sourcemap-codec", - "@sveltejs/acorn-typescript", - "@types/estree", - "@types/trusted-types", - "acorn", - "aria-query", - "axobject-query", - "clsx", - "devalue", - "esm-env", - "esrap", - "is-reference", - "locate-character", - "magic-string", - "zimmerframe" - ] - }, - "tinypool@2.1.0": { - "integrity": "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==" - }, - "tslib@2.8.1": { - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - }, - "zimmerframe@1.1.4": { - "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==" - }, - "zod@4.4.3": { - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==" - } - }, - "remote": { - "https://deno.land/std@0.224.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", - "https://deno.land/std@0.224.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834", - "https://deno.land/std@0.224.0/assert/assert_almost_equals.ts": "9e416114322012c9a21fa68e187637ce2d7df25bcbdbfd957cd639e65d3cf293", - "https://deno.land/std@0.224.0/assert/assert_array_includes.ts": "14c5094471bc8e4a7895fc6aa5a184300d8a1879606574cb1cd715ef36a4a3c7", - "https://deno.land/std@0.224.0/assert/assert_equals.ts": "3bbca947d85b9d374a108687b1a8ba3785a7850436b5a8930d81f34a32cb8c74", - "https://deno.land/std@0.224.0/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd", - "https://deno.land/std@0.224.0/assert/assert_false.ts": "3e9be8e33275db00d952e9acb0cd29481a44fa0a4af6d37239ff58d79e8edeff", - "https://deno.land/std@0.224.0/assert/assert_greater.ts": "5e57b201fd51b64ced36c828e3dfd773412c1a6120c1a5a99066c9b261974e46", - "https://deno.land/std@0.224.0/assert/assert_greater_or_equal.ts": "9870030f997a08361b6f63400273c2fb1856f5db86c0c3852aab2a002e425c5b", - "https://deno.land/std@0.224.0/assert/assert_instance_of.ts": "e22343c1fdcacfaea8f37784ad782683ec1cf599ae9b1b618954e9c22f376f2c", - "https://deno.land/std@0.224.0/assert/assert_is_error.ts": "f856b3bc978a7aa6a601f3fec6603491ab6255118afa6baa84b04426dd3cc491", - "https://deno.land/std@0.224.0/assert/assert_less.ts": "60b61e13a1982865a72726a5fa86c24fad7eb27c3c08b13883fb68882b307f68", - "https://deno.land/std@0.224.0/assert/assert_less_or_equal.ts": "d2c84e17faba4afe085e6c9123a63395accf4f9e00150db899c46e67420e0ec3", - "https://deno.land/std@0.224.0/assert/assert_match.ts": "ace1710dd3b2811c391946954234b5da910c5665aed817943d086d4d4871a8b7", - "https://deno.land/std@0.224.0/assert/assert_not_equals.ts": "78d45dd46133d76ce624b2c6c09392f6110f0df9b73f911d20208a68dee2ef29", - "https://deno.land/std@0.224.0/assert/assert_not_instance_of.ts": "3434a669b4d20cdcc5359779301a0588f941ffdc2ad68803c31eabdb4890cf7a", - "https://deno.land/std@0.224.0/assert/assert_not_match.ts": "df30417240aa2d35b1ea44df7e541991348a063d9ee823430e0b58079a72242a", - "https://deno.land/std@0.224.0/assert/assert_not_strict_equals.ts": "37f73880bd672709373d6dc2c5f148691119bed161f3020fff3548a0496f71b8", - "https://deno.land/std@0.224.0/assert/assert_object_match.ts": "411450fd194fdaabc0089ae68f916b545a49d7b7e6d0026e84a54c9e7eed2693", - "https://deno.land/std@0.224.0/assert/assert_rejects.ts": "4bee1d6d565a5b623146a14668da8f9eb1f026a4f338bbf92b37e43e0aa53c31", - "https://deno.land/std@0.224.0/assert/assert_strict_equals.ts": "b4f45f0fd2e54d9029171876bd0b42dd9ed0efd8f853ab92a3f50127acfa54f5", - "https://deno.land/std@0.224.0/assert/assert_string_includes.ts": "496b9ecad84deab72c8718735373feb6cdaa071eb91a98206f6f3cb4285e71b8", - "https://deno.land/std@0.224.0/assert/assert_throws.ts": "c6508b2879d465898dab2798009299867e67c570d7d34c90a2d235e4553906eb", - "https://deno.land/std@0.224.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917", - "https://deno.land/std@0.224.0/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47", - "https://deno.land/std@0.224.0/assert/fail.ts": "0eba674ffb47dff083f02ced76d5130460bff1a9a68c6514ebe0cdea4abadb68", - "https://deno.land/std@0.224.0/assert/mod.ts": "48b8cb8a619ea0b7958ad7ee9376500fe902284bb36f0e32c598c3dc34cbd6f3", - "https://deno.land/std@0.224.0/assert/unimplemented.ts": "8c55a5793e9147b4f1ef68cd66496b7d5ba7a9e7ca30c6da070c1a58da723d73", - "https://deno.land/std@0.224.0/assert/unreachable.ts": "5ae3dbf63ef988615b93eb08d395dda771c96546565f9e521ed86f6510c29e19", - "https://deno.land/std@0.224.0/fmt/colors.ts": "508563c0659dd7198ba4bbf87e97f654af3c34eb56ba790260f252ad8012e1c5", - "https://deno.land/std@0.224.0/internal/diff.ts": "6234a4b493ebe65dc67a18a0eb97ef683626a1166a1906232ce186ae9f65f4e6", - "https://deno.land/std@0.224.0/internal/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2", - "https://deno.land/std@0.224.0/internal/mod.ts": "534125398c8e7426183e12dc255bb635d94e06d0f93c60a297723abe69d3b22e" - }, - "workspace": { - "dependencies": [ - "jsr:@std/fs@^1.0.24", - "npm:@biomejs/js-api@4.0.0", - "npm:@biomejs/wasm-bundler@2.4.16", - "npm:@fuzdev/fuz_util@0.64.0", - "npm:@oxc-parser/binding-wasm32-wasi@0.134.0", - "npm:@sveltejs/acorn-typescript@1.0.10", - "npm:acorn@8.16.0", - "npm:oxc-parser@0.134.0", - "npm:oxfmt@0.53.0", - "npm:prettier-plugin-svelte@4.1.1", - "npm:prettier@3.8.3", - "npm:svelte@5.56.1", - "npm:zod@^4.4.3" - ] - } -} diff --git a/benches/deno/lib/versions.ts b/benches/deno/lib/versions.ts deleted file mode 100644 index 33138590f..000000000 --- a/benches/deno/lib/versions.ts +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Centralized version loading from deno.json - * - * Single source of truth for all package versions used in benchmarks. - */ - -import { extract_version } from './types.ts'; - -/** Canonical implementation versions */ -export interface CanonicalVersions { - prettier: string; - 'prettier-plugin-svelte': string; - svelte: string; - acorn: string; - '@sveltejs/acorn-typescript': string; -} - -/** OXC implementation versions */ -export interface OxcVersions { - 'oxc-parser': string; - oxfmt: string; -} - -/** Biome implementation versions */ -export interface BiomeVersions { - js_api: string; - wasm: string; -} - -/** All implementation versions */ -export interface AllVersions { - canonical: CanonicalVersions; - oxc: OxcVersions; - biome: BiomeVersions; -} - -/** Default versions when loading fails */ -const DEFAULT_VERSIONS: AllVersions = { - canonical: { - prettier: 'unknown', - 'prettier-plugin-svelte': 'unknown', - svelte: 'unknown', - acorn: 'unknown', - '@sveltejs/acorn-typescript': 'unknown', - }, - oxc: { - 'oxc-parser': 'unknown', - oxfmt: 'unknown', - }, - biome: { - js_api: 'unknown', - wasm: 'unknown', - }, -}; - -/** - * Load all package versions from deno.json import map. - * - * Reads benches/deno/deno.json to extract versions for all implementations. - */ -export async function load_all_versions(): Promise { - try { - const deno_json_path = new URL('../deno.json', import.meta.url).pathname; - const content = await Deno.readTextFile(deno_json_path); - const config = JSON.parse(content); - const imports = config.imports || {}; - - return { - canonical: { - prettier: extract_version(imports['prettier'] || ''), - 'prettier-plugin-svelte': extract_version(imports['prettier-plugin-svelte'] || ''), - svelte: extract_version(imports['svelte'] || ''), - acorn: extract_version(imports['acorn'] || ''), - '@sveltejs/acorn-typescript': extract_version( - imports['@sveltejs/acorn-typescript'] || '', - ), - }, - oxc: { - 'oxc-parser': extract_version(imports['oxc-parser'] || ''), - oxfmt: extract_version(imports['oxfmt'] || ''), - }, - biome: { - js_api: extract_version(imports['@biomejs/js-api'] || ''), - wasm: extract_version(imports['@biomejs/wasm-bundler'] || ''), - }, - }; - } catch { - return DEFAULT_VERSIONS; - } -} diff --git a/benches/deno/results/report.json b/benches/deno/results/report.json deleted file mode 100644 index 13d4ef4af..000000000 --- a/benches/deno/results/report.json +++ /dev/null @@ -1,684 +0,0 @@ -{ - "version": 4, - "timestamp": "2026-06-12T09:22:00.588Z", - "git_commit": "9b5c4e98", - "corpus": { - "svelte": 1240, - "typescript": 4025, - "css": 193 - }, - "versions": { - "svelte": "5.56.1", - "acorn": "8.16.0", - "acorn_ts": "1.0.10", - "prettier": "3.8.3", - "prettier_svelte": "3.5.2", - "oxc_parser": "0.134.0", - "oxfmt": "0.53.0", - "biome": "2.4.16" - }, - "binary_sizes": [ - { - "label": "tsv (native)", - "bytes": 3861760, - "kind": "native", - "gzip_bytes": 1622771 - }, - { - "label": "tsv_format_wasm", - "bytes": 2196292, - "kind": "wasm", - "gzip_bytes": 715422 - }, - { - "label": "tsv_parse_wasm", - "bytes": 1699625, - "kind": "wasm", - "gzip_bytes": 526578 - }, - { - "label": "tsv_wasm", - "bytes": 2888918, - "kind": "wasm", - "gzip_bytes": 911323 - }, - { - "label": "biome (wasm)", - "bytes": 34430368, - "kind": "wasm", - "gzip_bytes": 8187702 - }, - { - "label": "oxc-parser (native)", - "bytes": 2658008, - "kind": "native", - "gzip_bytes": 1032774 - }, - { - "label": "oxfmt (native)", - "bytes": 8016464, - "kind": "native", - "gzip_bytes": 3224684 - }, - { - "label": "oxc-parser (wasm)", - "bytes": 1866798, - "kind": "wasm", - "gzip_bytes": 518682 - } - ], - "entries": [ - { - "name": "svelte/compiler", - "group": "parse/svelte", - "mean_ns": 353647929.8666667, - "p50_ns": 351794280, - "p75_ns": 355710613.5, - "p90_ns": 358757843.8, - "p95_ns": 359832344.1, - "p99_ns": 361455435.21999997, - "min_ns": 349590498, - "max_ns": 361861208, - "std_dev_ns": 3732468.9277879535, - "cv": 0.010554194193064213, - "ops_per_second": 2.8276710127414653, - "sample_size": 15, - "files_processed": 1193, - "files_total": 1240, - "files_iterated": 1192 - }, - { - "name": "tsv-json", - "group": "parse/svelte", - "mean_ns": 485025992.4444444, - "p50_ns": 485086813, - "p75_ns": 487644066, - "p90_ns": 491656222, - "p95_ns": 494258617.5, - "p99_ns": 496340533.9, - "min_ns": 481783564, - "max_ns": 496861013, - "std_dev_ns": 1892163.1540198317, - "cv": 0.0039011582543930627, - "ops_per_second": 2.061745175676418, - "sample_size": 9, - "files_processed": 1202, - "files_total": 1240, - "files_iterated": 1192 - }, - { - "name": "tsv_wasm-json", - "group": "parse/svelte", - "mean_ns": 515988848.71428573, - "p50_ns": 516072939.5, - "p75_ns": 517319991, - "p90_ns": 519264292.5, - "p95_ns": 520772636.25, - "p99_ns": 521979311.25, - "min_ns": 515560589, - "max_ns": 522280980, - "std_dev_ns": 253147.57598596797, - "cv": 0.0004906066800023837, - "ops_per_second": 1.9380263788485899, - "sample_size": 7, - "files_processed": 1202, - "files_total": 1240, - "files_iterated": 1192 - }, - { - "name": "tsv-internal", - "group": "parse/svelte", - "mean_ns": 37041735.949579835, - "p50_ns": 36817941, - "p75_ns": 38031003.5, - "p90_ns": 39745595, - "p95_ns": 49374707.5, - "p99_ns": 70563356.69999997, - "min_ns": 35490755, - "max_ns": 73560234, - "std_dev_ns": 1041838.039960544, - "cv": 0.02812605870790355, - "ops_per_second": 26.996574927297463, - "sample_size": 119, - "files_processed": 1202, - "files_total": 1240, - "files_iterated": 1192 - }, - { - "name": "tsv_wasm-internal", - "group": "parse/svelte", - "mean_ns": 45254932.2745098, - "p50_ns": 45241227, - "p75_ns": 45348407.5, - "p90_ns": 45449227, - "p95_ns": 45624719, - "p99_ns": 45694463.7, - "min_ns": 45087137, - "max_ns": 45720491, - "std_dev_ns": 94029.59204496059, - "cv": 0.0020777755554817943, - "ops_per_second": 22.097038924600444, - "sample_size": 102, - "files_processed": 1202, - "files_total": 1240, - "files_iterated": 1192 - }, - { - "name": "prettier", - "group": "format/svelte", - "mean_ns": 3156053205.2, - "p50_ns": 3153333425, - "p75_ns": 3161183958, - "p90_ns": 3191384359.8, - "p95_ns": 3201451160.4, - "p99_ns": 3209504600.88, - "min_ns": 3116677318, - "max_ns": 3211517961, - "std_dev_ns": 35365115.51584766, - "cv": 0.011205487745763958, - "ops_per_second": 0.316851439117811, - "sample_size": 5, - "files_processed": 1201, - "files_total": 1240, - "files_iterated": 1194 - }, - { - "name": "tsv", - "group": "format/svelte", - "mean_ns": 253589550.66666666, - "p50_ns": 250899714, - "p75_ns": 261502311.75, - "p90_ns": 270307677.1, - "p95_ns": 291692469.25, - "p99_ns": 299630277.84999996, - "min_ns": 247143299, - "max_ns": 301614730, - "std_dev_ns": 6469364.524097994, - "cv": 0.02551116363860637, - "ops_per_second": 3.9433801486342004, - "sample_size": 18, - "files_processed": 1202, - "files_total": 1240, - "files_iterated": 1194 - }, - { - "name": "tsv_wasm", - "group": "format/svelte", - "mean_ns": 348305291.1666667, - "p50_ns": 348407825, - "p75_ns": 349005457.5, - "p90_ns": 351966927.4, - "p95_ns": 353359477.1, - "p99_ns": 355469057.02, - "min_ns": 347712508, - "max_ns": 355996452, - "std_dev_ns": 403574.7899962474, - "cv": 0.0011586811921359351, - "ops_per_second": 2.8710445272032703, - "sample_size": 12, - "files_processed": 1202, - "files_total": 1240, - "files_iterated": 1194 - }, - { - "name": "oxfmt", - "group": "format/svelte", - "mean_ns": 3363123440.8, - "p50_ns": 3355465187, - "p75_ns": 3380464215, - "p90_ns": 3387858512.4, - "p95_ns": 3390323278.2, - "p99_ns": 3392295090.84, - "min_ns": 3336319057, - "max_ns": 3392788044, - "std_dev_ns": 22995300.045456335, - "cv": 0.006837483205786329, - "ops_per_second": 0.2973426392467253, - "sample_size": 5, - "files_processed": 1201, - "files_total": 1240, - "files_iterated": 1194 - }, - { - "name": "biome-wasm", - "group": "format/svelte", - "mean_ns": 651628305.75, - "p50_ns": 651348032.5, - "p75_ns": 652776746.25, - "p90_ns": 655602311.7, - "p95_ns": 657068072.85, - "p99_ns": 658240681.77, - "min_ns": 646287594, - "max_ns": 658533834, - "std_dev_ns": 3695077.8107031505, - "cv": 0.005670529929558927, - "ops_per_second": 1.5346171907757093, - "sample_size": 8, - "files_processed": 1238, - "files_total": 1240, - "files_iterated": 1194 - }, - { - "name": "acorn-typescript", - "group": "parse/typescript", - "mean_ns": 2213405912.6, - "p50_ns": 2212095774, - "p75_ns": 2213405114, - "p90_ns": 2218802607.8, - "p95_ns": 2220601772.4, - "p99_ns": 2222041104.08, - "min_ns": 2209487030, - "max_ns": 2222400937, - "std_dev_ns": 5295312.414249306, - "cv": 0.0023923819775240017, - "ops_per_second": 0.4517924138123132, - "sample_size": 5, - "files_processed": 3693, - "files_total": 4025, - "files_iterated": 3603 - }, - { - "name": "tsv-json", - "group": "parse/typescript", - "mean_ns": 2049624429.8, - "p50_ns": 2046277896, - "p75_ns": 2052475955, - "p90_ns": 2062325034.8, - "p95_ns": 2065608061.4, - "p99_ns": 2068234482.68, - "min_ns": 2036381168, - "max_ns": 2068891088, - "std_dev_ns": 12211486.98364508, - "cv": 0.005957914438420635, - "ops_per_second": 0.4878942627052796, - "sample_size": 5, - "files_processed": 3743, - "files_total": 4025, - "files_iterated": 3603 - }, - { - "name": "tsv_wasm-json", - "group": "parse/typescript", - "mean_ns": 2223665077.4, - "p50_ns": 2223809451, - "p75_ns": 2224511693, - "p90_ns": 2224643608.4, - "p95_ns": 2224687580.2, - "p99_ns": 2224722757.64, - "min_ns": 2222334633, - "max_ns": 2224731552, - "std_dev_ns": 1021470.6667904371, - "cv": 0.0004593635422762416, - "ops_per_second": 0.44970801141026184, - "sample_size": 5, - "files_processed": 3743, - "files_total": 4025, - "files_iterated": 3603 - }, - { - "name": "tsv-internal", - "group": "parse/typescript", - "mean_ns": 236250428.1875, - "p50_ns": 235985787, - "p75_ns": 239292380, - "p90_ns": 262673433, - "p95_ns": 263116119, - "p99_ns": 263948169.4, - "min_ns": 234967322, - "max_ns": 264156182, - "std_dev_ns": 1336552.468610353, - "cv": 0.005657354692917632, - "ops_per_second": 4.232796561140413, - "sample_size": 16, - "files_processed": 3743, - "files_total": 4025, - "files_iterated": 3603 - }, - { - "name": "tsv_wasm-internal", - "group": "parse/typescript", - "mean_ns": 292595892.125, - "p50_ns": 292647736.5, - "p75_ns": 292773388.75, - "p90_ns": 293666035.6, - "p95_ns": 294709175.9, - "p99_ns": 294963799.18, - "min_ns": 292266142, - "max_ns": 295027455, - "std_dev_ns": 262236.36256371846, - "cv": 0.0008962407525929597, - "ops_per_second": 3.4176829781765687, - "sample_size": 16, - "files_processed": 3743, - "files_total": 4025, - "files_iterated": 3603 - }, - { - "name": "oxc-parser", - "group": "parse/typescript", - "mean_ns": 864942821.5, - "p50_ns": 863969686.5, - "p75_ns": 878826551, - "p90_ns": 884913960, - "p95_ns": 887896262.5, - "p99_ns": 890282104.5, - "min_ns": 845083325, - "max_ns": 890878565, - "std_dev_ns": 20069394.017162047, - "cv": 0.023203145362091483, - "ops_per_second": 1.1561457880716106, - "sample_size": 6, - "files_processed": 3833, - "files_total": 4025, - "files_iterated": 3603 - }, - { - "name": "oxc-parser-wasm", - "group": "parse/typescript", - "mean_ns": 976785685.3333334, - "p50_ns": 975594108.5, - "p75_ns": 979113434.75, - "p90_ns": 982226200, - "p95_ns": 983362576, - "p99_ns": 984271676.8, - "min_ns": 971966753, - "max_ns": 984498952, - "std_dev_ns": 4714293.024074751, - "cv": 0.004826333037902754, - "ops_per_second": 1.023766026688592, - "sample_size": 6, - "files_processed": 4025, - "files_total": 4025, - "files_iterated": 3603 - }, - { - "name": "prettier", - "group": "format/typescript", - "mean_ns": 8773944013.666666, - "p50_ns": 8784008051, - "p75_ns": 8807150369, - "p90_ns": 8902301987.4, - "p95_ns": 8961594658.2, - "p99_ns": 9009028794.84, - "min_ns": 8712430383, - "max_ns": 9020887329, - "std_dev_ns": 36684367.115987, - "cv": 0.004181057806939032, - "ops_per_second": 0.1139738296075696, - "sample_size": 6, - "files_processed": 3855, - "files_total": 4025, - "files_iterated": 3701 - }, - { - "name": "tsv", - "group": "format/typescript", - "mean_ns": 854559033.5, - "p50_ns": 856988296.5, - "p75_ns": 860171191.5, - "p90_ns": 861313209, - "p95_ns": 861398115.5, - "p99_ns": 861466040.7, - "min_ns": 838541329, - "max_ns": 861483022, - "std_dev_ns": 8547810.99796243, - "cv": 0.01000259860685497, - "ops_per_second": 1.1701941712608437, - "sample_size": 6, - "files_processed": 3743, - "files_total": 4025, - "files_iterated": 3701 - }, - { - "name": "tsv_wasm", - "group": "format/typescript", - "mean_ns": 1145280037.8, - "p50_ns": 1144938011, - "p75_ns": 1145815746, - "p90_ns": 1146670300.2, - "p95_ns": 1146955151.6, - "p99_ns": 1147183032.72, - "min_ns": 1144152898, - "max_ns": 1147240003, - "std_dev_ns": 1281560.5264546424, - "cv": 0.0011189931581418527, - "ops_per_second": 0.8731488954622204, - "sample_size": 5, - "files_processed": 3743, - "files_total": 4025, - "files_iterated": 3701 - }, - { - "name": "oxfmt", - "group": "format/typescript", - "mean_ns": 802078434.8571428, - "p50_ns": 804423326, - "p75_ns": 806569662, - "p90_ns": 809150059.2, - "p95_ns": 809881109.1, - "p99_ns": 810465949.02, - "min_ns": 792012009, - "max_ns": 810612159, - "std_dev_ns": 7054022.950975906, - "cv": 0.008794679727590843, - "ops_per_second": 1.246760860960074, - "sample_size": 7, - "files_processed": 3836, - "files_total": 4025, - "files_iterated": 3701 - }, - { - "name": "biome-wasm", - "group": "format/typescript", - "mean_ns": 3651240436.25, - "p50_ns": 3651115766, - "p75_ns": 3652416674, - "p90_ns": 3654275795, - "p95_ns": 3654895502, - "p99_ns": 3655391267.6, - "min_ns": 3650446557, - "max_ns": 3655515209, - "std_dev_ns": 835808.0747653235, - "cv": 0.00022891071934548872, - "ops_per_second": 0.2738795260021409, - "sample_size": 4, - "files_processed": 4025, - "files_total": 4025, - "files_iterated": 3701 - }, - { - "name": "svelte/compiler", - "group": "parse/css", - "mean_ns": 19403785.678294573, - "p50_ns": 19376518.5, - "p75_ns": 19515459.5, - "p90_ns": 19626101.3, - "p95_ns": 19749809.1, - "p99_ns": 19835973.34, - "min_ns": 19083462, - "max_ns": 19889772, - "std_dev_ns": 170231.79292084067, - "cv": 0.008773122716525623, - "ops_per_second": 51.53633505232013, - "sample_size": 258, - "files_processed": 163, - "files_total": 193, - "files_iterated": 159 - }, - { - "name": "tsv-json", - "group": "parse/css", - "mean_ns": 176879819.27586207, - "p50_ns": 176417640, - "p75_ns": 178453737, - "p90_ns": 179335842.4, - "p95_ns": 179414368, - "p99_ns": 179869721.35999998, - "min_ns": 173847338, - "max_ns": 180029857, - "std_dev_ns": 1802916.9896241936, - "cv": 0.010192892535763852, - "ops_per_second": 5.653556206094932, - "sample_size": 29, - "files_processed": 165, - "files_total": 193, - "files_iterated": 159 - }, - { - "name": "tsv_wasm-json", - "group": "parse/css", - "mean_ns": 223033824.05555555, - "p50_ns": 222987561, - "p75_ns": 224042748.5, - "p90_ns": 226002163.2, - "p95_ns": 226359314, - "p99_ns": 226689078.04, - "min_ns": 222564338, - "max_ns": 226779975, - "std_dev_ns": 476931.02029914665, - "cv": 0.002138379783060832, - "ops_per_second": 4.483624868266213, - "sample_size": 18, - "files_processed": 165, - "files_total": 193, - "files_iterated": 159 - }, - { - "name": "tsv-internal", - "group": "parse/css", - "mean_ns": 23123759.831578948, - "p50_ns": 23081315.5, - "p75_ns": 23581269.25, - "p90_ns": 25285569.600000005, - "p95_ns": 26399632.149999995, - "p99_ns": 34455670.899999976, - "min_ns": 22528124, - "max_ns": 43861736, - "std_dev_ns": 454153.9601688399, - "cv": 0.019640143448844544, - "ops_per_second": 43.24556245539061, - "sample_size": 190, - "files_processed": 165, - "files_total": 193, - "files_iterated": 159 - }, - { - "name": "tsv_wasm-internal", - "group": "parse/css", - "mean_ns": 32072885.51879699, - "p50_ns": 32066954.5, - "p75_ns": 32148053.5, - "p90_ns": 32335215.5, - "p95_ns": 32349665.75, - "p99_ns": 32378088.75, - "min_ns": 31983936, - "max_ns": 32565198, - "std_dev_ns": 53586.24561517934, - "cv": 0.0016707647206789045, - "ops_per_second": 31.178984485631293, - "sample_size": 133, - "files_processed": 165, - "files_total": 193, - "files_iterated": 159 - }, - { - "name": "prettier", - "group": "format/css", - "mean_ns": 731055145.8571428, - "p50_ns": 726866934, - "p75_ns": 737411474, - "p90_ns": 739494874, - "p95_ns": 740913023.5, - "p99_ns": 742047543.1, - "min_ns": 723869573, - "max_ns": 742331173, - "std_dev_ns": 7724050.9095097985, - "cv": 0.010565620053810789, - "ops_per_second": 1.3678858642428766, - "sample_size": 7, - "files_processed": 192, - "files_total": 193, - "files_iterated": 165 - }, - { - "name": "tsv", - "group": "format/css", - "mean_ns": 42276700.15044248, - "p50_ns": 42363994, - "p75_ns": 42798711, - "p90_ns": 43541791.3, - "p95_ns": 44634919.449999996, - "p99_ns": 50024498.75, - "min_ns": 40686670, - "max_ns": 51286794, - "std_dev_ns": 850647.2521532943, - "cv": 0.020120947215043962, - "ops_per_second": 23.65369095604624, - "sample_size": 113, - "files_processed": 165, - "files_total": 193, - "files_iterated": 165 - }, - { - "name": "tsv_wasm", - "group": "format/css", - "mean_ns": 56842907.02898551, - "p50_ns": 56836126.5, - "p75_ns": 57051209.25, - "p90_ns": 57277215.5, - "p95_ns": 57411214.85, - "p99_ns": 57614455.839999996, - "min_ns": 56701796, - "max_ns": 57937459, - "std_dev_ns": 94515.15490540798, - "cv": 0.0016627431608522859, - "ops_per_second": 17.59234445011894, - "sample_size": 69, - "files_processed": 165, - "files_total": 193, - "files_iterated": 165 - }, - { - "name": "oxfmt", - "group": "format/css", - "mean_ns": 759715951, - "p50_ns": 758504294, - "p75_ns": 764356670.5, - "p90_ns": 792120220.8000001, - "p95_ns": 810371960.4, - "p99_ns": 824973352.0799999, - "min_ns": 755827467, - "max_ns": 828623700, - "std_dev_ns": 4300372.980217599, - "cv": 0.005660501105126328, - "ops_per_second": 1.3162814321375227, - "sample_size": 6, - "files_processed": 192, - "files_total": 193, - "files_iterated": 165 - }, - { - "name": "biome-wasm", - "group": "format/css", - "mean_ns": 207351523.875, - "p50_ns": 207159397, - "p75_ns": 208264123, - "p90_ns": 208754043.4, - "p95_ns": 209395575, - "p99_ns": 209795343.92, - "min_ns": 205889964, - "max_ns": 209888054, - "std_dev_ns": 897025.2129294197, - "cv": 0.004326108610950857, - "ops_per_second": 4.822727999832984, - "sample_size": 24, - "files_processed": 193, - "files_total": 193, - "files_iterated": 165 - } - ], - "suppressed_noise": { - "oxfmt::textToDoc": 1, - "panicked at crates/biome_rowan": 1 - } -} diff --git a/benches/deno/results/report.md b/benches/deno/results/report.md deleted file mode 100644 index 32657ac36..000000000 --- a/benches/deno/results/report.md +++ /dev/null @@ -1,193 +0,0 @@ -# tsv benchmark results - -**Date:** 2026-06-12T09:22:00.588Z (9b5c4e98) - -**Corpus:** 1240 Svelte (1.6 MB), 4025 TypeScript (13.1 MB), 193 CSS (0.7 MB) — 5458 files, 15.4 MB total - -**Versions:** svelte@5.56.1, acorn@8.16.0, acorn-typescript@1.0.10, prettier@3.8.3, prettier-plugin-svelte@3.5.2, oxc-parser@0.134.0, oxfmt@0.53.0, @biomejs/wasm-bundler@2.4.16 - -**Methodology:** Single-threaded — every implementation formats/parses one file at a time, measured sequentially with no cross-file parallelism. The numbers are per-file, single-core latency/throughput, not the multi-core batch throughput a CLI gets formatting many files at once. - -## parse/svelte - -| Task Name | ops/sec | n | p50 (ms) | p75 (ms) | p90 (ms) | p95 (ms) | p99 (ms) | min (ms) | max (ms) | vs svelte/compiler (speedup) | -| ----------------- | ------- | --- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | ---------------------------- | -| svelte/compiler | 2.83 | 15 | 351.79 | 355.71 | 358.76 | 359.83 | 361.46 | 349.59 | 361.86 | baseline | -| tsv-json | 2.06 | 9 | 485.09 | 487.64 | 491.66 | — | — | 481.78 | 496.86 | 0.73x | -| tsv_wasm-json | 1.94 | 7 | 516.07 | 517.32 | 519.26 | — | — | 515.56 | 522.28 | 0.69x | -| tsv-internal | 27.00 | 119 | 36.82 | 38.03 | 39.75 | 49.37 | 70.56 | 35.49 | 73.56 | 9.55x | -| tsv_wasm-internal | 22.10 | 102 | 45.24 | 45.35 | 45.45 | 45.62 | 45.69 | 45.09 | 45.72 | 7.81x | - -**Files (intersection):** 1192 - -**Throughput:** svelte/compiler 4.5 MB/s, tsv-json 3.3 MB/s, tsv_wasm-json 3.1 MB/s, tsv-internal 43.4 MB/s, tsv_wasm-internal 35.5 MB/s - -**Coverage:** svelte/compiler 1193/1240 (96%), tsv-json 1202/1240 (96%), tsv_wasm-json 1202/1240 (96%), tsv-internal 1202/1240 (96%), tsv_wasm-internal 1202/1240 (96%) - -**JSON overhead** (json_ns / internal_ns, higher = more cost): tsv-json 13.1x tsv-internal, tsv_wasm-json 11.4x tsv_wasm-internal - -## format/svelte - -| Task Name | ops/sec | n | p50 (ms) | p75 (ms) | p90 (ms) | p95 (ms) | p99 (ms) | min (ms) | max (ms) | vs prettier (speedup) | -| ---------- | ------- | -- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | --------------------- | -| prettier | 0.32 | 5 | 3153.33 | 3161.18 | 3191.38 | — | — | 3116.68 | 3211.52 | baseline | -| tsv | 3.94 | 18 | 250.90 | 261.50 | 270.31 | 291.69 | 299.63 | 247.14 | 301.61 | 12.4x | -| tsv_wasm | 2.87 | 12 | 348.41 | 349.01 | 351.97 | 353.36 | 355.47 | 347.71 | 356.00 | 9.06x | -| oxfmt | 0.30 | 5 | 3355.47 | 3380.46 | 3387.86 | — | — | 3336.32 | 3392.79 | 0.94x | -| biome-wasm | 1.53 | 8 | 651.35 | 652.78 | 655.60 | — | — | 646.29 | 658.53 | 4.84x | - -**Files (intersection):** 1194 - -**Throughput:** prettier 0.5 MB/s, tsv 6.1 MB/s, tsv_wasm 4.5 MB/s, oxfmt 0.5 MB/s, biome-wasm 2.4 MB/s - -**Coverage:** prettier 1201/1240 (96%), tsv 1202/1240 (96%), tsv_wasm 1202/1240 (96%), oxfmt 1201/1240 (96%), biome-wasm 1238/1240 (99%) - -## parse/typescript - -| Task Name | ops/sec | n | p50 (ms) | p75 (ms) | p90 (ms) | p95 (ms) | p99 (ms) | min (ms) | max (ms) | vs acorn-typescript (speedup) | -| ----------------- | ------- | -- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | ----------------------------- | -| acorn-typescript | 0.45 | 5 | 2212.10 | 2213.41 | 2218.80 | — | — | 2209.49 | 2222.40 | baseline | -| tsv-json | 0.49 | 5 | 2046.28 | 2052.48 | 2062.33 | — | — | 2036.38 | 2068.89 | 1.08x | -| tsv_wasm-json | 0.45 | 5 | 2223.81 | 2224.51 | 2224.64 | — | — | 2222.33 | 2224.73 | 1.00x | -| tsv-internal | 4.23 | 16 | 235.99 | 239.29 | 262.67 | 263.12 | 263.95 | 234.97 | 264.16 | 9.37x | -| tsv_wasm-internal | 3.42 | 16 | 292.65 | 292.77 | 293.67 | 294.71 | 294.96 | 292.27 | 295.03 | 7.56x | -| oxc-parser | 1.16 | 6 | 863.97 | 878.83 | 884.91 | — | — | 845.08 | 890.88 | 2.56x | -| oxc-parser-wasm | 1.02 | 6 | 975.59 | 979.11 | 982.23 | — | — | 971.97 | 984.50 | 2.27x | - -**Files (intersection):** 3603 - -**Throughput:** acorn-typescript 5.8 MB/s, tsv-json 6.3 MB/s, tsv_wasm-json 5.8 MB/s, tsv-internal 54.8 MB/s, tsv_wasm-internal 44.2 MB/s, oxc-parser 15.0 MB/s, oxc-parser-wasm 13.3 MB/s - -**Coverage:** acorn-typescript 3693/4025 (91%), tsv-json 3743/4025 (92%), tsv_wasm-json 3743/4025 (92%), tsv-internal 3743/4025 (92%), tsv_wasm-internal 3743/4025 (92%), oxc-parser 3833/4025 (95%), oxc-parser-wasm 4025/4025 (100%) - -**JSON overhead** (json_ns / internal_ns, higher = more cost): tsv-json 8.7x tsv-internal, tsv_wasm-json 7.6x tsv_wasm-internal - -## format/typescript - -| Task Name | ops/sec | n | p50 (s) | p75 (s) | p90 (s) | p95 (s) | p99 (s) | min (s) | max (s) | vs prettier (speedup) | -| ---------- | ------- | - | ------- | ------- | ------- | ------- | ------- | ------- | ------- | --------------------- | -| prettier | 0.11 | 6 | 8.78 | 8.81 | 8.90 | — | — | 8.71 | 9.02 | baseline | -| tsv | 1.17 | 6 | 0.86 | 0.86 | 0.86 | — | — | 0.84 | 0.86 | 10.3x | -| tsv_wasm | 0.87 | 5 | 1.14 | 1.15 | 1.15 | — | — | 1.14 | 1.15 | 7.66x | -| oxfmt | 1.25 | 7 | 0.80 | 0.81 | 0.81 | — | — | 0.79 | 0.81 | 10.9x | -| biome-wasm | 0.27 | 4 | 3.65 | 3.65 | 3.65 | — | — | 3.65 | 3.66 | 2.40x | - -**Files (intersection):** 3701 - -**Throughput:** prettier 1.5 MB/s, tsv 15.2 MB/s, tsv_wasm 11.3 MB/s, oxfmt 16.2 MB/s, biome-wasm 3.6 MB/s - -**Coverage:** prettier 3855/4025 (95%), tsv 3743/4025 (92%), tsv_wasm 3743/4025 (92%), oxfmt 3836/4025 (95%), biome-wasm 4025/4025 (100%) - -## parse/css - -| Task Name | ops/sec | n | p50 (ms) | p75 (ms) | p90 (ms) | p95 (ms) | p99 (ms) | min (ms) | max (ms) | vs svelte/compiler (speedup) | -| ----------------- | ------- | --- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | ---------------------------- | -| svelte/compiler | 51.54 | 258 | 19.38 | 19.52 | 19.63 | 19.75 | 19.84 | 19.08 | 19.89 | baseline | -| tsv-json | 5.65 | 29 | 176.42 | 178.45 | 179.34 | 179.41 | 179.87 | 173.85 | 180.03 | 0.11x | -| tsv_wasm-json | 4.48 | 18 | 222.99 | 224.04 | 226.00 | 226.36 | 226.69 | 222.56 | 226.78 | 0.09x | -| tsv-internal | 43.25 | 190 | 23.08 | 23.58 | 25.29 | 26.40 | 34.46 | 22.53 | 43.86 | 0.84x | -| tsv_wasm-internal | 31.18 | 133 | 32.07 | 32.15 | 32.34 | 32.35 | 32.38 | 31.98 | 32.57 | 0.60x | - -**Files (intersection):** 159 - -**Throughput:** svelte/compiler 35.2 MB/s, tsv-json 3.9 MB/s, tsv_wasm-json 3.1 MB/s, tsv-internal 29.5 MB/s, tsv_wasm-internal 21.3 MB/s - -**Coverage:** svelte/compiler 163/193 (84%), tsv-json 165/193 (85%), tsv_wasm-json 165/193 (85%), tsv-internal 165/193 (85%), tsv_wasm-internal 165/193 (85%) - -**JSON overhead** (json_ns / internal_ns, higher = more cost): tsv-json 7.6x tsv-internal, tsv_wasm-json 7.0x tsv_wasm-internal - -## format/css - -| Task Name | ops/sec | n | p50 (ms) | p75 (ms) | p90 (ms) | p95 (ms) | p99 (ms) | min (ms) | max (ms) | vs prettier (speedup) | -| ---------- | ------- | --- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | --------------------- | -| prettier | 1.37 | 7 | 726.87 | 737.41 | 739.49 | — | — | 723.87 | 742.33 | baseline | -| tsv | 23.65 | 113 | 42.36 | 42.80 | 43.54 | 44.63 | 50.02 | 40.69 | 51.29 | 17.3x | -| tsv_wasm | 17.59 | 69 | 56.84 | 57.05 | 57.28 | 57.41 | 57.61 | 56.70 | 57.94 | 12.9x | -| oxfmt | 1.32 | 6 | 758.50 | 764.36 | 792.12 | — | — | 755.83 | 828.62 | 0.96x | -| biome-wasm | 4.82 | 24 | 207.16 | 208.26 | 208.75 | 209.40 | 209.80 | 205.89 | 209.89 | 3.53x | - -**Files (intersection):** 165 - -**Throughput:** prettier 0.9 MB/s, tsv 16.4 MB/s, tsv_wasm 12.2 MB/s, oxfmt 0.9 MB/s, biome-wasm 3.3 MB/s - -**Coverage:** prettier 192/193 (99%), tsv 165/193 (85%), tsv_wasm 165/193 (85%), oxfmt 192/193 (99%), biome-wasm 193/193 (100%) - -_Note: every `Nx` is speedup form — values > 1 mean self is faster. File counts come from the per-group `Files (intersection):` / `Coverage:` lines and the Comparisons table row labels._ - -## Binary Sizes - -| Binary | Size | Gzipped | vs tsv | vs tsv (gz) | -| ------------------------- | ------: | -------: | -----: | ----------: | -| tsv_format_wasm | 2.2 MB | 715.4 KB | 0.8x | 0.8x | -| tsv_parse_wasm | 1.7 MB | 526.6 KB | 0.6x | 0.6x | -| tsv_wasm | 2.9 MB | 911.3 KB | — | — | -| biome (wasm) | 34.4 MB | 8.2 MB | 11.9x | 9.0x | -| oxc-parser (wasm) | 1.9 MB | 518.7 KB | 0.6x | 0.6x | -| tsv (native) | 3.9 MB | 1.6 MB | — | — | -| oxc-parser+oxfmt (native) | 10.7 MB | 4.3 MB | 2.8x | 2.6x | -| oxc-parser (native) | 2.7 MB | 1.0 MB | 0.7x | 0.6x | -| oxfmt (native) | 8.0 MB | 3.2 MB | 2.1x | 2.0x | - -_Gzipped ≈ npm-tarball wire size (`gzip -c`, system default level). `vs tsv (gz)` compares gzipped bytes; `vs tsv` compares raw on-disk bytes._ - -## Comparisons to tsv (speedup) - -| Benchmark | Comparisons | -| ------------------------- | -------------------------------------- | -| format svelte (1194f) | **12.4x** prettier, **13.3x** oxfmt | -| format typescript (3701f) | **10.3x** prettier, **0.94x** oxfmt | -| format css (165f) | **17.3x** prettier, **18.0x** oxfmt | -| parse svelte (1192f) | **0.73x** svelte | -| parse typescript (3603f) | **1.08x** svelte, **0.42x** oxc-parser | -| parse css (159f) | **0.11x** svelte | - -## Comparisons to tsv_wasm (speedup) - -| Benchmark | Comparisons | -| ------------------------- | ------------------------------------------- | -| format svelte (1194f) | **9.06x** prettier, **1.87x** biome-wasm | -| format typescript (3701f) | **7.66x** prettier, **3.19x** biome-wasm | -| format css (165f) | **12.9x** prettier, **3.65x** biome-wasm | -| parse svelte (1192f) | **0.69x** svelte | -| parse typescript (3603f) | **1.00x** svelte, **0.44x** oxc-parser-wasm | -| parse css (159f) | **0.09x** svelte | - -_`Nx` is speedup — self is N× faster than the named opponent. `(Mf)` is the self impl's iterated count (per-group intersection in default mode; per-impl success set in `BENCH_MODE=union`). Parse canonical: svelte/compiler for .svelte/.css, acorn-typescript for .ts. oxc-parser (native and wasm) serializes the AST to JSON in Rust and deserializes it in JS — the same eager materialization as tsv-json/tsv_wasm-json, so these parse rows are apples-to-apples. tsv-internal/tsv_wasm-internal are parse-only (no JS materialization) and have no oxc counterpart — oxc exposes no comparably cheap mode (its JS API always serializes; experimentalLazy is setup-dominated). Format groups include parse time — each formatter parses internally._ - -## Skipped Files - -1390 unique file+error combinations — Svelte 165, TypeScript 1165, CSS 60. - -**Per-benchmark skip counts:** - -- parse/typescript: acorn-typescript: 332 -- parse/typescript: tsv-json: 282 -- parse/typescript: tsv_wasm-json: 282 -- parse/typescript: tsv-internal: 282 -- parse/typescript: tsv_wasm-internal: 282 -- format/typescript: tsv: 282 -- format/typescript: tsv_wasm: 282 -- parse/typescript: oxc-parser: 192 -- format/typescript: oxfmt: 189 -- format/typescript: prettier: 170 -- parse/svelte: svelte/compiler: 47 -- format/svelte: prettier: 39 -- format/svelte: oxfmt: 39 -- parse/svelte: tsv-json: 38 -- parse/svelte: tsv_wasm-json: 38 -- parse/svelte: tsv-internal: 38 -- parse/svelte: tsv_wasm-internal: 38 -- format/svelte: tsv: 38 -- format/svelte: tsv_wasm: 38 -- parse/css: svelte/compiler: 30 -- parse/css: tsv-json: 28 -- parse/css: tsv_wasm-json: 28 -- parse/css: tsv-internal: 28 -- parse/css: tsv_wasm-internal: 28 -- format/css: tsv: 28 -- format/css: tsv_wasm: 28 -- format/svelte: biome-wasm: 2 -- format/css: prettier: 1 -- format/css: oxfmt: 1 - -_Per-file detail omitted. Re-run with `--verbose` to include error messages and failure sets per file._ diff --git a/benches/deno/CLAUDE.md b/benches/js/CLAUDE.md similarity index 71% rename from benches/deno/CLAUDE.md rename to benches/js/CLAUDE.md index 76732fd43..28f486fe9 100644 --- a/benches/deno/CLAUDE.md +++ b/benches/js/CLAUDE.md @@ -4,6 +4,74 @@ Uses [@fuzdev/fuz_util](https://github.com/fuzdev/fuz_util) benchmarking library for statistical analysis. +> **Directory note:** this is the **runtime-neutral** JS benchmark harness — +> named `js` (not `deno`) because the same code runs under Deno, Node, and Bun +> (see [Cross-Runtime](#cross-runtime-deno--node--bun)). The `corpus_compare_*` +> and `diagnostics/` entries stay Deno-idiomatic; `smoke` is portable across all +> three (`smoke` / `smoke:node` / `smoke:bun`). + +## Cross-Runtime (Deno + Node + Bun) + +The bench runs under **Deno, Node, and Bun** from one shared codebase. +The motivation: a single-runtime bench can silently fold a runtime-specific effect +into an engine number — the concrete case being the Deno-FFI fast-call memory +sensitivity that mismeasured the native path (see §Known Issues + the lore +`TODO_NODE_BENCHMARKS.md`). A per-runtime delta on the same row is the detector. + +**Design (well-factored, not forked):** + +- **Runtime-labeled sibling reports.** Each runtime writes its own + `results/report..{json,md}` (+ a timestamped `…_..*` + pair), same schema, never merged. Every row carries a `runtime` field; the JSON + has a top-level `runtime` and `version: 5`. `deno task bench:compose` (run at + the end of `deno task bench`) then folds the siblings into a compact combined + `results/report.{json,md}` — the cross-runtime view tsv.fuz.dev consumes + (`compose_reports.ts`; a per-runtime delta on a row is the headline). +- **One bench body, runtime-detected.** `bench.ts` runs under both — it detects + the runtime (`lib/runtime.ts` `current_runtime()`) and selects the + runtime-specific artifacts. No forked entry; `bench:node:run` is literally + `node benches/js/bench.ts`. +- **Portable shared modules.** The shared/entry modules use `node:` builtins + (Deno supports them) + `@fuzdev/fuz_util` helpers (`fs_search`, `fs_exists`, + `spawn_out`, `to_file_path`) — **no `Deno.*`, no `@std/*`**. The only genuinely + runtime-specific files are the native loader (`ffi.ts` `Deno.dlopen` vs + `napi.ts` `process.dlopen`) and the WASM target the loader picks. The + Deno-only entry points (`corpus_compare_*`, `diagnostics/*`) stay + Deno-idiomatic (`Deno.*` + `node:` builtins, no `@std/*`). The `deno test` + suite is the dependency-free divergence detectors (`node:assert` + relative + imports — see §Divergence Detection). +- **The native row differs by runtime, fairly.** Deno → FFI (`tsv_ffi`, via + `Deno.dlopen`); Node → N-API (`tsv_napi`, via `process.dlopen`). Same engine, + same per-thread arena reuse, different binding boundary. +- **The WASM row uses each runtime's own wasm-pack target bundle** (same + `tsv_wasm_bg.wasm`, different JS glue) — Deno the `deno` target, Node the + `nodejs` target — both with the full export set incl. `parse_internal_*`. The + shipped web bundle is deliberately not used (it curates `parse_internal_*` out). + +**Dependencies: `package.json` is the source of truth.** Both runtimes consume one +`node_modules` (`benches/js/package.json`). Deno reads it via +`"nodeModulesDir": "manual"` in `deno.json`; Node reads it directly. There are no +jsr or remote deps — the bench and the diagnostics import npm packages by bare +specifier (resolved from `package.json`) and otherwise use `node:` builtins, so +`deno.json` carries only `nodeModulesDir: manual` + `lock: false` (no `deno.lock`; +npm integrity is `package-lock.json`'s job). `@types/node` is a types-only +devDependency so the `node:` builtins type-check under `deno check`. + +**Install with `deno task bench:install`** (runs `benches/js/install_deps.ts`). +It is the canonical installer: a plain `npm install` works but **prunes the +`@oxc-parser/binding-wasm32-wasi` binding** (the oxc-parser-wasm row) — that +binding is pure-wasm but its metadata declares `cpu: wasm32`, so npm skips it on +any non-wasm host and reconciles away a `--no-save` add. `install_deps.ts` runs +`npm install` then force-fetches it at the `oxc-parser` version (oxc ships all +bindings in lockstep). After a bump or a stray `npm install`, re-run +`bench:install`. + +**oxc-parser-wasm runs under all three.** Its binding ships two entries — a +fetch-based browser entry (`parser.wasi-browser.js`) that Deno needs, and the +default `node:wasi` entry that Node/Bun need — so `oxc_wasm.ts` picks the right +one per runtime (`current_runtime()`). (Node also has oxc-parser **native**, the +more relevant Node number, regardless.) + ## Corpus Comparison Compare formatting output against Prettier on arbitrary codebases: @@ -186,15 +254,21 @@ Patterns are ordered specific to broad. Each links to `conformance_sections` and deno task divergence:audit # Human-readable report deno task divergence:audit --json # Machine-readable JSON -# Deno test suite — every *_test.ts under lib/, gated by `deno task check`. Covers -# the divergence detectors (pattern positive/negative overmatch-rejection cases, +# Deno test suite — the divergence detectors under lib/divergence/, gated by +# `deno task check`. Covers pattern positive/negative overmatch-rejection cases, # safety differential cases, and a behavioral fixture-coverage audit that drives # each detector against its own committed fixtures — input == ours, output_prettier -# == prettier — failing if a pattern stops claiming a hunk in a fixture it lists) -# plus canonical_test.ts (asserts the prettier baseline formats with a filepath, so -# `.ts` single-type-param arrows stay `` and `.svelte` ones get ``). +# == prettier — failing if a pattern stops claiming a hunk in a fixture it lists. +# These are dependency-free (`node:assert` + relative imports, no node_modules), so +# CI runs them on a clean checkout with no `bench:install` — that's why they're in +# the core `check` gate. deno task test:deno +# The canonical-oracle test (NOT gated — it needs prettier/svelte, so run after +# `bench:install`): asserts the prettier baseline formats with a filepath, so `.ts` +# single-type-param arrows stay `` and `.svelte` ones get ``. +deno task test:deno:canonical + # Per-pattern corpus coverage with sample diffs (spot-check for overmatching) deno task corpus:compare:format --all --audit-patterns ``` @@ -230,66 +304,82 @@ Every pattern in `patterns.ts` includes: ## Benchmark Commands -Results are saved to `benches/deno/results/` as timestamped files plus -`report.json` and `report.md` (committed to git). To publish benchmarks -to tsv.fuz.dev, run `npm run update-benchmarks` in ~/dev/tsv.fuz.dev. - -The committed `report.json` (baseline `version: 4`) carries, beyond timing -stats: per-language `corpus` totals, `versions`, and `binary_sizes` (each with -`gzip_bytes`). Each `entries[]` row adds `files_processed`/`files_total` -(per-impl preflight coverage — the `Coverage:` line) and `files_iterated` (the -timed set — the `Files (intersection):` count). A top-level `suppressed_noise` -map records silenced third-party stderr crashes as `{pattern: count}`. -`report.md` renders coverage/iterated as prose; the per-entry numbers and -`suppressed_noise` are JSON-only. +Each runtime saves to `benches/js/results/` as timestamped files plus a +committed `report..{json,md}` pair (`report.deno.*` / `report.node.*`). +To publish benchmarks to tsv.fuz.dev, run `npm run update-benchmarks` in +~/dev/tsv.fuz.dev (it reads the per-runtime files — see the cross-repo note in +the lore when renaming from the old single `report.json`). + +The committed `report..json` (baseline `version: 5`) carries, beyond +timing stats: a top-level `runtime`, per-language `corpus` totals, `versions`, +and `binary_sizes` (each with `gzip_bytes`). Each `entries[]` row adds a +`runtime` field, `files_processed`/`files_total` (per-impl preflight coverage — +the `Coverage:` line) and `files_iterated` (the timed set — the `Files +(intersection):` count). A top-level `suppressed_noise` map records silenced +third-party stderr crashes as `{pattern: count}`. `report..md` renders +coverage/iterated as prose; the per-entry numbers and `suppressed_noise` are +JSON-only. ```bash -# Run benchmarks (builds the bench artifact set — `build:bench` — automatically) -deno task bench +deno task bench:install # one-time: install harness npm deps (see Cross-Runtime above) + +# Run benchmarks (builds the runtime's bench artifacts automatically). +# `bench` runs all three and FAILS FAST if node or bun isn't installed (the `&&` +# chain stops at the missing binary). Deno is the only hard dependency, so if you +# don't have node and/or bun, run the per-runtime tasks you DO have — each writes +# its own report..* sibling, and `bench:compose` folds whatever exists. +deno task bench # ALL three + compose (needs node AND bun installed) +deno task bench:deno # Deno only (no node/bun needed) +deno task bench:node # Node only (needs node) +deno task bench:bun # Bun only (needs bun; reuses the Node artifacts — N-API + nodejs-target WASM) +deno task bench:compose # Fold whatever report.{deno,node,bun}.json exist → combined report.{json,md} # Run without rebuilding (if already built) — guarded against stale artifacts, # see "Artifact Freshness Guard" below -deno task bench:run - -# Output formats -deno task bench:run -- --json # Output as JSON (for CI/tooling) -deno task bench:run -- --markdown # Output as Markdown tables -deno task bench:run -- --verbose # Include per-file skip detail (paths + errors) -deno task bench:run -- --save-report # Force-overwrite the committed results/report.{json,md} - # on a limited/filtered run (full runs overwrite it anyway; - # the timestamped results/_.{json,md} pair is always written) +deno task bench:deno:run +deno task bench:node:run +deno task bench:bun:run + +# Output formats / flags (shown for :deno:run; same for :node:run) +deno task bench:deno:run -- --json # Output as JSON (for CI/tooling) +deno task bench:deno:run -- --markdown # Output as Markdown tables +deno task bench:deno:run -- --verbose # Include per-file skip detail (paths + errors) +deno task bench:deno:run -- --save-report # Force-overwrite the committed report..{json,md} + # on a limited/filtered run (full runs overwrite it anyway; + # the timestamped results/_..* pair is always written) # Baseline regression detection -deno task bench:run -- --save-baseline # Save current results as baseline -deno task bench:run -- --compare-baseline # Compare against saved baseline +deno task bench:deno:run -- --save-baseline # Save current results as baseline +deno task bench:deno:run -- --compare-baseline # Compare against saved baseline # Wipe local-only bench state (gitignored): baseline.json + timestamped -# results pairs. Preserves the committed `results/report.{json,md}` because +# results pairs. Preserves the committed `report..{json,md}` because # the glob is anchored on a leading digit (timestamped files start with a year). deno task bench:clean -# Environment variables -BENCH_LIMIT=5 deno task bench:run # Limit files per language (default: all) -BENCH_FILTER=zzz deno task bench:run # Filter by path pattern (default: none) -BENCH_DURATION=10000 deno task bench:run # Duration per benchmark in ms (default: 5000) -BENCH_WARMUP=10 deno task bench:run # Set warmup iterations (default: 3) -BENCH_MODE=union deno task bench:run # Per-impl iteration (default: intersection) -BENCH_STALE_OK=1 deno task bench:run # Override the freshness guard (see below; default: off) -BENCH_FORCED_ASYNC=1 deno task bench:run # Add the tsv-forced-async control row (diagnostic; default: off) +# Environment variables (apply to any runtime's :run) +BENCH_LIMIT=5 deno task bench:deno:run +BENCH_FILTER=zzz deno task bench:deno:run +BENCH_DURATION=10000 deno task bench:deno:run +BENCH_WARMUP=10 deno task bench:deno:run +BENCH_MODE=union deno task bench:deno:run +BENCH_STALE_OK=1 deno task bench:deno:run +BENCH_FORCED_ASYNC=1 deno task bench:deno:run ``` ## Artifact Freshness Guard -The rebuild-skipping tasks (`bench:run`, `corpus:compare:format:run`, and -`smoke`) skip the rebuild so you can iterate on the harness without paying the -wasm-pack cost — at the risk of silently measuring a binary older than current -source (a CSS run once reported `146/183` against a stale `.so` that should have -been `155/183`). `lib/check_artifact_freshness.ts` guards against this: before a -run touches the executed artifacts (the profile-aware FFI library + the -`pkg/all/deno` WASM bundle), it compares their mtimes against the crate sources -feeding them and **aborts (exit 1)** if any is stale, or missing. The build-first -tasks (`bench`, `corpus:compare:format`) rebuild first, so they pass the guard -for free. +The rebuild-skipping tasks (`bench:deno:run` / `bench:node:run`, +`corpus:compare:format:run`, and `smoke`) skip the rebuild so you can iterate on +the harness without paying the wasm-pack cost — at the risk of silently measuring +a binary older than current source (a CSS run once reported `146/183` against a +stale `.so` that should have been `155/183`). `lib/check_artifact_freshness.ts` +guards against this: before a run touches the executed artifacts (the runtime's +native binding + WASM bundle — Deno: FFI + `pkg/all/deno`; Node: N-API + +`pkg/all/nodejs`), it compares their mtimes against the crate sources feeding them +and **aborts (exit 1)** if any is stale, or missing. The build-first tasks +(`bench`, `bench:deno`, `bench:node`, `corpus:compare:format`) rebuild first, so +they pass the guard for free. **Escape hatch:** `BENCH_STALE_OK=1` downgrades a _stale_ artifact to a `⚠` warning and proceeds (a _missing_ one stays fatal). See the module doc for the @@ -297,9 +387,9 @@ full rationale (e.g. why stale is a hard error, not a warning). ```bash # After editing a crate, the fast/correct paths: -deno task bench # rebuilds, then runs — always fresh -deno task build:ffi && deno task bench:run # rebuild just what you changed, then :run -BENCH_STALE_OK=1 deno task bench:run # deliberately measure the current (stale) binary +deno task bench:deno # rebuilds, then runs — always fresh +deno task build:ffi && deno task bench:deno:run # rebuild just what you changed, then :run +BENCH_STALE_OK=1 deno task bench:deno:run # deliberately measure the current (stale) binary ``` ## Smoke Test @@ -308,9 +398,12 @@ BENCH_STALE_OK=1 deno task bench:run # deliberately measure the current (stal (trivial fixed inputs, non-throwing + non-empty + idempotent). Exits non-zero on any failure. Use it to catch "implementation totally broken" before running the full bench. `corpus_compare_format` is still the real correctness gate. +It is runtime-neutral like the bench: `smoke` (Deno), `smoke:node`, and +`smoke:bun` each load that runtime's own native + WASM artifacts, so an +impl-load break is caught per runtime (it's how the Bun biome-load issue surfaced). Like the bench/corpus `:run` tasks, `smoke` skips the rebuild for speed and is -guarded by the freshness check above — it aborts on a stale or missing FFI/WASM +guarded by the freshness check above — it aborts on a stale or missing native/WASM artifact (rebuild with `deno task build:bench`, or `BENCH_STALE_OK=1` to override). It is **not** a build-first task. @@ -386,8 +479,8 @@ Things the published numbers measure that aren't quite what they look like: layer) or `@fuzdev/tsv_parse_wasm` (~1.7 MB, no printers). The Binary Sizes table lists all three; the throughput rows reflect the full build. The native `tsv` row is the same story: the perf row loads the full - `libtsv_ffi`, while the Binary Sizes table also lists `tsv format (native)` - and `tsv parse (native)` subset builds (no perf rows of their own — they + `libtsv_ffi`, while the Binary Sizes table also lists `tsv format (ffi)` + and `tsv parse (ffi)` subset builds (no perf rows of their own — they exist only to size scope-matched against `oxfmt` and `oxc-parser`). - **Intersection-corpus iteration (default)** — within each group, every impl is timed on the same all-N intersection: the set of files every impl @@ -396,7 +489,7 @@ Things the published numbers measure that aren't quite what they look like: as "A is N× faster than B on the files they both handle"). Trade-off: one noisy impl shrinks the corpus for the whole group — e.g. if `biome-wasm` skips 60% of CSS files, `tsv`/`prettier`/`oxfmt` are timed on only the - remaining 40%. The Coverage section in `report.md` still discloses each + remaining 40%. The Coverage section in `report..md` still discloses each impl's preflight skip rate, so the asymmetry is visible to the reader even though the timed numbers normalize over it. `Throughput` and the `(Mf)` annotation in every table reflect the iterated set, not the full @@ -426,7 +519,7 @@ Things the published numbers measure that aren't quite what they look like: - Default off because the published ratios should reflect what users see in real code (opportunistic GC). Enable via `BENCH_GC=1` if you want the stability of forced GC for a noisy high-allocation workload. - - A `report.md` generated with the hook on has a narrower + - A `report..md` generated with the hook on has a narrower internal-vs-JSON-materializing-parser spread than a default (hook-off) run, so don't diff numbers across the two configurations line-for-line. - **`-json` parse rows are apples-to-apples; the `oxc-parser` "lazy" story @@ -492,12 +585,17 @@ and `skip` overrides. Non-existent paths are silently skipped. ## Architecture ``` -benches/deno/ -├── bench.ts # Benchmark entry point -├── smoke.ts # Smoke test for formatters and parsers -├── corpus_compare_format.ts # Formatting comparison vs prettier (entry point) -├── corpus_compare_parse.ts # Parse/AST comparison vs canonical parsers (entry point) -├── divergence_audit.ts # Divergence audit entry point +benches/js/ +├── package.json # npm dep source of truth (both runtimes); install_deps drives it +├── package-lock.json # npm lock (committed for reproducibility) +├── deno.json # nodeModulesDir: manual + lock: false (npm from package.json; no jsr/remote deps) +├── install_deps.ts # `bench:install`: npm install + force-fetch the oxc wasi binding +├── bench.ts # Benchmark entry point (runtime-neutral — runs under Deno AND Node) +├── smoke.ts # Smoke test for formatters and parsers (runtime-neutral: smoke / smoke:node / smoke:bun) +├── compose_reports.ts # Fold report.{deno,node,bun}.json → combined report.{json,md} (bench:compose) +├── corpus_compare_format.ts # Formatting comparison vs prettier (Deno-only entry point) +├── corpus_compare_parse.ts # Parse/AST comparison vs canonical parsers (Deno-only entry point) +├── divergence_audit.ts # Divergence audit entry point (Deno-only) ├── diagnostics/ # ad-hoc diagnostic scripts (not wired into `deno task` — see §Diagnostic scripts) │ ├── skip_triage.ts # parse-gap triage (tsv vs canonical) │ ├── test262_compare.ts # test262 differential (tsv vs oxc-parser, from the Rust manifest) @@ -511,16 +609,18 @@ benches/deno/ │ ├── biome.ts # Biome WASM wrapper (Svelte, TypeScript, CSS) │ ├── canonical.ts # Prettier + Svelte parser wrappers │ ├── compare_cli.ts # Shared scaffolding for the corpus_compare_* entry points -│ ├── corpus.ts # DevReposLoader + DirectoryLoader (load/stream) +│ ├── corpus.ts # DevReposLoader + DirectoryLoader (load/stream; node: builtins) │ ├── diff.ts # Line-based diff utilities (LCS algorithm) -│ ├── ffi.ts # Deno.dlopen bindings (NativeImplementation) -│ ├── implementations.ts # Implementation registry and task generation +│ ├── ffi.ts # Deno.dlopen bindings (NativeImplementation — Deno native, runtime-specific) +│ ├── napi.ts # process.dlopen bindings (NapiImplementation — Node/Bun native, runtime-specific) +│ ├── runtime.ts # Tiny cross-runtime helpers: current_runtime / os / arch normalizers +│ ├── implementations.ts # Implementation registry (branches native FFI vs N-API by runtime) │ ├── oxc.ts # OXC native wrappers (oxc-parser + oxfmt) -│ ├── oxc_wasm.ts # OXC WASM wrapper (oxc-parser via wasm32-wasi) +│ ├── oxc_wasm.ts # OXC WASM wrapper (oxc-parser via wasm32-wasi; per-runtime wasi entry) │ ├── report.ts # Summary report generation │ ├── types.ts # Shared type definitions -│ ├── versions.ts # Version loading from deno.json -│ ├── wasm.ts # WASM module loader (WasmImplementation) +│ ├── versions.ts # Version loading from package.json +│ ├── wasm.ts # WASM module loader (WasmImplementation — deno/nodejs target by runtime) │ └── divergence/ # Divergence detection module │ ├── mod.ts # Main exports │ ├── safety.ts # Safety check (differential char-frequency vs prettier) @@ -531,38 +631,42 @@ benches/deno/ ## Implementations -Versions read automatically from `deno.json` import map at runtime. +Versions read automatically from `package.json` `dependencies` at runtime +(`lib/versions.ts`). ### Updating dependencies -**How resolution works on any machine.** The `benches/deno/deno.json` import -map pins exact versions and `benches/deno/deno.lock` pins their integrity -hashes. `deno task bench` (and `smoke`, `corpus:compare:format`, `test:deno`) fetch -**exactly** those versions from npm/jsr on first run and cache them — there is -no `npm install`, no `node_modules`, and no auto-upgrade. A fresh checkout on -another machine reproduces the pinned set byte-for-byte; it never pulls newer -releases on its own. The Rust artifacts the bench builds (`tsv_ffi`, -`tsv_wasm`) are pinned the same way via `Cargo.lock`. Upgrading is always a -deliberate, committed act. +**How resolution works on any machine.** `benches/js/package.json` pins the npm +dep versions (the single source of truth, consumed by both runtimes) and +`package-lock.json` pins their integrity. **Run `deno task bench:install`** to +populate `node_modules` (one installer — `npm install` — plus the force-fetch of +the oxc wasi binding; see [Cross-Runtime](#cross-runtime-deno--node--bun)). Deno reads +that `node_modules` via `"nodeModulesDir": "manual"`; Node reads it directly (the +config shape — no jsr/remote deps, no `deno.lock` — is covered above). +The Rust artifacts the bench builds (`tsv_ffi`, `tsv_napi`, `tsv_wasm`) are pinned +via `Cargo.lock`. Upgrading is always a deliberate, committed act. A plain +`npm install` prunes the oxc wasi binding — re-run `bench:install`. **Routine refresh** (alternative impls + infra — no fixture impact): ```bash -deno outdated # run in benches/deno/ — shows current vs latest -deno update --latest oxc-parser oxfmt @biomejs/js-api @biomejs/wasm-bundler @fuzdev/fuz_util zod @std/fs -deno task smoke # confirm every impl still loads + formats (32 checks) -deno task bench # regenerate results/report.{json,md} -# commit deno.json + deno.lock + results/report.* +cd benches/js && npm outdated # shows current vs latest +# bump the version in benches/js/package.json, then: +deno task bench:install # re-install at the new pins (+ re-fetch the oxc wasi binding) +deno task smoke # confirm every impl still loads + formats (32 checks) +deno task bench # regenerate report.{deno,node,bun}.* + combined report.{json,md} +# commit package.json + package-lock.json + results/report.* ``` These packages are free to bump independently — they're measured against, not baked into fixtures. -⚠ **The oxc wasm binding has a subpath import entry** -(`@oxc-parser/binding-wasm32-wasi/.../parser.wasi-browser.js`) that -`deno update` does **not** bump — set it by hand to match `oxc-parser`'s -version and re-run `deno install`. `binary_sizes.ts` keys the wasm size off the -oxc version, so a mismatch silently drops the WASM size from the report. +⚠ **The oxc wasm binding is not a regular dep.** It's pure-wasm but its metadata +declares `cpu: wasm32`, so it lives in neither `dependencies` nor +`optionalDependencies` (both break or get pruned). `install_deps.ts` force-fetches +it at the `oxc-parser` version (oxc ships all bindings in lockstep) — so bumping +`oxc-parser` in `package.json` automatically carries it. `binary_sizes.ts` reads +it from `node_modules` (flat, no version dir). **Canonical baseline is coupled — do NOT bump it as routine.** The five canonical packages (`prettier`, `svelte`, `acorn`, `@sveltejs/acorn-typescript`, @@ -572,7 +676,8 @@ fixture's `expected.json` and `output_prettier.svelte`. The two pin sets **must stay identical**: the bench has to measure against the same parser/formatter that defines fixture correctness. Bumping any of the five is therefore not a benchmark refresh — it re-baselines the entire fixture corpus. Do it -deliberately: edit `deno.json` and `sidecar.ts` in lockstep, run +deliberately: edit `package.json` and `sidecar.ts` in lockstep (the +`//canonical-sync` note in package.json restates this), run `deno task fixtures:update`, and review the resulting fixture churn. ### Canonical (JS baseline) @@ -595,11 +700,14 @@ corpus divergences against `@ryanatkn` code that tsv was formatting correctly. - oxc-parser (NAPI) — Fast TypeScript parser; languages: TypeScript, JS - oxfmt (NAPI) — Fast formatter; languages: TypeScript, JS, CSS, Svelte (experimental) -- biome (WASM) — Formatter/linter; languages: Svelte, TypeScript, JS, CSS +- biome (WASM) — Formatter/linter; languages: TypeScript, JS, CSS, and Svelte + (Svelte via biome's experimental HTML-superset support — `html.experimentalFullSupportEnabled`; + it formats the template **and** the embedded `