From ffe4934b0680f7e13c2d113f4f7763d7843b640c Mon Sep 17 00:00:00 2001 From: Denis Bezrukov <6227442+denbezrukov@users.noreply.github.com> Date: Sun, 30 Apr 2023 17:18:11 +0300 Subject: [PATCH] feat(rome_js_parser): EcmaScript @decorators #4252 --- .../js/decorators/member-expression.js.snap | 629 ++---------------- .../prettier/js/decorators/parens.js.snap | 49 +- .../argument-list-preserve-line.ts.snap | 112 ---- .../typescript/decorators/decorators.ts.snap | 32 +- .../decorators/inline-decorators.ts.snap | 59 -- crates/rome_js_parser/src/syntax/class.rs | 3 + crates/rome_js_parser/src/tests.rs | 5 +- .../inline/err/decorator_class_member.rast | 111 +++- .../inline/err/decorator_class_member.ts | 3 + 9 files changed, 161 insertions(+), 842 deletions(-) delete mode 100644 crates/rome_js_formatter/tests/specs/prettier/typescript/decorators/argument-list-preserve-line.ts.snap diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/decorators/member-expression.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/decorators/member-expression.js.snap index 2ec98c44717..9f346cfcf97 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/js/decorators/member-expression.js.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/js/decorators/member-expression.js.snap @@ -65,55 +65,56 @@ info: js/decorators/member-expression.js ```diff --- Prettier +++ Rome -@@ -1,10 +1,10 @@ +@@ -1,54 +1,42 @@ [ class { - @decorators[0] -+ @(decorators[0]) - method() {} +- method() {} ++ @(decorators[0]) method() {} }, class { -- @decorators [0]; -+ @decorators[0] + @decorators [0]; method() {} }, class { -@@ -12,7 +12,7 @@ - method() {} +- @(decorators?.[0]) +- method() {} ++ @(decorators?.[0]) method() {} }, class { - @decorators.at(0) -+ @(decorators.at(0)) - method() {} +- method() {} ++ @(decorators.at(0)) method() {} }, class { -@@ -20,7 +20,7 @@ - method() {} +- @(decorators?.at(0)) +- method() {} ++ @(decorators?.at(0)) method() {} ++ }, ++ class { ++ @(decorators.first) method() {} ++ }, ++ class { ++ @(decorators?.first) method() {} }, class { - @decorators.first -+ @(decorators.first) - method() {} +- method() {} ++ @(decorators[first]) method() {} }, class { -@@ -28,27 +28,23 @@ +- @(decorators?.first) ++ @decorators [first]; method() {} }, class { -+ @(decorators[first]) -+ method() {} -+ }, -+ class { - @decorators[first] - method() {} +- @decorators[first] +- method() {} ++ @(decorators["first"]) method() {} }, ++ @(decorators[first]) class { - @decorators [first]; -+ @(decorators["first"]) -+ method() {} -+ }, -+ @(decorators[first]) -+ class { method() {} }, + @(decorators[0]) @@ -133,8 +134,7 @@ info: js/decorators/member-expression.js - method() {} - } - ), --]; -+] + ]; ``` # Output @@ -142,44 +142,36 @@ info: js/decorators/member-expression.js ```js [ class { - @(decorators[0]) - method() {} + @(decorators[0]) method() {} }, class { - @decorators[0] + @decorators [0]; method() {} }, class { - @(decorators?.[0]) - method() {} + @(decorators?.[0]) method() {} }, class { - @(decorators.at(0)) - method() {} + @(decorators.at(0)) method() {} }, class { - @(decorators?.at(0)) - method() {} + @(decorators?.at(0)) method() {} }, class { - @(decorators.first) - method() {} + @(decorators.first) method() {} }, class { - @(decorators?.first) - method() {} + @(decorators?.first) method() {} }, class { - @(decorators[first]) - method() {} + @(decorators[first]) method() {} }, class { - @decorators[first] + @decorators [first]; method() {} }, class { - @(decorators["first"]) - method() {} + @(decorators["first"]) method() {} }, @(decorators[first]) class { @@ -189,552 +181,7 @@ info: js/decorators/member-expression.js class { method() {} }, -] -``` - -# Errors -``` -member-expression.js:3:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected an identifier, a string literal, a number literal, a private field name, or a computed name but instead found '@' - - 1 │ [ - 2 │ class { - > 3 │ @(decorators[0]) - │ ^ - 4 │ method() {} - 5 │ }, - - i Expected an identifier, a string literal, a number literal, a private field name, or a computed name here - - 1 │ [ - 2 │ class { - > 3 │ @(decorators[0]) - │ ^ - 4 │ method() {} - 5 │ }, - -member-expression.js:4:14 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `{` - - 2 │ class { - 3 │ @(decorators[0]) - > 4 │ method() {} - │ ^ - 5 │ }, - 6 │ class { - - i Remove { - -member-expression.js:5:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `}` - - 3 │ @(decorators[0]) - 4 │ method() {} - > 5 │ }, - │ ^ - 6 │ class { - 7 │ @decorators[0] - - i Remove } - -member-expression.js:7:16 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `[` - - 5 │ }, - 6 │ class { - > 7 │ @decorators[0] - │ ^ - 8 │ method() {} - 9 │ }, - - i Remove [ - -member-expression.js:8:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `method` - - 6 │ class { - 7 │ @decorators[0] - > 8 │ method() {} - │ ^^^^^^ - 9 │ }, - 10 │ class { - - i Remove method - -member-expression.js:8:14 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `{` - - 6 │ class { - 7 │ @decorators[0] - > 8 │ method() {} - │ ^ - 9 │ }, - 10 │ class { - - i Remove { - -member-expression.js:9:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `}` - - 7 │ @decorators[0] - 8 │ method() {} - > 9 │ }, - │ ^ - 10 │ class { - 11 │ @(decorators?.[0]) - - i Remove } - -member-expression.js:11:6 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `(` - - 9 │ }, - 10 │ class { - > 11 │ @(decorators?.[0]) - │ ^ - 12 │ method() {} - 13 │ }, - - i Remove ( - -member-expression.js:12:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `method` - - 10 │ class { - 11 │ @(decorators?.[0]) - > 12 │ method() {} - │ ^^^^^^ - 13 │ }, - 14 │ class { - - i Remove method - -member-expression.js:12:14 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `{` - - 10 │ class { - 11 │ @(decorators?.[0]) - > 12 │ method() {} - │ ^ - 13 │ }, - 14 │ class { - - i Remove { - -member-expression.js:13:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `}` - - 11 │ @(decorators?.[0]) - 12 │ method() {} - > 13 │ }, - │ ^ - 14 │ class { - 15 │ @(decorators.at(0)) - - i Remove } - -member-expression.js:15:6 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `(` - - 13 │ }, - 14 │ class { - > 15 │ @(decorators.at(0)) - │ ^ - 16 │ method() {} - 17 │ }, - - i Remove ( - -member-expression.js:16:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `method` - - 14 │ class { - 15 │ @(decorators.at(0)) - > 16 │ method() {} - │ ^^^^^^ - 17 │ }, - 18 │ class { - - i Remove method - -member-expression.js:16:14 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `{` - - 14 │ class { - 15 │ @(decorators.at(0)) - > 16 │ method() {} - │ ^ - 17 │ }, - 18 │ class { - - i Remove { - -member-expression.js:17:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `}` - - 15 │ @(decorators.at(0)) - 16 │ method() {} - > 17 │ }, - │ ^ - 18 │ class { - 19 │ @(decorators?.at(0)) - - i Remove } - -member-expression.js:19:6 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `(` - - 17 │ }, - 18 │ class { - > 19 │ @(decorators?.at(0)) - │ ^ - 20 │ method() {} - 21 │ }, - - i Remove ( - -member-expression.js:20:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `method` - - 18 │ class { - 19 │ @(decorators?.at(0)) - > 20 │ method() {} - │ ^^^^^^ - 21 │ }, - 22 │ class { - - i Remove method - -member-expression.js:20:14 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `{` - - 18 │ class { - 19 │ @(decorators?.at(0)) - > 20 │ method() {} - │ ^ - 21 │ }, - 22 │ class { - - i Remove { - -member-expression.js:21:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `}` - - 19 │ @(decorators?.at(0)) - 20 │ method() {} - > 21 │ }, - │ ^ - 22 │ class { - 23 │ @(decorators.first) - - i Remove } - -member-expression.js:23:6 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `(` - - 21 │ }, - 22 │ class { - > 23 │ @(decorators.first) - │ ^ - 24 │ method() {} - 25 │ }, - - i Remove ( - -member-expression.js:24:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `method` - - 22 │ class { - 23 │ @(decorators.first) - > 24 │ method() {} - │ ^^^^^^ - 25 │ }, - 26 │ class { - - i Remove method - -member-expression.js:24:14 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `{` - - 22 │ class { - 23 │ @(decorators.first) - > 24 │ method() {} - │ ^ - 25 │ }, - 26 │ class { - - i Remove { - -member-expression.js:25:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `}` - - 23 │ @(decorators.first) - 24 │ method() {} - > 25 │ }, - │ ^ - 26 │ class { - 27 │ @(decorators?.first) - - i Remove } - -member-expression.js:27:6 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `(` - - 25 │ }, - 26 │ class { - > 27 │ @(decorators?.first) - │ ^ - 28 │ method() {} - 29 │ }, - - i Remove ( - -member-expression.js:28:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `method` - - 26 │ class { - 27 │ @(decorators?.first) - > 28 │ method() {} - │ ^^^^^^ - 29 │ }, - 30 │ class { - - i Remove method - -member-expression.js:28:14 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `{` - - 26 │ class { - 27 │ @(decorators?.first) - > 28 │ method() {} - │ ^ - 29 │ }, - 30 │ class { - - i Remove { - -member-expression.js:29:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `}` - - 27 │ @(decorators?.first) - 28 │ method() {} - > 29 │ }, - │ ^ - 30 │ class { - 31 │ @(decorators[first]) - - i Remove } - -member-expression.js:31:6 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `(` - - 29 │ }, - 30 │ class { - > 31 │ @(decorators[first]) - │ ^ - 32 │ method() {} - 33 │ }, - - i Remove ( - -member-expression.js:32:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `method` - - 30 │ class { - 31 │ @(decorators[first]) - > 32 │ method() {} - │ ^^^^^^ - 33 │ }, - 34 │ class { - - i Remove method - -member-expression.js:32:14 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `{` - - 30 │ class { - 31 │ @(decorators[first]) - > 32 │ method() {} - │ ^ - 33 │ }, - 34 │ class { - - i Remove { - -member-expression.js:33:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `}` - - 31 │ @(decorators[first]) - 32 │ method() {} - > 33 │ }, - │ ^ - 34 │ class { - 35 │ @decorators[first] - - i Remove } - -member-expression.js:35:16 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `[` - - 33 │ }, - 34 │ class { - > 35 │ @decorators[first] - │ ^ - 36 │ method() {} - 37 │ }, - - i Remove [ - -member-expression.js:36:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `method` - - 34 │ class { - 35 │ @decorators[first] - > 36 │ method() {} - │ ^^^^^^ - 37 │ }, - 38 │ class { - - i Remove method - -member-expression.js:36:14 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `{` - - 34 │ class { - 35 │ @decorators[first] - > 36 │ method() {} - │ ^ - 37 │ }, - 38 │ class { - - i Remove { - -member-expression.js:37:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `}` - - 35 │ @decorators[first] - 36 │ method() {} - > 37 │ }, - │ ^ - 38 │ class { - 39 │ @(decorators["first"]) - - i Remove } - -member-expression.js:39:6 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `(` - - 37 │ }, - 38 │ class { - > 39 │ @(decorators["first"]) - │ ^ - 40 │ method() {} - 41 │ }, - - i Remove ( - -member-expression.js:40:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `method` - - 38 │ class { - 39 │ @(decorators["first"]) - > 40 │ method() {} - │ ^^^^^^ - 41 │ }, - 42 │ @(decorators[first]) - - i Remove method - -member-expression.js:40:14 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `{` - - 38 │ class { - 39 │ @(decorators["first"]) - > 40 │ method() {} - │ ^ - 41 │ }, - 42 │ @(decorators[first]) - - i Remove { - -member-expression.js:41:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `}` - - 39 │ @(decorators["first"]) - 40 │ method() {} - > 41 │ }, - │ ^ - 42 │ @(decorators[first]) - 43 │ class { - - i Remove } - -member-expression.js:42:4 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `(` - - 40 │ method() {} - 41 │ }, - > 42 │ @(decorators[first]) - │ ^ - 43 │ class { - 44 │ method() {} - - i Remove ( - -member-expression.js:43:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `class` - - 41 │ }, - 42 │ @(decorators[first]) - > 43 │ class { - │ ^^^^^ - 44 │ method() {} - 45 │ }, - - i Remove class - - +]; ``` diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/decorators/parens.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/decorators/parens.js.snap index c89f4d4e250..6d8f478c33b 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/js/decorators/parens.js.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/js/decorators/parens.js.snap @@ -19,12 +19,11 @@ class X { ```diff --- Prettier +++ Rome -@@ -1,4 +1,4 @@ +@@ -1,4 +1,3 @@ class X { - @(computed().volatile()) - x; -+@(computed().volatile()) -+x; ++ @(computed().volatile()) x; } ``` @@ -32,50 +31,8 @@ class X { ```js class X { -@(computed().volatile()) -x; + @(computed().volatile()) x; } ``` -# Errors -``` -parens.js:2:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected an identifier, a string literal, a number literal, a private field name, or a computed name but instead found '@' - - 1 │ class X { - > 2 │ @(computed().volatile()) - │ ^ - 3 │ x - 4 │ } - - i Expected an identifier, a string literal, a number literal, a private field name, or a computed name here - - 1 │ class X { - > 2 │ @(computed().volatile()) - │ ^ - 3 │ x - 4 │ } - -parens.js:4:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected a statement but instead found '}' - - 2 │ @(computed().volatile()) - 3 │ x - > 4 │ } - │ ^ - 5 │ - - i Expected a statement here - - 2 │ @(computed().volatile()) - 3 │ x - > 4 │ } - │ ^ - 5 │ - - -``` - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/decorators/argument-list-preserve-line.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/decorators/argument-list-preserve-line.ts.snap deleted file mode 100644 index ba011291f32..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/decorators/argument-list-preserve-line.ts.snap +++ /dev/null @@ -1,112 +0,0 @@ ---- -source: crates/rome_formatter_test/src/snapshot_builder.rs -info: typescript/decorators/argument-list-preserve-line.ts ---- - -# Input - -```ts -class Foo { - constructor( - @inject(Bar) - private readonly bar: IBar, - - @inject(MyProcessor) - private readonly myProcessor: IMyProcessor, - - @inject(InjectionTypes.AnotherThing) - - private readonly anotherThing: IAnotherThing | undefined, - ) { } -} - -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,12 +1,13 @@ - class Foo { - constructor( - @inject(Bar) -- private readonly bar: IBar, -+ private readonly bar: IBar, - - @inject(MyProcessor) -- private readonly myProcessor: IMyProcessor, -+ private readonly myProcessor: IMyProcessor, - - @inject(InjectionTypes.AnotherThing) -- private readonly anotherThing: IAnotherThing | undefined, -+ -+ private readonly anotherThing: IAnotherThing | undefined, - ) {} - } -``` - -# Output - -```ts -class Foo { - constructor( - @inject(Bar) - private readonly bar: IBar, - - @inject(MyProcessor) - private readonly myProcessor: IMyProcessor, - - @inject(InjectionTypes.AnotherThing) - - private readonly anotherThing: IAnotherThing | undefined, - ) {} -} -``` - -# Errors -``` -argument-list-preserve-line.ts:3:9 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Decorators are not valid here. - - 1 │ class Foo { - 2 │ constructor( - > 3 │ @inject(Bar) - │ ^^^^^^^^^^^^ - 4 │ private readonly bar: IBar, - 5 │ - - i Decorators are only valid on class declarations, class expressions, and class methods. - -argument-list-preserve-line.ts:6:9 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Decorators are not valid here. - - 4 │ private readonly bar: IBar, - 5 │ - > 6 │ @inject(MyProcessor) - │ ^^^^^^^^^^^^^^^^^^^^ - 7 │ private readonly myProcessor: IMyProcessor, - 8 │ - - i Decorators are only valid on class declarations, class expressions, and class methods. - -argument-list-preserve-line.ts:9:9 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Decorators are not valid here. - - 7 │ private readonly myProcessor: IMyProcessor, - 8 │ - > 9 │ @inject(InjectionTypes.AnotherThing) - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 10 │ - 11 │ private readonly anotherThing: IAnotherThing | undefined, - - i Decorators are only valid on class declarations, class expressions, and class methods. - - -``` - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/decorators/decorators.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/decorators/decorators.ts.snap index 1915050b253..48844a827ff 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/decorators/decorators.ts.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/typescript/decorators/decorators.ts.snap @@ -92,17 +92,16 @@ class Class6 { ```diff --- Prettier +++ Rome -@@ -1,5 +1,8 @@ +@@ -1,5 +1,7 @@ export class TestTextFileService { - constructor(@ILifecycleService lifecycleService) {} + constructor( -+ @ILifecycleService lifecycleService, -+ ) { -+ } ++ @ILifecycleService lifecycleService, ++ ) {} } @commonEditorContribution -@@ -50,12 +53,24 @@ +@@ -50,12 +52,24 @@ } class Class5 { @@ -139,9 +138,8 @@ class Class6 { ```ts export class TestTextFileService { constructor( - @ILifecycleService lifecycleService, - ) { - } + @ILifecycleService lifecycleService, + ) {} } @commonEditorContribution @@ -215,22 +213,4 @@ class Class6 { } ``` -# Errors -``` -decorators.ts:3:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Decorators are not valid here. - - 1 │ export class TestTextFileService { - 2 │ constructor( - > 3 │ @ILifecycleService lifecycleService, - │ ^^^^^^^^^^^^^^^^^^ - 4 │ ) { - 5 │ } - - i Decorators are only valid on class declarations, class expressions, and class methods. - - -``` - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/decorators/inline-decorators.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/decorators/inline-decorators.ts.snap index e4ce3729e0c..2adab07208a 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/decorators/inline-decorators.ts.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/typescript/decorators/inline-decorators.ts.snap @@ -165,63 +165,4 @@ class MyContainerComponent { } ``` -# Errors -``` -inline-decorators.ts:32:9 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Decorators are not valid here. - - 31 │ constructor ( - > 32 │ @d1 private x: number, - │ ^^^ - 33 │ @d2(foo) private y: number, - 34 │ @d3('foo') private z: number, - - i Decorators are only valid on class declarations, class expressions, and class methods. - -inline-decorators.ts:33:9 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Decorators are not valid here. - - 31 │ constructor ( - 32 │ @d1 private x: number, - > 33 │ @d2(foo) private y: number, - │ ^^^^^^^^ - 34 │ @d3('foo') private z: number, - 35 │ @d4({ - - i Decorators are only valid on class declarations, class expressions, and class methods. - -inline-decorators.ts:34:9 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Decorators are not valid here. - - 32 │ @d1 private x: number, - 33 │ @d2(foo) private y: number, - > 34 │ @d3('foo') private z: number, - │ ^^^^^^^^^^ - 35 │ @d4({ - 36 │ x: string - - i Decorators are only valid on class declarations, class expressions, and class methods. - -inline-decorators.ts:35:9 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Decorators are not valid here. - - 33 │ @d2(foo) private y: number, - 34 │ @d3('foo') private z: number, - > 35 │ @d4({ - │ ^^^^^ - > 36 │ x: string - > 37 │ }) private a: string, - │ ^^ - 38 │ ) {} - 39 │ } - - i Decorators are only valid on class declarations, class expressions, and class methods. - - -``` - diff --git a/crates/rome_js_parser/src/syntax/class.rs b/crates/rome_js_parser/src/syntax/class.rs index f6b61edcd1f..54a044b13ab 100644 --- a/crates/rome_js_parser/src/syntax/class.rs +++ b/crates/rome_js_parser/src/syntax/class.rs @@ -2189,6 +2189,9 @@ impl ClassMemberModifiers { // abstract class Qux { // @dec declare static foo: string; // } + // class Bar { + // @dec declare foo = '123'; + // } return Some(decorators_not_allowed(p, modifier.as_text_range())); } else if member_kind == TS_INDEX_SIGNATURE_CLASS_MEMBER && !matches!(modifier.kind, ModifierKind::Static | ModifierKind::Readonly) diff --git a/crates/rome_js_parser/src/tests.rs b/crates/rome_js_parser/src/tests.rs index e03cc2ce7cf..da4cc57a2d0 100644 --- a/crates/rome_js_parser/src/tests.rs +++ b/crates/rome_js_parser/src/tests.rs @@ -393,10 +393,9 @@ fn diagnostics_print_correctly() { #[test] pub fn quick_test() { let code = r#" -class C { - constructor(@foo readonly x: number) {} +class Foo { + @decorator declare a; } - "#; let root = parse(code, SourceType::ts()); let syntax = root.syntax(); diff --git a/crates/rome_js_parser/test_data/inline/err/decorator_class_member.rast b/crates/rome_js_parser/test_data/inline/err/decorator_class_member.rast index e20b5a57b5c..3018b5cca57 100644 --- a/crates/rome_js_parser/test_data/inline/err/decorator_class_member.rast +++ b/crates/rome_js_parser/test_data/inline/err/decorator_class_member.rast @@ -402,14 +402,58 @@ JsModule { ], r_curly_token: R_CURLY@368..370 "}" [Newline("\n")] [], }, + JsClassDeclaration { + decorators: JsDecoratorList [], + abstract_token: missing (optional), + class_token: CLASS_KW@370..377 "class" [Newline("\n")] [Whitespace(" ")], + id: JsIdentifierBinding { + name_token: IDENT@377..381 "Bar" [] [Whitespace(" ")], + }, + type_parameters: missing (optional), + extends_clause: missing (optional), + implements_clause: missing (optional), + l_curly_token: L_CURLY@381..382 "{" [] [], + members: JsClassMemberList [ + JsBogusMember { + items: [ + JsBogus { + items: [ + JsDecorator { + at_token: AT@382..387 "@" [Newline("\n"), Whitespace(" ")] [], + expression: JsIdentifierExpression { + name: JsReferenceIdentifier { + value_token: IDENT@387..391 "dec" [] [Whitespace(" ")], + }, + }, + }, + TsDeclareModifier { + modifier_token: DECLARE_KW@391..399 "declare" [] [Whitespace(" ")], + }, + ], + }, + JsLiteralMemberName { + value: IDENT@399..403 "foo" [] [Whitespace(" ")], + }, + JsInitializerClause { + eq_token: EQ@403..405 "=" [] [Whitespace(" ")], + expression: JsStringLiteralExpression { + value_token: JS_STRING_LITERAL@405..410 "'123'" [] [], + }, + }, + SEMICOLON@410..411 ";" [] [], + ], + }, + ], + r_curly_token: R_CURLY@411..413 "}" [Newline("\n")] [], + }, ], - eof_token: EOF@370..371 "" [Newline("\n")] [], + eof_token: EOF@413..414 "" [Newline("\n")] [], } -0: JS_MODULE@0..371 +0: JS_MODULE@0..414 0: (empty) 1: JS_DIRECTIVE_LIST@0..0 - 2: JS_MODULE_ITEM_LIST@0..370 + 2: JS_MODULE_ITEM_LIST@0..413 0: JS_CLASS_DECLARATION@0..81 0: JS_DECORATOR_LIST@0..0 1: (empty) @@ -669,7 +713,35 @@ JsModule { 0: STRING_KW@361..367 "string" [] [] 3: SEMICOLON@367..368 ";" [] [] 9: R_CURLY@368..370 "}" [Newline("\n")] [] - 3: EOF@370..371 "" [Newline("\n")] [] + 5: JS_CLASS_DECLARATION@370..413 + 0: JS_DECORATOR_LIST@370..370 + 1: (empty) + 2: CLASS_KW@370..377 "class" [Newline("\n")] [Whitespace(" ")] + 3: JS_IDENTIFIER_BINDING@377..381 + 0: IDENT@377..381 "Bar" [] [Whitespace(" ")] + 4: (empty) + 5: (empty) + 6: (empty) + 7: L_CURLY@381..382 "{" [] [] + 8: JS_CLASS_MEMBER_LIST@382..411 + 0: JS_BOGUS_MEMBER@382..411 + 0: JS_BOGUS@382..399 + 0: JS_DECORATOR@382..391 + 0: AT@382..387 "@" [Newline("\n"), Whitespace(" ")] [] + 1: JS_IDENTIFIER_EXPRESSION@387..391 + 0: JS_REFERENCE_IDENTIFIER@387..391 + 0: IDENT@387..391 "dec" [] [Whitespace(" ")] + 1: TS_DECLARE_MODIFIER@391..399 + 0: DECLARE_KW@391..399 "declare" [] [Whitespace(" ")] + 1: JS_LITERAL_MEMBER_NAME@399..403 + 0: IDENT@399..403 "foo" [] [Whitespace(" ")] + 2: JS_INITIALIZER_CLAUSE@403..410 + 0: EQ@403..405 "=" [] [Whitespace(" ")] + 1: JS_STRING_LITERAL_EXPRESSION@405..410 + 0: JS_STRING_LITERAL@405..410 "'123'" [] [] + 3: SEMICOLON@410..411 ";" [] [] + 9: R_CURLY@411..413 "}" [Newline("\n")] [] + 3: EOF@413..414 "" [Newline("\n")] [] -- decorator_class_member.ts:2:4 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ @@ -777,7 +849,33 @@ decorator_class_member.ts:20:3 parse ━━━━━━━━━━━━━━ > 20 │ @dec declare static foo: string; │ ^^^^ 21 │ } - 22 │ + 22 │ class Bar { + + i Decorators are only valid on class declarations, class expressions, and class methods. + +-- +decorator_class_member.ts:23:21 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × In ambient contexts, properties with initializers need to be readonly. + + 21 │ } + 22 │ class Bar { + > 23 │ @dec declare foo = '123'; + │ ^^^^^^^ + 24 │ } + 25 │ + +-- +decorator_class_member.ts:23:4 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Decorators are not valid here. + + 21 │ } + 22 │ class Bar { + > 23 │ @dec declare foo = '123'; + │ ^^^^ + 24 │ } + 25 │ i Decorators are only valid on class declarations, class expressions, and class methods. @@ -803,3 +901,6 @@ declare class Baz { abstract class Qux { @dec declare static foo: string; } +class Bar { + @dec declare foo = '123'; +} diff --git a/crates/rome_js_parser/test_data/inline/err/decorator_class_member.ts b/crates/rome_js_parser/test_data/inline/err/decorator_class_member.ts index 912b0f6f07f..84a98713d12 100644 --- a/crates/rome_js_parser/test_data/inline/err/decorator_class_member.ts +++ b/crates/rome_js_parser/test_data/inline/err/decorator_class_member.ts @@ -19,3 +19,6 @@ declare class Baz { abstract class Qux { @dec declare static foo: string; } +class Bar { + @dec declare foo = '123'; +}