diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 6a0756107d..c11dd2ace0 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -1689,7 +1689,7 @@ export default (superClass: Class): Class => kind = "let"; } - return this.tsInDeclareContext(() => { + return this.tsInAmbientContext(() => { switch (starttype) { case tt._function: nany.declare = true; @@ -1979,7 +1979,7 @@ export default (superClass: Class): Class => this.finishNode(node, bodilessType); return; } - if (bodilessType === "TSDeclareFunction" && this.state.isDeclareContext) { + if (bodilessType === "TSDeclareFunction" && this.state.isAmbientContext) { this.raise(node.start, TSErrors.DeclareFunctionHasImplementation); if ( // $FlowIgnore @@ -2342,7 +2342,7 @@ export default (superClass: Class): Class => ); }; if (member.declare) { - this.tsInDeclareContext(callParseClassMember); + this.tsInAmbientContext(callParseClassMember); } else { callParseClassMember(); } @@ -2569,7 +2569,7 @@ export default (superClass: Class): Class => parseClassProperty(node: N.ClassProperty): N.ClassProperty { this.parseClassPropertyAnnotation(node); - if (this.state.isDeclareContext && this.match(tt.eq)) { + if (this.state.isAmbientContext && this.match(tt.eq)) { this.raise(this.state.start, TSErrors.DeclareClassFieldHasInitializer); } @@ -2824,7 +2824,7 @@ export default (superClass: Class): Class => if (this.eat(tt.question)) { if ( param.type !== "Identifier" && - !this.state.isDeclareContext && + !this.state.isAmbientContext && !this.state.inType ) { this.raise(param.start, TSErrors.PatternIsOptional); @@ -2935,7 +2935,7 @@ export default (superClass: Class): Class => checkCommaAfterRest(close) { if ( - this.state.isDeclareContext && + this.state.isAmbientContext && this.match(tt.comma) && this.lookaheadCharCode() === close ) { @@ -3081,13 +3081,13 @@ export default (superClass: Class): Class => return param; } - tsInDeclareContext(cb: () => T): T { - const oldIsDeclareContext = this.state.isDeclareContext; - this.state.isDeclareContext = true; + tsInAmbientContext(cb: () => T): T { + const oldIsAmbientContext = this.state.isAmbientContext; + this.state.isAmbientContext = true; try { return cb(); } finally { - this.state.isDeclareContext = oldIsDeclareContext; + this.state.isAmbientContext = oldIsAmbientContext; } } @@ -3152,4 +3152,22 @@ export default (superClass: Class): Class => } return method; } + + shouldParseAsAmbientContext(): boolean { + return !!this.getPluginOption("typescript", "dts"); + } + + parse() { + if (this.shouldParseAsAmbientContext()) { + this.state.isAmbientContext = true; + } + return super.parse(); + } + + getExpression() { + if (this.shouldParseAsAmbientContext()) { + this.state.isAmbientContext = true; + } + return super.getExpression(); + } }; diff --git a/packages/babel-parser/src/tokenizer/state.js b/packages/babel-parser/src/tokenizer/state.js index d2bdd96369..2dd357c191 100644 --- a/packages/babel-parser/src/tokenizer/state.js +++ b/packages/babel-parser/src/tokenizer/state.js @@ -65,7 +65,7 @@ export default class State { inPropertyName: boolean = false; hasFlowComment: boolean = false; isIterator: boolean = false; - isDeclareContext: boolean = false; + isAmbientContext: boolean = false; inAbstractClass: boolean = false; // For the smartPipelines plugin: diff --git a/packages/babel-parser/test/fixtures/typescript/dts/invalid-class-implementation/input.ts b/packages/babel-parser/test/fixtures/typescript/dts/invalid-class-implementation/input.ts new file mode 100644 index 0000000000..a39e5fb90d --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/dts/invalid-class-implementation/input.ts @@ -0,0 +1 @@ +function foo(): any {} diff --git a/packages/babel-parser/test/fixtures/typescript/dts/invalid-class-implementation/output.json b/packages/babel-parser/test/fixtures/typescript/dts/invalid-class-implementation/output.json new file mode 100644 index 0000000000..f521d5ac35 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/dts/invalid-class-implementation/output.json @@ -0,0 +1,42 @@ +{ + "type": "File", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}}, + "errors": [ + "SyntaxError: An implementation cannot be declared in ambient contexts. (1:0)" + ], + "program": { + "type": "Program", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "FunctionDeclaration", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}}, + "id": { + "type": "Identifier", + "start":9,"end":12,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "generator": false, + "async": false, + "params": [], + "returnType": { + "type": "TSTypeAnnotation", + "start":14,"end":19,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":19}}, + "typeAnnotation": { + "type": "TSAnyKeyword", + "start":16,"end":19,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":19}} + } + }, + "body": { + "type": "BlockStatement", + "start":20,"end":22,"loc":{"start":{"line":1,"column":20},"end":{"line":1,"column":22}}, + "body": [], + "directives": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/dts/invalid-class-initializer/input.ts b/packages/babel-parser/test/fixtures/typescript/dts/invalid-class-initializer/input.ts new file mode 100644 index 0000000000..b03ef6bed7 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/dts/invalid-class-initializer/input.ts @@ -0,0 +1,3 @@ +class Foo { + foo = 3; +} diff --git a/packages/babel-parser/test/fixtures/typescript/dts/invalid-class-initializer/output.json b/packages/babel-parser/test/fixtures/typescript/dts/invalid-class-initializer/output.json new file mode 100644 index 0000000000..2ee49774bf --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/dts/invalid-class-initializer/output.json @@ -0,0 +1,52 @@ +{ + "type": "File", + "start":0,"end":24,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "errors": [ + "SyntaxError: Initializers are not allowed in ambient contexts. (2:6)" + ], + "program": { + "type": "Program", + "start":0,"end":24,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":24,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"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":24,"loc":{"start":{"line":1,"column":10},"end":{"line":3,"column":1}}, + "body": [ + { + "type": "ClassProperty", + "start":14,"end":22,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":10}}, + "static": false, + "key": { + "type": "Identifier", + "start":14,"end":17,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":5},"identifierName":"foo"}, + "name": "foo" + }, + "computed": false, + "value": { + "type": "NumericLiteral", + "start":20,"end":21,"loc":{"start":{"line":2,"column":8},"end":{"line":2,"column":9}}, + "extra": { + "rawValue": 3, + "raw": "3" + }, + "value": 3 + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/dts/options.json b/packages/babel-parser/test/fixtures/typescript/dts/options.json new file mode 100644 index 0000000000..556af06f63 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/dts/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["typescript", { "dts": true }], "classProperties"] +} diff --git a/packages/babel-parser/test/fixtures/typescript/dts/valid-optional-pattern/input.ts b/packages/babel-parser/test/fixtures/typescript/dts/valid-optional-pattern/input.ts new file mode 100644 index 0000000000..6c17e7dc58 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/dts/valid-optional-pattern/input.ts @@ -0,0 +1 @@ +function f([]?): any; diff --git a/packages/babel-parser/test/fixtures/typescript/dts/valid-optional-pattern/output.json b/packages/babel-parser/test/fixtures/typescript/dts/valid-optional-pattern/output.json new file mode 100644 index 0000000000..b784640ec1 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/dts/valid-optional-pattern/output.json @@ -0,0 +1,40 @@ +{ + "type": "File", + "start":0,"end":21,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":21}}, + "program": { + "type": "Program", + "start":0,"end":21,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":21}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "TSDeclareFunction", + "start":0,"end":21,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":21}}, + "id": { + "type": "Identifier", + "start":9,"end":10,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":10},"identifierName":"f"}, + "name": "f" + }, + "generator": false, + "async": false, + "params": [ + { + "type": "ArrayPattern", + "start":11,"end":14,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":14}}, + "elements": [], + "optional": true + } + ], + "returnType": { + "type": "TSTypeAnnotation", + "start":15,"end":20,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":20}}, + "typeAnnotation": { + "type": "TSAnyKeyword", + "start":17,"end":20,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":20}} + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/dts/valid-trailing-comma-for-rest/input.ts b/packages/babel-parser/test/fixtures/typescript/dts/valid-trailing-comma-for-rest/input.ts new file mode 100644 index 0000000000..bab3cff958 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/dts/valid-trailing-comma-for-rest/input.ts @@ -0,0 +1 @@ +function foo(...args: any[], ); diff --git a/packages/babel-parser/test/fixtures/typescript/dts/valid-trailing-comma-for-rest/output.json b/packages/babel-parser/test/fixtures/typescript/dts/valid-trailing-comma-for-rest/output.json new file mode 100644 index 0000000000..62bf4f6d7f --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/dts/valid-trailing-comma-for-rest/output.json @@ -0,0 +1,47 @@ +{ + "type": "File", + "start":0,"end":31,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":31}}, + "program": { + "type": "Program", + "start":0,"end":31,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":31}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "TSDeclareFunction", + "start":0,"end":31,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":31}}, + "id": { + "type": "Identifier", + "start":9,"end":12,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":12},"identifierName":"foo"}, + "name": "foo" + }, + "generator": false, + "async": false, + "params": [ + { + "type": "RestElement", + "start":13,"end":27,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":27}}, + "argument": { + "type": "Identifier", + "start":16,"end":20,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":20},"identifierName":"args"}, + "name": "args" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":20,"end":27,"loc":{"start":{"line":1,"column":20},"end":{"line":1,"column":27}}, + "typeAnnotation": { + "type": "TSArrayType", + "start":22,"end":27,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":27}}, + "elementType": { + "type": "TSAnyKeyword", + "start":22,"end":25,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":25}} + } + } + } + } + ] + } + ], + "directives": [] + } +} \ No newline at end of file