Skip to content

Commit

Permalink
challenge(formatter): Handle special first-argument expansions in cal…
Browse files Browse the repository at this point in the history
…l arguments (#777)
  • Loading branch information
faultyserver committed Nov 19, 2023
1 parent cd234f7 commit 70c10d4
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 602 deletions.
101 changes: 97 additions & 4 deletions crates/biome_js_formatter/src/js/expressions/call_arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use crate::js::expressions::arrow_function_expression::{
use crate::js::lists::array_element_list::can_concisely_print_array_list;
use crate::prelude::*;
use crate::utils::function_body::FunctionBodyCacheMode;
use crate::utils::member_chain::SimpleArgument;
use crate::utils::test_call::is_test_call_expression;
use crate::utils::{is_long_curried_call, write_arguments_multi_line};
use biome_formatter::{format_args, format_element, write, VecBuffer};
use biome_js_syntax::{
AnyJsCallArgument, AnyJsExpression, AnyJsFunctionBody, AnyJsLiteralExpression, AnyJsStatement,
AnyTsReturnType, AnyTsType, JsCallArgumentList, JsCallArguments, JsCallArgumentsFields,
JsCallExpression, JsExpressionStatement, JsFunctionExpression, JsImportCallExpression,
JsLanguage,
AnyTsReturnType, AnyTsType, JsBinaryExpressionFields, JsCallArgumentList, JsCallArguments,
JsCallArgumentsFields, JsCallExpression, JsExpressionStatement, JsFunctionExpression,
JsImportCallExpression, JsLanguage, TsAsExpressionFields, TsSatisfiesExpressionFields,
};
use biome_rowan::{AstSeparatedElement, AstSeparatedList, SyntaxResult};

Expand Down Expand Up @@ -796,7 +797,8 @@ fn should_group_first_argument(
}

Ok(!comments.has_comments(first.syntax())
&& !can_group_expression_argument(&second, false, comments)?)
&& !can_group_expression_argument(&second, false, comments)?
&& is_relatively_short_argument(second))
}
_ => Ok(false),
}
Expand Down Expand Up @@ -859,6 +861,97 @@ fn should_group_last_argument(
}
}

/// Check if `ty` is a relatively simple type annotation, allowing a few
/// additional cases through. The simplicity is determined as
/// either being a keyword type or any reference type with no additional type
/// parameters. For example:
/// number => true
/// unknown => true
/// HTMLElement => true
/// string | object => false
/// Foo<string> => false
///
/// Note that Prettier allows extracting the inner type from arrays and
/// single-argument generic types, but for now, this implementation does not.
fn is_simple_ts_type(ty: AnyTsType) -> bool {
match ty {
// Any keyword or literal types
AnyTsType::TsAnyType(_)
| AnyTsType::TsBigintLiteralType(_)
| AnyTsType::TsBigintType(_)
| AnyTsType::TsBooleanLiteralType(_)
| AnyTsType::TsBooleanType(_)
| AnyTsType::TsNeverType(_)
| AnyTsType::TsNullLiteralType(_)
| AnyTsType::TsNumberLiteralType(_)
| AnyTsType::TsNumberType(_)
| AnyTsType::TsObjectType(_)
| AnyTsType::TsStringLiteralType(_)
| AnyTsType::TsStringType(_)
| AnyTsType::TsSymbolType(_)
| AnyTsType::TsTemplateLiteralType(_)
| AnyTsType::TsThisType(_)
| AnyTsType::TsUndefinedType(_)
| AnyTsType::TsUnknownType(_)
| AnyTsType::TsVoidType(_) => true,

// Any reference with no generic type arguments
AnyTsType::TsReferenceType(reference) => reference.type_arguments().is_none(),

_ => false,
}
}

/// Checks if `argument` is "short" enough to be groupable. This aims to be
/// logically similar to Prettier's [`isHopefullyShortCallArgument`](https://github.com/prettier/prettier/blob/093745f0ec429d3db47c1edd823357e0ef24e226/src/language-js/print/call-arguments.js#L279),
fn is_relatively_short_argument(argument: AnyJsExpression) -> bool {
match argument {
AnyJsExpression::JsBinaryExpression(binary_expression) => {
if let JsBinaryExpressionFields {
left: Ok(left),
operator_token: _,
right: Ok(right),
} = binary_expression.as_fields()
{
SimpleArgument::from(left).is_simple() && SimpleArgument::from(right).is_simple()
} else {
false
}
}
AnyJsExpression::TsAsExpression(as_expression) => {
if let TsAsExpressionFields {
expression: Ok(expression),
as_token: _,
ty: Ok(annotation),
} = as_expression.as_fields()
{
is_simple_ts_type(annotation) && SimpleArgument::from(expression).is_simple()
} else {
false
}
}
AnyJsExpression::TsSatisfiesExpression(as_expression) => {
if let TsSatisfiesExpressionFields {
expression: Ok(expression),
satisfies_token: _,
ty: Ok(annotation),
} = as_expression.as_fields()
{
is_simple_ts_type(annotation) && SimpleArgument::from(expression).is_simple()
} else {
false
}
}
AnyJsExpression::AnyJsLiteralExpression(
AnyJsLiteralExpression::JsRegexLiteralExpression(_),
) => true,
AnyJsExpression::JsCallExpression(call) => call
.arguments()
.map_or(false, |args| args.args().len() <= 1),
_ => SimpleArgument::from(argument).is_simple(),
}
}

/// Checks if `argument` benefits from grouping in call arguments.
fn can_group_expression_argument(
argument: &AnyJsExpression,
Expand Down
2 changes: 1 addition & 1 deletion crates/biome_js_formatter/src/utils/member_chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ use crate::utils::member_chain::chain_member::{CallExpressionPosition, ChainMemb
use crate::utils::member_chain::groups::{
MemberChainGroup, MemberChainGroupsBuilder, TailChainGroups,
};
use crate::utils::member_chain::simple_argument::SimpleArgument;
pub use crate::utils::member_chain::simple_argument::SimpleArgument;
use crate::utils::test_call::is_test_call_expression;
use crate::JsLabels;
use biome_formatter::{write, Buffer};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use biome_rowan::{AstSeparatedList, SyntaxResult};
/// [TsNonNullAssertionExpression]: [biome_js_syntax::TsNonNullAssertionExpression]
/// [Prettier]: https://github.com/prettier/prettier/blob/a9de2a128cc8eea84ddd90efdc210378a894ab6b/src/language-js/utils/index.js#L802-L886
#[derive(Debug)]
pub(crate) enum SimpleArgument {
pub enum SimpleArgument {
Expression(AnyJsExpression),
Assignment(AnyJsAssignment),
Name(AnyJsName),
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

0 comments on commit 70c10d4

Please sign in to comment.