diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index f1937e9eca4c..309d2187fc84 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: { [key: TsModifier]: ?true }, 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,8 +1919,10 @@ export default (superClass: Class): Class => state: { hadConstructor: boolean }, constructorAllowsSuper: boolean, ): void { + this.tsParseModifiers(member, ["declare"]); const accessibility = this.parseAccessModifier(); if (accessibility) member.accessibility = accessibility; + this.tsParseModifiers(member, ["declare"]); super.parseClassMember(classBody, member, state, constructorAllowsSuper); } @@ -1935,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/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..fe51bdeadee2 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/duplicate-modifier-1/output.json @@ -0,0 +1,125 @@ +{ + "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 + } + }, + "declare": true, + "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 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