Skip to content

Repository files navigation

tsv

a pixelated orange quill drawing a precise line

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:

  1. correctness (spec conformance for HTML/CSS/JS, fidelity to Svelte and TypeScript)
  2. speed
  3. binary size and memory usage
  4. 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.

About

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-format on 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

Install

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:

npm i -D @fuzdev/tsv
npx tsv format src            # if installed locally
npx @fuzdev/tsv format src    # or without installing first
import {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:

Design

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, and trailingComma: 'none'), and there are no config files or CLI options for formatting style; (opinionated like gofmt, 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 format discovery 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.

Docs

Developing

Dev dependencies:

  • Rust - rustc, cargo
  • Deno - see deno.json for the tasks
    • uses npm: imports from svelte, typescript, acorn, @sveltejs/acorn-typescript, prettier, prettier-plugin-svelte

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 svelte

For the full reference see CLAUDE.md § Commands.

Project structure

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's bumpalo arena (the bindings reuse a per-thread arena across calls via tsv_arena)
  • format(ast, source) -> String — plus format_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, and format_str(source), the parse+format one-shot
  • convert_ast_json_bytes(ast, source) -> Vec<u8> — the wire JSON, emitted directly from the internal AST, with a convert_ast_json_string wrapper and span-only _no_locations variants of both alongside (default-on convert cargo feature; turn off for parse+format-only builds)

For more details see CLAUDE.md.

Credits

tsv is an implementation of various software designs and specs:

Software:

Web Standards:

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.

Contributing

fuz.dev/contributing

License

MIT

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

About

precise language tools for TypeScript/JS, CSS, and Svelte in Rust

Resources

Code of conduct

Contributing

Security policy

Stars

26 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages