From 84ee9016ba4f99bb423cb144173d5ba679377de2 Mon Sep 17 00:00:00 2001
From: Seiya <20365512+seiyab@users.noreply.github.com>
Date: Sun, 22 Jun 2025 00:51:13 +0900
Subject: [PATCH] Get JSX in arrow in method call to be consistent (#17616)
* add failing test
* fix #17489
* add more tests
* refactor ...but perhaps get ugly? I'm not sure
* Apply automated changes
* utilize path.match
* add changelog
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
---
changelog_unreleased/javascript/17616.md | 46 ++++++++++
src/language-js/print/jsx.js | 33 +++++--
.../__snapshots__/format.test.js.snap | 92 ++++++++++++++++++-
.../optional-chaining/optional-chaining.jsx | 40 ++++++++
4 files changed, 203 insertions(+), 8 deletions(-)
create mode 100644 changelog_unreleased/javascript/17616.md
diff --git a/changelog_unreleased/javascript/17616.md b/changelog_unreleased/javascript/17616.md
new file mode 100644
index 000000000..775a9d050
--- /dev/null
+++ b/changelog_unreleased/javascript/17616.md
@@ -0,0 +1,46 @@
+#### Improve consistency for JSX in optional method call (#17616 by @seiyab)
+
+
+```jsx
+// Input
+
+
+ {Array(20)
+ .fill()
+ ?.map((_, i) => (
+
{i + 1}
+ ))}
+
+;
+
+// Prettier stable (ESTree based parsers like espree and typescript)
+
+
+ {Array(20)
+ .fill()
+ ?.map((_, i) =>
{i + 1}
)}
+
+;
+
+// Prettier stable (babel and babel-ts parser)
+
+
+ {Array(20)
+ .fill()
+ ?.map((_, i) => (
+
{i + 1}
+ ))}
+
+;
+
+// Prettier main (parsers of both types)
+
+
+ {Array(20)
+ .fill()
+ ?.map((_, i) => (
+
{i + 1}
+ ))}
+
+;
+```
diff --git a/src/language-js/print/jsx.js b/src/language-js/print/jsx.js
index a2a705491..20b106a7c 100644
--- a/src/language-js/print/jsx.js
+++ b/src/language-js/print/jsx.js
@@ -504,13 +504,7 @@ function maybeWrapJsxElementInParens(path, elem, options) {
return elem;
}
- const shouldBreak = path.match(
- undefined,
- (node) => node.type === "ArrowFunctionExpression",
- isCallExpression,
- (node) => node.type === "JSXExpressionContainer",
- );
-
+ const shouldBreak = shouldBreakJsxElement(path);
const needsParens = pathNeedsParens(path, options);
return group(
@@ -524,6 +518,31 @@ function maybeWrapJsxElementInParens(path, elem, options) {
);
}
+function shouldBreakJsxElement(path) {
+ return (
+ path.match(
+ undefined,
+ (node) => node.type === "ArrowFunctionExpression",
+ isCallExpression,
+ ) &&
+ // Babel
+ (path.match(
+ undefined,
+ undefined,
+ undefined,
+ (node) => node.type === "JSXExpressionContainer",
+ ) ||
+ // Estree
+ path.match(
+ undefined,
+ undefined,
+ undefined,
+ (node) => node.type === "ChainExpression",
+ (node) => node.type === "JSXExpressionContainer",
+ ))
+ );
+}
+
function printJsxAttribute(path, options, print) {
const { node } = path;
const parts = [];
diff --git a/tests/format/jsx/optional-chaining/__snapshots__/format.test.js.snap b/tests/format/jsx/optional-chaining/__snapshots__/format.test.js.snap
index 959f68a90..770ab4b71 100644
--- a/tests/format/jsx/optional-chaining/__snapshots__/format.test.js.snap
+++ b/tests/format/jsx/optional-chaining/__snapshots__/format.test.js.snap
@@ -1,4 +1,4 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`optional-chaining.jsx format 1`] = `
====================================options=====================================
@@ -18,6 +18,46 @@ function foo() {
)
}
+function Component( ) {
+ return (
+
+ {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?.bbbbbbbbbbbbbbbbbbbbbbbbb.map(
+ (p, i) =>
{p}
+ )}
+
+ );
+}
+
+function Component() {
+ return (
+
+ {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?.bbbbbbbbbbbbbbbbbbbbbbbbb().map(
+ (p, i) =>
{p}
+ )}
+
+ );
+}
+
+function Component() {
+ return (
+
+ {aaa?.aaa()?.aaa()?.map(
+ (p, i) =>
{p}
+ )}
+
+ );
+}
+
+function Component() {
+ return (
+
+ {aaa?.aaa?.()?.aaa?.()?.map?.(
+ (p, i) =>
{p}
+ )}
+
+ );
+}
+
=====================================output=====================================
function foo() {
// https://github.com/marmelab/react-admin/blob/5ae855aa958ba54438b144bf0907b1437c5a5d77/examples/demo/src/orders/Totals.tsx#L38-L43
@@ -31,5 +71,55 @@ function foo() {
);
}
+function Component() {
+ return (
+
+ {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?.bbbbbbbbbbbbbbbbbbbbbbbbb.map(
+ (p, i) => (
+
{p}
+ ),
+ )}
+
+ );
+}
+
+function Component() {
+ return (
+
+ {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ ?.bbbbbbbbbbbbbbbbbbbbbbbbb()
+ .map((p, i) => (
+
{p}
+ ))}
+
+ );
+}
+
+function Component() {
+ return (
+
+ {aaa
+ ?.aaa()
+ ?.aaa()
+ ?.map((p, i) => (
+
{p}
+ ))}
+
+ );
+}
+
+function Component() {
+ return (
+
+ {aaa
+ ?.aaa?.()
+ ?.aaa?.()
+ ?.map?.((p, i) => (
+
{p}
+ ))}
+
+ );
+}
+
================================================================================
`;
diff --git a/tests/format/jsx/optional-chaining/optional-chaining.jsx b/tests/format/jsx/optional-chaining/optional-chaining.jsx
index 3d5ffd50a..6b59a8bc1 100644
--- a/tests/format/jsx/optional-chaining/optional-chaining.jsx
+++ b/tests/format/jsx/optional-chaining/optional-chaining.jsx
@@ -9,3 +9,43 @@ function foo() {
)
}
+
+function Component( ) {
+ return (
+
+ {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?.bbbbbbbbbbbbbbbbbbbbbbbbb.map(
+ (p, i) =>
{p}
+ )}
+
+ );
+}
+
+function Component() {
+ return (
+
+ {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?.bbbbbbbbbbbbbbbbbbbbbbbbb().map(
+ (p, i) =>
{p}
+ )}
+
+ );
+}
+
+function Component() {
+ return (
+
+ {aaa?.aaa()?.aaa()?.map(
+ (p, i) =>
{p}
+ )}
+
+ );
+}
+
+function Component() {
+ return (
+
+ {aaa?.aaa?.()?.aaa?.()?.map?.(
+ (p, i) =>
{p}
+ )}
+
+ );
+}