TypeScript: Throw errors for invalid modifier on type parameter (#13853)

This commit is contained in:
fisker Cheung authored and GitHub committed 2022-11-18 09:54:23 +08:00
1 parent bac69974fd
commit b697a596a6
17 files changed
+218 -89

No files matched your search

-2
View File
@@ -207,10 +207,8 @@ const allowedMessageCodes = new Set([
"InvalidTupleMemberLabel", "InvalidTupleMemberLabel",
"NonClassMethodPropertyHasAbstractModifer", "NonClassMethodPropertyHasAbstractModifer",
"ReadonlyForMethodSignature",
"ClassMethodHasDeclare", "ClassMethodHasDeclare",
"ClassMethodHasReadonly", "ClassMethodHasReadonly",
"InvalidModifierOnTypeMember",
"DuplicateAccessibilityModifier", "DuplicateAccessibilityModifier",
"IndexSignatureHasDeclare", "IndexSignatureHasDeclare",
@@ -8,6 +8,9 @@ const SyntaxKind = {
SourceFile: 305, SourceFile: 305,
DeclareKeyword: 135, DeclareKeyword: 135,
PropertyDeclaration: 167, PropertyDeclaration: 167,
InKeyword: 101,
OutKeyword: 144,
TypeParameter: 168,
}; };
function getTsNodeLocation(nodeOrToken) { 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) { function getTsNode(node, tsParseResult) {
const { esTreeNodeToTSNodeMap, tsNodeToESTreeNodeMap } = tsParseResult; const { esTreeNodeToTSNodeMap, tsNodeToESTreeNodeMap } = tsParseResult;
const tsNode = esTreeNodeToTSNodeMap.get(node); const tsNode = esTreeNodeToTSNodeMap.get(node);
@@ -113,7 +142,8 @@ function throwErrorForInvalidNodes(tsParseResult, options) {
// decorators // decorators
// abstract properties // abstract properties
// declare in accessor // declare in accessor
!/@|abstract|declare/.test(options.originalText) // modifiers on type parameter
!/@|abstract|declare|interface/.test(options.originalText)
) { ) {
return; return;
} }
@@ -127,6 +157,7 @@ function throwErrorForInvalidNodes(tsParseResult, options) {
throwErrorForInvalidDeclare(tsNode, esTreeNode); throwErrorForInvalidDeclare(tsNode, esTreeNode);
throwErrorForInvalidDecorator(tsNode); throwErrorForInvalidDecorator(tsNode);
throwErrorForInvalidAbstractProperty(tsNode, esTreeNode); throwErrorForInvalidAbstractProperty(tsNode, esTreeNode);
throwErrorForInvalidModifierOnTypeParameter(tsNode, esTreeNode);
}); });
} }
-7
View File
@@ -320,13 +320,6 @@ function printTypescript(path, options, print) {
parts.push( parts.push(
node.accessibility ? [node.accessibility, " "] : "", node.accessibility ? [node.accessibility, " "] : "",
kind, 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 ? "[" : "", node.computed ? "[" : "",
print("key"), print("key"),
node.computed ? "]" : "", node.computed ? "]" : "",
+5
View File
@@ -166,6 +166,11 @@ function runSpec(fixtures, parsers, options) {
snippets = snippets.map((test, index) => { snippets = snippets.map((test, index) => {
test = typeof test === "string" ? { code: test } : test; test = typeof test === "string" ? { code: test } : test;
if (typeof test.code !== "string") {
throw Object.assign(new Error("Invalid test"), { test });
}
return { return {
...test, ...test,
name: `snippet: ${test.name || `#${index}`}`, 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`] = ` exports[`value-of-abstract-property.ts [typescript] format 1`] = `
"Abstract property cannot have an initializer (2:3) "Abstract property cannot have an initializer (2:3)
1 | abstract class Foo { 1 | abstract class Foo {
@@ -43,3 +43,67 @@ exports[`snippet: #2 [babel-ts] format 1`] = `
> 1 | <string>foo = '100'; > 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( run_spec(
{ {
importMeta: import.meta, importMeta: import.meta,
@@ -5,6 +7,22 @@ run_spec(
"foo as any = 10;", "foo as any = 10;",
"({ a: b as any = 2000 } = x);", "({ a: b as any = 2000 } = x);",
"<string>foo = '100';", "<string>foo = '100';",
...[
"abstract",
"declare",
"export",
"static",
"private",
"protected",
"public",
"readonly",
].map(
(modifier) => outdent`
interface Foo {
${modifier} e();
}
`
),
], ],
}, },
["babel-ts"] ["babel-ts"]
@@ -1,3 +1,5 @@
import { outdent } from "outdent";
run_spec( run_spec(
{ {
importMeta: import.meta, importMeta: import.meta,
@@ -8,6 +10,22 @@ run_spec(
'let x4 = <div>{"foo"}></div>;', 'let x4 = <div>{"foo"}></div>;',
'let x5 = <div>}{"foo"}</div>;', 'let x5 = <div>}{"foo"}</div>;',
'let x6 = <div>>{"foo"}</div>;', 'let x6 = <div>>{"foo"}</div>;',
...[
"abstract",
"declare",
"export",
"static",
"private",
"protected",
"public",
"readonly",
].map(
(modifier) => outdent`
interface Foo {
${modifier} e();
}
`
),
], ],
}, },
["typescript"] ["typescript"]
@@ -26,32 +26,12 @@ parsers: ["babel-ts"]
printWidth: 80 printWidth: 80
| printWidth | printWidth
=====================================input====================================== =====================================input======================================
interface Foo {
private a();
public b();
protected c();
static d();
declare e();
abstract f();
readonly g();
}
class Bar { class Bar {
declare e() {}; declare e() {};
readonly g() {}; readonly g() {};
} }
=====================================output===================================== =====================================output=====================================
interface Foo {
private a();
public b();
protected c();
static d();
declare e();
abstract f();
readonly g();
}
class Bar { class Bar {
declare e() {} declare e() {}
readonly g() {} readonly g() {}
@@ -1,13 +1,3 @@
interface Foo {
private a();
public b();
protected c();
static d();
declare e();
abstract f();
readonly g();
}
class Bar { class Bar {
declare e() {}; declare e() {};
readonly g() {}; readonly g() {};
@@ -57,16 +57,6 @@ parsers: ["typescript"]
printWidth: 80 printWidth: 80
| printWidth | printWidth
=====================================input====================================== =====================================input======================================
interface Foo {
private a();
public b();
protected c();
static d();
declare e();
abstract f();
readonly g();
}
class Bar { class Bar {
declare e() {}; declare e() {};
abstract f() {}; abstract f() {};
@@ -74,16 +64,6 @@ class Bar {
} }
=====================================output===================================== =====================================output=====================================
interface Foo {
private a();
public b();
protected c();
static d();
e();
f();
readonly g();
}
class Bar { class Bar {
e() {} e() {}
abstract f() {} abstract f() {}
@@ -1,13 +1,3 @@
interface Foo {
private a();
public b();
protected c();
static d();
declare e();
abstract f();
readonly g();
}
class Bar { class Bar {
declare e() {}; declare e() {};
abstract f() {}; 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`] = ` exports[`methods.ts format 1`] = `
====================================options===================================== ====================================options=====================================
parsers: ["typescript"] parsers: ["typescript"]
@@ -414,7 +403,7 @@ class X {
} }
interface Iterable<T> { interface Iterable<T> {
export [Symbol.iterator](): Iterator<T>; [Symbol.iterator](): Iterator<T>;
} }
export class Check { export class Check {
@@ -427,7 +416,7 @@ class X {
} }
interface Iterable<T> { interface Iterable<T> {
export [Symbol.iterator](): Iterator<T>; [Symbol.iterator](): Iterator<T>;
} }
export class Check { export class Check {
+1 -1
View File
@@ -1,3 +1,3 @@
run_spec(import.meta, ["typescript"], { run_spec(import.meta, ["typescript"], {
errors: { "babel-ts": ["constructor.ts", "generics.ts", "methods.ts"] }, errors: { "babel-ts": ["constructor.ts", "generics.ts"] },
}); });
+1 -1
View File
@@ -3,7 +3,7 @@ class X {
} }
interface Iterable<T> { interface Iterable<T> {
export [Symbol.iterator](): Iterator<T>; [Symbol.iterator](): Iterator<T>;
} }
export class Check { export class Check {
@@ -668,11 +668,12 @@ printWidth: 80
| printWidth | printWidth
=====================================input====================================== =====================================input======================================
interface I { interface I {
public [a: string]: number; [a: string]: number;
} }
=====================================output===================================== =====================================output=====================================
interface I { interface I {
public [a: string]: number; [a: string]: number;
} }
================================================================================ ================================================================================
@@ -1,3 +1,3 @@
interface I { interface I {
public [a: string]: number; [a: string]: number;
} }