From 12d1cccc4f4818ca68ad16c7911fdcffa94586b7 Mon Sep 17 00:00:00 2001 From: sosukesuzuki Date: Thu, 14 Jan 2021 19:34:50 +0900 Subject: [PATCH 1/8] Parse abstract constructor signature --- .../src/plugins/typescript/index.js | 23 +++++++- packages/babel-parser/src/types.js | 1 + .../abstract-constructor-signatures/input.ts | 1 + .../output.json | 52 +++++++++++++++++++ .../types/constructor-signatures/input.ts | 1 + .../types/constructor-signatures/output.json | 52 +++++++++++++++++++ 6 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 packages/babel-parser/test/fixtures/typescript/types/abstract-constructor-signatures/input.ts create mode 100644 packages/babel-parser/test/fixtures/typescript/types/abstract-constructor-signatures/output.json create mode 100644 packages/babel-parser/test/fixtures/typescript/types/constructor-signatures/input.ts create mode 100644 packages/babel-parser/test/fixtures/typescript/types/constructor-signatures/output.json diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 7a1fbc80cc8d..38beb7022c0d 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -790,10 +790,21 @@ export default (superClass: Class): Class => tsParseFunctionOrConstructorType( type: "TSFunctionType" | "TSConstructorType", + abstract?: boolean, ): N.TsFunctionOrConstructorType { const node: N.TsFunctionOrConstructorType = this.startNode(); if (type === "TSConstructorType") { - this.expect(tt._new); + if (abstract) { + // $FlowIgnore + node.abstract = true; + // eat "abstract" + this.expectContextual("abstract"); + this.expect(tt._new); + } else { + // $FlowIgnore + node.abstract = false; + this.expect(tt._new); + } } this.tsFillSignature(tt.arrow, node); return this.finishNode(node, type); @@ -1219,6 +1230,10 @@ export default (superClass: Class): Class => return this.finishNode(node, "TSConditionalType"); } + isAbstractConstructorSignature(): boolean { + return this.isContextual("abstract") && this.lookahead().type === tt._new; + } + tsParseNonConditionalType(): N.TsType { if (this.tsIsStartOfFunctionType()) { return this.tsParseFunctionOrConstructorType("TSFunctionType"); @@ -1226,6 +1241,12 @@ export default (superClass: Class): Class => if (this.match(tt._new)) { // As in `new () => Date` return this.tsParseFunctionOrConstructorType("TSConstructorType"); + } else if (this.isAbstractConstructorSignature()) { + // As in `abstract new () => Date` + return this.tsParseFunctionOrConstructorType( + "TSConstructorType", + /* abstract */ true, + ); } return this.tsParseUnionTypeOrHigher(); } diff --git a/packages/babel-parser/src/types.js b/packages/babel-parser/src/types.js index d5a28729d41b..1c9d4c02c6bd 100644 --- a/packages/babel-parser/src/types.js +++ b/packages/babel-parser/src/types.js @@ -1250,6 +1250,7 @@ export type TsConstructorType = TsTypeBase & TsSignatureDeclarationBase & { type: "TSConstructorType", typeAnnotation: TsTypeAnnotation, + abstract: boolean, }; export type TsTypeReference = TsTypeBase & { diff --git a/packages/babel-parser/test/fixtures/typescript/types/abstract-constructor-signatures/input.ts b/packages/babel-parser/test/fixtures/typescript/types/abstract-constructor-signatures/input.ts new file mode 100644 index 000000000000..a97259f96888 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/abstract-constructor-signatures/input.ts @@ -0,0 +1 @@ +let x: abstract new () => void = X; diff --git a/packages/babel-parser/test/fixtures/typescript/types/abstract-constructor-signatures/output.json b/packages/babel-parser/test/fixtures/typescript/types/abstract-constructor-signatures/output.json new file mode 100644 index 000000000000..a64414ea8902 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/abstract-constructor-signatures/output.json @@ -0,0 +1,52 @@ +{ + "type": "File", + "start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}}, + "program": { + "type": "Program", + "start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "VariableDeclaration", + "start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}}, + "declarations": [ + { + "type": "VariableDeclarator", + "start":4,"end":34,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":34}}, + "id": { + "type": "Identifier", + "start":4,"end":30,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":30},"identifierName":"x"}, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":5,"end":30,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":30}}, + "typeAnnotation": { + "type": "TSConstructorType", + "start":7,"end":30,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":30}}, + "abstract": true, + "parameters": [], + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":23,"end":30,"loc":{"start":{"line":1,"column":23},"end":{"line":1,"column":30}}, + "typeAnnotation": { + "type": "TSVoidKeyword", + "start":26,"end":30,"loc":{"start":{"line":1,"column":26},"end":{"line":1,"column":30}} + } + } + } + } + }, + "init": { + "type": "Identifier", + "start":33,"end":34,"loc":{"start":{"line":1,"column":33},"end":{"line":1,"column":34},"identifierName":"X"}, + "name": "X" + } + } + ], + "kind": "let" + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/constructor-signatures/input.ts b/packages/babel-parser/test/fixtures/typescript/types/constructor-signatures/input.ts new file mode 100644 index 000000000000..64ed0e7cdcca --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/constructor-signatures/input.ts @@ -0,0 +1 @@ +let x: new () => void = X; diff --git a/packages/babel-parser/test/fixtures/typescript/types/constructor-signatures/output.json b/packages/babel-parser/test/fixtures/typescript/types/constructor-signatures/output.json new file mode 100644 index 000000000000..e616d855034d --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/constructor-signatures/output.json @@ -0,0 +1,52 @@ +{ + "type": "File", + "start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}}, + "program": { + "type": "Program", + "start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "VariableDeclaration", + "start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}}, + "declarations": [ + { + "type": "VariableDeclarator", + "start":4,"end":25,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":25}}, + "id": { + "type": "Identifier", + "start":4,"end":21,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":21},"identifierName":"x"}, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":5,"end":21,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":21}}, + "typeAnnotation": { + "type": "TSConstructorType", + "start":7,"end":21,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":21}}, + "abstract": false, + "parameters": [], + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":14,"end":21,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":21}}, + "typeAnnotation": { + "type": "TSVoidKeyword", + "start":17,"end":21,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":21}} + } + } + } + } + }, + "init": { + "type": "Identifier", + "start":24,"end":25,"loc":{"start":{"line":1,"column":24},"end":{"line":1,"column":25},"identifierName":"X"}, + "name": "X" + } + } + ], + "kind": "let" + } + ], + "directives": [] + } +} \ No newline at end of file From 526faa13ddb87a4f917dedac0c5f1ca6d9ce8812 Mon Sep 17 00:00:00 2001 From: sosukesuzuki Date: Thu, 14 Jan 2021 21:20:28 +0900 Subject: [PATCH 2/8] babel-types --- .../babel-types/src/definitions/typescript.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/babel-types/src/definitions/typescript.ts b/packages/babel-types/src/definitions/typescript.ts index 23075cf40ff3..7e55d71ac9e8 100644 --- a/packages/babel-types/src/definitions/typescript.ts +++ b/packages/babel-types/src/definitions/typescript.ts @@ -157,14 +157,22 @@ defineType("TSThisType", { fields: {}, }); -const fnOrCtr = { +const fnOrCtrBase = { aliases: ["TSType"], visitor: ["typeParameters", "parameters", "typeAnnotation"], - fields: signatureDeclarationCommon, }; -defineType("TSFunctionType", fnOrCtr); -defineType("TSConstructorType", fnOrCtr); +defineType("TSFunctionType", { + ...fnOrCtrBase, + fields: signatureDeclarationCommon, +}); +defineType("TSConstructorType", { + ...fnOrCtrBase, + fields: { + ...signatureDeclarationCommon, + abstract: validateOptional(bool), + }, +}); defineType("TSTypeReference", { aliases: ["TSType"], From 4a496aed10509d063fc85b8a5491e7b3f2e906c2 Mon Sep 17 00:00:00 2001 From: sosukesuzuki Date: Thu, 14 Jan 2021 21:31:34 +0900 Subject: [PATCH 3/8] babel-generator --- packages/babel-generator/src/generators/typescript.ts | 4 ++++ .../typescript/abstract-constructor-signature-types/input.js | 1 + .../typescript/abstract-constructor-signature-types/output.js | 1 + .../fixtures/typescript/constructor-signature-types/input.js | 1 + .../fixtures/typescript/constructor-signature-types/output.js | 1 + 5 files changed, 8 insertions(+) create mode 100644 packages/babel-generator/test/fixtures/typescript/abstract-constructor-signature-types/input.js create mode 100644 packages/babel-generator/test/fixtures/typescript/abstract-constructor-signature-types/output.js create mode 100644 packages/babel-generator/test/fixtures/typescript/constructor-signature-types/input.js create mode 100644 packages/babel-generator/test/fixtures/typescript/constructor-signature-types/output.js diff --git a/packages/babel-generator/src/generators/typescript.ts b/packages/babel-generator/src/generators/typescript.ts index 9c18ab0a0bfc..14375b0beac5 100644 --- a/packages/babel-generator/src/generators/typescript.ts +++ b/packages/babel-generator/src/generators/typescript.ts @@ -194,6 +194,10 @@ export function TSFunctionType(this: Printer, node: t.TSFunctionType) { } export function TSConstructorType(this: Printer, node: t.TSConstructorType) { + if (node.abstract) { + this.word("abstract"); + this.space(); + } this.word("new"); this.space(); this.tsPrintFunctionOrConstructorType(node); diff --git a/packages/babel-generator/test/fixtures/typescript/abstract-constructor-signature-types/input.js b/packages/babel-generator/test/fixtures/typescript/abstract-constructor-signature-types/input.js new file mode 100644 index 000000000000..fbaa3a91c4a4 --- /dev/null +++ b/packages/babel-generator/test/fixtures/typescript/abstract-constructor-signature-types/input.js @@ -0,0 +1 @@ +const x: abstract new () => void; diff --git a/packages/babel-generator/test/fixtures/typescript/abstract-constructor-signature-types/output.js b/packages/babel-generator/test/fixtures/typescript/abstract-constructor-signature-types/output.js new file mode 100644 index 000000000000..5c520bc29f3c --- /dev/null +++ b/packages/babel-generator/test/fixtures/typescript/abstract-constructor-signature-types/output.js @@ -0,0 +1 @@ +const x: abstract new () => void; \ No newline at end of file diff --git a/packages/babel-generator/test/fixtures/typescript/constructor-signature-types/input.js b/packages/babel-generator/test/fixtures/typescript/constructor-signature-types/input.js new file mode 100644 index 000000000000..c1fc7b6057c6 --- /dev/null +++ b/packages/babel-generator/test/fixtures/typescript/constructor-signature-types/input.js @@ -0,0 +1 @@ +const x: new () => void; diff --git a/packages/babel-generator/test/fixtures/typescript/constructor-signature-types/output.js b/packages/babel-generator/test/fixtures/typescript/constructor-signature-types/output.js new file mode 100644 index 000000000000..218e27130c01 --- /dev/null +++ b/packages/babel-generator/test/fixtures/typescript/constructor-signature-types/output.js @@ -0,0 +1 @@ +const x: new () => void; \ No newline at end of file From 8ba6c8924b5a99b305ca743a9531cfe957f00b51 Mon Sep 17 00:00:00 2001 From: sosukesuzuki Date: Thu, 14 Jan 2021 22:10:54 +0900 Subject: [PATCH 4/8] Add more tests for parser --- .../types/types-named-abstract/input.ts | 2 + .../types/types-named-abstract/output.json | 65 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 packages/babel-parser/test/fixtures/typescript/types/types-named-abstract/input.ts create mode 100644 packages/babel-parser/test/fixtures/typescript/types/types-named-abstract/output.json diff --git a/packages/babel-parser/test/fixtures/typescript/types/types-named-abstract/input.ts b/packages/babel-parser/test/fixtures/typescript/types/types-named-abstract/input.ts new file mode 100644 index 000000000000..9e2956945277 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/types-named-abstract/input.ts @@ -0,0 +1,2 @@ +type abstract = "abstract"; +let x: abstract; diff --git a/packages/babel-parser/test/fixtures/typescript/types/types-named-abstract/output.json b/packages/babel-parser/test/fixtures/typescript/types/types-named-abstract/output.json new file mode 100644 index 000000000000..4cf4d9086cad --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/types-named-abstract/output.json @@ -0,0 +1,65 @@ +{ + "type": "File", + "start":0,"end":44,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":16}}, + "program": { + "type": "Program", + "start":0,"end":44,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":16}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start":0,"end":27,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}}, + "id": { + "type": "Identifier", + "start":5,"end":13,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":13},"identifierName":"abstract"}, + "name": "abstract" + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start":16,"end":26,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":26}}, + "literal": { + "type": "StringLiteral", + "start":16,"end":26,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":26}}, + "extra": { + "rawValue": "abstract", + "raw": "\"abstract\"" + }, + "value": "abstract" + } + } + }, + { + "type": "VariableDeclaration", + "start":28,"end":44,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":16}}, + "declarations": [ + { + "type": "VariableDeclarator", + "start":32,"end":43,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":15}}, + "id": { + "type": "Identifier", + "start":32,"end":43,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":15},"identifierName":"x"}, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":33,"end":43,"loc":{"start":{"line":2,"column":5},"end":{"line":2,"column":15}}, + "typeAnnotation": { + "type": "TSTypeReference", + "start":35,"end":43,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":15}}, + "typeName": { + "type": "Identifier", + "start":35,"end":43,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":15},"identifierName":"abstract"}, + "name": "abstract" + } + } + } + }, + "init": null + } + ], + "kind": "let" + } + ], + "directives": [] + } +} \ No newline at end of file From 3bfe2a8afa7c4d4f9e7314151ad26e2165923220 Mon Sep 17 00:00:00 2001 From: sosukesuzuki Date: Thu, 14 Jan 2021 23:11:55 +0900 Subject: [PATCH 5/8] Refactor --- packages/babel-parser/src/plugins/typescript/index.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 38beb7022c0d..b271aa4139c4 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -794,15 +794,13 @@ export default (superClass: Class): Class => ): N.TsFunctionOrConstructorType { const node: N.TsFunctionOrConstructorType = this.startNode(); if (type === "TSConstructorType") { + // $FlowIgnore + node.abstract = !!abstract; if (abstract) { - // $FlowIgnore - node.abstract = true; // eat "abstract" this.expectContextual("abstract"); this.expect(tt._new); } else { - // $FlowIgnore - node.abstract = false; this.expect(tt._new); } } From 524c5efe48be7d5f8b6bf08ea3f39afd9562e443 Mon Sep 17 00:00:00 2001 From: sosukesuzuki Date: Thu, 14 Jan 2021 23:36:08 +0900 Subject: [PATCH 6/8] Address reviews --- packages/babel-parser/src/plugins/typescript/index.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index b271aa4139c4..11ee466f8805 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -796,13 +796,8 @@ export default (superClass: Class): Class => if (type === "TSConstructorType") { // $FlowIgnore node.abstract = !!abstract; - if (abstract) { - // eat "abstract" - this.expectContextual("abstract"); - this.expect(tt._new); - } else { - this.expect(tt._new); - } + if (abstract) this.next(); + this.expect(tt._new); } this.tsFillSignature(tt.arrow, node); return this.finishNode(node, type); From c658d097bccc038d55546554bf4ff45ee827d7ad Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Fri, 15 Jan 2021 00:29:07 +0900 Subject: [PATCH 7/8] Update packages/babel-parser/src/plugins/typescript/index.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Huáng Jùnliàng --- 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 11ee466f8805..ef3e4b4f349a 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -797,7 +797,7 @@ export default (superClass: Class): Class => // $FlowIgnore node.abstract = !!abstract; if (abstract) this.next(); - this.expect(tt._new); + this.next(); // eat `new` } this.tsFillSignature(tt.arrow, node); return this.finishNode(node, type); From d6c4d07e456c5c720708a5e619839ec2bcaef4cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Sun, 21 Feb 2021 19:23:55 +0100 Subject: [PATCH 8/8] Update after rebase --- packages/babel-types/src/ast-types/generated/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/babel-types/src/ast-types/generated/index.ts b/packages/babel-types/src/ast-types/generated/index.ts index ced0274bc549..8d482061ffd4 100755 --- a/packages/babel-types/src/ast-types/generated/index.ts +++ b/packages/babel-types/src/ast-types/generated/index.ts @@ -1767,6 +1767,7 @@ export interface TSConstructorType extends BaseNode { typeParameters?: TSTypeParameterDeclaration | null; parameters: Array; typeAnnotation?: TSTypeAnnotation | null; + abstract?: boolean | null; } export interface TSTypeReference extends BaseNode {