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"
|
||||
| "declare"
|
||||
| "static"
|
||||
| "public"
|
||||
| "private"
|
||||
| "protected";
|
||||
| N.Accessibility;
|
||||
|
||||
function nonNull<T>(x: ?T): T {
|
||||
if (x == null) {
|
||||
@ -71,6 +69,7 @@ const TSErrors = Object.freeze({
|
||||
DeclareFunctionHasImplementation:
|
||||
"An implementation cannot be declared in ambient contexts.",
|
||||
DuplicateModifier: "Duplicate modifier: '%0'",
|
||||
DuplicateAccessibilityModifier: "Accessibility modifier already seen.",
|
||||
EmptyHeritageClauseType: "'%0' list cannot be empty.",
|
||||
EmptyTypeArguments: "Type argument 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> =>
|
||||
class extends superClass {
|
||||
getScopeHandler(): Class<TypeScriptScopeHandler> {
|
||||
@ -196,22 +201,33 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
||||
* this.tsParseModifiers(node, ["public"]);
|
||||
* this.tsParseModifiers(node, ["abstract", "readonly"]);
|
||||
*/
|
||||
tsParseModifiers<T: TsModifier>(
|
||||
modified: { [key: TsModifier]: ?true },
|
||||
allowedModifiers: T[],
|
||||
tsParseModifiers(
|
||||
modified: {
|
||||
[key: TsModifier]: ?true,
|
||||
accessibility?: N.Accessibility,
|
||||
},
|
||||
allowedModifiers: TsModifier[],
|
||||
): void {
|
||||
for (;;) {
|
||||
const startPos = this.state.start;
|
||||
const modifier: ?T = this.tsParseModifier(allowedModifiers);
|
||||
const modifier: ?TsModifier = this.tsParseModifier(allowedModifiers);
|
||||
|
||||
if (!modifier) break;
|
||||
|
||||
if (tsIsAccessModifier(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tsIsListTerminator(kind: ParsingContext): boolean {
|
||||
switch (kind) {
|
||||
@ -2120,10 +2136,12 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
||||
member: any,
|
||||
state: N.ParseClassMemberState,
|
||||
): void {
|
||||
this.tsParseModifiers(member, ["declare"]);
|
||||
const accessibility = this.parseAccessModifier();
|
||||
if (accessibility) member.accessibility = accessibility;
|
||||
this.tsParseModifiers(member, ["declare"]);
|
||||
this.tsParseModifiers(member, [
|
||||
"declare",
|
||||
"private",
|
||||
"public",
|
||||
"protected",
|
||||
]);
|
||||
|
||||
const callParseClassMember = () => {
|
||||
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