precise language tools for TypeScript/JS, CSS, and Svelte in Rust - tsv.fuz.dev
tsv is a toolchain for TypeScript/JS, CSS, and Svelte in Rust (and planned HTML/JSON). It ships a formatter that closely follows Prettier + prettier-plugin-svelte, and a drop-in for Svelte's parser + acorn + acorn-typescript.
tsv aims to simplify its covered domains and stay lean, and so it makes opinionated choices. The formatter has a single non-configurable style, using Svelte's Prettier config. Among other benefits this means tsv doesn't depend on a JS runtime, which it would need to resolve configs like Prettier.
Compared to Oxc, Biome, and SWC, tsv is a set of focused tools, not an extensible language platform, so the focus is Web standards + TS + Svelte and there's no support for JSX/SCSS/etc. tsv's extensibility story is currently limited to using its Rust crates as libraries (or forking); bridging to JS or WASM plugins is an open question (leaning against).
Compared to rsvelte, tsv has its own TS/JS/CSS parsers instead of using Oxc, and rsvelte additionally has a Svelte compiler and linter/typechecker integration (the full toolchain; tsv has some in-progress work here, scope unknown and may never ship).
tsv prioritizes, in order:
- correctness (spec conformance for HTML/CSS/JS, fidelity to Svelte and TypeScript)
- speed
- binary size and memory usage
- extensibility, modularity, reusability
Staying simple is an over-arching goal, and sometimes at odds with flexibility. Feedback is welcome to help navigate these tradeoffs.
See the benchmarks for measurements. Compared to Oxc/oxfmt and Biome, tsv is smaller and faster at parsing and formatting its supported languages, but lacks their features, extensibility, and broad language support. One reason for tsv to exist is to help find the performance bonuses left on the table in the Web's implementations.
tsv is near production-ready, with a long tail of rare bugs (and numerous fixes to bugs in acorn-typescript/Prettier/prettier-plugin-svelte). Reports and feedback are appreciated. See the issues and discussions.
The only first-party unsafe is in tsv_ffi, where the C boundary requires it;
tsv_napi relaxes the lint only to deny so napi-derive's generated code compiles.
Otherwise unsafe_code = "forbid".
AI disclosure: this codebase is LLM-generated, and some caveats apply. It's a high-effort project that prioritizes quality.
status: near production-ready - a long tail of rare bugs remains, and APIs may still change
tsv implements aspects of:
- HTML/CSS/JS and other Web specs
- TypeScript
- Svelte
- Prettier and prettier-plugin-svelte
tsv features:
- parsers for TypeScript/JS, CSS, and Svelte, drop-in for Svelte+acorn+acorn-typescript
- formatter following Prettier + prettier-plugin-svelte + Svelte's prettier config (with intentional divergences and no supported style config)
- VSCode formatter extension -
fuzdev.tsv-formaton the Marketplace and Open VSX (WASM-only, works in desktop VSCode and the browser host) - ts-to-js conversion (types-to-whitespace only)
- module lexer
Future features (unknown order):
- minifier
- JSON support
- HTML support (formatting as Svelte isn't correct e.g. with whitespace and
{, but the lift to support it is small) - JS parsing diagnostics (test262 negative cases)
- CSS error recovery (recover past invalid CSS per the spec)
- maybe later or never:
- TypeScript 7 integration (the Go impl), unlocking
what rsvelte already provides:
- linter - type aware, initially focused on serializable data-only plugins for extensibility
- svelte-check replacement
- LSP
- includes an experimental first-party typechecker
tsv_check(which may never ship)
- Svelte compiler (experimental partial implementation, may never ship - see rsvelte)
- bundling is out of scope
- discussion welcome
- TypeScript 7 integration (the Go impl), unlocking
what rsvelte already provides:
tsv ships to npm as a native package for Node and Bun, plus three WASM packages for browsers, Deno, and platforms without a prebuilt binary:
@fuzdev/tsv- the full tool (formatter + parser) as a prebuilt native N-API addon, shipping tsv's real native CLI binary as thetsvcommand@fuzdev/tsv-wasm- the full tool with the sametsvCLI, as WASM@fuzdev/tsv-format-wasm- formatter only (smaller)@fuzdev/tsv-parse-wasm- parser + JSON AST only (smallest)
npm i -D @fuzdev/tsv
npx tsv format src # if installed locally
npx @fuzdev/tsv format src # or without installing firstimport {format_svelte} from '@fuzdev/tsv';
const formatted = format_svelte('<script>\nconst x=1\n</script>');import {parse_svelte, type Root} from '@fuzdev/tsv';
const ast: Root = parse_svelte('<script>const x = 1;</script>');@fuzdev/tsv and @fuzdev/tsv-wasm are drop-in swaps.
The native package is prebuilt
for Linux (x64 gnu and musl, arm64 gnu), macOS (arm64 and x64), and Windows x64.
As with other wasm packages, browsers must call await init().
The same native tsv CLI binaries are attached to each
GitHub Release (one per platform above,
with a SHA256SUMS) for use without npm; every asset carries a build provenance
attestation (gh attestation verify tsv-linux-x64-gnu -R fuzdev/tsv).
See the website docs and package READMEs for the full API and CLI flags:
- crates/tsv_napi/npm/README.md
- crates/tsv_wasm/README_all.md
- crates/tsv_wasm/README_format.md
- crates/tsv_wasm/README_parse.md
tsv's goal is to be an optimal, focused toolchain for TypeScript/JS, CSS, and Svelte. (with planned JSON/HTML)
- reduce complexity within the defined scope
- supports Web+TS+Svelte - but no JSX/SCSS/etc
- formatter is non-configurable: formatting style is hardcoded to
Prettier's defaults with Svelte's official repo config
(
printWidth: 100,useTabs: true,singleQuote: true, andtrailingComma: 'none'), and there are no config files or CLI options for formatting style; (opinionated likegofmt,zig fmt, and Python's Black)
- parsers compatible with Svelte/acorn/acorn-typescript
- can generate a public JSON AST that should exactly match Svelte 5's modern AST with acorn and acorn-typescript (excluding bug fixes, see docs/conformance_svelte.md), and tsv has its own internal optimal AST
- formatters following Prettier
- formatting is similar to Prettier and prettier-plugin-svelte for the common case, and diverges more often for Svelte than TypeScript; tsv closely follows Prettier's TypeScript choices (see docs/conformance_prettier.md)
tsv formatdiscovery honors.gitignore,.prettierignore,.formatignore(the latter is original to tsv, all 3 use gitignore syntax)
- Rust-only
- minimal dependencies
- no C compiler needed to build tsv
- crates will be published to crates.io for reusability
- tsv currently has no support for JS plugins or JS/WASM runtime integration - JS bridging and WASM plugins will be evaluated to see if the tradeoffs work for tsv's goals, but the current lean is against, mainly for performance and simplicity; JS reaches tsv through the WASM and native N-API/FFI bindings
- optimal
- prioritizes speed, then binary size and memory usage
- ships optimal binary artifacts: so if all you need is a formatter or parser, a minimal build is available (currently just for WASM where it matters more, and with lang-specific artifacts likely coming), and heavier future layers (incremental parsing, CST for LSP) will be feature-gated so they don't regress the focused artifacts
- modern and Web-conformant, roughly aiming to be up-to-date with late-stage TC39 proposals
Intentional non-features:
- no formatter style config settings
- no markup for frameworks besides Svelte - no JSX/TSX, Vue, Astro, etc (unlike Biome+Oxc+SWC+friends) - but note that you can use tsv's crates and patterns to vibe your own thing
- no SCSS, CSS Modules, LESS, etc - standard CSS with Svelte extensions only
- no strict Prettier conformance - see the conformance doc and discussion #1
Each language is a self-contained Rust crate exposing the same
parse/format/convert_ast_json_bytes functions over its own concrete types - no
central Language trait, registry, or dynamic dispatch ("closed scope, open convention").
Each artifact includes only what it uses: the parse build excludes the printers,
the format build excludes the JSON-AST conversion layer, and a future TypeScript/JS-only
build would exclude Svelte and CSS (lang-specific builds aren't published yet) -
see docs/architecture.md.
- CLAUDE.md - development guide (commands, structure, conventions)
- docs/architecture.md - the major design decisions
- docs/directives.md -
format-ignore/prettier-ignoreformatting directives - docs/cli.md - commands and design
- docs/audits.md - the standing audit gates: what each proves, its blind spots, and where it gates
- docs/benchmarks.md - benchmark fairness caveats, the implementation catalog, and binary size reporting
- docs/conformance_prettier.md - where formatting diverges from Prettier (and why); its §Catalogs table indexes the per-language catalogs
- docs/conformance_svelte.md - where the parser diverges from Svelte (and why)
- docs/conformance_test262.md - ECMAScript parser conformance
- docs/conformance_tsc.md - TypeScript parser conformance against the compiler's own corpus
- docs/fixture_overview.md - fixture system design
- docs/fixture_workflow.md - step-by-step fixture creation
- docs/fixture_naming.md - fixture naming conventions and patterns
Dev dependencies:
- Rust - rustc, cargo
- Deno - see deno.json for the tasks
- uses
npm:imports fromsvelte,typescript,acorn,@sveltejs/acorn-typescript,prettier,prettier-plugin-svelte
- uses
Rust dependencies are kept fairly minimal. See CLAUDE.md § Rust Crates for the full list.
# Build workspace (recommended - uses deno tasks)
deno task build # dev build
deno task dev # watch mode (requires: cargo install cargo-watch)
deno task check # all checks (typecheck, tests, audits, lint, fmt)
# Or build directly with cargo
cargo build --workspace
cargo check --workspace # fast syntax check (no codegen)
cargo test --workspace # all tests including fixture validation
# Run CLI
cargo run -p tsv_cli parse --content "const x = 1;" --parser typescript
cargo run -p tsv_cli format --content "<div>test</div>" --parser svelteFor the full reference see CLAUDE.md § Commands.
Multi-crate workspace with clean separation of concerns:
tsv/
├── Cargo.toml # workspace root
├── crates/
│ ├── tsv_lang/ # foundation (Span, Location, ParseError)
│ ├── tsv_arena/ # shared binding substrate: per-thread reusable AST/doc arenas + the goal axis
│ ├── tsv_html/ # HTML classification and whitespace rules
│ ├── tsv_ignore/ # gitignore-aware discovery matcher (.gitignore/.formatignore/.prettierignore)
│ ├── tsv_discover/ # file-discovery policy (build-output heuristic + safety nets) over tsv_ignore
│ ├── tsv_ts/ # TypeScript parser/formatter (standalone)
│ ├── tsv_css/ # CSS parser/formatter (standalone)
│ ├── tsv_svelte/ # Svelte parser/formatter (uses tsv_ts + tsv_css)
│ ├── tsv_svelte_compile/ # experimental Svelte→JS compiler + JS canonicalizer (may never ship; not in any shipped artifact)
│ ├── tsv_check/ # experimental TypeScript binder/checker (may never ship; not in any shipped artifact)
│ ├── tsv_cli/ # unified CLI (binary: `tsv`)
│ ├── tsv_debug/ # dev utilities (binary: `tsv_debug`, uses Deno)
│ ├── tsv_ffi/ # C FFI bindings
│ ├── tsv_wasm/ # WebAssembly bindings
│ └── tsv_napi/ # N-API bindings (Node/Bun native path)
└── tests/ # workspace-level integration tests
Each language crate exports a consistent API:
parse(source, arena) -> Result<AST>— the AST allocates into the caller'sbumpaloarena (the bindings reuse a per-thread arena across calls viatsv_arena)format(ast, source) -> String— plusformat_in(ast, source, doc_arena), the same formatter writing through a reusable doc arena for the bindings' hot loop,format_folded_in(ast, &folded, doc_arena)for a caller that folded the source's line terminators itself, andformat_str(source), the parse+format one-shotconvert_ast_json_bytes(ast, source) -> Vec<u8>— the wire JSON, emitted directly from the internal AST, with aconvert_ast_json_stringwrapper and span-only_no_locationsvariants of both alongside (default-onconvertcargo feature; turn off for parse+format-only builds)
For more details see CLAUDE.md.
tsv is an implementation of various software designs and specs:
Software:
- Svelte
- Prettier which was forked from recast's printer, which is based on the algorithms described in "A prettier printer" by Philip Wadler
- TypeScript
Web Standards:
- WHATWG HTML - HTML Living Standard
- WHATWG DOM - DOM Living Standard
- W3C CSS Working Group - CSS specifications
- TC39 ECMAScript - JS language specification
- TC39 test262 - ECMAScript conformance tests
- W3C webref - Machine-readable web specs
- web-platform-tests/wpt - Test suites for Web platform specs
Claude Code was instrumental to this project, and tsv wouldn't exist without LLMs because of the high coding labor requirements. Source code of projects similar to tsv was not used by agents or consulted by the author unless listed above. The author learned Rust in 2015 but wrote only simple learning programs and some abandoned toys before tsv.
The code for the following projects was sometimes read by AI agents while producing tsv, so their license information is included for completeness:
Svelte Copyright (c) 2016-2026 Svelte Contributors MIT - https://github.com/sveltejs/svelte/blob/main/LICENSE.md
Prettier Copyright © James Long and contributors MIT - https://github.com/prettier/prettier/blob/main/LICENSE