TypeScript: Throw errors for invalid modifier on type parameter (#13853)
This commit is contained in:
1 parent
bac69974fd
commit
b697a596a6
17 files changed
+218
-89
No files matched your search
@@ -207,10 +207,8 @@ const allowedMessageCodes = new Set([
|
||||
"InvalidTupleMemberLabel",
|
||||
|
||||
"NonClassMethodPropertyHasAbstractModifer",
|
||||
"ReadonlyForMethodSignature",
|
||||
"ClassMethodHasDeclare",
|
||||
"ClassMethodHasReadonly",
|
||||
"InvalidModifierOnTypeMember",
|
||||
"DuplicateAccessibilityModifier",
|
||||
"IndexSignatureHasDeclare",
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ const SyntaxKind = {
|
||||
SourceFile: 305,
|
||||
DeclareKeyword: 135,
|
||||
PropertyDeclaration: 167,
|
||||
InKeyword: 101,
|
||||
OutKeyword: 144,
|
||||
TypeParameter: 168,
|
||||
};
|
||||
|
||||
function getTsNodeLocation(nodeOrToken) {
|
||||
@@ -93,6 +96,32 @@ function throwErrorForInvalidDeclare(tsNode, esTreeNode) {
|
||||
);
|
||||
}
|
||||
|
||||
function throwErrorForInvalidModifierOnTypeParameter(tsNode, esTreeNode) {
|
||||
if (
|
||||
esTreeNode.type !== "TSMethodSignature" ||
|
||||
tsNode.kind !== SyntaxKind.TypeParameter
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const invalidModifier = tsNode.modifiers?.find(
|
||||
(modifier) =>
|
||||
!(
|
||||
modifier.kind === SyntaxKind.InKeyword ||
|
||||
modifier.kind === SyntaxKind.OutKeyword
|
||||
)
|
||||
);
|
||||
|
||||
if (!invalidModifier) {
|
||||
return;
|
||||
}
|
||||
|
||||
throwTsSyntaxError(
|
||||
{ loc: getTsNodeLocation(invalidModifier) },
|
||||
"This modifier cannot appear on a type member"
|
||||
);
|
||||
}
|
||||
|
||||
function getTsNode(node, tsParseResult) {
|
||||
const { esTreeNodeToTSNodeMap, tsNodeToESTreeNodeMap } = tsParseResult;
|
||||
const tsNode = esTreeNodeToTSNodeMap.get(node);
|
||||
@@ -113,7 +142,8 @@ function throwErrorForInvalidNodes(tsParseResult, options) {
|
||||
// decorators
|
||||
// abstract properties
|
||||
// declare in accessor
|
||||
!/@|abstract|declare/.test(options.originalText)
|
||||
// modifiers on type parameter
|
||||
!/@|abstract|declare|interface/.test(options.originalText)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@@ -127,6 +157,7 @@ function throwErrorForInvalidNodes(tsParseResult, options) {
|
||||
throwErrorForInvalidDeclare(tsNode, esTreeNode);
|
||||
throwErrorForInvalidDecorator(tsNode);
|
||||
throwErrorForInvalidAbstractProperty(tsNode, esTreeNode);
|
||||
throwErrorForInvalidModifierOnTypeParameter(tsNode, esTreeNode);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -320,13 +320,6 @@ function printTypescript(path, options, print) {
|
||||
parts.push(
|
||||
node.accessibility ? [node.accessibility, " "] : "",
|
||||
kind,
|
||||
node.export ? "export " : "",
|
||||
node.static ? "static " : "",
|
||||
node.readonly ? "readonly " : "",
|
||||
// "abstract" and "declare" are supported by only "babel-ts"
|
||||
// https://github.com/prettier/prettier/issues/9760
|
||||
node.abstract ? "abstract " : "",
|
||||
node.declare ? "declare " : "",
|
||||
node.computed ? "[" : "",
|
||||
print("key"),
|
||||
node.computed ? "]" : "",
|
||||
|
||||
@@ -166,6 +166,11 @@ function runSpec(fixtures, parsers, options) {
|
||||
|
||||
snippets = snippets.map((test, index) => {
|
||||
test = typeof test === "string" ? { code: test } : test;
|
||||
|
||||
if (typeof test.code !== "string") {
|
||||
throw Object.assign(new Error("Invalid test"), { test });
|
||||
}
|
||||
|
||||
return {
|
||||
...test,
|
||||
name: `snippet: ${test.name || `#${index}`}`,
|
||||
|
||||
@@ -94,6 +94,78 @@ exports[`snippet: #5 [typescript] format 1`] = `
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #6 [typescript] format 1`] = `
|
||||
"This modifier cannot appear on a type member (1:16)
|
||||
> 1 | interface Foo {
|
||||
| ^
|
||||
> 2 | abstract e();
|
||||
| ^^^^^^^^^^^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #7 [typescript] format 1`] = `
|
||||
"This modifier cannot appear on a type member (1:16)
|
||||
> 1 | interface Foo {
|
||||
| ^
|
||||
> 2 | declare e();
|
||||
| ^^^^^^^^^^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #8 [typescript] format 1`] = `
|
||||
"This modifier cannot appear on a type member (1:16)
|
||||
> 1 | interface Foo {
|
||||
| ^
|
||||
> 2 | export e();
|
||||
| ^^^^^^^^^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #9 [typescript] format 1`] = `
|
||||
"This modifier cannot appear on a type member (1:16)
|
||||
> 1 | interface Foo {
|
||||
| ^
|
||||
> 2 | static e();
|
||||
| ^^^^^^^^^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #10 [typescript] format 1`] = `
|
||||
"This modifier cannot appear on a type member (1:16)
|
||||
> 1 | interface Foo {
|
||||
| ^
|
||||
> 2 | private e();
|
||||
| ^^^^^^^^^^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #11 [typescript] format 1`] = `
|
||||
"This modifier cannot appear on a type member (1:16)
|
||||
> 1 | interface Foo {
|
||||
| ^
|
||||
> 2 | protected e();
|
||||
| ^^^^^^^^^^^^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #12 [typescript] format 1`] = `
|
||||
"This modifier cannot appear on a type member (1:16)
|
||||
> 1 | interface Foo {
|
||||
| ^
|
||||
> 2 | public e();
|
||||
| ^^^^^^^^^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #13 [typescript] format 1`] = `
|
||||
"This modifier cannot appear on a type member (1:16)
|
||||
> 1 | interface Foo {
|
||||
| ^
|
||||
> 2 | readonly e();
|
||||
| ^^^^^^^^^^^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`value-of-abstract-property.ts [typescript] format 1`] = `
|
||||
"Abstract property cannot have an initializer (2:3)
|
||||
1 | abstract class Foo {
|
||||
|
||||
@@ -43,3 +43,67 @@ exports[`snippet: #2 [babel-ts] format 1`] = `
|
||||
> 1 | <string>foo = '100';
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [babel-ts] format 1`] = `
|
||||
"'abstract' modifier cannot appear on a type member. (2:3)
|
||||
1 | interface Foo {
|
||||
> 2 | abstract e();
|
||||
| ^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [babel-ts] format 1`] = `
|
||||
"'declare' modifier cannot appear on a type member. (2:3)
|
||||
1 | interface Foo {
|
||||
> 2 | declare e();
|
||||
| ^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #5 [babel-ts] format 1`] = `
|
||||
"Unexpected token, expected ";" (2:10)
|
||||
1 | interface Foo {
|
||||
> 2 | export e();
|
||||
| ^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #6 [babel-ts] format 1`] = `
|
||||
"'static' modifier cannot appear on a type member. (2:3)
|
||||
1 | interface Foo {
|
||||
> 2 | static e();
|
||||
| ^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #7 [babel-ts] format 1`] = `
|
||||
"'private' modifier cannot appear on a type member. (2:3)
|
||||
1 | interface Foo {
|
||||
> 2 | private e();
|
||||
| ^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #8 [babel-ts] format 1`] = `
|
||||
"'protected' modifier cannot appear on a type member. (2:3)
|
||||
1 | interface Foo {
|
||||
> 2 | protected e();
|
||||
| ^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #9 [babel-ts] format 1`] = `
|
||||
"'public' modifier cannot appear on a type member. (2:3)
|
||||
1 | interface Foo {
|
||||
> 2 | public e();
|
||||
| ^
|
||||
3 | }"
|
||||
`;
|
||||
|
||||
exports[`snippet: #10 [babel-ts] format 1`] = `
|
||||
"'readonly' modifier can only appear on a property declaration or index signature. (2:3)
|
||||
1 | interface Foo {
|
||||
> 2 | readonly e();
|
||||
| ^
|
||||
3 | }"
|
||||
`;
|
||||
@@ -1,3 +1,5 @@
|
||||
import { outdent } from "outdent";
|
||||
|
||||
run_spec(
|
||||
{
|
||||
importMeta: import.meta,
|
||||
@@ -5,6 +7,22 @@ run_spec(
|
||||
"foo as any = 10;",
|
||||
"({ a: b as any = 2000 } = x);",
|
||||
"<string>foo = '100';",
|
||||
...[
|
||||
"abstract",
|
||||
"declare",
|
||||
"export",
|
||||
"static",
|
||||
"private",
|
||||
"protected",
|
||||
"public",
|
||||
"readonly",
|
||||
].map(
|
||||
(modifier) => outdent`
|
||||
interface Foo {
|
||||
${modifier} e();
|
||||
}
|
||||
`
|
||||
),
|
||||
],
|
||||
},
|
||||
["babel-ts"]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { outdent } from "outdent";
|
||||
|
||||
run_spec(
|
||||
{
|
||||
importMeta: import.meta,
|
||||
@@ -8,6 +10,22 @@ run_spec(
|
||||
'let x4 = <div>{"foo"}></div>;',
|
||||
'let x5 = <div>}{"foo"}</div>;',
|
||||
'let x6 = <div>>{"foo"}</div>;',
|
||||
...[
|
||||
"abstract",
|
||||
"declare",
|
||||
"export",
|
||||
"static",
|
||||
"private",
|
||||
"protected",
|
||||
"public",
|
||||
"readonly",
|
||||
].map(
|
||||
(modifier) => outdent`
|
||||
interface Foo {
|
||||
${modifier} e();
|
||||
}
|
||||
`
|
||||
),
|
||||
],
|
||||
},
|
||||
["typescript"]
|
||||
|
||||
@@ -26,32 +26,12 @@ parsers: ["babel-ts"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
interface Foo {
|
||||
private a();
|
||||
public b();
|
||||
protected c();
|
||||
static d();
|
||||
declare e();
|
||||
abstract f();
|
||||
readonly g();
|
||||
}
|
||||
|
||||
class Bar {
|
||||
declare e() {};
|
||||
readonly g() {};
|
||||
}
|
||||
|
||||
=====================================output=====================================
|
||||
interface Foo {
|
||||
private a();
|
||||
public b();
|
||||
protected c();
|
||||
static d();
|
||||
declare e();
|
||||
abstract f();
|
||||
readonly g();
|
||||
}
|
||||
|
||||
class Bar {
|
||||
declare e() {}
|
||||
readonly g() {}
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
interface Foo {
|
||||
private a();
|
||||
public b();
|
||||
protected c();
|
||||
static d();
|
||||
declare e();
|
||||
abstract f();
|
||||
readonly g();
|
||||
}
|
||||
|
||||
class Bar {
|
||||
declare e() {};
|
||||
readonly g() {};
|
||||
|
||||
@@ -57,16 +57,6 @@ parsers: ["typescript"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
interface Foo {
|
||||
private a();
|
||||
public b();
|
||||
protected c();
|
||||
static d();
|
||||
declare e();
|
||||
abstract f();
|
||||
readonly g();
|
||||
}
|
||||
|
||||
class Bar {
|
||||
declare e() {};
|
||||
abstract f() {};
|
||||
@@ -74,16 +64,6 @@ class Bar {
|
||||
}
|
||||
|
||||
=====================================output=====================================
|
||||
interface Foo {
|
||||
private a();
|
||||
public b();
|
||||
protected c();
|
||||
static d();
|
||||
e();
|
||||
f();
|
||||
readonly g();
|
||||
}
|
||||
|
||||
class Bar {
|
||||
e() {}
|
||||
abstract f() {}
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
interface Foo {
|
||||
private a();
|
||||
public b();
|
||||
protected c();
|
||||
static d();
|
||||
declare e();
|
||||
abstract f();
|
||||
readonly g();
|
||||
}
|
||||
|
||||
class Bar {
|
||||
declare e() {};
|
||||
abstract f() {};
|
||||
|
||||
@@ -392,17 +392,6 @@ interface AudioBufferList {
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`methods.ts [babel-ts] format 1`] = `
|
||||
"Unexpected token, expected ";" (6:10)
|
||||
4 |
|
||||
5 | interface Iterable<T> {
|
||||
> 6 | export [Symbol.iterator](): Iterator<T>;
|
||||
| ^
|
||||
7 | }
|
||||
8 |
|
||||
9 | export class Check {"
|
||||
`;
|
||||
|
||||
exports[`methods.ts format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["typescript"]
|
||||
@@ -414,7 +403,7 @@ class X {
|
||||
}
|
||||
|
||||
interface Iterable<T> {
|
||||
export [Symbol.iterator](): Iterator<T>;
|
||||
[Symbol.iterator](): Iterator<T>;
|
||||
}
|
||||
|
||||
export class Check {
|
||||
@@ -427,7 +416,7 @@ class X {
|
||||
}
|
||||
|
||||
interface Iterable<T> {
|
||||
export [Symbol.iterator](): Iterator<T>;
|
||||
[Symbol.iterator](): Iterator<T>;
|
||||
}
|
||||
|
||||
export class Check {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
run_spec(import.meta, ["typescript"], {
|
||||
errors: { "babel-ts": ["constructor.ts", "generics.ts", "methods.ts"] },
|
||||
errors: { "babel-ts": ["constructor.ts", "generics.ts"] },
|
||||
});
|
||||
@@ -3,7 +3,7 @@ class X {
|
||||
}
|
||||
|
||||
interface Iterable<T> {
|
||||
export [Symbol.iterator](): Iterator<T>;
|
||||
[Symbol.iterator](): Iterator<T>;
|
||||
}
|
||||
|
||||
export class Check {
|
||||
|
||||
@@ -668,11 +668,12 @@ printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
interface I {
|
||||
public [a: string]: number;
|
||||
[a: string]: number;
|
||||
}
|
||||
|
||||
=====================================output=====================================
|
||||
interface I {
|
||||
public [a: string]: number;
|
||||
[a: string]: number;
|
||||
}
|
||||
|
||||
================================================================================
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
interface I {
|
||||
public [a: string]: number;
|
||||
}
|
||||
[a: string]: number;
|
||||
}
|
||||
Reference in new issue
Block a user