From c22e72eb24b9dd83d43e693067d9c856acf9977d Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sat, 13 Feb 2021 01:20:06 +0900 Subject: [PATCH] Raise recoverable error for type members with invalid modifiers (#12785) --- .../src/plugins/typescript/index.js | 33 ++++- .../invalid-modifiers-method/input.ts | 9 ++ .../invalid-modifiers-method/output.json | 121 ++++++++++++++++++ .../invalid-modifiers-property/input.ts | 8 ++ .../invalid-modifiers-property/output.json | 102 +++++++++++++++ 5 files changed, 268 insertions(+), 5 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-method/input.ts create mode 100644 packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-method/output.json create mode 100644 packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-property/input.ts create mode 100644 packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-property/output.json diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 86ec75450715..aed992336b99 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -82,6 +82,7 @@ const TSErrors = Object.freeze({ IndexSignatureHasStatic: "Index signatures cannot have the 'static' modifier", IndexSignatureHasDeclare: "Index signatures cannot have the 'declare' modifier", + InvalidModifierOnTypeMember: "'%0' modifier cannot appear on a type member.", InvalidTupleMemberLabel: "Tuple members must be labeled with a simple identifier.", MixedLabeledAndUnlabeledElements: @@ -98,6 +99,8 @@ const TSErrors = Object.freeze({ "Private elements cannot have the 'abstract' modifier.", PrivateElementHasAccessibility: "Private elements cannot have an accessibility modifier ('%0')", + ReadonlyForMethodSignature: + "'readonly' modifier can only appear on a property declaration or index signature.", TypeAnnotationAfterAssign: "Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`", UnexpectedParameterModifier: @@ -207,10 +210,14 @@ export default (superClass: Class): Class => accessibility?: N.Accessibility, }, allowedModifiers: TsModifier[], + disallowedModifiers?: TsModifier[], + errorTemplate?: string, ): void { for (;;) { const startPos = this.state.start; - const modifier: ?TsModifier = this.tsParseModifier(allowedModifiers); + const modifier: ?TsModifier = this.tsParseModifier( + allowedModifiers.concat(disallowedModifiers ?? []), + ); if (!modifier) break; @@ -226,6 +233,15 @@ export default (superClass: Class): Class => } modified[modifier] = true; } + + if (disallowedModifiers?.includes(modifier)) { + this.raise( + startPos, + // $FlowIgnore + errorTemplate, + modifier, + ); + } } } @@ -537,7 +553,10 @@ export default (superClass: Class): Class => if (this.eat(tt.question)) node.optional = true; const nodeAny: any = node; - if (!readonly && (this.match(tt.parenL) || this.isRelational("<"))) { + if (this.match(tt.parenL) || this.isRelational("<")) { + if (readonly) { + this.raise(node.start, TSErrors.ReadonlyForMethodSignature); + } const method: N.TsMethodSignature = nodeAny; this.tsFillSignature(tt.colon, method); this.tsParseTypeMemberSemicolon(); @@ -573,16 +592,20 @@ export default (superClass: Class): Class => } } - const readonly = !!this.tsParseModifier(["readonly"]); + this.tsParseModifiers( + node, + ["readonly"], + ["declare", "abstract", "private", "protected", "public", "static"], + TSErrors.InvalidModifierOnTypeMember, + ); const idx = this.tsTryParseIndexSignature(node); if (idx) { - if (readonly) node.readonly = true; return idx; } this.parsePropertyName(node, /* isPrivateNameAllowed */ false); - return this.tsParsePropertyOrMethodSignature(node, readonly); + return this.tsParsePropertyOrMethodSignature(node, !!node.readonly); } tsParseTypeLiteral(): N.TsTypeLiteral { diff --git a/packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-method/input.ts b/packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-method/input.ts new file mode 100644 index 000000000000..d8a52921ddc3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-method/input.ts @@ -0,0 +1,9 @@ +interface Foo { + private a(); + public b(); + protected c(); + static d(); + declare e(); + abstract f(); + readonly g(); +} diff --git a/packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-method/output.json b/packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-method/output.json new file mode 100644 index 000000000000..080f46b132ef --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-method/output.json @@ -0,0 +1,121 @@ +{ + "type": "File", + "start":0,"end":124,"loc":{"start":{"line":1,"column":0},"end":{"line":9,"column":1}}, + "errors": [ + "SyntaxError: 'private' modifier cannot appear on a type member. (2:2)", + "SyntaxError: 'public' modifier cannot appear on a type member. (3:2)", + "SyntaxError: 'protected' modifier cannot appear on a type member. (4:2)", + "SyntaxError: 'static' modifier cannot appear on a type member. (5:2)", + "SyntaxError: 'declare' modifier cannot appear on a type member. (6:2)", + "SyntaxError: 'abstract' modifier cannot appear on a type member. (7:2)", + "SyntaxError: 'readonly' modifier can only appear on a property declaration or index signature. (8:2)" + ], + "program": { + "type": "Program", + "start":0,"end":124,"loc":{"start":{"line":1,"column":0},"end":{"line":9,"column":1}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSInterfaceDeclaration", + "start":0,"end":124,"loc":{"start":{"line":1,"column":0},"end":{"line":9,"column":1}}, + "id": { + "type": "Identifier", + "start":10,"end":13,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":13},"identifierName":"Foo"}, + "name": "Foo" + }, + "body": { + "type": "TSInterfaceBody", + "start":14,"end":124,"loc":{"start":{"line":1,"column":14},"end":{"line":9,"column":1}}, + "body": [ + { + "type": "TSMethodSignature", + "start":18,"end":30,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":14}}, + "accessibility": "private", + "key": { + "type": "Identifier", + "start":26,"end":27,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":11},"identifierName":"a"}, + "name": "a" + }, + "computed": false, + "parameters": [] + }, + { + "type": "TSMethodSignature", + "start":33,"end":44,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":13}}, + "accessibility": "public", + "key": { + "type": "Identifier", + "start":40,"end":41,"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":10},"identifierName":"b"}, + "name": "b" + }, + "computed": false, + "parameters": [] + }, + { + "type": "TSMethodSignature", + "start":47,"end":61,"loc":{"start":{"line":4,"column":2},"end":{"line":4,"column":16}}, + "accessibility": "protected", + "key": { + "type": "Identifier", + "start":57,"end":58,"loc":{"start":{"line":4,"column":12},"end":{"line":4,"column":13},"identifierName":"c"}, + "name": "c" + }, + "computed": false, + "parameters": [] + }, + { + "type": "TSMethodSignature", + "start":64,"end":75,"loc":{"start":{"line":5,"column":2},"end":{"line":5,"column":13}}, + "static": true, + "key": { + "type": "Identifier", + "start":71,"end":72,"loc":{"start":{"line":5,"column":9},"end":{"line":5,"column":10},"identifierName":"d"}, + "name": "d" + }, + "computed": false, + "parameters": [] + }, + { + "type": "TSMethodSignature", + "start":78,"end":90,"loc":{"start":{"line":6,"column":2},"end":{"line":6,"column":14}}, + "declare": true, + "key": { + "type": "Identifier", + "start":86,"end":87,"loc":{"start":{"line":6,"column":10},"end":{"line":6,"column":11},"identifierName":"e"}, + "name": "e" + }, + "computed": false, + "parameters": [] + }, + { + "type": "TSMethodSignature", + "start":93,"end":106,"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":15}}, + "abstract": true, + "key": { + "type": "Identifier", + "start":102,"end":103,"loc":{"start":{"line":7,"column":11},"end":{"line":7,"column":12},"identifierName":"f"}, + "name": "f" + }, + "computed": false, + "parameters": [] + }, + { + "type": "TSMethodSignature", + "start":109,"end":122,"loc":{"start":{"line":8,"column":2},"end":{"line":8,"column":15}}, + "readonly": true, + "key": { + "type": "Identifier", + "start":118,"end":119,"loc":{"start":{"line":8,"column":11},"end":{"line":8,"column":12},"identifierName":"g"}, + "name": "g" + }, + "computed": false, + "parameters": [] + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-property/input.ts b/packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-property/input.ts new file mode 100644 index 000000000000..d79fc481ff79 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-property/input.ts @@ -0,0 +1,8 @@ +interface Foo { + private a; + public b; + protected c; + static d; + declare e; + abstract f; +} diff --git a/packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-property/output.json b/packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-property/output.json new file mode 100644 index 000000000000..be58676dc3a4 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/interface/invalid-modifiers-property/output.json @@ -0,0 +1,102 @@ +{ + "type": "File", + "start":0,"end":96,"loc":{"start":{"line":1,"column":0},"end":{"line":8,"column":1}}, + "errors": [ + "SyntaxError: 'private' modifier cannot appear on a type member. (2:2)", + "SyntaxError: 'public' modifier cannot appear on a type member. (3:2)", + "SyntaxError: 'protected' modifier cannot appear on a type member. (4:2)", + "SyntaxError: 'static' modifier cannot appear on a type member. (5:2)", + "SyntaxError: 'declare' modifier cannot appear on a type member. (6:2)", + "SyntaxError: 'abstract' modifier cannot appear on a type member. (7:2)" + ], + "program": { + "type": "Program", + "start":0,"end":96,"loc":{"start":{"line":1,"column":0},"end":{"line":8,"column":1}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSInterfaceDeclaration", + "start":0,"end":96,"loc":{"start":{"line":1,"column":0},"end":{"line":8,"column":1}}, + "id": { + "type": "Identifier", + "start":10,"end":13,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":13},"identifierName":"Foo"}, + "name": "Foo" + }, + "body": { + "type": "TSInterfaceBody", + "start":14,"end":96,"loc":{"start":{"line":1,"column":14},"end":{"line":8,"column":1}}, + "body": [ + { + "type": "TSPropertySignature", + "start":18,"end":28,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":12}}, + "accessibility": "private", + "key": { + "type": "Identifier", + "start":26,"end":27,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":11},"identifierName":"a"}, + "name": "a" + }, + "computed": false + }, + { + "type": "TSPropertySignature", + "start":31,"end":40,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":11}}, + "accessibility": "public", + "key": { + "type": "Identifier", + "start":38,"end":39,"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":10},"identifierName":"b"}, + "name": "b" + }, + "computed": false + }, + { + "type": "TSPropertySignature", + "start":43,"end":55,"loc":{"start":{"line":4,"column":2},"end":{"line":4,"column":14}}, + "accessibility": "protected", + "key": { + "type": "Identifier", + "start":53,"end":54,"loc":{"start":{"line":4,"column":12},"end":{"line":4,"column":13},"identifierName":"c"}, + "name": "c" + }, + "computed": false + }, + { + "type": "TSPropertySignature", + "start":58,"end":67,"loc":{"start":{"line":5,"column":2},"end":{"line":5,"column":11}}, + "static": true, + "key": { + "type": "Identifier", + "start":65,"end":66,"loc":{"start":{"line":5,"column":9},"end":{"line":5,"column":10},"identifierName":"d"}, + "name": "d" + }, + "computed": false + }, + { + "type": "TSPropertySignature", + "start":70,"end":80,"loc":{"start":{"line":6,"column":2},"end":{"line":6,"column":12}}, + "declare": true, + "key": { + "type": "Identifier", + "start":78,"end":79,"loc":{"start":{"line":6,"column":10},"end":{"line":6,"column":11},"identifierName":"e"}, + "name": "e" + }, + "computed": false + }, + { + "type": "TSPropertySignature", + "start":83,"end":94,"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":13}}, + "abstract": true, + "key": { + "type": "Identifier", + "start":92,"end":93,"loc":{"start":{"line":7,"column":11},"end":{"line":7,"column":12},"identifierName":"f"}, + "name": "f" + }, + "computed": false + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file