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): chain tail arrow function
Browse files Browse the repository at this point in the history
  • Loading branch information
ematipico committed Jun 20, 2022
1 parent 58f73b4 commit 984337f
Show file tree
Hide file tree
Showing 11 changed files with 242 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
use crate::prelude::*;
use crate::utils::JsObjectPatternLike;
use crate::FormatNodeFields;
use rome_formatter::write;
use rome_js_syntax::JsObjectAssignmentPattern;
use rome_js_syntax::JsObjectAssignmentPatternFields;

impl FormatNodeFields<JsObjectAssignmentPattern> for FormatNodeRule<JsObjectAssignmentPattern> {
fn fmt_fields(node: &JsObjectAssignmentPattern, f: &mut JsFormatter) -> FormatResult<()> {
let JsObjectAssignmentPatternFields {
l_curly_token,
properties,
r_curly_token,
} = node.as_fields();

write!(
f,
[
format_delimited(&l_curly_token?, &properties.format(), &r_curly_token?,)
.soft_block_spaces()
]
)
write!(f, [JsObjectPatternLike::from(node.clone())])
}
}
16 changes: 2 additions & 14 deletions crates/rome_js_formatter/src/js/bindings/object_binding_pattern.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
use crate::prelude::*;
use crate::utils::JsObjectPatternLike;
use crate::FormatNodeFields;
use rome_formatter::write;
use rome_js_syntax::JsObjectBindingPattern;
use rome_js_syntax::JsObjectBindingPatternFields;

impl FormatNodeFields<JsObjectBindingPattern> for FormatNodeRule<JsObjectBindingPattern> {
fn fmt_fields(node: &JsObjectBindingPattern, f: &mut JsFormatter) -> FormatResult<()> {
let JsObjectBindingPatternFields {
l_curly_token,
properties,
r_curly_token,
} = node.as_fields();

write!(
f,
[
format_delimited(&l_curly_token?, &properties.format(), &r_curly_token?,)
.soft_block_spaces()
]
)
write!(f, [JsObjectPatternLike::from(node.clone())])
}
}
10 changes: 5 additions & 5 deletions crates/rome_js_formatter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,11 +526,11 @@ mod test {
// use this test check if your snippet prints as you wish, without using a snapshot
fn quick_test() {
let src = r#"
a = {
ee: {qqq, ffff},
loreum,
ipsurmm,
} = {};
class C {
set something({ something: { els: {lorem} } }) {}
}
"#;
let syntax = SourceType::ts();
Expand Down
64 changes: 39 additions & 25 deletions crates/rome_js_formatter/src/utils/assignment_like.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::utils::object::write_member_name;
use crate::utils::JsAnyBinaryLikeExpression;
use rome_formatter::{format_args, write};
use rome_js_syntax::{
JsAnyAssignmentPattern, JsAnyExpression, JsAnyObjectAssignmentPatternMember,
JsAnyAssignmentPattern, JsAnyExpression, JsAnyFunctionBody, JsAnyObjectAssignmentPatternMember,
JsAnyObjectBindingPatternMember, JsAnyObjectMemberName, JsAssignmentExpression,
JsObjectAssignmentPattern, JsObjectAssignmentPatternProperty, JsObjectBindingPattern,
JsPropertyObjectMember, JsSyntaxKind,
Expand Down Expand Up @@ -33,7 +33,7 @@ declare_node_union! {

impl AnyObjectPattern {
fn is_complex(&self) -> SyntaxResult<bool> {
return match self {
match self {
AnyObjectPattern::JsObjectAssignmentPattern(assignment_pattern) => {
let properties_len = assignment_pattern.properties().len();
// A binding is complex when we have at least one [JsObjectBindingPatternProperty]
Expand Down Expand Up @@ -76,19 +76,16 @@ impl AnyObjectPattern {
});
Ok(properties_len > 2 && has_at_least_a_complex_binding)
}
};
}
}
}

impl LeftAssignmentLike {
fn as_object_assignment_pattern(&self) -> Option<AnyObjectPattern> {
match self {
LeftAssignmentLike::JsAnyAssignmentPattern(pattern) => match pattern {
JsAnyAssignmentPattern::JsObjectAssignmentPattern(node) => {
Some(AnyObjectPattern::from(node.clone()))
}
_ => None,
},
LeftAssignmentLike::JsAnyAssignmentPattern(
JsAnyAssignmentPattern::JsObjectAssignmentPattern(node),
) => Some(AnyObjectPattern::from(node.clone())),
_ => None,
}
}
Expand Down Expand Up @@ -174,6 +171,9 @@ pub(crate) enum AssignmentLikeLayout {

///
BreakLeftHandSide,

///
ChainTailArrowFunction,
}

impl JsAnyAssignmentLike {
Expand Down Expand Up @@ -244,7 +244,7 @@ impl JsAnyAssignmentLike {
}
}

fn format_right<'t>(&self, f: &mut JsFormatter) -> FormatResult<()> {
fn write_right(&self, f: &mut JsFormatter) -> FormatResult<()> {
match self {
JsAnyAssignmentLike::JsPropertyObjectMember(property) => {
let value = property.value()?;
Expand Down Expand Up @@ -347,7 +347,25 @@ impl JsAnyAssignmentLike {
if right_is_tail {
Some(AssignmentLikeLayout::ChainTail)
} else {
Some(AssignmentLikeLayout::Chain)
match right {
RightAssignmentLike::JsAnyExpression(
JsAnyExpression::JsArrowFunctionExpression(arrow),
) => {
let body = arrow.body()?;
if matches!(
body,
JsAnyFunctionBody::JsAnyExpression(
JsAnyExpression::JsArrowFunctionExpression(_)
)
) {
Some(AssignmentLikeLayout::ChainTailArrowFunction)
} else {
Some(AssignmentLikeLayout::Chain)
}
}

_ => Some(AssignmentLikeLayout::Chain),
}
}
} else {
None
Expand Down Expand Up @@ -415,14 +433,6 @@ pub(crate) fn is_break_after_operator(right: &JsAnyExpression) -> SyntaxResult<b
}
}

// head is a long chain, meaning that right -> right are both assignment expressions
if let JsAnyExpression::JsAssignmentExpression(assignment) = right {
let right = assignment.right()?;
if matches!(right, JsAnyExpression::JsAssignmentExpression(_)) {
return Ok(true);
}
}

if JsAnyBinaryLikeExpression::cast(right.syntax().clone())
.map_or(false, |expression| !expression.should_inline())
{
Expand Down Expand Up @@ -474,7 +484,7 @@ impl Format<JsFormatContext> for JsAnyAssignmentLike {
AssignmentLikeLayout::Fluid => {
let group_id = f.group_id("assignment_like");

let right = format_with(|f| self.format_right(f)).memoized();
let right = format_with(|f| self.write_right(f)).memoized();

write![
f,
Expand All @@ -492,14 +502,14 @@ impl Format<JsFormatContext> for JsAnyAssignmentLike {
f,
[group_elements(&indent(&format_args![
soft_line_break_or_space(),
format_with(|f| { self.format_right(f) }),
format_with(|f| { self.write_right(f) }),
])),]
]
}
AssignmentLikeLayout::NeverBreakAfterOperator => {
write![
f,
[space_token(), format_with(|f| { self.format_right(f) }),]
[space_token(), format_with(|f| { self.write_right(f) }),]
]
}

Expand All @@ -508,7 +518,7 @@ impl Format<JsFormatContext> for JsAnyAssignmentLike {
f,
[
space_token(),
group_elements(&format_with(|f| { self.format_right(f) }),),
group_elements(&format_with(|f| { self.write_right(f) }),),
]
]
}
Expand All @@ -518,7 +528,7 @@ impl Format<JsFormatContext> for JsAnyAssignmentLike {
f,
[
soft_line_break_or_space(),
format_with(|f| { self.format_right(f) }),
format_with(|f| { self.write_right(f) }),
]
)
}
Expand All @@ -528,10 +538,14 @@ impl Format<JsFormatContext> for JsAnyAssignmentLike {
f,
[&indent(&format_args![
soft_line_break_or_space(),
format_with(|f| { self.format_right(f) }),
format_with(|f| { self.write_right(f) }),
])]
)
}

AssignmentLikeLayout::ChainTailArrowFunction => {
write!(f, [space_token(), format_with(|f| { self.write_right(f) })])
}
});

match layout {
Expand Down
2 changes: 2 additions & 0 deletions crates/rome_js_formatter/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod string_utils;
pub(crate) mod format_class;
mod member_chain;
mod object;
mod object_pattern_like;
#[cfg(test)]
mod quickcheck_utils;

Expand All @@ -16,6 +17,7 @@ pub(crate) use assignment_like::{is_break_after_operator, JsAnyAssignmentLike};
pub(crate) use binary_like_expression::{format_binary_like_expression, JsAnyBinaryLikeExpression};
pub(crate) use format_conditional::{format_conditional, Conditional};
pub(crate) use member_chain::format_call_expression;
pub(crate) use object_pattern_like::JsObjectPatternLike;
use rome_formatter::{format_args, normalize_newlines, write, Buffer, VecBuffer};
use rome_js_syntax::suppression::{has_suppressions_category, SuppressionCategory};
use rome_js_syntax::JsSyntaxKind::JS_STRING_LITERAL;
Expand Down
129 changes: 129 additions & 0 deletions crates/rome_js_formatter/src/utils/object_pattern_like.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
use crate::prelude::*;
use crate::JsFormatContext;
use rome_formatter::formatter::Formatter;
use rome_formatter::write;
use rome_formatter::{Format, FormatResult};
use rome_js_syntax::{
JsAnyAssignmentPattern, JsAnyBindingPattern, JsAnyObjectAssignmentPatternMember,
JsAnyObjectBindingPatternMember, JsObjectAssignmentPattern, JsObjectBindingPattern,
JsSyntaxKind, JsSyntaxToken,
};
use rome_rowan::{declare_node_union, AstNode, SyntaxResult};

declare_node_union! {
pub (crate) JsObjectPatternLike = JsObjectAssignmentPattern | JsObjectBindingPattern
}

impl JsObjectPatternLike {
fn l_curly_token(&self) -> SyntaxResult<JsSyntaxToken> {
match self {
JsObjectPatternLike::JsObjectAssignmentPattern(node) => node.l_curly_token(),
JsObjectPatternLike::JsObjectBindingPattern(node) => node.l_curly_token(),
}
}

fn r_curly_token(&self) -> SyntaxResult<JsSyntaxToken> {
match self {
JsObjectPatternLike::JsObjectAssignmentPattern(node) => node.r_curly_token(),
JsObjectPatternLike::JsObjectBindingPattern(node) => node.r_curly_token(),
}
}

fn write_properties(&self, f: &mut JsFormatter) -> FormatResult<()> {
match self {
JsObjectPatternLike::JsObjectAssignmentPattern(node) => {
write!(f, [node.properties().format()])
}
JsObjectPatternLike::JsObjectBindingPattern(node) => {
write!(f, [node.properties().format()])
}
}
}

fn should_break_properties(&self) -> SyntaxResult<bool> {
let has_at_least_a_complex_property = match self {
JsObjectPatternLike::JsObjectAssignmentPattern(node) => {
node.properties().iter().any(|property| {
if let Ok(
JsAnyObjectAssignmentPatternMember::JsObjectAssignmentPatternProperty(node),
) = property
{
let pattern = node.pattern();
matches!(
pattern,
Ok(JsAnyAssignmentPattern::JsObjectAssignmentPattern(_)
| JsAnyAssignmentPattern::JsArrayAssignmentPattern(_))
)
} else {
false
}
})
}
JsObjectPatternLike::JsObjectBindingPattern(node) => {
node.properties().iter().any(|property| {
if let Ok(JsAnyObjectBindingPatternMember::JsObjectBindingPatternProperty(
node,
)) = property
{
let pattern = node.pattern();
matches!(
pattern,
Ok(JsAnyBindingPattern::JsObjectBindingPattern(_)
| JsAnyBindingPattern::JsArrayBindingPattern(_))
)
} else {
false
}
})
}
};

let parent_kind = self.syntax().parent().map(|p| p.kind());

let parent_where_not_to_break = !matches!(
parent_kind,
Some(
// These parents are the kinds where we want to prevent
// to go to multiple lines.
JsSyntaxKind::JS_FUNCTION_EXPRESSION
| JsSyntaxKind::JS_ARROW_FUNCTION_EXPRESSION
| JsSyntaxKind::JS_OBJECT_ASSIGNMENT_PATTERN_PROPERTY
| JsSyntaxKind::JS_CATCH_DECLARATION
| JsSyntaxKind::JS_FUNCTION_DECLARATION
| JsSyntaxKind::JS_OBJECT_BINDING_PATTERN_PROPERTY
| JsSyntaxKind::JS_FORMAL_PARAMETER
)
);

Ok(parent_where_not_to_break && has_at_least_a_complex_property)
}
}

impl Format<JsFormatContext> for JsObjectPatternLike {
fn fmt(&self, f: &mut Formatter<JsFormatContext>) -> FormatResult<()> {
let should_break_properties = self.should_break_properties()?;

if should_break_properties {
write!(
f,
[
&self.l_curly_token()?.format(),
group_elements(&block_indent(&format_with(|f| {
self.write_properties(f)
}),),),
&self.r_curly_token()?.format(),
]
)
} else {
write!(
f,
[format_delimited(
&self.l_curly_token()?,
&format_with(|f| { self.write_properties(f) }),
&self.r_curly_token()?,
)
.soft_block_spaces()]
)
}
}
}
Loading

0 comments on commit 984337f

Please sign in to comment.