Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
198 commits
Select commit Hold shift + click to select a range
07f53b2
docs: permit agent commits on the svelte-compiler branch
ryanatkn Jul 12, 2026
2c7185b
feat: add svelte-compile oracle sidecar tool + canonical_compile command
ryanatkn Jul 12, 2026
8665173
docs: document canonical_compile in Debug Tooling
ryanatkn Jul 12, 2026
82544c2
feat: add tsv_ts format_canonical intent-erased reprint entry point
ryanatkn Jul 12, 2026
20a743b
feat: mint tsv_svelte_compile crate with compile skeleton and JS cano…
ryanatkn Jul 12, 2026
0a6f744
feat: add compile_compare debug command and canonicalize idempotence …
ryanatkn Jul 12, 2026
cdba066
docs: document compile_compare command and tsv_svelte_compile crate
ryanatkn Jul 12, 2026
2e3c572
fix: keep comment-adjacency newline reads real in canonical mode
ryanatkn Jul 12, 2026
ebbe5bd
feat: add compile fixture tree with init/validate commands and seed f…
ryanatkn Jul 12, 2026
f429933
feat: gate canonicalize_audit and compile_conformance_audit in check
ryanatkn Jul 12, 2026
4fde5b4
docs: document compile fixture and canonicalize audit tooling
ryanatkn Jul 12, 2026
0446c4b
chore: strip milestone labels, fix audit doc scope, add mjs/cjs, supp…
ryanatkn Jul 12, 2026
2d2a5aa
feat: server codegen for static markup, props, and scoped css via app…
ryanatkn Jul 12, 2026
174fce2
docs: describe server codegen, flip compile fixture gates to parity
ryanatkn Jul 12, 2026
b00a301
fix: rune refusal walk, oracle whitespace/entity/void emission, scrip…
ryanatkn Jul 12, 2026
5d72265
fix: refuse option elements, populated select/optgroup, and bare rune…
ryanatkn Jul 12, 2026
81b4c05
feat: rune SSR rewrites, evaluator fold port, dynamic attributes, htm…
ryanatkn Jul 12, 2026
a1ba17e
test: add rune, attribute, and html-tag compile fixtures
ryanatkn Jul 12, 2026
ee71927
feat: script comment carry-through with divergent-class refusals
ryanatkn Jul 12, 2026
fc915a8
docs: describe M2 transforms, evaluator port, and comment carry-through
ryanatkn Jul 12, 2026
75d0e1b
fix: match ECMAScript exponentiation special cases in the fold
ryanatkn Jul 12, 2026
7c3aad3
refactor: restructure template emission onto a statement body builder
ryanatkn Jul 12, 2026
b50ea91
refactor: add scope-overlay and unique-name scaffolding for block emi…
ryanatkn Jul 12, 2026
91e2e06
feat: compile Svelte control-flow blocks ({#if}/{#each}/{#await}/{#ke…
ryanatkn Jul 12, 2026
78ad64e
fix: port needs_context wrapper + import hoisting; refuse components,…
ryanatkn Jul 13, 2026
4003d5f
fix: split multi-declarator top-level declarations per declarator (or…
ryanatkn Jul 13, 2026
0374d5c
fix: refuse instance-script exports; inject $$slots/$$events into $pr…
ryanatkn Jul 13, 2026
7b636c4
feat: add compile_corpus_compare corpus-scale parity runner + compile…
ryanatkn Jul 13, 2026
33ab5f5
refactor: parallelize compile_fixtures_validate on the shared bulk wo…
ryanatkn Jul 13, 2026
b84e8aa
feat: self-validate compile() output by reparse (CompileError::Corrup…
ryanatkn Jul 13, 2026
e7e7e66
docs: add checklist_svelte_compiler.md coverage map
ryanatkn Jul 13, 2026
7b216d0
chore: cargo fmt
ryanatkn Jul 13, 2026
8cc1e45
fix: fold fully-static mixed attributes to static emission; drop empt…
ryanatkn Jul 13, 2026
209d9c1
fix: match oracle class clsx rule; harden corpus tool buckets and wal…
ryanatkn Jul 13, 2026
e4c8a5e
refactor: typed Refusal inventory replaces free-form Unsupported stri…
ryanatkn Jul 13, 2026
8fc0266
feat: drop event-attribute handlers in SSR output (refuse onload/oner…
ryanatkn Jul 13, 2026
0827bfd
feat: support $$slots (inject sanitize_slots, force $$props, guard ca…
ryanatkn Jul 13, 2026
bf0e703
feat: support <svelte:head> ($.head with ported filename hash, hoisted)
ryanatkn Jul 13, 2026
e5a1ed5
fix: rename rest-props $$slots to $$slots_ when sanitize_slots owns t…
ryanatkn Jul 13, 2026
681ea31
fix: event-attribute drop tests the raw name (ONCLICK emits, onClick …
ryanatkn Jul 13, 2026
1ff93ca
fix: Opaque handler-shadowed bindings so dropped-handler mutations ne…
ryanatkn Jul 13, 2026
0c52dd7
docs: pin raw-name event decision, $$slots_ rename, and shadow envelo…
ryanatkn Jul 13, 2026
b996d20
feat: compile {#snippet} and {@render} (server SSR)
ryanatkn Jul 13, 2026
09c05d8
feat: compile static component invocations + props (server SSR)
ryanatkn Jul 13, 2026
76dc60c
feat: compile component default-slot children (implicit children snip…
ryanatkn Jul 13, 2026
9adf3e9
feat: compile component named snippet props ({#snippet} children)
ryanatkn Jul 13, 2026
de05755
fix: snippet hoist sees component spread refs via shared attr_refs tr…
ryanatkn Jul 13, 2026
e71d39a
fix: analysis passes count refs in skipped attr positions inside drop…
ryanatkn Jul 13, 2026
1ccfd40
fix: count directive-name/special-element/render-callee refs in dropp…
ryanatkn Jul 13, 2026
cac16f3
fix: count style: shorthand name reference in dropped {:catch}
ryanatkn Jul 13, 2026
1276a9a
merge main
ryanatkn Jul 13, 2026
4ef5882
Merge branch 'main' into svelte-compiler
ryanatkn Jul 13, 2026
c37c472
refactor: qualify canonical printer's layout line-break table + gate …
ryanatkn Jul 13, 2026
1f26e02
docs: document compile_corpus_compare and complete the compile crate …
ryanatkn Jul 13, 2026
e777b4f
feat: add compile_profile and erase_comment_census debug tooling
ryanatkn Jul 13, 2026
29825c7
feat: refuse legacy reactive statements and runes-invalid imports, pr…
ryanatkn Jul 13, 2026
2a9fd3d
docs: note new runes-mode refusals in the compile crate coverage prose
ryanatkn Jul 13, 2026
f8699c6
feat: erase TypeScript in the Svelte compiler (lang="ts" compiles at …
ryanatkn Jul 13, 2026
5d012d2
fix: unthunk $derived, widen the erased-comment window, unwrap JsdocC…
ryanatkn Jul 13, 2026
ca9b71a
feat: erase TypeScript at the Svelte template borrow points
ryanatkn Jul 13, 2026
093fc9f
docs: template-side type erasure and the dropped-region walking contract
ryanatkn Jul 13, 2026
1ae951b
fix: decide the {@render} call shape before erasure, and is_standalon…
ryanatkn Jul 13, 2026
6b023f8
docs: note the parse-time {@render} call-shape rule
ryanatkn Jul 13, 2026
581c091
docs: distinguish refusing an oracle bug from diverging from the oracle
ryanatkn Jul 13, 2026
a133d45
fix: unwrap TypeScript wrappers in needs_context root_of (spurious co…
ryanatkn Jul 13, 2026
ed6a185
feat: refuse a top-level {#snippet} rest parameter; drop the derived-…
ryanatkn Jul 13, 2026
49c574d
fix: preserve a destructured block pattern type annotation (parser, p…
ryanatkn Jul 13, 2026
fac735c
docs: template-erasure contract corrections and the compile fixture f…
ryanatkn Jul 13, 2026
50b0259
fix: preserve an escaped whitespace in a CSS value (prettier strands …
ryanatkn Jul 13, 2026
d56b260
fix: treat a CSS escape as opaque in every value/selector scan; rever…
ryanatkn Jul 13, 2026
cfa5f57
fix: close the escape-opacity class in the pseudo, url, and forgiving…
ryanatkn Jul 13, 2026
609a360
fix: revert the lexer escape-terminator narrowing; trim CSS whitespac…
ryanatkn Jul 14, 2026
b4f912a
chore: re-pin svelte-fixtures counts for three added suite inputs
ryanatkn Jul 14, 2026
448f460
docs: cover type erasure, the CSS escape-opacity rule, and typed bloc…
ryanatkn Jul 14, 2026
b30612d
Merge branch 'main' into svelte-compiler
ryanatkn Jul 14, 2026
60eab31
docs: document the COMMENT-LOSS bucket and the snippet rest-parameter…
ryanatkn Jul 14, 2026
94a690a
refactor: split transform_server.rs into script_rewrite/fragment/bloc…
ryanatkn Jul 14, 2026
b6dc52f
test: extract lib.rs's #[cfg(test)] module into src/tests.rs
ryanatkn Jul 14, 2026
45bcd54
refactor: centralize FragmentNode child-fragment recursion in one exh…
ryanatkn Jul 14, 2026
769abef
feat: drop the no-op directive/attach attribute family in the Svelte …
ryanatkn Jul 14, 2026
ef8e044
docs: note the phase-2 directive-validity refusal gap in the checklist
ryanatkn Jul 14, 2026
47ffe71
fix: refuse the five oracle-rejected directive-validity combinations …
ryanatkn Jul 14, 2026
3a27794
docs: note the two sanctioned animate over-refusals (fallback positio…
ryanatkn Jul 14, 2026
19eba5c
feat: compile class: directives to $.attr_class in the Svelte SSR com…
ryanatkn Jul 14, 2026
74f46f2
feat: compile style: directives to $.attr_style in the Svelte SSR com…
ryanatkn Jul 14, 2026
4191adf
chore: rustfmt the animate_host_element signature (Task 1 drift)
ryanatkn Jul 14, 2026
c7be042
fix: HTML-escape the static class base in the Svelte compiler's $.att…
ryanatkn Jul 14, 2026
13272b9
feat: compile bind: core kinds (this/value/checked/group) in the Svel…
ryanatkn Jul 14, 2026
594179d
fix: refuse a non-lvalue bind:this target in the Svelte compiler
ryanatkn Jul 14, 2026
5bb55bd
feat: compile an element {...spread} to the fused $.attributes object…
ryanatkn Jul 14, 2026
8c131dd
feat: compile an element {...spread} co-present with class:/style:/bi…
ryanatkn Jul 14, 2026
6e9514d
fix: refuse omit_in_ssr binds on the Svelte compiler's spread path
ryanatkn Jul 14, 2026
43b740c
merge main
ryanatkn Jul 15, 2026
f4544b7
merge main
ryanatkn Jul 16, 2026
4e16d28
merge main
ryanatkn Jul 16, 2026
ddd429c
merge main
ryanatkn Jul 16, 2026
9689571
feat: add sole-blocker refusal census to compile_corpus_compare
ryanatkn Jul 16, 2026
6793e19
refactor: extract analyze() Analysis product from compile_server
ryanatkn Jul 17, 2026
249c3e8
feat: scope same-element non-combinator CSS selectors
ryanatkn Jul 17, 2026
85a5266
feat: scope CSS combinators and basic :global
ryanatkn Jul 17, 2026
b19dbed
docs: update compiler checklist for CSS combinators and :global
ryanatkn Jul 17, 2026
76884b0
docs: update crate CLAUDE.md for element census and combinator scoping
ryanatkn Jul 17, 2026
5a656f4
feat: compile SSR-inert special elements (svelte:window/body/document)
ryanatkn Jul 17, 2026
e400e93
wip
ryanatkn Jul 17, 2026
3039fd8
feat: compile <svelte:element> (SSR $.element emission)
ryanatkn Jul 17, 2026
5c9d67f
feat: scope CSS on <svelte:element> (census leaf+owner + type bypass)
ryanatkn Jul 17, 2026
e783ab4
merge main
ryanatkn Jul 17, 2026
700efd7
add fixtures
ryanatkn Jul 17, 2026
0e812a4
feat: implement
ryanatkn Jul 17, 2026
447186b
feat: implement
ryanatkn Jul 17, 2026
928c84c
docs
ryanatkn Jul 17, 2026
67ade81
feat: compile $props.id and $state.snapshot
ryanatkn Jul 17, 2026
f1f40b9
docs
ryanatkn Jul 17, 2026
bd0ecf5
feat: compile nested reads
ryanatkn Jul 18, 2026
19269ed
docs
ryanatkn Jul 18, 2026
039b71b
Merge branch 'main' into svelte-compiler
ryanatkn Jul 18, 2026
f231b24
comments
ryanatkn Jul 18, 2026
4913278
feat: compile template-position $store reads
ryanatkn Jul 18, 2026
d84d01a
feat: compile script-position $store reads and writes
ryanatkn Jul 18, 2026
5f2b3b6
wip derived
ryanatkn Jul 18, 2026
1d5d50b
merge main
ryanatkn Jul 18, 2026
c050d18
Merge branch 'main' into svelte-compiler
ryanatkn Jul 18, 2026
9083433
derived
ryanatkn Jul 18, 2026
9776fa8
docs
ryanatkn Jul 18, 2026
ff3755b
feat: compile <title> inside <svelte:head>
ryanatkn Jul 18, 2026
d1ead00
Merge branch 'main' into svelte-compiler
ryanatkn Jul 18, 2026
c607832
feat: compile plain module scripts
ryanatkn Jul 18, 2026
752576c
feat: compile script-position $derived reads
ryanatkn Jul 18, 2026
d8abe4b
docs: remove scratch design docs; sync compiler checklist
ryanatkn Jul 18, 2026
c1036c3
feat: compile class-field $state runes
ryanatkn Jul 18, 2026
b71a743
refactor: lazy structural-sharing in class-field $state rewrite
ryanatkn Jul 18, 2026
ac1b918
Merge branch 'main' into svelte-compiler
ryanatkn Jul 18, 2026
6322db3
merge main
ryanatkn Jul 18, 2026
e9d028b
git commit -m 'feat: compile comments after the last script statement'
ryanatkn Jul 18, 2026
b27a4d5
Merge branch 'main' into svelte-compiler
ryanatkn Jul 18, 2026
dd7d0b4
feat: split refusal taxonomy, gate over-acceptance, report target set
ryanatkn Jul 19, 2026
3e1311e
fix: refuse presence-read constructs in dropped regions
ryanatkn Jul 19, 2026
4dc4778
feat: compile <svelte:boundary>
ryanatkn Jul 19, 2026
8254cc2
fix: close const/import bind-target, snapshot-fold, dup-props, and {:…
ryanatkn Jul 19, 2026
de12ab1
fixtures
ryanatkn Jul 19, 2026
bb01d73
feat: add differential compile fuzzer + compiler doc audits
ryanatkn Jul 19, 2026
0cf7005
fix: refuse $-prefixed bindings at declarator, function, class, impor…
ryanatkn Jul 19, 2026
8fc31b5
Merge branch 'main' into svelte-compiler
ryanatkn Jul 19, 2026
59313e7
feat: gate Svelte validation suites with an over-acceptance ratchet
ryanatkn Jul 19, 2026
4ee15dc
feat: add exotic-whitespace mutation operator to compile_fuzz
ryanatkn Jul 19, 2026
9a06b01
fix: refuse invalid assignment targets
ryanatkn Jul 20, 2026
2a4ad3b
fix: close compile mismatch and over-acceptance classes
ryanatkn Jul 20, 2026
1df392b
Merge branch 'main' into svelte-compiler
ryanatkn Jul 20, 2026
0a78c9e
fix: refuse writes to template-scoped consts
ryanatkn Jul 20, 2026
b882694
Merge branch 'main' into svelte-compiler
ryanatkn Jul 20, 2026
f76f0ea
wip
ryanatkn Jul 20, 2026
74e4491
merge main
ryanatkn Jul 20, 2026
dda7a28
fix: refuse invalid HTML node placement
ryanatkn Jul 20, 2026
785d0e3
refactor: exhaustive element census descent, document walk phases
ryanatkn Jul 20, 2026
f388161
feat: report census fence containment beside the target set
ryanatkn Jul 20, 2026
8723455
fix: refuse invalid attribute names and misplaced slot attributes
ryanatkn Jul 20, 2026
3b27c80
Merge branch 'main' into svelte-compiler
ryanatkn Jul 20, 2026
94526e2
merge main
ryanatkn Jul 20, 2026
736de1b
attributes
ryanatkn Jul 20, 2026
d061749
test: refactor
ryanatkn Jul 20, 2026
65df651
test: more refactoring
ryanatkn Jul 20, 2026
dc02742
cleanup
ryanatkn Jul 20, 2026
fe3a6a6
refactor
ryanatkn Jul 20, 2026
bb24851
more refactoring
ryanatkn Jul 20, 2026
8f45de9
more refactoring
ryanatkn Jul 20, 2026
b95560e
docs
ryanatkn Jul 20, 2026
d31facc
test: guard every_variant against omitted Refusal variants
ryanatkn Jul 20, 2026
1e9c2f3
more refactoring
ryanatkn Jul 20, 2026
b8fad27
fix: refuse unquoted multi-chunk attribute values
ryanatkn Jul 20, 2026
01de438
feat: port snippet declaration and export validation
ryanatkn Jul 20, 2026
128b006
fix: emit non-hoisted snippets in recursive-direct-first order
ryanatkn Jul 20, 2026
5a4a140
feat: refuse unknown <svelte:...> meta tags
ryanatkn Jul 20, 2026
44f7b89
feat: refuse rune calls with a spread argument
ryanatkn Jul 20, 2026
f9081c7
feat: refuse export { x as default } in <script module>
ryanatkn Jul 20, 2026
09d5a15
refactor
ryanatkn Jul 20, 2026
de62ed9
feat: refuse {#each} with a key but no as clause
ryanatkn Jul 20, 2026
f26531c
feat: refuse <script> context attribute other than module
ryanatkn Jul 20, 2026
21ece9b
feat: refuse valued <script module> attribute
ryanatkn Jul 20, 2026
a565ea1
docs
ryanatkn Jul 20, 2026
0c1e6db
feat: refuse reserved <script> attributes
ryanatkn Jul 21, 2026
7f0fdcb
merge main
ryanatkn Jul 21, 2026
ef5a942
feat: refuse props with a $$-prefixed name
ryanatkn Jul 21, 2026
83aa62b
feat: refuse props.$$-prefixed member access on a rest_prop
ryanatkn Jul 21, 2026
632bee4
feat: refuse arguments referenced outside a function
ryanatkn Jul 21, 2026
dbe94ab
feat: refuse $props() destructure with a computed key or nested pattern
ryanatkn Jul 21, 2026
6ed2439
refactor: fuse the dollar-binding shape gate and decode into one walk
ryanatkn Jul 21, 2026
3c8a643
feat: compile escaped $-prefixed store reads and writes
ryanatkn Jul 21, 2026
e30c87d
feat: carry module-script comments the oracle keeps
ryanatkn Jul 21, 2026
e88a557
Merge branch 'main' into svelte-compiler
ryanatkn Jul 21, 2026
d0488c3
feat: match esrap alias-drop for string-literal import/export specifiers
ryanatkn Jul 21, 2026
2b7316a
feat: compile destructured $derived and $derived.by declarators
ryanatkn Jul 21, 2026
b67802c
refactor
ryanatkn Jul 21, 2026
57f0182
feat: compile destructured declarators
ryanatkn Jul 21, 2026
2ccf51b
feat: scope selectors inside CSS group at-rules
ryanatkn Jul 21, 2026
e7ca0e2
feat: compile css @keyframes scoping
ryanatkn Jul 22, 2026
0f3bfa1
feat: compile CSS matching against dynamic and mixed attribute values
ryanatkn Jul 22, 2026
7777bda
merge
ryanatkn Jul 22, 2026
8cd53c2
readme
ryanatkn Jul 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
126 changes: 122 additions & 4 deletions CLAUDE.md

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [
"crates/tsv_ts",
"crates/tsv_css",
"crates/tsv_svelte",
"crates/tsv_svelte_compile",
"crates/tsv_cli",
"crates/tsv_debug",
"crates/tsv_wasm",
Expand Down Expand Up @@ -44,6 +45,9 @@ tsv_discover = { path = "crates/tsv_discover" }
tsv_ts = { path = "crates/tsv_ts", default-features = false }
tsv_css = { path = "crates/tsv_css", default-features = false }
tsv_svelte = { path = "crates/tsv_svelte", default-features = false }
# Svelte→JS compiler + JS canonicalizer. Dev-tooling consumer only (tsv_debug);
# no shipped artifact links it yet.
tsv_svelte_compile = { path = "crates/tsv_svelte_compile" }

# External dependencies
argh = "0.1"
Expand Down Expand Up @@ -174,6 +178,7 @@ serde_json.workspace = true
[dev-dependencies]
tsv_debug = { path = "crates/tsv_debug" }
tsv_cli = { path = "crates/tsv_cli" }
tsv_svelte_compile.workspace = true
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
futures-util.workspace = true
bumpalo.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ Future features (unknown order):
but the lift to support it is small)
- JS parsing diagnostics (test262 negative cases)
- CSS error recovery (recover past invalid CSS per the spec)
- Svelte compiler (partially implemented, not ready for usage)
- later:
- TypeScript 7 integration (the Go impl), unlocking:
- svelte-check replacement
- LSP
- linter - type aware, initially focused on serializable data-only plugins for extensibility
- Svelte compiler (exact mirror, maybe out of scope, see [rsvelte](https://github.com/baseballyama/rsvelte))
- bundling is probably out of scope
- [discussion](https://github.com/fuzdev/tsv/discussions) welcome

Expand Down
21 changes: 21 additions & 0 deletions crates/tsv_css/src/ast/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,27 @@ pub struct CssAtrule<'arena> {
pub span: Span,
}

impl CssAtrule<'_> {
/// The at-rule's **public-AST prelude** — the exact string Svelte's parser exposes as
/// `node.prelude` (its `read_value(...).trim()`, block comments elided). Routes through
/// the wire-JSON prelude reconstruction ([`convert_prelude_to_string`]), the single
/// fixture-gated definition of that shape, so a consumer that must agree with the
/// oracle's `node.prelude` byte-for-byte — the Svelte compiler's `@keyframes` name
/// collection and its `-global-` prefix test — reads the identical bytes rather than the
/// printer-facing [`PreludeValue::Raw`] `content`, which is CSS-whitespace-trimmed and
/// comment-preserving and so diverges on a prelude carrying a comment or JS-only
/// whitespace (`@keyframes spin /* c */`, a trailing vertical tab / NBSP).
///
/// A pure visibility bridge over the writer's own reconstruction — no parse, printer, or
/// wire behavior of its own.
///
/// [`convert_prelude_to_string`]: crate::ast::convert::convert_prelude_to_string
#[cfg(feature = "convert")]
pub fn public_prelude<'src>(&self, source: &'src str) -> std::borrow::Cow<'src, str> {
crate::ast::convert::convert_prelude_to_string(&self.prelude, source)
}
}

/// At-rule block - can contain rules, declarations, or nested at-rules
#[derive(Debug, Clone)]
pub struct CssAtruleBlock<'arena> {
Expand Down
3 changes: 2 additions & 1 deletion crates/tsv_debug/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> Developer tooling crate — fixtures, comparisons, corpus runs. Embeds a Deno sidecar for canonical JS tools.

Unlike `tsv_cli` (pure Rust, production binary), `tsv_debug` exists to validate and debug `tsv` against external sources of truth: Prettier (formatting), Svelte's compiler (parsing), acorn-typescript (TS AST shape). The binary `tsv_debug` powers `deno task fixtures:*`, `deno task corpus:compare:format`, `deno task bench`, and friends. For the command catalog see [../../CLAUDE.md §Debug Tooling](../../CLAUDE.md#debug-tooling); the audit gates are cataloged in [../../docs/audits.md](../../docs/audits.md), the profiling tools in [../../docs/performance.md](../../docs/performance.md).
Unlike `tsv_cli` (pure Rust, production binary), `tsv_debug` exists to validate and debug `tsv` against external sources of truth: Prettier (formatting), Svelte's compiler (parsing), acorn-typescript (TS AST shape). The binary `tsv_debug` powers `deno task fixtures:*`, `deno task corpus:compare:format`, `deno task bench`, and friends. For the command catalog see [../../CLAUDE.md §Debug Tooling](../../CLAUDE.md#debug-tooling); the audit gates are cataloged in [../../docs/audits.md](../../docs/audits.md), the profiling tools in [../../docs/performance.md](../../docs/performance.md), the Svelte-compiler harnesses in [../../docs/compile_tooling.md](../../docs/compile_tooling.md).

## Architecture Position

Expand All @@ -15,6 +15,7 @@ The Deno sidecar is a **long-running subprocess pool** spawned lazily on first u
- `deno/` — Sidecar plumbing: `actor.rs` owns one spawned process (`mod.rs` holds the pool + round-robin dispatch), `protocol.rs` is the JSON-lines wire format, `sidecar.ts` is the embedded TypeScript that runs inside Deno and dispatches to prettier / svelte (parse **and** `compile`) / acorn / parseCss. Pinned npm versions live in `sidecar.ts`. The `svelte-render-key` tool compiles for the server target and reduces the baked template to its browser-visible render (block-aware whitespace collapse, `<script>`/`<style>`/comments stripped) — the authoritative oracle behind the fixture render-equivalence check.
- `fixtures/` — The fixture workflow surface — `model.rs` holds the data model (`InputType`, `Fixture`, divergence-suffix rules), `discovery.rs` walks the fixtures tree, `variants.rs` discovers variant files, `mod.rs` keeps IO/parse helpers, `validation/` is the validator (`fixtures_validate`: structure rules, per-phase checks, errors, summary — including `phases/render_equivalence.rs`, which asserts every Svelte whitespace variant *renders* like `input`, not merely that it normalizes to it), `audit_signature.rs` pins prettier's multi-pass chain.
- `test262/` — ECMAScript conformance runner: `discovery.rs` walks the test262 tree, `frontmatter.rs` parses the YAML harness metadata, `runner.rs` drives our parser (`run_test`) and grades the strict subset into the differential `Manifest` (`grade_for_manifest`, sharing the `classify` skip logic with `run_test`). Pure Rust — no Deno needed. The `test262 --emit-manifest` JSON feeds `benches/js/diagnostics/test262_compare.ts` for the tsv-vs-oxc-parser comparison.
- `cli/commands/compile_fuzz/` — the differential compile fuzzer: `anchors.rs` reads the splice offsets off tsv's Svelte parse (fragment gaps, wrappable subtrees, attribute slots, script slots, and the server-DROPPED regions — a `{:catch}` body, a `<svelte:boundary>` `pending`/`failed` snippet), `operators.rs` holds the eleven feature-level mutation operators (the cross-component donor graft, and the exotic-whitespace probe over the JS/CSS/attribute/template positions whose whitespace classes disagree), and `mod.rs` owns the generate-then-grade loop. Operators are AST/feature level rather than byte level because a compile mutant must stay oracle-**compilable** to grade anything; grading runs tsv's `compile()` first and skips the sidecar on a refusal. See [../../docs/compile_tooling.md](../../docs/compile_tooling.md).
- `diff.rs` — Colored text / JSON diffing with line-width annotations (used by `compare`, `ast_diff`, validation failures).
- `error.rs` — `DebugError` — wraps `DenoError`, `io::Error`, `serde_json::Error`; exposes `hint()` for actionable messages.
- `cli/` — argh `TopLevel`/`Subcommand` dispatch in `mod.rs` + per-command `FromArgs` modules under `cli/commands/`. Shared three-mode input plumbing (file path / `--content` / `--stdin`) comes from `tsv_cli::cli::input::InputArgs`.
Expand Down
1 change: 1 addition & 0 deletions crates/tsv_debug/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ tsv_lang = { workspace = true }
tsv_svelte = { workspace = true, features = ["convert"] }
tsv_ts = { workspace = true, features = ["convert", "debug_lex"] }
tsv_css = { workspace = true, features = ["convert", "debug_lex"] }
tsv_svelte_compile = { workspace = true }
tsv_html = { workspace = true }
argh.workspace = true
serde.workspace = true
Expand Down
7 changes: 5 additions & 2 deletions crates/tsv_debug/src/audit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
// verify layer is internally feature-gated.)
pub(crate) mod properties;

// The ratchet is NOT gated: `compile_corpus_compare --ratchet` (the validation-suite
// gate) drives no comment ledger, so it must exist in a default build. It is pure
// generic snapshot plumbing with no ledger dependency of its own.
pub(crate) mod ratchet;

// The injection machinery is only reachable through `gap_audit` / `blank_audit`,
// both themselves behind the `comment_check` feature (they arm
// `tsv_lang::comment_ledger`), so gate these too — otherwise they read as dead
Expand All @@ -35,8 +40,6 @@ pub(crate) mod node_edge;
#[cfg(feature = "comment_check")]
pub(crate) mod parallel;
#[cfg(feature = "comment_check")]
pub(crate) mod ratchet;
#[cfg(feature = "comment_check")]
pub(crate) mod report;
#[cfg(feature = "comment_check")]
pub(crate) mod sites;
107 changes: 107 additions & 0 deletions crates/tsv_debug/src/cli/commands/canonical_compile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use crate::cli::CliError;
use crate::deno::{self, SvelteCompileOutput, SvelteGenerate};
use argh::FromArgs;
use tsv_cli::cli::input::{InputArgs, ParserType};
use tsv_cli::json_utils::to_json_with_tabs;

/// Compile Svelte with the canonical Svelte compiler (the deterministic oracle).
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "canonical_compile")]
#[allow(clippy::struct_excessive_bools)] // independent CLI flags
pub struct CanonicalCompileCommand {
/// compile target: server | client (default: server)
#[argh(option, default = "SvelteGenerate::Server")]
target: SvelteGenerate,

/// also print the compiled CSS
#[argh(switch)]
css: bool,

/// development-mode output
#[argh(switch)]
dev: bool,

/// emit { js, css, warnings } as JSON
#[argh(switch)]
json: bool,

/// content to compile
#[argh(option)]
content: Option<String>,

/// read from stdin
#[argh(switch)]
stdin: bool,

/// file path
#[argh(positional)]
file: Option<String>,
}

impl CanonicalCompileCommand {
pub(crate) fn run(self) -> Result<(), CliError> {
// Compile is Svelte-only, so force the parser: --content/--stdin don't
// require an explicit --parser, and a file argument's extension is ignored.
let input_args = InputArgs {
content: self.content,
stdin: self.stdin,
parser: Some(ParserType::Svelte),
file: self.file,
};
let input = match input_args.resolve() {
Ok((input, _parser)) => input,
Err(e) => {
eprintln!("Error: {e}");
return Err(CliError::Failed);
}
};

let rt = super::create_runtime();
match rt.block_on(deno::svelte_compile(input.content(), self.target, self.dev)) {
Ok(output) => print_output(&output, self.css, self.json),
Err(err) => {
eprintln!("Error compiling: {err}");
Err(CliError::Failed)
}
}
}
}

/// Print the compile output: JSON when `as_json`, else the JS (and the CSS when
/// `show_css`, under a delimiting comment).
fn print_output(
output: &SvelteCompileOutput,
show_css: bool,
as_json: bool,
) -> Result<(), CliError> {
if as_json {
match to_json_with_tabs(output) {
Ok(json) => {
println!("{json}");
Ok(())
}
Err(err) => {
eprintln!("Error serializing output: {err}");
Err(CliError::Failed)
}
}
} else {
print_block(&output.js);
if show_css {
println!("/* --- css --- */");
match &output.css {
Some(css) => print_block(css),
None => println!("/* (none) */"),
}
}
Ok(())
}
}

/// Print `text`, ensuring it ends with exactly one trailing newline.
fn print_block(text: &str) {
print!("{text}");
if !text.ends_with('\n') {
println!();
}
}
Loading