feature(rome_js_formatter): TS Interface formatting
MODIFY
crates/rome_js_formatter/src/ts/bindings/type_parameters.rs
crates/rome_js_formatter/src/ts/bindings/type_parameters.rs
use crate::prelude::*;
-use rome_formatter::write;
+use rome_formatter::{write, FormatRuleWithOptions, GroupId};
use rome_js_syntax::{TsTypeParameters, TsTypeParametersFields};
#[derive(Debug, Clone, Default)]
-pub struct FormatTsTypeParameters;
+pub struct FormatTsTypeParameters {
+ group_id: Option<GroupId>,
+}
+
+impl FormatRuleWithOptions<TsTypeParameters> for FormatTsTypeParameters {
+ type Options = Option<GroupId>;
+
+ fn with_options(mut self, options: Self::Options) -> Self {
+ self.group_id = options;
+ self
+ }
+}
impl FormatNodeRule<TsTypeParameters> for FormatTsTypeParameters {
fn fmt_fields(&self, node: &TsTypeParameters, f: &mut JsFormatter) -> FormatResult<()> {
@@ -17,8 +28,8 @@ impl FormatNodeRule<TsTypeParameters> for FormatTsTypeParameters {
write!(
f,
[
- format_delimited(&l_angle_token?, &items.format(), &r_angle_token?,)
- .soft_block_indent()
+ format_delimited(&l_angle_token?, &items.format(), &r_angle_token?)
+ .soft_block_indent_with_group_id(self.group_id)
]
)
}

MODIFY
crates/rome_js_formatter/src/ts/classes/extends_clause.rs
crates/rome_js_formatter/src/ts/classes/extends_clause.rs
use crate::prelude::*;
-use rome_formatter::{format_args, write};
+use rome_formatter::write;
use rome_js_syntax::{TsExtendsClause, TsExtendsClauseFields};
#[derive(Debug, Clone, Default)]
@@ -13,19 +13,13 @@ impl FormatNodeRule<TsExtendsClause> for FormatTsExtendsClause {
types,
} = node.as_fields();
- let extends_token = extends_token.format().memoized();
- let types = types.format().memoized();
-
write!(
f,
- [group_elements(&format_args!(
- if_group_breaks(&block_indent(&format_args![
- &extends_token,
+ [
+ extends_token.format(),
space_token(),
- soft_block_indent(&types)
- ])),
- if_group_fits_on_line(&format_args![&extends_token, space_token(), &types]),
- ))]
+ &indent(&types.format())
+ ]
)
}
}

MODIFY
crates/rome_js_formatter/src/ts/declarations/interface_declaration.rs
crates/rome_js_formatter/src/ts/declarations/interface_declaration.rs
use crate::prelude::*;
-use rome_formatter::write;
+use rome_formatter::{format_args, write};
use rome_js_syntax::{TsInterfaceDeclaration, TsInterfaceDeclarationFields};
#[derive(Debug, Clone, Default)]
@@ -18,25 +18,128 @@ impl FormatNodeRule<TsInterfaceDeclaration> for FormatTsInterfaceDeclaration {
r_curly_token,
} = node.as_fields();
- write![
+ let l_curly_token = l_curly_token?;
+ let r_curly_token = r_curly_token?;
+ let id = id?;
+ let type_parameters = type_parameters;
+
+ let type_parameter_group = type_parameters
+ .as_ref()
+ .map(|_| f.group_id("type-parameters"));
+
+ let format_id = format_with(|f| {
+ write!(f, [id.format(),])?;
+
+ if let Some(type_parameters) = &type_parameters {
+ write!(
+ f,
+ [type_parameters.format().with_options(type_parameter_group)]
+ )?;
+ }
+
+ Ok(())
+ });
+
+ let should_indent_extends_only = type_parameters
+ .as_ref()
+ .map_or(false, |params| !params.syntax().has_trailing_comments());
+
+ let format_extends = format_with(|f| {
+ if let Some(extends_clause) = &extends_clause {
+ if should_indent_extends_only {
+ write!(
f,
[
- interface_token.format(),
- space_token(),
- id.format(),
- type_parameters.format(),
- space_token(),
+ if_group_breaks(&space_token()).with_group_id(type_parameter_group),
+ if_group_fits_on_line(&soft_line_break_or_space())
+ .with_group_id(type_parameter_group),
]
- ]?;
+ )?;
+ } else {
+ write!(f, [soft_line_break_or_space()])?;
+ }
- if let Some(extends_clause) = extends_clause {
write!(f, [extends_clause.format(), space_token()])?;
}
+ Ok(())
+ });
+
+ write![f, [interface_token.format(), space_token()]]?;
+
+ // Manually handle the trailing comments and push them into the members block
+ // to prevent that a comment gets formatted on the same line as the opening `{`
+ let last_node = match (&type_parameters, &extends_clause) {
+ (_, Some(extends_clause)) => extends_clause.syntax(),
+ (Some(type_parameters), None) => type_parameters.syntax(),
+ (None, None) => id.syntax(),
+ };
+
+ let last_token = last_node.last_token();
+ let mut has_trailing_comments = false;
+
+ if let Some(last_token) = &last_token {
+ for comment in last_token
+ .trailing_trivia()
+ .pieces()
+ .filter_map(|piece| piece.as_comments())
+ {
+ has_trailing_comments = true;
+ f.state_mut().mark_comment_as_formatted(&comment);
+ }
+ }
+
+ let id_has_trailing_comments = id.syntax().has_trailing_comments();
+ if id_has_trailing_comments || extends_clause.is_some() {
+ if should_indent_extends_only {
+ write!(
+ f,
+ [group_elements(&format_args!(
+ format_id,
+ indent(&format_extends)
+ ))]
+ )?;
+ } else {
+ write!(
+ f,
+ [group_elements(&indent(&format_args!(
+ format_id,
+ format_extends
+ )))]
+ )?;
+ }
+ } else {
+ write!(f, [format_id, format_extends])?;
+ }
+
write!(
f,
[
- format_delimited(&l_curly_token?, &members.format(), &r_curly_token?,)
+ space_token(),
+ format_delimited(
+ &l_curly_token,
+ &format_args![
+ format_with(|f| {
+ // Write the manual handled comments
+ if let Some(last_token) = &last_token {
+ if has_trailing_comments {
+ write!(
+ f,
+ [
+ format_trailing_trivia(last_token)
+ .skip_formatted_check(),
+ hard_line_break()
+ ]
+ )?;
+ }
+ }
+
+ Ok(())
+ }),
+ members.format()
+ ],
+ &r_curly_token
+ )
.block_indent()
]
)

MODIFY
crates/rome_js_formatter/tests/specs/prettier/typescript/interface/comments-generic.ts.snap
crates/rome_js_formatter/tests/specs/prettier/typescript/interface/comments-generic.ts.snap
@@ -43,35 +43,33 @@ interface ReallyReallyLongName<
TypeArgumentNumberOne,
TypeArgumentNumberTwo,
TypeArgumentNumberThree,
-> extends BaseInterface {} // 1
+ > // 1
+ extends BaseInterface {}
interface ReallyReallyLongName2<
TypeArgumentNumberOne,
TypeArgumentNumberTwo,
TypeArgumentNumberThree,
->
- // 1
+ > // 1
// 2
- extends
- BaseInterface
-{}
+ extends BaseInterface {}
interface ReallyReallyLongName3<
TypeArgumentNumberOne,
TypeArgumentNumberTwo,
TypeArgumentNumberThree,
->
- // 1
+ > // 1
// 2
- extends
- BaseInterface // 3
-{}
+ extends BaseInterface {
+ // 3
+}
interface Foo<
FOOOOOOOOOOOOOOOOOOOOOOOOOO,
FOOOOOOOOOOOOOOOOOOOOOOOOOO,
FOOOOOOOOOOOOOOOOOOOOOOOOOO,
-> extends Foo {} // comments
+ > // comments
+ extends Foo {}
```

MODIFY
crates/rome_js_formatter/tests/specs/prettier/typescript/interface/generic.ts.snap
crates/rome_js_formatter/tests/specs/prettier/typescript/interface/generic.ts.snap
@@ -18,9 +18,7 @@ interface Foo<
# Output
```js
interface Foo<FOOOOOOOOOOOOOOOOOOOOOOOOOO, FOOOOOOOOOOOOOOOOOOOOOOO>
- extends
- Foo
-{}
+ extends Foo {}
interface Foo<
FOOOOOOOOOOOOOOOOOOOOOOOOOO,

MODIFY
crates/rome_js_formatter/tests/specs/prettier/typescript/interface/long-extends.ts.snap
crates/rome_js_formatter/tests/specs/prettier/typescript/interface/long-extends.ts.snap
@@ -33,34 +33,26 @@ export interface I extends A, B, C {
}
export interface ThirdVeryLongAndBoringInterfaceName
- extends
- ALongAndBoringInterfaceName
-{
+ extends ALongAndBoringInterfaceName {
c: string;
}
export interface ThirdVeryLongAndBoringInterfaceName
- extends
- ALongAndBoringInterfaceName,
- AnotherLongAndBoringInterfaceName
-{
+ extends ALongAndBoringInterfaceName,
+ AnotherLongAndBoringInterfaceName {
c: string;
}
export interface ThirdVeryLongAndBoringInterfaceName
- extends
- AVeryLongAndBoringInterfaceName,
- AnotherVeryLongAndBoringInterfaceName
-{
+ extends AVeryLongAndBoringInterfaceName,
+ AnotherVeryLongAndBoringInterfaceName {
c: string;
}
export interface ThirdVeryLongAndBoringInterfaceName
- extends
- A_AVeryLongAndBoringInterfaceName,
+ extends A_AVeryLongAndBoringInterfaceName,
B_AVeryLongAndBoringInterfaceName,
- C_AVeryLongAndBoringInterfaceName
-{
+ C_AVeryLongAndBoringInterfaceName {
c: string;
}

MODIFY
crates/rome_js_formatter/tests/specs/prettier/typescript/interface2/break.ts
crates/rome_js_formatter/tests/specs/prettier/typescript/interface2/break.ts
export interface Environment1 extends GenericEnvironment<
SomeType,
AnotherType,
- YetAnotherType,
+ YetAnotherType
> {
m(): void;
};
@@ -12,7 +12,7 @@ export class Environment2 extends GenericEnvironment<
DifferentType1,
DifferentType2,
DifferentType3,
- DifferentType4,
+ DifferentType4
> {
m() {};
};

MODIFY
crates/rome_js_formatter/tests/specs/prettier/typescript/interface2/comments-declare.ts.snap
crates/rome_js_formatter/tests/specs/prettier/typescript/interface2/comments-declare.ts.snap
@@ -12,11 +12,9 @@ declare interface a // 1
# Output
```js
-declare interface a
- // 1
- extends
- b // 2
-{
+declare interface a // 1
+ extends b {
+ // 2
foo: boolean;
}

MODIFY
crates/rome_js_formatter/tests/specs/prettier/typescript/interface2/comments.ts.snap
crates/rome_js_formatter/tests/specs/prettier/typescript/interface2/comments.ts.snap
@@ -42,44 +42,39 @@ interface A1 {
foo(): bar;
}
-interface A2 extends Base {
- // comment
+interface A2 // comment
+ extends Base {
foo(): bar;
}
-interface A3
- // comment1
- extends
- Base // comment2
-{
+interface A3 // comment1
+ extends Base {
+ // comment2
foo(): bar;
}
-interface A4
- // comment1
- extends
- Base // comment2
+interface A4 // comment1
+ extends Base
// comment3
{
+ // comment2
foo(): bar;
}
-interface A5
- // comment1
- extends
- Base // comment2
+interface A5 // comment1
+ extends Base
// comment3
{
// comment4
+ // comment2
foo(): bar;
}
-interface A6
- // comment1
- extends
- Base // comment2
+interface A6 // comment1
+ extends Base
// comment3
{
+ // comment2
// comment4
foo(): bar;
}

MODIFY
crates/rome_js_formatter/tests/specs/ts/declaration/interface.ts.snap
crates/rome_js_formatter/tests/specs/ts/declaration/interface.ts.snap
---
source: crates/rome_js_formatter/tests/spec_test.rs
-assertion_line: 242
expression: interface.ts
---
# Input
@@ -35,7 +34,8 @@ Line width: 80
Quote style: Double Quotes
-----
interface A {}
-interface B extends A /** comment **/ {
+interface B extends A {
+ /** comment **/
something: string;
}
@@ -54,12 +54,10 @@ interface C<
// @ts-ignore
interface D
- extends
- B<string, symbol>,
+ extends B<string, symbol>,
F<string, symbol>,
G<string, number, symbol>,
- H<string, number, symbol>
-{
+ H<string, number, symbol> {
something1: string;
something2: string;
something3: string;

feature(rome_js_formatter): TS Interface formatting (#2773)