diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 1d0195f4..d7e1b48b 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -473,6 +473,37 @@ type FooBar = { }; ``` +#### JavaScript: Fix ugly formatting on object destructuring with parameter decorators ([#6411] by [@sosukesuzuki]) + +Previously, Prettier formatted decorators for destructured parameters in a weird way. Now, parameter decorators are placed just above the parameter they belong to. + + +```js +// Input +class Class { + method( + @decorator + { foo } + ) {} +} + +// Prettier (stable) +class Class { + method(@decorator + { + foo + }) {} +} + +// Prettier (master) +class Class { + method( + @decorator + { foo } + ) {} +} +``` + [#5910]: https://github.com/prettier/prettier/pull/5910 [#6186]: https://github.com/prettier/prettier/pull/6186 [#6206]: https://github.com/prettier/prettier/pull/6206 @@ -489,6 +520,7 @@ type FooBar = { [#6340]: https://github.com/prettier/prettier/pull/6340 [#6412]: https://github.com/prettier/prettier/pull/6412 [#6420]: https://github.com/prettier/prettier/pull/6420 +[#6411]: https://github.com/prettier/prettier/pull/6411 [@duailibe]: https://github.com/duailibe [@gavinjoyce]: https://github.com/gavinjoyce [@sosukesuzuki]: https://github.com/sosukesuzuki diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js index 86f09c3e..dad577e6 100644 --- a/src/language-js/printer-estree.js +++ b/src/language-js/printer-estree.js @@ -1419,6 +1419,7 @@ function printPathNoParens(path, options, print, args) { (n.type === "ObjectPattern" && parent && shouldHugArguments(parent) && + !n.decorators && parent.params[0] === n) || (shouldHugType(n) && parentParentParent && @@ -4355,7 +4356,10 @@ function printFunctionParams(path, print, options, expandArg, printTypeParams) { // b, // c // }) {} - if (shouldHugParameters) { + const hasNotParameterDecorator = fun[paramsField].every( + param => !param.decorators + ); + if (shouldHugParameters && hasNotParameterDecorator) { return concat([typeParams, "(", concat(printed), ")"]); } diff --git a/tests/typescript_decorators/__snapshots__/jsfmt.spec.js.snap b/tests/typescript_decorators/__snapshots__/jsfmt.spec.js.snap index d6f0f540..113a721d 100644 --- a/tests/typescript_decorators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/typescript_decorators/__snapshots__/jsfmt.spec.js.snap @@ -87,6 +87,49 @@ class AngularComponent { @Input() myInput: string; } +class Class { + method( + @Decorator + { prop1, prop2 }: Type + ) { + doSomething(); + } +} + +class Class { + method( + @Decorator1 + @Decorator2 + { prop1, prop2 }: Type + ) { + doSomething(); + } +} + +class Class { + method( + @Decorator + { prop1_1, prop1_2 }: Type, + { prop2_1, prop2_2 }: Type + ) { + doSomething(); + } +} + +class Class { + method( + param1, + @Decorator + { prop1, prop2 }: Type + ) {} +} + +class Class { + method( + @Decorator { prop1 }: Type + ) {} +} + =====================================output===================================== export class TestTextFileService { constructor(@ILifecycleService lifecycleService) {} @@ -102,6 +145,47 @@ class AngularComponent { @Input() myInput: string; } +class Class { + method( + @Decorator + { prop1, prop2 }: Type + ) { + doSomething(); + } +} + +class Class { + method( + @Decorator1 + @Decorator2 + { prop1, prop2 }: Type + ) { + doSomething(); + } +} + +class Class { + method( + @Decorator + { prop1_1, prop1_2 }: Type, + { prop2_1, prop2_2 }: Type + ) { + doSomething(); + } +} + +class Class { + method( + param1, + @Decorator + { prop1, prop2 }: Type + ) {} +} + +class Class { + method(@Decorator { prop1 }: Type) {} +} + ================================================================================ `; diff --git a/tests/typescript_decorators/decorators.js b/tests/typescript_decorators/decorators.js index 3224863b..7b7cd214 100644 --- a/tests/typescript_decorators/decorators.js +++ b/tests/typescript_decorators/decorators.js @@ -15,3 +15,46 @@ export class TabCompletionController { class AngularComponent { @Input() myInput: string; } + +class Class { + method( + @Decorator + { prop1, prop2 }: Type + ) { + doSomething(); + } +} + +class Class { + method( + @Decorator1 + @Decorator2 + { prop1, prop2 }: Type + ) { + doSomething(); + } +} + +class Class { + method( + @Decorator + { prop1_1, prop1_2 }: Type, + { prop2_1, prop2_2 }: Type + ) { + doSomething(); + } +} + +class Class { + method( + param1, + @Decorator + { prop1, prop2 }: Type + ) {} +} + +class Class { + method( + @Decorator { prop1 }: Type + ) {} +}