From f9fae7f34ce6a5664073fb9c78d692dcacb82527 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Fri, 24 Mar 2023 16:08:46 +0800 Subject: [PATCH 1/6] Allow multiple decorators on same getter/setter (#14584) --- changelog_unreleased/typescript/14584.md | 31 ++++++++++++++ .../parse/postprocess/typescript.js | 41 +++++-------------- .../__snapshots__/jsfmt.spec.js.snap | 13 +----- .../typescript/decorators/jsfmt.spec.js | 2 +- 4 files changed, 43 insertions(+), 44 deletions(-) create mode 100644 changelog_unreleased/typescript/14584.md diff --git a/changelog_unreleased/typescript/14584.md b/changelog_unreleased/typescript/14584.md new file mode 100644 index 000000000..70cf95469 --- /dev/null +++ b/changelog_unreleased/typescript/14584.md @@ -0,0 +1,31 @@ +#### Allow multiple decorators on same getter/setter (#14584 by @fisker) + + +```ts +// Input +class A { + @decorator() + get foo () {} + + @decorator() + set foo (value) {} +} + +// Prettier stable +SyntaxError: Decorators cannot be applied to multiple get/set accessors of the same name. (5:3) + 3 | get foo () {} + 4 | +> 5 | @decorator() + | ^^^^^^^^^^^^ + 6 | set foo (value) {} + 7 | } + +// Prettier main +class A { + @decorator() + get foo() {} + + @decorator() + set foo(value) {} +} +``` diff --git a/src/language-js/parse/postprocess/typescript.js b/src/language-js/parse/postprocess/typescript.js index 926f60432..761cd76d5 100644 --- a/src/language-js/parse/postprocess/typescript.js +++ b/src/language-js/parse/postprocess/typescript.js @@ -57,40 +57,19 @@ function throwErrorForInvalidDecorator(node) { const { SyntaxKind } = ts; for (const modifier of modifiers) { - if (ts.isDecorator(modifier)) { - if (!nodeCanBeDecorated(node)) { - if ( - node.kind === SyntaxKind.MethodDeclaration && - // @ts-expect-error -- internal? - !ts.nodeIsPresent(node.body) - ) { - throwErrorOnTsNode( - modifier, - "A decorator can only decorate a method implementation, not an overload." - ); - } else { - throwErrorOnTsNode(modifier, "Decorators are not valid here."); - } - } else if ( - node.kind === SyntaxKind.GetAccessor || - node.kind === SyntaxKind.SetAccessor - ) { + if (ts.isDecorator(modifier) && !nodeCanBeDecorated(node)) { + if ( + node.kind === SyntaxKind.MethodDeclaration && // @ts-expect-error -- internal? - const accessors = ts.getAllAccessorDeclarations( - node.parent.members, - node + !ts.nodeIsPresent(node.body) + ) { + throwErrorOnTsNode( + modifier, + "A decorator can only decorate a method implementation, not an overload." ); - if ( - // @ts-expect-error -- internal? - ts.hasDecorators(accessors.firstAccessor) && - node === accessors.secondAccessor - ) { - throwErrorOnTsNode( - modifier, - "Decorators cannot be applied to multiple get/set accessors of the same name." - ); - } } + + throwErrorOnTsNode(modifier, "Decorators are not valid here."); } } } diff --git a/tests/format/typescript/decorators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/decorators/__snapshots__/jsfmt.spec.js.snap index 501c86771..d501273a7 100644 --- a/tests/format/typescript/decorators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/decorators/__snapshots__/jsfmt.spec.js.snap @@ -30,7 +30,7 @@ exports[`abstract-method.ts [typescript] format 1`] = ` 5 |" `; -exports[`accessor.ts [babel-ts] format 1`] = ` +exports[`accessor.ts format 1`] = ` ====================================options===================================== parsers: ["typescript"] printWidth: 80 @@ -56,17 +56,6 @@ class A { ================================================================================ `; -exports[`accessor.ts [typescript] format 1`] = ` -"Decorators cannot be applied to multiple get/set accessors of the same name. (4:5) - 2 | @foo() - 3 | get a() {return 1} -> 4 | @bar() - | ^^^^^^ - 5 | set a(v) {} - 6 | } - 7 |" -`; - exports[`argument-list-preserve-line.ts format 1`] = ` ====================================options===================================== parsers: ["typescript"] diff --git a/tests/format/typescript/decorators/jsfmt.spec.js b/tests/format/typescript/decorators/jsfmt.spec.js index 3e59a6c31..78dd2704f 100644 --- a/tests/format/typescript/decorators/jsfmt.spec.js +++ b/tests/format/typescript/decorators/jsfmt.spec.js @@ -1,3 +1,3 @@ run_spec(__dirname, ["typescript"], { - errors: { typescript: ["abstract-method.ts", "accessor.ts"] }, + errors: { typescript: ["abstract-method.ts"] }, }); From 543a9d71a7a61436948814181bd3a5b434a6c2ae Mon Sep 17 00:00:00 2001 From: fisker Date: Fri, 24 Mar 2023 16:11:52 +0800 Subject: [PATCH 2/6] Release 2.8.7 --- .github/ISSUE_TEMPLATE/formatting.md | 2 +- .github/ISSUE_TEMPLATE/integration.md | 2 +- CHANGELOG.md | 61 +++++++++++++++++++ docs/browser.md | 30 ++++----- package.json | 2 +- .../versioned_docs/version-stable/browser.md | 30 ++++----- 6 files changed, 94 insertions(+), 33 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/formatting.md b/.github/ISSUE_TEMPLATE/formatting.md index dde56b359..fefab43bd 100644 --- a/.github/ISSUE_TEMPLATE/formatting.md +++ b/.github/ISSUE_TEMPLATE/formatting.md @@ -26,7 +26,7 @@ Don't fill the form below manually! Let a program create a report for you: --> -**Prettier 2.8.6** +**Prettier 2.8.7** [Playground link](https://prettier.io/playground/#.....) ```sh diff --git a/.github/ISSUE_TEMPLATE/integration.md b/.github/ISSUE_TEMPLATE/integration.md index e3aba155c..a50a5df0c 100644 --- a/.github/ISSUE_TEMPLATE/integration.md +++ b/.github/ISSUE_TEMPLATE/integration.md @@ -20,7 +20,7 @@ BEFORE SUBMITTING AN ISSUE: **Environments:** -- Prettier Version: 2.8.6 +- Prettier Version: 2.8.7 - Running Prettier via: - Runtime: - Operating System: diff --git a/CHANGELOG.md b/CHANGELOG.md index e07428f2f..ff5a7d774 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,64 @@ +# 2.8.7 + +[diff](https://github.com/prettier/prettier/compare/2.8.6...2.8.7) + +#### Allow decorators on private members and class expressions ([#14548](https://github.com/prettier/prettier/pull/14548) by [@fisker](https://github.com/fisker)) + + +```ts +// Input +class A { + @decorator() + #privateMethod () {} +} + +// Prettier 2.8.6 +SyntaxError: Decorators are not valid here. (2:3) + 1 | class A { +> 2 | @decorator() + | ^^^^^^^^^^^^ + 3 | #privateMethod () {} + 4 | } + +// Prettier 2.8.7 +class A { + @decorator() + #privateMethod() {} +} +``` + +#### Allow multiple decorators on same getter/setter ([#14584](https://github.com/prettier/prettier/pull/14584) by [@fisker](https://github.com/fisker)) + + +```ts +// Input +class A { + @decorator() + get foo () {} + + @decorator() + set foo (value) {} +} + +// Prettier 2.8.6 +SyntaxError: Decorators cannot be applied to multiple get/set accessors of the same name. (5:3) + 3 | get foo () {} + 4 | +> 5 | @decorator() + | ^^^^^^^^^^^^ + 6 | set foo (value) {} + 7 | } + +// Prettier 2.8.7 +class A { + @decorator() + get foo() {} + + @decorator() + set foo(value) {} +} +``` + # 2.8.6 [diff](https://github.com/prettier/prettier/compare/2.8.5...2.8.6) diff --git a/docs/browser.md b/docs/browser.md index 3300c8337..2a48cf69d 100644 --- a/docs/browser.md +++ b/docs/browser.md @@ -20,8 +20,8 @@ Required options: - **`plugins`**: Unlike the `format` function from the [Node.js-based API](api.md#prettierformatsource--options), this function doesn’t load plugins automatically. The `plugins` option is required because all the parsers included in the Prettier package come as plugins (for reasons of file size). These plugins are files named - - `parser-*.js` in and - - `parser-*.mjs` in + - `parser-*.js` in and + - `parser-*.mjs` in You need to load the ones that you’re going to use and pass them to `prettier.format` using the `plugins` option. @@ -32,8 +32,8 @@ See below for examples. ### Global ```html - - + + - + + + + + + + + + + + + + + +``` diff --git a/src/language-html/print-preprocess.js b/src/language-html/print-preprocess.js index 789ab7e56..43533907b 100644 --- a/src/language-html/print-preprocess.js +++ b/src/language-html/print-preprocess.js @@ -411,18 +411,13 @@ function addIsSpaceSensitive(ast, options) { } function markTsScript(ast, options) { - if (options.parser === "vue") { - const vueScriptTag = ast.children.find((child) => - isVueScriptTag(child, options) + options.__should_parse_vue_template_with_ts = + options.parser === "vue" && + ast.children.some( + (child) => + isVueScriptTag(child, options) && + ["ts", "typescript"].includes(child.attrMap.lang) ); - if (!vueScriptTag) { - return; - } - const { lang } = vueScriptTag.attrMap; - if (lang === "ts" || lang === "typescript") { - options.__should_parse_vue_template_with_ts = true; - } - } } module.exports = preprocess; diff --git a/tests/format/vue/multiparser/__snapshots__/jsfmt.spec.js.snap b/tests/format/vue/multiparser/__snapshots__/jsfmt.spec.js.snap index a921d3a0d..54599abe5 100644 --- a/tests/format/vue/multiparser/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/vue/multiparser/__snapshots__/jsfmt.spec.js.snap @@ -70,6 +70,60 @@ export default { ================================================================================ `; +exports[`lang-ts-multiple-script-tags.vue format 1`] = ` +====================================options===================================== +parsers: ["vue"] +printWidth: 80 + | printWidth +=====================================input====================================== + + + + + + + + + + + + +=====================================output===================================== + + + + + + + + + + + + +================================================================================ +`; + exports[`lang-tsx.vue format 1`] = ` ====================================options===================================== parsers: ["vue"] diff --git a/tests/format/vue/multiparser/lang-ts-multiple-script-tags.vue b/tests/format/vue/multiparser/lang-ts-multiple-script-tags.vue new file mode 100644 index 000000000..d60027bb2 --- /dev/null +++ b/tests/format/vue/multiparser/lang-ts-multiple-script-tags.vue @@ -0,0 +1,21 @@ + + + + + + + + + + +