From bbdc1994fc6efec9e2711c465f5eb2ab5e4e9d7b Mon Sep 17 00:00:00 2001 From: Jon Egeland Date: Sat, 25 Nov 2023 19:36:13 +0000 Subject: [PATCH 1/3] collapse arrow expressions as curried bodies --- .../expressions/arrow_function_expression.rs | 1 + .../tests/specs/js/module/call/curried.js | 29 ++++ .../specs/js/module/call/curried.js.snap | 97 ++++++++++++ .../prettier/js/arrows/currying-4.js.snap | 140 +++++------------- 4 files changed, 161 insertions(+), 106 deletions(-) create mode 100644 crates/biome_js_formatter/tests/specs/js/module/call/curried.js create mode 100644 crates/biome_js_formatter/tests/specs/js/module/call/curried.js.snap diff --git a/crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs b/crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs index 0edd7cc16c9e..e4c8099622f9 100644 --- a/crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs +++ b/crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs @@ -458,6 +458,7 @@ impl Format for ArrowChain { AnyJsFunctionBody::JsFunctionBody(_) | AnyJsFunctionBody::AnyJsExpression( AnyJsExpression::JsObjectExpression(_) + | AnyJsExpression::JsArrayExpression(_) | AnyJsExpression::JsSequenceExpression(_) ) ); diff --git a/crates/biome_js_formatter/tests/specs/js/module/call/curried.js b/crates/biome_js_formatter/tests/specs/js/module/call/curried.js new file mode 100644 index 000000000000..831940dba637 --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/js/module/call/curried.js @@ -0,0 +1,29 @@ +foo((argument1) => + (argument2) => + (argument3) => + (argument4) => + (argument5) => + (argument6) => + (argument7) => + (argument8) => + (argument9) => + (argument10) => + (argument11) => + (argument12) =>3); + +foo((argument1) => + (argument2) => + (argument3) => + (argument4) => + (argument5) => + (argument6) => + (argument7) => + (argument8) => + (argument9) => + (argument10) => + (argument11) => + (argument12) => ({ + foo: bar, + bar: baz, + baz: foo + })); \ No newline at end of file diff --git a/crates/biome_js_formatter/tests/specs/js/module/call/curried.js.snap b/crates/biome_js_formatter/tests/specs/js/module/call/curried.js.snap new file mode 100644 index 000000000000..4cff6582d07d --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/js/module/call/curried.js.snap @@ -0,0 +1,97 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: js/module/call/curried.js +--- + +# Input + +```js +foo((argument1) => + (argument2) => + (argument3) => + (argument4) => + (argument5) => + (argument6) => + (argument7) => + (argument8) => + (argument9) => + (argument10) => + (argument11) => + (argument12) =>3); + +foo((argument1) => + (argument2) => + (argument3) => + (argument4) => + (argument5) => + (argument6) => + (argument7) => + (argument8) => + (argument9) => + (argument10) => + (argument11) => + (argument12) => ({ + foo: bar, + bar: baz, + baz: foo + })); +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Quote style: Double Quotes +JSX quote style: Double Quotes +Quote properties: As needed +Trailing comma: All +Semicolons: Always +Arrow parentheses: Always +Bracket spacing: true +Bracket same line: false +----- + +```js +foo( + (argument1) => + (argument2) => + (argument3) => + (argument4) => + (argument5) => + (argument6) => + (argument7) => + (argument8) => + (argument9) => + (argument10) => + (argument11) => + (argument12) => + 3, +); + +foo((argument1) => + (argument2) => + (argument3) => + (argument4) => + (argument5) => + (argument6) => + (argument7) => + (argument8) => + (argument9) => + (argument10) => + (argument11) => + (argument12) => ({ + foo: bar, + bar: baz, + baz: foo, + })); +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/arrows/currying-4.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/arrows/currying-4.js.snap index fa5aff9502a3..6f1c4c94b815 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/arrows/currying-4.js.snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/arrows/currying-4.js.snap @@ -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 */); @@ -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 */); From 83d18fac742ba183ddc2e7c7b03b037a1bf9c6f2 Mon Sep 17 00:00:00 2001 From: Jon Egeland Date: Sat, 25 Nov 2023 21:30:32 +0000 Subject: [PATCH 2/3] add comments to arrow function condition values --- .../expressions/arrow_function_expression.rs | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs b/crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs index e4c8099622f9..d7b094e18157 100644 --- a/crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs +++ b/crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs @@ -449,10 +449,35 @@ impl Format for ArrowChain { 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 funciton 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(_) @@ -463,7 +488,10 @@ impl Format for ArrowChain { ) ); - 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) @@ -603,7 +631,7 @@ impl Format 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), From 664cd92572f5fec56bb708fb950c612f74ec4453 Mon Sep 17 00:00:00 2001 From: Jon Egeland Date: Sun, 26 Nov 2023 22:46:13 +0000 Subject: [PATCH 3/3] rip printer group mode fix from ruff --- crates/biome_formatter/src/printer/mod.rs | 6 ++ .../expressions/arrow_function_expression.rs | 21 ++-- .../tests/specs/js/module/call/curried.js | 29 ------ .../specs/js/module/call/curried.js.snap | 97 ------------------- .../prettier/js/arrays/issue-10159.js.snap | 60 ------------ 5 files changed, 20 insertions(+), 193 deletions(-) delete mode 100644 crates/biome_js_formatter/tests/specs/js/module/call/curried.js delete mode 100644 crates/biome_js_formatter/tests/specs/js/module/call/curried.js.snap delete mode 100644 crates/biome_js_formatter/tests/specs/prettier/js/arrays/issue-10159.js.snap diff --git a/crates/biome_formatter/src/printer/mod.rs b/crates/biome_formatter/src/printer/mod.rs index 864ca0749338..826cc5653372 100644 --- a/crates/biome_formatter/src/printer/mod.rs +++ b/crates/biome_formatter/src/printer/mod.rs @@ -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)); diff --git a/crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs b/crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs index d7b094e18157..eb859a76a92a 100644 --- a/crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs +++ b/crates/biome_js_formatter/src/js/expressions/arrow_function_expression.rs @@ -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 { if arrow.type_parameters().is_some() { return Ok(true); @@ -438,6 +447,8 @@ impl Format 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(), @@ -445,10 +456,6 @@ impl Format for ArrowChain { ) }); - 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. @@ -457,13 +464,13 @@ impl Format for ArrowChain { // becomes // ( // () => () => - // a + // a // )(); let is_callee = head_parent .as_ref() .map_or(false, |parent| is_callee(head.syntax(), parent)); - // With arrays, objects, sequence expressions, and block funciton bodies, + // 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. @@ -739,7 +746,7 @@ fn template_literal_contains_new_line(template: &JsTemplateExpression) -> bool { /// /// /// # Examples -// +/// /// ```javascript /// "test" + ` /// some content diff --git a/crates/biome_js_formatter/tests/specs/js/module/call/curried.js b/crates/biome_js_formatter/tests/specs/js/module/call/curried.js deleted file mode 100644 index 831940dba637..000000000000 --- a/crates/biome_js_formatter/tests/specs/js/module/call/curried.js +++ /dev/null @@ -1,29 +0,0 @@ -foo((argument1) => - (argument2) => - (argument3) => - (argument4) => - (argument5) => - (argument6) => - (argument7) => - (argument8) => - (argument9) => - (argument10) => - (argument11) => - (argument12) =>3); - -foo((argument1) => - (argument2) => - (argument3) => - (argument4) => - (argument5) => - (argument6) => - (argument7) => - (argument8) => - (argument9) => - (argument10) => - (argument11) => - (argument12) => ({ - foo: bar, - bar: baz, - baz: foo - })); \ No newline at end of file diff --git a/crates/biome_js_formatter/tests/specs/js/module/call/curried.js.snap b/crates/biome_js_formatter/tests/specs/js/module/call/curried.js.snap deleted file mode 100644 index 4cff6582d07d..000000000000 --- a/crates/biome_js_formatter/tests/specs/js/module/call/curried.js.snap +++ /dev/null @@ -1,97 +0,0 @@ ---- -source: crates/biome_formatter_test/src/snapshot_builder.rs -info: js/module/call/curried.js ---- - -# Input - -```js -foo((argument1) => - (argument2) => - (argument3) => - (argument4) => - (argument5) => - (argument6) => - (argument7) => - (argument8) => - (argument9) => - (argument10) => - (argument11) => - (argument12) =>3); - -foo((argument1) => - (argument2) => - (argument3) => - (argument4) => - (argument5) => - (argument6) => - (argument7) => - (argument8) => - (argument9) => - (argument10) => - (argument11) => - (argument12) => ({ - foo: bar, - bar: baz, - baz: foo - })); -``` - - -============================= - -# Outputs - -## Output 1 - ------ -Indent style: Tab -Indent width: 2 -Line ending: LF -Line width: 80 -Quote style: Double Quotes -JSX quote style: Double Quotes -Quote properties: As needed -Trailing comma: All -Semicolons: Always -Arrow parentheses: Always -Bracket spacing: true -Bracket same line: false ------ - -```js -foo( - (argument1) => - (argument2) => - (argument3) => - (argument4) => - (argument5) => - (argument6) => - (argument7) => - (argument8) => - (argument9) => - (argument10) => - (argument11) => - (argument12) => - 3, -); - -foo((argument1) => - (argument2) => - (argument3) => - (argument4) => - (argument5) => - (argument6) => - (argument7) => - (argument8) => - (argument9) => - (argument10) => - (argument11) => - (argument12) => ({ - foo: bar, - bar: baz, - baz: foo, - })); -``` - - diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/arrays/issue-10159.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/arrays/issue-10159.js.snap deleted file mode 100644 index 61add494c85e..000000000000 --- a/crates/biome_js_formatter/tests/specs/prettier/js/arrays/issue-10159.js.snap +++ /dev/null @@ -1,60 +0,0 @@ ---- -source: crates/biome_formatter_test/src/snapshot_builder.rs -info: js/arrays/issue-10159.js ---- - -# Input - -```js -{for (const srcPath of [src, `${src}.js`, `${src}/index`, `${src}/index.js`]) {}} -{for (const srcPath of [123, 123_123_123, 123_123_123_1, 13_123_3123_31_43]) {}} -{for (const srcPath of [123, 123_123_123, 123_123_123_1, 13_123_3123_31_432]) {}} -{for (const srcPath of [123, 123_123_123, 123_123_123_1, 13_123_3123_31_4321]) {}} - -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Biome -@@ -7,7 +7,9 @@ - } - } - { -- for (const srcPath of [123, 123_123_123, 123_123_123_1, 13_123_3123_31_432]) { -+ for (const srcPath of [ -+ 123, 123_123_123, 123_123_123_1, 13_123_3123_31_432, -+ ]) { - } - } - { -``` - -# Output - -```js -{ - for (const srcPath of [src, `${src}.js`, `${src}/index`, `${src}/index.js`]) { - } -} -{ - for (const srcPath of [123, 123_123_123, 123_123_123_1, 13_123_3123_31_43]) { - } -} -{ - for (const srcPath of [ - 123, 123_123_123, 123_123_123_1, 13_123_3123_31_432, - ]) { - } -} -{ - for (const srcPath of [ - 123, 123_123_123, 123_123_123_1, 13_123_3123_31_4321, - ]) { - } -} -``` - -