Allow decorator on private members and class expressions (#14548)
This commit is contained in:
1 parent
ddf3b43c33
commit
44aef0b1ba
8 files changed
+97
-91
No files matched your search
@@ -0,0 +1,24 @@
|
||||
#### Allow decorators on private members and class expressions (#14548 by @fisker)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
// Input
|
||||
class A {
|
||||
@decorator()
|
||||
#privateMethod () {}
|
||||
}
|
||||
|
||||
// Prettier stable
|
||||
SyntaxError: Decorators are not valid here. (2:3)
|
||||
1 | class A {
|
||||
> 2 | @decorator()
|
||||
| ^^^^^^^^^^^^
|
||||
3 | #privateMethod () {}
|
||||
4 | }
|
||||
|
||||
// Prettier main
|
||||
class A {
|
||||
@decorator()
|
||||
#privateMethod() {}
|
||||
}
|
||||
```
|
||||
@@ -30,6 +30,20 @@ function throwErrorOnTsNode(node, message) {
|
||||
throwSyntaxError({ loc: { start, end } }, message);
|
||||
}
|
||||
|
||||
function nodeCanBeDecorated(node) {
|
||||
const ts = require("typescript");
|
||||
|
||||
return [true, false].some((useLegacyDecorators) =>
|
||||
// @ts-expect-error -- internal?
|
||||
ts.nodeCanBeDecorated(
|
||||
useLegacyDecorators,
|
||||
node,
|
||||
node.parent,
|
||||
node.parent.parent
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Invalid decorators are removed since `@typescript-eslint/typescript-estree` v4
|
||||
// https://github.com/typescript-eslint/typescript-eslint/pull/2375
|
||||
// There is a `checkGrammarDecorators` in `typescript` package, consider use it directly in future
|
||||
@@ -44,16 +58,7 @@ function throwErrorForInvalidDecorator(node) {
|
||||
const { SyntaxKind } = ts;
|
||||
for (const modifier of modifiers) {
|
||||
if (ts.isDecorator(modifier)) {
|
||||
const legacyDecorators = true;
|
||||
if (
|
||||
// @ts-expect-error -- internal?
|
||||
!ts.nodeCanBeDecorated(
|
||||
legacyDecorators,
|
||||
node,
|
||||
node.parent,
|
||||
node.parent.parent
|
||||
)
|
||||
) {
|
||||
if (!nodeCanBeDecorated(node)) {
|
||||
if (
|
||||
node.kind === SyntaxKind.MethodDeclaration &&
|
||||
// @ts-expect-error -- internal?
|
||||
@@ -67,9 +72,8 @@ function throwErrorForInvalidDecorator(node) {
|
||||
throwErrorOnTsNode(modifier, "Decorators are not valid here.");
|
||||
}
|
||||
} else if (
|
||||
legacyDecorators &&
|
||||
(node.kind === SyntaxKind.GetAccessor ||
|
||||
node.kind === SyntaxKind.SetAccessor)
|
||||
node.kind === SyntaxKind.GetAccessor ||
|
||||
node.kind === SyntaxKind.SetAccessor
|
||||
) {
|
||||
// @ts-expect-error -- internal?
|
||||
const accessors = ts.getAllAccessorDeclarations(
|
||||
|
||||
@@ -24,14 +24,6 @@ exports[`arguments.js [flow] format 1`] = `
|
||||
3 |"
|
||||
`;
|
||||
|
||||
exports[`arguments.js [typescript] format 1`] = `
|
||||
"Decorators are not valid here. (1:13)
|
||||
> 1 | console.log(@deco class Foo {})
|
||||
| ^^^^^
|
||||
2 | console.log(@deco class {})
|
||||
3 |"
|
||||
`;
|
||||
|
||||
exports[`arguments.js - {"semi":false} [acorn] format 1`] = `
|
||||
"Unexpected character '@' (1:13)
|
||||
> 1 | console.log(@deco class Foo {})
|
||||
@@ -56,14 +48,6 @@ exports[`arguments.js - {"semi":false} [flow] format 1`] = `
|
||||
3 |"
|
||||
`;
|
||||
|
||||
exports[`arguments.js - {"semi":false} [typescript] format 1`] = `
|
||||
"Decorators are not valid here. (1:13)
|
||||
> 1 | console.log(@deco class Foo {})
|
||||
| ^^^^^
|
||||
2 | console.log(@deco class {})
|
||||
3 |"
|
||||
`;
|
||||
|
||||
exports[`arguments.js - {"semi":false} format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["babel", "flow", "typescript"]
|
||||
@@ -144,15 +128,6 @@ exports[`class-expression.js [flow] format 1`] = `
|
||||
4 | (@deco class Foo {});"
|
||||
`;
|
||||
|
||||
exports[`class-expression.js [typescript] format 1`] = `
|
||||
"Decorators are not valid here. (1:13)
|
||||
> 1 | const a1 = (@deco class Foo {});
|
||||
| ^^^^^
|
||||
2 | const a2 = (@deco class {});
|
||||
3 |
|
||||
4 | (@deco class Foo {});"
|
||||
`;
|
||||
|
||||
exports[`class-expression.js - {"semi":false} [acorn] format 1`] = `
|
||||
"Unexpected character '@' (1:13)
|
||||
> 1 | const a1 = (@deco class Foo {});
|
||||
@@ -180,15 +155,6 @@ exports[`class-expression.js - {"semi":false} [flow] format 1`] = `
|
||||
4 | (@deco class Foo {});"
|
||||
`;
|
||||
|
||||
exports[`class-expression.js - {"semi":false} [typescript] format 1`] = `
|
||||
"Decorators are not valid here. (1:13)
|
||||
> 1 | const a1 = (@deco class Foo {});
|
||||
| ^^^^^
|
||||
2 | const a2 = (@deco class {});
|
||||
3 |
|
||||
4 | (@deco class Foo {});"
|
||||
`;
|
||||
|
||||
exports[`class-expression.js - {"semi":false} format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["babel", "flow", "typescript"]
|
||||
@@ -336,14 +302,6 @@ exports[`member-expression.js [flow] format 1`] = `
|
||||
3 |"
|
||||
`;
|
||||
|
||||
exports[`member-expression.js [typescript] format 1`] = `
|
||||
"Decorators are not valid here. (1:2)
|
||||
> 1 | (@deco class Foo {}).name;
|
||||
| ^^^^^
|
||||
2 | (@deco class {}).name;
|
||||
3 |"
|
||||
`;
|
||||
|
||||
exports[`member-expression.js - {"semi":false} [acorn] format 1`] = `
|
||||
"Unexpected character '@' (1:2)
|
||||
> 1 | (@deco class Foo {}).name;
|
||||
@@ -368,14 +326,6 @@ exports[`member-expression.js - {"semi":false} [flow] format 1`] = `
|
||||
3 |"
|
||||
`;
|
||||
|
||||
exports[`member-expression.js - {"semi":false} [typescript] format 1`] = `
|
||||
"Decorators are not valid here. (1:2)
|
||||
> 1 | (@deco class Foo {}).name;
|
||||
| ^^^^^
|
||||
2 | (@deco class {}).name;
|
||||
3 |"
|
||||
`;
|
||||
|
||||
exports[`member-expression.js - {"semi":false} format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["babel", "flow", "typescript"]
|
||||
@@ -448,15 +398,6 @@ exports[`super-class.js [flow] format 1`] = `
|
||||
4 |"
|
||||
`;
|
||||
|
||||
exports[`super-class.js [typescript] format 1`] = `
|
||||
"Decorators are not valid here. (1:20)
|
||||
> 1 | class Foo extends (@deco class Foo {}){}
|
||||
| ^^^^^
|
||||
2 |
|
||||
3 | class Foo extends (@deco class {}){}
|
||||
4 |"
|
||||
`;
|
||||
|
||||
exports[`super-class.js - {"semi":false} [acorn] format 1`] = `
|
||||
"Unexpected character '@' (1:20)
|
||||
> 1 | class Foo extends (@deco class Foo {}){}
|
||||
@@ -484,15 +425,6 @@ exports[`super-class.js - {"semi":false} [flow] format 1`] = `
|
||||
4 |"
|
||||
`;
|
||||
|
||||
exports[`super-class.js - {"semi":false} [typescript] format 1`] = `
|
||||
"Decorators are not valid here. (1:20)
|
||||
> 1 | class Foo extends (@deco class Foo {}){}
|
||||
| ^^^^^
|
||||
2 |
|
||||
3 | class Foo extends (@deco class {}){}
|
||||
4 |"
|
||||
`;
|
||||
|
||||
exports[`super-class.js - {"semi":false} format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["babel", "flow", "typescript"]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const errors = {
|
||||
flow: true,
|
||||
typescript: true,
|
||||
acorn: true,
|
||||
espree: true,
|
||||
};
|
||||
|
||||
@@ -497,6 +497,48 @@ class MyContainerComponent {
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`legacy.ts format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["typescript"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
[
|
||||
@decorator() class {},
|
||||
@decorator() class A {},
|
||||
];
|
||||
|
||||
class A {
|
||||
@decorator() accessor #field;
|
||||
}
|
||||
|
||||
class B {
|
||||
@decorator() #field () {}
|
||||
}
|
||||
|
||||
=====================================output=====================================
|
||||
[
|
||||
(
|
||||
@decorator()
|
||||
class {}
|
||||
),
|
||||
(
|
||||
@decorator()
|
||||
class A {}
|
||||
),
|
||||
];
|
||||
|
||||
class A {
|
||||
@decorator() accessor #field;
|
||||
}
|
||||
|
||||
class B {
|
||||
@decorator() #field() {}
|
||||
}
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`mobx.ts format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["typescript"]
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[
|
||||
@decorator() class {},
|
||||
@decorator() class A {},
|
||||
];
|
||||
|
||||
class A {
|
||||
@decorator() accessor #field;
|
||||
}
|
||||
|
||||
class B {
|
||||
@decorator() #field () {}
|
||||
}
|
||||
+1
-8
@@ -49,7 +49,7 @@ exports[`3.ts [typescript] format 1`] = `
|
||||
2 |"
|
||||
`;
|
||||
|
||||
exports[`4.ts [babel-ts] format 1`] = `
|
||||
exports[`4.ts format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["typescript"]
|
||||
printWidth: 80
|
||||
@@ -66,13 +66,6 @@ printWidth: 80
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`4.ts [typescript] format 1`] = `
|
||||
"Decorators are not valid here. (1:2)
|
||||
> 1 | (@f<<T>(v: T) => void>() class {});
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
2 |"
|
||||
`;
|
||||
|
||||
exports[`5.tsx [babel-ts] format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["typescript"]
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
run_spec(__dirname, ["typescript"], {
|
||||
errors: { typescript: ["3.ts", "4.ts", "5.tsx"] },
|
||||
errors: { typescript: ["3.ts", "5.tsx"] },
|
||||
});
|
||||
Reference in new issue
Block a user