feat: add print(...) function

#16188

Pull request

Draft
R
Rich-Harris
Jun 17, 2025, 1:57 AM

Over on sveltejs/esrap#68 we're working on making esrap pluggable, so that it can be used to print any AST composed of { type: string, ... } nodes rather than just estree and its TypeScript extensions. That includes Svelte ASTs.

The main motivation for exposing this is so that we can make it easier to write preprocessors. Historically, Svelte exposed a preprocess API, but it's all strings and duct tape, and it's difficult to integrate preprocessors cleanly with bundlers as we've seen with enhanced-img.

When the preprocessor API was introduced, things looked very different. Preprocessing was necessary to support things like TypeScript and Sass. Today, TypeScript is supported natively, and CSS is sufficiently capable that Sass is little more than a historical curiosity.

In the long term, we'd therefore like to move away from the preprocessor API in favour of providing more robust lower-level utilities. For example enhanced-img, which can only be used in a Vite context, really should just be a Vite plugin:

import { parse, print } from 'svelte/compiler';
import { walk } from 'zimmerframe';

function transform(code) {
  const ast = parse(code);

  const transformed = walk(ast, null, {
    RegularElement(node, context) {
      if (node.name !== 'enhanced:img') return;
      // ...
    }
  });

  return print(ast);
}

There are other potential uses, such as migrations or sv add or having a 'format' button in the playground.

As a side-effect, quality of compiler output will be slightly better in certain cases, such as when encountering comments inside nodes. (Today, we attach leadingComments and trailingComments to each node, but this is a brittle and not-very-widely-used convention. The new esrap API expects an array of comments to be passed instead.)

This functionality already exists in svelte-ast-print (thank you @xeho91!), but having it in core means we can re-use the esrap version that's already installed alongside svelte, and will help ensure it stays current with new features.

Before submitting the PR, please make sure you do the following

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • Prefix your PR title with feat:, fix:, chore:, or docs:.
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.
  • If this PR changes code within packages/svelte/src, add a changeset (npx changeset).

Tests and linting

  • Run the tests with pnpm test and lint the project with pnpm lint

Info

Assignees None
Reviewers None
Labels None
Milestone None