diff --git a/Makefile b/Makefile index 6537e089b8f7..2063f2445c7c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ FLOW_COMMIT = a1f9a4c709dcebb27a5084acf47755fbae699c25 TEST262_COMMIT = 058adfed86b1d4129996faaf50a85ea55379a66a -TYPESCRIPT_COMMIT = d779a190535e52896cfe5100101173c00b6b8625 +TYPESCRIPT_COMMIT = da8633212023517630de5f3620a23736b63234b1 FORCE_PUBLISH = "@babel/runtime,@babel/runtime-corejs2,@babel/runtime-corejs3,@babel/standalone" diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 4321bbf5f437..78ea2f01d7ca 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -1605,7 +1605,7 @@ export default class ExpressionParser extends LValParser { node.quasis = [curElt]; while (!curElt.tail) { this.expect(tt.dollarBraceL); - node.expressions.push(this.parseExpression()); + node.expressions.push(this.parseTemplateSubstitution()); this.expect(tt.braceR); node.quasis.push((curElt = this.parseTemplateElement(isTagged))); } @@ -1613,6 +1613,11 @@ export default class ExpressionParser extends LValParser { return this.finishNode(node, "TemplateLiteral"); } + // This is overwritten by the TypeScript plugin to parse template types + parseTemplateSubstitution(): N.Expression { + return this.parseExpression(); + } + // Parse an object literal, binding pattern, or record. parseObjectLike( diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 1b9b7f1f3e83..39307b13d135 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -94,8 +94,6 @@ const TSErrors = Object.freeze({ "Private elements cannot have the 'abstract' modifier.", PrivateElementHasAccessibility: "Private elements cannot have an accessibility modifier ('%0')", - TemplateTypeHasSubstitution: - "Template literal types cannot have any substitution", TypeAnnotationAfterAssign: "Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`", UnexpectedParameterModifier: @@ -773,17 +771,15 @@ export default (superClass: Class): Class => tsParseTemplateLiteralType(): N.TsType { const node: N.TsLiteralType = this.startNode(); - const templateNode = this.parseTemplate(false); - if (templateNode.expressions.length > 0) { - this.raise( - templateNode.expressions[0].start, - TSErrors.TemplateTypeHasSubstitution, - ); - } - node.literal = templateNode; + node.literal = this.parseTemplate(false); return this.finishNode(node, "TSLiteralType"); } + parseTemplateSubstitution(): N.TsType { + if (this.state.inType) return this.tsParseType(); + return super.parseTemplateSubstitution(); + } + tsParseThisTypeOrThisTypePredicate(): N.TsThisType | N.TsTypePredicate { const thisKeyword = this.tsParseThisTypeNode(); if (this.isContextual("is") && !this.hasPrecedingLineBreak()) { diff --git a/packages/babel-parser/test/fixtures/typescript/types/literal-string-2/output.json b/packages/babel-parser/test/fixtures/typescript/types/literal-string-2/output.json index 1b6b7291f9be..3459f5976eda 100644 --- a/packages/babel-parser/test/fixtures/typescript/types/literal-string-2/output.json +++ b/packages/babel-parser/test/fixtures/typescript/types/literal-string-2/output.json @@ -1,9 +1,6 @@ { "type": "File", "start":0,"end":20,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":20}}, - "errors": [ - "SyntaxError: Template literal types cannot have any substitution (1:14)" - ], "program": { "type": "Program", "start":0,"end":20,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":20}}, @@ -32,9 +29,13 @@ "start":7,"end":19,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":19}}, "expressions": [ { - "type": "Identifier", - "start":14,"end":17,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":17},"identifierName":"bar"}, - "name": "bar" + "type": "TSTypeReference", + "start":14,"end":17,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":17}}, + "typeName": { + "type": "Identifier", + "start":14,"end":17,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":17},"identifierName":"bar"}, + "name": "bar" + } } ], "quasis": [ diff --git a/packages/babel-parser/test/fixtures/typescript/types/literal-string-3/input.ts b/packages/babel-parser/test/fixtures/typescript/types/literal-string-3/input.ts new file mode 100644 index 000000000000..994ef1af2ab2 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/literal-string-3/input.ts @@ -0,0 +1 @@ +let x: `foo-${bar + baz}`; diff --git a/packages/babel-parser/test/fixtures/typescript/types/literal-string-3/options.json b/packages/babel-parser/test/fixtures/typescript/types/literal-string-3/options.json new file mode 100644 index 000000000000..92ccb389f675 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/literal-string-3/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token, expected \"}\" (1:18)" +} diff --git a/packages/babel-parser/test/fixtures/typescript/types/literal-string-4/input.ts b/packages/babel-parser/test/fixtures/typescript/types/literal-string-4/input.ts new file mode 100644 index 000000000000..020b98d485d3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/literal-string-4/input.ts @@ -0,0 +1 @@ +let x: `foo-${infer bar}`; diff --git a/packages/babel-parser/test/fixtures/typescript/types/literal-string-4/output.json b/packages/babel-parser/test/fixtures/typescript/types/literal-string-4/output.json new file mode 100644 index 000000000000..5bc58ae9d4ba --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/literal-string-4/output.json @@ -0,0 +1,73 @@ +{ + "type": "File", + "start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}}, + "program": { + "type": "Program", + "start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "VariableDeclaration", + "start":0,"end":26,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":26}}, + "declarations": [ + { + "type": "VariableDeclarator", + "start":4,"end":25,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":25}}, + "id": { + "type": "Identifier", + "start":4,"end":25,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":25},"identifierName":"x"}, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":5,"end":25,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":25}}, + "typeAnnotation": { + "type": "TSLiteralType", + "start":7,"end":25,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":25}}, + "literal": { + "type": "TemplateLiteral", + "start":7,"end":25,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":25}}, + "expressions": [ + { + "type": "TSInferType", + "start":14,"end":23,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":23}}, + "typeParameter": { + "type": "TSTypeParameter", + "start":20,"end":23,"loc":{"start":{"line":1,"column":20},"end":{"line":1,"column":23}}, + "name": "bar" + } + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start":8,"end":12,"loc":{"start":{"line":1,"column":8},"end":{"line":1,"column":12}}, + "value": { + "raw": "foo-", + "cooked": "foo-" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start":24,"end":24,"loc":{"start":{"line":1,"column":24},"end":{"line":1,"column":24}}, + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ] + } + } + } + }, + "init": null + } + ], + "kind": "let" + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-types/src/definitions/core.js b/packages/babel-types/src/definitions/core.js index 03e16da49226..4072d7bc0b6a 100644 --- a/packages/babel-types/src/definitions/core.js +++ b/packages/babel-types/src/definitions/core.js @@ -1841,7 +1841,13 @@ defineType("TemplateLiteral", { expressions: { validate: chain( assertValueType("array"), - assertEach(assertNodeType("Expression")), + assertEach( + assertNodeType( + "Expression", + // For TypeScript template literal types + "TSType", + ), + ), function (node, key, val) { if (node.quasis.length !== val.length + 1) { throw new TypeError( diff --git a/scripts/parser-tests/typescript/allowlist.txt b/scripts/parser-tests/typescript/allowlist.txt index a773587592ec..6f73e1c8fc58 100644 --- a/scripts/parser-tests/typescript/allowlist.txt +++ b/scripts/parser-tests/typescript/allowlist.txt @@ -226,6 +226,7 @@ gettersAndSettersErrors.ts giant.ts globalThisDeclarationEmit.ts globalThisDeclarationEmit2.ts +hugeDeclarationOutputGetsTruncatedWithError.ts implementClausePrecedingExtends.ts implementsClauseAlreadySeen.ts importAndVariableDeclarationConflict1.ts