From 06c48c06ba1d17cb690ec8168d67d1c7d72a7ff7 Mon Sep 17 00:00:00 2001 From: Harpica Date: Fri, 24 Feb 2023 14:34:20 +0300 Subject: [PATCH 1/6] [ts] fix: keywords in labeled tuples (#13702) --- .../src/plugins/typescript/index.ts | 40 +-- .../types/tuple-keyword-labeled/input.ts | 9 + .../types/tuple-keyword-labeled/output.json | 235 ++++++++++++++++++ 3 files changed, 267 insertions(+), 17 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/input.ts create mode 100644 packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json diff --git a/packages/babel-parser/src/plugins/typescript/index.ts b/packages/babel-parser/src/plugins/typescript/index.ts index 7f1b9e9829f3..cbd6a6b8a086 100644 --- a/packages/babel-parser/src/plugins/typescript/index.ts +++ b/packages/babel-parser/src/plugins/typescript/index.ts @@ -11,6 +11,7 @@ import { type TokenType, tokenIsTemplate, tokenCanStartExpression, + tokenIsKeyword, } from "../../tokenizer/types"; import { types as tc } from "../../tokenizer/context"; import type * as N from "../../types"; @@ -1099,13 +1100,16 @@ export default (superClass: ClassWithMixin) => return this.finishNode(node, "TSTupleType"); } - tsParseTupleElementType(): N.TsType | N.TsNamedTupleMember { + tsParseTupleElementType(): N.TsNamedTupleMember | N.TsType { // parses `...TsType[]` const { startLoc } = this.state; const rest = this.eat(tt.ellipsis); - let type: N.TsType | N.TsNamedTupleMember = this.tsParseType(); + const isKeyword = tokenIsKeyword(this.state.type); + let type: N.TsNamedTupleMember | N.TsType | N.Identifier = isKeyword + ? this.parseIdentifier(true) + : this.tsParseType(); const optional = this.eat(tt.question); const labeled = this.eat(tt.colon); @@ -1113,34 +1117,36 @@ export default (superClass: ClassWithMixin) => const labeledNode = this.startNodeAtNode(type); labeledNode.optional = optional; - if ( - type.type === "TSTypeReference" && - !type.typeParameters && - type.typeName.type === "Identifier" - ) { - labeledNode.label = type.typeName; + if (isKeyword) { + labeledNode.label = type as N.Identifier; } else { - this.raise(TSErrors.InvalidTupleMemberLabel, { at: type }); - // @ts-expect-error This produces an invalid AST, but at least we don't drop - // nodes representing the invalid source. - labeledNode.label = type; + if ( + type.type === "TSTypeReference" && + !type.typeParameters && + type.typeName.type === "Identifier" + ) { + labeledNode.label = type.typeName; + } else { + this.raise(TSErrors.InvalidTupleMemberLabel, { at: type }); + // @ts-expect-error This produces an invalid AST, but at least we don't drop + // nodes representing the invalid source. + labeledNode.label = type; + } } - labeledNode.elementType = this.tsParseType(); type = this.finishNode(labeledNode, "TSNamedTupleMember"); } else if (optional) { const optionalTypeNode = this.startNodeAtNode(type); - optionalTypeNode.typeAnnotation = type; + optionalTypeNode.typeAnnotation = type as N.TsType; type = this.finishNode(optionalTypeNode, "TSOptionalType"); } - if (rest) { const restNode = this.startNodeAt(startLoc); - restNode.typeAnnotation = type; + restNode.typeAnnotation = type as N.TsType; type = this.finishNode(restNode, "TSRestType"); } - return type; + return type as N.TsNamedTupleMember | N.TsType; } tsParseParenthesizedType(): N.TsParenthesizedType { diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/input.ts new file mode 100644 index 000000000000..c97b346bf9e0 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/input.ts @@ -0,0 +1,9 @@ +type FuncWithDescription = [ + function: (...args: any[]) => any, + string: string +] + +const fnWithDescriptions: FuncWithDescription[] = [ + [(x:number) => x, "return the number"], + [(x:number, y:number) => x*y, "multiply the numbers"] +] diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json new file mode 100644 index 000000000000..fc9f3ece47cd --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json @@ -0,0 +1,235 @@ +{ + "type": "File", + "start":0,"end":237,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":9,"column":1,"index":237}}, + "errors": [ + "SyntaxError: Tuple members must be labeled with a simple identifier. (3:2)" + ], + "program": { + "type": "Program", + "start":0,"end":237,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":9,"column":1,"index":237}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start":0,"end":84,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":84}}, + "id": { + "type": "Identifier", + "start":5,"end":24,"loc":{"start":{"line":1,"column":5,"index":5},"end":{"line":1,"column":24,"index":24},"identifierName":"FuncWithDescription"}, + "name": "FuncWithDescription" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start":27,"end":84,"loc":{"start":{"line":1,"column":27,"index":27},"end":{"line":4,"column":1,"index":84}}, + "elementTypes": [ + { + "type": "TSNamedTupleMember", + "start":31,"end":64,"loc":{"start":{"line":2,"column":2,"index":31},"end":{"line":2,"column":35,"index":64}}, + "optional": false, + "label": { + "type": "Identifier", + "start":31,"end":39,"loc":{"start":{"line":2,"column":2,"index":31},"end":{"line":2,"column":10,"index":39},"identifierName":"function"}, + "name": "function" + }, + "elementType": { + "type": "TSFunctionType", + "start":41,"end":64,"loc":{"start":{"line":2,"column":12,"index":41},"end":{"line":2,"column":35,"index":64}}, + "parameters": [ + { + "type": "RestElement", + "start":42,"end":56,"loc":{"start":{"line":2,"column":13,"index":42},"end":{"line":2,"column":27,"index":56}}, + "argument": { + "type": "Identifier", + "start":45,"end":49,"loc":{"start":{"line":2,"column":16,"index":45},"end":{"line":2,"column":20,"index":49},"identifierName":"args"}, + "name": "args" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":49,"end":56,"loc":{"start":{"line":2,"column":20,"index":49},"end":{"line":2,"column":27,"index":56}}, + "typeAnnotation": { + "type": "TSArrayType", + "start":51,"end":56,"loc":{"start":{"line":2,"column":22,"index":51},"end":{"line":2,"column":27,"index":56}}, + "elementType": { + "type": "TSAnyKeyword", + "start":51,"end":54,"loc":{"start":{"line":2,"column":22,"index":51},"end":{"line":2,"column":25,"index":54}} + } + } + } + } + ], + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":58,"end":64,"loc":{"start":{"line":2,"column":29,"index":58},"end":{"line":2,"column":35,"index":64}}, + "typeAnnotation": { + "type": "TSAnyKeyword", + "start":61,"end":64,"loc":{"start":{"line":2,"column":32,"index":61},"end":{"line":2,"column":35,"index":64}} + } + } + } + }, + { + "type": "TSNamedTupleMember", + "start":68,"end":82,"loc":{"start":{"line":3,"column":2,"index":68},"end":{"line":3,"column":16,"index":82}}, + "optional": false, + "label": { + "type": "TSStringKeyword", + "start":68,"end":74,"loc":{"start":{"line":3,"column":2,"index":68},"end":{"line":3,"column":8,"index":74}} + }, + "elementType": { + "type": "TSStringKeyword", + "start":76,"end":82,"loc":{"start":{"line":3,"column":10,"index":76},"end":{"line":3,"column":16,"index":82}} + } + } + ] + } + }, + { + "type": "VariableDeclaration", + "start":86,"end":237,"loc":{"start":{"line":6,"column":0,"index":86},"end":{"line":9,"column":1,"index":237}}, + "declarations": [ + { + "type": "VariableDeclarator", + "start":92,"end":237,"loc":{"start":{"line":6,"column":6,"index":92},"end":{"line":9,"column":1,"index":237}}, + "id": { + "type": "Identifier", + "start":92,"end":133,"loc":{"start":{"line":6,"column":6,"index":92},"end":{"line":6,"column":47,"index":133},"identifierName":"fnWithDescriptions"}, + "name": "fnWithDescriptions", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":110,"end":133,"loc":{"start":{"line":6,"column":24,"index":110},"end":{"line":6,"column":47,"index":133}}, + "typeAnnotation": { + "type": "TSArrayType", + "start":112,"end":133,"loc":{"start":{"line":6,"column":26,"index":112},"end":{"line":6,"column":47,"index":133}}, + "elementType": { + "type": "TSTypeReference", + "start":112,"end":131,"loc":{"start":{"line":6,"column":26,"index":112},"end":{"line":6,"column":45,"index":131}}, + "typeName": { + "type": "Identifier", + "start":112,"end":131,"loc":{"start":{"line":6,"column":26,"index":112},"end":{"line":6,"column":45,"index":131},"identifierName":"FuncWithDescription"}, + "name": "FuncWithDescription" + } + } + } + } + }, + "init": { + "type": "ArrayExpression", + "start":136,"end":237,"loc":{"start":{"line":6,"column":50,"index":136},"end":{"line":9,"column":1,"index":237}}, + "elements": [ + { + "type": "ArrayExpression", + "start":140,"end":178,"loc":{"start":{"line":7,"column":2,"index":140},"end":{"line":7,"column":40,"index":178}}, + "elements": [ + { + "type": "ArrowFunctionExpression", + "start":141,"end":156,"loc":{"start":{"line":7,"column":3,"index":141},"end":{"line":7,"column":18,"index":156}}, + "id": null, + "generator": false, + "async": false, + "params": [ + { + "type": "Identifier", + "start":142,"end":150,"loc":{"start":{"line":7,"column":4,"index":142},"end":{"line":7,"column":12,"index":150},"identifierName":"x"}, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":143,"end":150,"loc":{"start":{"line":7,"column":5,"index":143},"end":{"line":7,"column":12,"index":150}}, + "typeAnnotation": { + "type": "TSNumberKeyword", + "start":144,"end":150,"loc":{"start":{"line":7,"column":6,"index":144},"end":{"line":7,"column":12,"index":150}} + } + } + } + ], + "body": { + "type": "Identifier", + "start":155,"end":156,"loc":{"start":{"line":7,"column":17,"index":155},"end":{"line":7,"column":18,"index":156},"identifierName":"x"}, + "name": "x" + } + }, + { + "type": "StringLiteral", + "start":158,"end":177,"loc":{"start":{"line":7,"column":20,"index":158},"end":{"line":7,"column":39,"index":177}}, + "extra": { + "rawValue": "return the number", + "raw": "\"return the number\"" + }, + "value": "return the number" + } + ] + }, + { + "type": "ArrayExpression", + "start":182,"end":235,"loc":{"start":{"line":8,"column":2,"index":182},"end":{"line":8,"column":55,"index":235}}, + "elements": [ + { + "type": "ArrowFunctionExpression", + "start":183,"end":210,"loc":{"start":{"line":8,"column":3,"index":183},"end":{"line":8,"column":30,"index":210}}, + "id": null, + "generator": false, + "async": false, + "params": [ + { + "type": "Identifier", + "start":184,"end":192,"loc":{"start":{"line":8,"column":4,"index":184},"end":{"line":8,"column":12,"index":192},"identifierName":"x"}, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":185,"end":192,"loc":{"start":{"line":8,"column":5,"index":185},"end":{"line":8,"column":12,"index":192}}, + "typeAnnotation": { + "type": "TSNumberKeyword", + "start":186,"end":192,"loc":{"start":{"line":8,"column":6,"index":186},"end":{"line":8,"column":12,"index":192}} + } + } + }, + { + "type": "Identifier", + "start":194,"end":202,"loc":{"start":{"line":8,"column":14,"index":194},"end":{"line":8,"column":22,"index":202},"identifierName":"y"}, + "name": "y", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":195,"end":202,"loc":{"start":{"line":8,"column":15,"index":195},"end":{"line":8,"column":22,"index":202}}, + "typeAnnotation": { + "type": "TSNumberKeyword", + "start":196,"end":202,"loc":{"start":{"line":8,"column":16,"index":196},"end":{"line":8,"column":22,"index":202}} + } + } + } + ], + "body": { + "type": "BinaryExpression", + "start":207,"end":210,"loc":{"start":{"line":8,"column":27,"index":207},"end":{"line":8,"column":30,"index":210}}, + "left": { + "type": "Identifier", + "start":207,"end":208,"loc":{"start":{"line":8,"column":27,"index":207},"end":{"line":8,"column":28,"index":208},"identifierName":"x"}, + "name": "x" + }, + "operator": "*", + "right": { + "type": "Identifier", + "start":209,"end":210,"loc":{"start":{"line":8,"column":29,"index":209},"end":{"line":8,"column":30,"index":210},"identifierName":"y"}, + "name": "y" + } + } + }, + { + "type": "StringLiteral", + "start":212,"end":234,"loc":{"start":{"line":8,"column":32,"index":212},"end":{"line":8,"column":54,"index":234}}, + "extra": { + "rawValue": "multiply the numbers", + "raw": "\"multiply the numbers\"" + }, + "value": "multiply the numbers" + } + ] + } + ] + } + } + ], + "kind": "const" + } + ], + "directives": [] + } +} From f5465eabf8dc3d2ce20ba513a5d77d9d0119864e Mon Sep 17 00:00:00 2001 From: Harpica Date: Fri, 24 Feb 2023 14:34:20 +0300 Subject: [PATCH 2/6] fix: babel 8 tests --- .../tuple-keyword-labeled-babel-7/input.ts | 4 + .../options.json | 3 + .../tuple-keyword-labeled-babel-7/output.json | 89 ++++++++++ .../types/tuple-keyword-labeled/input.ts | 5 - .../types/tuple-keyword-labeled/options.json | 3 + .../types/tuple-keyword-labeled/output.json | 154 +----------------- 6 files changed, 103 insertions(+), 155 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/input.ts create mode 100644 packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/options.json create mode 100644 packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/output.json create mode 100644 packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/options.json diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/input.ts new file mode 100644 index 000000000000..dc2583d50c5c --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/input.ts @@ -0,0 +1,4 @@ +type FuncWithDescriptionBabel7 = [ + function: (...args: any[]) => any, + string: string +] diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/options.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/options.json new file mode 100644 index 000000000000..29a3f0e84167 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/options.json @@ -0,0 +1,3 @@ +{ + "BABEL_8_BREAKING": false +} diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/output.json new file mode 100644 index 000000000000..0d5656bcb4dc --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/output.json @@ -0,0 +1,89 @@ +{ + "type": "File", + "start":0,"end":90,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":90}}, + "errors": [ + "SyntaxError: Tuple members must be labeled with a simple identifier. (3:2)" + ], + "program": { + "type": "Program", + "start":0,"end":90,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":90}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start":0,"end":90,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":90}}, + "id": { + "type": "Identifier", + "start":5,"end":30,"loc":{"start":{"line":1,"column":5,"index":5},"end":{"line":1,"column":30,"index":30},"identifierName":"FuncWithDescriptionBabel7"}, + "name": "FuncWithDescriptionBabel7" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start":33,"end":90,"loc":{"start":{"line":1,"column":33,"index":33},"end":{"line":4,"column":1,"index":90}}, + "elementTypes": [ + { + "type": "TSNamedTupleMember", + "start":37,"end":70,"loc":{"start":{"line":2,"column":2,"index":37},"end":{"line":2,"column":35,"index":70}}, + "optional": false, + "label": { + "type": "Identifier", + "start":37,"end":45,"loc":{"start":{"line":2,"column":2,"index":37},"end":{"line":2,"column":10,"index":45},"identifierName":"function"}, + "name": "function" + }, + "elementType": { + "type": "TSFunctionType", + "start":47,"end":70,"loc":{"start":{"line":2,"column":12,"index":47},"end":{"line":2,"column":35,"index":70}}, + "parameters": [ + { + "type": "RestElement", + "start":48,"end":62,"loc":{"start":{"line":2,"column":13,"index":48},"end":{"line":2,"column":27,"index":62}}, + "argument": { + "type": "Identifier", + "start":51,"end":55,"loc":{"start":{"line":2,"column":16,"index":51},"end":{"line":2,"column":20,"index":55},"identifierName":"args"}, + "name": "args" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":55,"end":62,"loc":{"start":{"line":2,"column":20,"index":55},"end":{"line":2,"column":27,"index":62}}, + "typeAnnotation": { + "type": "TSArrayType", + "start":57,"end":62,"loc":{"start":{"line":2,"column":22,"index":57},"end":{"line":2,"column":27,"index":62}}, + "elementType": { + "type": "TSAnyKeyword", + "start":57,"end":60,"loc":{"start":{"line":2,"column":22,"index":57},"end":{"line":2,"column":25,"index":60}} + } + } + } + } + ], + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":64,"end":70,"loc":{"start":{"line":2,"column":29,"index":64},"end":{"line":2,"column":35,"index":70}}, + "typeAnnotation": { + "type": "TSAnyKeyword", + "start":67,"end":70,"loc":{"start":{"line":2,"column":32,"index":67},"end":{"line":2,"column":35,"index":70}} + } + } + } + }, + { + "type": "TSNamedTupleMember", + "start":74,"end":88,"loc":{"start":{"line":3,"column":2,"index":74},"end":{"line":3,"column":16,"index":88}}, + "optional": false, + "label": { + "type": "TSStringKeyword", + "start":74,"end":80,"loc":{"start":{"line":3,"column":2,"index":74},"end":{"line":3,"column":8,"index":80}} + }, + "elementType": { + "type": "TSStringKeyword", + "start":82,"end":88,"loc":{"start":{"line":3,"column":10,"index":82},"end":{"line":3,"column":16,"index":88}} + } + } + ] + } + } + ], + "directives": [] + } +} diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/input.ts index c97b346bf9e0..a920e7c9f9e6 100644 --- a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/input.ts +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/input.ts @@ -2,8 +2,3 @@ type FuncWithDescription = [ function: (...args: any[]) => any, string: string ] - -const fnWithDescriptions: FuncWithDescription[] = [ - [(x:number) => x, "return the number"], - [(x:number, y:number) => x*y, "multiply the numbers"] -] diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/options.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/options.json new file mode 100644 index 000000000000..cbf6d1595427 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/options.json @@ -0,0 +1,3 @@ +{ + "BABEL_8_BREAKING": true +} diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json index fc9f3ece47cd..75802102de34 100644 --- a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json @@ -1,12 +1,12 @@ { "type": "File", - "start":0,"end":237,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":9,"column":1,"index":237}}, + "start":0,"end":84,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":84}}, "errors": [ "SyntaxError: Tuple members must be labeled with a simple identifier. (3:2)" ], "program": { "type": "Program", - "start":0,"end":237,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":9,"column":1,"index":237}}, + "start":0,"end":84,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":84}}, "sourceType": "module", "interpreter": null, "body": [ @@ -34,7 +34,7 @@ "elementType": { "type": "TSFunctionType", "start":41,"end":64,"loc":{"start":{"line":2,"column":12,"index":41},"end":{"line":2,"column":35,"index":64}}, - "parameters": [ + "params": [ { "type": "RestElement", "start":42,"end":56,"loc":{"start":{"line":2,"column":13,"index":42},"end":{"line":2,"column":27,"index":56}}, @@ -57,7 +57,7 @@ } } ], - "typeAnnotation": { + "returnType": { "type": "TSTypeAnnotation", "start":58,"end":64,"loc":{"start":{"line":2,"column":29,"index":58},"end":{"line":2,"column":35,"index":64}}, "typeAnnotation": { @@ -82,152 +82,6 @@ } ] } - }, - { - "type": "VariableDeclaration", - "start":86,"end":237,"loc":{"start":{"line":6,"column":0,"index":86},"end":{"line":9,"column":1,"index":237}}, - "declarations": [ - { - "type": "VariableDeclarator", - "start":92,"end":237,"loc":{"start":{"line":6,"column":6,"index":92},"end":{"line":9,"column":1,"index":237}}, - "id": { - "type": "Identifier", - "start":92,"end":133,"loc":{"start":{"line":6,"column":6,"index":92},"end":{"line":6,"column":47,"index":133},"identifierName":"fnWithDescriptions"}, - "name": "fnWithDescriptions", - "typeAnnotation": { - "type": "TSTypeAnnotation", - "start":110,"end":133,"loc":{"start":{"line":6,"column":24,"index":110},"end":{"line":6,"column":47,"index":133}}, - "typeAnnotation": { - "type": "TSArrayType", - "start":112,"end":133,"loc":{"start":{"line":6,"column":26,"index":112},"end":{"line":6,"column":47,"index":133}}, - "elementType": { - "type": "TSTypeReference", - "start":112,"end":131,"loc":{"start":{"line":6,"column":26,"index":112},"end":{"line":6,"column":45,"index":131}}, - "typeName": { - "type": "Identifier", - "start":112,"end":131,"loc":{"start":{"line":6,"column":26,"index":112},"end":{"line":6,"column":45,"index":131},"identifierName":"FuncWithDescription"}, - "name": "FuncWithDescription" - } - } - } - } - }, - "init": { - "type": "ArrayExpression", - "start":136,"end":237,"loc":{"start":{"line":6,"column":50,"index":136},"end":{"line":9,"column":1,"index":237}}, - "elements": [ - { - "type": "ArrayExpression", - "start":140,"end":178,"loc":{"start":{"line":7,"column":2,"index":140},"end":{"line":7,"column":40,"index":178}}, - "elements": [ - { - "type": "ArrowFunctionExpression", - "start":141,"end":156,"loc":{"start":{"line":7,"column":3,"index":141},"end":{"line":7,"column":18,"index":156}}, - "id": null, - "generator": false, - "async": false, - "params": [ - { - "type": "Identifier", - "start":142,"end":150,"loc":{"start":{"line":7,"column":4,"index":142},"end":{"line":7,"column":12,"index":150},"identifierName":"x"}, - "name": "x", - "typeAnnotation": { - "type": "TSTypeAnnotation", - "start":143,"end":150,"loc":{"start":{"line":7,"column":5,"index":143},"end":{"line":7,"column":12,"index":150}}, - "typeAnnotation": { - "type": "TSNumberKeyword", - "start":144,"end":150,"loc":{"start":{"line":7,"column":6,"index":144},"end":{"line":7,"column":12,"index":150}} - } - } - } - ], - "body": { - "type": "Identifier", - "start":155,"end":156,"loc":{"start":{"line":7,"column":17,"index":155},"end":{"line":7,"column":18,"index":156},"identifierName":"x"}, - "name": "x" - } - }, - { - "type": "StringLiteral", - "start":158,"end":177,"loc":{"start":{"line":7,"column":20,"index":158},"end":{"line":7,"column":39,"index":177}}, - "extra": { - "rawValue": "return the number", - "raw": "\"return the number\"" - }, - "value": "return the number" - } - ] - }, - { - "type": "ArrayExpression", - "start":182,"end":235,"loc":{"start":{"line":8,"column":2,"index":182},"end":{"line":8,"column":55,"index":235}}, - "elements": [ - { - "type": "ArrowFunctionExpression", - "start":183,"end":210,"loc":{"start":{"line":8,"column":3,"index":183},"end":{"line":8,"column":30,"index":210}}, - "id": null, - "generator": false, - "async": false, - "params": [ - { - "type": "Identifier", - "start":184,"end":192,"loc":{"start":{"line":8,"column":4,"index":184},"end":{"line":8,"column":12,"index":192},"identifierName":"x"}, - "name": "x", - "typeAnnotation": { - "type": "TSTypeAnnotation", - "start":185,"end":192,"loc":{"start":{"line":8,"column":5,"index":185},"end":{"line":8,"column":12,"index":192}}, - "typeAnnotation": { - "type": "TSNumberKeyword", - "start":186,"end":192,"loc":{"start":{"line":8,"column":6,"index":186},"end":{"line":8,"column":12,"index":192}} - } - } - }, - { - "type": "Identifier", - "start":194,"end":202,"loc":{"start":{"line":8,"column":14,"index":194},"end":{"line":8,"column":22,"index":202},"identifierName":"y"}, - "name": "y", - "typeAnnotation": { - "type": "TSTypeAnnotation", - "start":195,"end":202,"loc":{"start":{"line":8,"column":15,"index":195},"end":{"line":8,"column":22,"index":202}}, - "typeAnnotation": { - "type": "TSNumberKeyword", - "start":196,"end":202,"loc":{"start":{"line":8,"column":16,"index":196},"end":{"line":8,"column":22,"index":202}} - } - } - } - ], - "body": { - "type": "BinaryExpression", - "start":207,"end":210,"loc":{"start":{"line":8,"column":27,"index":207},"end":{"line":8,"column":30,"index":210}}, - "left": { - "type": "Identifier", - "start":207,"end":208,"loc":{"start":{"line":8,"column":27,"index":207},"end":{"line":8,"column":28,"index":208},"identifierName":"x"}, - "name": "x" - }, - "operator": "*", - "right": { - "type": "Identifier", - "start":209,"end":210,"loc":{"start":{"line":8,"column":29,"index":209},"end":{"line":8,"column":30,"index":210},"identifierName":"y"}, - "name": "y" - } - } - }, - { - "type": "StringLiteral", - "start":212,"end":234,"loc":{"start":{"line":8,"column":32,"index":212},"end":{"line":8,"column":54,"index":234}}, - "extra": { - "rawValue": "multiply the numbers", - "raw": "\"multiply the numbers\"" - }, - "value": "multiply the numbers" - } - ] - } - ] - } - } - ], - "kind": "const" } ], "directives": [] From 1026aa3ffe93e331ef971b467d55c926298e982c Mon Sep 17 00:00:00 2001 From: harpica Date: Fri, 24 Feb 2023 14:39:39 +0300 Subject: [PATCH 3/6] fix: types could be treated as identif. in tuples --- .../src/plugins/typescript/index.ts | 71 ++++++++++++++----- .../tuple-keyword-labeled-babel-7/output.json | 8 +-- .../types/tuple-keyword-labeled/output.json | 8 +-- 3 files changed, 61 insertions(+), 26 deletions(-) diff --git a/packages/babel-parser/src/plugins/typescript/index.ts b/packages/babel-parser/src/plugins/typescript/index.ts index cbd6a6b8a086..66b1f62bc392 100644 --- a/packages/babel-parser/src/plugins/typescript/index.ts +++ b/packages/babel-parser/src/plugins/typescript/index.ts @@ -11,7 +11,6 @@ import { type TokenType, tokenIsTemplate, tokenCanStartExpression, - tokenIsKeyword, } from "../../tokenizer/types"; import { types as tc } from "../../tokenizer/context"; import type * as N from "../../types"; @@ -1106,47 +1105,87 @@ export default (superClass: ClassWithMixin) => const { startLoc } = this.state; const rest = this.eat(tt.ellipsis); - const isKeyword = tokenIsKeyword(this.state.type); - let type: N.TsNamedTupleMember | N.TsType | N.Identifier = isKeyword - ? this.parseIdentifier(true) - : this.tsParseType(); - const optional = this.eat(tt.question); - const labeled = this.eat(tt.colon); - if (labeled) { - const labeledNode = this.startNodeAtNode(type); - labeledNode.optional = optional; + let labeled: boolean; + let label: N.Identifier; + let optional: boolean; + let type: N.TsNamedTupleMember | N.TsType; + + const isWord = tokenIsKeywordOrIdentifier(this.state.type); + if (isWord && this.lookaheadCharCode() === charCodes.colon) { + labeled = true; + optional = false; + label = this.parseIdentifier(true); + this.expect(tt.colon); + type = this.tsParseType(); + } else if ( + isWord && + this.lookaheadCharCode() === charCodes.questionMark + ) { + optional = true; + const startLoc = this.state.startLoc; + const wordName = this.state.value; + const typeOrLabel = this.tsParseNonArrayType(); + + if (this.lookaheadCharCode() === charCodes.colon) { + labeled = true; + label = this.createIdentifier( + this.startNodeAt(startLoc), + wordName, + ); + this.expect(tt.question); + this.expect(tt.colon); + type = this.tsParseType(); + } else { + labeled = false; + type = typeOrLabel; + this.expect(tt.question); + } + } else { + type = this.tsParseType(); + optional = this.eat(tt.question); + labeled = this.eat(tt.colon); + } - if (isKeyword) { - labeledNode.label = type as N.Identifier; + if (labeled) { + let labeledNode: Undone; + if (label) { + labeledNode = this.startNodeAtNode(label); + labeledNode.optional = optional; + labeledNode.label = label; + labeledNode.elementType = type; } else { + labeledNode = this.startNodeAtNode(type); + labeledNode.optional = optional; if ( type.type === "TSTypeReference" && !type.typeParameters && type.typeName.type === "Identifier" ) { labeledNode.label = type.typeName; + labeledNode.elementType = this.tsParseType(); } else { this.raise(TSErrors.InvalidTupleMemberLabel, { at: type }); // @ts-expect-error This produces an invalid AST, but at least we don't drop // nodes representing the invalid source. labeledNode.label = type; + labeledNode.elementType = this.tsParseType(); } } - labeledNode.elementType = this.tsParseType(); type = this.finishNode(labeledNode, "TSNamedTupleMember"); } else if (optional) { const optionalTypeNode = this.startNodeAtNode(type); - optionalTypeNode.typeAnnotation = type as N.TsType; + optionalTypeNode.typeAnnotation = type; type = this.finishNode(optionalTypeNode, "TSOptionalType"); } + if (rest) { const restNode = this.startNodeAt(startLoc); - restNode.typeAnnotation = type as N.TsType; + restNode.typeAnnotation = type; type = this.finishNode(restNode, "TSRestType"); } - return type as N.TsNamedTupleMember | N.TsType; + return type; } tsParseParenthesizedType(): N.TsParenthesizedType { diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/output.json index 0d5656bcb4dc..25b6e8dea18b 100644 --- a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/output.json +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/output.json @@ -1,9 +1,6 @@ { "type": "File", "start":0,"end":90,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":90}}, - "errors": [ - "SyntaxError: Tuple members must be labeled with a simple identifier. (3:2)" - ], "program": { "type": "Program", "start":0,"end":90,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":90}}, @@ -72,8 +69,9 @@ "start":74,"end":88,"loc":{"start":{"line":3,"column":2,"index":74},"end":{"line":3,"column":16,"index":88}}, "optional": false, "label": { - "type": "TSStringKeyword", - "start":74,"end":80,"loc":{"start":{"line":3,"column":2,"index":74},"end":{"line":3,"column":8,"index":80}} + "type": "Identifier", + "start":74,"end":80,"loc":{"start":{"line":3,"column":2,"index":74},"end":{"line":3,"column":8,"index":80},"identifierName":"string"}, + "name": "string" }, "elementType": { "type": "TSStringKeyword", diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json index 75802102de34..9d6cf78efaf1 100644 --- a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json @@ -1,9 +1,6 @@ { "type": "File", "start":0,"end":84,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":84}}, - "errors": [ - "SyntaxError: Tuple members must be labeled with a simple identifier. (3:2)" - ], "program": { "type": "Program", "start":0,"end":84,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":84}}, @@ -72,8 +69,9 @@ "start":68,"end":82,"loc":{"start":{"line":3,"column":2,"index":68},"end":{"line":3,"column":16,"index":82}}, "optional": false, "label": { - "type": "TSStringKeyword", - "start":68,"end":74,"loc":{"start":{"line":3,"column":2,"index":68},"end":{"line":3,"column":8,"index":74}} + "type": "Identifier", + "start":68,"end":74,"loc":{"start":{"line":3,"column":2,"index":68},"end":{"line":3,"column":8,"index":74},"identifierName":"string"}, + "name": "string" }, "elementType": { "type": "TSStringKeyword", From 6f3897d8a170384fcb04557d1efcec25847015a3 Mon Sep 17 00:00:00 2001 From: harpica Date: Fri, 24 Feb 2023 14:39:39 +0300 Subject: [PATCH 4/6] refactor: raise error and add comments --- .../src/plugins/typescript/index.ts | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/packages/babel-parser/src/plugins/typescript/index.ts b/packages/babel-parser/src/plugins/typescript/index.ts index 66b1f62bc392..f8037c6b3d0a 100644 --- a/packages/babel-parser/src/plugins/typescript/index.ts +++ b/packages/babel-parser/src/plugins/typescript/index.ts @@ -1144,6 +1144,9 @@ export default (superClass: ClassWithMixin) => } else { type = this.tsParseType(); optional = this.eat(tt.question); + // In this case (labeled === true) could be only in invalid label. + // E.g. [x.y:type] + // An error is raised while processing node. labeled = this.eat(tt.colon); } @@ -1157,20 +1160,11 @@ export default (superClass: ClassWithMixin) => } else { labeledNode = this.startNodeAtNode(type); labeledNode.optional = optional; - if ( - type.type === "TSTypeReference" && - !type.typeParameters && - type.typeName.type === "Identifier" - ) { - labeledNode.label = type.typeName; - labeledNode.elementType = this.tsParseType(); - } else { - this.raise(TSErrors.InvalidTupleMemberLabel, { at: type }); - // @ts-expect-error This produces an invalid AST, but at least we don't drop - // nodes representing the invalid source. - labeledNode.label = type; - labeledNode.elementType = this.tsParseType(); - } + this.raise(TSErrors.InvalidTupleMemberLabel, { at: type }); + // @ts-expect-error This produces an invalid AST, but at least we don't drop + // nodes representing the invalid source. + labeledNode.label = type; + labeledNode.elementType = this.tsParseType(); } type = this.finishNode(labeledNode, "TSNamedTupleMember"); } else if (optional) { From 73503f53862134f2c435b4ed5659bf39b7439e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Tue, 14 Mar 2023 14:42:13 +0100 Subject: [PATCH 5/6] Review by JLHwung --- .../src/plugins/typescript/index.ts | 8 +++---- .../tuple-keyword-labeled-babel-7/input.ts | 3 ++- .../tuple-keyword-labeled-babel-7/output.json | 22 +++++++++++++++---- .../types/tuple-keyword-labeled/input.ts | 3 ++- .../types/tuple-keyword-labeled/output.json | 22 +++++++++++++++---- 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/packages/babel-parser/src/plugins/typescript/index.ts b/packages/babel-parser/src/plugins/typescript/index.ts index f8037c6b3d0a..c483d1f743c8 100644 --- a/packages/babel-parser/src/plugins/typescript/index.ts +++ b/packages/babel-parser/src/plugins/typescript/index.ts @@ -1112,16 +1112,14 @@ export default (superClass: ClassWithMixin) => let type: N.TsNamedTupleMember | N.TsType; const isWord = tokenIsKeywordOrIdentifier(this.state.type); - if (isWord && this.lookaheadCharCode() === charCodes.colon) { + const chAfterWord = isWord ? this.lookaheadCharCode() : null; + if (chAfterWord === charCodes.colon) { labeled = true; optional = false; label = this.parseIdentifier(true); this.expect(tt.colon); type = this.tsParseType(); - } else if ( - isWord && - this.lookaheadCharCode() === charCodes.questionMark - ) { + } else if (chAfterWord === charCodes.questionMark) { optional = true; const startLoc = this.state.startLoc; const wordName = this.state.value; diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/input.ts index dc2583d50c5c..fd066b19ef94 100644 --- a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/input.ts +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/input.ts @@ -1,4 +1,5 @@ type FuncWithDescriptionBabel7 = [ function: (...args: any[]) => any, - string: string + string: string, + void?: number ] diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/output.json index 25b6e8dea18b..185a30bf052e 100644 --- a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/output.json +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled-babel-7/output.json @@ -1,15 +1,15 @@ { "type": "File", - "start":0,"end":90,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":90}}, + "start":0,"end":107,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":5,"column":1,"index":107}}, "program": { "type": "Program", - "start":0,"end":90,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":90}}, + "start":0,"end":107,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":5,"column":1,"index":107}}, "sourceType": "module", "interpreter": null, "body": [ { "type": "TSTypeAliasDeclaration", - "start":0,"end":90,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":90}}, + "start":0,"end":107,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":5,"column":1,"index":107}}, "id": { "type": "Identifier", "start":5,"end":30,"loc":{"start":{"line":1,"column":5,"index":5},"end":{"line":1,"column":30,"index":30},"identifierName":"FuncWithDescriptionBabel7"}, @@ -17,7 +17,7 @@ }, "typeAnnotation": { "type": "TSTupleType", - "start":33,"end":90,"loc":{"start":{"line":1,"column":33,"index":33},"end":{"line":4,"column":1,"index":90}}, + "start":33,"end":107,"loc":{"start":{"line":1,"column":33,"index":33},"end":{"line":5,"column":1,"index":107}}, "elementTypes": [ { "type": "TSNamedTupleMember", @@ -77,6 +77,20 @@ "type": "TSStringKeyword", "start":82,"end":88,"loc":{"start":{"line":3,"column":10,"index":82},"end":{"line":3,"column":16,"index":88}} } + }, + { + "type": "TSNamedTupleMember", + "start":92,"end":105,"loc":{"start":{"line":4,"column":2,"index":92},"end":{"line":4,"column":15,"index":105}}, + "optional": true, + "label": { + "type": "Identifier", + "start":92,"end":96,"loc":{"start":{"line":4,"column":2,"index":92},"end":{"line":4,"column":6,"index":96},"identifierName":"void"}, + "name": "void" + }, + "elementType": { + "type": "TSNumberKeyword", + "start":99,"end":105,"loc":{"start":{"line":4,"column":9,"index":99},"end":{"line":4,"column":15,"index":105}} + } } ] } diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/input.ts index a920e7c9f9e6..53ba036ce700 100644 --- a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/input.ts +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/input.ts @@ -1,4 +1,5 @@ type FuncWithDescription = [ function: (...args: any[]) => any, - string: string + string: string, + void?: number ] diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json index 9d6cf78efaf1..61773f1f92b7 100644 --- a/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-keyword-labeled/output.json @@ -1,15 +1,15 @@ { "type": "File", - "start":0,"end":84,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":84}}, + "start":0,"end":101,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":5,"column":1,"index":101}}, "program": { "type": "Program", - "start":0,"end":84,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":84}}, + "start":0,"end":101,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":5,"column":1,"index":101}}, "sourceType": "module", "interpreter": null, "body": [ { "type": "TSTypeAliasDeclaration", - "start":0,"end":84,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":1,"index":84}}, + "start":0,"end":101,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":5,"column":1,"index":101}}, "id": { "type": "Identifier", "start":5,"end":24,"loc":{"start":{"line":1,"column":5,"index":5},"end":{"line":1,"column":24,"index":24},"identifierName":"FuncWithDescription"}, @@ -17,7 +17,7 @@ }, "typeAnnotation": { "type": "TSTupleType", - "start":27,"end":84,"loc":{"start":{"line":1,"column":27,"index":27},"end":{"line":4,"column":1,"index":84}}, + "start":27,"end":101,"loc":{"start":{"line":1,"column":27,"index":27},"end":{"line":5,"column":1,"index":101}}, "elementTypes": [ { "type": "TSNamedTupleMember", @@ -77,6 +77,20 @@ "type": "TSStringKeyword", "start":76,"end":82,"loc":{"start":{"line":3,"column":10,"index":76},"end":{"line":3,"column":16,"index":82}} } + }, + { + "type": "TSNamedTupleMember", + "start":86,"end":99,"loc":{"start":{"line":4,"column":2,"index":86},"end":{"line":4,"column":15,"index":99}}, + "optional": true, + "label": { + "type": "Identifier", + "start":86,"end":90,"loc":{"start":{"line":4,"column":2,"index":86},"end":{"line":4,"column":6,"index":90},"identifierName":"void"}, + "name": "void" + }, + "elementType": { + "type": "TSNumberKeyword", + "start":93,"end":99,"loc":{"start":{"line":4,"column":9,"index":93},"end":{"line":4,"column":15,"index":99}} + } } ] } From d50e5c7689f05dc74e7d76d23a599b248d772549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Tue, 14 Mar 2023 14:49:58 +0100 Subject: [PATCH 6/6] Recover from `[name:type?]` --- .../src/plugins/typescript/index.ts | 11 +++- .../options.json | 5 +- .../output.json | 50 +++++++++++++++++++ 3 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/output.json diff --git a/packages/babel-parser/src/plugins/typescript/index.ts b/packages/babel-parser/src/plugins/typescript/index.ts index c483d1f743c8..6586537f4bf3 100644 --- a/packages/babel-parser/src/plugins/typescript/index.ts +++ b/packages/babel-parser/src/plugins/typescript/index.ts @@ -214,6 +214,8 @@ const TSErrors = ParseErrorEnum`typescript`({ `Single type parameter ${typeParameterName} should have a trailing comma. Example usage: <${typeParameterName},>.`, StaticBlockCannotHaveModifier: "Static class blocks cannot have any modifier.", + TupleOptionalAfterType: + "A labeled tuple optional element must be declared using a question mark after the name and before the colon (`name?: type`), rather than after the type (`name: type?`).", TypeAnnotationAfterAssign: "Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`.", TypeImportCannotSpecifyDefaultAndNamed: @@ -460,8 +462,6 @@ export default (superClass: ClassWithMixin) => case "TypeParametersOrArguments": return this.match(tt.gt); } - - throw new Error("Unreachable"); } tsParseList( @@ -1155,6 +1155,13 @@ export default (superClass: ClassWithMixin) => labeledNode.optional = optional; labeledNode.label = label; labeledNode.elementType = type; + + if (this.eat(tt.question)) { + labeledNode.optional = true; + this.raise(TSErrors.TupleOptionalAfterType, { + at: this.state.lastTokStartLoc, + }); + } } else { labeledNode = this.startNodeAtNode(type); labeledNode.optional = optional; diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/options.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/options.json index 32484cd670a1..aaf792adc2cf 100644 --- a/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/options.json +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/options.json @@ -2,6 +2,5 @@ "sourceType": "module", "plugins": [ "typescript" - ], - "throws": "Unexpected token, expected \",\" (1:14)" -} \ No newline at end of file + ] +} diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/output.json new file mode 100644 index 000000000000..442be868803d --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/output.json @@ -0,0 +1,50 @@ +{ + "type": "File", + "start":0,"end":17,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":17,"index":17}}, + "errors": [ + "SyntaxError: A labeled tuple optional element must be declared using a question mark after the name and before the colon (`name?: type`), rather than after the type (`name: type?`). (1:14)" + ], + "program": { + "type": "Program", + "start":0,"end":17,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":17,"index":17}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start":0,"end":17,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":17,"index":17}}, + "id": { + "type": "Identifier", + "start":5,"end":6,"loc":{"start":{"line":1,"column":5,"index":5},"end":{"line":1,"column":6,"index":6},"identifierName":"T"}, + "name": "T" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start":9,"end":16,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":16,"index":16}}, + "elementTypes": [ + { + "type": "TSNamedTupleMember", + "start":10,"end":15,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":15,"index":15}}, + "optional": true, + "label": { + "type": "Identifier", + "start":10,"end":11,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":11,"index":11},"identifierName":"x"}, + "name": "x" + }, + "elementType": { + "type": "TSTypeReference", + "start":13,"end":14,"loc":{"start":{"line":1,"column":13,"index":13},"end":{"line":1,"column":14,"index":14}}, + "typeName": { + "type": "Identifier", + "start":13,"end":14,"loc":{"start":{"line":1,"column":13,"index":13},"end":{"line":1,"column":14,"index":14},"identifierName":"A"}, + "name": "A" + } + } + } + ] + } + } + ], + "directives": [] + } +}