Skip to content

Commit

Permalink
Formatter: TS Intersection & Union types rome#3162
Browse files Browse the repository at this point in the history
  • Loading branch information
denbezrukov committed Sep 12, 2022
1 parent 9c790af commit 1aa9365
Show file tree
Hide file tree
Showing 5 changed files with 718 additions and 57 deletions.
4 changes: 1 addition & 3 deletions crates/rome_js_formatter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -750,9 +750,7 @@ function() {
// use this test check if your snippet prints as you wish, without using a snapshot
fn quick_test() {
let src = r#"
type A =
/*das*/B | C;
type C = B & (C | A) & B;
"#;
let syntax = SourceType::tsx();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::prelude::*;
use crate::utils::should_hug_type;
use rome_formatter::write;
use rome_js_factory::make::token;
use rome_js_syntax::{JsLanguage, TsType, TsUnionTypeVariantList};
use rome_rowan::{AstSeparatedElement, AstSeparatedList};

Expand Down
72 changes: 32 additions & 40 deletions crates/rome_js_formatter/src/ts/types/union_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use rome_js_syntax::{JsSyntaxNode, TsUnionTypeFields};
pub struct FormatTsUnionType;

impl FormatNodeRule<TsUnionType> for FormatTsUnionType {
// [Prettier applies]: https://github.com/prettier/prettier/blob/cd3e530c2e51fb8296c0fb7738a9afdd3a3a4410/src/language-js/print/type-annotation.js#L123-L202
fn fmt_fields(&self, node: &TsUnionType, f: &mut JsFormatter) -> FormatResult<()> {
let TsUnionTypeFields {
leading_separator_token,
Expand Down Expand Up @@ -54,16 +55,11 @@ impl FormatNodeRule<TsUnionType> for FormatTsUnionType {
}
};

let body = format_with(|f| {
let types = format_with(|f| {
write!(
f,
[
FormatTypeSetLeadingSeparator {
// stange comment
// type A = [
// /*lol*/
// A | B,
// ]
new_line: should_indent && !has_leading_own_line_comment,
separator: JsSyntaxKind::PIPE,
leading_separator: leading_separator_token.as_ref()
Expand All @@ -73,41 +69,37 @@ impl FormatNodeRule<TsUnionType> for FormatTsUnionType {
)
});

// we add parentheses if union is in intersaction
//
if node.needs_parentheses() {
return write!(f, [group(&format_args![indent(&body), soft_line_break()])]);
}

//rename
let is_tuple_with_args = node
.parent::<TsTupleTypeElementList>()
.map_or(false, |tuple| tuple.len() > 1);
let content = format_with(|f| {
if node.needs_parentheses() {
return write!(f, [indent(&types), soft_line_break()]);
}

let is_inside_complex_tuple_type = node
.parent::<TsTupleTypeElementList>()
.map_or(false, |tuple| tuple.len() > 1);

if is_inside_complex_tuple_type {
write!(
f,
[
indent(&format_args![
if_group_breaks(&format_args![text("("), soft_line_break()]),
types
]),
soft_line_break(),
if_group_breaks(&text(")"))
]
)
} else {
if should_indent {
write!(f, [&indent(&types)])
} else {
write!(f, [&types])
}
}
});

if is_tuple_with_args {
write!(
f,
[group(&format_args![
indent(&format_args![
if_group_breaks(&format_args![text("("), soft_line_break()]),
body
]),
soft_line_break(),
if_group_breaks(&text(")"))
])]
)
} else {
write![
f,
[group(&format_with(|f| {
if should_indent {
write!(f, [&indent(&body)])
} else {
write!(f, [&body])
}
}))]
]
}
write!(f, [group(&content)])
}

fn needs_parentheses(&self, item: &TsUnionType) -> bool {
Expand Down
223 changes: 218 additions & 5 deletions crates/rome_js_formatter/tests/specs/ts/type/union_type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ type ShortUnion =
| A
| B


type LongUnion = A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

type Comments =
Expand All @@ -12,22 +11,236 @@ type Comments =
A | B /*
trailing type */

type A = [
/*leading comment with new line*/
A | B,
];

type RemoveLeadingSeparatorIfNotBreak = /*a*/ | /*b*/ A | B;

type BreakLongTypeAddedLeadingSeparator = BBBBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDDDDDDDDD;
type BreakLongTypeWithLeadingComment = /*leading comment*/ BBBBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDDDDDDDDD;

<B | C | D> someLongLongObject.longlongmember;

<BBBBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDDDDDDDDD> someLongLongObject.longlongmember;
(<BBBBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDDDDDDDDD> someLongLongObject.longlongmember) += 1

type FunctionTypeWithReturnUnion = () => /*1*/|/*2*/ A | B | C;
type FunctionTypeWithReturnUnion1 = () => /*1*/|/*2*/ A | B | C;

type FunctionTypeWithReturnUnion = () => BBBBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDDDDDDDDD;
type FunctionTypeWithReturnUnion2 = () => BBBBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDDDDDDDDD;

type InlineType = TypeName | null | void;
type InlineTypeWithLongName = TypeNameTypeNameTypeNameTypeNameTypeNameTypeNameTypeName | null | void;

type TypeWithTypleInside = [
type TypeWithTypleInsideShort = [
A | [A, B, C] | C,
A | [A, B, C] | C,
];

type TypeWithTypleInsideLong = [
AAAAAAAAAAAAAAAAA | [AAAAAAAAAAAAAAAAA, BBBBBBBBBBBB, CCCCCCCCCCCCC] | CCCCCCCCCCCCCCCCCCCC,
AAAAAAAAAAAAAAAAA | [AAAAAAAAAAAAAAAAA, BBBBBBBBBBBB, CCCCCCCCCCCCC] | CCCCCCCCCCCCCCCCCCCC,
]
];

type TypeWithUnionInsideIntersactionAddParenthesesShort = B & (C | A) & D;

type TypeWithUnionInsideIntersactionAddParenthesesLong = BBBBBBBBBBBB & (CCCCCCCCCCCCC | AAAAAAAAAAAAAAAAA) & DDDDDDDDDDDDDDDDDDDDDDDDDDDDD;

const fooo: SomeThingWithShortMappedType<{
[P in A | B | C | string]: number;
}> = {};

const fooo: SomeThingWithLongMappedType<{
[P in AAAAAAAAAAAAAAAAA | BBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDDDDDDDDD]: number;
}> = {};

export type A =
| aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
| bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;

export type B =
| aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
| bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;

export type C =
| aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
| bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;

export type D =
| aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
| bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;

export type Multi = (string | number)[];

function f(): string | number {}

var x: string | number;
var y: string | number;

class Foo<T extends string | number> {}

interface Interface {
i: (X | Y) & Z;
j: Partial<X | Y>;
}

type State = {
sharedProperty: 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
)[];

const foo2: (
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
)[] = [];

const foo3: keyof (
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
) = bar;

const foo4:
| foo
| (
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
) = bar;

let a1: C;
let a2: 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 a10: /*1*/ /*2*/ C;
let a11: /*1*/ /*2*/ C;

let aa1: /*1*/ /*2*/ C | D;
let aa2: /*1*/ /*2*/ C | /*3*/ D;
let aa3: /*1*/ /*2*/ C | /*3*/ D /*4*/;

type A1 = C;
type A2 = 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 A10 = /*1*/ /*2*/ 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 Ctor = (new () => X) | Y;

type A = [AAAAAAAAAAAAAAAAAAAAAA | BBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDD]

type B = [
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
]

type B1 = [
(
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
)
]

type C = [
| [AAAAAAAAAAAAAAAAAAAAAA | BBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDD]
| [AAAAAAAAAAAAAAAAAAAAAA | BBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDD]
]

type D = [
(AAAAAAAAAAAAAAAAAAAAAA | BBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDD),
(AAAAAAAAAAAAAAAAAAAAAA | BBBBBBBBBBBBBBBBBBBBBB | CCCCCCCCCCCCCCCCCCCCCC | DDDDDDDDDDDDDDDDDDDDDD)
]

type D1 = [
(
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
),
(
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
)
]

type D2 = [
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD,
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD
]

type E = [ AA | BB, AA | BB ]

type F = [
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
| CCCCCCCCCCCCCCCCCCCCCC
| DDDDDDDDDDDDDDDDDDDDDD,
| AAAAAAAAAAAAAAAAAAAAAA
| BBBBBBBBBBBBBBBBBBBBBB
]

type GetChatsSagaEffects =
| CallEffect
| PutEffect<
| GetUsersRequestedAction
| GetChatsSucceededAction
| GetChatsFailedAction
| GetChatsStartedAction
>
| SelectEffect

//https://github.com/prettier/prettier/issues/13153
type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =
| Fooo1000
| Baz2000
| BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
Loading

0 comments on commit 1aa9365

Please sign in to comment.