Skip to content

Commit

Permalink
fix(js_formatter): array printing and grouping in arrows (#917)
Browse files Browse the repository at this point in the history
  • Loading branch information
faultyserver authored Nov 27, 2023
1 parent 0ee617e commit c1e3f41
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 173 deletions.
6 changes: 6 additions & 0 deletions crates/biome_formatter/src/printer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ impl<'a> Printer<'a> {
_ => {
self.state.measured_group_fits = true;

if let Some(id) = group.id() {
self.state
.group_modes
.insert_print_mode(id, PrintMode::Flat);
}

// Measure to see if the group fits up on a single line. If that's the case,
// print the group in "flat" mode, otherwise continue in expanded mode
stack.push(TagKind::Group, args.with_print_mode(PrintMode::Flat));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,15 @@ fn format_signature(
})
}

/// Returns a `true` result if the arrow function contains any elements which
/// should force the chain to break onto multiple lines. This includes any kind
/// of return type annotation if the function also takes parameters (e.g.,
/// `(a, b): bool => ...`), or any kind of rest/object/array binding parameter
/// (e.g., `({a, b: foo}) => ...`).
///
/// The complexity of these expressions limits their legibility when printed
/// inline, so they force the chain to break to preserve clarity. Any other
/// cases are considered simple enough to print in a single line.
fn should_break_chain(arrow: &JsArrowFunctionExpression) -> SyntaxResult<bool> {
if arrow.type_parameters().is_some() {
return Ok(true);
Expand Down Expand Up @@ -438,31 +447,58 @@ impl Format<JsFormatContext> for ArrowChain {
} = self;

let head_parent = head.syntax().parent();
let tail_body = tail.body()?;
let is_assignment_rhs = self.options.assignment_layout.is_some();
let ancestor_call_expr_or_logical_expr = head.syntax().ancestors().any(|ancestor| {
matches!(
ancestor.kind(),
JsSyntaxKind::JS_CALL_EXPRESSION | JsSyntaxKind::JS_LOGICAL_EXPRESSION
)
});

let tail_body = tail.body()?;

let is_assignment_rhs = self.options.assignment_layout.is_some();

// If this chain is the callee in a parent call expression, then we
// want it to break onto a new line to clearly show that the arrow
// chain is distinct and the _result_ is what's being called.
// Example:
// (() => () => a)()
// becomes
// (
// () => () =>
// a
// )();
let is_callee = head_parent
.as_ref()
.map_or(false, |parent| is_callee(head.syntax(), parent));

// With arrays, objects, sequence expressions, and block function bodies,
// the opening brace gives a convenient boundary to insert a line break,
// allowing that token to live immediately after the last arrow token
// and save a line from being printed with just the punctuation.
//
// (foo) => (bar) => [a, b]
//
// (foo) => (bar) => [
// a,
// b
// ]
//
// If the body is _not_ one of those kinds, then we'll want to insert a
// soft line break before the body so that it prints on a separate line
// in its entirety.
let body_on_separate_line = !matches!(
tail_body,
AnyJsFunctionBody::JsFunctionBody(_)
| AnyJsFunctionBody::AnyJsExpression(
AnyJsExpression::JsObjectExpression(_)
| AnyJsExpression::JsArrayExpression(_)
| AnyJsExpression::JsSequenceExpression(_)
)
);

let break_before_chain = (is_callee && body_on_separate_line)
// If the arrow chain will break onto multiple lines, either because
// it's a callee or because the body is printed on its own line, then
// the signatures should be expanded first.
let break_signatures = (is_callee && body_on_separate_line)
|| matches!(
self.options.assignment_layout,
Some(AssignmentLikeLayout::ChainTailArrowFunction)
Expand Down Expand Up @@ -602,7 +638,7 @@ impl Format<JsFormatContext> for ArrowChain {
[
group(&indent(&format_arrow_signatures))
.with_group_id(Some(group_id))
.should_expand(break_before_chain),
.should_expand(break_signatures),
space(),
tail.fat_arrow_token().format(),
indent_if_group_breaks(&format_tail_body, group_id),
Expand Down Expand Up @@ -710,7 +746,7 @@ fn template_literal_contains_new_line(template: &JsTemplateExpression) -> bool {
///
///
/// # Examples
//
///
/// ```javascript
/// "test" + `
/// some content
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -75,77 +75,7 @@ a(
```diff
--- Prettier
+++ Biome
@@ -41,47 +41,49 @@
"sky.",
];

-const x2 = () => () => [
- "The",
- "green",
- "dragon",
- "liked",
- "to",
- "knit",
- "sweaters",
- "for",
- "the",
- "fluffy",
- "clouds",
- "in",
- "the",
- "sky.",
-];
+const x2 = () => () =>
+ [
+ "The",
+ "green",
+ "dragon",
+ "liked",
+ "to",
+ "knit",
+ "sweaters",
+ "for",
+ "the",
+ "fluffy",
+ "clouds",
+ "in",
+ "the",
+ "sky.",
+ ];

-const x3 = () => () => () => [
- "The",
- "green",
- "dragon",
- "liked",
- "to",
- "knit",
- "sweaters",
- "for",
- "the",
- "fluffy",
- "clouds",
- "in",
- "the",
- "sky.",
-];
+const x3 = () => () => () =>
+ [
+ "The",
+ "green",
+ "dragon",
+ "liked",
+ "to",
+ "knit",
+ "sweaters",
+ "for",
+ "the",
+ "fluffy",
+ "clouds",
+ "in",
+ "the",
+ "sky.",
+ ];
@@ -77,11 +77,11 @@

f((a) => (1, 2, 3) /* a */);
f((a) => (b) => (1, 2, 3) /* b */ /* a */);
Expand Down Expand Up @@ -207,41 +137,39 @@ const x1 = () => [
"sky.",
];

const x2 = () => () =>
[
"The",
"green",
"dragon",
"liked",
"to",
"knit",
"sweaters",
"for",
"the",
"fluffy",
"clouds",
"in",
"the",
"sky.",
];

const x3 = () => () => () =>
[
"The",
"green",
"dragon",
"liked",
"to",
"knit",
"sweaters",
"for",
"the",
"fluffy",
"clouds",
"in",
"the",
"sky.",
];
const x2 = () => () => [
"The",
"green",
"dragon",
"liked",
"to",
"knit",
"sweaters",
"for",
"the",
"fluffy",
"clouds",
"in",
"the",
"sky.",
];

const x3 = () => () => () => [
"The",
"green",
"dragon",
"liked",
"to",
"knit",
"sweaters",
"for",
"the",
"fluffy",
"clouds",
"in",
"the",
"sky.",
];

f((a) => (1, 2, 3) /* a */);
f((a) => (b) => (1, 2, 3) /* b */ /* a */);
Expand Down

0 comments on commit c1e3f41

Please sign in to comment.