npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tsrx/prettier-plugin

v0.6.3

Published

TSRX plugin for Prettier

Readme

@tsrx/prettier-plugin

A Prettier plugin for formatting TSRX files.

The goal is Prettier's output wherever TSRX is TSX, so TSRX only differs where its syntax does: @{ … } blocks, @if/@for/@switch/@try, {value} shorthand props, <style>/<script> bodies, and comments between JSX children.

Usage

  1. Install Prettier and the plugin as dev dependencies:

    npm install -D prettier @tsrx/prettier-plugin
    # or
    pnpm add -D prettier @tsrx/prettier-plugin
  2. Add the plugin to your Prettier config, for example .prettierrc:

    { "plugins": ["@tsrx/prettier-plugin"] }
  3. Format with Prettier:

    npx prettier --write "src/**/*.tsrx"
    # or
    pnpm exec prettier --write "src/**/*.tsrx"

In your editor

The TSRX language server formats .tsrx files with your project's Prettier and this plugin. The TSRX Syntax for VS Code extension uses it, and so does any editor that formats through the language server. You do not need the Prettier extension for VS Code.

The language server adds the plugin itself, so a .tsrx file formats in the editor even when your Prettier config does not list the plugin. The prettier command does not do this: for the command line, keep the plugin in your Prettier config (step 2).

How it works

  • Parser (src/parse.js) parses with @tsrx/core in collect mode, so mistakes TypeScript only reports as diagnostics (a redeclared variable) still format. An unclosed or mismatched tag is still an error: the parser would guess the markup's structure. So is a dynamic tag whose expression isn't an identifier, a member access or a string literal (<{getTag()} />). Then it reshapes the acorn-typescript AST into the typescript-estree shape that Prettier's printer expects:
    • renames, such as superTypeParameters → superTypeArguments, accessor fields → AccessorProperty, namespace A.B → TSQualifiedName, and export import → ExportNamedDeclaration;
    • the parts of Prettier's parser postprocess that its printer relies on: __contentEnd, locEnd for statements, rebalanced logical expressions, merged touching JSDoc comments, dropped single-type unions;
    • a comment between JSX children, which renders like {/* … */} in TSX, is the {…} child that {/* … */} is in the parser's tree (a JSXExpressionContainer with a JSXEmptyExpression, and no braces in the source), so Prettier lays it out; it becomes the plugin's comment child, which prints without the braces, and a prettier-ignore one keeps the next child as written;
    • comments go to Prettier as a flat list with their source text, and Prettier attaches them itself.
  • Printer (src/printer.js) is Prettier's estree printer from prettier/plugins/estree. It sees the options as its own typescript parser's, because it checks the parser's name for TypeScript-only rules. The plugin prints the TSRX syntax:
    • @{ … } is a block statement with an @, and @case bodies are blocks, so blank lines and comments follow Prettier's statement rules.
    • Directives are presented to Prettier as do { … } expressions. A directive's head is printed while the node presents itself as its statement (IfStatement, ForOfStatement), so @if (…) breaks like if (…).
    • A directive, or a @{ … } block used as a value, lays out like a JSX element: wrapped in ( … ) where it's assigned, returned, thrown, or an arrow's body, with its comments inside the parentheses. While its parent prints, it presents itself as a JSXElement (withTsrxValuesAsJsx), so Prettier's JSX-specific layout applies to it. A @{ … } function or arrow body stays on its line.
    • An element that starts a statement keeps its parentheses where TSRX would read it as output without them, as Prettier keeps them before a statement that would start with {, function or class: in a template body wherever it starts the statement ((<hr />) + 1;), and in any other block when it is the whole statement ((<div />);).
    • A @{ … } block that is an element's or fragment's only child hugs its tags (<div>@{, the statements, }</div>), as a function's @{ … } body hugs its ), and one in an expression container hugs the braces ({@{, }}), as Prettier hugs a function there.
    • A comment before a tag name: after a line comment, Prettier would print <// note with the name below it, which TSX can't parse, so the comment and the name go on their own indented lines after <, as in Prettier's closing tags. A block comment prints straight after < (</* note */ div />).
    • <style> bodies are formatted as CSS. A <script> body is formatted as Prettier's HTML formatter formats it: its type or lang picks the parser (JavaScript without either; JSON for JSON, import maps, and speculation rules; Markdown; HTML), JavaScript and TypeScript bodies are formatted with this plugin's own parser, and a body without a parser (src, an unknown type), or that its parser can't read, is kept as written on its own lines, as Prettier keeps it. With embeddedLanguageFormatting: "off", <style> bodies are kept as written and <script> bodies are kept on their own lines.
    • Comments between a directive's branches are placed by Prettier's own comment handling for if and try, while @if and @try present themselves as those statements. A comment before @empty is handled like one before else.
  • JSX children (src/jsx.js): a comment between children prints without the braces, as written. An element with such comments is laid out by a copy of Prettier's printJsxElementInternal and printJsxChildren with the two rules a bare comment needs: a line comment ends its line, and it keeps whitespace before it after text or a comment (touching them, // is text); text that starts with // right after a block comment stays on its line. Every other element is printed by Prettier itself. Keep the copy in step with Prettier when upgrading.

The plugin needs no other Prettier plugin, including in prettier/standalone, except to format JSON, HTML, or Markdown <script> bodies there.

Selection formatting

The plugin supports selection formatting (also called range formatting). Use your editor's Format Selection command to format part of a .tsrx file, or pass Prettier's rangeStart and rangeEnd options when formatting through its API.

In the browser

prettier/standalone loads no parser by itself, and this plugin brings only its own and the CSS one for <style>. JavaScript and TypeScript <script> bodies are formatted with the plugin's parser, but a JSON, HTML, or Markdown body is kept as written unless you pass the Prettier plugins that parse and print it: Prettier finds a body's parser and printer among all the plugins in plugins.

import * as prettier from 'prettier/standalone';
import tsrx from '@tsrx/prettier-plugin';
// JSON, import maps, and speculation rules: babel parses JSON, estree prints it
import * as babel from 'prettier/plugins/babel';
import * as estree from 'prettier/plugins/estree';
// <script type="text/html">
import * as html from 'prettier/plugins/html';
// <script type="text/markdown">
import * as markdown from 'prettier/plugins/markdown';

const formatted = await prettier.format(code, {
  parser: 'tsrx',
  plugins: [tsrx, babel, estree, html, markdown],
});

In Node, prettier loads its own plugins, so these bodies are formatted without passing them.

Prettier versions

The Prettier peer dependency is >=3.6.0, with no upper limit. We recommend Prettier 3.9.9 or newer for more correct formatting. Older versions have formatting differences and known compatibility gaps, including prettier-ignore on template outputs.

The full formatting suite uses 3.9.9; focused import-type compatibility tests also run with 3.6.0.

Tests

  • tests/import-types.test.js checks import types, comments, standalone output, cursors, and selections with both the workspace Prettier and 3.6.0. Run the older-version checks with pnpm test --project prettier-plugin-3.6.
  • tests/tsrx.test.js covers TSRX syntax, which Prettier's own tests don't. Each formatting test also checks that a second format changes nothing.
  • tests/tsrx-migrated.test.js holds every test of the previous implementation that exercises TSRX syntax (#852, Phase 2), under one describe with their old names. Each expects this plugin's output and that formatting it again changes nothing, and, where Prettier's typescript parser gives the same output, checks that too. The old tests of plain JavaScript and TypeScript aren't migrated: Prettier prints those, the imported Prettier tests run them through the TSRX parser, and core's parser tests cover the parser.
  • tests/prettier/ holds Prettier's own format tests for JavaScript, JSX, and TypeScript, imported by scripts/import-prettier-tests.js. A case is imported when Prettier's typescript parser prints the snapshot's output and the input is TSRX: valid TSX, in a strict-mode module. tests/prettier.test.js runs every case through this plugin the way Prettier's harness does (with its cursor, range and line endings) and expects exactly Prettier's output.
  • tests/prettier/manifest.json records the Prettier version, the cases that were left out and why, and the imported cases that the TSRX parser rejects.
  • tests/prettier-known-failures.json lists the cases that don't pass yet. They run as expected failures, and a listed case that starts passing fails the run, so the list only shrinks. Refresh it after a change with UPDATE_KNOWN_FAILURES=1 pnpm test --project prettier-plugin.
  • tests/prettier-overrides.js holds the cases where TSRX deliberately differs from Prettier, each with its reason. An override skips the case (for example, syntax that is only a proposal), expects Prettier's output for the input as a .tsx file, or replaces the input or the expected output.

The files in tests/prettier/ come from Prettier and are under Prettier's MIT license.

Ongoing: keeping up with Prettier

The maintenance checklist from #852 applies to every Prettier upgrade:

  1. Re-import the installed release's format tests, then review and refresh the known failures:

    pnpm --filter @tsrx/prettier-plugin import-prettier-tests
    UPDATE_KNOWN_FAILURES=1 pnpm test --project prettier-plugin
    pnpm test --project prettier-plugin --project prettier-plugin-3.6

    The importer clones the installed release's tests, or accepts --source <prettier checkout>. Review changes to the imported cases, overrides, and known failures: a new failure can mean a regression or a change in Prettier's output.

  2. Keep src/jsx.js in step with Prettier's printJsxElementInternal and printJsxChildren, which it copies to handle comments between TSRX children.

  3. Check src/parse.js against Prettier's src/language-js/parse/postprocess. The node shapes and metadata the printer expects can change between releases.

  4. Check range formatting in src/range.js against Prettier's formatRange in src/main/core.js and calculateRange in src/main/range.js. It relies on Prettier passing the options object from the file's parse to the range's format, and on how Prettier grows a selection to AST nodes. For example, prettier/prettier#19880 changes how a range grows after 3.9. Verify the range and cursor tests on each upgrade, even when the release is already allowed by the peer dependency.