prettier / prettier/prettier

API to preserve format of nodes unchanged by codemods

Open
#14,832 9 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
52.3k
Forks
5k
Avg merge
19h 2m
Merged PRs (30d)
117

Description

I'm on the hunt for better ways to prevent irrelevant formatting changes in codemods... AFAIK the most popular tool for this right now is recast (used by JSCodeshift), but it's slow to add support for new syntax features, and I've seen buggy output from it various times over the years.

Reformatting the transformed code with prettier helps, but it's not enough because unchanged objects that were previously on one line can get broken up into multiple lines, and so forth.
One of the most basic solutions would be deterministic output, but that wouldn't be good at preserving blank lines or one-line groups.

If only prettier exported its printers, preserving format after a codemod would be fairly simple, theoretically:

  • Make a custom printer that wraps another printer
    • When printing a given node:
      • if it (and all its descendants) were unchanged by the codemod:
        • output the original source for the node verbatim
      • otherwise, let the wrapped printer print the node
        • if any of its descendants were unchanged by the codemod, this printer will use the original source for them too
  • Do a second pass to reformat the code with the usual printer

This would be one potential benefit of exporting internal plugins printers.

I was able to do something similar to this with @babel/generator via a hack that allowed me to wrap its print node function, and so far the results have been very good. But @babel/generator doesn't export its printer API either so I had to use a hack to get at it.

The resulting indentation can be a little off, but the second pass through prettier fixes that.

Maybe another theoretical option would be to parse the source into prettier's internal AST format, manipulate that AST, and then call formatAST on it, but formatAST unfortunately isn't public API, and the tools I'm concerned with might require a complete redesign to operate on prettier AST nodes, I don't know.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the printer-wrapping approach described in the issue and compare it with babel-generator-hack/src/babel/reprint.ts, which demonstrates a related hack. Review the implications of exposing printer APIs or formatAST; done means a supported approach preserves unchanged node source while allowing changed nodes to be printed and reformatted, but no Prettier test file is named.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.