ts: Throw recoverable for duplicates access modifier (#12775)
* Support parsing for duplicates access modifiers Support parsing for duplicates access modifiers * Fix lint problems * Address reviews
This commit is contained in:
parent
d242ea04c8
commit
f1a327506e
@ -36,9 +36,7 @@ type TsModifier =
|
|||||||
| "abstract"
|
| "abstract"
|
||||||
| "declare"
|
| "declare"
|
||||||
| "static"
|
| "static"
|
||||||
| "public"
|
| N.Accessibility;
|
||||||
| "private"
|
|
||||||
| "protected";
|
|
||||||
|
|
||||||
function nonNull<T>(x: ?T): T {
|
function nonNull<T>(x: ?T): T {
|
||||||
if (x == null) {
|
if (x == null) {
|
||||||
@ -71,6 +69,7 @@ const TSErrors = Object.freeze({
|
|||||||
DeclareFunctionHasImplementation:
|
DeclareFunctionHasImplementation:
|
||||||
"An implementation cannot be declared in ambient contexts.",
|
"An implementation cannot be declared in ambient contexts.",
|
||||||
DuplicateModifier: "Duplicate modifier: '%0'",
|
DuplicateModifier: "Duplicate modifier: '%0'",
|
||||||
|
DuplicateAccessibilityModifier: "Accessibility modifier already seen.",
|
||||||
EmptyHeritageClauseType: "'%0' list cannot be empty.",
|
EmptyHeritageClauseType: "'%0' list cannot be empty.",
|
||||||
EmptyTypeArguments: "Type argument list cannot be empty.",
|
EmptyTypeArguments: "Type argument list cannot be empty.",
|
||||||
EmptyTypeParameters: "Type parameter list cannot be empty.",
|
EmptyTypeParameters: "Type parameter list cannot be empty.",
|
||||||
@ -146,6 +145,12 @@ function keywordTypeFromName(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function tsIsAccessModifier(modifier: string): boolean %checks {
|
||||||
|
return (
|
||||||
|
modifier === "private" || modifier === "public" || modifier === "protected"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default (superClass: Class<Parser>): Class<Parser> =>
|
export default (superClass: Class<Parser>): Class<Parser> =>
|
||||||
class extends superClass {
|
class extends superClass {
|
||||||
getScopeHandler(): Class<TypeScriptScopeHandler> {
|
getScopeHandler(): Class<TypeScriptScopeHandler> {
|
||||||
@ -196,20 +201,31 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
* this.tsParseModifiers(node, ["public"]);
|
* this.tsParseModifiers(node, ["public"]);
|
||||||
* this.tsParseModifiers(node, ["abstract", "readonly"]);
|
* this.tsParseModifiers(node, ["abstract", "readonly"]);
|
||||||
*/
|
*/
|
||||||
tsParseModifiers<T: TsModifier>(
|
tsParseModifiers(
|
||||||
modified: { [key: TsModifier]: ?true },
|
modified: {
|
||||||
allowedModifiers: T[],
|
[key: TsModifier]: ?true,
|
||||||
|
accessibility?: N.Accessibility,
|
||||||
|
},
|
||||||
|
allowedModifiers: TsModifier[],
|
||||||
): void {
|
): void {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const startPos = this.state.start;
|
const startPos = this.state.start;
|
||||||
const modifier: ?T = this.tsParseModifier(allowedModifiers);
|
const modifier: ?TsModifier = this.tsParseModifier(allowedModifiers);
|
||||||
|
|
||||||
if (!modifier) break;
|
if (!modifier) break;
|
||||||
|
|
||||||
if (Object.hasOwnProperty.call(modified, modifier)) {
|
if (tsIsAccessModifier(modifier)) {
|
||||||
this.raise(startPos, TSErrors.DuplicateModifier, modifier);
|
if (modified.accessibility) {
|
||||||
|
this.raise(startPos, TSErrors.DuplicateAccessibilityModifier);
|
||||||
|
} else {
|
||||||
|
modified.accessibility = modifier;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Object.hasOwnProperty.call(modified, modifier)) {
|
||||||
|
this.raise(startPos, TSErrors.DuplicateModifier, modifier);
|
||||||
|
}
|
||||||
|
modified[modifier] = true;
|
||||||
}
|
}
|
||||||
modified[modifier] = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2120,10 +2136,12 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
member: any,
|
member: any,
|
||||||
state: N.ParseClassMemberState,
|
state: N.ParseClassMemberState,
|
||||||
): void {
|
): void {
|
||||||
this.tsParseModifiers(member, ["declare"]);
|
this.tsParseModifiers(member, [
|
||||||
const accessibility = this.parseAccessModifier();
|
"declare",
|
||||||
if (accessibility) member.accessibility = accessibility;
|
"private",
|
||||||
this.tsParseModifiers(member, ["declare"]);
|
"public",
|
||||||
|
"protected",
|
||||||
|
]);
|
||||||
|
|
||||||
const callParseClassMember = () => {
|
const callParseClassMember = () => {
|
||||||
super.parseClassMember(classBody, member, state);
|
super.parseClassMember(classBody, member, state);
|
||||||
|
|||||||
7
packages/babel-parser/test/fixtures/typescript/class/duplicates-accessibility/input.ts
vendored
Normal file
7
packages/babel-parser/test/fixtures/typescript/class/duplicates-accessibility/input.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
class Foo {
|
||||||
|
public public a;
|
||||||
|
private public b;
|
||||||
|
protected private c;
|
||||||
|
public protected d;
|
||||||
|
public protected private e;
|
||||||
|
}
|
||||||
102
packages/babel-parser/test/fixtures/typescript/class/duplicates-accessibility/output.json
vendored
Normal file
102
packages/babel-parser/test/fixtures/typescript/class/duplicates-accessibility/output.json
vendored
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start":0,"end":127,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}},
|
||||||
|
"errors": [
|
||||||
|
"SyntaxError: Accessibility modifier already seen. (2:9)",
|
||||||
|
"SyntaxError: Accessibility modifier already seen. (3:10)",
|
||||||
|
"SyntaxError: Accessibility modifier already seen. (4:12)",
|
||||||
|
"SyntaxError: Accessibility modifier already seen. (5:9)",
|
||||||
|
"SyntaxError: Accessibility modifier already seen. (6:9)",
|
||||||
|
"SyntaxError: Accessibility modifier already seen. (6:19)"
|
||||||
|
],
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start":0,"end":127,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}},
|
||||||
|
"sourceType": "module",
|
||||||
|
"interpreter": null,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ClassDeclaration",
|
||||||
|
"start":0,"end":127,"loc":{"start":{"line":1,"column":0},"end":{"line":7,"column":1}},
|
||||||
|
"id": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
|
||||||
|
"name": "Foo"
|
||||||
|
},
|
||||||
|
"superClass": null,
|
||||||
|
"body": {
|
||||||
|
"type": "ClassBody",
|
||||||
|
"start":10,"end":127,"loc":{"start":{"line":1,"column":10},"end":{"line":7,"column":1}},
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ClassProperty",
|
||||||
|
"start":14,"end":30,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":18}},
|
||||||
|
"accessibility": "public",
|
||||||
|
"static": false,
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":28,"end":29,"loc":{"start":{"line":2,"column":16},"end":{"line":2,"column":17},"identifierName":"a"},
|
||||||
|
"name": "a"
|
||||||
|
},
|
||||||
|
"computed": false,
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ClassProperty",
|
||||||
|
"start":33,"end":50,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":19}},
|
||||||
|
"accessibility": "private",
|
||||||
|
"static": false,
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":48,"end":49,"loc":{"start":{"line":3,"column":17},"end":{"line":3,"column":18},"identifierName":"b"},
|
||||||
|
"name": "b"
|
||||||
|
},
|
||||||
|
"computed": false,
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ClassProperty",
|
||||||
|
"start":53,"end":73,"loc":{"start":{"line":4,"column":2},"end":{"line":4,"column":22}},
|
||||||
|
"accessibility": "protected",
|
||||||
|
"static": false,
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":71,"end":72,"loc":{"start":{"line":4,"column":20},"end":{"line":4,"column":21},"identifierName":"c"},
|
||||||
|
"name": "c"
|
||||||
|
},
|
||||||
|
"computed": false,
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ClassProperty",
|
||||||
|
"start":76,"end":95,"loc":{"start":{"line":5,"column":2},"end":{"line":5,"column":21}},
|
||||||
|
"accessibility": "public",
|
||||||
|
"static": false,
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":93,"end":94,"loc":{"start":{"line":5,"column":19},"end":{"line":5,"column":20},"identifierName":"d"},
|
||||||
|
"name": "d"
|
||||||
|
},
|
||||||
|
"computed": false,
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ClassProperty",
|
||||||
|
"start":98,"end":125,"loc":{"start":{"line":6,"column":2},"end":{"line":6,"column":29}},
|
||||||
|
"accessibility": "public",
|
||||||
|
"static": false,
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":123,"end":124,"loc":{"start":{"line":6,"column":27},"end":{"line":6,"column":28},"identifierName":"e"},
|
||||||
|
"name": "e"
|
||||||
|
},
|
||||||
|
"computed": false,
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user