diff --git a/Makefile b/Makefile index 4d280f5b20df..f0118381e39a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ FLOW_COMMIT = a1f9a4c709dcebb27a5084acf47755fbae699c25 TEST262_COMMIT = 058adfed86b1d4129996faaf50a85ea55379a66a -TYPESCRIPT_COMMIT = 5fc917be2e4dd64c8e9504d36615cd7fbfdd4cd3 +TYPESCRIPT_COMMIT = ffa35d3272647fe48ddf173e1f0928f772c18630 FORCE_PUBLISH = "@babel/runtime,@babel/runtime-corejs2,@babel/runtime-corejs3,@babel/standalone" diff --git a/packages/babel-generator/src/generators/statements.js b/packages/babel-generator/src/generators/statements.js index 24f9a2dbe5cd..dbeb45bf32b9 100644 --- a/packages/babel-generator/src/generators/statements.js +++ b/packages/babel-generator/src/generators/statements.js @@ -174,6 +174,7 @@ export function CatchClause(node: Object) { if (node.param) { this.token("("); this.print(node.param, node); + this.print(node.param.typeAnnotation, node); this.token(")"); this.space(); } diff --git a/packages/babel-generator/src/generators/typescript.js b/packages/babel-generator/src/generators/typescript.js index 39c580d74d2f..ea3e2218437d 100644 --- a/packages/babel-generator/src/generators/typescript.js +++ b/packages/babel-generator/src/generators/typescript.js @@ -262,6 +262,14 @@ export function TSRestType(node) { this.print(node.typeAnnotation, node); } +export function TSNamedTupleMember(node) { + this.print(node.label, node); + if (node.optional) this.token("?"); + this.token(":"); + this.space(); + this.print(node.elementType, node); +} + export function TSUnionType(node) { this.tsPrintUnionOrIntersectionType(node, "|"); } diff --git a/packages/babel-generator/test/fixtures/typescript/catch-param-type/input.js b/packages/babel-generator/test/fixtures/typescript/catch-param-type/input.js new file mode 100644 index 000000000000..76318908d8b3 --- /dev/null +++ b/packages/babel-generator/test/fixtures/typescript/catch-param-type/input.js @@ -0,0 +1,2 @@ +try {} catch (e: unknown) {} +try {} catch (e: any) {} diff --git a/packages/babel-generator/test/fixtures/typescript/catch-param-type/output.js b/packages/babel-generator/test/fixtures/typescript/catch-param-type/output.js new file mode 100644 index 000000000000..e9e71a8acf93 --- /dev/null +++ b/packages/babel-generator/test/fixtures/typescript/catch-param-type/output.js @@ -0,0 +1,3 @@ +try {} catch (e: unknown) {} + +try {} catch (e: any) {} \ No newline at end of file diff --git a/packages/babel-generator/test/fixtures/typescript/tuple-labeled/input.js b/packages/babel-generator/test/fixtures/typescript/tuple-labeled/input.js new file mode 100644 index 000000000000..a8d132c09bd3 --- /dev/null +++ b/packages/babel-generator/test/fixtures/typescript/tuple-labeled/input.js @@ -0,0 +1 @@ +type T = [x: A, y?: B, ...z: C]; diff --git a/packages/babel-generator/test/fixtures/typescript/tuple-labeled/output.js b/packages/babel-generator/test/fixtures/typescript/tuple-labeled/output.js new file mode 100644 index 000000000000..b9111dbd9aa6 --- /dev/null +++ b/packages/babel-generator/test/fixtures/typescript/tuple-labeled/output.js @@ -0,0 +1 @@ +type T = [x: A, y?: B, ...z: C]; \ No newline at end of file diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index 9bbed6ca25f1..224515cd76e2 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -636,6 +636,16 @@ export default class StatementParser extends ExpressionParser { return this.finishNode(node, "ThrowStatement"); } + parseCatchClauseParam(): N.Identifier { + const param = this.parseBindingAtom(); + + const simple = param.type === "Identifier"; + this.scope.enter(simple ? SCOPE_SIMPLE_CATCH : 0); + this.checkLVal(param, BIND_LEXICAL, null, "catch clause"); + + return param; + } + parseTryStatement(node: N.TryStatement): N.TryStatement { this.next(); @@ -647,10 +657,7 @@ export default class StatementParser extends ExpressionParser { this.next(); if (this.match(tt.parenL)) { this.expect(tt.parenL); - clause.param = this.parseBindingAtom(); - const simple = clause.param.type === "Identifier"; - this.scope.enter(simple ? SCOPE_SIMPLE_CATCH : 0); - this.checkLVal(clause.param, BIND_LEXICAL, null, "catch clause"); + clause.param = this.parseCatchClauseParam(); this.expect(tt.parenR); } else { clause.param = null; diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 6309c8ea8fcb..bb3a5a10ccb7 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -74,6 +74,10 @@ const TSErrors = Object.freeze({ IndexSignatureHasAccessibility: "Index signatures cannot have an accessibility modifier ('%0')", IndexSignatureHasStatic: "Index signatures cannot have the 'static' modifier", + InvalidTupleMemberLabel: + "Tuple members must be labeled with a simple identifier.", + MixedLabeledAndUnlabeledElements: + "Tuple members must all have names or all not have names.", OptionalTypeBeforeRequired: "A required element cannot follow an optional element.", PatternIsOptional: @@ -630,43 +634,90 @@ export default (superClass: Class): Class => /* skipFirstToken */ false, ); - // Validate the elementTypes to ensure: - // No mandatory elements may follow optional elements - // If there's a rest element, it must be at the end of the tuple + // Validate the elementTypes to ensure that no mandatory elements + // follow optional elements let seenOptionalElement = false; + let labeledElements = null; node.elementTypes.forEach(elementNode => { - if (elementNode.type === "TSOptionalType") { - seenOptionalElement = true; - } else if (seenOptionalElement && elementNode.type !== "TSRestType") { + let { type } = elementNode; + + if ( + seenOptionalElement && + type !== "TSRestType" && + type !== "TSOptionalType" && + !(type === "TSNamedTupleMember" && elementNode.optional) + ) { this.raise(elementNode.start, TSErrors.OptionalTypeBeforeRequired); } + + // Flow doesn't support ||= + seenOptionalElement = + seenOptionalElement || + (type === "TSNamedTupleMember" && elementNode.optional) || + type === "TSOptionalType"; + + // When checking labels, check the argument of the spread operator + if (type === "TSRestType") { + elementNode = elementNode.typeAnnotation; + type = elementNode.type; + } + + const isLabeled = type === "TSNamedTupleMember"; + // Flow doesn't support ??= + labeledElements = labeledElements ?? isLabeled; + if (labeledElements !== isLabeled) { + this.raise( + elementNode.start, + TSErrors.MixedLabeledAndUnlabeledElements, + ); + } }); return this.finishNode(node, "TSTupleType"); } - tsParseTupleElementType(): N.TsType { + tsParseTupleElementType(): N.TsType | N.TsNamedTupleMember { // parses `...TsType[]` - if (this.match(tt.ellipsis)) { - const restNode: N.TsRestType = this.startNode(); - this.next(); // skips ellipsis - restNode.typeAnnotation = this.tsParseType(); + + const { start: startPos, startLoc } = this.state; + + const rest = this.eat(tt.ellipsis); + let type = this.tsParseType(); + const optional = this.eat(tt.question); + const labeled = this.eat(tt.colon); + + if (labeled) { + const labeledNode: N.TsNamedTupleMember = this.startNodeAtNode(type); + labeledNode.optional = optional; + if ( - this.match(tt.comma) && - this.lookaheadCharCode() !== charCodes.rightSquareBracket + type.type === "TSTypeReference" && + !type.typeParameters && + type.typeName.type === "Identifier" ) { - this.raiseRestNotLast(this.state.start); + labeledNode.label = (type.typeName: N.Identifier); + } else { + this.raise(type.start, TSErrors.InvalidTupleMemberLabel); + // This produces an invalid AST, but at least we don't drop + // nodes representing the invalid source. + // $FlowIgnore + labeledNode.label = type; } - return this.finishNode(restNode, "TSRestType"); - } - const type = this.tsParseType(); - // parses `TsType?` - if (this.eat(tt.question)) { + labeledNode.elementType = this.tsParseType(); + type = this.finishNode(labeledNode, "TSNamedTupleMember"); + } else if (optional) { const optionalTypeNode: N.TsOptionalType = this.startNodeAtNode(type); optionalTypeNode.typeAnnotation = type; - return this.finishNode(optionalTypeNode, "TSOptionalType"); + type = this.finishNode(optionalTypeNode, "TSOptionalType"); } + + if (rest) { + const restNode: N.TsRestType = this.startNodeAt(startPos, startLoc); + restNode.typeAnnotation = type; + type = this.finishNode(restNode, "TSRestType"); + } + return type; } @@ -2667,4 +2718,15 @@ export default (superClass: Class): Class => return hasContextParam ? baseCount + 1 : baseCount; } + + parseCatchClauseParam(): N.Identifier { + const param = super.parseCatchClauseParam(); + const type = this.tsTryParseTypeAnnotation(); + + if (type) { + param.typeAnnotation = type; + } + + return param; + } }; diff --git a/packages/babel-parser/src/types.js b/packages/babel-parser/src/types.js index 17f96dc4934c..3566baaafbe2 100644 --- a/packages/babel-parser/src/types.js +++ b/packages/babel-parser/src/types.js @@ -1264,7 +1264,14 @@ export type TsArrayType = TsTypeBase & { export type TsTupleType = TsTypeBase & { type: "TSTupleType", - elementTypes: $ReadOnlyArray, + elementTypes: $ReadOnlyArray, +}; + +export type TsNamedTupleMember = NodeBase & { + type: "TSNamedTupleMember", + label: Identifier, + optional: boolean, + elementType: TsType, }; export type TsOptionalType = TsTypeBase & { @@ -1274,7 +1281,7 @@ export type TsOptionalType = TsTypeBase & { export type TsRestType = TsTypeBase & { type: "TSRestType", - typeAnnotation: TsType, + typeAnnotation: TsType | TsNamedTupleMember, }; export type TsUnionOrIntersectionType = TsUnionType | TsIntersectionType; diff --git a/packages/babel-parser/test/fixtures/typescript/catch-clause/unknown/input.ts b/packages/babel-parser/test/fixtures/typescript/catch-clause/unknown/input.ts new file mode 100644 index 000000000000..6e5c28505572 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/catch-clause/unknown/input.ts @@ -0,0 +1,9 @@ +try {} catch (ex) {} +try {} catch (ex: unknown) {} +try {} catch (ex: any) {} + +// The following can't be error'd at parse time +try {} catch (ex: A) {} +try {} catch (ex: Error) {} +try {} catch (ex: string) {} +try {} catch (ex: string | number) {} diff --git a/packages/babel-parser/test/fixtures/typescript/catch-clause/unknown/output.json b/packages/babel-parser/test/fixtures/typescript/catch-clause/unknown/output.json new file mode 100644 index 000000000000..fa244b40b2b2 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/catch-clause/unknown/output.json @@ -0,0 +1,284 @@ +{ + "type": "File", + "start":0,"end":244,"loc":{"start":{"line":1,"column":0},"end":{"line":9,"column":37}}, + "program": { + "type": "Program", + "start":0,"end":244,"loc":{"start":{"line":1,"column":0},"end":{"line":9,"column":37}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TryStatement", + "start":0,"end":20,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":20}}, + "block": { + "type": "BlockStatement", + "start":4,"end":6,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":6}}, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start":7,"end":20,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":20}}, + "param": { + "type": "Identifier", + "start":14,"end":16,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":16},"identifierName":"ex"}, + "name": "ex" + }, + "body": { + "type": "BlockStatement", + "start":18,"end":20,"loc":{"start":{"line":1,"column":18},"end":{"line":1,"column":20}}, + "body": [], + "directives": [] + } + }, + "finalizer": null + }, + { + "type": "TryStatement", + "start":21,"end":50,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":29}}, + "block": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":6}}, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start":28,"end":50,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":29}}, + "param": { + "type": "Identifier", + "start":35,"end":37,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":16},"identifierName":"ex"}, + "name": "ex", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":37,"end":46,"loc":{"start":{"line":2,"column":16},"end":{"line":2,"column":25}}, + "typeAnnotation": { + "type": "TSUnknownKeyword", + "start":39,"end":46,"loc":{"start":{"line":2,"column":18},"end":{"line":2,"column":25}} + } + } + }, + "body": { + "type": "BlockStatement", + "start":48,"end":50,"loc":{"start":{"line":2,"column":27},"end":{"line":2,"column":29}}, + "body": [], + "directives": [] + } + }, + "finalizer": null + }, + { + "type": "TryStatement", + "start":51,"end":76,"loc":{"start":{"line":3,"column":0},"end":{"line":3,"column":25}}, + "block": { + "type": "BlockStatement", + "start":55,"end":57,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":6}}, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start":58,"end":76,"loc":{"start":{"line":3,"column":7},"end":{"line":3,"column":25}}, + "param": { + "type": "Identifier", + "start":65,"end":67,"loc":{"start":{"line":3,"column":14},"end":{"line":3,"column":16},"identifierName":"ex"}, + "name": "ex", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":67,"end":72,"loc":{"start":{"line":3,"column":16},"end":{"line":3,"column":21}}, + "typeAnnotation": { + "type": "TSAnyKeyword", + "start":69,"end":72,"loc":{"start":{"line":3,"column":18},"end":{"line":3,"column":21}} + } + } + }, + "body": { + "type": "BlockStatement", + "start":74,"end":76,"loc":{"start":{"line":3,"column":23},"end":{"line":3,"column":25}}, + "body": [], + "directives": [] + } + }, + "finalizer": null, + "trailingComments": [ + { + "type": "CommentLine", + "value": " The following can't be error'd at parse time", + "start":78,"end":125,"loc":{"start":{"line":5,"column":0},"end":{"line":5,"column":47}} + } + ] + }, + { + "type": "TryStatement", + "start":126,"end":149,"loc":{"start":{"line":6,"column":0},"end":{"line":6,"column":23}}, + "block": { + "type": "BlockStatement", + "start":130,"end":132,"loc":{"start":{"line":6,"column":4},"end":{"line":6,"column":6}}, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start":133,"end":149,"loc":{"start":{"line":6,"column":7},"end":{"line":6,"column":23}}, + "param": { + "type": "Identifier", + "start":140,"end":142,"loc":{"start":{"line":6,"column":14},"end":{"line":6,"column":16},"identifierName":"ex"}, + "name": "ex", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":142,"end":145,"loc":{"start":{"line":6,"column":16},"end":{"line":6,"column":19}}, + "typeAnnotation": { + "type": "TSTypeReference", + "start":144,"end":145,"loc":{"start":{"line":6,"column":18},"end":{"line":6,"column":19}}, + "typeName": { + "type": "Identifier", + "start":144,"end":145,"loc":{"start":{"line":6,"column":18},"end":{"line":6,"column":19},"identifierName":"A"}, + "name": "A" + } + } + } + }, + "body": { + "type": "BlockStatement", + "start":147,"end":149,"loc":{"start":{"line":6,"column":21},"end":{"line":6,"column":23}}, + "body": [], + "directives": [] + } + }, + "finalizer": null, + "leadingComments": [ + { + "type": "CommentLine", + "value": " The following can't be error'd at parse time", + "start":78,"end":125,"loc":{"start":{"line":5,"column":0},"end":{"line":5,"column":47}} + } + ] + }, + { + "type": "TryStatement", + "start":150,"end":177,"loc":{"start":{"line":7,"column":0},"end":{"line":7,"column":27}}, + "block": { + "type": "BlockStatement", + "start":154,"end":156,"loc":{"start":{"line":7,"column":4},"end":{"line":7,"column":6}}, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start":157,"end":177,"loc":{"start":{"line":7,"column":7},"end":{"line":7,"column":27}}, + "param": { + "type": "Identifier", + "start":164,"end":166,"loc":{"start":{"line":7,"column":14},"end":{"line":7,"column":16},"identifierName":"ex"}, + "name": "ex", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":166,"end":173,"loc":{"start":{"line":7,"column":16},"end":{"line":7,"column":23}}, + "typeAnnotation": { + "type": "TSTypeReference", + "start":168,"end":173,"loc":{"start":{"line":7,"column":18},"end":{"line":7,"column":23}}, + "typeName": { + "type": "Identifier", + "start":168,"end":173,"loc":{"start":{"line":7,"column":18},"end":{"line":7,"column":23},"identifierName":"Error"}, + "name": "Error" + } + } + } + }, + "body": { + "type": "BlockStatement", + "start":175,"end":177,"loc":{"start":{"line":7,"column":25},"end":{"line":7,"column":27}}, + "body": [], + "directives": [] + } + }, + "finalizer": null + }, + { + "type": "TryStatement", + "start":178,"end":206,"loc":{"start":{"line":8,"column":0},"end":{"line":8,"column":28}}, + "block": { + "type": "BlockStatement", + "start":182,"end":184,"loc":{"start":{"line":8,"column":4},"end":{"line":8,"column":6}}, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start":185,"end":206,"loc":{"start":{"line":8,"column":7},"end":{"line":8,"column":28}}, + "param": { + "type": "Identifier", + "start":192,"end":194,"loc":{"start":{"line":8,"column":14},"end":{"line":8,"column":16},"identifierName":"ex"}, + "name": "ex", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":194,"end":202,"loc":{"start":{"line":8,"column":16},"end":{"line":8,"column":24}}, + "typeAnnotation": { + "type": "TSStringKeyword", + "start":196,"end":202,"loc":{"start":{"line":8,"column":18},"end":{"line":8,"column":24}} + } + } + }, + "body": { + "type": "BlockStatement", + "start":204,"end":206,"loc":{"start":{"line":8,"column":26},"end":{"line":8,"column":28}}, + "body": [], + "directives": [] + } + }, + "finalizer": null + }, + { + "type": "TryStatement", + "start":207,"end":244,"loc":{"start":{"line":9,"column":0},"end":{"line":9,"column":37}}, + "block": { + "type": "BlockStatement", + "start":211,"end":213,"loc":{"start":{"line":9,"column":4},"end":{"line":9,"column":6}}, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start":214,"end":244,"loc":{"start":{"line":9,"column":7},"end":{"line":9,"column":37}}, + "param": { + "type": "Identifier", + "start":221,"end":223,"loc":{"start":{"line":9,"column":14},"end":{"line":9,"column":16},"identifierName":"ex"}, + "name": "ex", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":223,"end":240,"loc":{"start":{"line":9,"column":16},"end":{"line":9,"column":33}}, + "typeAnnotation": { + "type": "TSUnionType", + "start":225,"end":240,"loc":{"start":{"line":9,"column":18},"end":{"line":9,"column":33}}, + "types": [ + { + "type": "TSStringKeyword", + "start":225,"end":231,"loc":{"start":{"line":9,"column":18},"end":{"line":9,"column":24}} + }, + { + "type": "TSNumberKeyword", + "start":234,"end":240,"loc":{"start":{"line":9,"column":27},"end":{"line":9,"column":33}} + } + ] + } + } + }, + "body": { + "type": "BlockStatement", + "start":242,"end":244,"loc":{"start":{"line":9,"column":35},"end":{"line":9,"column":37}}, + "body": [], + "directives": [] + } + }, + "finalizer": null + } + ], + "directives": [] + }, + "comments": [ + { + "type": "CommentLine", + "value": " The following can't be error'd at parse time", + "start":78,"end":125,"loc":{"start":{"line":5,"column":0},"end":{"line":5,"column":47}} + } + ] +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-1/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-1/input.ts new file mode 100644 index 000000000000..8b4d80dddbfb --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-1/input.ts @@ -0,0 +1 @@ +type T = [x.y: A]; diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-1/options.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-1/options.json new file mode 100644 index 000000000000..d1b7c8ebeace --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-1/options.json @@ -0,0 +1,6 @@ +{ + "sourceType": "module", + "plugins": [ + "typescript" + ] +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-1/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-1/output.json new file mode 100644 index 000000000000..f78fc791b541 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-1/output.json @@ -0,0 +1,63 @@ +{ + "type": "File", + "start":0,"end":18,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":18}}, + "errors": [ + "SyntaxError: Tuple members must be labeled with a simple identifier. (1:10)" + ], + "program": { + "type": "Program", + "start":0,"end":18,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":18}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start":0,"end":18,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":18}}, + "id": { + "type": "Identifier", + "start":5,"end":6,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":6},"identifierName":"T"}, + "name": "T" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start":9,"end":17,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":17}}, + "elementTypes": [ + { + "type": "TSNamedTupleMember", + "start":10,"end":16,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":16}}, + "optional": false, + "label": { + "type": "TSTypeReference", + "start":10,"end":13,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":13}}, + "typeName": { + "type": "TSQualifiedName", + "start":10,"end":13,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":13}}, + "left": { + "type": "Identifier", + "start":10,"end":11,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":11},"identifierName":"x"}, + "name": "x" + }, + "right": { + "type": "Identifier", + "start":12,"end":13,"loc":{"start":{"line":1,"column":12},"end":{"line":1,"column":13},"identifierName":"y"}, + "name": "y" + } + } + }, + "elementType": { + "type": "TSTypeReference", + "start":15,"end":16,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":16}}, + "typeName": { + "type": "Identifier", + "start":15,"end":16,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":16},"identifierName":"A"}, + "name": "A" + } + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-2/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-2/input.ts new file mode 100644 index 000000000000..dc499f225690 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-2/input.ts @@ -0,0 +1 @@ +type T = [x: A]; diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-2/options.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-2/options.json new file mode 100644 index 000000000000..d1b7c8ebeace --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-2/options.json @@ -0,0 +1,6 @@ +{ + "sourceType": "module", + "plugins": [ + "typescript" + ] +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-2/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-2/output.json new file mode 100644 index 000000000000..37710a11ffc3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-2/output.json @@ -0,0 +1,69 @@ +{ + "type": "File", + "start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}}, + "errors": [ + "SyntaxError: Tuple members must be labeled with a simple identifier. (1:10)" + ], + "program": { + "type": "Program", + "start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}}, + "id": { + "type": "Identifier", + "start":5,"end":6,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":6},"identifierName":"T"}, + "name": "T" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start":9,"end":18,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":18}}, + "elementTypes": [ + { + "type": "TSNamedTupleMember", + "start":10,"end":17,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":17}}, + "optional": false, + "label": { + "type": "TSTypeReference", + "start":10,"end":14,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":14}}, + "typeName": { + "type": "Identifier", + "start":10,"end":11,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":11},"identifierName":"x"}, + "name": "x" + }, + "typeParameters": { + "type": "TSTypeParameterInstantiation", + "start":11,"end":14,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":14}}, + "params": [ + { + "type": "TSTypeReference", + "start":12,"end":13,"loc":{"start":{"line":1,"column":12},"end":{"line":1,"column":13}}, + "typeName": { + "type": "Identifier", + "start":12,"end":13,"loc":{"start":{"line":1,"column":12},"end":{"line":1,"column":13},"identifierName":"y"}, + "name": "y" + } + } + ] + } + }, + "elementType": { + "type": "TSTypeReference", + "start":16,"end":17,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":17}}, + "typeName": { + "type": "Identifier", + "start":16,"end":17,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":17},"identifierName":"A"}, + "name": "A" + } + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-after-unlabeled/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-after-unlabeled/input.ts new file mode 100644 index 000000000000..938829fbc562 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-after-unlabeled/input.ts @@ -0,0 +1 @@ +type T = [A, y: B]; diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-after-unlabeled/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-after-unlabeled/output.json new file mode 100644 index 000000000000..c0deaecdd5f3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-after-unlabeled/output.json @@ -0,0 +1,59 @@ +{ + "type": "File", + "start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}}, + "errors": [ + "SyntaxError: Tuple members must all have names or all not have names. (1:13)" + ], + "program": { + "type": "Program", + "start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}}, + "id": { + "type": "Identifier", + "start":5,"end":6,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":6},"identifierName":"T"}, + "name": "T" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start":9,"end":18,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":18}}, + "elementTypes": [ + { + "type": "TSTypeReference", + "start":10,"end":11,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":11}}, + "typeName": { + "type": "Identifier", + "start":10,"end":11,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":11},"identifierName":"A"}, + "name": "A" + } + }, + { + "type": "TSNamedTupleMember", + "start":13,"end":17,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":17}}, + "optional": false, + "label": { + "type": "Identifier", + "start":13,"end":14,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":14},"identifierName":"y"}, + "name": "y" + }, + "elementType": { + "type": "TSTypeReference", + "start":16,"end":17,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":17}}, + "typeName": { + "type": "Identifier", + "start":16,"end":17,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":17},"identifierName":"B"}, + "name": "B" + } + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-before-unlabeled/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-before-unlabeled/input.ts new file mode 100644 index 000000000000..c0191826d929 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-before-unlabeled/input.ts @@ -0,0 +1 @@ +type T = [x: A, B]; diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-before-unlabeled/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-before-unlabeled/output.json new file mode 100644 index 000000000000..083db448c753 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-before-unlabeled/output.json @@ -0,0 +1,59 @@ +{ + "type": "File", + "start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}}, + "errors": [ + "SyntaxError: Tuple members must all have names or all not have names. (1:16)" + ], + "program": { + "type": "Program", + "start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}}, + "id": { + "type": "Identifier", + "start":5,"end":6,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":6},"identifierName":"T"}, + "name": "T" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start":9,"end":18,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":18}}, + "elementTypes": [ + { + "type": "TSNamedTupleMember", + "start":10,"end":14,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":14}}, + "optional": false, + "label": { + "type": "Identifier", + "start":10,"end":11,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":11},"identifierName":"x"}, + "name": "x" + }, + "elementType": { + "type": "TSTypeReference", + "start":13,"end":14,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":14}}, + "typeName": { + "type": "Identifier", + "start":13,"end":14,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":14},"identifierName":"A"}, + "name": "A" + } + } + }, + { + "type": "TSTypeReference", + "start":16,"end":17,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":17}}, + "typeName": { + "type": "Identifier", + "start":16,"end":17,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":17},"identifierName":"B"}, + "name": "B" + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/input.ts new file mode 100644 index 000000000000..aa8784ffd62f --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/input.ts @@ -0,0 +1 @@ +type T = [x: A?]; 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 new file mode 100644 index 000000000000..32484cd670a1 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/options.json @@ -0,0 +1,7 @@ +{ + "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-spread/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-spread/input.ts new file mode 100644 index 000000000000..1f84d8117f3b --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-spread/input.ts @@ -0,0 +1 @@ +let x: [A: string, ...B: number[]] diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-spread/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-spread/output.json new file mode 100644 index 000000000000..e0a6607cfd8e --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-spread/output.json @@ -0,0 +1,76 @@ +{ + "type": "File", + "start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":34}}, + "program": { + "type": "Program", + "start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":34}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "VariableDeclaration", + "start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":34}}, + "declarations": [ + { + "type": "VariableDeclarator", + "start":4,"end":34,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":34}}, + "id": { + "type": "Identifier", + "start":4,"end":34,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":34},"identifierName":"x"}, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":5,"end":34,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":34}}, + "typeAnnotation": { + "type": "TSTupleType", + "start":7,"end":34,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":34}}, + "elementTypes": [ + { + "type": "TSNamedTupleMember", + "start":8,"end":17,"loc":{"start":{"line":1,"column":8},"end":{"line":1,"column":17}}, + "optional": false, + "label": { + "type": "Identifier", + "start":8,"end":9,"loc":{"start":{"line":1,"column":8},"end":{"line":1,"column":9},"identifierName":"A"}, + "name": "A" + }, + "elementType": { + "type": "TSStringKeyword", + "start":11,"end":17,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":17}} + } + }, + { + "type": "TSRestType", + "start":19,"end":33,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":33}}, + "typeAnnotation": { + "type": "TSNamedTupleMember", + "start":22,"end":33,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":33}}, + "optional": false, + "label": { + "type": "Identifier", + "start":22,"end":23,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":23},"identifierName":"B"}, + "name": "B" + }, + "elementType": { + "type": "TSArrayType", + "start":25,"end":33,"loc":{"start":{"line":1,"column":25},"end":{"line":1,"column":33}}, + "elementType": { + "type": "TSNumberKeyword", + "start":25,"end":31,"loc":{"start":{"line":1,"column":25},"end":{"line":1,"column":31}} + } + } + } + } + ] + } + } + }, + "init": null + } + ], + "kind": "let" + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled/input.ts new file mode 100644 index 000000000000..4ded9c4935fa --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled/input.ts @@ -0,0 +1 @@ +type T = [foo: string, bar?: number]; diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled/output.json new file mode 100644 index 000000000000..f8ddae722eb3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled/output.json @@ -0,0 +1,56 @@ +{ + "type": "File", + "start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}}, + "program": { + "type": "Program", + "start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}}, + "id": { + "type": "Identifier", + "start":5,"end":6,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":6},"identifierName":"T"}, + "name": "T" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start":9,"end":36,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":36}}, + "elementTypes": [ + { + "type": "TSNamedTupleMember", + "start":10,"end":21,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":21}}, + "optional": false, + "label": { + "type": "Identifier", + "start":10,"end":13,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":13},"identifierName":"foo"}, + "name": "foo" + }, + "elementType": { + "type": "TSStringKeyword", + "start":15,"end":21,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":21}} + } + }, + { + "type": "TSNamedTupleMember", + "start":23,"end":35,"loc":{"start":{"line":1,"column":23},"end":{"line":1,"column":35}}, + "optional": true, + "label": { + "type": "Identifier", + "start":23,"end":26,"loc":{"start":{"line":1,"column":23},"end":{"line":1,"column":26},"identifierName":"bar"}, + "name": "bar" + }, + "elementType": { + "type": "TSNumberKeyword", + "start":29,"end":35,"loc":{"start":{"line":1,"column":29},"end":{"line":1,"column":35}} + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-required-after-labeled-optional/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-required-after-labeled-optional/input.ts new file mode 100644 index 000000000000..65546562d1c2 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-required-after-labeled-optional/input.ts @@ -0,0 +1 @@ +type T = [x?: A, y: B]; diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-required-after-labeled-optional/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-required-after-labeled-optional/output.json new file mode 100644 index 000000000000..6675981261a0 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-required-after-labeled-optional/output.json @@ -0,0 +1,69 @@ +{ + "type": "File", + "start":0,"end":23,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":23}}, + "errors": [ + "SyntaxError: A required element cannot follow an optional element. (1:17)" + ], + "program": { + "type": "Program", + "start":0,"end":23,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":23}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start":0,"end":23,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":23}}, + "id": { + "type": "Identifier", + "start":5,"end":6,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":6},"identifierName":"T"}, + "name": "T" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start":9,"end":22,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":22}}, + "elementTypes": [ + { + "type": "TSNamedTupleMember", + "start":10,"end":15,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":15}}, + "optional": true, + "label": { + "type": "Identifier", + "start":10,"end":11,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":11},"identifierName":"x"}, + "name": "x" + }, + "elementType": { + "type": "TSTypeReference", + "start":14,"end":15,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":15}}, + "typeName": { + "type": "Identifier", + "start":14,"end":15,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":15},"identifierName":"A"}, + "name": "A" + } + } + }, + { + "type": "TSNamedTupleMember", + "start":17,"end":21,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":21}}, + "optional": false, + "label": { + "type": "Identifier", + "start":17,"end":18,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":18},"identifierName":"y"}, + "name": "y" + }, + "elementType": { + "type": "TSTypeReference", + "start":20,"end":21,"loc":{"start":{"line":1,"column":20},"end":{"line":1,"column":21}}, + "typeName": { + "type": "Identifier", + "start":20,"end":21,"loc":{"start":{"line":1,"column":20},"end":{"line":1,"column":21},"identifierName":"B"}, + "name": "B" + } + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-invalid/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-invalid/input.ts deleted file mode 100644 index 2bfeae2e87eb..000000000000 --- a/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-invalid/input.ts +++ /dev/null @@ -1 +0,0 @@ -let x: [...number[], string] diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-invalid/options.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-invalid/options.json deleted file mode 100644 index 82b4f09fc940..000000000000 --- a/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-invalid/options.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sourceType": "module", - "plugins": ["typescript"], - "throws": "Rest element must be last element (1:19)" -} diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-not-last/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-not-last/input.ts new file mode 100644 index 000000000000..050a60b540ea --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-not-last/input.ts @@ -0,0 +1 @@ +let x: [...[number, string], string] diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-not-last/options.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-not-last/options.json new file mode 100644 index 000000000000..fe9bffaa5e1a --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-not-last/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "plugins": ["typescript"] +} diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-not-last/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-not-last/output.json new file mode 100644 index 000000000000..5d0076a745ba --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-rest-not-last/output.json @@ -0,0 +1,62 @@ +{ + "type": "File", + "start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}}, + "program": { + "type": "Program", + "start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "VariableDeclaration", + "start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}}, + "declarations": [ + { + "type": "VariableDeclarator", + "start":4,"end":36,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":36}}, + "id": { + "type": "Identifier", + "start":4,"end":36,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":36},"identifierName":"x"}, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":5,"end":36,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":36}}, + "typeAnnotation": { + "type": "TSTupleType", + "start":7,"end":36,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":36}}, + "elementTypes": [ + { + "type": "TSRestType", + "start":8,"end":27,"loc":{"start":{"line":1,"column":8},"end":{"line":1,"column":27}}, + "typeAnnotation": { + "type": "TSTupleType", + "start":11,"end":27,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":27}}, + "elementTypes": [ + { + "type": "TSNumberKeyword", + "start":12,"end":18,"loc":{"start":{"line":1,"column":12},"end":{"line":1,"column":18}} + }, + { + "type": "TSStringKeyword", + "start":20,"end":26,"loc":{"start":{"line":1,"column":20},"end":{"line":1,"column":26}} + } + ] + } + }, + { + "type": "TSStringKeyword", + "start":29,"end":35,"loc":{"start":{"line":1,"column":29},"end":{"line":1,"column":35}} + } + ] + } + } + }, + "init": null + } + ], + "kind": "let" + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-unlabeled-spread-after-labeled/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-unlabeled-spread-after-labeled/input.ts new file mode 100644 index 000000000000..82ac1034fda4 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-unlabeled-spread-after-labeled/input.ts @@ -0,0 +1 @@ +type T = [x: A, ...B]; diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-unlabeled-spread-after-labeled/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-unlabeled-spread-after-labeled/output.json new file mode 100644 index 000000000000..24e7d290ecd6 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-unlabeled-spread-after-labeled/output.json @@ -0,0 +1,63 @@ +{ + "type": "File", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}}, + "errors": [ + "SyntaxError: Tuple members must all have names or all not have names. (1:19)" + ], + "program": { + "type": "Program", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}}, + "id": { + "type": "Identifier", + "start":5,"end":6,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":6},"identifierName":"T"}, + "name": "T" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start":9,"end":21,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":21}}, + "elementTypes": [ + { + "type": "TSNamedTupleMember", + "start":10,"end":14,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":14}}, + "optional": false, + "label": { + "type": "Identifier", + "start":10,"end":11,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":11},"identifierName":"x"}, + "name": "x" + }, + "elementType": { + "type": "TSTypeReference", + "start":13,"end":14,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":14}}, + "typeName": { + "type": "Identifier", + "start":13,"end":14,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":14},"identifierName":"A"}, + "name": "A" + } + } + }, + { + "type": "TSRestType", + "start":16,"end":20,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":20}}, + "typeAnnotation": { + "type": "TSTypeReference", + "start":19,"end":20,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":20}}, + "typeName": { + "type": "Identifier", + "start":19,"end":20,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":20},"identifierName":"B"}, + "name": "B" + } + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-unlabeled-spread-before-labeled/input.ts b/packages/babel-parser/test/fixtures/typescript/types/tuple-unlabeled-spread-before-labeled/input.ts new file mode 100644 index 000000000000..a45bda9425f3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-unlabeled-spread-before-labeled/input.ts @@ -0,0 +1 @@ +type T = [...B, x: A]; diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-unlabeled-spread-before-labeled/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-unlabeled-spread-before-labeled/output.json new file mode 100644 index 000000000000..5115e0744bd4 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-unlabeled-spread-before-labeled/output.json @@ -0,0 +1,63 @@ +{ + "type": "File", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}}, + "errors": [ + "SyntaxError: Tuple members must all have names or all not have names. (1:16)" + ], + "program": { + "type": "Program", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}}, + "id": { + "type": "Identifier", + "start":5,"end":6,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":6},"identifierName":"T"}, + "name": "T" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start":9,"end":21,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":21}}, + "elementTypes": [ + { + "type": "TSRestType", + "start":10,"end":14,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":14}}, + "typeAnnotation": { + "type": "TSTypeReference", + "start":13,"end":14,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":14}}, + "typeName": { + "type": "Identifier", + "start":13,"end":14,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":14},"identifierName":"B"}, + "name": "B" + } + } + }, + { + "type": "TSNamedTupleMember", + "start":16,"end":20,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":20}}, + "optional": false, + "label": { + "type": "Identifier", + "start":16,"end":17,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":17},"identifierName":"x"}, + "name": "x" + }, + "elementType": { + "type": "TSTypeReference", + "start":19,"end":20,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":20}}, + "typeName": { + "type": "Identifier", + "start":19,"end":20,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":20},"identifierName":"A"}, + "name": "A" + } + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/catch-clause/param-type/input.ts b/packages/babel-plugin-transform-typescript/test/fixtures/catch-clause/param-type/input.ts new file mode 100644 index 000000000000..0aa11053c6ee --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/catch-clause/param-type/input.ts @@ -0,0 +1 @@ +try {} catch (e: any) {} diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/catch-clause/param-type/options.json b/packages/babel-plugin-transform-typescript/test/fixtures/catch-clause/param-type/options.json new file mode 100644 index 000000000000..d5e8a7e4201b --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/catch-clause/param-type/options.json @@ -0,0 +1,4 @@ +{ + "plugins": ["transform-typescript"], + "sourceType": "module" +} diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/catch-clause/param-type/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/catch-clause/param-type/output.mjs new file mode 100644 index 000000000000..0ead89004c5c --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/catch-clause/param-type/output.mjs @@ -0,0 +1 @@ +try {} catch (e) {} diff --git a/packages/babel-types/src/asserts/generated/index.js b/packages/babel-types/src/asserts/generated/index.js index 457103a16b71..2c24ad6a5496 100644 --- a/packages/babel-types/src/asserts/generated/index.js +++ b/packages/babel-types/src/asserts/generated/index.js @@ -920,6 +920,12 @@ export function assertTSOptionalType(node: Object, opts?: Object = {}): void { export function assertTSRestType(node: Object, opts?: Object = {}): void { assert("TSRestType", node, opts); } +export function assertTSNamedTupleMember( + node: Object, + opts?: Object = {}, +): void { + assert("TSNamedTupleMember", node, opts); +} export function assertTSUnionType(node: Object, opts?: Object = {}): void { assert("TSUnionType", node, opts); } diff --git a/packages/babel-types/src/builders/generated/index.js b/packages/babel-types/src/builders/generated/index.js index 321a666787ef..905b4676cb06 100644 --- a/packages/babel-types/src/builders/generated/index.js +++ b/packages/babel-types/src/builders/generated/index.js @@ -890,6 +890,11 @@ export function tsRestType(...args: Array): Object { } export { tsRestType as TSRestType }; export { tsRestType as tSRestType }; +export function tsNamedTupleMember(...args: Array): Object { + return builder("TSNamedTupleMember", ...args); +} +export { tsNamedTupleMember as TSNamedTupleMember }; +export { tsNamedTupleMember as tSNamedTupleMember }; export function tsUnionType(...args: Array): Object { return builder("TSUnionType", ...args); } diff --git a/packages/babel-types/src/definitions/typescript.js b/packages/babel-types/src/definitions/typescript.js index e4ec9872d918..b74c350c0f3f 100644 --- a/packages/babel-types/src/definitions/typescript.js +++ b/packages/babel-types/src/definitions/typescript.js @@ -212,7 +212,7 @@ defineType("TSTupleType", { aliases: ["TSType"], visitor: ["elementTypes"], fields: { - elementTypes: validateArrayOfType("TSType"), + elementTypes: validateArrayOfType(["TSType", "TSNamedTupleMember"]), }, }); @@ -232,6 +232,19 @@ defineType("TSRestType", { }, }); +defineType("TSNamedTupleMember", { + visitor: ["label", "elementType"], + builder: ["label", "elementType", "optional"], + fields: { + label: validateType("Identifier"), + optional: { + validate: bool, + default: false, + }, + elementType: validateType("TSType"), + }, +}); + const unionOrIntersection = { aliases: ["TSType"], visitor: ["types"], diff --git a/packages/babel-types/src/validators/generated/index.js b/packages/babel-types/src/validators/generated/index.js index 746034390aaf..1e353f0970c5 100644 --- a/packages/babel-types/src/validators/generated/index.js +++ b/packages/babel-types/src/validators/generated/index.js @@ -3027,6 +3027,20 @@ export function isTSRestType(node: ?Object, opts?: Object): boolean { return false; } +export function isTSNamedTupleMember(node: ?Object, opts?: Object): boolean { + if (!node) return false; + + const nodeType = node.type; + if (nodeType === "TSNamedTupleMember") { + if (typeof opts === "undefined") { + return true; + } else { + return shallowEqual(node, opts); + } + } + + return false; +} export function isTSUnionType(node: ?Object, opts?: Object): boolean { if (!node) return false; diff --git a/scripts/parser-tests/typescript/allowlist.txt b/scripts/parser-tests/typescript/allowlist.txt index eac6245793ea..ad5eb837ec79 100644 --- a/scripts/parser-tests/typescript/allowlist.txt +++ b/scripts/parser-tests/typescript/allowlist.txt @@ -48,6 +48,8 @@ augmentedTypesFunction.ts augmentedTypesInterface.ts augmentedTypesVar.ts bigintIndex.ts +binderBinaryExpressionStress.ts +binderBinaryExpressionStressJs.ts cacheResolutions.ts cachedModuleResolution1.ts cachedModuleResolution2.ts @@ -64,6 +66,7 @@ classCannotExtendVar.ts classExpressionWithDecorator1.ts classExtendsAcrossFiles.ts classExtendsMultipleBaseClasses.ts +classIndexer5.ts classOverloadForFunction.ts collisionExportsRequireAndClass.ts commonSourceDir5.ts @@ -87,8 +90,10 @@ declarationEmitDestructuringOptionalBindingParametersInOverloads.ts declarationEmitDestructuringParameterProperties.ts declarationEmitDestructuringWithOptionalBindingParameters.ts declarationEmitExpandoPropertyPrivateName.ts +declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.ts declarationEmitExportAssignment.ts declarationEmitExportDeclaration.ts +declarationEmitForModuleImportingModuleAugmentationRetainsImport.ts declarationEmitForTypesWhichNeedImportTypes.ts declarationEmitInterfaceWithNonEntityNameExpressionHeritage.ts declarationEmitPrefersPathKindBasedOnBundling.ts @@ -98,6 +103,7 @@ declarationImportTypeAliasInferredAndEmittable.ts declarationMapsMultifile.ts declarationMapsOutFile.ts declarationsForInferredTypeFromOtherFile.ts +declarationsIndirectGeneratedAliasReference.ts declareModifierOnImport1.ts decoratorMetadataRestParameterWithImportedType.ts decoratorMetadataWithImportDeclarationNameCollision.ts @@ -195,6 +201,7 @@ exportSameNameFuncVar.ts exportSpecifierAndExportedMemberDeclaration.ts exportSpecifierAndLocalMemberDeclaration.ts exportStarFromEmptyModule.ts +exportStarNotElided.ts expressionsForbiddenInParameterInitializers.ts extendingClassFromAliasAndUsageInIndexer.ts extendsClauseAlreadySeen.ts @@ -209,6 +216,8 @@ functionExpressionInWithBlock.ts functionExpressionWithResolutionOfTypeNamedArguments01.ts gettersAndSettersErrors.ts giant.ts +globalThisDeclarationEmit.ts +globalThisDeclarationEmit2.ts implementClausePrecedingExtends.ts implementsClauseAlreadySeen.ts importAndVariableDeclarationConflict1.ts @@ -227,13 +236,24 @@ importHelpersNoHelpers.ts importHelpersNoModule.ts importHelpersOutFile.ts importHelpersSystem.ts +importNonExportedMember10.ts +importNonExportedMember11.ts +importNonExportedMember4.ts +importNonExportedMember5.ts +importNonExportedMember6.ts +importNonExportedMember7.ts +importNonExportedMember8.ts +importNonExportedMember9.ts importWithTrailingSlash.ts +importedEnumMemberMergedWithExportedAliasIsError.ts importedModuleClassNameClash.ts indexSignatureWithAccessibilityModifier.ts indexSignatureWithInitializer1.ts +indexSignatureWithTrailingComma.ts indexTypeCheck.ts indexWithoutParamType.ts indexerSignatureWithRestParam.ts +inferrenceInfiniteLoopWithSubtyping.ts initializedParameterBeforeNonoptionalNotOptional.ts interfaceMayNotBeExtendedWitACall.ts interfaceWithImplements1.ts @@ -242,12 +262,15 @@ isLiteral1.ts isLiteral2.ts isolatedModulesReExportType.ts jsEnumTagOnObjectFrozen.ts +jsExportMemberMergedWithModuleAugmentation.ts jsFileCompilationBindDuplicateIdentifier.ts jsFileCompilationDuplicateFunctionImplementation.ts jsFileCompilationDuplicateFunctionImplementationFileOrderReversed.ts jsFileCompilationExternalPackageError.ts +jsFileImportPreservedWhenUsed.ts jsNoImplicitAnyNoCascadingReferenceErrors.ts jsdocAccessEnumType.ts +jsdocPropertyTagInvalid.ts jsxAttributeWithoutExpressionReact.tsx jsxIntrinsicElementsExtendsRecord.tsx letAndVarRedeclaration.ts @@ -335,6 +358,8 @@ preserveUnusedImports.ts privacyCheckExternalModuleExportAssignmentOfGenericClass.ts privacyTopLevelAmbientExternalModuleImportWithExport.ts privacyTopLevelAmbientExternalModuleImportWithoutExport.ts +privateFieldAssignabilityFromUnknown.ts +privateNameWeakMapCollision.ts reExportGlobalDeclaration1.ts reExportUndefined1.ts reExportUndefined2.ts @@ -388,6 +413,7 @@ unusedImports3.ts unusedImports4.ts unusedImports5.ts unusedInvalidTypeArguments.ts +usedImportNotElidedInJs.ts varAndFunctionShareName.ts varArgConstructorMemberParameter.ts withStatement.ts diff --git a/scripts/parser-tests/typescript/error-codes.js b/scripts/parser-tests/typescript/error-codes.js index 2a2580dfb8a2..16ce4eb71c94 100644 --- a/scripts/parser-tests/typescript/error-codes.js +++ b/scripts/parser-tests/typescript/error-codes.js @@ -40,7 +40,7 @@ module.exports = [ "TS1163", // A 'yield' expression is only allowed in a generator body. "TS1184", // Modifiers cannot appear here. "TS1191", // An import declaration cannot have modifiers. - "TS1196", // Catch clause variable cannot have a type annotation. + "TS1196", // Catch clause variable type annotation must be 'any' or 'unknown' if specified. "TS1197", // Catch clause variable cannot have an initializer. "TS1200", // Line terminator not permitted before arrow. "TS1312", // '=' can only be used in an object literal property inside a destructuring assignment.