From d0645fe477e88a223683f921281ea313909dc37b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Sat, 15 Feb 2020 12:24:29 -0500 Subject: [PATCH 1/4] fix: parse declare modifiers around accessibility modifiers --- packages/babel-parser/src/plugins/typescript/index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index f1937e9eca4c..a581bfa8299b 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -1922,8 +1922,16 @@ export default (superClass: Class): Class => state: { hadConstructor: boolean }, constructorAllowsSuper: boolean, ): void { + const preDeclare = this.tsParseModifier(["declare"]); const accessibility = this.parseAccessModifier(); if (accessibility) member.accessibility = accessibility; + const startPos = this.state.start; + const postDeclare = this.tsParseModifier(["declare"]); + if (preDeclare && postDeclare) { + this.raise(startPos, "Duplicate modifier: 'declare'"); + } else if (preDeclare || postDeclare) { + member.declare = true; + } super.parseClassMember(classBody, member, state, constructorAllowsSuper); } From 07296b77b2006619643678522d64e8ff1088a484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Sat, 15 Feb 2020 12:24:46 -0500 Subject: [PATCH 2/4] test: add tests --- .../class/declare-field-modifiers/input.ts | 11 + .../class/declare-field-modifiers/output.json | 372 ++++++++++++++++++ .../class/duplicate-modifier-1/input.ts | 3 + .../class/duplicate-modifier-1/output.json | 124 ++++++ 4 files changed, 510 insertions(+) create mode 100644 packages/babel-parser/test/fixtures/typescript/class/declare-field-modifiers/input.ts create mode 100644 packages/babel-parser/test/fixtures/typescript/class/declare-field-modifiers/output.json create mode 100644 packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/input.ts create mode 100644 packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/output.json diff --git a/packages/babel-parser/test/fixtures/typescript/class/declare-field-modifiers/input.ts b/packages/babel-parser/test/fixtures/typescript/class/declare-field-modifiers/input.ts new file mode 100644 index 000000000000..5eeb011f60ba --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/declare-field-modifiers/input.ts @@ -0,0 +1,11 @@ +class A { + declare static foo; + static declare foo0: string; + + declare public foo1; + public declare foo2; + + declare public static foo4; + public declare static foo3; + public static declare foo5; +} diff --git a/packages/babel-parser/test/fixtures/typescript/class/declare-field-modifiers/output.json b/packages/babel-parser/test/fixtures/typescript/class/declare-field-modifiers/output.json new file mode 100644 index 000000000000..a2a697b6ec13 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/declare-field-modifiers/output.json @@ -0,0 +1,372 @@ +{ + "type": "File", + "start": 0, + "end": 202, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 11, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 202, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 11, + "column": 1 + } + }, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 202, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 11, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 6, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "A" + }, + "name": "A" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 8, + "end": 202, + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 11, + "column": 1 + } + }, + "body": [ + { + "type": "ClassProperty", + "start": 12, + "end": 31, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 21 + } + }, + "declare": true, + "static": true, + "key": { + "type": "Identifier", + "start": 27, + "end": 30, + "loc": { + "start": { + "line": 2, + "column": 17 + }, + "end": { + "line": 2, + "column": 20 + }, + "identifierName": "foo" + }, + "name": "foo" + }, + "computed": false, + "value": null + }, + { + "type": "ClassProperty", + "start": 34, + "end": 62, + "loc": { + "start": { + "line": 3, + "column": 2 + }, + "end": { + "line": 3, + "column": 30 + } + }, + "declare": true, + "static": true, + "key": { + "type": "Identifier", + "start": 49, + "end": 53, + "loc": { + "start": { + "line": 3, + "column": 17 + }, + "end": { + "line": 3, + "column": 21 + }, + "identifierName": "foo0" + }, + "name": "foo0" + }, + "computed": false, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 53, + "end": 61, + "loc": { + "start": { + "line": 3, + "column": 21 + }, + "end": { + "line": 3, + "column": 29 + } + }, + "typeAnnotation": { + "type": "TSStringKeyword", + "start": 55, + "end": 61, + "loc": { + "start": { + "line": 3, + "column": 23 + }, + "end": { + "line": 3, + "column": 29 + } + } + } + }, + "value": null + }, + { + "type": "ClassProperty", + "start": 66, + "end": 86, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 22 + } + }, + "accessibility": "public", + "declare": true, + "static": false, + "key": { + "type": "Identifier", + "start": 81, + "end": 85, + "loc": { + "start": { + "line": 5, + "column": 17 + }, + "end": { + "line": 5, + "column": 21 + }, + "identifierName": "foo1" + }, + "name": "foo1" + }, + "computed": false, + "value": null + }, + { + "type": "ClassProperty", + "start": 89, + "end": 109, + "loc": { + "start": { + "line": 6, + "column": 2 + }, + "end": { + "line": 6, + "column": 22 + } + }, + "accessibility": "public", + "declare": true, + "static": false, + "key": { + "type": "Identifier", + "start": 104, + "end": 108, + "loc": { + "start": { + "line": 6, + "column": 17 + }, + "end": { + "line": 6, + "column": 21 + }, + "identifierName": "foo2" + }, + "name": "foo2" + }, + "computed": false, + "value": null + }, + { + "type": "ClassProperty", + "start": 113, + "end": 140, + "loc": { + "start": { + "line": 8, + "column": 2 + }, + "end": { + "line": 8, + "column": 29 + } + }, + "accessibility": "public", + "declare": true, + "static": true, + "key": { + "type": "Identifier", + "start": 135, + "end": 139, + "loc": { + "start": { + "line": 8, + "column": 24 + }, + "end": { + "line": 8, + "column": 28 + }, + "identifierName": "foo4" + }, + "name": "foo4" + }, + "computed": false, + "value": null + }, + { + "type": "ClassProperty", + "start": 143, + "end": 170, + "loc": { + "start": { + "line": 9, + "column": 2 + }, + "end": { + "line": 9, + "column": 29 + } + }, + "accessibility": "public", + "declare": true, + "static": true, + "key": { + "type": "Identifier", + "start": 165, + "end": 169, + "loc": { + "start": { + "line": 9, + "column": 24 + }, + "end": { + "line": 9, + "column": 28 + }, + "identifierName": "foo3" + }, + "name": "foo3" + }, + "computed": false, + "value": null + }, + { + "type": "ClassProperty", + "start": 173, + "end": 200, + "loc": { + "start": { + "line": 10, + "column": 2 + }, + "end": { + "line": 10, + "column": 29 + } + }, + "accessibility": "public", + "declare": true, + "static": true, + "key": { + "type": "Identifier", + "start": 195, + "end": 199, + "loc": { + "start": { + "line": 10, + "column": 24 + }, + "end": { + "line": 10, + "column": 28 + }, + "identifierName": "foo5" + }, + "name": "foo5" + }, + "computed": false, + "value": null + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/input.ts b/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/input.ts new file mode 100644 index 000000000000..41589defb3c4 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/input.ts @@ -0,0 +1,3 @@ +class A { + declare public declare foo; +} diff --git a/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/output.json b/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/output.json new file mode 100644 index 000000000000..816197276c9e --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/output.json @@ -0,0 +1,124 @@ +{ + "type": "File", + "start": 0, + "end": 41, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "errors": [ + "SyntaxError: Duplicate modifier: 'declare' (2:17)" + ], + "program": { + "type": "Program", + "start": 0, + "end": 41, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 41, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 6, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "A" + }, + "name": "A" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 8, + "end": 41, + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ClassProperty", + "start": 12, + "end": 39, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 29 + } + }, + "accessibility": "public", + "static": false, + "key": { + "type": "Identifier", + "start": 35, + "end": 38, + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 28 + }, + "identifierName": "foo" + }, + "name": "foo" + }, + "computed": false, + "value": null + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file From c6360e3e65ec27531e8d4a9935326e228377557e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Sat, 15 Feb 2020 12:42:54 -0500 Subject: [PATCH 3/4] fix: check duplicate modifiers in modified nodes --- .../src/plugins/typescript/index.js | 35 ++--- .../class/duplicate-modifier-1/output.json | 1 + .../class/duplicate-modifier-2/input.ts | 3 + .../class/duplicate-modifier-2/output.json | 125 ++++++++++++++++++ 4 files changed, 139 insertions(+), 25 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-2/input.ts create mode 100644 packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-2/output.json diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index a581bfa8299b..f613fbdb68be 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -135,27 +135,24 @@ export default (superClass: Class): Class => /** Parses a list of modifiers, in any order. * If you need a specific order, you must call this function multiple times: - * this.tsParseModifiers(["public"]); - * this.tsParseModifiers(["abstract", "readonly"]); + * this.tsParseModifiers(node, ["public"]); + * this.tsParseModifiers(node, ["abstract", "readonly"]); */ tsParseModifiers( + modified: N.ClassMember, allowedModifiers: T[], - ): { [key: TsModifier]: ?true, __proto__: null } { - const modifiers = Object.create(null); - + ): void { while (true) { const startPos = this.state.start; const modifier: ?T = this.tsParseModifier(allowedModifiers); if (!modifier) break; - if (Object.hasOwnProperty.call(modifiers, modifier)) { + if (Object.hasOwnProperty.call(modified, modifier)) { this.raise(startPos, `Duplicate modifier: '${modifier}'`); } - modifiers[modifier] = true; + modified[modifier] = true; } - - return modifiers; } tsIsListTerminator(kind: ParsingContext): boolean { @@ -1922,16 +1919,10 @@ export default (superClass: Class): Class => state: { hadConstructor: boolean }, constructorAllowsSuper: boolean, ): void { - const preDeclare = this.tsParseModifier(["declare"]); + this.tsParseModifiers(member, ["declare"]); const accessibility = this.parseAccessModifier(); if (accessibility) member.accessibility = accessibility; - const startPos = this.state.start; - const postDeclare = this.tsParseModifier(["declare"]); - if (preDeclare && postDeclare) { - this.raise(startPos, "Duplicate modifier: 'declare'"); - } else if (preDeclare || postDeclare) { - member.declare = true; - } + this.tsParseModifiers(member, ["declare"]); super.parseClassMember(classBody, member, state, constructorAllowsSuper); } @@ -1943,19 +1934,13 @@ export default (superClass: Class): Class => isStatic: boolean, constructorAllowsSuper: boolean, ): void { - const modifiers = this.tsParseModifiers([ - "abstract", - "readonly", - "declare", - ]); - - Object.assign(member, modifiers); + this.tsParseModifiers(member, ["abstract", "readonly", "declare"]); const idx = this.tsTryParseIndexSignature(member); if (idx) { classBody.body.push(idx); - if (modifiers.abstract) { + if ((member: any).abstract) { this.raise( member.start, "Index signatures cannot have the 'abstract' modifier", diff --git a/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/output.json b/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/output.json index 816197276c9e..fe51bdeadee2 100644 --- a/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/output.json +++ b/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/output.json @@ -93,6 +93,7 @@ "column": 29 } }, + "declare": true, "accessibility": "public", "static": false, "key": { diff --git a/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-2/input.ts b/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-2/input.ts new file mode 100644 index 000000000000..d2909835d448 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-2/input.ts @@ -0,0 +1,3 @@ +class A { + declare public static declare foo; +} diff --git a/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-2/output.json b/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-2/output.json new file mode 100644 index 000000000000..d4a3379dd77d --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-2/output.json @@ -0,0 +1,125 @@ +{ + "type": "File", + "start": 0, + "end": 48, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "errors": [ + "SyntaxError: Duplicate modifier: 'declare' (2:24)" + ], + "program": { + "type": "Program", + "start": 0, + "end": 48, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 48, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 6, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "A" + }, + "name": "A" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 8, + "end": 48, + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ClassProperty", + "start": 12, + "end": 46, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 36 + } + }, + "declare": true, + "accessibility": "public", + "static": true, + "key": { + "type": "Identifier", + "start": 42, + "end": 45, + "loc": { + "start": { + "line": 2, + "column": 32 + }, + "end": { + "line": 2, + "column": 35 + }, + "identifierName": "foo" + }, + "name": "foo" + }, + "computed": false, + "value": null + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file From 91db516e65ad40b4a4ff2f1cab277b0ebf6f810b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Sat, 15 Feb 2020 12:53:49 -0500 Subject: [PATCH 4/4] fix flow error --- packages/babel-parser/src/plugins/typescript/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index f613fbdb68be..309d2187fc84 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -139,7 +139,7 @@ export default (superClass: Class): Class => * this.tsParseModifiers(node, ["abstract", "readonly"]); */ tsParseModifiers( - modified: N.ClassMember, + modified: { [key: TsModifier]: ?true }, allowedModifiers: T[], ): void { while (true) {