fix(formatter): Use hard_space between : and TSTypeAnnotation#20858
fix(formatter): Use hard_space between : and TSTypeAnnotation#20858
hard_space between : and TSTypeAnnotation#20858Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
Merging this PR will not alter performance
Comparing Footnotes
|
8c3a7c0 to
9d7b6e3
Compare
fits measurement
9d7b6e3 to
02ca7b3
Compare
fits measurementhard_space between : and TSTypeAnnotation
|
I noticed something while researching
Honestly, I can't think of any reason to put trailing spaces at the end of a line...🤔 |
|
I will take a look soon! For |
|
@Dunqing How do you think about:
? |
|
Closing, at the very least, this PR is useless now. |
…d-mode early exit (#20954) Closes #20519 Alternative to #20858 ## Summary The `fits()` measurer in the printer defers `Space` elements via a `pending_space` boolean flag. When the measurer exits early through an expanded-mode line break (`Fits::Yes`), any unresolved `pending_space` is silently lost — causing the measured width to be off by one. This caused the decorator in `@property(...) prop: Type` to incorrectly stay on the same line because the space after `:` was not counted in the width measurement. ### Root cause In `FitsMeasurer::fits_element`, `Space` sets `pending_space = true` (deferred), while `HardSpace` immediately increments `line_width`. When `fits()` returns `Fits::Yes` via the expanded-mode line break path (line 1040), the pending space is never resolved. For the decorator case: 1. After `@property(...)` + space + `tooltipPlacement` + `:` → `line_width = 80` 2. `Space` after `:` → `pending_space = true` (line_width stays 80) 3. Union type group inherits Expanded mode → `if_group_breaks(separator)` included 4. Separator's `SoftOrSpace` in Expanded mode → `return Fits::Yes` **without resolving pending_space** 5. The +1 char from the space is lost, making the decorator group incorrectly "fit" ### Fix Resolve `pending_space` before returning `Fits::Yes` from the expanded-mode early exit path. This matches Ruff's approach where `Space` is counted eagerly via `fits_text(Text::Token(" "))`. ### Conformance - JS: 746/753 (unchanged) - TS: 591/601 (unchanged — `18148.ts` fixed, `comment.ts` regressed) The `comment.ts` regression (`typescript/union/consistent-with-flow/comment.ts`) is a **pre-existing Prettier bug** — at `printWidth: 81`, Prettier itself produces the same double-indented output with a spurious blank line: ```ts // printWidth: 81 → Prettier also double-indents: type SuperLong...Blaa = ← spurious blank line | Fooo1000 ← 4 spaces (double indent) ``` At exactly 80 chars, Prettier avoids this only because its own fits check has the same off-by-one (the space is not counted), causing the Fluid layout's inner group to accidentally "fit". ## Test plan - [x] `cargo test -p oxc_formatter` — 262 passed - [x] `cargo test -p oxc_formatter -- fixtures` — 213 passed (including new `issue-20519.ts`) - [x] `cargo run -p oxc_prettier_conformance` — JS 746/753, TS 591/601 - [x] `cargo clippy -p oxc_formatter` — clean 🤖 Generated with [Claude Code](https://claude.com/claude-code)

Fixes #20519
This ensures that the
print_widthis calculated correctly infits().