Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
feat(rome_js_formatter): parenthesise TsTypeAssertionExpression
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaReiser committed Aug 13, 2022
1 parent 8c76c2a commit fbb4bd8
Show file tree
Hide file tree
Showing 54 changed files with 1,505 additions and 1,078 deletions.
17 changes: 16 additions & 1 deletion crates/rome_js_formatter/src/js/auxiliary/new_target.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::prelude::*;

use crate::parentheses::NeedsParentheses;
use rome_formatter::write;
use rome_js_syntax::NewTarget;
use rome_js_syntax::NewTargetFields;
use rome_js_syntax::{JsSyntaxNode, NewTarget};

#[derive(Debug, Clone, Default)]
pub struct FormatNewTarget;
Expand All @@ -24,4 +25,18 @@ impl FormatNodeRule<NewTarget> for FormatNewTarget {
]
]
}

fn needs_parentheses(&self, item: &NewTarget) -> bool {
item.needs_parentheses()
}
}

impl NeedsParentheses for NewTarget {
fn needs_parentheses(&self) -> bool {
false
}

fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool {
false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ impl FormatNodeRule<JsArrayExpression> for FormatJsArrayExpression {
]
)
}

fn needs_parentheses(&self, item: &JsArrayExpression) -> bool {
item.needs_parentheses()
}
}

impl NeedsParentheses for JsArrayExpression {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use crate::prelude::*;
use rome_formatter::{format_args, write};

use crate::parentheses::{
is_binary_like_left_or_right, is_conditional_test, is_in_left_hand_side_position,
NeedsParentheses,
is_binary_like_left_or_right, is_conditional_test,
update_or_lower_expression_needs_parentheses, NeedsParentheses,
};
use crate::utils::{
resolve_expression, resolve_left_most_expression, JsAnyBinaryLikeLeftExpression,
Expand Down Expand Up @@ -105,14 +105,6 @@ impl FormatNodeRule<JsArrowFunctionExpression> for FormatJsArrowFunctionExpressi
])
])]
);
// // We handle sequence expressions as the body of arrows specially,
// // so that the required parentheses end up on their own lines.
// if (node.body.type === "SequenceExpression") {
// return group([
// ...parts,
// group([" (", indent([softline, body]), softline, ")"]),
// ]);
// }
}
_ => false,
},
Expand Down Expand Up @@ -178,7 +170,7 @@ impl NeedsParentheses for JsArrowFunctionExpression {

_ => {
is_conditional_test(self.syntax(), parent)
|| is_in_left_hand_side_position(self.syntax(), parent)
|| update_or_lower_expression_needs_parentheses(self.syntax(), parent)
|| is_binary_like_left_or_right(self.syntax(), parent)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ use crate::utils::{resolve_expression_syntax, JsAnyAssignmentLike};

use crate::parentheses::{is_first_in_statement, FirstInStatementMode, NeedsParentheses};
use rome_formatter::write;

use rome_js_syntax::{
JsAnyAssignmentPattern, JsAnyForInitializer, JsAnyFunctionBody, JsArrowFunctionExpression,
JsAssignmentExpression, JsForStatement, JsParenthesizedExpression, JsSyntaxKind, JsSyntaxNode,
JsAssignmentExpression, JsForStatement, JsSyntaxKind, JsSyntaxNode,
};
use rome_rowan::AstNode;

#[derive(Debug, Clone, Default)]
pub struct FormatJsAssignmentExpression;
Expand All @@ -23,11 +25,6 @@ impl FormatNodeRule<JsAssignmentExpression> for FormatJsAssignmentExpression {

impl NeedsParentheses for JsAssignmentExpression {
fn needs_parentheses_with_parent(&self, parent: &JsSyntaxNode) -> bool {
let grand_parent = parent
.ancestors()
.skip(1)
.find(|parent| !JsParenthesizedExpression::can_cast(parent.kind()));

match parent.kind() {
JsSyntaxKind::JS_ASSIGNMENT_EXPRESSION => false,
// `[a = b]`
Expand Down Expand Up @@ -70,23 +67,35 @@ impl NeedsParentheses for JsAssignmentExpression {
Ok(JsAnyAssignmentPattern::JsObjectAssignmentPattern(_))
)
}
JsSyntaxKind::JS_SEQUENCE_EXPRESSION => grand_parent
.and_then(JsForStatement::cast)
.map_or(true, |for_statement| {
let is_initializer = match for_statement.initializer() {
Some(JsAnyForInitializer::JsAnyExpression(expression)) => {
&resolve_expression_syntax(expression) == parent
JsSyntaxKind::JS_SEQUENCE_EXPRESSION => {
let mut child = parent.clone();

for ancestor in parent.ancestors().skip(1) {
match ancestor.kind() {
JsSyntaxKind::JS_SEQUENCE_EXPRESSION
| JsSyntaxKind::JS_PARENTHESIZED_EXPRESSION => child = ancestor,
JsSyntaxKind::JS_FOR_STATEMENT => {
let for_statement = JsForStatement::unwrap_cast(ancestor);

let is_initializer = match for_statement.initializer() {
Some(JsAnyForInitializer::JsAnyExpression(expression)) => {
expression.syntax() == &child
}
None | Some(_) => false,
};

let is_update =
for_statement.update().map(AstNode::into_syntax).as_ref()
== Some(&child);

return !(is_initializer || is_update);
}
None | Some(_) => false,
};
let is_update = for_statement
.update()
.map(resolve_expression_syntax)
.as_ref()
== Some(parent);
_ => break,
}
}

!(is_initializer || is_update)
}),
true
}

_ => true,
}
Expand All @@ -110,6 +119,8 @@ mod tests {
assert_not_needs_parentheses!("a => { a = 3 }", JsAssignmentExpression);

assert_not_needs_parentheses!("for(a = 3;;) {}", JsAssignmentExpression);
assert_not_needs_parentheses!("for(a = 3, b = 2;;) {}", JsAssignmentExpression[1]);
assert_not_needs_parentheses!("for(a = 3, b = 2, c= 3;;) {}", JsAssignmentExpression[2]);
assert_needs_parentheses!("for(; a = 3; ) {}", JsAssignmentExpression);
assert_not_needs_parentheses!("for(;;a = 3) {}", JsAssignmentExpression);

Expand Down
44 changes: 40 additions & 4 deletions crates/rome_js_formatter/src/js/expressions/await_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use crate::prelude::*;
use rome_formatter::write;

use crate::parentheses::{
is_binary_like_left_or_right, is_conditional_test, unary_expression_needs_parentheses,
NeedsParentheses,
is_binary_like_left_or_right, is_callee, is_conditional_test, is_member_object, is_spread,
resolve_expression_parent, update_or_lower_expression_needs_parentheses, NeedsParentheses,
};

use rome_js_syntax::{JsAwaitExpression, JsSyntaxNode};
Expand All @@ -19,7 +19,36 @@ impl FormatNodeRule<JsAwaitExpression> for FormatJsAwaitExpression {
argument,
} = node.as_fields();

write![f, [await_token.format(), space(), argument.format(),]]
let format_inner =
format_with(|f| write![f, [await_token.format(), space(), argument.format()]]);

let parent = resolve_expression_parent(node.syntax());

if let Some(parent) = parent {
if is_callee(node.syntax(), &parent) || is_member_object(node.syntax(), &parent) {
let ancestor_await_or_block = parent.ancestors().skip(1).find(|ancestor| {
matches!(
ancestor.kind(),
JsSyntaxKind::JS_AWAIT_EXPRESSION
// Stop at statement boundaries.
| JsSyntaxKind::JS_STATEMENT_LIST
| JsSyntaxKind::JS_MODULE_ITEM_LIST
)
});

let indented = format_with(|f| write!(f, [soft_block_indent(&format_inner)]));

return if ancestor_await_or_block.map_or(false, |ancestor| {
JsAwaitExpression::can_cast(ancestor.kind())
}) {
write!(f, [indented])
} else {
write!(f, [group(&indented)])
};
}
}

write!(f, [format_inner])
}

fn needs_parentheses(&self, item: &JsAwaitExpression) -> bool {
Expand All @@ -34,12 +63,19 @@ impl NeedsParentheses for JsAwaitExpression {
}

pub(super) fn await_or_yield_needs_parens(parent: &JsSyntaxNode, node: &JsSyntaxNode) -> bool {
debug_assert!(matches!(
node.kind(),
JsSyntaxKind::JS_AWAIT_EXPRESSION | JsSyntaxKind::JS_YIELD_EXPRESSION
));

match parent.kind() {
JsSyntaxKind::JS_UNARY_EXPRESSION | JsSyntaxKind::TS_AS_EXPRESSION => true,

_ => {
let expression = node;
is_conditional_test(node, parent)
|| unary_expression_needs_parentheses(node, parent)
|| update_or_lower_expression_needs_parentheses(expression, parent)
|| is_spread(expression, parent)
|| is_binary_like_left_or_right(node, parent)
}
}
Expand Down
69 changes: 67 additions & 2 deletions crates/rome_js_formatter/src/js/expressions/binary_expression.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::prelude::*;
use crate::utils::{format_binary_like_expression, JsAnyBinaryLikeExpression};
use crate::utils::{
format_binary_like_expression, needs_binary_like_parentheses, JsAnyBinaryLikeExpression,
};

use rome_js_syntax::JsBinaryExpression;
use crate::parentheses::NeedsParentheses;
use rome_js_syntax::{JsBinaryExpression, JsSyntaxNode};

#[derive(Debug, Clone, Default)]
pub struct FormatJsBinaryExpression;
Expand All @@ -18,3 +21,65 @@ impl FormatNodeRule<JsBinaryExpression> for FormatJsBinaryExpression {
)
}
}

impl NeedsParentheses for JsBinaryExpression {
fn needs_parentheses_with_parent(&self, parent: &JsSyntaxNode) -> bool {
needs_binary_like_parentheses(&JsAnyBinaryLikeExpression::from(self.clone()), parent)
}
}

#[cfg(test)]
mod tests {
use crate::{assert_needs_parentheses, assert_not_needs_parentheses};
use rome_js_syntax::{JsBinaryExpression, SourceType};

#[test]
fn needs_parentheses() {
assert_needs_parentheses!("class X extends (4 + 4) {}", JsBinaryExpression);

assert_needs_parentheses!("(4 + 4) as number", JsBinaryExpression);
assert_needs_parentheses!("<number>(4 + 4)", JsBinaryExpression);
assert_needs_parentheses!("!(4 + 4)", JsBinaryExpression);
assert_needs_parentheses!("await (4 + 4)", JsBinaryExpression);
assert_needs_parentheses!("(4 + 4)!", JsBinaryExpression);

assert_needs_parentheses!("(4 + 4)()", JsBinaryExpression);
assert_needs_parentheses!("(4 + 4)?.()", JsBinaryExpression);
assert_needs_parentheses!("new (4 + 4)()", JsBinaryExpression);
assert_needs_parentheses!("(4 + 4)`template`", JsBinaryExpression);
assert_needs_parentheses!("[...(4 + 4)]", JsBinaryExpression);
assert_needs_parentheses!("({...(4 + 4)})", JsBinaryExpression);
assert_needs_parentheses!(
"<test {...(4 + 4)} />",
JsBinaryExpression,
SourceType::tsx()
);
assert_needs_parentheses!(
"<test>{...(4 + 4)}</test>",
JsBinaryExpression,
SourceType::tsx()
);

assert_needs_parentheses!("(4 + 4).member", JsBinaryExpression);
assert_needs_parentheses!("(4 + 4)[member]", JsBinaryExpression);
assert_not_needs_parentheses!("object[4 + 4]", JsBinaryExpression);

assert_needs_parentheses!("(4 + 4) * 3", JsBinaryExpression[1]);
assert_not_needs_parentheses!("(4 + 4) * 3", JsBinaryExpression[0]);

assert_needs_parentheses!("a ** b ** c", JsBinaryExpression[1]);
assert_not_needs_parentheses!("a ** b ** c", JsBinaryExpression[0]);

assert_needs_parentheses!("a * r >> 5", JsBinaryExpression[1]);
assert_not_needs_parentheses!("a * r >> 5", JsBinaryExpression[0]);

assert_needs_parentheses!("a * r | 4", JsBinaryExpression[1]);
assert_not_needs_parentheses!("a * r | 5", JsBinaryExpression[0]);

assert_needs_parentheses!("a % 4 + 4", JsBinaryExpression[1]);
assert_not_needs_parentheses!("a % 4 + 4", JsBinaryExpression[0]);

assert_needs_parentheses!("a == b == c", JsBinaryExpression[1]);
assert_not_needs_parentheses!("a == b == c", JsBinaryExpression[0]);
}
}
Loading

0 comments on commit fbb4bd8

Please sign in to comment.