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 17, 2022
1 parent 6dbe074 commit f2665fe
Show file tree
Hide file tree
Showing 67 changed files with 2,217 additions and 1,091 deletions.
30 changes: 28 additions & 2 deletions 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::{ExpressionNode, NeedsParentheses};
use rome_formatter::write;
use rome_js_syntax::NewTarget;
use rome_js_syntax::NewTargetFields;
use rome_js_syntax::{JsAnyExpression, NewTargetFields};
use rome_js_syntax::{JsSyntaxNode, NewTarget};

#[derive(Debug, Clone, Default)]
pub struct FormatNewTarget;
Expand All @@ -24,4 +25,29 @@ 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
}
}

impl ExpressionNode for NewTarget {
#[inline]
fn resolve(&self) -> JsAnyExpression {
self.clone().into()
}

fn into_resolved(self) -> JsAnyExpression {
self.into()
}
}
22 changes: 20 additions & 2 deletions crates/rome_js_formatter/src/js/expressions/array_expression.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::prelude::*;

use crate::parentheses::NeedsParentheses;
use crate::parentheses::{ExpressionNode, NeedsParentheses};
use rome_formatter::write;
use rome_js_syntax::JsArrayExpressionFields;
use rome_js_syntax::{JsAnyExpression, JsArrayExpressionFields};
use rome_js_syntax::{JsArrayExpression, JsSyntaxNode};

#[derive(Debug, Clone, Default)]
Expand All @@ -28,13 +28,31 @@ impl FormatNodeRule<JsArrayExpression> for FormatJsArrayExpression {
]
)
}

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

impl NeedsParentheses for JsArrayExpression {
#[inline(always)]
fn needs_parentheses(&self) -> bool {
false
}
#[inline(always)]
fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool {
false
}
}

impl ExpressionNode for JsArrayExpression {
#[inline]
fn resolve(&self) -> JsAnyExpression {
self.clone().into()
}

#[inline]
fn into_resolved(self) -> JsAnyExpression {
self.into()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ 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,
};
use crate::utils::{
resolve_expression, resolve_left_most_expression, JsAnyBinaryLikeLeftExpression,
is_binary_like_left_or_right, is_conditional_test,
update_or_lower_expression_needs_parentheses, ExpressionNode, NeedsParentheses,
};
use crate::utils::{resolve_left_most_expression, JsAnyBinaryLikeLeftExpression};
use rome_js_syntax::{
JsAnyArrowFunctionParameters, JsAnyExpression, JsAnyFunctionBody, JsAnyTemplateElement,
JsArrowFunctionExpression, JsArrowFunctionExpressionFields, JsSyntaxKind, JsSyntaxNode,
Expand Down Expand Up @@ -88,13 +86,13 @@ impl FormatNodeRule<JsArrowFunctionExpression> for FormatJsArrowFunctionExpressi
// going to get broken anyways.
let body_has_soft_line_break = match &body {
JsFunctionBody(_) => true,
JsAnyExpression(expr) => match resolve_expression(expr.clone()) {
JsAnyExpression(expr) => match expr.resolve() {
JsArrowFunctionExpression(_)
| JsArrayExpression(_)
| JsObjectExpression(_)
| JsParenthesizedExpression(_)
| JsTemplate(_)
| JsxTagExpression(_) => true,
JsTemplate(template) => is_multiline_template_starting_on_same_line(&template),
JsSequenceExpression(_) => {
return write!(
f,
Expand All @@ -108,14 +106,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 All @@ -126,7 +116,7 @@ impl FormatNodeRule<JsArrowFunctionExpression> for FormatJsArrowFunctionExpressi
// case and added by the object expression itself
let should_add_parens = match &body {
JsAnyExpression(expression) => {
let resolved = resolve_expression(expression.clone());
let resolved = expression.resolve();

let is_conditional = matches!(resolved, JsConditionalExpression(_));
let are_parentheses_mandatory = matches!(
Expand Down Expand Up @@ -181,13 +171,25 @@ 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)
}
}
}
}

impl ExpressionNode for JsArrowFunctionExpression {
#[inline]
fn resolve(&self) -> JsAnyExpression {
self.clone().into()
}

#[inline]
fn into_resolved(self) -> JsAnyExpression {
self.into()
}
}

#[cfg(test)]
mod tests {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use crate::prelude::*;
use crate::utils::{resolve_expression_syntax, JsAnyAssignmentLike};
use crate::utils::JsAnyAssignmentLike;

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

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

#[derive(Debug, Clone, Default)]
pub struct FormatJsAssignmentExpression;
Expand All @@ -23,11 +27,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 All @@ -38,7 +37,7 @@ impl NeedsParentheses for JsAssignmentExpression {

match arrow.body() {
Ok(JsAnyFunctionBody::JsAnyExpression(expression)) => {
&resolve_expression_syntax(expression) == self.syntax()
&expression.resolve_syntax() == self.syntax()
}
_ => false,
}
Expand All @@ -47,14 +46,14 @@ impl NeedsParentheses for JsAssignmentExpression {
let for_statement = JsForStatement::unwrap_cast(parent.clone());
let is_initializer = match for_statement.initializer() {
Some(JsAnyForInitializer::JsAnyExpression(expression)) => {
&resolve_expression_syntax(expression) == self.syntax()
&expression.resolve_syntax() == self.syntax()
}
None | Some(_) => false,
};

let is_update = for_statement
.update()
.map(resolve_expression_syntax)
.map(ExpressionNode::into_resolved_syntax)
.as_ref()
== Some(self.syntax());

Expand All @@ -70,29 +69,53 @@ 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,
}
}
}

impl ExpressionNode for JsAssignmentExpression {
#[inline]
fn resolve(&self) -> JsAnyExpression {
self.clone().into()
}

#[inline]
fn into_resolved(self) -> JsAnyExpression {
self.into()
}
}

#[cfg(test)]
mod tests {

Expand All @@ -110,6 +133,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
58 changes: 53 additions & 5 deletions crates/rome_js_formatter/src/js/expressions/await_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ 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,
update_or_lower_expression_needs_parentheses, ExpressionNode, NeedsParentheses,
};

use rome_js_syntax::{JsAwaitExpression, JsSyntaxNode};
use rome_js_syntax::{JsAnyExpression, JsAwaitExpression, JsSyntaxNode};
use rome_js_syntax::{JsAwaitExpressionFields, JsSyntaxKind};

#[derive(Debug, Clone, Default)]
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 = node.resolve_parent();

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,17 +63,36 @@ 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)
}
}
}

impl ExpressionNode for JsAwaitExpression {
#[inline]
fn resolve(&self) -> JsAnyExpression {
self.clone().into()
}

#[inline]
fn into_resolved(self) -> JsAnyExpression {
self.into()
}
}

#[cfg(test)]
mod tests {

Expand Down
Loading

0 comments on commit f2665fe

Please sign in to comment.