Skip to content

Format Document is not idempotent when a line break moves a token that enclosing nodes start at #65000

Open

Description

@roninjin10

🔎 Search Terms

format document, formatter, idempotent, idempotence, indentation, continuation indent, non-null assertion

🕗 Version & Regression Information

  • TypeScript 7 at main 4a4b24d (FormatDocument).
  • TypeScript 6.0.3's language service (getFormattingEditsForDocument) behaves the same way.

⏯ Playground Link

Not applicable: run Format Document twice on the code below (indent size 4, smart indentation).

💻 Code

{{0!
("")}}
{{x
+ y}}

🙁 Actual behavior

The first format indents (""), and + y, by 8 spaces; formatting the result again moves them to 12. With an identifier callee, {{x\n("")}}, the first format already gives 12.

When a formatting rule adds a line break before a token, only the dynamic indenter of the token's own node is updated. In the first input that node is the non-null expression 0!; the call 0!("") and its statement start at the same token and moved too, but keep the indentation they inherited while everything was on one line. In the second input, the binary expression's continuation delta is reset although its statement starts at the same x.

🙂 Expected behavior

The first format gives the stable result, and formatting it again changes nothing.

Additional information about the issue

Found by fuzzing the formatter for idempotence in a fork of this repository. A fix with a regression test for both inputs is in #64994.

This report was drafted with Claude Code (Claude Opus 5.5).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions