diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 78a7f20283fc..766d0edb6b1c 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -283,6 +283,7 @@ export default (superClass: Class): Class => } else { enforceOrder(startPos, modifier, modifier, "override"); enforceOrder(startPos, modifier, modifier, "static"); + enforceOrder(startPos, modifier, modifier, "readonly"); modified.accessibility = modifier; } @@ -1927,10 +1928,23 @@ export default (superClass: Class): Class => let accessibility: ?N.Accessibility; let readonly = false; + let override = false; if (allowModifiers !== undefined) { - accessibility = this.parseAccessModifier(); - readonly = !!this.tsParseModifier(["readonly"]); - if (allowModifiers === false && (accessibility || readonly)) { + const modified = {}; + this.tsParseModifiers(modified, [ + "public", + "private", + "protected", + "override", + "readonly", + ]); + accessibility = modified.accessibility; + override = modified.override; + readonly = modified.readonly; + if ( + allowModifiers === false && + (accessibility || readonly || override) + ) { this.raise(startPos, TSErrors.UnexpectedParameterModifier); } } @@ -1938,13 +1952,14 @@ export default (superClass: Class): Class => const left = this.parseMaybeDefault(); this.parseAssignableListItemTypes(left); const elt = this.parseMaybeDefault(left.start, left.loc.start, left); - if (accessibility || readonly) { + if (accessibility || readonly || override) { const pp: N.TSParameterProperty = this.startNodeAt(startPos, startLoc); if (decorators.length) { pp.decorators = decorators; } if (accessibility) pp.accessibility = accessibility; if (readonly) pp.readonly = readonly; + if (override) pp.override = override; if (elt.type !== "Identifier" && elt.type !== "AssignmentPattern") { this.raise(pp.start, TSErrors.UnsupportedParameterPropertyKind); } diff --git a/packages/babel-parser/src/types.js b/packages/babel-parser/src/types.js index aaf7afdf1134..5001f7e1101c 100644 --- a/packages/babel-parser/src/types.js +++ b/packages/babel-parser/src/types.js @@ -1178,6 +1178,7 @@ export type TSParameterProperty = HasDecorators & { // At least one of `accessibility` or `readonly` must be set. accessibility?: ?Accessibility, readonly?: ?true, + override?: ?true, parameter: Identifier | AssignmentPattern, }; diff --git a/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-1/input.ts b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-1/input.ts new file mode 100644 index 000000000000..c431aaff84d5 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-1/input.ts @@ -0,0 +1,3 @@ +class D extends B { + constructor(readonly override foo: string) {} +} diff --git a/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-1/output.json b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-1/output.json new file mode 100644 index 000000000000..03050c7ad27f --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-1/output.json @@ -0,0 +1,78 @@ +{ + "type": "File", + "start":0,"end":69,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "errors": [ + "SyntaxError: 'override' modifier must precede 'readonly' modifier. (2:23)" + ], + "program": { + "type": "Program", + "start":0,"end":69,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":69,"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":"D"}, + "name": "D" + }, + "superClass": { + "type": "Identifier", + "start":16,"end":17,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":17},"identifierName":"B"}, + "name": "B" + }, + "body": { + "type": "ClassBody", + "start":18,"end":69,"loc":{"start":{"line":1,"column":18},"end":{"line":3,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":22,"end":67,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":47}}, + "static": false, + "key": { + "type": "Identifier", + "start":22,"end":33,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":13},"identifierName":"constructor"}, + "name": "constructor" + }, + "computed": false, + "kind": "constructor", + "id": null, + "generator": false, + "async": false, + "params": [ + { + "type": "TSParameterProperty", + "start":34,"end":63,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":43}}, + "readonly": true, + "override": true, + "parameter": { + "type": "Identifier", + "start":52,"end":63,"loc":{"start":{"line":2,"column":32},"end":{"line":2,"column":43},"identifierName":"foo"}, + "name": "foo", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":55,"end":63,"loc":{"start":{"line":2,"column":35},"end":{"line":2,"column":43}}, + "typeAnnotation": { + "type": "TSStringKeyword", + "start":57,"end":63,"loc":{"start":{"line":2,"column":37},"end":{"line":2,"column":43}} + } + } + } + } + ], + "body": { + "type": "BlockStatement", + "start":65,"end":67,"loc":{"start":{"line":2,"column":45},"end":{"line":2,"column":47}}, + "body": [], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-2/input.ts b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-2/input.ts new file mode 100644 index 000000000000..e291c585e55e --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-2/input.ts @@ -0,0 +1,3 @@ +class D extends B { + constructor(readonly public foo: string) {} +} diff --git a/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-2/output.json b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-2/output.json new file mode 100644 index 000000000000..078fcbedf24f --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-2/output.json @@ -0,0 +1,78 @@ +{ + "type": "File", + "start":0,"end":67,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "errors": [ + "SyntaxError: 'public' modifier must precede 'readonly' modifier. (2:23)" + ], + "program": { + "type": "Program", + "start":0,"end":67,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":67,"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":"D"}, + "name": "D" + }, + "superClass": { + "type": "Identifier", + "start":16,"end":17,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":17},"identifierName":"B"}, + "name": "B" + }, + "body": { + "type": "ClassBody", + "start":18,"end":67,"loc":{"start":{"line":1,"column":18},"end":{"line":3,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":22,"end":65,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":45}}, + "static": false, + "key": { + "type": "Identifier", + "start":22,"end":33,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":13},"identifierName":"constructor"}, + "name": "constructor" + }, + "computed": false, + "kind": "constructor", + "id": null, + "generator": false, + "async": false, + "params": [ + { + "type": "TSParameterProperty", + "start":34,"end":61,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":41}}, + "accessibility": "public", + "readonly": true, + "parameter": { + "type": "Identifier", + "start":50,"end":61,"loc":{"start":{"line":2,"column":30},"end":{"line":2,"column":41},"identifierName":"foo"}, + "name": "foo", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":53,"end":61,"loc":{"start":{"line":2,"column":33},"end":{"line":2,"column":41}}, + "typeAnnotation": { + "type": "TSStringKeyword", + "start":55,"end":61,"loc":{"start":{"line":2,"column":35},"end":{"line":2,"column":41}} + } + } + } + } + ], + "body": { + "type": "BlockStatement", + "start":63,"end":65,"loc":{"start":{"line":2,"column":43},"end":{"line":2,"column":45}}, + "body": [], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-3/input.ts b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-3/input.ts new file mode 100644 index 000000000000..1d9dd7d348ef --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-3/input.ts @@ -0,0 +1,3 @@ +class D extends B { + constructor(override readonly public foo: string) {} +} diff --git a/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-3/output.json b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-3/output.json new file mode 100644 index 000000000000..85f613b166d9 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-invalid-order-modifiers-3/output.json @@ -0,0 +1,80 @@ +{ + "type": "File", + "start":0,"end":76,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "errors": [ + "SyntaxError: 'public' modifier must precede 'override' modifier. (2:32)", + "SyntaxError: 'public' modifier must precede 'readonly' modifier. (2:32)" + ], + "program": { + "type": "Program", + "start":0,"end":76,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":76,"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":"D"}, + "name": "D" + }, + "superClass": { + "type": "Identifier", + "start":16,"end":17,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":17},"identifierName":"B"}, + "name": "B" + }, + "body": { + "type": "ClassBody", + "start":18,"end":76,"loc":{"start":{"line":1,"column":18},"end":{"line":3,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":22,"end":74,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":54}}, + "static": false, + "key": { + "type": "Identifier", + "start":22,"end":33,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":13},"identifierName":"constructor"}, + "name": "constructor" + }, + "computed": false, + "kind": "constructor", + "id": null, + "generator": false, + "async": false, + "params": [ + { + "type": "TSParameterProperty", + "start":34,"end":70,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":50}}, + "accessibility": "public", + "readonly": true, + "override": true, + "parameter": { + "type": "Identifier", + "start":59,"end":70,"loc":{"start":{"line":2,"column":39},"end":{"line":2,"column":50},"identifierName":"foo"}, + "name": "foo", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":62,"end":70,"loc":{"start":{"line":2,"column":42},"end":{"line":2,"column":50}}, + "typeAnnotation": { + "type": "TSStringKeyword", + "start":64,"end":70,"loc":{"start":{"line":2,"column":44},"end":{"line":2,"column":50}} + } + } + } + } + ], + "body": { + "type": "BlockStatement", + "start":72,"end":74,"loc":{"start":{"line":2,"column":52},"end":{"line":2,"column":54}}, + "body": [], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/class/constructor-with-override-modifer-names/input.ts b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-override-modifer-names/input.ts new file mode 100644 index 000000000000..626ede3c87f9 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-override-modifer-names/input.ts @@ -0,0 +1,5 @@ +class D extends B { + constructor(override foo: string) { + super(foo); + } +} diff --git a/packages/babel-parser/test/fixtures/typescript/class/constructor-with-override-modifer-names/output.json b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-override-modifer-names/output.json new file mode 100644 index 000000000000..ebdce9ee80f3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/constructor-with-override-modifer-names/output.json @@ -0,0 +1,94 @@ +{ + "type": "File", + "start":0,"end":79,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":79,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":79,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"D"}, + "name": "D" + }, + "superClass": { + "type": "Identifier", + "start":16,"end":17,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":17},"identifierName":"B"}, + "name": "B" + }, + "body": { + "type": "ClassBody", + "start":18,"end":79,"loc":{"start":{"line":1,"column":18},"end":{"line":5,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":22,"end":77,"loc":{"start":{"line":2,"column":2},"end":{"line":4,"column":3}}, + "static": false, + "key": { + "type": "Identifier", + "start":22,"end":33,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":13},"identifierName":"constructor"}, + "name": "constructor" + }, + "computed": false, + "kind": "constructor", + "id": null, + "generator": false, + "async": false, + "params": [ + { + "type": "TSParameterProperty", + "start":34,"end":54,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":34}}, + "override": true, + "parameter": { + "type": "Identifier", + "start":43,"end":54,"loc":{"start":{"line":2,"column":23},"end":{"line":2,"column":34},"identifierName":"foo"}, + "name": "foo", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":46,"end":54,"loc":{"start":{"line":2,"column":26},"end":{"line":2,"column":34}}, + "typeAnnotation": { + "type": "TSStringKeyword", + "start":48,"end":54,"loc":{"start":{"line":2,"column":28},"end":{"line":2,"column":34}} + } + } + } + } + ], + "body": { + "type": "BlockStatement", + "start":56,"end":77,"loc":{"start":{"line":2,"column":36},"end":{"line":4,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":62,"end":73,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":15}}, + "expression": { + "type": "CallExpression", + "start":62,"end":72,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":14}}, + "callee": { + "type": "Super", + "start":62,"end":67,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":9}} + }, + "arguments": [ + { + "type": "Identifier", + "start":68,"end":71,"loc":{"start":{"line":3,"column":10},"end":{"line":3,"column":13},"identifierName":"foo"}, + "name": "foo" + } + ] + } + } + ], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/class/invalid-modifiers-order/input.ts b/packages/babel-parser/test/fixtures/typescript/class/invalid-modifiers-order/input.ts new file mode 100644 index 000000000000..003d264c477a --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/invalid-modifiers-order/input.ts @@ -0,0 +1,6 @@ +class Foo extends Bar { + override private foo1: string + readonly private foo2: string; + readonly private override foo3: string; + private readonly override foo4: string; +} diff --git a/packages/babel-parser/test/fixtures/typescript/class/invalid-modifiers-order/output.json b/packages/babel-parser/test/fixtures/typescript/class/invalid-modifiers-order/output.json new file mode 100644 index 000000000000..3eb82ef8f26f --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/invalid-modifiers-order/output.json @@ -0,0 +1,130 @@ +{ + "type": "File", + "start":0,"end":174,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "errors": [ + "SyntaxError: 'private' modifier must precede 'override' modifier. (2:11)", + "SyntaxError: 'private' modifier must precede 'readonly' modifier. (3:11)", + "SyntaxError: 'private' modifier must precede 'readonly' modifier. (4:11)", + "SyntaxError: 'override' modifier must precede 'readonly' modifier. (4:19)", + "SyntaxError: 'override' modifier must precede 'readonly' modifier. (5:19)" + ], + "program": { + "type": "Program", + "start":0,"end":174,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":174,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"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": { + "type": "Identifier", + "start":18,"end":21,"loc":{"start":{"line":1,"column":18},"end":{"line":1,"column":21},"identifierName":"Bar"}, + "name": "Bar" + }, + "body": { + "type": "ClassBody", + "start":22,"end":174,"loc":{"start":{"line":1,"column":22},"end":{"line":6,"column":1}}, + "body": [ + { + "type": "ClassProperty", + "start":26,"end":55,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":31}}, + "override": true, + "accessibility": "private", + "static": false, + "key": { + "type": "Identifier", + "start":43,"end":47,"loc":{"start":{"line":2,"column":19},"end":{"line":2,"column":23},"identifierName":"foo1"}, + "name": "foo1" + }, + "computed": false, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":47,"end":55,"loc":{"start":{"line":2,"column":23},"end":{"line":2,"column":31}}, + "typeAnnotation": { + "type": "TSStringKeyword", + "start":49,"end":55,"loc":{"start":{"line":2,"column":25},"end":{"line":2,"column":31}} + } + }, + "value": null + }, + { + "type": "ClassProperty", + "start":58,"end":88,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":32}}, + "readonly": true, + "accessibility": "private", + "static": false, + "key": { + "type": "Identifier", + "start":75,"end":79,"loc":{"start":{"line":3,"column":19},"end":{"line":3,"column":23},"identifierName":"foo2"}, + "name": "foo2" + }, + "computed": false, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":79,"end":87,"loc":{"start":{"line":3,"column":23},"end":{"line":3,"column":31}}, + "typeAnnotation": { + "type": "TSStringKeyword", + "start":81,"end":87,"loc":{"start":{"line":3,"column":25},"end":{"line":3,"column":31}} + } + }, + "value": null + }, + { + "type": "ClassProperty", + "start":91,"end":130,"loc":{"start":{"line":4,"column":2},"end":{"line":4,"column":41}}, + "readonly": true, + "accessibility": "private", + "override": true, + "static": false, + "key": { + "type": "Identifier", + "start":117,"end":121,"loc":{"start":{"line":4,"column":28},"end":{"line":4,"column":32},"identifierName":"foo3"}, + "name": "foo3" + }, + "computed": false, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":121,"end":129,"loc":{"start":{"line":4,"column":32},"end":{"line":4,"column":40}}, + "typeAnnotation": { + "type": "TSStringKeyword", + "start":123,"end":129,"loc":{"start":{"line":4,"column":34},"end":{"line":4,"column":40}} + } + }, + "value": null + }, + { + "type": "ClassProperty", + "start":133,"end":172,"loc":{"start":{"line":5,"column":2},"end":{"line":5,"column":41}}, + "accessibility": "private", + "readonly": true, + "override": true, + "static": false, + "key": { + "type": "Identifier", + "start":159,"end":163,"loc":{"start":{"line":5,"column":28},"end":{"line":5,"column":32},"identifierName":"foo4"}, + "name": "foo4" + }, + "computed": false, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":163,"end":171,"loc":{"start":{"line":5,"column":32},"end":{"line":5,"column":40}}, + "typeAnnotation": { + "type": "TSStringKeyword", + "start":165,"end":171,"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":40}} + } + }, + "value": null + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file