Skip to content

Comments

fix(formatter): JSX text wrapping incorrect 2#16320

Merged
graphite-app[bot] merged 1 commit intomainfrom
12-01-fix_formatter_jsx_text_wrapping_incorrect_2
Dec 3, 2025
Merged

fix(formatter): JSX text wrapping incorrect 2#16320
graphite-app[bot] merged 1 commit intomainfrom
12-01-fix_formatter_jsx_text_wrapping_incorrect_2

Conversation

@Dunqing
Copy link
Member

@Dunqing Dunqing commented Dec 1, 2025

Two tests regressed, but I kind of think they are correct. I created prettier/prettier#18384 to confirm the issue in Prettier. Aligned with Prettier's current behavior

Copy link
Member Author

Dunqing commented Dec 1, 2025


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • 0-merge - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

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.

@codspeed-hq
Copy link

codspeed-hq bot commented Dec 1, 2025

CodSpeed Performance Report

Merging #16320 will not alter performance

Comparing 12-01-fix_formatter_jsx_text_wrapping_incorrect_2 (018f092) with main (b86d3e3)1

Summary

✅ 38 untouched
⏩ 7 skipped2

Footnotes

  1. No successful run was found on main (a4edb2b) during the generation of this report, so b86d3e3 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

  2. 7 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@Dunqing
Copy link
Member Author

Dunqing commented Dec 1, 2025

@leaysgur I just got confirmation from Prettier that these two cases are known issues. Can you run the build for this PR and check in next.js to see if that case is resolved and ensure there are no other cases that have failed? If so, I think we can merge it without waiting for a Prettier fix.

@leaysgur
Copy link
Member

leaysgur commented Dec 1, 2025

This branch vs prettier@3.7.3, diffs are below:

modified:   examples/markdoc/next.config.js
modified:   examples/prisma-postgres/app/setup/page.tsx
modified:   examples/with-azure-cosmos/pages/index.tsx
modified:   examples/with-mongodb/app/app-demo/page.tsx
modified:   examples/with-mongodb/pages/index.tsx
modified:   examples/with-passport/lib/password-local.js
modified:   packages/next/src/build/webpack-config.ts
modified:   packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts
modified:   packages/next/src/next-devtools/dev-overlay/components/errors/dev-tools-indicator/dev-tools-info/route-info.tsx
modified:   packages/next/src/next-devtools/dev-overlay/container/errors.tsx
modified:   packages/next/taskfile.js
modified:   test/e2e/app-dir/router-stuck-dynamic-static-segment/app/page.tsx
modified:   turbopack/crates/turbopack-tracing/tests/node-file-trace/integration/webpack-target-node/webpack-api-runtime.js
modified:   turbopack/crates/turbopack-tracing/tests/node-file-trace/test/unit/webpack-wrapper-strs-namespaces-large/input.js

And these files are related to {' '}.

  • examples/prisma-postgres/app/setup/page.tsx
  • examples/with-azure-cosmos/pages/index.tsx
  • examples/with-mongodb/app/app-demo/page.tsx
  • examples/with-mongodb/pages/index.tsx
  • packages/next/src/next-devtools/dev-overlay/components/errors/dev-tools-indicator/dev-tools-info/route-info.tsx
  • packages/next/src/next-devtools/dev-overlay/container/errors.tsx
  • test/e2e/app-dir/router-stuck-dynamic-static-segment/app/page.tsx

and diff:

diff --git a/examples/prisma-postgres/app/setup/page.tsx b/examples/prisma-postgres/app/setup/page.tsx
index 49b6897b..7cba513d 100644
--- a/examples/prisma-postgres/app/setup/page.tsx
+++ b/examples/prisma-postgres/app/setup/page.tsx
@@ -101,7 +101,9 @@ export default function SetupPage() {
                 described in the next step.
               </li>
               <li>
-                In your Netlify account, click the <strong>Extensions</strong>{" "}
+                In your Netlify account, click the <strong>
+                  Extensions
+                </strong>{" "}
                 tab in the left-hand sidenav and navigate to the installed{" "}
                 <strong>Prisma Postgres</strong> extension. Then find the text
                 field for the <strong>Integration token</strong>, paste the
@@ -122,7 +124,9 @@ export default function SetupPage() {
             </p>
             <ol className="list-decimal pl-6 mt-2 space-y-1 text-gray-700">
               <li>
-                In your Netlify Dashboard, click on the <strong>Sites</strong>{" "}
+                In your Netlify Dashboard, click on the <strong>
+                  Sites
+                </strong>{" "}
                 item in the left-hand sidenav and click on the site that was
                 deployed with this template.
               </li>
@@ -159,7 +163,9 @@ export default function SetupPage() {
             </p>
             <ol className="list-decimal pl-6 mt-2 space-y-1 text-gray-700">
               <li>
-                In your Netlify Dashboard, click on the <strong>Sites</strong>{" "}
+                In your Netlify Dashboard, click on the <strong>
+                  Sites
+                </strong>{" "}
                 item in the left-hand sidenav and click on the site that was
                 deployed with this template.
               </li>
diff --git a/examples/with-azure-cosmos/pages/index.tsx b/examples/with-azure-cosmos/pages/index.tsx
index 1d04a7a4..9a485e05 100644
--- a/examples/with-azure-cosmos/pages/index.tsx
+++ b/examples/with-azure-cosmos/pages/index.tsx
@@ -29,7 +29,9 @@ const Home = (props: Props) => {
         <h2 className="subtitle">You are connected to CosmosDB</h2>
       ) : (
         <h2 className="subtitle">
-          You are NOT connected to CosmosDB. Check the <code>README.md</code>{" "}
+          You are NOT connected to CosmosDB. Check the <code>
+            README.md
+          </code>{" "}
           for instructions.
         </h2>
       )}
diff --git a/examples/with-mongodb/app/app-demo/page.tsx b/examples/with-mongodb/app/app-demo/page.tsx
index 0e8dd9f8..29973407 100644
--- a/examples/with-mongodb/app/app-demo/page.tsx
+++ b/examples/with-mongodb/app/app-demo/page.tsx
@@ -58,7 +58,9 @@ export default async function Home() {
           </h2>
         ) : (
           <h2 className="text-lg text-red-500">
-            You are NOT connected to MongoDB. Check the <code>README.md</code>{" "}
+            You are NOT connected to MongoDB. Check the <code>
+              README.md
+            </code>{" "}
             for instructions.
           </h2>
         )}
diff --git a/examples/with-mongodb/pages/index.tsx b/examples/with-mongodb/pages/index.tsx
index b5292dd5..ab0b0975 100644
--- a/examples/with-mongodb/pages/index.tsx
+++ b/examples/with-mongodb/pages/index.tsx
@@ -84,7 +84,9 @@ export default function Home({
           </h2>
         ) : (
           <h2 className="text-lg text-red-500">
-            You are NOT connected to MongoDB. Check the <code>README.md</code>{" "}
+            You are NOT connected to MongoDB. Check the <code>
+              README.md
+            </code>{" "}
             for instructions.
           </h2>
         )}
diff --git a/packages/next/src/next-devtools/dev-overlay/components/errors/dev-tools-indicator/dev-tools-info/route-info.tsx b/packages/next/src/next-devtools/dev-overlay/components/errors/dev-tools-indicator/dev-tools-info/route-info.tsx
index 066cec4d..1d9f8f70 100644
--- a/packages/next/src/next-devtools/dev-overlay/components/errors/dev-tools-indicator/dev-tools-info/route-info.tsx
+++ b/packages/next/src/next-devtools/dev-overlay/components/errors/dev-tools-indicator/dev-tools-info/route-info.tsx
@@ -8,7 +8,9 @@ function StaticRouteContent({
     <article className="dev-tools-info-article" {...props}>
       <p className="dev-tools-info-paragraph">
         The path{' '}
-        <code className="dev-tools-info-code">{window.location.pathname}</code>{' '}
+        <code className="dev-tools-info-code">
+          {window.location.pathname}
+        </code>{' '}
         is marked as "static" since it will be prerendered during the build
         time.
       </p>
@@ -46,7 +48,9 @@ function DynamicRouteContent({
     <article className="dev-tools-info-article" {...props}>
       <p className="dev-tools-info-paragraph">
         The path{' '}
-        <code className="dev-tools-info-code">{window.location.pathname}</code>{' '}
+        <code className="dev-tools-info-code">
+          {window.location.pathname}
+        </code>{' '}
         is marked as "dynamic" since it will be rendered for each user at{' '}
         <strong>request time</strong>.
       </p>
diff --git a/packages/next/src/next-devtools/dev-overlay/container/errors.tsx b/packages/next/src/next-devtools/dev-overlay/container/errors.tsx
index 3768e40b..4354a38e 100644
--- a/packages/next/src/next-devtools/dev-overlay/container/errors.tsx
+++ b/packages/next/src/next-devtools/dev-overlay/container/errors.tsx
@@ -245,7 +245,9 @@ function BlockingPageLoadErrorDescription({
           </p>
           <p>
             <code>params</code> are usually considered Runtime data but if all
-            params are provided a value using <code>generateStaticParams</code>{' '}
+            params are provided a value using <code>
+              generateStaticParams
+            </code>{' '}
             they can be statically prerendered.
           </p>
           <p>
diff --git a/test/e2e/app-dir/router-stuck-dynamic-static-segment/app/page.tsx b/test/e2e/app-dir/router-stuck-dynamic-static-segment/app/page.tsx
index 64b89e01..e31689c7 100644
--- a/test/e2e/app-dir/router-stuck-dynamic-static-segment/app/page.tsx
+++ b/test/e2e/app-dir/router-stuck-dynamic-static-segment/app/page.tsx
@@ -20,7 +20,9 @@ export default function Home() {
       <p>
         Reloading and pressing the "Go to another page" link and then going to
         the blog post does work however, suggesting the issue is navigating from{' '}
-        <code>/blog</code> to <code>/blog/a-post</code> (<code>/[slug]</code>{' '}
+        <code>/blog</code> to <code>/blog/a-post</code> (<code>
+          /[slug]
+        </code>{' '}
         where slug is blog and <code>/blog/[slug]</code> where slug is a-post)
       </p>
       <Link href="/blog" style={{ display: 'block' }} id="to-blog">

If {' '} is now being counted correctly and triggering a break, this appears to be a reasonable.

But I'm not sure break position is intuitive or not.

input:

//3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
//     10|       20|       30|       40|       50|       60|       70|       80|       90|
export default function Home() {
  return (
    <div>
      <p>
        Reloading and pressing the "Go to another page" link and then going to
        the blog post does work however, suggesting the issue is navigating from{' '}
        <code>/blog</code> to <code>/blog/a-post</code> (<code>/[slug]</code>{' '}
        where slug is blog and <code>/blog/[slug]</code> where slug is a-post)
      </p>
    </div>
  )
}

oxfmt:

//3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
//     10|       20|       30|       40|       50|       60|       70|       80|       90|
export default function Home() {
  return (
    <div>
      <p>
        Reloading and pressing the "Go to another page" link and then going to
        the blog post does work however, suggesting the issue is navigating from{" "}
        <code>/blog</code> to <code>/blog/a-post</code> (<code>
          /[slug]
        </code>{" "}
        where slug is blog and <code>/blog/[slug]</code> where slug is a-post)
      </p>
    </div>
  );
}

prettier@3.7.3

//3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
//     10|       20|       30|       40|       50|       60|       70|       80|       90|
export default function Home() {
  return (
    <div>
      <p>
        Reloading and pressing the "Go to another page" link and then going to
        the blog post does work however, suggesting the issue is navigating from{" "}
        <code>/blog</code> to <code>/blog/a-post</code> (<code>/[slug]</code>{" "}
        where slug is blog and <code>/blog/[slug]</code> where slug is a-post)
      </p>
    </div>
  );
}

@leaysgur
Copy link
Member

leaysgur commented Dec 1, 2025

For original issue: #16199, now it produces the same result.

@Dunqing Dunqing force-pushed the 12-01-fix_formatter_jsx_text_wrapping_incorrect_2 branch from 8e258fa to 5c8912f Compare December 1, 2025 05:31
@Dunqing Dunqing force-pushed the 12-01-refactor_formatter_clean_up_dead_code_in_jsx branch from 47f8821 to cfab9df Compare December 1, 2025 05:31
@Dunqing
Copy link
Member Author

Dunqing commented Dec 1, 2025

Thank you for testing it. Since it would produce more differences and some cases should be improved further, I will leave this PR until it exactly matches the current Prettier output.

@graphite-app graphite-app bot changed the base branch from 12-01-refactor_formatter_clean_up_dead_code_in_jsx to graphite-base/16320 December 1, 2025 05:45
@graphite-app graphite-app bot force-pushed the 12-01-fix_formatter_jsx_text_wrapping_incorrect_2 branch from 5c8912f to 6d58044 Compare December 1, 2025 05:50
@graphite-app graphite-app bot force-pushed the graphite-base/16320 branch from cfab9df to 2b8f982 Compare December 1, 2025 05:50
@graphite-app graphite-app bot changed the base branch from graphite-base/16320 to main December 1, 2025 05:51
@graphite-app graphite-app bot force-pushed the 12-01-fix_formatter_jsx_text_wrapping_incorrect_2 branch from 6d58044 to 85eafe6 Compare December 1, 2025 05:51
@Dunqing Dunqing force-pushed the 12-01-fix_formatter_jsx_text_wrapping_incorrect_2 branch 3 times, most recently from 1dc064e to ebc9cb9 Compare December 3, 2025 06:37
@Dunqing
Copy link
Member Author

Dunqing commented Dec 3, 2025

Finally, I figured out why it produces different output while the IR/Doc is basically the same. This is due to the slight differences in handling measured_group_fits in the Oxfmt compared to Prettier, which is called as shouldRemeasure in Prettier and represents the opposite meaning.

After exactly matching what shouldRemeasure does in Prettier, two regressed cases are gone.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a JSX text wrapping issue (#16199) by modifying how the formatter's printer tracks whether groups fit on a single line. The key change is refactoring the initialization of measured_group_fits state and removing redundant state resets during printing.

  • Refactored PrinterState initialization to use a dedicated constructor method
  • Removed manual state resets for measured_group_fits that were preventing correct text wrapping
  • Added comprehensive test coverage for the fix with snapshots at different print widths

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
crates/oxc_formatter/src/formatter/printer/mod.rs Adds PrinterState::new() constructor with explicit measured_group_fits initialization; removes redundant state resets after measuring fill entries and line breaks
crates/oxc_formatter/tests/fixtures/js/jsx/issue-16199.jsx Test input file demonstrating the JSX text wrapping scenario that was incorrectly formatted
crates/oxc_formatter/tests/fixtures/js/jsx/issue-16199.jsx.snap Snapshot file showing expected formatter output at printWidth 80 and 100, verifying the fix works correctly

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Member

@leaysgur leaysgur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also confirmed all {' '} related diffs in next.js repo are gone... 👍🏻

@leaysgur leaysgur added the 0-merge Merge with Graphite Merge Queue label Dec 3, 2025
Copy link
Member

leaysgur commented Dec 3, 2025

Merge activity

* close: #16199

~~Two tests regressed, but I kind of think they are correct. I created prettier/prettier#18384 to confirm the issue in Prettier.~~ Aligned with Prettier's current behavior
@graphite-app graphite-app bot force-pushed the 12-01-fix_formatter_jsx_text_wrapping_incorrect_2 branch from 018f092 to ee0756b Compare December 3, 2025 06:59
@graphite-app graphite-app bot merged commit ee0756b into main Dec 3, 2025
20 checks passed
@graphite-app graphite-app bot deleted the 12-01-fix_formatter_jsx_text_wrapping_incorrect_2 branch December 3, 2025 07:05
@graphite-app graphite-app bot removed the 0-merge Merge with Graphite Merge Queue label Dec 3, 2025
overlookmotel pushed a commit that referenced this pull request Dec 8, 2025
# Oxlint
### 🚀 Features

- 5c62c16 linter/plugins: Allow JS plugins to access `globals` (#16512)
(Arsh)
- ba7bd51 linter: Implement no-useless-return rule (#16388) (FMP1783)
- fa605df linter: Fix `arrow-body-style` automatically (#16252) (Hamir
Mahal)
- 7584938 linter/plugins: Add ESLint compat mode to `RuleTester`
(#16538) (overlookmotel)
- b38c2d0 linter/plugins: Add `SourceCode#lineStartIndices` getter
(#16510) (overlookmotel)
- ba93ffc linter/plugins: Add `SourceCode#tokensAndComments` getter
(#16503) (overlookmotel)
- d2ca540 linter/plugins: Add `SourceCode#isESTree` property (#16499)
(overlookmotel)
- 9001234 linter: Add fix support for tsgolint diagnostics (#16344)
(camc314)
- 2d6bb85 editors: Toggle client after vscode config changing (#16162)
(Liang Mi)
- 0ec454c linter/plugins: Merge default options into options (#16358)
(overlookmotel)

### 🐛 Bug Fixes

- a806d74 linter: Use import type for ESTree in visitor.d.ts (#16472)
(camc314)
- 8933c84 linter: Fix jest/expect-expect rule docs. (#16550)
(connorshea)
- 1c08879 linter: Fix false positive in no-invalid-fetch-options for
conditional expressions (#16570) (camc314)
- 1a69b06 linter: Junit support for multiple files/errors/diagnostics
(#16568) (Shrey Sudhir)
- a7d435b linter/sort-keys: Preserve multi-line formatting in autofix
(#16563) (camc314)
- fd84dcc linter/plugins: `RuleTester` parser catch fatal errors
(#16558) (overlookmotel)
- ab4deb0 linter/plugins: Improve safety of options merging (#16549)
(overlookmotel)
- a58c76a linter: Fix the `react/jsx-fragments` rule config to take a
string argument (#16175) (connorshea)
- f7751cc linter/plugins: Fix TS types for `RuleTester` (#16546)
(overlookmotel)
- 6d33320 linter/plugins: Prevent user modifying the default config
(#16545) (overlookmotel)
- b4483c5 linter/plugins: Add config support skeleton to `RuleTester`
(#16537) (overlookmotel)
- 3a49158 linter/plugins: Improve TS types for tokens (#16502)
(overlookmotel)
- 0c14531 oxlint/lsp: Revalidate all known files after internal restart
(#16407) (Sysix)
- 2d3217e linter/plugins: Remove panics from `lint_file` and
`setup_configs` (#16453) (overlookmotel)
- 655341b linter/oxc: Not emit error when the threshold is zero and we
haven't detected a barrel file (#16455) (Said Atrahouch)
- b9f359f linter/no-var: Expand fix span to prevent conflicts with other
rules (#16445) (camc314)
- c6778f3 linter: Preserve original quote style in no-hex-escape fixer
(#16410) (camc314)
- 3ad913b linter: Improve rule docs page autofix description (#16281)
(Hamir Mahal)
- 0b7e00c linter: Handle keyword unary expressions in yoda rule fix
(#16402) (camc314)
- 5fd3096 lsp: Skip (un)registering file watcher when not dynamic
watchers are supported (#16406) (Sysix)
- 804144f lsp: Respect `null` as invalid settings for
`workspace/didChangeConfiguration` (#16361) (Sysix)
- 723a7e5 linter: Prevent invalid BigInt literal fix for exponential
notation (#16401) (camc314)
- 2589fb1 linter: Fix prefer_expect_resolves fixer for member
expressions (#16393) (camc314)
- 428c7cd linter: Wrap logical expressions in parentheses when fixing
no-extra-boolean-cast (#16363) (camc314)
- 3903567 linter: Skip prefer-string-raw in type annotations and .d.ts
files (#16382) (camc314)
- d490daa linter/func-names: Use centralized reserved keyword check and
fix ancestor traversal (#16362) (camc314)
- d846c53 tsgolint: Use `expect` when sending diagnostics (#16341)
(camc314)
- 114665d lsp: Watch for files when workspace folder is added &
`workspace/configuration` is not supported (#16307) (Sysix)
- f5d0ebb linter/func-names: Avoid suggesting reserved keywords as
function names (#16352) (camc314)
- d268135 linter/no-console-spaces: Preserve escape sequences in fixer
output (#16349) (camc314)
- b02c21a linter/valid-title: Preserve escape sequences in fixer output
(#16348) (camc314)
- 2373b76 linter/no-untyped-mock-factory: Fix fixer producing invalid
syntax when newline exists after opening paren (#16351) (camc314)

### ⚡ Performance

- 67cfa58 lsp: Avoid some clones (#16519) (Sysix)
- 2a09665 oxlint/lsp: Store only `LinterCodeAction` instead of the
complete `DiagnosticReport` (#16516) (Sysix)
- 0ca9754 lsp: Avoid `Uri` to `String` and back to `Uri` conversion
(#16470) (Sysix)
- 2736636 lsp: Avoid cloning when revalidating diagnostics (#16469)
(Sysix)
- 793b989 linter/plugins: Move result-processing work off main JS thread
(#16456) (overlookmotel)
- 44dff7b linter/plugins: Skip serialization overhead when no errors
(#16443) (overlookmotel)
- 1aa2409 linter/plugins: Do not remove `messageId` field from
`DiagnosticReport` before sending to Rust (#16442) (overlookmotel)
- 5017db8 linter/plugins: Reduce calls to `Path::to_string_lossy`
(#16429) (overlookmotel)
- 194e357 linter: Use `SmallVec` for rule options (#16400) (Copilot)
- e31b2bd linter: Only clone config if required (#16350) (overlookmotel)
- 3026086 linter: Avoid cloning rule options (#16338) (overlookmotel)

### 📚 Documentation

- fef77af linter: Fix `jsx-a11y/img-redundant-alt` configuration option
names. (#16552) (connorshea)
- c0766df linter: Add config option docs for `unicorn/filename-case`
rule. (#16280) (connorshea)
- e24aabd linter/plugins: Correct comment (#16559) (overlookmotel)
- 514c724 linter: Fix the name of the IIFEs config option in
eslint/max-lines-per-function (#16554) (connorshea)
- 4d94438 linter/rules: Correct arrow body style options in
documentation (#16509) (GRK)
- 6bac4ec linter: Pull configuration struct doc comment when rendering
config docs (#16288) (connorshea)
- 8c85e08 linter/plugins: Add TODO comment (#16511) (overlookmotel)
- a9b9298 linter/plugins: Add JSDoc comments to `SourceCode` properties
(#16497) (overlookmotel)
- 467cc1a linter/plugins: Improve comment on error branch (#16464)
(overlookmotel)
- 041b119 linter: Add config option docs to `jest/consistent-test-it`
rule. (#16286) (connorshea)

### 🛡️ Security

- d90ef9f deps: Update dependency rolldown to v1.0.0-beta.53 (#16428)
(renovate[bot])
# Oxfmt
### 🚀 Features

- 3184f17 oxfmt: Pass filepath field to prettier formatting (#16591)
(Yuji Sugiura)
- 7bb3304 oxfmt: Pass populated config to prettier formatting (#16584)
(leaysgur)
- 69f84d2 oxfmt: Pass raw config to prettier formatting (#16582)
(leaysgur)
- a83a2ec oxfmt: Expose `setupConfig(configJSON: string)` napi callback
(#16579) (leaysgur)
- 930533f formatter: Convert single `\r` to `\n` in string and add a
debug assertion to ensure that there is no `\r` in the text (#16531)
(Dunqing)
- af76b0e oxfmt: Support formatting HTML, YAML, GraphQL, Handlerbars,
Markdown, CSS files (#16524) (leaysgur)
- 66b64ef oxfmt: Support formatting JSON files (#16523) (leaysgur)
- 4767926 oxfmt: Prepare non-js/ts file support with prettier (#16480)
(leaysgur)
- 2b4ce5d oxfmt: Use dedicated `format_by_xxx_formatter` method by
`SourceType` (#16417) (leaysgur)
- 0867d2f oxfmt: Set up JS `formatFile()` function for Rust via napi
(#16415) (leaysgur)
- b6feb66 oxfmt: Rename `embedded.ts` with preparing `formatFile()`
function (#16414) (leaysgur)
- 80e6999 formatter: Add debug assertion to ensure that there is no
empty content is passed in (#16475) (Dunqing)
- 7374856 formatter/sort-imports: Support `options.internalPattern`
(#16372) (leaysgur)
- dd2cb62 oxfmt: Not error on explicit `--write` flag used (#16376)
(leaysgur)

### 🐛 Bug Fixes

- 40b0134 formatter: Incorrect formatting of `useImperativeHandle` hook
(#16533) (Dunqing)
- 75393e7 formatter: Incorrect handling of `CRLF` for multiline block
comment (#16528) (Dunqing)
- ee0756b formatter: JSX text wrapping incorrect 2 (#16320) (Dunqing)
- 36308b8 formatter: Fix indent for new expression with type cast
(#16380) (leaysgur)

### ⚡ Performance

- 6f16a8f formatter: Avoid using an indent with a empty content (#16474)
(Dunqing)
- 201c98f formatter: Early return when no comments need to be printed
(#16432) (Dunqing)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Copilot AI pushed a commit that referenced this pull request Dec 10, 2025
# Oxlint
### 🚀 Features

- 5c62c16 linter/plugins: Allow JS plugins to access `globals` (#16512)
(Arsh)
- ba7bd51 linter: Implement no-useless-return rule (#16388) (FMP1783)
- fa605df linter: Fix `arrow-body-style` automatically (#16252) (Hamir
Mahal)
- 7584938 linter/plugins: Add ESLint compat mode to `RuleTester`
(#16538) (overlookmotel)
- b38c2d0 linter/plugins: Add `SourceCode#lineStartIndices` getter
(#16510) (overlookmotel)
- ba93ffc linter/plugins: Add `SourceCode#tokensAndComments` getter
(#16503) (overlookmotel)
- d2ca540 linter/plugins: Add `SourceCode#isESTree` property (#16499)
(overlookmotel)
- 9001234 linter: Add fix support for tsgolint diagnostics (#16344)
(camc314)
- 2d6bb85 editors: Toggle client after vscode config changing (#16162)
(Liang Mi)
- 0ec454c linter/plugins: Merge default options into options (#16358)
(overlookmotel)

### 🐛 Bug Fixes

- a806d74 linter: Use import type for ESTree in visitor.d.ts (#16472)
(camc314)
- 8933c84 linter: Fix jest/expect-expect rule docs. (#16550)
(connorshea)
- 1c08879 linter: Fix false positive in no-invalid-fetch-options for
conditional expressions (#16570) (camc314)
- 1a69b06 linter: Junit support for multiple files/errors/diagnostics
(#16568) (Shrey Sudhir)
- a7d435b linter/sort-keys: Preserve multi-line formatting in autofix
(#16563) (camc314)
- fd84dcc linter/plugins: `RuleTester` parser catch fatal errors
(#16558) (overlookmotel)
- ab4deb0 linter/plugins: Improve safety of options merging (#16549)
(overlookmotel)
- a58c76a linter: Fix the `react/jsx-fragments` rule config to take a
string argument (#16175) (connorshea)
- f7751cc linter/plugins: Fix TS types for `RuleTester` (#16546)
(overlookmotel)
- 6d33320 linter/plugins: Prevent user modifying the default config
(#16545) (overlookmotel)
- b4483c5 linter/plugins: Add config support skeleton to `RuleTester`
(#16537) (overlookmotel)
- 3a49158 linter/plugins: Improve TS types for tokens (#16502)
(overlookmotel)
- 0c14531 oxlint/lsp: Revalidate all known files after internal restart
(#16407) (Sysix)
- 2d3217e linter/plugins: Remove panics from `lint_file` and
`setup_configs` (#16453) (overlookmotel)
- 655341b linter/oxc: Not emit error when the threshold is zero and we
haven't detected a barrel file (#16455) (Said Atrahouch)
- b9f359f linter/no-var: Expand fix span to prevent conflicts with other
rules (#16445) (camc314)
- c6778f3 linter: Preserve original quote style in no-hex-escape fixer
(#16410) (camc314)
- 3ad913b linter: Improve rule docs page autofix description (#16281)
(Hamir Mahal)
- 0b7e00c linter: Handle keyword unary expressions in yoda rule fix
(#16402) (camc314)
- 5fd3096 lsp: Skip (un)registering file watcher when not dynamic
watchers are supported (#16406) (Sysix)
- 804144f lsp: Respect `null` as invalid settings for
`workspace/didChangeConfiguration` (#16361) (Sysix)
- 723a7e5 linter: Prevent invalid BigInt literal fix for exponential
notation (#16401) (camc314)
- 2589fb1 linter: Fix prefer_expect_resolves fixer for member
expressions (#16393) (camc314)
- 428c7cd linter: Wrap logical expressions in parentheses when fixing
no-extra-boolean-cast (#16363) (camc314)
- 3903567 linter: Skip prefer-string-raw in type annotations and .d.ts
files (#16382) (camc314)
- d490daa linter/func-names: Use centralized reserved keyword check and
fix ancestor traversal (#16362) (camc314)
- d846c53 tsgolint: Use `expect` when sending diagnostics (#16341)
(camc314)
- 114665d lsp: Watch for files when workspace folder is added &
`workspace/configuration` is not supported (#16307) (Sysix)
- f5d0ebb linter/func-names: Avoid suggesting reserved keywords as
function names (#16352) (camc314)
- d268135 linter/no-console-spaces: Preserve escape sequences in fixer
output (#16349) (camc314)
- b02c21a linter/valid-title: Preserve escape sequences in fixer output
(#16348) (camc314)
- 2373b76 linter/no-untyped-mock-factory: Fix fixer producing invalid
syntax when newline exists after opening paren (#16351) (camc314)

### ⚡ Performance

- 67cfa58 lsp: Avoid some clones (#16519) (Sysix)
- 2a09665 oxlint/lsp: Store only `LinterCodeAction` instead of the
complete `DiagnosticReport` (#16516) (Sysix)
- 0ca9754 lsp: Avoid `Uri` to `String` and back to `Uri` conversion
(#16470) (Sysix)
- 2736636 lsp: Avoid cloning when revalidating diagnostics (#16469)
(Sysix)
- 793b989 linter/plugins: Move result-processing work off main JS thread
(#16456) (overlookmotel)
- 44dff7b linter/plugins: Skip serialization overhead when no errors
(#16443) (overlookmotel)
- 1aa2409 linter/plugins: Do not remove `messageId` field from
`DiagnosticReport` before sending to Rust (#16442) (overlookmotel)
- 5017db8 linter/plugins: Reduce calls to `Path::to_string_lossy`
(#16429) (overlookmotel)
- 194e357 linter: Use `SmallVec` for rule options (#16400) (Copilot)
- e31b2bd linter: Only clone config if required (#16350) (overlookmotel)
- 3026086 linter: Avoid cloning rule options (#16338) (overlookmotel)

### 📚 Documentation

- fef77af linter: Fix `jsx-a11y/img-redundant-alt` configuration option
names. (#16552) (connorshea)
- c0766df linter: Add config option docs for `unicorn/filename-case`
rule. (#16280) (connorshea)
- e24aabd linter/plugins: Correct comment (#16559) (overlookmotel)
- 514c724 linter: Fix the name of the IIFEs config option in
eslint/max-lines-per-function (#16554) (connorshea)
- 4d94438 linter/rules: Correct arrow body style options in
documentation (#16509) (GRK)
- 6bac4ec linter: Pull configuration struct doc comment when rendering
config docs (#16288) (connorshea)
- 8c85e08 linter/plugins: Add TODO comment (#16511) (overlookmotel)
- a9b9298 linter/plugins: Add JSDoc comments to `SourceCode` properties
(#16497) (overlookmotel)
- 467cc1a linter/plugins: Improve comment on error branch (#16464)
(overlookmotel)
- 041b119 linter: Add config option docs to `jest/consistent-test-it`
rule. (#16286) (connorshea)

### 🛡️ Security

- d90ef9f deps: Update dependency rolldown to v1.0.0-beta.53 (#16428)
(renovate[bot])
# Oxfmt
### 🚀 Features

- 3184f17 oxfmt: Pass filepath field to prettier formatting (#16591)
(Yuji Sugiura)
- 7bb3304 oxfmt: Pass populated config to prettier formatting (#16584)
(leaysgur)
- 69f84d2 oxfmt: Pass raw config to prettier formatting (#16582)
(leaysgur)
- a83a2ec oxfmt: Expose `setupConfig(configJSON: string)` napi callback
(#16579) (leaysgur)
- 930533f formatter: Convert single `\r` to `\n` in string and add a
debug assertion to ensure that there is no `\r` in the text (#16531)
(Dunqing)
- af76b0e oxfmt: Support formatting HTML, YAML, GraphQL, Handlerbars,
Markdown, CSS files (#16524) (leaysgur)
- 66b64ef oxfmt: Support formatting JSON files (#16523) (leaysgur)
- 4767926 oxfmt: Prepare non-js/ts file support with prettier (#16480)
(leaysgur)
- 2b4ce5d oxfmt: Use dedicated `format_by_xxx_formatter` method by
`SourceType` (#16417) (leaysgur)
- 0867d2f oxfmt: Set up JS `formatFile()` function for Rust via napi
(#16415) (leaysgur)
- b6feb66 oxfmt: Rename `embedded.ts` with preparing `formatFile()`
function (#16414) (leaysgur)
- 80e6999 formatter: Add debug assertion to ensure that there is no
empty content is passed in (#16475) (Dunqing)
- 7374856 formatter/sort-imports: Support `options.internalPattern`
(#16372) (leaysgur)
- dd2cb62 oxfmt: Not error on explicit `--write` flag used (#16376)
(leaysgur)

### 🐛 Bug Fixes

- 40b0134 formatter: Incorrect formatting of `useImperativeHandle` hook
(#16533) (Dunqing)
- 75393e7 formatter: Incorrect handling of `CRLF` for multiline block
comment (#16528) (Dunqing)
- ee0756b formatter: JSX text wrapping incorrect 2 (#16320) (Dunqing)
- 36308b8 formatter: Fix indent for new expression with type cast
(#16380) (leaysgur)

### ⚡ Performance

- 6f16a8f formatter: Avoid using an indent with a empty content (#16474)
(Dunqing)
- 201c98f formatter: Early return when no comments need to be printed
(#16432) (Dunqing)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
taearls pushed a commit to taearls/oxc that referenced this pull request Dec 11, 2025
* close: oxc-project#16199

~~Two tests regressed, but I kind of think they are correct. I created prettier/prettier#18384 to confirm the issue in Prettier.~~ Aligned with Prettier's current behavior
taearls pushed a commit to taearls/oxc that referenced this pull request Dec 11, 2025
# Oxlint
### 🚀 Features

- 5c62c16 linter/plugins: Allow JS plugins to access `globals` (oxc-project#16512)
(Arsh)
- ba7bd51 linter: Implement no-useless-return rule (oxc-project#16388) (FMP1783)
- fa605df linter: Fix `arrow-body-style` automatically (oxc-project#16252) (Hamir
Mahal)
- 7584938 linter/plugins: Add ESLint compat mode to `RuleTester`
(oxc-project#16538) (overlookmotel)
- b38c2d0 linter/plugins: Add `SourceCode#lineStartIndices` getter
(oxc-project#16510) (overlookmotel)
- ba93ffc linter/plugins: Add `SourceCode#tokensAndComments` getter
(oxc-project#16503) (overlookmotel)
- d2ca540 linter/plugins: Add `SourceCode#isESTree` property (oxc-project#16499)
(overlookmotel)
- 9001234 linter: Add fix support for tsgolint diagnostics (oxc-project#16344)
(camc314)
- 2d6bb85 editors: Toggle client after vscode config changing (oxc-project#16162)
(Liang Mi)
- 0ec454c linter/plugins: Merge default options into options (oxc-project#16358)
(overlookmotel)

### 🐛 Bug Fixes

- a806d74 linter: Use import type for ESTree in visitor.d.ts (oxc-project#16472)
(camc314)
- 8933c84 linter: Fix jest/expect-expect rule docs. (oxc-project#16550)
(connorshea)
- 1c08879 linter: Fix false positive in no-invalid-fetch-options for
conditional expressions (oxc-project#16570) (camc314)
- 1a69b06 linter: Junit support for multiple files/errors/diagnostics
(oxc-project#16568) (Shrey Sudhir)
- a7d435b linter/sort-keys: Preserve multi-line formatting in autofix
(oxc-project#16563) (camc314)
- fd84dcc linter/plugins: `RuleTester` parser catch fatal errors
(oxc-project#16558) (overlookmotel)
- ab4deb0 linter/plugins: Improve safety of options merging (oxc-project#16549)
(overlookmotel)
- a58c76a linter: Fix the `react/jsx-fragments` rule config to take a
string argument (oxc-project#16175) (connorshea)
- f7751cc linter/plugins: Fix TS types for `RuleTester` (oxc-project#16546)
(overlookmotel)
- 6d33320 linter/plugins: Prevent user modifying the default config
(oxc-project#16545) (overlookmotel)
- b4483c5 linter/plugins: Add config support skeleton to `RuleTester`
(oxc-project#16537) (overlookmotel)
- 3a49158 linter/plugins: Improve TS types for tokens (oxc-project#16502)
(overlookmotel)
- 0c14531 oxlint/lsp: Revalidate all known files after internal restart
(oxc-project#16407) (Sysix)
- 2d3217e linter/plugins: Remove panics from `lint_file` and
`setup_configs` (oxc-project#16453) (overlookmotel)
- 655341b linter/oxc: Not emit error when the threshold is zero and we
haven't detected a barrel file (oxc-project#16455) (Said Atrahouch)
- b9f359f linter/no-var: Expand fix span to prevent conflicts with other
rules (oxc-project#16445) (camc314)
- c6778f3 linter: Preserve original quote style in no-hex-escape fixer
(oxc-project#16410) (camc314)
- 3ad913b linter: Improve rule docs page autofix description (oxc-project#16281)
(Hamir Mahal)
- 0b7e00c linter: Handle keyword unary expressions in yoda rule fix
(oxc-project#16402) (camc314)
- 5fd3096 lsp: Skip (un)registering file watcher when not dynamic
watchers are supported (oxc-project#16406) (Sysix)
- 804144f lsp: Respect `null` as invalid settings for
`workspace/didChangeConfiguration` (oxc-project#16361) (Sysix)
- 723a7e5 linter: Prevent invalid BigInt literal fix for exponential
notation (oxc-project#16401) (camc314)
- 2589fb1 linter: Fix prefer_expect_resolves fixer for member
expressions (oxc-project#16393) (camc314)
- 428c7cd linter: Wrap logical expressions in parentheses when fixing
no-extra-boolean-cast (oxc-project#16363) (camc314)
- 3903567 linter: Skip prefer-string-raw in type annotations and .d.ts
files (oxc-project#16382) (camc314)
- d490daa linter/func-names: Use centralized reserved keyword check and
fix ancestor traversal (oxc-project#16362) (camc314)
- d846c53 tsgolint: Use `expect` when sending diagnostics (oxc-project#16341)
(camc314)
- 114665d lsp: Watch for files when workspace folder is added &
`workspace/configuration` is not supported (oxc-project#16307) (Sysix)
- f5d0ebb linter/func-names: Avoid suggesting reserved keywords as
function names (oxc-project#16352) (camc314)
- d268135 linter/no-console-spaces: Preserve escape sequences in fixer
output (oxc-project#16349) (camc314)
- b02c21a linter/valid-title: Preserve escape sequences in fixer output
(oxc-project#16348) (camc314)
- 2373b76 linter/no-untyped-mock-factory: Fix fixer producing invalid
syntax when newline exists after opening paren (oxc-project#16351) (camc314)

### ⚡ Performance

- 67cfa58 lsp: Avoid some clones (oxc-project#16519) (Sysix)
- 2a09665 oxlint/lsp: Store only `LinterCodeAction` instead of the
complete `DiagnosticReport` (oxc-project#16516) (Sysix)
- 0ca9754 lsp: Avoid `Uri` to `String` and back to `Uri` conversion
(oxc-project#16470) (Sysix)
- 2736636 lsp: Avoid cloning when revalidating diagnostics (oxc-project#16469)
(Sysix)
- 793b989 linter/plugins: Move result-processing work off main JS thread
(oxc-project#16456) (overlookmotel)
- 44dff7b linter/plugins: Skip serialization overhead when no errors
(oxc-project#16443) (overlookmotel)
- 1aa2409 linter/plugins: Do not remove `messageId` field from
`DiagnosticReport` before sending to Rust (oxc-project#16442) (overlookmotel)
- 5017db8 linter/plugins: Reduce calls to `Path::to_string_lossy`
(oxc-project#16429) (overlookmotel)
- 194e357 linter: Use `SmallVec` for rule options (oxc-project#16400) (Copilot)
- e31b2bd linter: Only clone config if required (oxc-project#16350) (overlookmotel)
- 3026086 linter: Avoid cloning rule options (oxc-project#16338) (overlookmotel)

### 📚 Documentation

- fef77af linter: Fix `jsx-a11y/img-redundant-alt` configuration option
names. (oxc-project#16552) (connorshea)
- c0766df linter: Add config option docs for `unicorn/filename-case`
rule. (oxc-project#16280) (connorshea)
- e24aabd linter/plugins: Correct comment (oxc-project#16559) (overlookmotel)
- 514c724 linter: Fix the name of the IIFEs config option in
eslint/max-lines-per-function (oxc-project#16554) (connorshea)
- 4d94438 linter/rules: Correct arrow body style options in
documentation (oxc-project#16509) (GRK)
- 6bac4ec linter: Pull configuration struct doc comment when rendering
config docs (oxc-project#16288) (connorshea)
- 8c85e08 linter/plugins: Add TODO comment (oxc-project#16511) (overlookmotel)
- a9b9298 linter/plugins: Add JSDoc comments to `SourceCode` properties
(oxc-project#16497) (overlookmotel)
- 467cc1a linter/plugins: Improve comment on error branch (oxc-project#16464)
(overlookmotel)
- 041b119 linter: Add config option docs to `jest/consistent-test-it`
rule. (oxc-project#16286) (connorshea)

### 🛡️ Security

- d90ef9f deps: Update dependency rolldown to v1.0.0-beta.53 (oxc-project#16428)
(renovate[bot])
# Oxfmt
### 🚀 Features

- 3184f17 oxfmt: Pass filepath field to prettier formatting (oxc-project#16591)
(Yuji Sugiura)
- 7bb3304 oxfmt: Pass populated config to prettier formatting (oxc-project#16584)
(leaysgur)
- 69f84d2 oxfmt: Pass raw config to prettier formatting (oxc-project#16582)
(leaysgur)
- a83a2ec oxfmt: Expose `setupConfig(configJSON: string)` napi callback
(oxc-project#16579) (leaysgur)
- 930533f formatter: Convert single `\r` to `\n` in string and add a
debug assertion to ensure that there is no `\r` in the text (oxc-project#16531)
(Dunqing)
- af76b0e oxfmt: Support formatting HTML, YAML, GraphQL, Handlerbars,
Markdown, CSS files (oxc-project#16524) (leaysgur)
- 66b64ef oxfmt: Support formatting JSON files (oxc-project#16523) (leaysgur)
- 4767926 oxfmt: Prepare non-js/ts file support with prettier (oxc-project#16480)
(leaysgur)
- 2b4ce5d oxfmt: Use dedicated `format_by_xxx_formatter` method by
`SourceType` (oxc-project#16417) (leaysgur)
- 0867d2f oxfmt: Set up JS `formatFile()` function for Rust via napi
(oxc-project#16415) (leaysgur)
- b6feb66 oxfmt: Rename `embedded.ts` with preparing `formatFile()`
function (oxc-project#16414) (leaysgur)
- 80e6999 formatter: Add debug assertion to ensure that there is no
empty content is passed in (oxc-project#16475) (Dunqing)
- 7374856 formatter/sort-imports: Support `options.internalPattern`
(oxc-project#16372) (leaysgur)
- dd2cb62 oxfmt: Not error on explicit `--write` flag used (oxc-project#16376)
(leaysgur)

### 🐛 Bug Fixes

- 40b0134 formatter: Incorrect formatting of `useImperativeHandle` hook
(oxc-project#16533) (Dunqing)
- 75393e7 formatter: Incorrect handling of `CRLF` for multiline block
comment (oxc-project#16528) (Dunqing)
- ee0756b formatter: JSX text wrapping incorrect 2 (oxc-project#16320) (Dunqing)
- 36308b8 formatter: Fix indent for new expression with type cast
(oxc-project#16380) (leaysgur)

### ⚡ Performance

- 6f16a8f formatter: Avoid using an indent with a empty content (oxc-project#16474)
(Dunqing)
- 201c98f formatter: Early return when no comments need to be printed
(oxc-project#16432) (Dunqing)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-formatter Area - Formatter C-bug Category - Bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

formatter: Diff with Prettier on JSXText does not break in some cases

2 participants