From 4d77bcd26d1f06a9dc926e96f17be3dc0feb0054 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Thu, 25 Aug 2022 10:47:09 +0200 Subject: [PATCH 1/4] 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 34e2313261f..2243320127d 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 39f070c7f34..bc8894ac7b7 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 45ff5eb30db..eeabd9ce0d0 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 daf2c6abbf3..333e0d7494f 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 fa131abe703..2b1e18221ce 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 b6f6d8bb073..4ee716ab525 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 0de01291245..0fb4cfa6733 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 6a8dc6f5b4e..399fd9d62bf 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 911b3dee83f..e9315e0a9e2 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 d6c1ab3026c..ce13b5562e8 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 f12e37212b8..2facbdfe3e7 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 33847e7dbc7..47f71787d63 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 90ee306da06..fa299321eb8 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 16062fa36da..a56b90c423e 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 fddb1d9a230..b39c3e0ebe5 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 0240fca7d49..d392640eee2 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 8ee0714549d..df9bb9bc517 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 e9d47d0304b..fd262f94b71 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 cfd021c439f..12c0af04458 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 9a83230888e..94780fba316 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 4ad6c25b519..c90e04c15a4 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 22771135a06..63125b8d712 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 f4288f01323..ab8fd15cf90 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 a545b17e397..e63b7b5b9fc 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 8bd8138fab6..80d7c05fb80 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 f1c89491250..34023eefa36 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 3ca62311b74..335f8aaad17 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 9e5c63632f9..07db99fc6e3 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 3bf49800b55..5f34901c543 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 099d7a6f427..816f6c9070c 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 7aa921f5466..a8a137061bf 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 3439e3eacac..af876a4c397 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 fd6dd01eded..cdaaae84963 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 b445cd5dc46..d5ed37b4726 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 37a7e821397..666e6330363 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 54ed55045d1..ed00add990e 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 f9818bd0a5c..6e20c2d25e5 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 dbb57205c52..297fb022eed 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 98d9137afb4..165e4e81271 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 aab1fb48184..118ee868618 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 59e591bf4fa..e242c45bdf8 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 012c2ea0a99..bec88409655 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 99f5dca786e..2ff9f6c44d1 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 28231eb2e6a..00000000000 --- 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 8e19c3de6dd..00000000000 --- 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 6d3f1a8bfea..00000000000 --- 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 ed2d581fa90..00000000000 --- 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 5958f8a1ab5..00000000000 --- 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 aa336a39fcf..00000000000 --- 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 af019ba8041..e1a8d4a8207 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 f2b504f2ffa..d321dd2b756 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 b52e8f798c7..00000000000 --- 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 cb9141b6966..00000000000 --- 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 8b6eb213ae8..f4bf6bd2af6 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 ffcbccefab6..a542fbd8728 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 4f33e76cfcb..4ab582937c8 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 f27eb06b09a..373399d0cb8 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 cdeedea776a..6e235fb82ed 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, From 8ae1f8eae595e86cab0e71a4352735440294d3ea Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Mon, 29 Aug 2022 17:30:45 +0200 Subject: [PATCH 2/4] My beloved friend clippy --- crates/rome_js_formatter/src/parentheses.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/rome_js_formatter/src/parentheses.rs b/crates/rome_js_formatter/src/parentheses.rs index eeabd9ce0d0..d8742b09e19 100644 --- a/crates/rome_js_formatter/src/parentheses.rs +++ b/crates/rome_js_formatter/src/parentheses.rs @@ -44,9 +44,9 @@ use rome_js_syntax::{ JsAnyLiteralExpression, JsArrowFunctionExpression, JsAssignmentExpression, JsBinaryExpression, JsBinaryOperator, JsComputedMemberAssignment, JsComputedMemberExpression, JsConditionalExpression, JsLanguage, JsParenthesizedAssignment, JsParenthesizedExpression, - JsSequenceExpression, JsSyntaxKind, JsSyntaxNode, JsSyntaxToken, TsConditionalType, - TsIndexedAccessType, TsIntersectionTypeElementList, TsParenthesizedType, TsType, - TsUnionTypeVariantList, + JsSequenceExpression, JsStaticMemberAssignment, JsStaticMemberExpression, JsSyntaxKind, + JsSyntaxNode, JsSyntaxToken, TsConditionalType, TsIndexedAccessType, + TsIntersectionTypeElementList, TsParenthesizedType, TsType, TsUnionTypeVariantList, }; use rome_rowan::{declare_node_union, match_ast, AstNode, AstSeparatedList, SyntaxResult}; From f2fdd85746429041a822650258612dc6d9ab3eb5 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Mon, 29 Aug 2022 17:38:31 +0200 Subject: [PATCH 3/4] Format files --- crates/rome_js_formatter/src/ts/types/type_operator_type.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 d5ed37b4726..780f05dd9ab 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 @@ -2,9 +2,7 @@ use crate::prelude::*; use crate::parentheses::{operator_type_or_higher_needs_parens, NeedsParentheses}; use rome_formatter::write; -use rome_js_syntax::{ - JsSyntaxNode, TsTypeOperatorType, TsTypeOperatorTypeFields, -}; +use rome_js_syntax::{JsSyntaxNode, TsTypeOperatorType, TsTypeOperatorTypeFields}; use rome_rowan::AstNode; #[derive(Debug, Clone, Default)] From 52386d237c798e984059df793497e18f89ca2160 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Mon, 29 Aug 2022 19:31:24 +0200 Subject: [PATCH 4/4] Update Node tests --- npm/rome/tests/daemon.test.mjs | 36 +++++++++++----------- npm/rome/tests/wasm.test.mjs | 36 +++++++++++----------- npm/rome/tests/wasm/formatContent.test.mjs | 36 +++++++++++----------- 3 files changed, 54 insertions(+), 54 deletions(-) diff --git a/npm/rome/tests/daemon.test.mjs b/npm/rome/tests/daemon.test.mjs index 24a5db5c73c..787bfca123e 100644 --- a/npm/rome/tests/daemon.test.mjs +++ b/npm/rome/tests/daemon.test.mjs @@ -108,8 +108,8 @@ describe("Rome Deamon formatter", () => { expect(result.content).toEqual("function f() {}\n"); expect(result.diagnostics).toEqual([]); - expect(result.ir).toEqual( - '["function", " ", "f", group(["(", ")"]), " ", "{", "}", hard_line_break]', + expect(result.ir).toMatchInlineSnapshot( + '"[\\"function\\", \\" \\", \\"f\\", group([\\"(\\", \\")\\"]), \\" \\", \\"{\\", \\"}\\", hard_line_break]"', ); }); @@ -152,22 +152,22 @@ describe("Rome Deamon formatter", () => { expect(result.content).toEqual("function g() {}"); expect(result.diagnostics).toEqual([]); - expect(result.ir).toEqual( - `[ - "let", - " ", - group(["a"]), - ";", - hard_line_break, - "function", - " ", - "g", - group(["(", ")"]), - " ", - "{", - "}", - hard_line_break -]`, + expect(result.ir).toMatchInlineSnapshot( + ` + "[ + group([\\"let\\", \\" \\", \\"a\\"]), + \\";\\", + hard_line_break, + \\"function\\", + \\" \\", + \\"g\\", + group([\\"(\\", \\")\\"]), + \\" \\", + \\"{\\", + \\"}\\", + hard_line_break + ]" + `, ); }); }); diff --git a/npm/rome/tests/wasm.test.mjs b/npm/rome/tests/wasm.test.mjs index 6d41ad64343..73308e16d6e 100644 --- a/npm/rome/tests/wasm.test.mjs +++ b/npm/rome/tests/wasm.test.mjs @@ -70,8 +70,8 @@ describe("Rome WebAssembly formatter", () => { expect(result.content).toEqual("function f() {}\n"); expect(result.diagnostics).toEqual([]); - expect(result.ir).toEqual( - '["function", " ", "f", group(["(", ")"]), " ", "{", "}", hard_line_break]', + expect(result.ir).toMatchInlineSnapshot( + '"[\\"function\\", \\" \\", \\"f\\", group([\\"(\\", \\")\\"]), \\" \\", \\"{\\", \\"}\\", hard_line_break]"', ); }); @@ -102,22 +102,22 @@ describe("Rome WebAssembly formatter", () => { expect(result.content).toEqual("function g() {}"); expect(result.diagnostics).toEqual([]); - expect(result.ir).toEqual( - `[ - "let", - " ", - group(["a"]), - ";", - hard_line_break, - "function", - " ", - "g", - group(["(", ")"]), - " ", - "{", - "}", - hard_line_break -]`, + expect(result.ir).toMatchInlineSnapshot( + ` + "[ + group([\\"let\\", \\" \\", \\"a\\"]), + \\";\\", + hard_line_break, + \\"function\\", + \\" \\", + \\"g\\", + group([\\"(\\", \\")\\"]), + \\" \\", + \\"{\\", + \\"}\\", + hard_line_break + ]" + `, ); }); }); diff --git a/npm/rome/tests/wasm/formatContent.test.mjs b/npm/rome/tests/wasm/formatContent.test.mjs index 9f465449691..b266bf8f753 100644 --- a/npm/rome/tests/wasm/formatContent.test.mjs +++ b/npm/rome/tests/wasm/formatContent.test.mjs @@ -45,8 +45,8 @@ describe("Rome WebAssembly formatContent", () => { expect(result.content).toEqual("function f() {}\n"); expect(result.diagnostics).toEqual([]); - expect(result.ir).toEqual( - '["function", " ", "f", group(["(", ")"]), " ", "{", "}", hard_line_break]', + expect(result.ir).toMatchInlineSnapshot( + '"[\\"function\\", \\" \\", \\"f\\", group([\\"(\\", \\")\\"]), \\" \\", \\"{\\", \\"}\\", hard_line_break]"', ); }); @@ -77,22 +77,22 @@ describe("Rome WebAssembly formatContent", () => { expect(result.content).toEqual("function g() {}"); expect(result.diagnostics).toEqual([]); - expect(result.ir).toEqual( - `[ - "let", - " ", - group(["a"]), - ";", - hard_line_break, - "function", - " ", - "g", - group(["(", ")"]), - " ", - "{", - "}", - hard_line_break -]`, + expect(result.ir).toMatchInlineSnapshot( + ` + "[ + group([\\"let\\", \\" \\", \\"a\\"]), + \\";\\", + hard_line_break, + \\"function\\", + \\" \\", + \\"g\\", + group([\\"(\\", \\")\\"]), + \\" \\", + \\"{\\", + \\"}\\", + hard_line_break + ]" + `, ); });