Formatting
oxc-tsrx-fmt formats .tsrx files with Oxfmt, OXC's formatter, and then
converts the result back into TSRX. Ordinary JS/TS files are formatted by
Oxfmt directly, with a byte-for-byte-identical-output guarantee versus
running oxfmt yourself.
How a format run works#
The file you wrote, byte for byte. Nothing is changed on disk at any point.
export function Cart({ items }: Props) @{
var total = 0;
debugger;
<section class="cart">
@if (items.length > 0) {
@for (const item of items; key item.id) {
<Row item={item} />
}
} @else {
<Empty />
}
</section>
}One byte-oriented pass finds every TSRX control token and records its exact position. This is the real overlay for the file above:
| Token | Bytes |
|---|---|
FunctionBody | 39–40 |
If | 101–102 |
For | 132–133 |
Else | 216–217 |
The TSRX syntax becomes formatting-safe markers in an in-memory copy; your code is copied verbatim. This is the actual projection:
export function Cart({ items }: Props) /*_t0_0*/{
var total = 0;
debugger;
<section class="cart">
{_t0_W0_({async *_t0_M0_(){/*_t0_N0S__*//*_t0_1*/if (items.length > 0) {
/*_t0_2*/for (const item of _t0_H0_(/*_t0_R0S__*/items/*_t0_R0E__*/,_t0_KH0_(/*_t0_K0S__*/item.id/*_t0_K0E__*/),_t0_HE0_)) {
<Row item={item} />
}
} /*_t0_3*/else {
<Empty />
}/*_t0_N0E__*/}},_t0_E0_)}
</section>
}Canonical Oxfmt parses and lays out that copy exactly once. The markers are designed to survive formatting so nothing about your control flow is lost.
A checked single pass converts the formatted copy back into TSRX: markers become @-controls again, raw <style> bytes are restored from your original, and the result must re-scan to the same structure before anything is written.
Step by step:
- The file is scanned and projected to a valid-TSX copy, the same idea as linting, except here the placeholders are special markers designed to survive formatting.
- Oxfmt parses and formats that copy. Once.
- The lift walks the formatted output and turns it back into TSRX:
markers become
@if/@for/@switch/@tryagain, your code keeps its new formatting, dynamic closing tags are rebuilt from their opening expression, and raw<style>contents are copied from your original file untouched. - As a final safety check, the lifted result is re-scanned and must match the structural fingerprint of the input. If anything doesn't line up, the tool errors out instead of writing a broken file.
Usage#
# Check without modifying files; exits 1 and lists files that differ oxc-tsrx-fmt --check src/Counter.tsrx Checking formatting... src/Counter.tsrx (0ms) Format issues found in above 1 files. Run without `--check` to fix. Finished in 0ms on 1 files using 18 threads. # Format and write files; success prints only the summary line oxc-tsrx-fmt --write src/Counter.tsrx src/View.tsx Finished in 0ms on 2 files using 18 threads. # Editor/stdin mode: formatted source goes to stdout oxc-tsrx-fmt --stdin-filepath=src/Counter.tsrx < src/Counter.tsrx export function Counter({ start }: { start: number }) @{ var count = start; console.log("mounted"); debugger; <div class="counter"> <span>{count}</span> </div>; } # Explicit config and worker count oxc-tsrx-fmt --write --config config/format.json --threads=4 src/Counter.tsrx Finished in 0ms on 1 files using 4 threads. # The explicit config switched the file to single quotes, no semicolons cat src/Counter.tsrx export function Counter({ start }: { start: number }) @{ var count = start console.log('mounted') debugger ;<div class="counter"> <span>{count}</span> </div> }
Writes are transactional: every file in the batch must format successfully before the first one is replaced on disk, so a crash or bad file never leaves your project half-formatted. Symbolic links are rejected.
Configuration#
oxc-tsrx-fmt finds one .oxfmtrc.json or .oxfmtrc.jsonc by searching
upward, or takes --config/-c. The standard layout options work:
printWidth, singleQuote, semi, useTabs, tabWidth, trailingComma,
arrowParens, bracketSpacing, singleAttributePerLine, and more, plus
overrides and ignorePatterns. The full list is in
Configuration.
Options that could silently change TSRX output in unsupported ways are
rejected with a clear error before anything is formatted or written:
sortImports, jsdoc formatting, embedded-language formatting, experimental
flags, .editorconfig, and JS/TS config files.
CSS inside <style> is preserved, not formatted#
Bytes inside a raw <style> element are copied through exactly as you wrote
them. The upstream OXC CSS formatter currently can't be used without patching
OXC's dependency graph, and this project's core rule is no patches, so CSS
formatting waits until upstream exposes a clean package boundary.
How we know the lift is safe#
A pinned, read-only corpus of real-world TSRX (the Markless oracle) proves
that all 179 parser-valid tracked files format, re-parse, and converge
(formatting a formatted file changes nothing), and that all 12 known invalid
fixtures are rejected. Every raw <style> payload is compared byte-for-byte.