From c7a8c36cd7e86c0b5be901bd9464857fb64c1beb Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Thu, 25 Aug 2022 10:47:09 +0200 Subject: [PATCH] feat(rome_js_formatter): Parenthesize Types This PR implements the rules for when parentheses around TypeScript types are needed or can be removed without changing the semantics of the program. The majority of the PR is to implement `NeedsParentheses` for every `TsType`. This PR further fixes an instability issue with the syntax rewriter. The rewriter used to remove all whitespace between the `(` paren and the token (or first comment and skipped token trivia). This is necessary or the formatter otherwise inserts an extra blank line before nodes that are parenthesized: ``` a ( Long && Longer && ) ``` becomes ``` a ( Long && Longer && ) ``` Notice, the added new line. What this logic didn't account for is that it should not remove a leading new line before a comment because we want to keep the comment on its own line and this requires that there's a leading new line trivia. The last fix is in the source map that so far assumed that all ranges are added in increasing `end` order ``` correct: 2..3, 2..4, 2..5 (notice how the ranges are sorted by end) incorrect: 2..4, 2..3, 2..5 ``` This PR updates the sorting of the text ranges to also account the end ranges. I added unit tests for all rules where parentheses are required and reviewed the updated snapshots. There are a few new changes but these unrelated to parentheses but instead problems with the formatting of the specific syntax. Average compatibility: 83.70 -> 84.11 Compatible lines: 80.79 -> 81.42 --- .../js/declarations/variable_declaration.rs | 11 +- .../src/js/lists/variable_declarator_list.rs | 88 +++---- crates/rome_js_formatter/src/parentheses.rs | 160 +++++++++++- .../rome_js_formatter/src/syntax_rewriter.rs | 4 + .../ts/expressions/template_literal_type.rs | 13 +- .../src/ts/module/import_type.rs | 13 +- .../src/ts/types/any_type.rs | 14 +- .../src/ts/types/array_type.rs | 14 +- .../src/ts/types/asserts_return_type.rs | 14 +- .../src/ts/types/big_int_literal_type.rs | 13 +- .../src/ts/types/bigint_type.rs | 13 +- .../src/ts/types/boolean_literal_type.rs | 13 +- .../src/ts/types/boolean_type.rs | 13 +- .../src/ts/types/conditional_type.rs | 104 +++++++- .../src/ts/types/constructor_type.rs | 61 ++++- .../src/ts/types/function_type.rs | 80 +++++- .../src/ts/types/indexed_access_type.rs | 13 +- .../src/ts/types/infer_type.rs | 37 ++- .../src/ts/types/intersection_type.rs | 80 +++++- .../src/ts/types/mapped_type.rs | 13 +- .../src/ts/types/never_type.rs | 13 +- .../src/ts/types/non_primitive_type.rs | 13 +- .../src/ts/types/null_literal_type.rs | 13 +- .../src/ts/types/number_literal_type.rs | 13 +- .../src/ts/types/number_type.rs | 13 +- .../src/ts/types/object_type.rs | 13 +- .../src/ts/types/parenthesized_type.rs | 24 +- .../src/ts/types/reference_type.rs | 13 +- .../src/ts/types/string_literal_type.rs | 13 +- .../src/ts/types/string_type.rs | 13 +- .../src/ts/types/symbol_type.rs | 13 +- .../src/ts/types/this_type.rs | 13 +- .../src/ts/types/tuple_type.rs | 13 +- .../src/ts/types/type_operator_type.rs | 37 ++- .../src/ts/types/typeof_type.rs | 13 +- .../src/ts/types/undefined_type.rs | 13 +- .../src/ts/types/union_type.rs | 55 ++-- .../src/ts/types/unknown_type.rs | 13 +- .../src/ts/types/void_type.rs | 13 +- .../src/utils/assignment_like.rs | 25 +- .../src/utils/conditional.rs | 2 +- .../specs/prettier/typescript/as/as.ts.snap | 19 +- .../contextualSignatureInstantiation2.ts.snap | 4 +- .../conditonal-types.ts.snap | 137 ---------- ...nctionTypeNoUnnecessaryParentheses.ts.snap | 34 --- .../typeParameters/functionTypeLong.ts.snap | 48 ---- .../function-type/type-annotation.ts.snap | 36 --- .../intersection/intersection-parens.ts.snap | 177 ------------- .../prettier/typescript/keyof/keyof.ts.snap | 57 ---- .../keyword-types/conditional-types.ts.snap | 48 +--- ...keyword-types-with-parens-comments.ts.snap | 197 ++++++-------- .../typescript/rest-type/infer-type.ts.snap | 58 ----- .../typescript/union/comments.ts.snap | 58 ----- .../typescript/union/inlining.ts.snap | 28 +- .../typescript/union/prettier-ignore.ts.snap | 28 +- .../typescript/union/union-parens.ts.snap | 245 +++++------------- .../typescript/union/within-tuple.ts.snap | 134 ++++------ .../ts/expression/type_expression.ts.snap | 2 +- 58 files changed, 1237 insertions(+), 1195 deletions(-) delete mode 100644 crates/rome_js_formatter/tests/specs/prettier/typescript/conditional-types/conditonal-types.ts.snap delete mode 100644 crates/rome_js_formatter/tests/specs/prettier/typescript/conformance/types/functions/TSFunctionTypeNoUnnecessaryParentheses.ts.snap delete mode 100644 crates/rome_js_formatter/tests/specs/prettier/typescript/custom/typeParameters/functionTypeLong.ts.snap delete mode 100644 crates/rome_js_formatter/tests/specs/prettier/typescript/function-type/type-annotation.ts.snap delete mode 100644 crates/rome_js_formatter/tests/specs/prettier/typescript/intersection/intersection-parens.ts.snap delete mode 100644 crates/rome_js_formatter/tests/specs/prettier/typescript/keyof/keyof.ts.snap delete mode 100644 crates/rome_js_formatter/tests/specs/prettier/typescript/rest-type/infer-type.ts.snap delete mode 100644 crates/rome_js_formatter/tests/specs/prettier/typescript/union/comments.ts.snap diff --git a/crates/rome_js_formatter/src/js/declarations/variable_declaration.rs b/crates/rome_js_formatter/src/js/declarations/variable_declaration.rs index 34e2313261f0..2243320127d6 100644 --- a/crates/rome_js_formatter/src/js/declarations/variable_declaration.rs +++ b/crates/rome_js_formatter/src/js/declarations/variable_declaration.rs @@ -1,5 +1,5 @@ use crate::prelude::*; -use rome_formatter::write; +use rome_formatter::{format_args, write}; use rome_js_syntax::JsVariableDeclaration; use rome_js_syntax::JsVariableDeclarationFields; @@ -11,6 +11,13 @@ impl FormatNodeRule for FormatJsVariableDeclaration { fn fmt_fields(&self, node: &JsVariableDeclaration, f: &mut JsFormatter) -> FormatResult<()> { let JsVariableDeclarationFields { kind, declarators } = node.as_fields(); - write!(f, [kind.format(), space(), declarators.format()]) + write!( + f, + [group(&format_args![ + kind.format(), + space(), + declarators.format() + ])] + ) } } diff --git a/crates/rome_js_formatter/src/js/lists/variable_declarator_list.rs b/crates/rome_js_formatter/src/js/lists/variable_declarator_list.rs index 39f070c7f344..bc8894ac7b76 100644 --- a/crates/rome_js_formatter/src/js/lists/variable_declarator_list.rs +++ b/crates/rome_js_formatter/src/js/lists/variable_declarator_list.rs @@ -11,60 +11,56 @@ impl FormatRule for FormatJsVariableDeclaratorList { type Context = JsFormatContext; fn fmt(&self, node: &JsVariableDeclaratorList, f: &mut JsFormatter) -> FormatResult<()> { - let format_inner = format_with(|f| { - let length = node.len(); + let length = node.len(); - let is_parent_for_loop = node.syntax().grand_parent().map_or(false, |grand_parent| { - matches!( - grand_parent.kind(), - JsSyntaxKind::JS_FOR_STATEMENT - | JsSyntaxKind::JS_FOR_OF_STATEMENT - | JsSyntaxKind::JS_FOR_IN_STATEMENT - ) - }); - - let has_any_initializer = node.iter().any(|declarator| { - declarator.map_or(false, |declarator| declarator.initializer().is_some()) - }); + let is_parent_for_loop = node.syntax().grand_parent().map_or(false, |grand_parent| { + matches!( + grand_parent.kind(), + JsSyntaxKind::JS_FOR_STATEMENT + | JsSyntaxKind::JS_FOR_OF_STATEMENT + | JsSyntaxKind::JS_FOR_IN_STATEMENT + ) + }); - let format_separator = format_with(|f| { - if !is_parent_for_loop && has_any_initializer { - write!(f, [hard_line_break()]) - } else { - write!(f, [soft_line_break_or_space()]) - } - }); + let has_any_initializer = node.iter().any(|declarator| { + declarator.map_or(false, |declarator| declarator.initializer().is_some()) + }); - let mut declarators = node.iter().zip( - node.format_separated(JsSyntaxKind::COMMA) - .with_trailing_separator(TrailingSeparator::Disallowed), - ); + let format_separator = format_with(|f| { + if !is_parent_for_loop && has_any_initializer { + write!(f, [hard_line_break()]) + } else { + write!(f, [soft_line_break_or_space()]) + } + }); - let (first_declarator, format_first_declarator) = match declarators.next() { - Some((syntax, format_first_declarator)) => (syntax?, format_first_declarator), - None => return Err(FormatError::SyntaxError), - }; + let mut declarators = node.iter().zip( + node.format_separated(JsSyntaxKind::COMMA) + .with_trailing_separator(TrailingSeparator::Disallowed), + ); - if length == 1 && !first_declarator.syntax().has_leading_comments() { - return write!(f, [format_first_declarator]); - } + let (first_declarator, format_first_declarator) = match declarators.next() { + Some((syntax, format_first_declarator)) => (syntax?, format_first_declarator), + None => return Err(FormatError::SyntaxError), + }; - write!( - f, - [indent(&format_once(|f| { - write!(f, [format_first_declarator])?; + if length == 1 && !first_declarator.syntax().has_leading_comments() { + return write!(f, [format_first_declarator]); + } - if length > 1 { - write!(f, [format_separator])?; - } + write!( + f, + [indent(&format_once(|f| { + write!(f, [format_first_declarator])?; - f.join_with(&format_separator) - .entries(declarators.map(|(_, format)| format)) - .finish() - }))] - ) - }); + if length > 1 { + write!(f, [format_separator])?; + } - write!(f, [group(&format_inner)]) + f.join_with(&format_separator) + .entries(declarators.map(|(_, format)| format)) + .finish() + }))] + ) } } diff --git a/crates/rome_js_formatter/src/parentheses.rs b/crates/rome_js_formatter/src/parentheses.rs index 45ff5eb30dbf..eeabd9ce0d09 100644 --- a/crates/rome_js_formatter/src/parentheses.rs +++ b/crates/rome_js_formatter/src/parentheses.rs @@ -44,10 +44,11 @@ use rome_js_syntax::{ JsAnyLiteralExpression, JsArrowFunctionExpression, JsAssignmentExpression, JsBinaryExpression, JsBinaryOperator, JsComputedMemberAssignment, JsComputedMemberExpression, JsConditionalExpression, JsLanguage, JsParenthesizedAssignment, JsParenthesizedExpression, - JsSequenceExpression, JsStaticMemberAssignment, JsStaticMemberExpression, JsSyntaxKind, - JsSyntaxNode, JsSyntaxToken, + JsSequenceExpression, JsSyntaxKind, JsSyntaxNode, JsSyntaxToken, TsConditionalType, + TsIndexedAccessType, TsIntersectionTypeElementList, TsParenthesizedType, TsType, + TsUnionTypeVariantList, }; -use rome_rowan::{declare_node_union, match_ast, AstNode, SyntaxResult}; +use rome_rowan::{declare_node_union, match_ast, AstNode, AstSeparatedList, SyntaxResult}; /// Node that may be parenthesized to ensure it forms valid syntax or to improve readability pub trait NeedsParentheses: AstNode { @@ -597,8 +598,76 @@ pub(crate) fn is_spread(node: &JsSyntaxNode, parent: &JsSyntaxNode) -> bool { ) } +/// Returns `true` if a TS primary type needs parentheses +pub(crate) fn operator_type_or_higher_needs_parens( + node: &JsSyntaxNode, + parent: &JsSyntaxNode, +) -> bool { + debug_assert_is_parent(node, parent); + + match parent.kind() { + JsSyntaxKind::TS_ARRAY_TYPE + | JsSyntaxKind::TS_TYPE_OPERATOR_TYPE + | JsSyntaxKind::TS_REST_TUPLE_TYPE_ELEMENT + | JsSyntaxKind::TS_OPTIONAL_TUPLE_TYPE_ELEMENT => true, + JsSyntaxKind::TS_INDEXED_ACCESS_TYPE => { + let indexed = TsIndexedAccessType::unwrap_cast(parent.clone()); + + indexed.object_type().map(AstNode::into_syntax).as_ref() == Ok(node) + } + _ => false, + } +} + +/// Tests if `node` is the check type of a [TsConditionalType] +/// +/// ```javascript +/// type s = A extends string ? string : number // true for `A`, false for `string` and `number` +/// ``` +pub(crate) fn is_check_type(node: &JsSyntaxNode, parent: &JsSyntaxNode) -> bool { + debug_assert_is_parent(node, parent); + + match parent.kind() { + JsSyntaxKind::TS_CONDITIONAL_TYPE => { + let conditional = TsConditionalType::unwrap_cast(parent.clone()); + + conditional.check_type().map(AstNode::into_syntax).as_ref() == Ok(node) + } + _ => false, + } +} + +/// Returns `true` if node is in a union or intersection type with more than one variant +/// +/// ```javascript +/// type A = &string // -> false for `string` because `string` is the only variant +/// type B = string & number // -> true for `string` or `number` +/// type C = |string // -> false +/// type D = string | number // -> true +/// ``` +pub(crate) fn is_in_many_type_union_or_intersection_list( + node: &JsSyntaxNode, + parent: &JsSyntaxNode, +) -> bool { + debug_assert_is_parent(node, parent); + + match parent.kind() { + JsSyntaxKind::TS_UNION_TYPE_VARIANT_LIST => { + let list = TsUnionTypeVariantList::unwrap_cast(parent.clone()); + + list.len() > 1 + } + JsSyntaxKind::TS_INTERSECTION_TYPE_ELEMENT_LIST => { + let list = TsIntersectionTypeElementList::unwrap_cast(parent.clone()); + + list.len() > 1 + } + _ => false, + } +} + declare_node_union! { - pub(crate) JsAnyParenthesized = JsParenthesizedExpression | JsParenthesizedAssignment + pub(crate) JsAnyParenthesized = JsParenthesizedExpression | JsParenthesizedAssignment | TsParenthesizedType } impl JsAnyParenthesized { @@ -606,6 +675,7 @@ impl JsAnyParenthesized { match self { JsAnyParenthesized::JsParenthesizedExpression(expression) => expression.l_paren_token(), JsAnyParenthesized::JsParenthesizedAssignment(assignment) => assignment.l_paren_token(), + JsAnyParenthesized::TsParenthesizedType(ty) => ty.l_paren_token(), } } @@ -617,6 +687,7 @@ impl JsAnyParenthesized { JsAnyParenthesized::JsParenthesizedAssignment(assignment) => { assignment.assignment().map(AstNode::into_syntax) } + JsAnyParenthesized::TsParenthesizedType(ty) => ty.ty().map(AstNode::into_syntax), } } @@ -624,6 +695,7 @@ impl JsAnyParenthesized { match self { JsAnyParenthesized::JsParenthesizedExpression(expression) => expression.r_paren_token(), JsAnyParenthesized::JsParenthesizedAssignment(assignment) => assignment.r_paren_token(), + JsAnyParenthesized::TsParenthesizedType(ty) => ty.r_paren_token(), } } } @@ -716,6 +788,86 @@ impl NeedsParentheses for JsAnyAssignmentPattern { } } +impl NeedsParentheses for TsType { + fn needs_parentheses(&self) -> bool { + match self { + TsType::TsAnyType(ty) => ty.needs_parentheses(), + TsType::TsArrayType(ty) => ty.needs_parentheses(), + TsType::TsBigIntLiteralType(ty) => ty.needs_parentheses(), + TsType::TsBigintType(ty) => ty.needs_parentheses(), + TsType::TsBooleanLiteralType(ty) => ty.needs_parentheses(), + TsType::TsBooleanType(ty) => ty.needs_parentheses(), + TsType::TsConditionalType(ty) => ty.needs_parentheses(), + TsType::TsConstructorType(ty) => ty.needs_parentheses(), + TsType::TsFunctionType(ty) => ty.needs_parentheses(), + TsType::TsImportType(ty) => ty.needs_parentheses(), + TsType::TsIndexedAccessType(ty) => ty.needs_parentheses(), + TsType::TsInferType(ty) => ty.needs_parentheses(), + TsType::TsIntersectionType(ty) => ty.needs_parentheses(), + TsType::TsMappedType(ty) => ty.needs_parentheses(), + TsType::TsNeverType(ty) => ty.needs_parentheses(), + TsType::TsNonPrimitiveType(ty) => ty.needs_parentheses(), + TsType::TsNullLiteralType(ty) => ty.needs_parentheses(), + TsType::TsNumberLiteralType(ty) => ty.needs_parentheses(), + TsType::TsNumberType(ty) => ty.needs_parentheses(), + TsType::TsObjectType(ty) => ty.needs_parentheses(), + TsType::TsParenthesizedType(ty) => ty.needs_parentheses(), + TsType::TsReferenceType(ty) => ty.needs_parentheses(), + TsType::TsStringLiteralType(ty) => ty.needs_parentheses(), + TsType::TsStringType(ty) => ty.needs_parentheses(), + TsType::TsSymbolType(ty) => ty.needs_parentheses(), + TsType::TsTemplateLiteralType(ty) => ty.needs_parentheses(), + TsType::TsThisType(ty) => ty.needs_parentheses(), + TsType::TsTupleType(ty) => ty.needs_parentheses(), + TsType::TsTypeOperatorType(ty) => ty.needs_parentheses(), + TsType::TsTypeofType(ty) => ty.needs_parentheses(), + TsType::TsUndefinedType(ty) => ty.needs_parentheses(), + TsType::TsUnionType(ty) => ty.needs_parentheses(), + TsType::TsUnknownType(ty) => ty.needs_parentheses(), + TsType::TsVoidType(ty) => ty.needs_parentheses(), + } + } + + fn needs_parentheses_with_parent(&self, parent: &JsSyntaxNode) -> bool { + match self { + TsType::TsAnyType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsArrayType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsBigIntLiteralType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsBigintType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsBooleanLiteralType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsBooleanType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsConditionalType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsConstructorType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsFunctionType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsImportType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsIndexedAccessType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsInferType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsIntersectionType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsMappedType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsNeverType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsNonPrimitiveType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsNullLiteralType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsNumberLiteralType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsNumberType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsObjectType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsParenthesizedType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsReferenceType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsStringLiteralType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsStringType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsSymbolType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsTemplateLiteralType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsThisType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsTupleType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsTypeOperatorType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsTypeofType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsUndefinedType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsUnionType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsUnknownType(ty) => ty.needs_parentheses_with_parent(parent), + TsType::TsVoidType(ty) => ty.needs_parentheses_with_parent(parent), + } + } +} + fn debug_assert_is_expression(node: &JsSyntaxNode) { debug_assert!( JsAnyExpression::can_cast(node.kind()), diff --git a/crates/rome_js_formatter/src/syntax_rewriter.rs b/crates/rome_js_formatter/src/syntax_rewriter.rs index daf2c6abbf33..333e0d7494f0 100644 --- a/crates/rome_js_formatter/src/syntax_rewriter.rs +++ b/crates/rome_js_formatter/src/syntax_rewriter.rs @@ -3,6 +3,7 @@ use crate::TextRange; use rome_formatter::{TransformSourceMap, TransformSourceMapBuilder}; use rome_js_syntax::{ JsAnyAssignment, JsAnyExpression, JsLanguage, JsLogicalExpression, JsSyntaxKind, JsSyntaxNode, + TsType, }; use rome_rowan::syntax::SyntaxTrivia; use rome_rowan::{ @@ -157,6 +158,9 @@ impl JsFormatSyntaxRewriter { .with_assignment(JsAnyAssignment::unwrap_cast(inner)) .into_syntax() } + JsAnyParenthesized::TsParenthesizedType(ty) => { + ty.with_ty(TsType::unwrap_cast(inner)).into_syntax() + } }; VisitNodeSignal::Replace(updated) diff --git a/crates/rome_js_formatter/src/ts/expressions/template_literal_type.rs b/crates/rome_js_formatter/src/ts/expressions/template_literal_type.rs index fa131abe703a..2b1e18221ceb 100644 --- a/crates/rome_js_formatter/src/ts/expressions/template_literal_type.rs +++ b/crates/rome_js_formatter/src/ts/expressions/template_literal_type.rs @@ -1,8 +1,9 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::TsTemplateLiteralType; use rome_js_syntax::TsTemplateLiteralTypeFields; +use rome_js_syntax::{JsSyntaxNode, TsTemplateLiteralType}; #[derive(Debug, Clone, Default)] pub struct FormatTsTemplateLiteralType; @@ -24,4 +25,14 @@ impl FormatNodeRule for FormatTsTemplateLiteralType { ] ] } + + fn needs_parentheses(&self, item: &TsTemplateLiteralType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsTemplateLiteralType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/module/import_type.rs b/crates/rome_js_formatter/src/ts/module/import_type.rs index b6f6d8bb0731..4ee716ab5255 100644 --- a/crates/rome_js_formatter/src/ts/module/import_type.rs +++ b/crates/rome_js_formatter/src/ts/module/import_type.rs @@ -1,9 +1,10 @@ use crate::prelude::*; use crate::utils::{FormatLiteralStringToken, StringLiteralParentKind}; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::TsImportType; use rome_js_syntax::TsImportTypeFields; +use rome_js_syntax::{JsSyntaxNode, TsImportType}; #[derive(Debug, Clone, Default)] pub struct FormatTsImportType; @@ -39,4 +40,14 @@ impl FormatNodeRule for FormatTsImportType { ] ] } + + fn needs_parentheses(&self, item: &TsImportType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsImportType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/any_type.rs b/crates/rome_js_formatter/src/ts/types/any_type.rs index 0de012912456..0fb4cfa67337 100644 --- a/crates/rome_js_formatter/src/ts/types/any_type.rs +++ b/crates/rome_js_formatter/src/ts/types/any_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsAnyType, TsAnyTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsAnyType, TsAnyTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsAnyType; @@ -12,4 +13,15 @@ impl FormatNodeRule for FormatTsAnyType { write![f, [any_token.format()]] } + + fn needs_parentheses(&self, item: &TsAnyType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsAnyType { + #[inline] + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/array_type.rs b/crates/rome_js_formatter/src/ts/types/array_type.rs index 6a8dc6f5b4e9..399fd9d62bf0 100644 --- a/crates/rome_js_formatter/src/ts/types/array_type.rs +++ b/crates/rome_js_formatter/src/ts/types/array_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsArrayType, TsArrayTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsArrayType, TsArrayTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsArrayType; @@ -22,4 +23,15 @@ impl FormatNodeRule for FormatTsArrayType { ] ] } + + fn needs_parentheses(&self, item: &TsArrayType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsArrayType { + #[inline] + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/asserts_return_type.rs b/crates/rome_js_formatter/src/ts/types/asserts_return_type.rs index 911b3dee83fd..e9315e0a9e2c 100644 --- a/crates/rome_js_formatter/src/ts/types/asserts_return_type.rs +++ b/crates/rome_js_formatter/src/ts/types/asserts_return_type.rs @@ -1,8 +1,9 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::TsAssertsReturnType; use rome_js_syntax::TsAssertsReturnTypeFields; +use rome_js_syntax::{JsSyntaxNode, TsAssertsReturnType}; #[derive(Debug, Clone, Default)] pub struct FormatTsAssertsReturnType; @@ -25,4 +26,15 @@ impl FormatNodeRule for FormatTsAssertsReturnType { ] ] } + + fn needs_parentheses(&self, item: &TsAssertsReturnType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsAssertsReturnType { + #[inline] + fn needs_parentheses_with_parent(&self, _: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/big_int_literal_type.rs b/crates/rome_js_formatter/src/ts/types/big_int_literal_type.rs index d6c1ab3026cd..ce13b5562e89 100644 --- a/crates/rome_js_formatter/src/ts/types/big_int_literal_type.rs +++ b/crates/rome_js_formatter/src/ts/types/big_int_literal_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsBigIntLiteralType, TsBigIntLiteralTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsBigIntLiteralType, TsBigIntLiteralTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsBigIntLiteralType; @@ -15,4 +16,14 @@ impl FormatNodeRule for FormatTsBigIntLiteralType { write![f, [minus_token.format(), literal_token.format()]] } + + fn needs_parentheses(&self, item: &TsBigIntLiteralType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsBigIntLiteralType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/bigint_type.rs b/crates/rome_js_formatter/src/ts/types/bigint_type.rs index f12e37212b82..2facbdfe3e7c 100644 --- a/crates/rome_js_formatter/src/ts/types/bigint_type.rs +++ b/crates/rome_js_formatter/src/ts/types/bigint_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsBigintType, TsBigintTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsBigintType, TsBigintTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsBigintType; @@ -12,4 +13,14 @@ impl FormatNodeRule for FormatTsBigintType { write![f, [bigint_token.format()]] } + + fn needs_parentheses(&self, item: &TsBigintType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsBigintType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/boolean_literal_type.rs b/crates/rome_js_formatter/src/ts/types/boolean_literal_type.rs index 33847e7dbc74..47f71787d63d 100644 --- a/crates/rome_js_formatter/src/ts/types/boolean_literal_type.rs +++ b/crates/rome_js_formatter/src/ts/types/boolean_literal_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsBooleanLiteralType, TsBooleanLiteralTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsBooleanLiteralType, TsBooleanLiteralTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsBooleanLiteralType; @@ -11,4 +12,14 @@ impl FormatNodeRule for FormatTsBooleanLiteralType { let TsBooleanLiteralTypeFields { literal } = node.as_fields(); write![f, [literal.format()]] } + + fn needs_parentheses(&self, item: &TsBooleanLiteralType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsBooleanLiteralType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/boolean_type.rs b/crates/rome_js_formatter/src/ts/types/boolean_type.rs index 90ee306da06f..fa299321eb87 100644 --- a/crates/rome_js_formatter/src/ts/types/boolean_type.rs +++ b/crates/rome_js_formatter/src/ts/types/boolean_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsBooleanType, TsBooleanTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsBooleanType, TsBooleanTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsBooleanType; @@ -12,4 +13,14 @@ impl FormatNodeRule for FormatTsBooleanType { write![f, [boolean_token.format()]] } + + fn needs_parentheses(&self, item: &TsBooleanType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsBooleanType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/conditional_type.rs b/crates/rome_js_formatter/src/ts/types/conditional_type.rs index 16062fa36dac..a56b90c423e3 100644 --- a/crates/rome_js_formatter/src/ts/types/conditional_type.rs +++ b/crates/rome_js_formatter/src/ts/types/conditional_type.rs @@ -1,7 +1,12 @@ use crate::prelude::*; use crate::utils::JsAnyConditional; -use rome_js_syntax::TsConditionalType; +use crate::parentheses::{ + is_check_type, is_in_many_type_union_or_intersection_list, + operator_type_or_higher_needs_parens, NeedsParentheses, +}; +use rome_js_syntax::{JsSyntaxKind, JsSyntaxNode, TsConditionalType}; +use rome_rowan::AstNode; #[derive(Debug, Clone, Default)] pub struct FormatTsConditionalType; @@ -14,4 +19,101 @@ impl FormatNodeRule for FormatTsConditionalType { ) -> FormatResult<()> { JsAnyConditional::from(node.clone()).fmt(formatter) } + + fn needs_parentheses(&self, item: &TsConditionalType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsConditionalType { + fn needs_parentheses_with_parent(&self, parent: &JsSyntaxNode) -> bool { + match parent.kind() { + JsSyntaxKind::TS_CONDITIONAL_TYPE => { + let conditional = TsConditionalType::unwrap_cast(parent.clone()); + + let is_extends_type = conditional + .extends_type() + .map(AstNode::into_syntax) + .as_ref() + == Ok(self.syntax()); + + is_check_type(self.syntax(), parent) || is_extends_type + } + + _ => { + is_in_many_type_union_or_intersection_list(self.syntax(), parent) + || operator_type_or_higher_needs_parens(self.syntax(), parent) + } + } + } +} + +#[cfg(test)] +mod tests { + + use crate::{assert_needs_parentheses, assert_not_needs_parentheses}; + use rome_js_syntax::TsConditionalType; + + #[test] + fn needs_parentheses() { + assert_needs_parentheses!("type s = (A extends B ? C : D)[]", TsConditionalType); + + assert_needs_parentheses!("type s = unique (A extends B ? C : D);", TsConditionalType); + + assert_needs_parentheses!( + "type s = [number, ...(A extends B ? C : D)]", + TsConditionalType + ); + assert_needs_parentheses!("type s = [(A extends B ? C : D)?]", TsConditionalType); + + assert_needs_parentheses!("type s = (A extends B ? C : D)[a]", TsConditionalType); + assert_not_needs_parentheses!("type s = a[A extends B ? C : D]", TsConditionalType); + + assert_needs_parentheses!("type s = (A extends B ? C : D) & b", TsConditionalType); + assert_needs_parentheses!("type s = a & (A extends B ? C : D)", TsConditionalType); + + // This does require parentheses but the formatter will strip the leading `&`, leaving only the inner type + // thus, no parentheses are required + assert_not_needs_parentheses!("type s = &(A extends B ? C : D)", TsConditionalType); + + assert_needs_parentheses!("type s = (A extends B ? C : D) | b", TsConditionalType); + assert_needs_parentheses!("type s = a | (A extends B ? C : D)", TsConditionalType); + assert_not_needs_parentheses!("type s = |(A extends B ? C : D)", TsConditionalType); + + assert_needs_parentheses!( + "type s = (A extends B ? C : D) extends E ? F : G", + TsConditionalType[1] + ); + assert_not_needs_parentheses!( + "type s = (A extends B ? C : D) extends E ? F : G", + TsConditionalType[0] + ); + + assert_needs_parentheses!( + "type s = A extends (B extends C ? D : E) ? F : G", + TsConditionalType[1] + ); + assert_not_needs_parentheses!( + "type s = A extends (B extends C ? D : E) ? F : G", + TsConditionalType[0] + ); + + assert_not_needs_parentheses!( + "type s = A extends B ? (C extends D ? E : F) : G", + TsConditionalType[0] + ); + assert_not_needs_parentheses!( + "type s = A extends B ? (C extends D ? E : F) : G", + TsConditionalType[1] + ); + + assert_not_needs_parentheses!( + "type s = A extends B ? C : (D extends E ? F : G)", + TsConditionalType[0] + ); + assert_not_needs_parentheses!( + "type s = A extends B ? C : (D extends E ? F : G)", + TsConditionalType[1] + ); + } } diff --git a/crates/rome_js_formatter/src/ts/types/constructor_type.rs b/crates/rome_js_formatter/src/ts/types/constructor_type.rs index fddb1d9a230f..b39c3e0ebe52 100644 --- a/crates/rome_js_formatter/src/ts/types/constructor_type.rs +++ b/crates/rome_js_formatter/src/ts/types/constructor_type.rs @@ -1,8 +1,10 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; +use crate::ts::types::function_type::function_like_type_needs_parentheses; use rome_formatter::write; -use rome_js_syntax::TsConstructorType; use rome_js_syntax::TsConstructorTypeFields; +use rome_js_syntax::{JsSyntaxNode, TsConstructorType}; #[derive(Debug, Clone, Default)] pub struct FormatTsConstructorType; @@ -36,4 +38,61 @@ impl FormatNodeRule for FormatTsConstructorType { ] ] } + + fn needs_parentheses(&self, item: &TsConstructorType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsConstructorType { + fn needs_parentheses_with_parent(&self, parent: &JsSyntaxNode) -> bool { + function_like_type_needs_parentheses(self.syntax(), parent) + } +} + +#[cfg(test)] +mod tests { + + use crate::{assert_needs_parentheses, assert_not_needs_parentheses}; + use rome_js_syntax::TsConstructorType; + + #[test] + fn needs_parentheses() { + assert_needs_parentheses!("type s = (new () => string)[]", TsConstructorType); + + assert_needs_parentheses!("type s = unique (new () => string);", TsConstructorType); + + assert_needs_parentheses!( + "type s = [number, ...(new () => string)]", + TsConstructorType + ); + assert_needs_parentheses!("type s = [(new () => string)?]", TsConstructorType); + + assert_needs_parentheses!("type s = (new () => string)[a]", TsConstructorType); + assert_not_needs_parentheses!("type s = a[new () => string]", TsConstructorType); + + assert_needs_parentheses!("type s = (new () => string) & b", TsConstructorType); + assert_needs_parentheses!("type s = a & (new () => string)", TsConstructorType); + + // This does require parentheses but the formatter will strip the leading `&`, leaving only the inner type + // thus, no parentheses are required + assert_not_needs_parentheses!("type s = &(new () => string)", TsConstructorType); + + assert_needs_parentheses!("type s = (new () => string) | b", TsConstructorType); + assert_needs_parentheses!("type s = a | (new () => string)", TsConstructorType); + assert_not_needs_parentheses!("type s = |(new () => string)", TsConstructorType); + + assert_needs_parentheses!( + "type s = (new () => string) extends string ? string : number", + TsConstructorType + ); + assert_not_needs_parentheses!( + "type s = A extends string ? (new () => string) : number", + TsConstructorType + ); + assert_not_needs_parentheses!( + "type s = A extends string ? string : (new () => string)", + TsConstructorType + ) + } } diff --git a/crates/rome_js_formatter/src/ts/types/function_type.rs b/crates/rome_js_formatter/src/ts/types/function_type.rs index 0240fca7d493..d392640eee26 100644 --- a/crates/rome_js_formatter/src/ts/types/function_type.rs +++ b/crates/rome_js_formatter/src/ts/types/function_type.rs @@ -1,9 +1,13 @@ use crate::prelude::*; use crate::js::declarations::function_declaration::should_group_function_parameters; +use crate::parentheses::{ + is_check_type, is_in_many_type_union_or_intersection_list, + operator_type_or_higher_needs_parens, NeedsParentheses, +}; use rome_formatter::write; -use rome_js_syntax::TsFunctionType; use rome_js_syntax::TsFunctionTypeFields; +use rome_js_syntax::{JsSyntaxKind, JsSyntaxNode, TsFunctionType}; #[derive(Debug, Clone, Default)] pub struct FormatTsFunctionType; @@ -48,4 +52,78 @@ impl FormatNodeRule for FormatTsFunctionType { write!(f, [group(&format_inner)]) } + + fn needs_parentheses(&self, item: &TsFunctionType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsFunctionType { + fn needs_parentheses_with_parent(&self, parent: &JsSyntaxNode) -> bool { + function_like_type_needs_parentheses(self.syntax(), parent) + } +} + +pub(super) fn function_like_type_needs_parentheses( + node: &JsSyntaxNode, + parent: &JsSyntaxNode, +) -> bool { + match parent.kind() { + JsSyntaxKind::TS_RETURN_TYPE_ANNOTATION => { + let grand_parent = parent.parent(); + + grand_parent.map_or(false, |grand_parent| { + grand_parent.kind() == JsSyntaxKind::JS_ARROW_FUNCTION_EXPRESSION + }) + } + _ => { + is_check_type(node, parent) + || operator_type_or_higher_needs_parens(node, parent) + || is_in_many_type_union_or_intersection_list(node, parent) + } + } +} + +#[cfg(test)] +mod tests { + + use crate::{assert_needs_parentheses, assert_not_needs_parentheses}; + use rome_js_syntax::TsFunctionType; + + #[test] + fn needs_parentheses() { + assert_needs_parentheses!("type s = (() => string)[]", TsFunctionType); + + assert_needs_parentheses!("type s = unique (() => string);", TsFunctionType); + + assert_needs_parentheses!("type s = [number, ...(() => string)]", TsFunctionType); + assert_needs_parentheses!("type s = [(() => string)?]", TsFunctionType); + + assert_needs_parentheses!("type s = (() => string)[a]", TsFunctionType); + assert_not_needs_parentheses!("type s = a[() => string]", TsFunctionType); + + assert_needs_parentheses!("type s = (() => string) & b", TsFunctionType); + assert_needs_parentheses!("type s = a & (() => string)", TsFunctionType); + + // This does require parentheses but the formatter will strip the leading `&`, leaving only the inner type + // thus, no parentheses are required + assert_not_needs_parentheses!("type s = &(() => string)", TsFunctionType); + + assert_needs_parentheses!("type s = (() => string) | b", TsFunctionType); + assert_needs_parentheses!("type s = a | (() => string)", TsFunctionType); + assert_not_needs_parentheses!("type s = |(() => string)", TsFunctionType); + + assert_needs_parentheses!( + "type s = (() => string) extends string ? string : number", + TsFunctionType + ); + assert_not_needs_parentheses!( + "type s = A extends string ? (() => string) : number", + TsFunctionType + ); + assert_not_needs_parentheses!( + "type s = A extends string ? string : (() => string)", + TsFunctionType + ) + } } diff --git a/crates/rome_js_formatter/src/ts/types/indexed_access_type.rs b/crates/rome_js_formatter/src/ts/types/indexed_access_type.rs index 8ee0714549da..df9bb9bc517e 100644 --- a/crates/rome_js_formatter/src/ts/types/indexed_access_type.rs +++ b/crates/rome_js_formatter/src/ts/types/indexed_access_type.rs @@ -1,8 +1,9 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::TsIndexedAccessType; use rome_js_syntax::TsIndexedAccessTypeFields; +use rome_js_syntax::{JsSyntaxNode, TsIndexedAccessType}; #[derive(Debug, Clone, Default)] pub struct FormatTsIndexedAccessType; @@ -25,4 +26,14 @@ impl FormatNodeRule for FormatTsIndexedAccessType { ] ] } + + fn needs_parentheses(&self, item: &TsIndexedAccessType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsIndexedAccessType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/infer_type.rs b/crates/rome_js_formatter/src/ts/types/infer_type.rs index e9d47d0304b9..fd262f94b714 100644 --- a/crates/rome_js_formatter/src/ts/types/infer_type.rs +++ b/crates/rome_js_formatter/src/ts/types/infer_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::{operator_type_or_higher_needs_parens, NeedsParentheses}; use rome_formatter::write; -use rome_js_syntax::{TsInferType, TsInferTypeFields}; +use rome_js_syntax::{JsSyntaxKind, JsSyntaxNode, TsInferType, TsInferTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsInferType; @@ -14,4 +15,38 @@ impl FormatNodeRule for FormatTsInferType { } = node.as_fields(); write![f, [infer_token.format(), space(), type_parameter.format()]] } + + fn needs_parentheses(&self, item: &TsInferType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsInferType { + fn needs_parentheses_with_parent(&self, parent: &JsSyntaxNode) -> bool { + if parent.kind() == JsSyntaxKind::TS_REST_TUPLE_TYPE_ELEMENT { + false + } else { + operator_type_or_higher_needs_parens(self.syntax(), parent) + } + } +} + +#[cfg(test)] +mod tests { + + use crate::{assert_needs_parentheses, assert_not_needs_parentheses}; + use rome_js_syntax::TsInferType; + + #[test] + fn needs_parentheses() { + assert_needs_parentheses!("let s: (infer string)[] = symbol();", TsInferType); + + assert_needs_parentheses!("let s: unique (infer string);", TsInferType); + + assert_not_needs_parentheses!("let s: [number, ...infer string]", TsInferType); + assert_needs_parentheses!("let s: [(infer string)?]", TsInferType); + + assert_needs_parentheses!("let s: (infer string)[a]", TsInferType); + assert_not_needs_parentheses!("let s: a[(infer string)]", TsInferType); + } } diff --git a/crates/rome_js_formatter/src/ts/types/intersection_type.rs b/crates/rome_js_formatter/src/ts/types/intersection_type.rs index cfd021c439f5..12c0af04458e 100644 --- a/crates/rome_js_formatter/src/ts/types/intersection_type.rs +++ b/crates/rome_js_formatter/src/ts/types/intersection_type.rs @@ -1,7 +1,14 @@ use crate::prelude::*; +use crate::parentheses::{ + is_in_many_type_union_or_intersection_list, operator_type_or_higher_needs_parens, + NeedsParentheses, +}; use rome_formatter::{format_args, write}; -use rome_js_syntax::{JsSyntaxKind, TsIntersectionTypeFields}; +use rome_js_syntax::{ + JsSyntaxKind, JsSyntaxNode, TsIntersectionTypeElementList, TsIntersectionTypeFields, + TsUnionTypeVariantList, +}; use rome_js_syntax::{JsSyntaxToken, TsIntersectionType}; #[derive(Debug, Clone, Default)] @@ -26,6 +33,10 @@ impl FormatNodeRule for FormatTsIntersectionType { )))] ) } + + fn needs_parentheses(&self, item: &TsIntersectionType) -> bool { + item.needs_parentheses() + } } pub struct FormatTypeSetLeadingSeparator<'a> { @@ -49,3 +60,70 @@ impl Format for FormatTypeSetLeadingSeparator<'_> { } } } + +impl NeedsParentheses for TsIntersectionType { + fn needs_parentheses_with_parent(&self, parent: &JsSyntaxNode) -> bool { + union_or_intersection_type_needs_parentheses( + self.syntax(), + parent, + &TsIntersectionOrUnionTypeList::TsIntersectionTypeElementList(self.types()), + ) + } +} + +pub(super) fn union_or_intersection_type_needs_parentheses( + node: &JsSyntaxNode, + parent: &JsSyntaxNode, + types: &TsIntersectionOrUnionTypeList, +) -> bool { + debug_assert!(matches!( + node.kind(), + JsSyntaxKind::TS_INTERSECTION_TYPE | JsSyntaxKind::TS_UNION_TYPE + )); + + if is_in_many_type_union_or_intersection_list(node, parent) { + types.len() > 1 + } else { + operator_type_or_higher_needs_parens(node, parent) + } +} + +pub(super) enum TsIntersectionOrUnionTypeList { + TsIntersectionTypeElementList(TsIntersectionTypeElementList), + TsUnionTypeVariantList(TsUnionTypeVariantList), +} + +impl TsIntersectionOrUnionTypeList { + fn len(&self) -> usize { + match self { + TsIntersectionOrUnionTypeList::TsIntersectionTypeElementList(list) => list.len(), + TsIntersectionOrUnionTypeList::TsUnionTypeVariantList(list) => list.len(), + } + } +} + +#[cfg(test)] +mod tests { + + use crate::{assert_needs_parentheses, assert_not_needs_parentheses}; + use rome_js_syntax::TsIntersectionType; + + #[test] + fn needs_parentheses() { + assert_needs_parentheses!("let s: (string & number)[] = symbol();", TsIntersectionType); + + assert_needs_parentheses!("let s: unique (string & number);", TsIntersectionType); + + assert_needs_parentheses!("let s: [number, ...(string & number)]", TsIntersectionType); + assert_needs_parentheses!("let s: [(string & number)?]", TsIntersectionType); + + assert_needs_parentheses!("let s: (string & number)[a]", TsIntersectionType); + assert_not_needs_parentheses!("let s: a[(string & number)]", TsIntersectionType); + + assert_not_needs_parentheses!("let s: (&a) & (&b)", TsIntersectionType[1]); + assert_not_needs_parentheses!("let s: (&a) & (&b)", TsIntersectionType[2]); + + assert_needs_parentheses!("let s: (a & b) & (&c)", TsIntersectionType[1]); + assert_not_needs_parentheses!("let s: (a & b) & (&c)", TsIntersectionType[2]); + } +} diff --git a/crates/rome_js_formatter/src/ts/types/mapped_type.rs b/crates/rome_js_formatter/src/ts/types/mapped_type.rs index 9a83230888eb..94780fba3162 100644 --- a/crates/rome_js_formatter/src/ts/types/mapped_type.rs +++ b/crates/rome_js_formatter/src/ts/types/mapped_type.rs @@ -1,8 +1,9 @@ use crate::prelude::*; use crate::utils::FormatWithSemicolon; +use crate::parentheses::NeedsParentheses; use rome_formatter::{format_args, write}; -use rome_js_syntax::{TsMappedType, TsMappedTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsMappedType, TsMappedTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsMappedType; @@ -53,4 +54,14 @@ impl FormatNodeRule for FormatTsMappedType { .block_indent()] ) } + + fn needs_parentheses(&self, item: &TsMappedType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsMappedType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/never_type.rs b/crates/rome_js_formatter/src/ts/types/never_type.rs index 4ad6c25b519c..c90e04c15a4c 100644 --- a/crates/rome_js_formatter/src/ts/types/never_type.rs +++ b/crates/rome_js_formatter/src/ts/types/never_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsNeverType, TsNeverTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsNeverType, TsNeverTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsNeverType; @@ -11,4 +12,14 @@ impl FormatNodeRule for FormatTsNeverType { let TsNeverTypeFields { never_token } = node.as_fields(); write![f, [never_token.format()]] } + + fn needs_parentheses(&self, item: &TsNeverType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsNeverType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/non_primitive_type.rs b/crates/rome_js_formatter/src/ts/types/non_primitive_type.rs index 22771135a061..63125b8d7122 100644 --- a/crates/rome_js_formatter/src/ts/types/non_primitive_type.rs +++ b/crates/rome_js_formatter/src/ts/types/non_primitive_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsNonPrimitiveType, TsNonPrimitiveTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsNonPrimitiveType, TsNonPrimitiveTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsNonPrimitiveType; @@ -12,4 +13,14 @@ impl FormatNodeRule for FormatTsNonPrimitiveType { write![f, [object_token.format()]] } + + fn needs_parentheses(&self, item: &TsNonPrimitiveType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsNonPrimitiveType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/null_literal_type.rs b/crates/rome_js_formatter/src/ts/types/null_literal_type.rs index f4288f01323a..ab8fd15cf908 100644 --- a/crates/rome_js_formatter/src/ts/types/null_literal_type.rs +++ b/crates/rome_js_formatter/src/ts/types/null_literal_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsNullLiteralType, TsNullLiteralTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsNullLiteralType, TsNullLiteralTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsNullLiteralType; @@ -11,4 +12,14 @@ impl FormatNodeRule for FormatTsNullLiteralType { let TsNullLiteralTypeFields { literal_token } = node.as_fields(); write![f, [literal_token.format()]] } + + fn needs_parentheses(&self, item: &TsNullLiteralType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsNullLiteralType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/number_literal_type.rs b/crates/rome_js_formatter/src/ts/types/number_literal_type.rs index a545b17e3976..e63b7b5b9fce 100644 --- a/crates/rome_js_formatter/src/ts/types/number_literal_type.rs +++ b/crates/rome_js_formatter/src/ts/types/number_literal_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsNumberLiteralType, TsNumberLiteralTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsNumberLiteralType, TsNumberLiteralTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsNumberLiteralType; @@ -14,4 +15,14 @@ impl FormatNodeRule for FormatTsNumberLiteralType { } = node.as_fields(); write![f, [minus_token.format(), literal_token.format()]] } + + fn needs_parentheses(&self, item: &TsNumberLiteralType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsNumberLiteralType { + fn needs_parentheses_with_parent(&self, _: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/number_type.rs b/crates/rome_js_formatter/src/ts/types/number_type.rs index 8bd8138fab69..80d7c05fb800 100644 --- a/crates/rome_js_formatter/src/ts/types/number_type.rs +++ b/crates/rome_js_formatter/src/ts/types/number_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsNumberType, TsNumberTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsNumberType, TsNumberTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsNumberType; @@ -12,4 +13,14 @@ impl FormatNodeRule for FormatTsNumberType { write![f, [number_token.format()]] } + + fn needs_parentheses(&self, item: &TsNumberType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsNumberType { + fn needs_parentheses_with_parent(&self, _: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/object_type.rs b/crates/rome_js_formatter/src/ts/types/object_type.rs index f1c89491250a..34023eefa360 100644 --- a/crates/rome_js_formatter/src/ts/types/object_type.rs +++ b/crates/rome_js_formatter/src/ts/types/object_type.rs @@ -1,7 +1,8 @@ +use crate::parentheses::NeedsParentheses; use crate::prelude::*; use crate::utils::JsObjectLike; use rome_formatter::write; -use rome_js_syntax::TsObjectType; +use rome_js_syntax::{JsSyntaxNode, TsObjectType}; #[derive(Debug, Clone, Default)] pub struct FormatTsObjectType; @@ -10,4 +11,14 @@ impl FormatNodeRule for FormatTsObjectType { fn fmt_fields(&self, node: &TsObjectType, f: &mut JsFormatter) -> FormatResult<()> { write!(f, [JsObjectLike::from(node.clone())]) } + + fn needs_parentheses(&self, item: &TsObjectType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsObjectType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/parenthesized_type.rs b/crates/rome_js_formatter/src/ts/types/parenthesized_type.rs index 3ca62311b74c..335f8aaad170 100644 --- a/crates/rome_js_formatter/src/ts/types/parenthesized_type.rs +++ b/crates/rome_js_formatter/src/ts/types/parenthesized_type.rs @@ -1,8 +1,9 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::TsParenthesizedType; use rome_js_syntax::TsParenthesizedTypeFields; +use rome_js_syntax::{JsSyntaxNode, TsParenthesizedType}; #[derive(Debug, Clone, Default)] pub struct FormatTsParenthesizedType; @@ -17,10 +18,23 @@ impl FormatNodeRule for FormatTsParenthesizedType { write!( f, - [ - format_delimited(&l_paren_token?, &ty.format(), &r_paren_token?,) - .soft_block_indent() - ] + [l_paren_token.format(), &ty.format(), r_paren_token.format()] ) } + + fn needs_parentheses(&self, item: &TsParenthesizedType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsParenthesizedType { + #[inline] + fn needs_parentheses(&self) -> bool { + false + } + + #[inline] + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/reference_type.rs b/crates/rome_js_formatter/src/ts/types/reference_type.rs index 9e5c63632f93..07db99fc6e35 100644 --- a/crates/rome_js_formatter/src/ts/types/reference_type.rs +++ b/crates/rome_js_formatter/src/ts/types/reference_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsReferenceType, TsReferenceTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsReferenceType, TsReferenceTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsReferenceType; @@ -15,4 +16,14 @@ impl FormatNodeRule for FormatTsReferenceType { write![f, [name.format(), type_arguments.format()]] } + + fn needs_parentheses(&self, item: &TsReferenceType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsReferenceType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/string_literal_type.rs b/crates/rome_js_formatter/src/ts/types/string_literal_type.rs index 3bf49800b556..5f34901c5438 100644 --- a/crates/rome_js_formatter/src/ts/types/string_literal_type.rs +++ b/crates/rome_js_formatter/src/ts/types/string_literal_type.rs @@ -1,8 +1,9 @@ use crate::prelude::*; use crate::utils::{FormatLiteralStringToken, StringLiteralParentKind}; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsStringLiteralType, TsStringLiteralTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsStringLiteralType, TsStringLiteralTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsStringLiteralType; @@ -19,4 +20,14 @@ impl FormatNodeRule for FormatTsStringLiteralType { )] ) } + + fn needs_parentheses(&self, item: &TsStringLiteralType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsStringLiteralType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/string_type.rs b/crates/rome_js_formatter/src/ts/types/string_type.rs index 099d7a6f4279..816f6c9070c5 100644 --- a/crates/rome_js_formatter/src/ts/types/string_type.rs +++ b/crates/rome_js_formatter/src/ts/types/string_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsStringType, TsStringTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsStringType, TsStringTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsStringType; @@ -12,4 +13,14 @@ impl FormatNodeRule for FormatTsStringType { write![f, [string_token.format()]] } + + fn needs_parentheses(&self, item: &TsStringType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsStringType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/symbol_type.rs b/crates/rome_js_formatter/src/ts/types/symbol_type.rs index 7aa921f54663..a8a137061bfd 100644 --- a/crates/rome_js_formatter/src/ts/types/symbol_type.rs +++ b/crates/rome_js_formatter/src/ts/types/symbol_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsSymbolType, TsSymbolTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsSymbolType, TsSymbolTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsSymbolType; @@ -12,4 +13,14 @@ impl FormatNodeRule for FormatTsSymbolType { write![f, [symbol_token.format()]] } + + fn needs_parentheses(&self, item: &TsSymbolType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsSymbolType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/this_type.rs b/crates/rome_js_formatter/src/ts/types/this_type.rs index 3439e3eacac4..af876a4c3977 100644 --- a/crates/rome_js_formatter/src/ts/types/this_type.rs +++ b/crates/rome_js_formatter/src/ts/types/this_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsThisType, TsThisTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsThisType, TsThisTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsThisType; @@ -12,4 +13,14 @@ impl FormatNodeRule for FormatTsThisType { write![f, [this_token.format()]] } + + fn needs_parentheses(&self, item: &TsThisType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsThisType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/tuple_type.rs b/crates/rome_js_formatter/src/ts/types/tuple_type.rs index fd6dd01eded5..cdaaae849636 100644 --- a/crates/rome_js_formatter/src/ts/types/tuple_type.rs +++ b/crates/rome_js_formatter/src/ts/types/tuple_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsTupleType, TsTupleTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsTupleType, TsTupleTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsTupleType; @@ -22,4 +23,14 @@ impl FormatNodeRule for FormatTsTupleType { ] ) } + + fn needs_parentheses(&self, item: &TsTupleType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsTupleType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/type_operator_type.rs b/crates/rome_js_formatter/src/ts/types/type_operator_type.rs index b445cd5dc46c..d5ed37b4726f 100644 --- a/crates/rome_js_formatter/src/ts/types/type_operator_type.rs +++ b/crates/rome_js_formatter/src/ts/types/type_operator_type.rs @@ -1,7 +1,11 @@ use crate::prelude::*; +use crate::parentheses::{operator_type_or_higher_needs_parens, NeedsParentheses}; use rome_formatter::write; -use rome_js_syntax::{TsTypeOperatorType, TsTypeOperatorTypeFields}; +use rome_js_syntax::{ + JsSyntaxNode, TsTypeOperatorType, TsTypeOperatorTypeFields, +}; +use rome_rowan::AstNode; #[derive(Debug, Clone, Default)] pub struct FormatTsTypeOperatorType; @@ -12,4 +16,35 @@ impl FormatNodeRule for FormatTsTypeOperatorType { write![f, [operator_token.format(), space(), ty.format()]] } + + fn needs_parentheses(&self, item: &TsTypeOperatorType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsTypeOperatorType { + fn needs_parentheses_with_parent(&self, parent: &JsSyntaxNode) -> bool { + operator_type_or_higher_needs_parens(self.syntax(), parent) + } +} + +#[cfg(test)] +mod tests { + + use crate::{assert_needs_parentheses, assert_not_needs_parentheses}; + use rome_js_syntax::TsTypeOperatorType; + + #[test] + fn needs_parentheses() { + assert_needs_parentheses!("let s: (unique symbol)[] = symbol();", TsTypeOperatorType); + + assert_needs_parentheses!("let s: unique (unique symbol);", TsTypeOperatorType[1]); + assert_not_needs_parentheses!("let s: unique (unique symbol);", TsTypeOperatorType[0]); + + assert_needs_parentheses!("let s: [number, ...(unique symbol)]", TsTypeOperatorType); + assert_needs_parentheses!("let s: [(unique symbol)?]", TsTypeOperatorType); + + assert_needs_parentheses!("let s: (unique symbol)[a]", TsTypeOperatorType); + assert_not_needs_parentheses!("let s: a[(unique symbol)]", TsTypeOperatorType); + } } diff --git a/crates/rome_js_formatter/src/ts/types/typeof_type.rs b/crates/rome_js_formatter/src/ts/types/typeof_type.rs index 37a7e821397f..666e6330363d 100644 --- a/crates/rome_js_formatter/src/ts/types/typeof_type.rs +++ b/crates/rome_js_formatter/src/ts/types/typeof_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsTypeofType, TsTypeofTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsTypeofType, TsTypeofTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsTypeofType; @@ -18,4 +19,14 @@ impl FormatNodeRule for FormatTsTypeofType { [typeof_token.format(), space(), expression_name.format()] ] } + + fn needs_parentheses(&self, item: &TsTypeofType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsTypeofType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/undefined_type.rs b/crates/rome_js_formatter/src/ts/types/undefined_type.rs index 54ed55045d11..ed00add990ee 100644 --- a/crates/rome_js_formatter/src/ts/types/undefined_type.rs +++ b/crates/rome_js_formatter/src/ts/types/undefined_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsUndefinedType, TsUndefinedTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsUndefinedType, TsUndefinedTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsUndefinedType; @@ -12,4 +13,14 @@ impl FormatNodeRule for FormatTsUndefinedType { write![f, [undefined_token.format()]] } + + fn needs_parentheses(&self, item: &TsUndefinedType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsUndefinedType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/union_type.rs b/crates/rome_js_formatter/src/ts/types/union_type.rs index f9818bd0a5c3..6e20c2d25e58 100644 --- a/crates/rome_js_formatter/src/ts/types/union_type.rs +++ b/crates/rome_js_formatter/src/ts/types/union_type.rs @@ -1,8 +1,12 @@ +use crate::parentheses::NeedsParentheses; use crate::prelude::*; -use crate::ts::types::intersection_type::FormatTypeSetLeadingSeparator; -use rome_formatter::{write, Buffer}; -use rome_js_syntax::TsUnionTypeFields; +use crate::ts::types::intersection_type::{ + union_or_intersection_type_needs_parentheses, FormatTypeSetLeadingSeparator, + TsIntersectionOrUnionTypeList, +}; +use rome_formatter::{format_args, write, Buffer}; use rome_js_syntax::{JsSyntaxKind, TsUnionType}; +use rome_js_syntax::{JsSyntaxNode, TsUnionTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsUnionType; @@ -14,6 +18,24 @@ impl FormatNodeRule for FormatTsUnionType { types, } = node.as_fields(); + let body = format_with(|f| { + write!( + f, + [ + soft_line_break(), + FormatTypeSetLeadingSeparator { + separator: JsSyntaxKind::PIPE, + leading_separator: leading_separator_token.as_ref() + }, + types.format() + ] + ) + }); + + if node.needs_parentheses() { + return write!(f, [group(&format_args![indent(&body), soft_line_break()])]); + } + let should_indent = { let parent_kind = node.syntax().parent().map(|p| p.kind()); @@ -30,19 +52,6 @@ impl FormatNodeRule for FormatTsUnionType { ) }; - let body = format_with(|f| { - write!( - f, - [ - soft_line_break(), - FormatTypeSetLeadingSeparator { - separator: JsSyntaxKind::PIPE, - leading_separator: leading_separator_token.as_ref() - }, - types.format() - ] - ) - }); write![ f, [group(&format_with(|f| { @@ -54,4 +63,18 @@ impl FormatNodeRule for FormatTsUnionType { }))] ] } + + fn needs_parentheses(&self, item: &TsUnionType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsUnionType { + fn needs_parentheses_with_parent(&self, parent: &JsSyntaxNode) -> bool { + union_or_intersection_type_needs_parentheses( + self.syntax(), + parent, + &TsIntersectionOrUnionTypeList::TsUnionTypeVariantList(self.types()), + ) + } } diff --git a/crates/rome_js_formatter/src/ts/types/unknown_type.rs b/crates/rome_js_formatter/src/ts/types/unknown_type.rs index dbb57205c521..297fb022eed2 100644 --- a/crates/rome_js_formatter/src/ts/types/unknown_type.rs +++ b/crates/rome_js_formatter/src/ts/types/unknown_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsUnknownType, TsUnknownTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsUnknownType, TsUnknownTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsUnknownType; @@ -12,4 +13,14 @@ impl FormatNodeRule for FormatTsUnknownType { write![f, [unknown_token.format()]] } + + fn needs_parentheses(&self, item: &TsUnknownType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsUnknownType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/ts/types/void_type.rs b/crates/rome_js_formatter/src/ts/types/void_type.rs index 98d9137afb43..165e4e812717 100644 --- a/crates/rome_js_formatter/src/ts/types/void_type.rs +++ b/crates/rome_js_formatter/src/ts/types/void_type.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use crate::parentheses::NeedsParentheses; use rome_formatter::write; -use rome_js_syntax::{TsVoidType, TsVoidTypeFields}; +use rome_js_syntax::{JsSyntaxNode, TsVoidType, TsVoidTypeFields}; #[derive(Debug, Clone, Default)] pub struct FormatTsVoidType; @@ -12,4 +13,14 @@ impl FormatNodeRule for FormatTsVoidType { write![f, [void_token.format()]] } + + fn needs_parentheses(&self, item: &TsVoidType) -> bool { + item.needs_parentheses() + } +} + +impl NeedsParentheses for TsVoidType { + fn needs_parentheses_with_parent(&self, _parent: &JsSyntaxNode) -> bool { + false + } } diff --git a/crates/rome_js_formatter/src/utils/assignment_like.rs b/crates/rome_js_formatter/src/utils/assignment_like.rs index aab1fb48184c..118ee8686188 100644 --- a/crates/rome_js_formatter/src/utils/assignment_like.rs +++ b/crates/rome_js_formatter/src/utils/assignment_like.rs @@ -903,36 +903,25 @@ impl Format for JsAnyAssignmentLike { // 4. we write the left node inside the main buffer based on the layout let mut buffer = VecBuffer::new(f.state_mut()); let is_left_short = self.write_left(&mut Formatter::new(&mut buffer))?; - let formatted_element = buffer.into_element(); + let formatted_left = buffer.into_element(); // Compare name only if we are in a position of computing it. // If not (for example, left is not an identifier), then let's fallback to false, // so we can continue the chain of checks let layout = self.layout(is_left_short, f)?; - let left = format_once(|f| { + let left = format_once(|f| f.write_element(formatted_left)); + let right = format_with(|f| self.write_right(f)).memoized(); + + let inner_content = format_with(|f| { if matches!( &layout, AssignmentLikeLayout::BreakLeftHandSide | AssignmentLikeLayout::OnlyLeft ) { - write!( - f, - [&format_once(|f| { f.write_element(formatted_element) })] - ) + write!(f, [left])?; } else { - write!( - f, - [group(&format_once(|f| { - f.write_element(formatted_element) - }))] - ) + write!(f, [group(&left)])?; } - }); - - let right = format_with(|f| self.write_right(f)); - - let inner_content = format_with(|f| { - write!(f, [left])?; if layout != AssignmentLikeLayout::SuppressedInitializer { self.write_operator(f)?; diff --git a/crates/rome_js_formatter/src/utils/conditional.rs b/crates/rome_js_formatter/src/utils/conditional.rs index 59e591bf4fa8..e242c45bdf84 100644 --- a/crates/rome_js_formatter/src/utils/conditional.rs +++ b/crates/rome_js_formatter/src/utils/conditional.rs @@ -320,7 +320,7 @@ impl JsAnyConditional { .extends_type() .map(AstNode::into_syntax) .as_ref() - == Ok(self.syntax()) + == Ok(node) } } } diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/as/as.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/as/as.ts.snap index 012c2ea0a991..bec884096553 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/as/as.ts.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/typescript/as/as.ts.snap @@ -72,19 +72,6 @@ const iter2 = createIterator(self.controller, child, self.tag as SyncFunctionCom const state = JSON.stringify({ next: window.location.href, nonce, -@@ -41,9 +41,9 @@ - thisIsAReallyReallyReallyReallyReallyLongIdentifier as SomeInterface; - const value2 = - thisIsAnIdentifier as thisIsAReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongInterface; --const value3 = thisIsAReallyLongIdentifier as -- | SomeInterface -- | SomeOtherInterface; -+const value3 = thisIsAReallyLongIdentifier as ( -+ SomeInterface | SomeOtherInterface -+); - const value4 = thisIsAReallyLongIdentifier as { - prop1: string; - prop2: number; ``` # Output @@ -133,9 +120,9 @@ const value1 = thisIsAReallyReallyReallyReallyReallyLongIdentifier as SomeInterface; const value2 = thisIsAnIdentifier as thisIsAReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongInterface; -const value3 = thisIsAReallyLongIdentifier as ( - SomeInterface | SomeOtherInterface -); +const value3 = thisIsAReallyLongIdentifier as + | SomeInterface + | SomeOtherInterface; const value4 = thisIsAReallyLongIdentifier as { prop1: string; prop2: number; diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/compiler/contextualSignatureInstantiation2.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/compiler/contextualSignatureInstantiation2.ts.snap index 99f5dca786e6..2ff9f6c44d15 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/compiler/contextualSignatureInstantiation2.ts.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/typescript/compiler/contextualSignatureInstantiation2.ts.snap @@ -25,7 +25,7 @@ var r23 = dot(id)(id);``` - (g: (_: U) => T): ((r: U) => S) => - (x) => - f(g(x)); -+dot = (f: (_: T) => S) => (g: (_: U) => T): (r: U) => S => (x) => ++dot = (f: (_: T) => S) => (g: (_: U) => T): ((r: U) => S) => (x) => + f(g(x)); var id: (x: T) => T; var r23 = dot(id)(id); @@ -36,7 +36,7 @@ var r23 = dot(id)(id);``` ```js // dot f g x = f(g(x)) var dot: (f: (_: T) => S) => (g: (_: U) => T) => (_: U) => S; -dot = (f: (_: T) => S) => (g: (_: U) => T): (r: U) => S => (x) => +dot = (f: (_: T) => S) => (g: (_: U) => T): ((r: U) => S) => (x) => f(g(x)); var id: (x: T) => T; var r23 = dot(id)(id); diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/conditional-types/conditonal-types.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/conditional-types/conditonal-types.ts.snap deleted file mode 100644 index 28231eb2e6a3..000000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/conditional-types/conditonal-types.ts.snap +++ /dev/null @@ -1,137 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -export type DeepReadonly = T extends any[] ? DeepReadonlyArray : T extends object ? DeepReadonlyObject : T; - -type NonFunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T]; - -interface DeepReadonlyArray extends ReadonlyArray> {} - -type DeepReadonlyObject = { - readonly [P in NonFunctionPropertyNames]: DeepReadonly; -}; - -type TypeName = - T extends string ? "string" : - T extends number ? "number" : - T extends boolean ? "boolean" : - T extends undefined ? "undefined" : - T extends Function ? "function" : - "object"; - -type Type01 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; -type Type02 = 0 extends ((1 extends 2 ? 3 : 4)) ? 5 : 6; -type Type03 = 0 extends (((1 extends 2 ? 3 : 4))) ? 5 : 6; -type Type04 = 0 extends ((((1 extends 2 ? 3 : 4)))) ? 5 : 6; -type Type05 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; -type Type06 = ((0 extends 1 ? 2 : 3)) extends 4 ? 5 : 6; -type Type07 = (((0 extends 1 ? 2 : 3))) extends 4 ? 5 : 6; -type Type08 = ((((0 extends 1 ? 2 : 3)))) extends 4 ? 5 : 6; - -type T1 = () => void extends T ? U : V; -type T1a = () => (void extends T ? U : V); -type T1b = () => (void) extends T ? U : V; -type T2 = (() => void) extends T ? U : V; - -type U1 = new () => X extends T ? U : V; -type U1a = new () => (X extends T ? U : V); -type U1b = new () => (X) extends T ? U : V; -type U2 = (new () => X) extends T ? U : V; -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -27,20 +27,20 @@ - : "object"; - - type Type01 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; --type Type02 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; --type Type03 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; --type Type04 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; -+type Type02 = 0 extends ((1 extends 2 ? 3 : 4)) ? 5 : 6; -+type Type03 = 0 extends (((1 extends 2 ? 3 : 4))) ? 5 : 6; -+type Type04 = 0 extends ((((1 extends 2 ? 3 : 4)))) ? 5 : 6; - type Type05 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; --type Type06 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; --type Type07 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; --type Type08 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; -+type Type06 = ((0 extends 1 ? 2 : 3)) extends 4 ? 5 : 6; -+type Type07 = (((0 extends 1 ? 2 : 3))) extends 4 ? 5 : 6; -+type Type08 = ((((0 extends 1 ? 2 : 3)))) extends 4 ? 5 : 6; - - type T1 = () => void extends T ? U : V; --type T1a = () => void extends T ? U : V; --type T1b = () => void extends T ? U : V; -+type T1a = () => (void extends T ? U : V); -+type T1b = () => (void) extends T ? U : V; - type T2 = (() => void) extends T ? U : V; - - type U1 = new () => X extends T ? U : V; --type U1a = new () => X extends T ? U : V; --type U1b = new () => X extends T ? U : V; -+type U1a = new () => (X extends T ? U : V); -+type U1b = new () => (X) extends T ? U : V; - type U2 = (new () => X) extends T ? U : V; -``` - -# Output - -```js -export type DeepReadonly = T extends any[] - ? DeepReadonlyArray - : T extends object - ? DeepReadonlyObject - : T; - -type NonFunctionPropertyNames = { - [K in keyof T]: T[K] extends Function ? never : K; -}[keyof T]; - -interface DeepReadonlyArray extends ReadonlyArray> {} - -type DeepReadonlyObject = { - readonly [P in NonFunctionPropertyNames]: DeepReadonly; -}; - -type TypeName = T extends string - ? "string" - : T extends number - ? "number" - : T extends boolean - ? "boolean" - : T extends undefined - ? "undefined" - : T extends Function - ? "function" - : "object"; - -type Type01 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; -type Type02 = 0 extends ((1 extends 2 ? 3 : 4)) ? 5 : 6; -type Type03 = 0 extends (((1 extends 2 ? 3 : 4))) ? 5 : 6; -type Type04 = 0 extends ((((1 extends 2 ? 3 : 4)))) ? 5 : 6; -type Type05 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; -type Type06 = ((0 extends 1 ? 2 : 3)) extends 4 ? 5 : 6; -type Type07 = (((0 extends 1 ? 2 : 3))) extends 4 ? 5 : 6; -type Type08 = ((((0 extends 1 ? 2 : 3)))) extends 4 ? 5 : 6; - -type T1 = () => void extends T ? U : V; -type T1a = () => (void extends T ? U : V); -type T1b = () => (void) extends T ? U : V; -type T2 = (() => void) extends T ? U : V; - -type U1 = new () => X extends T ? U : V; -type U1a = new () => (X extends T ? U : V); -type U1b = new () => (X) extends T ? U : V; -type U2 = (new () => X) extends T ? U : V; -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/conformance/types/functions/TSFunctionTypeNoUnnecessaryParentheses.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/conformance/types/functions/TSFunctionTypeNoUnnecessaryParentheses.ts.snap deleted file mode 100644 index 8e19c3de6dd9..000000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/conformance/types/functions/TSFunctionTypeNoUnnecessaryParentheses.ts.snap +++ /dev/null @@ -1,34 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -class Foo { - bar: (() => boolean); -}``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,3 +1,3 @@ - class Foo { -- bar: () => boolean; -+ bar: (() => boolean); - } -``` - -# Output - -```js -class Foo { - bar: (() => boolean); -} -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/custom/typeParameters/functionTypeLong.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/custom/typeParameters/functionTypeLong.ts.snap deleted file mode 100644 index 6d3f1a8bfeaf..000000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/custom/typeParameters/functionTypeLong.ts.snap +++ /dev/null @@ -1,48 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -type AwkwardlyLongFunctionTypeDefinition = < - GenericTypeNumberOne, - GenericTypeNumberTwo, - GenericTypeNumberThree ->( - arg1: GenericTypeNumberOne, - arg2: GenericTypeNumberTwo, - arg3: GenericTypeNumberThree -) => (GenericTypeNumberOne | GenericTypeNumberTwo | GenericTypeNumberThree); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -6,4 +6,4 @@ - arg1: GenericTypeNumberOne, - arg2: GenericTypeNumberTwo, - arg3: GenericTypeNumberThree, --) => GenericTypeNumberOne | GenericTypeNumberTwo | GenericTypeNumberThree; -+) => (GenericTypeNumberOne | GenericTypeNumberTwo | GenericTypeNumberThree); -``` - -# Output - -```js -type AwkwardlyLongFunctionTypeDefinition = < - GenericTypeNumberOne, - GenericTypeNumberTwo, - GenericTypeNumberThree, ->( - arg1: GenericTypeNumberOne, - arg2: GenericTypeNumberTwo, - arg3: GenericTypeNumberThree, -) => (GenericTypeNumberOne | GenericTypeNumberTwo | GenericTypeNumberThree); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/function-type/type-annotation.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/function-type/type-annotation.ts.snap deleted file mode 100644 index ed2d581fa90f..000000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/function-type/type-annotation.ts.snap +++ /dev/null @@ -1,36 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -const foo = (): () => void => (): void => null; -const bar = (): (() => void) => (): void => null; -const baz = (): ((() => void)) => (): void => null; -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,3 +1,3 @@ --const foo = (): (() => void) => (): void => null; -+const foo = (): () => void => (): void => null; - const bar = (): (() => void) => (): void => null; --const baz = (): (() => void) => (): void => null; -+const baz = (): ((() => void)) => (): void => null; -``` - -# Output - -```js -const foo = (): () => void => (): void => null; -const bar = (): (() => void) => (): void => null; -const baz = (): ((() => void)) => (): void => null; -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/intersection/intersection-parens.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/intersection/intersection-parens.ts.snap deleted file mode 100644 index 5958f8a1ab51..000000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/intersection/intersection-parens.ts.snap +++ /dev/null @@ -1,177 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -type A = (number | string) & boolean; -type B = ((number | string)) & boolean; -type C = (((number | string))) & boolean; -type D = ((((number | string)))) & boolean; - -let b1 : C; -let b2 : & C; -let b3 : (& C); -let b4 : & (C); -let b5 : (& (C)); -let b6 : /*1*/ & C; -let b7 : /*1*/ & (C); -let b8 : /*1*/ (& C); -let b9 : (/*1*/ & C); -let b10: /*1*/ & /*2*/ C; -let b11: /*1*/ (& /*2*/ C); - -let bb1: /*1*/ & /*2*/ C & D; -let bb2: /*1*/ & /*2*/ C & /*3*/ D; -let bb3: /*1*/ & /*2*/ C & /*3*/ D /*5*/; - -type B2 = & C; -type B3 = (& C); -type B4 = & (C); -type B5 = (& (C)); -type B6 = /*1*/ & C; -type B7 = /*1*/ & (C); -type B8 = /*1*/ (& C); -type B9 = (/*1*/ & C); -type B10 = /*1*/ & /*2*/ C; -type B11 = /*1*/ (& /*2*/ C); -type B12 = /*1*/ & ( (C)); - -type Bb1 = /*1*/ & /*2*/ C & D; -type Bb2 = /*1*/ & /*2*/ C & /*3*/ D; -type Bb3 = /*1*/ & /*2*/ C & /*3*/ D /*4*/; - -type D1 = /*1*/ | a & b; -type D2 = /*1*/ | a & (b); -type D3 = /*1*/ | a & (| b); -type D4 = /*1*/ | (a & b); -type D5 = /*1*/ (| a & b); -type D6 /*0*/ = /*1*/ (| a & b); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,43 +1,43 @@ - type A = (number | string) & boolean; --type B = (number | string) & boolean; --type C = (number | string) & boolean; --type D = (number | string) & boolean; -+type B = ((number | string)) & boolean; -+type C = (((number | string))) & boolean; -+type D = ((((number | string)))) & boolean; - - let b1: C; - let b2: C; --let b3: C; --let b4: C; --let b5: C; -+let b3: (C); -+let b4: (C); -+let b5: ((C)); - let b6: /*1*/ C; --let b7: /*1*/ C; --let b8: /*1*/ C; --let b9: /*1*/ C; -+let b7: /*1*/ (C); -+let b8: /*1*/ (C); -+let b9: (/*1*/ C); - let b10: /*1*/ /*2*/ C; --let b11: /*1*/ /*2*/ C; -+let b11: /*1*/ (/*2*/ C); - - let bb1: /*1*/ /*2*/ C & D; - let bb2: /*1*/ /*2*/ C & /*3*/ D; - let bb3: /*1*/ /*2*/ C & /*3*/ D /*5*/; - - type B2 = C; --type B3 = C; --type B4 = C; --type B5 = C; -+type B3 = (C); -+type B4 = (C); -+type B5 = ((C)); - type B6 = /*1*/ C; --type B7 = /*1*/ C; --type B8 = /*1*/ C; --type B9 = /*1*/ C; -+type B7 = /*1*/ (C); -+type B8 = /*1*/ (C); -+type B9 = (/*1*/ C); - type B10 = /*1*/ /*2*/ C; --type B11 = /*1*/ /*2*/ C; --type B12 = /*1*/ C; -+type B11 = /*1*/ (/*2*/ C); -+type B12 = /*1*/ ((C)); - - type Bb1 = /*1*/ /*2*/ C & D; - type Bb2 = /*1*/ /*2*/ C & /*3*/ D; - type Bb3 = /*1*/ /*2*/ C & /*3*/ D /*4*/; - - type D1 = /*1*/ a & b; --type D2 = /*1*/ a & b; --type D3 = /*1*/ a & b; --type D4 = /*1*/ a & b; --type D5 = /*1*/ a & b; --type D6 /*0*/ = /*1*/ a & b; -+type D2 = /*1*/ a & (b); -+type D3 = /*1*/ a & (b); -+type D4 = /*1*/ (a & b); -+type D5 = /*1*/ (a & b); -+type D6 /*0*/ = /*1*/ (a & b); -``` - -# Output - -```js -type A = (number | string) & boolean; -type B = ((number | string)) & boolean; -type C = (((number | string))) & boolean; -type D = ((((number | string)))) & boolean; - -let b1: C; -let b2: C; -let b3: (C); -let b4: (C); -let b5: ((C)); -let b6: /*1*/ C; -let b7: /*1*/ (C); -let b8: /*1*/ (C); -let b9: (/*1*/ C); -let b10: /*1*/ /*2*/ C; -let b11: /*1*/ (/*2*/ C); - -let bb1: /*1*/ /*2*/ C & D; -let bb2: /*1*/ /*2*/ C & /*3*/ D; -let bb3: /*1*/ /*2*/ C & /*3*/ D /*5*/; - -type B2 = C; -type B3 = (C); -type B4 = (C); -type B5 = ((C)); -type B6 = /*1*/ C; -type B7 = /*1*/ (C); -type B8 = /*1*/ (C); -type B9 = (/*1*/ C); -type B10 = /*1*/ /*2*/ C; -type B11 = /*1*/ (/*2*/ C); -type B12 = /*1*/ ((C)); - -type Bb1 = /*1*/ /*2*/ C & D; -type Bb2 = /*1*/ /*2*/ C & /*3*/ D; -type Bb3 = /*1*/ /*2*/ C & /*3*/ D /*4*/; - -type D1 = /*1*/ a & b; -type D2 = /*1*/ a & (b); -type D3 = /*1*/ a & (b); -type D4 = /*1*/ (a & b); -type D5 = /*1*/ (a & b); -type D6 /*0*/ = /*1*/ (a & b); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/keyof/keyof.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/keyof/keyof.ts.snap deleted file mode 100644 index aa336a39fcf7..000000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/keyof/keyof.ts.snap +++ /dev/null @@ -1,57 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -type A = keyof (T | U); -type B = keyof (X & Y); -type C = keyof T | U; -type D = keyof X & Y; -type E = (keyof T)[]; -type F = ((keyof T))[]; -type G = (keyof T1)["foo"]; -type H = ((keyof T1))["foo"]; -type I = (((keyof T1)))["foo"]; -type J = ((((keyof T1))))["foo"]; -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -3,8 +3,8 @@ - type C = keyof T | U; - type D = keyof X & Y; - type E = (keyof T)[]; --type F = (keyof T)[]; -+type F = ((keyof T))[]; - type G = (keyof T1)["foo"]; --type H = (keyof T1)["foo"]; --type I = (keyof T1)["foo"]; --type J = (keyof T1)["foo"]; -+type H = ((keyof T1))["foo"]; -+type I = (((keyof T1)))["foo"]; -+type J = ((((keyof T1))))["foo"]; -``` - -# Output - -```js -type A = keyof (T | U); -type B = keyof (X & Y); -type C = keyof T | U; -type D = keyof X & Y; -type E = (keyof T)[]; -type F = ((keyof T))[]; -type G = (keyof T1)["foo"]; -type H = ((keyof T1))["foo"]; -type I = (((keyof T1)))["foo"]; -type J = ((((keyof T1))))["foo"]; -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/keyword-types/conditional-types.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/keyword-types/conditional-types.ts.snap index af019ba8041f..e1a8d4a8207a 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/keyword-types/conditional-types.ts.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/typescript/keyword-types/conditional-types.ts.snap @@ -1,8 +1,5 @@ --- source: crates/rome_js_formatter/tests/prettier_tests.rs -assertion_line: 271 -info: - test_file: typescript/keyword-types/conditional-types.ts --- # Input @@ -30,26 +27,14 @@ export type UnwrappedResultRow = { ```diff --- Prettier +++ Rome -@@ -1,8 +1,14 @@ - export type UnwrappedResultRow = { -- [P in keyof T]: T[P] extends Req -- ? a -- : T[P] extends Opt -- ? b +@@ -3,6 +3,7 @@ + ? a + : T[P] extends Opt + ? b - : // TEST -- never; -+ [P in keyof T]: ( -+ T[P] extends Req -+ ? (a) -+ : ( -+ T[P] extends Opt -+ ? (b) -+ : ( -+ // TEST -+ never -+ ) -+ ) -+ ); ++ : ++ // TEST + never; }; ``` @@ -57,18 +42,13 @@ export type UnwrappedResultRow = { ```js export type UnwrappedResultRow = { - [P in keyof T]: ( - T[P] extends Req - ? (a) - : ( - T[P] extends Opt - ? (b) - : ( - // TEST - never - ) - ) - ); + [P in keyof T]: T[P] extends Req + ? a + : T[P] extends Opt + ? b + : + // TEST + never; }; ``` diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/keyword-types/keyword-types-with-parens-comments.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/keyword-types/keyword-types-with-parens-comments.ts.snap index f2b504f2ffa3..d321dd2b756e 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/keyword-types/keyword-types-with-parens-comments.ts.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/typescript/keyword-types/keyword-types-with-parens-comments.ts.snap @@ -65,142 +65,103 @@ let foo: ( ```diff --- Prettier +++ Rome -@@ -1,26 +1,52 @@ +@@ -1,26 +1,39 @@ -let foo: // comment --any; ++let foo: ++// comment + any; -let foo: // comment --null; ++let foo: ++// comment + null; -let foo: // comment --this; ++let foo: ++// comment + this; -let foo: // comment --number; ++let foo: ++// comment + number; -let foo: // comment --void; ++let foo: ++// comment + void; -let foo: // comment --boolean; ++let foo: ++// comment + boolean; -let foo: // comment --bigint; ++let foo: ++// comment + bigint; -let foo: // comment --symbol; ++let foo: ++// comment + symbol; -let foo: // comment --string; ++let foo: ++// comment + string; -let foo: // comment --never; ++let foo: ++// comment + never; -let foo: // comment --object; ++let foo: ++// comment + object; -let foo: // comment --undefined; ++let foo: ++// comment + undefined; -let foo: // comment --unknown; -+let foo: ( -+ // comment -+ any -+); -+let foo: ( -+ // comment -+ null -+); -+let foo: ( -+ // comment -+ this -+); -+let foo: ( -+ // comment -+ number -+); -+let foo: ( -+ // comment -+ void -+); -+let foo: ( -+ // comment -+ boolean -+); -+let foo: ( -+ // comment -+ bigint -+); -+let foo: ( -+ // comment -+ symbol -+); -+let foo: ( -+ // comment -+ string -+); -+let foo: ( -+ // comment -+ never -+); -+let foo: ( -+ // comment -+ object -+); -+let foo: ( -+ // comment -+ undefined -+); -+let foo: ( -+ // comment -+ unknown -+); ++let foo: ++// comment + unknown; ``` # Output ```js -let foo: ( - // comment - any -); -let foo: ( - // comment - null -); -let foo: ( - // comment - this -); -let foo: ( - // comment - number -); -let foo: ( - // comment - void -); -let foo: ( - // comment - boolean -); -let foo: ( - // comment - bigint -); -let foo: ( - // comment - symbol -); -let foo: ( - // comment - string -); -let foo: ( - // comment - never -); -let foo: ( - // comment - object -); -let foo: ( - // comment - undefined -); -let foo: ( - // comment - unknown -); +let foo: +// comment +any; +let foo: +// comment +null; +let foo: +// comment +this; +let foo: +// comment +number; +let foo: +// comment +void; +let foo: +// comment +boolean; +let foo: +// comment +bigint; +let foo: +// comment +symbol; +let foo: +// comment +string; +let foo: +// comment +never; +let foo: +// comment +object; +let foo: +// comment +undefined; +let foo: +// comment +unknown; ``` diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/rest-type/infer-type.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/rest-type/infer-type.ts.snap deleted file mode 100644 index b52e8f798c7c..000000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/rest-type/infer-type.ts.snap +++ /dev/null @@ -1,58 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -type Tail = T extends [infer U, ...infer R] ? R : never; - -// should remove parens from this, to avoid a type issue with TypeScript 4.0: -type Tail2 = T extends [infer U, ...(infer R)] ? R : never; - -// but not remove parens from this: -type Tail3 = T extends [infer U, ...(infer R)[]] ? R : never; - -type ReduceNextElement< - T extends readonly unknown[] -> = T extends readonly [infer V, ...infer R] ? [V, R] : never -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,7 +1,7 @@ - type Tail = T extends [infer U, ...infer R] ? R : never; - - // should remove parens from this, to avoid a type issue with TypeScript 4.0: --type Tail2 = T extends [infer U, ...infer R] ? R : never; -+type Tail2 = T extends [infer U, ...(infer R)] ? R : never; - - // but not remove parens from this: - type Tail3 = T extends [infer U, ...(infer R)[]] ? R : never; -``` - -# Output - -```js -type Tail = T extends [infer U, ...infer R] ? R : never; - -// should remove parens from this, to avoid a type issue with TypeScript 4.0: -type Tail2 = T extends [infer U, ...(infer R)] ? R : never; - -// but not remove parens from this: -type Tail3 = T extends [infer U, ...(infer R)[]] ? R : never; - -type ReduceNextElement = T extends readonly [ - infer V, - ...infer R, -] - ? [V, R] - : never; -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/union/comments.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/union/comments.ts.snap deleted file mode 100644 index cb9141b69666..000000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/union/comments.ts.snap +++ /dev/null @@ -1,58 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -type A1 = a /* 1 */ | b; -type A2 = a | /* 1 */ b; -type A3 = (a /* 1 */) | b; -type A4 = a | (/* 1 */ b); -type A5 = (a) /* 1 */ | b; -type A6 = a | /* 1 */ (b); - -type B1 = a /* 1 */ /* 2 */ | b; -type B2 = a /* 1 */ | /* 2 */ b; -type B3 = a | /* 1 */ /* 2 */ b; -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,9 +1,9 @@ - type A1 = a /* 1 */ | b; - type A2 = a | /* 1 */ b; --type A3 = a /* 1 */ | b; --type A4 = a | /* 1 */ b; --type A5 = a /* 1 */ | b; --type A6 = a | /* 1 */ b; -+type A3 = (a /* 1 */) | b; -+type A4 = a | (/* 1 */ b); -+type A5 = (a) /* 1 */ | b; -+type A6 = a | /* 1 */ (b); - - type B1 = a /* 1 */ /* 2 */ | b; - type B2 = a /* 1 */ | /* 2 */ b; -``` - -# Output - -```js -type A1 = a /* 1 */ | b; -type A2 = a | /* 1 */ b; -type A3 = (a /* 1 */) | b; -type A4 = a | (/* 1 */ b); -type A5 = (a) /* 1 */ | b; -type A6 = a | /* 1 */ (b); - -type B1 = a /* 1 */ /* 2 */ | b; -type B2 = a /* 1 */ | /* 2 */ b; -type B3 = a | /* 1 */ /* 2 */ b; -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/union/inlining.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/union/inlining.ts.snap index 8b6eb213ae84..f4bf6bd2af6e 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/union/inlining.ts.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/typescript/union/inlining.ts.snap @@ -91,7 +91,7 @@ type T8 = number | (((((arg: any) => void)))); | A // The upload timed out | B -@@ -27,15 +34,17 @@ +@@ -27,9 +34,11 @@ // Uploading to aws3 and CreatePostMutation succeeded | D; @@ -105,19 +105,7 @@ type T8 = number | (((((arg: any) => void)))); + }; type T1 = (number | string)["toString"]; --type T2 = (number | string)["toString"]; --type T3 = (number | string)["toString"]; --type T4 = (number | string)["toString"]; -+type T2 = ((number | string))["toString"]; -+type T3 = (((number | string)))["toString"]; -+type T4 = ((((number | string))))["toString"]; - type T5 = number | ((arg: any) => void); --type T6 = number | ((arg: any) => void); --type T7 = number | ((arg: any) => void); --type T8 = number | ((arg: any) => void); -+type T6 = number | (((arg: any) => void)); -+type T7 = number | ((((arg: any) => void))); -+type T8 = number | (((((arg: any) => void)))); + type T2 = (number | string)["toString"]; ``` # Output @@ -166,13 +154,13 @@ type window = }; type T1 = (number | string)["toString"]; -type T2 = ((number | string))["toString"]; -type T3 = (((number | string)))["toString"]; -type T4 = ((((number | string))))["toString"]; +type T2 = (number | string)["toString"]; +type T3 = (number | string)["toString"]; +type T4 = (number | string)["toString"]; type T5 = number | ((arg: any) => void); -type T6 = number | (((arg: any) => void)); -type T7 = number | ((((arg: any) => void))); -type T8 = number | (((((arg: any) => void)))); +type T6 = number | ((arg: any) => void); +type T7 = number | ((arg: any) => void); +type T8 = number | ((arg: any) => void); ``` diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/union/prettier-ignore.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/union/prettier-ignore.ts.snap index ffcbccefab60..a542fbd87285 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/union/prettier-ignore.ts.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/typescript/union/prettier-ignore.ts.snap @@ -47,11 +47,11 @@ export type a = - // prettier-ignore - | qux1&qux2; + // foo -+ | foo1 & foo2 ++ | (foo1 & foo2) + // bar -+ | bar1 & bar2 ++ | (bar1 & bar2) + // prettier-ignore -+ | qux1 & qux2; ++ | (qux1 & qux2); export type a = - // foo @@ -63,13 +63,13 @@ export type a = - // baz - | (baz1 & baz2); + // foo -+ | foo1 & foo2 ++ | (foo1 & foo2) + // bar -+ | bar1 & bar2 ++ | (bar1 & bar2) + // prettier-ignore -+ | qux1 & qux2 ++ | (qux1 & qux2) + // baz -+ | baz1 & baz2; ++ | (baz1 & baz2); export type a = // prettier-ignore @@ -87,21 +87,21 @@ export type a = ```js export type a = // foo - | foo1 & foo2 + | (foo1 & foo2) // bar - | bar1 & bar2 + | (bar1 & bar2) // prettier-ignore - | qux1 & qux2; + | (qux1 & qux2); export type a = // foo - | foo1 & foo2 + | (foo1 & foo2) // bar - | bar1 & bar2 + | (bar1 & bar2) // prettier-ignore - | qux1 & qux2 + | (qux1 & qux2) // baz - | baz1 & baz2; + | (baz1 & baz2); export type a = // prettier-ignore diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/union/union-parens.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/union/union-parens.ts.snap index 4f33e76cfcb0..4ab582937c8b 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/union/union-parens.ts.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/typescript/union/union-parens.ts.snap @@ -124,44 +124,8 @@ type Ctor = (new () => X) | Y; ```diff --- Prettier +++ Rome -@@ -1,10 +1,12 @@ --export type A = -- | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -- | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; -+export type A = ( -+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -+ | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -+); - --export type B = -- | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -- | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; -+export type B = ( -+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -+ | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -+); - - export type C = - | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -@@ -16,43 +18,44 @@ - - export type Multi = (string | number)[]; - --function f(): string | number {} -+function f(): (string | number) {} - --var x: string | number; --var y: string | number; -+var x: (string | number); -+var y: ((string | number)); - --class Foo {} -+class Foo {} - - interface Interface { - i: (X | Y) & Z; -- j: Partial; -+ j: Partial<(X | Y)>; +@@ -28,13 +28,15 @@ + j: Partial; } -type State = { @@ -176,124 +140,42 @@ type Ctor = (new () => X) | Y; + sharedProperty: any; + } + & ( -+ | { discriminant: "FOO"; foo: any } -+ | { discriminant: "BAR"; bar: any } -+ | { discriminant: "BAZ"; baz: any } ++ | { discriminant: "FOO"; foo: any } ++ | { discriminant: "BAR"; bar: any } ++ | { discriminant: "BAZ"; baz: any } + ); const foo1 = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as ( -- | string -- | undefined -+ string | undefined - )[]; - - const foo2: ( -- | AAAAAAAAAAAAAAAAAAAAAA -- | BBBBBBBBBBBBBBBBBBBBBB -- | CCCCCCCCCCCCCCCCCCCCCC -- | DDDDDDDDDDDDDDDDDDDDDD -+ | AAAAAAAAAAAAAAAAAAAAAA -+ | BBBBBBBBBBBBBBBBBBBBBB -+ | CCCCCCCCCCCCCCCCCCCCCC -+ | DDDDDDDDDDDDDDDDDDDDDD - )[] = []; - - const foo3: keyof ( -- | AAAAAAAAAAAAAAAAAAAAAA -- | BBBBBBBBBBBBBBBBBBBBBB -- | CCCCCCCCCCCCCCCCCCCCCC -- | DDDDDDDDDDDDDDDDDDDDDD + | string +@@ -58,11 +60,11 @@ + const foo4: + | foo + | ( +- | AAAAAAAAAAAAAAAAAAAAAA +- | BBBBBBBBBBBBBBBBBBBBBB +- | CCCCCCCCCCCCCCCCCCCCCC +- | DDDDDDDDDDDDDDDDDDDDDD +- ) = bar; + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC + | DDDDDDDDDDDDDDDDDDDDDD - ) = bar; - - const foo4: -@@ -62,19 +65,19 @@ - | BBBBBBBBBBBBBBBBBBBBBB - | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD -- ) = bar; + ) = bar; let a1: C; let a2: C; --let a3: C; --let a4: C; --let a5: C; -+let a3: (C); -+let a4: (C); -+let a5: ((C)); - let a6: /*1*/ C; --let a7: /*1*/ C; --let a8: /*1*/ C; --let a9: /*1*/ C; -+let a7: /*1*/ (C); -+let a8: /*1*/ (C); -+let a9: (/*1*/ C); - let a10: /*1*/ /*2*/ C; --let a11: /*1*/ /*2*/ C; -+let a11: /*1*/ (/*2*/ C); - - let aa1: /*1*/ /*2*/ C | D; - let aa2: /*1*/ /*2*/ C | /*3*/ D; -@@ -82,27 +85,27 @@ - - type A1 = C; - type A2 = C; --type A3 = C; --type A4 = C; --type A5 = C; -+type A3 = (C); -+type A4 = (C); -+type A5 = ((C)); - type A6 = /*1*/ C; --type A7 = /*1*/ C; --type A8 = /*1*/ C; --type A9 = /*1*/ C; -+type A7 = /*1*/ (C); -+type A8 = /*1*/ (C); -+type A9 = (/*1*/ C); - type A10 = /*1*/ /*2*/ C; --type A11 = /*1*/ /*2*/ C; --type A12 = /*1*/ C; --type A13 = /*1*/ C; -+type A11 = /*1*/ (/*2*/ C); -+type A12 = /*1*/ ((C)); -+type A13 = /*1*/ ((C)); - - type Aa1 = /*1*/ /*2*/ C | D; - type Aa2 = /*1*/ /*2*/ C | /*3*/ D; - type Aa3 = /*1*/ /*2*/ C | /*3*/ D /*4*/; - - type C1 = /*1*/ a | b; --type C2 = /*1*/ a | b; --type C3 = /*1*/ a | b; --type C4 = /*1*/ a | b; --type C5 = /*1*/ a | b; --type C6 /*0*/ = /*1*/ a | b; -+type C2 = /*1*/ a | (b); -+type C3 = /*1*/ a | (b); -+type C4 = /*1*/ (a | b); -+type C5 = /*1*/ (a | b); -+type C6 /*0*/ = /*1*/ (a | b); - - type Ctor = (new () => X) | Y; ``` # Output ```js -export type A = ( - | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -); +export type A = + | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; -export type B = ( - | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -); +export type B = + | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; export type C = | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -305,16 +187,16 @@ export type D = export type Multi = (string | number)[]; -function f(): (string | number) {} +function f(): string | number {} -var x: (string | number); -var y: ((string | number)); +var x: string | number; +var y: string | number; -class Foo {} +class Foo {} interface Interface { i: (X | Y) & Z; - j: Partial<(X | Y)>; + j: Partial; } type State = @@ -322,49 +204,50 @@ type State = sharedProperty: any; } & ( - | { discriminant: "FOO"; foo: any } - | { discriminant: "BAR"; bar: any } - | { discriminant: "BAZ"; baz: any } + | { discriminant: "FOO"; foo: any } + | { discriminant: "BAR"; bar: any } + | { discriminant: "BAZ"; baz: any } ); const foo1 = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz] as ( - string | undefined + | string + | undefined )[]; const foo2: ( - | AAAAAAAAAAAAAAAAAAAAAA - | BBBBBBBBBBBBBBBBBBBBBB - | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC + | DDDDDDDDDDDDDDDDDDDDDD )[] = []; const foo3: keyof ( - | AAAAAAAAAAAAAAAAAAAAAA - | BBBBBBBBBBBBBBBBBBBBBB - | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC + | DDDDDDDDDDDDDDDDDDDDDD ) = bar; const foo4: | foo | ( - | AAAAAAAAAAAAAAAAAAAAAA - | BBBBBBBBBBBBBBBBBBBBBB - | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC + | DDDDDDDDDDDDDDDDDDDDDD ) = bar; let a1: C; let a2: C; -let a3: (C); -let a4: (C); -let a5: ((C)); +let a3: C; +let a4: C; +let a5: C; let a6: /*1*/ C; -let a7: /*1*/ (C); -let a8: /*1*/ (C); -let a9: (/*1*/ C); +let a7: /*1*/ C; +let a8: /*1*/ C; +let a9: /*1*/ C; let a10: /*1*/ /*2*/ C; -let a11: /*1*/ (/*2*/ C); +let a11: /*1*/ /*2*/ C; let aa1: /*1*/ /*2*/ C | D; let aa2: /*1*/ /*2*/ C | /*3*/ D; @@ -372,28 +255,28 @@ let aa3: /*1*/ /*2*/ C | /*3*/ D /*4*/; type A1 = C; type A2 = C; -type A3 = (C); -type A4 = (C); -type A5 = ((C)); +type A3 = C; +type A4 = C; +type A5 = C; type A6 = /*1*/ C; -type A7 = /*1*/ (C); -type A8 = /*1*/ (C); -type A9 = (/*1*/ C); +type A7 = /*1*/ C; +type A8 = /*1*/ C; +type A9 = /*1*/ C; type A10 = /*1*/ /*2*/ C; -type A11 = /*1*/ (/*2*/ C); -type A12 = /*1*/ ((C)); -type A13 = /*1*/ ((C)); +type A11 = /*1*/ /*2*/ C; +type A12 = /*1*/ C; +type A13 = /*1*/ C; type Aa1 = /*1*/ /*2*/ C | D; type Aa2 = /*1*/ /*2*/ C | /*3*/ D; type Aa3 = /*1*/ /*2*/ C | /*3*/ D /*4*/; type C1 = /*1*/ a | b; -type C2 = /*1*/ a | (b); -type C3 = /*1*/ a | (b); -type C4 = /*1*/ (a | b); -type C5 = /*1*/ (a | b); -type C6 /*0*/ = /*1*/ (a | b); +type C2 = /*1*/ a | b; +type C3 = /*1*/ a | b; +type C4 = /*1*/ a | b; +type C5 = /*1*/ a | b; +type C6 /*0*/ = /*1*/ a | b; type Ctor = (new () => X) | Y; ``` diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/union/within-tuple.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/union/within-tuple.ts.snap index f27eb06b09a5..373399d0cb82 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/union/within-tuple.ts.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/typescript/union/within-tuple.ts.snap @@ -77,7 +77,7 @@ type F = [ ```diff --- Prettier +++ Rome -@@ -1,92 +1,88 @@ +@@ -1,92 +1,78 @@ type A = [ - | AAAAAAAAAAAAAAAAAAAAAA - | BBBBBBBBBBBBBBBBBBBBBB @@ -105,20 +105,18 @@ type F = [ - | BBBBBBBBBBBBBBBBBBBBBB - | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD, --]; -- --type C = [ ++ | AAAAAAAAAAAAAAAAAAAAAA ++ | BBBBBBBBBBBBBBBBBBBBBB ++ | CCCCCCCCCCCCCCCCCCCCCC ++ | DDDDDDDDDDDDDDDDDDDDDD, + ]; + + type C = [ - | [ -+ ( - | AAAAAAAAAAAAAAAAAAAAAA - | BBBBBBBBBBBBBBBBBBBBBB - | CCCCCCCCCCCCCCCCCCCCCC +- | AAAAAAAAAAAAAAAAAAAAAA +- | BBBBBBBBBBBBBBBBBBBBBB +- | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD, -+ | DDDDDDDDDDDDDDDDDDDDDD -+ ), -+]; -+ -+type C = [ + | [ + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB @@ -139,49 +137,37 @@ type F = [ ]; type D = [ - ( -- | AAAAAAAAAAAAAAAAAAAAAA -- | BBBBBBBBBBBBBBBBBBBBBB -- | CCCCCCCCCCCCCCCCCCCCCC +- ( + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD -+ | AAAAAAAAAAAAAAAAAAAAAA -+ | BBBBBBBBBBBBBBBBBBBBBB -+ | CCCCCCCCCCCCCCCCCCCCCC -+ | DDDDDDDDDDDDDDDDDDDDDD - ), - ( -- | AAAAAAAAAAAAAAAAAAAAAA -- | BBBBBBBBBBBBBBBBBBBBBB -- | CCCCCCCCCCCCCCCCCCCCCC +- ), +- ( ++ | DDDDDDDDDDDDDDDDDDDDDD, + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD -+ | AAAAAAAAAAAAAAAAAAAAAA -+ | BBBBBBBBBBBBBBBBBBBBBB -+ | CCCCCCCCCCCCCCCCCCCCCC -+ | DDDDDDDDDDDDDDDDDDDDDD - ), +- ), ++ | DDDDDDDDDDDDDDDDDDDDDD, ]; type D1 = [ - ( -- | AAAAAAAAAAAAAAAAAAAAAA -- | BBBBBBBBBBBBBBBBBBBBBB -- | CCCCCCCCCCCCCCCCCCCCCC +- ( + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD -+ | AAAAAAAAAAAAAAAAAAAAAA -+ | BBBBBBBBBBBBBBBBBBBBBB -+ | CCCCCCCCCCCCCCCCCCCCCC -+ | DDDDDDDDDDDDDDDDDDDDDD - ), - ( -- | AAAAAAAAAAAAAAAAAAAAAA -- | BBBBBBBBBBBBBBBBBBBBBB -- | CCCCCCCCCCCCCCCCCCCCCC +- ), +- ( ++ | DDDDDDDDDDDDDDDDDDDDDD, + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD -+ | AAAAAAAAAAAAAAAAAAAAAA -+ | BBBBBBBBBBBBBBBBBBBBBB -+ | CCCCCCCCCCCCCCCCCCCCCC -+ | DDDDDDDDDDDDDDDDDDDDDD - ), +- ), ++ | DDDDDDDDDDDDDDDDDDDDDD, ]; type D2 = [ @@ -233,12 +219,10 @@ type B = [ ]; type B1 = [ - ( - | AAAAAAAAAAAAAAAAAAAAAA - | BBBBBBBBBBBBBBBBBBBBBB - | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD - ), + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC + | DDDDDDDDDDDDDDDDDDDDDD, ]; type C = [ @@ -257,33 +241,25 @@ type C = [ ]; type D = [ - ( - | AAAAAAAAAAAAAAAAAAAAAA - | BBBBBBBBBBBBBBBBBBBBBB - | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD - ), - ( - | AAAAAAAAAAAAAAAAAAAAAA - | BBBBBBBBBBBBBBBBBBBBBB - | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD - ), + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC + | DDDDDDDDDDDDDDDDDDDDDD, + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC + | DDDDDDDDDDDDDDDDDDDDDD, ]; type D1 = [ - ( - | AAAAAAAAAAAAAAAAAAAAAA - | BBBBBBBBBBBBBBBBBBBBBB - | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD - ), - ( - | AAAAAAAAAAAAAAAAAAAAAA - | BBBBBBBBBBBBBBBBBBBBBB - | CCCCCCCCCCCCCCCCCCCCCC - | DDDDDDDDDDDDDDDDDDDDDD - ), + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC + | DDDDDDDDDDDDDDDDDDDDDD, + | AAAAAAAAAAAAAAAAAAAAAA + | BBBBBBBBBBBBBBBBBBBBBB + | CCCCCCCCCCCCCCCCCCCCCC + | DDDDDDDDDDDDDDDDDDDDDD, ]; type D2 = [ diff --git a/crates/rome_js_formatter/tests/specs/ts/expression/type_expression.ts.snap b/crates/rome_js_formatter/tests/specs/ts/expression/type_expression.ts.snap index cdeedea776ac..6e235fb82ed2 100644 --- a/crates/rome_js_formatter/tests/specs/ts/expression/type_expression.ts.snap +++ b/crates/rome_js_formatter/tests/specs/ts/expression/type_expression.ts.snap @@ -181,7 +181,7 @@ type TupleD = [ ...name: string[], ]; -type PA = (string); +type PA = string; type FunctionType = < Aaaaaaaaaaaaaaaaaaaaa,