fix(rome_js_formatter): Arrow with JSX Body
MODIFY
crates/rome_js_formatter/src/js/expressions/arrow_function_expression.rs
crates/rome_js_formatter/src/js/expressions/arrow_function_expression.rs
@@ -18,9 +18,9 @@ use crate::utils::{
use rome_js_syntax::{
JsAnyArrowFunctionParameters, JsAnyBindingPattern, JsAnyExpression, JsAnyFormalParameter,
JsAnyFunctionBody, JsAnyParameter, JsAnyTemplateElement, JsArrowFunctionExpression,
- JsSyntaxKind, JsSyntaxNode, JsTemplate, JsxExpressionChild,
+ JsSyntaxKind, JsSyntaxNode, JsTemplate,
};
-use rome_rowan::SyntaxResult;
+use rome_rowan::{SyntaxNodeOptionExt, SyntaxResult};
#[derive(Debug, Copy, Clone, Default)]
pub struct FormatJsArrowFunctionExpression {
@@ -73,6 +73,11 @@ impl FormatNodeRule<JsArrowFunctionExpression> for FormatJsArrowFunctionExpressi
)
});
+ let format_body = FormatMaybeCachedFunctionBody {
+ body: &body,
+ mode: self.options.body_cache_mode,
+ };
+
// With arrays, arrow selfs and objects, they have a natural line breaking strategy:
// Arrays and objects become blocks:
//
@@ -91,16 +96,15 @@ impl FormatNodeRule<JsArrowFunctionExpression> for FormatJsArrowFunctionExpressi
// do not have a soft line break after the arrow because the body is
// going to get broken anyways.
let body_has_soft_line_break = match &body {
- JsFunctionBody(_) => true,
- JsAnyExpression(expr) => match expr {
- JsArrowFunctionExpression(_)
- | JsArrayExpression(_)
- | JsObjectExpression(_)
- | JsxTagExpression(_) => true,
- JsTemplate(template) => {
+ JsFunctionBody(_)
+ | JsAnyExpression(
+ JsArrowFunctionExpression(_) | JsArrayExpression(_) | JsObjectExpression(_),
+ ) => !f.comments().has_leading_own_line_comment(body.syntax()),
+ JsAnyExpression(JsxTagExpression(_)) => true,
+ JsAnyExpression(JsTemplate(template)) => {
is_multiline_template_starting_on_same_line(template)
}
- JsSequenceExpression(_) => {
+ JsAnyExpression(JsSequenceExpression(_)) => {
return write!(
f,
[group(&format_args![
@@ -108,26 +112,23 @@ impl FormatNodeRule<JsArrowFunctionExpression> for FormatJsArrowFunctionExpressi
group(&format_args![
space(),
text("("),
- soft_block_indent(&body.format()),
+ soft_block_indent(&format_body),
text(")")
])
])]
);
}
_ => false,
- },
};
- let body_has_leading_line_comment = f
- .context()
- .comments()
- .has_leading_own_line_comment(body.syntax());
+ if body_has_soft_line_break {
+ write![f, [format_signature, space(), format_body]]
+ } else {
// Add parentheses to avoid confusion between `a => b ? c : d` and `a <= b ? c : d`
// but only if the body isn't an object/function or class expression because parentheses are always required in that
// case and added by the object expression itself
let should_add_parens = match &body {
- JsAnyExpression(expression) => {
- let is_conditional = matches!(expression, JsConditionalExpression(_));
+ JsAnyExpression(expression @ JsConditionalExpression(_)) => {
let are_parentheses_mandatory = matches!(
resolve_left_most_expression(expression),
JsAnyBinaryLikeLeftExpression::JsAnyExpression(
@@ -137,30 +138,20 @@ impl FormatNodeRule<JsArrowFunctionExpression> for FormatJsArrowFunctionExpressi
)
);
- is_conditional && !are_parentheses_mandatory
+ !are_parentheses_mandatory
}
_ => false,
};
- let format_body = FormatMaybeCachedFunctionBody {
- body: &body,
- mode: self.options.body_cache_mode,
- };
-
- if body_has_soft_line_break && !should_add_parens && !body_has_leading_line_comment
- {
- write![f, [format_signature, space(), format_body]]
- } else {
let is_last_call_arg = matches!(
self.options.call_arg_layout,
Some(GroupedCallArgumentLayout::GroupedLastArgument)
);
- let should_add_soft_line = is_last_call_arg
+ let should_add_soft_line = (is_last_call_arg
// if it's inside a JSXExpression (e.g. an attribute) we should align the expression's closing } with the line with the opening {.
- || node.parent::<JsxExpressionChild>().map_or(false, |_| {
- !f.context().comments().has_comments(node.syntax())
- });
+ || matches!(node.syntax().parent().kind(), Some(JsSyntaxKind::JSX_EXPRESSION_CHILD | JsSyntaxKind::JSX_EXPRESSION_ATTRIBUTE_VALUE)))
+ && !f.context().comments().has_comments(node.syntax());
write!(
f,

ADD
crates/rome_js_formatter/tests/specs/js/module/arrow/arrow-comments.js
+// array
+(action) =>
+ // eslint-disable-next-line react/no-array-index-key
+ [<li />];
+
+// function body
+(action) =>
+ // eslint-disable-next-line react/no-array-index-key
+{
+ return <li />;
+}
+
+// object expression
+(action) =>
+ // eslint-disable-next-line react/no-array-index-key
+ ({ a: 10
+ });
+
+ (action) => /* comment */ `
+${test}
+multiline`;

ADD
crates/rome_js_formatter/tests/specs/js/module/arrow/arrow-comments.js.snap
+---
+source: crates/rome_js_formatter/tests/spec_test.rs
+expression: arrow-comments.js
+---
+
+# Input
+
+```js
+// array
+(action) =>
+ // eslint-disable-next-line react/no-array-index-key
+ [<li />];
+
+// function body
+(action) =>
+ // eslint-disable-next-line react/no-array-index-key
+{
+ return <li />;
+}
+
+// object expression
+(action) =>
+ // eslint-disable-next-line react/no-array-index-key
+ ({ a: 10
+ });
+
+ (action) => /* comment */ `
+${test}
+multiline`;
+
+```
+
+
+=============================
+
+# Outputs
+
+## Output 1
+
+-----
+Indent style: Tab
+Line width: 80
+Quote style: Double Quotes
+Quote properties: As needed
+Trailing comma: All
+-----
+
+```js
+// array
+(action) =>
+ // eslint-disable-next-line react/no-array-index-key
+ [<li />];
+
+// function body
+(action) =>
+ // eslint-disable-next-line react/no-array-index-key
+ {
+ return <li />;
+ };
+
+// object expression
+(action) =>
+ // eslint-disable-next-line react/no-array-index-key
+ ({ a: 10 });
+
+(action) => /* comment */ `
+${test}
+multiline`;
+```
+
+

MODIFY
crates/rome_js_formatter/tests/specs/jsx/arrow_function.jsx
crates/rome_js_formatter/tests/specs/jsx/arrow_function.jsx
@@ -19,3 +19,11 @@ function BackTopContent(props){
</CSSMotion>
);
}
+
+function ArrowBodyIsJsxWithComment({ action }) {
+ return (action) =>
+ (
+ // eslint-disable-next-line react/no-array-index-key
+ <li/>
+ );
+}

MODIFY
crates/rome_js_formatter/tests/specs/jsx/arrow_function.jsx.snap
crates/rome_js_formatter/tests/specs/jsx/arrow_function.jsx.snap
@@ -28,6 +28,14 @@ function BackTopContent(props){
);
}
+function ArrowBodyIsJsxWithComment({ action }) {
+ return (action) =>
+ (
+ // eslint-disable-next-line react/no-array-index-key
+ <li/>
+ );
+}
+
```
@@ -70,6 +78,13 @@ function BackTopContent(props) {
</CSSMotion>
);
}
+
+function ArrowBodyIsJsxWithComment({ action }) {
+ return (action) => (
+ // eslint-disable-next-line react/no-array-index-key
+ <li />
+ );
+}
```

DELETE
crates/rome_js_formatter/tests/specs/prettier/js/trailing-comma/jsx.js.snap
----
-source: crates/rome_js_formatter/tests/prettier_tests.rs
----
-
-# Input
-
-```js
-<div
- onClick={() =>
- doSomething({
- foo: bar
- })
- }
-/>;
-```
-
-
-# Prettier differences
-
-```diff
---- Prettier
-+++ Rome
-@@ -2,6 +2,5 @@
- onClick={() =>
- doSomething({
- foo: bar,
-- })
-- }
-+ })}
- />;
-```
-
-# Output
-
-```js
-<div
- onClick={() =>
- doSomething({
- foo: bar,
- })}
-/>;
-```
-
-
-

MODIFY
website/playground/src/QuotePropertiesSelect.tsx
website/playground/src/QuotePropertiesSelect.tsx
@@ -30,7 +30,8 @@ export default function QuotePropertiesSelect({
name="quoteProperties"
value={quoteProperties ?? ""}
onChange={(e) =>
- setQuoteProperties(e.target.value as QuoteProperties)}
+ setQuoteProperties(e.target.value as QuoteProperties)
+ }
className="w-[100px] mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
>
<option value={QuoteProperties.AsNeeded}>As needed</option>

MODIFY
website/playground/src/TrailingCommaSelect.tsx
website/playground/src/TrailingCommaSelect.tsx
@@ -30,7 +30,8 @@ export default function TrailingCommaSelect({
name="trailingComma"
value={trailingComma ?? "all"}
onChange={(e) =>
- setTrailingComma(e.target.value as TrailingComma)}
+ setTrailingComma(e.target.value as TrailingComma)
+ }
className="w-[100px] mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
>
<option value={TrailingComma.All}>All</option>

fix(rome_js_formatter): Arrow with JSX Body (#3505)