From 29f41bec568429c0aa85e7e878dd9e48baf13540 Mon Sep 17 00:00:00 2001 From: Boshen Date: Tue, 20 Jan 2026 17:09:26 +0000 Subject: [PATCH] fix(formatter): only expand mapped types when newline immediately follows opening brace (#18087) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Fixed mapped type expansion logic to match Prettier's behavior - Only expand when there's a newline immediately after `{`, not when there's a newline anywhere before the property name ## Examples **Before (incorrect):** ```ts // Input: { readonly\n [A in B]: T} // Output (wrong - expanded): type A3 = { readonly [A in B]: T; }; ``` **After (correct):** ```ts // Input: { readonly\n [A in B]: T} // Output (correct - single line): type A3 = { readonly [A in B]: T }; ``` ## Test plan - [x] `cargo run -p oxc_prettier_conformance -- --filter mapped-type` - `break-mode.ts` now passes - [x] TS conformance improved from 584/606 (96.37%) to 585/606 (96.53%) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- crates/oxc_formatter/src/print/mapped_type.rs | 25 +++++++++---------- .../snapshots/prettier.ts.snap.md | 3 +-- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/crates/oxc_formatter/src/print/mapped_type.rs b/crates/oxc_formatter/src/print/mapped_type.rs index f2a96c8913a71..40780e5c35fd3 100644 --- a/crates/oxc_formatter/src/print/mapped_type.rs +++ b/crates/oxc_formatter/src/print/mapped_type.rs @@ -19,7 +19,7 @@ impl<'a> FormatWrite<'a> for AstNode<'a, TSMappedType<'a>> { let key = self.key(); let constraint = self.constraint(); let name_type = self.name_type(); - let should_expand = has_line_break_before_property_name(self, f.source_text()); + let should_expand = has_line_break_after_opening_brace(self, f.source_text()); let format_inner = format_with(|f| { if should_expand { @@ -84,16 +84,15 @@ impl<'a> FormatWrite<'a> for AstNode<'a, TSMappedType<'a>> { } } -/// Check if the user introduced a new line inside the node, but only if -/// that new line occurs at or before the property name. For example, -/// this would break: -/// { [ -/// A in B]: T} -/// Because the line break occurs before `A`, the property name. But this -/// would _not_ break: -/// { [A -/// in B]: T} -/// Because the break is _after_ the `A`. -fn has_line_break_before_property_name(node: &TSMappedType, f: SourceText) -> bool { - f.contains_newline_between(node.span.start, node.key.span.start) +/// Check if the user introduced a new line immediately after the opening brace. +/// For example, this would break: +/// { +/// readonly [A in B]: T} +/// Because the line break occurs right after `{`. But this would _not_ break: +/// { readonly +/// [A in B]: T} +/// Because the break is not immediately after `{`. +fn has_line_break_after_opening_brace(node: &TSMappedType, f: SourceText) -> bool { + // Check if there's a newline immediately after `{` (before any non-whitespace) + f.has_newline_after(node.span.start + 1) } diff --git a/tasks/prettier_conformance/snapshots/prettier.ts.snap.md b/tasks/prettier_conformance/snapshots/prettier.ts.snap.md index c1a9ab5ebd3b6..9e1cb7fbf951a 100644 --- a/tasks/prettier_conformance/snapshots/prettier.ts.snap.md +++ b/tasks/prettier_conformance/snapshots/prettier.ts.snap.md @@ -1,4 +1,4 @@ -ts compatibility: 584/605 (96.53%) +ts compatibility: 585/605 (96.69%) # Failed @@ -17,7 +17,6 @@ ts compatibility: 584/605 (96.53%) | typescript/interface2/comments-ts-only/18278.ts | 💥 | 95.65% | | typescript/last-argument-expansion/decorated-function.tsx | 💥 | 29.06% | | typescript/mapped-type/issue-11098.ts | 💥 | 97.03% | -| typescript/mapped-type/break-mode/break-mode.ts | 💥 | 68.75% | | typescript/property-signature/consistent-with-flow/comments.ts | 💥 | 80.00% | | typescript/top-level-await/test.ts | 💥 | 0.00% | | typescript/top-level-await/test.tsx | 💥 | 0.00% |