From d528ffc5e4627e547f0b3757c38b7b295dc1ff76 Mon Sep 17 00:00:00 2001 From: Denis Bezrukov <6227442+denbezrukov@users.noreply.github.com> Date: Sat, 29 Apr 2023 16:35:24 +0300 Subject: [PATCH] feat(rome_js_parser): EcmaScript @decorators #4252 --- crates/rome_js_formatter/src/comments.rs | 35 ++++++++++++++-- crates/rome_js_formatter/tests/quick_test.rs | 8 ++-- .../decorator-auto-accessors/comments.js.snap | 41 +++++++++++++++++++ .../tests/specs/ts/decoartors.ts.snap | 24 ++++------- 4 files changed, 84 insertions(+), 24 deletions(-) create mode 100644 crates/rome_js_formatter/tests/specs/prettier/js/decorator-auto-accessors/comments.js.snap diff --git a/crates/rome_js_formatter/src/comments.rs b/crates/rome_js_formatter/src/comments.rs index c08535e2b81..777a8036bb0 100644 --- a/crates/rome_js_formatter/src/comments.rs +++ b/crates/rome_js_formatter/src/comments.rs @@ -11,10 +11,11 @@ use rome_formatter::{ use rome_js_syntax::suppression::parse_suppression_comment; use rome_js_syntax::JsSyntaxKind::JS_EXPORT; use rome_js_syntax::{ - AnyJsClass, AnyJsName, AnyJsRoot, AnyJsStatement, JsArrayHole, JsArrowFunctionExpression, - JsBlockStatement, JsCallArguments, JsCatchClause, JsEmptyStatement, JsFinallyClause, - JsFormalParameter, JsFunctionBody, JsIdentifierExpression, JsIfStatement, JsLanguage, - JsSyntaxKind, JsSyntaxNode, JsVariableDeclarator, JsWhileStatement, TsInterfaceDeclaration, + AnyJsClass, AnyJsName, AnyJsPropertyModifier, AnyJsRoot, AnyJsStatement, JsArrayHole, + JsArrowFunctionExpression, JsBlockStatement, JsCallArguments, JsCatchClause, JsEmptyStatement, + JsFinallyClause, JsFormalParameter, JsFunctionBody, JsIdentifierExpression, JsIfStatement, + JsLanguage, JsSyntaxKind, JsSyntaxNode, JsVariableDeclarator, JsWhileStatement, + TsInterfaceDeclaration, }; use rome_rowan::{AstNode, SyntaxNodeOptionExt, SyntaxTriviaPieceComments, TextLen}; @@ -166,6 +167,7 @@ impl CommentStyle for JsCommentStyle { .or_else(handle_try_comment) .or_else(handle_class_comment) .or_else(handle_method_comment) + .or_else(handle_property_comments) .or_else(handle_for_comment) .or_else(handle_root_comments) .or_else(handle_array_hole_comment) @@ -184,6 +186,7 @@ impl CommentStyle for JsCommentStyle { .or_else(handle_try_comment) .or_else(handle_class_comment) .or_else(handle_method_comment) + .or_else(handle_property_comments) .or_else(handle_for_comment) .or_else(handle_root_comments) .or_else(handle_parameter_comment) @@ -508,6 +511,30 @@ fn handle_method_comment(comment: DecoratedComment) -> CommentPlacem CommentPlacement::Default(comment) } +fn handle_property_comments(comment: DecoratedComment) -> CommentPlacement { + let enclosing = comment.enclosing_node(); + + let is_property = matches!( + enclosing.kind(), + JsSyntaxKind::JS_PROPERTY_OBJECT_MEMBER | JsSyntaxKind::JS_PROPERTY_CLASS_MEMBER + ); + + if !is_property { + return CommentPlacement::Default(comment); + } + + if let (Some(preceding), Some(following)) = (comment.preceding_node(), comment.following_node()) + { + if preceding.kind() == JsSyntaxKind::JS_DECORATOR { + if let Some(modifier) = AnyJsPropertyModifier::cast_ref(following) { + return CommentPlacement::leading(modifier.into_syntax(), comment); + } + } + } + + CommentPlacement::Default(comment) +} + /// Handle a all comments document. /// See `blank.js` fn handle_root_comments(comment: DecoratedComment) -> CommentPlacement { diff --git a/crates/rome_js_formatter/tests/quick_test.rs b/crates/rome_js_formatter/tests/quick_test.rs index 057deb5a01e..6162a02746e 100644 --- a/crates/rome_js_formatter/tests/quick_test.rs +++ b/crates/rome_js_formatter/tests/quick_test.rs @@ -14,11 +14,13 @@ mod language { fn quick_test() { let src = r#" class A { - @dec() - // comment - accessor b; + @dec() + // comment + accessor b; } + + "#; let syntax = SourceType::tsx(); let tree = parse(src, syntax); diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/decorator-auto-accessors/comments.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/decorator-auto-accessors/comments.js.snap new file mode 100644 index 00000000000..25eb7ff0f60 --- /dev/null +++ b/crates/rome_js_formatter/tests/specs/prettier/js/decorator-auto-accessors/comments.js.snap @@ -0,0 +1,41 @@ +--- +source: crates/rome_formatter_test/src/snapshot_builder.rs +info: js/decorator-auto-accessors/comments.js +--- + +# Input + +```js +class A { + @dec() + // comment + accessor b; +} + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Rome +@@ -1,5 +1,4 @@ + class A { +- @dec() +- // comment ++ @dec() // comment + accessor b; + } +``` + +# Output + +```js +class A { + @dec() // comment + accessor b; +} +``` + + diff --git a/crates/rome_js_formatter/tests/specs/ts/decoartors.ts.snap b/crates/rome_js_formatter/tests/specs/ts/decoartors.ts.snap index 774970cf581..485a8a4d444 100644 --- a/crates/rome_js_formatter/tests/specs/ts/decoartors.ts.snap +++ b/crates/rome_js_formatter/tests/specs/ts/decoartors.ts.snap @@ -74,8 +74,7 @@ Semicolons: Always ```ts @sealed class Test { - @readonly - prop: string; + @readonly prop: string; constructor( @param test, @@ -97,17 +96,15 @@ export default class {} export class Test {} // Leading comment before decorator -@test // first decorator // first decorator -class // Leading comment before class -Test2 { +@test // first decorator +// Leading comment before class +class Test2 { /* * Leading multiline comment */ @test /* trailing multiline comment - for decorator */ @anotherDecorator() - - // leading comment + for decorator */ @anotherDecorator() // leading comment prop: string; } ``` @@ -116,13 +113,6 @@ Test2 { ## Unimplemented nodes/tokens -"@sealed" => 0..7 -"\t@readonl" => 21..30 -"\t\t@par" => 62..68 -"\t\t@readon" => 77..86 -"\t\t@aVeryLongDecoratorNameLetsSeeWhatHappensWith" => 104..151 -"@param" => 175..181 -"@param" => 219..225 -"@test // first decorator // first decorator\nclass // Leading c" => 338..400 -"\t@test /* trailing multiline comment\n\t for decorator */ @anotherDecorator(" => 468..542 +"@param" => 174..180 +"@param" => 218..224