diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 1cd8e16a0495f..817c5122199a0 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -4124,8 +4124,18 @@ namespace ts { case SyntaxKind.TemplateHead: case SyntaxKind.TemplateMiddle: case SyntaxKind.TemplateTail: - case SyntaxKind.TemplateExpression: + if ((node).templateFlags) { + transformFlags |= TransformFlags.AssertES2018; + break; + } + // falls through case SyntaxKind.TaggedTemplateExpression: + if (hasInvalidEscape((node).template)) { + transformFlags |= TransformFlags.AssertES2018; + break; + } + // falls through + case SyntaxKind.TemplateExpression: case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.StaticKeyword: case SyntaxKind.MetaProperty: diff --git a/src/compiler/factoryPublic.ts b/src/compiler/factoryPublic.ts index 2c59abbb494dc..4479e6c2e711e 100644 --- a/src/compiler/factoryPublic.ts +++ b/src/compiler/factoryPublic.ts @@ -1486,7 +1486,7 @@ namespace ts { let token = rawTextScanner.scan(); if (token === SyntaxKind.CloseBracketToken) { - token = rawTextScanner.reScanTemplateToken(); + token = rawTextScanner.reScanTemplateToken(/* isTaggedTemplate */ false); } if (rawTextScanner.isUnterminated()) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e990c0f675c32..621725827584b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1137,8 +1137,12 @@ namespace ts { return currentToken = scanner.reScanSlashToken(); } - function reScanTemplateToken(): SyntaxKind { - return currentToken = scanner.reScanTemplateToken(); + function reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind { + return currentToken = scanner.reScanTemplateToken(isTaggedTemplate); + } + + function reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind { + return currentToken = scanner.reScanTemplateHeadOrNoSubstitutionTemplate(); } function reScanLessThanToken(): SyntaxKind { @@ -2329,17 +2333,17 @@ namespace ts { return allowIdentifierNames ? parseIdentifierName() : parseIdentifier(); } - function parseTemplateExpression(): TemplateExpression { + function parseTemplateExpression(isTaggedTemplate: boolean): TemplateExpression { const template = createNode(SyntaxKind.TemplateExpression); - template.head = parseTemplateHead(); + template.head = parseTemplateHead(isTaggedTemplate); Debug.assert(template.head.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind"); const list = []; const listPos = getNodePos(); do { - list.push(parseTemplateSpan()); + list.push(parseTemplateSpan(isTaggedTemplate)); } while (last(list).literal.kind === SyntaxKind.TemplateMiddle); @@ -2348,13 +2352,13 @@ namespace ts { return finishNode(template); } - function parseTemplateSpan(): TemplateSpan { + function parseTemplateSpan(isTaggedTemplate: boolean): TemplateSpan { const span = createNode(SyntaxKind.TemplateSpan); span.expression = allowInAnd(parseExpression); let literal: TemplateMiddle | TemplateTail; if (token() === SyntaxKind.CloseBraceToken) { - reScanTemplateToken(); + reScanTemplateToken(isTaggedTemplate); literal = parseTemplateMiddleOrTemplateTail(); } else { @@ -2369,7 +2373,10 @@ namespace ts { return parseLiteralLikeNode(token()); } - function parseTemplateHead(): TemplateHead { + function parseTemplateHead(isTaggedTemplate: boolean): TemplateHead { + if (isTaggedTemplate) { + reScanTemplateHeadOrNoSubstitutionTemplate(); + } const fragment = parseLiteralLikeNode(token()); Debug.assert(fragment.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind"); return fragment; @@ -2413,6 +2420,10 @@ namespace ts { (node).numericLiteralFlags = scanner.getTokenFlags() & TokenFlags.NumericLiteralFlags; } + if (isTemplateLiteralKind(node.kind)) { + (node).templateFlags = scanner.getTokenFlags() & TokenFlags.ContainsInvalidEscape; + } + nextToken(); finishNode(node); @@ -4772,8 +4783,8 @@ namespace ts { tagExpression.questionDotToken = questionDotToken; tagExpression.typeArguments = typeArguments; tagExpression.template = token() === SyntaxKind.NoSubstitutionTemplateLiteral - ? parseLiteralNode() - : parseTemplateExpression(); + ? (reScanTemplateHeadOrNoSubstitutionTemplate(), parseLiteralNode()) + : parseTemplateExpression(/*isTaggedTemplate*/ true); if (questionDotToken || tag.flags & NodeFlags.OptionalChain) { tagExpression.flags |= NodeFlags.OptionalChain; } @@ -4945,7 +4956,7 @@ namespace ts { } break; case SyntaxKind.TemplateHead: - return parseTemplateExpression(); + return parseTemplateExpression(/* isTaggedTemplate */ false); } return parseIdentifier(Diagnostics.Expression_expected); diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 92d10f0b131fc..7172552a3ea69 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -28,7 +28,8 @@ namespace ts { getTokenFlags(): TokenFlags; reScanGreaterToken(): SyntaxKind; reScanSlashToken(): SyntaxKind; - reScanTemplateToken(): SyntaxKind; + reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind; + reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind; scanJsxIdentifier(): SyntaxKind; scanJsxAttributeValue(): SyntaxKind; reScanJsxAttributeValue(): SyntaxKind; @@ -468,6 +469,14 @@ namespace ts { return ch >= CharacterCodes._0 && ch <= CharacterCodes._9; } + function isHexDigit(ch: number): boolean { + return isDigit(ch) || ch >= CharacterCodes.A && ch <= CharacterCodes.F || ch >= CharacterCodes.a && ch <= CharacterCodes.f; + } + + function isCodePoint(code: number): boolean { + return code <= 0x10FFFF; + } + /* @internal */ export function isOctalDigit(ch: number): boolean { return ch >= CharacterCodes._0 && ch <= CharacterCodes._7; @@ -901,6 +910,7 @@ namespace ts { reScanGreaterToken, reScanSlashToken, reScanTemplateToken, + reScanTemplateHeadOrNoSubstitutionTemplate, scanJsxIdentifier, scanJsxAttributeValue, reScanJsxAttributeValue, @@ -1164,7 +1174,7 @@ namespace ts { * Sets the current 'tokenValue' and returns a NoSubstitutionTemplateLiteral or * a literal component of a TemplateExpression. */ - function scanTemplateAndSetTokenValue(): SyntaxKind { + function scanTemplateAndSetTokenValue(isTaggedTemplate: boolean): SyntaxKind { const startedWithBacktick = text.charCodeAt(pos) === CharacterCodes.backtick; pos++; @@ -1202,7 +1212,7 @@ namespace ts { // Escape character if (currChar === CharacterCodes.backslash) { contents += text.substring(start, pos); - contents += scanEscapeSequence(); + contents += scanEscapeSequence(isTaggedTemplate); start = pos; continue; } @@ -1231,7 +1241,8 @@ namespace ts { return resultingToken; } - function scanEscapeSequence(): string { + function scanEscapeSequence(isTaggedTemplate?: boolean): string { + const start = pos; pos++; if (pos >= end) { error(Diagnostics.Unexpected_end_of_text); @@ -1241,6 +1252,12 @@ namespace ts { pos++; switch (ch) { case CharacterCodes._0: + // '\01' + if (isTaggedTemplate && pos < end && isDigit(text.charCodeAt(pos))) { + pos++; + tokenFlags |= TokenFlags.ContainsInvalidEscape; + return text.substring(start, pos); + } return "\0"; case CharacterCodes.b: return "\b"; @@ -1259,10 +1276,41 @@ namespace ts { case CharacterCodes.doubleQuote: return "\""; case CharacterCodes.u: + if (isTaggedTemplate) { + // '\u' or '\u0' or '\u00' or '\u000' + for (let escapePos = pos; escapePos < pos + 4; escapePos++) { + if (escapePos < end && !isHexDigit(text.charCodeAt(escapePos)) && text.charCodeAt(escapePos) !== CharacterCodes.openBrace) { + pos = escapePos; + tokenFlags |= TokenFlags.ContainsInvalidEscape; + return text.substring(start, pos); + } + } + } // '\u{DDDDDDDD}' if (pos < end && text.charCodeAt(pos) === CharacterCodes.openBrace) { - tokenFlags |= TokenFlags.ExtendedUnicodeEscape; pos++; + + // '\u{' + if (isTaggedTemplate && !isHexDigit(text.charCodeAt(pos))) { + tokenFlags |= TokenFlags.ContainsInvalidEscape; + return text.substring(start, pos); + } + + if (isTaggedTemplate) { + const savePos = pos; + const escapedValueString = scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ false); + const escapedValue = escapedValueString ? parseInt(escapedValueString, 16) : -1; + + // '\u{Not Code Point' or '\u{CodePoint' + if (!isCodePoint(escapedValue) || text.charCodeAt(pos) !== CharacterCodes.closeBrace) { + tokenFlags |= TokenFlags.ContainsInvalidEscape; + return text.substring(start, pos); + } + else { + pos = savePos; + } + } + tokenFlags |= TokenFlags.ExtendedUnicodeEscape; return scanExtendedUnicodeEscape(); } @@ -1271,6 +1319,17 @@ namespace ts { return scanHexadecimalEscape(/*numDigits*/ 4); case CharacterCodes.x: + if (isTaggedTemplate) { + if (!isHexDigit(text.charCodeAt(pos))) { + tokenFlags |= TokenFlags.ContainsInvalidEscape; + return text.substring(start, pos); + } + else if (!isHexDigit(text.charCodeAt(pos + 1))) { + pos++; + tokenFlags |= TokenFlags.ContainsInvalidEscape; + return text.substring(start, pos); + } + } // '\xDD' return scanHexadecimalEscape(/*numDigits*/ 2); @@ -1561,7 +1620,7 @@ namespace ts { tokenValue = scanString(); return token = SyntaxKind.StringLiteral; case CharacterCodes.backtick: - return token = scanTemplateAndSetTokenValue(); + return token = scanTemplateAndSetTokenValue(/* isTaggedTemplate */ false); case CharacterCodes.percent: if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { return pos += 2, token = SyntaxKind.PercentEqualsToken; @@ -2019,10 +2078,15 @@ namespace ts { /** * Unconditionally back up and scan a template expression portion. */ - function reScanTemplateToken(): SyntaxKind { + function reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind { Debug.assert(token === SyntaxKind.CloseBraceToken, "'reScanTemplateToken' should only be called on a '}'"); pos = tokenPos; - return token = scanTemplateAndSetTokenValue(); + return token = scanTemplateAndSetTokenValue(isTaggedTemplate); + } + + function reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind { + pos = tokenPos; + return token = scanTemplateAndSetTokenValue(/* isTaggedTemplate */ true); } function reScanJsxToken(): JsxTokenSyntaxKind { diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 28722351b8d50..d4bf9605a2ebc 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -3951,78 +3951,14 @@ namespace ts { * @param node A TaggedTemplateExpression node. */ function visitTaggedTemplateExpression(node: TaggedTemplateExpression) { - // Visit the tag expression - const tag = visitNode(node.tag, visitor, isExpression); - - // Build up the template arguments and the raw and cooked strings for the template. - // We start out with 'undefined' for the first argument and revisit later - // to avoid walking over the template string twice and shifting all our arguments over after the fact. - const templateArguments: Expression[] = [undefined!]; - const cookedStrings: Expression[] = []; - const rawStrings: Expression[] = []; - const template = node.template; - if (isNoSubstitutionTemplateLiteral(template)) { - cookedStrings.push(createLiteral(template.text)); - rawStrings.push(getRawLiteral(template)); - } - else { - cookedStrings.push(createLiteral(template.head.text)); - rawStrings.push(getRawLiteral(template.head)); - for (const templateSpan of template.templateSpans) { - cookedStrings.push(createLiteral(templateSpan.literal.text)); - rawStrings.push(getRawLiteral(templateSpan.literal)); - templateArguments.push(visitNode(templateSpan.expression, visitor, isExpression)); - } - } - - const helperCall = createTemplateObjectHelper(context, createArrayLiteral(cookedStrings), createArrayLiteral(rawStrings)); - - // Create a variable to cache the template object if we're in a module. - // Do not do this in the global scope, as any variable we currently generate could conflict with - // variables from outside of the current compilation. In the future, we can revisit this behavior. - if (isExternalModule(currentSourceFile)) { - const tempVar = createUniqueName("templateObject"); - recordTaggedTemplateString(tempVar); - templateArguments[0] = createLogicalOr( - tempVar, - createAssignment( - tempVar, - helperCall) - ); - } - else { - templateArguments[0] = helperCall; - } - - return createCall(tag, /*typeArguments*/ undefined, templateArguments); - } - - /** - * Creates an ES5 compatible literal from an ES6 template literal. - * - * @param node The ES6 template literal. - */ - function getRawLiteral(node: TemplateLiteralLikeNode) { - // Find original source text, since we need to emit the raw strings of the tagged template. - // The raw strings contain the (escaped) strings of what the user wrote. - // Examples: `\n` is converted to "\\n", a template string with a newline to "\n". - let text = node.rawText; - if (text === undefined) { - text = getSourceTextOfNodeFromSourceFile(currentSourceFile, node); - - // text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"), - // thus we need to remove those characters. - // First template piece starts with "`", others with "}" - // Last template piece ends with "`", others with "${" - const isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail; - text = text.substring(1, text.length - (isLast ? 1 : 2)); - } - - // Newline normalization: - // ES6 Spec 11.8.6.1 - Static Semantics of TV's and TRV's - // and LineTerminatorSequences are normalized to for both TV and TRV. - text = text.replace(/\r\n?/g, "\n"); - return setTextRange(createLiteral(text), node); + return processTaggedTemplateExpression( + context, + node, + visitor, + currentSourceFile, + recordTaggedTemplateString, + ProcessLevel.All + ); } /** @@ -4358,18 +4294,6 @@ namespace ts { ); } - function createTemplateObjectHelper(context: TransformationContext, cooked: ArrayLiteralExpression, raw: ArrayLiteralExpression) { - context.requestEmitHelper(templateObjectHelper); - return createCall( - getUnscopedHelperName("__makeTemplateObject"), - /*typeArguments*/ undefined, - [ - cooked, - raw - ] - ); - } - export const extendsHelper: UnscopedEmitHelper = { name: "typescript:extends", importName: "__extends", @@ -4391,17 +4315,4 @@ namespace ts { }; })();` }; - - export const templateObjectHelper: UnscopedEmitHelper = { - name: "typescript:makeTemplateObject", - importName: "__makeTemplateObject", - scoped: false, - priority: 0, - text: ` - var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { - if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } - return cooked; - };` - }; - } diff --git a/src/compiler/transformers/es2018.ts b/src/compiler/transformers/es2018.ts index f03b24fc45ee6..6a7ec14e94e49 100644 --- a/src/compiler/transformers/es2018.ts +++ b/src/compiler/transformers/es2018.ts @@ -28,6 +28,9 @@ namespace ts { let enclosingSuperContainerFlags: NodeCheckFlags = 0; let hasLexicalThis: boolean; + let currentSourceFile: SourceFile; + let taggedTemplateStringDeclarations: VariableDeclaration[]; + /** Keeps track of property names accessed on super (`super.x`) within async functions. */ let capturedSuperProperties: UnderscoreEscapedMap; /** Whether the async function contains an element access on super (`super[x]`). */ @@ -37,15 +40,23 @@ namespace ts { return chainBundle(transformSourceFile); + function recordTaggedTemplateString(temp: Identifier) { + taggedTemplateStringDeclarations = append( + taggedTemplateStringDeclarations, + createVariableDeclaration(temp)); + } + function transformSourceFile(node: SourceFile) { if (node.isDeclarationFile) { return node; } - exportedVariableStatement = false; - hasLexicalThis = !isEffectiveStrictModeSourceFile(node, compilerOptions); - const visited = visitEachChild(node, visitor, context); + currentSourceFile = node; + const visited = visitSourceFile(node); addEmitHelpers(visited, context.readEmitHelpers()); + + currentSourceFile = undefined!; + taggedTemplateStringDeclarations = undefined!; return visited; } @@ -127,6 +138,8 @@ namespace ts { return visitExpressionStatement(node as ExpressionStatement); case SyntaxKind.ParenthesizedExpression: return visitParenthesizedExpression(node as ParenthesizedExpression, noDestructuringValue); + case SyntaxKind.TaggedTemplateExpression: + return visitTaggedTemplateExpression(node as TaggedTemplateExpression); case SyntaxKind.PropertyAccessExpression: if (capturedSuperProperties && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.SuperKeyword) { capturedSuperProperties.set(node.name.escapedText, true); @@ -297,6 +310,28 @@ namespace ts { return visitEachChild(node, noDestructuringValue ? visitorNoDestructuringValue : visitor, context); } + function visitSourceFile(node: SourceFile): SourceFile { + exportedVariableStatement = false; + hasLexicalThis = !isEffectiveStrictModeSourceFile(node, compilerOptions); + const visited = visitEachChild(node, visitor, context); + const statement = concatenate(visited.statements, taggedTemplateStringDeclarations && [ + createVariableStatement(/*modifiers*/ undefined, + createVariableDeclarationList(taggedTemplateStringDeclarations)) + ]); + return updateSourceFileNode(visited, setTextRange(createNodeArray(statement), node.statements)); + } + + function visitTaggedTemplateExpression(node: TaggedTemplateExpression) { + return processTaggedTemplateExpression( + context, + node, + visitor, + currentSourceFile, + recordTaggedTemplateString, + ProcessLevel.LiftRestriction + ); + } + /** * Visits a BinaryExpression that contains a destructuring assignment. * diff --git a/src/compiler/transformers/taggedTemplate.ts b/src/compiler/transformers/taggedTemplate.ts new file mode 100644 index 0000000000000..ea3e529b752dd --- /dev/null +++ b/src/compiler/transformers/taggedTemplate.ts @@ -0,0 +1,117 @@ +/*@internal*/ +namespace ts { + export enum ProcessLevel { + LiftRestriction, + All + } + + export function processTaggedTemplateExpression( + context: TransformationContext, + node: TaggedTemplateExpression, + visitor: ((node: Node) => VisitResult) | undefined, + currentSourceFile: SourceFile, + recordTaggedTemplateString: (temp: Identifier) => void, + level: ProcessLevel) { + + // Visit the tag expression + const tag = visitNode(node.tag, visitor, isExpression); + + // Build up the template arguments and the raw and cooked strings for the template. + // We start out with 'undefined' for the first argument and revisit later + // to avoid walking over the template string twice and shifting all our arguments over after the fact. + const templateArguments: Expression[] = [undefined!]; + const cookedStrings: Expression[] = []; + const rawStrings: Expression[] = []; + const template = node.template; + + if (level === ProcessLevel.LiftRestriction && !hasInvalidEscape(template)) return node; + + if (isNoSubstitutionTemplateLiteral(template)) { + cookedStrings.push(createTemplateCooked(template)); + rawStrings.push(getRawLiteral(template, currentSourceFile)); + } + else { + cookedStrings.push(createTemplateCooked(template.head)); + rawStrings.push(getRawLiteral(template.head, currentSourceFile)); + for (const templateSpan of template.templateSpans) { + cookedStrings.push(createTemplateCooked(templateSpan.literal)); + rawStrings.push(getRawLiteral(templateSpan.literal, currentSourceFile)); + templateArguments.push(visitNode(templateSpan.expression, visitor, isExpression)); + } + } + + const helperCall = createTemplateObjectHelper(context, createArrayLiteral(cookedStrings), createArrayLiteral(rawStrings)); + + // Create a variable to cache the template object if we're in a module. + // Do not do this in the global scope, as any variable we currently generate could conflict with + // variables from outside of the current compilation. In the future, we can revisit this behavior. + if (isExternalModule(currentSourceFile)) { + const tempVar = createUniqueName("templateObject"); + recordTaggedTemplateString(tempVar); + templateArguments[0] = createLogicalOr( + tempVar, + createAssignment( + tempVar, + helperCall) + ); + } + else { + templateArguments[0] = helperCall; + } + + return createCall(tag, /*typeArguments*/ undefined, templateArguments); + } + + function createTemplateCooked(template: TemplateHead | TemplateMiddle | TemplateTail | NoSubstitutionTemplateLiteral) { + return template.templateFlags ? createIdentifier("undefined") : createLiteral(template.text); + } + + /** + * Creates an ES5 compatible literal from an ES6 template literal. + * + * @param node The ES6 template literal. + */ + function getRawLiteral(node: LiteralLikeNode, currentSourceFile: SourceFile) { + // Find original source text, since we need to emit the raw strings of the tagged template. + // The raw strings contain the (escaped) strings of what the user wrote. + // Examples: `\n` is converted to "\\n", a template string with a newline to "\n". + let text = getSourceTextOfNodeFromSourceFile(currentSourceFile, node); + + // text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"), + // thus we need to remove those characters. + // First template piece starts with "`", others with "}" + // Last template piece ends with "`", others with "${" + const isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail; + text = text.substring(1, text.length - (isLast ? 1 : 2)); + + // Newline normalization: + // ES6 Spec 11.8.6.1 - Static Semantics of TV's and TRV's + // and LineTerminatorSequences are normalized to for both TV and TRV. + text = text.replace(/\r\n?/g, "\n"); + return setTextRange(createLiteral(text), node); + } + + function createTemplateObjectHelper(context: TransformationContext, cooked: ArrayLiteralExpression, raw: ArrayLiteralExpression) { + context.requestEmitHelper(templateObjectHelper); + return createCall( + getUnscopedHelperName("__makeTemplateObject"), + /*typeArguments*/ undefined, + [ + cooked, + raw + ] + ); + } + + export const templateObjectHelper: UnscopedEmitHelper = { + name: "typescript:makeTemplateObject", + importName: "__makeTemplateObject", + scoped: false, + priority: 0, + text: ` + var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; + };` + }; +} diff --git a/src/compiler/tsconfig.json b/src/compiler/tsconfig.json index a88f011115f99..846070b878166 100644 --- a/src/compiler/tsconfig.json +++ b/src/compiler/tsconfig.json @@ -38,6 +38,7 @@ "sourcemap.ts", "transformers/utilities.ts", "transformers/destructuring.ts", + "transformers/taggedTemplate.ts", "transformers/ts.ts", "transformers/classFields.ts", "transformers/es2017.ts", diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9b913c2f17d00..2c67997f2e017 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1735,6 +1735,8 @@ namespace ts { export interface NoSubstitutionTemplateLiteral extends LiteralExpression, TemplateLiteralLikeNode, Declaration { kind: SyntaxKind.NoSubstitutionTemplateLiteral; + /* @internal */ + templateFlags?: TokenFlags; } export const enum TokenFlags { @@ -1757,6 +1759,8 @@ namespace ts { /* @internal */ UnicodeEscape = 1 << 10, /* @internal */ + ContainsInvalidEscape = 1 << 11, // e.g. `\uhello` + /* @internal */ BinaryOrOctalSpecifier = BinarySpecifier | OctalSpecifier, /* @internal */ NumericLiteralFlags = Scientific | Octal | HexSpecifier | BinaryOrOctalSpecifier | ContainsSeparator @@ -1775,16 +1779,22 @@ namespace ts { export interface TemplateHead extends TemplateLiteralLikeNode { kind: SyntaxKind.TemplateHead; parent: TemplateExpression; + /* @internal */ + templateFlags?: TokenFlags; } export interface TemplateMiddle extends TemplateLiteralLikeNode { kind: SyntaxKind.TemplateMiddle; parent: TemplateSpan; + /* @internal */ + templateFlags?: TokenFlags; } export interface TemplateTail extends TemplateLiteralLikeNode { kind: SyntaxKind.TemplateTail; parent: TemplateSpan; + /* @internal */ + templateFlags?: TokenFlags; } export type TemplateLiteral = TemplateExpression | NoSubstitutionTemplateLiteral; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index bdee20ef861bf..a0a57176b0fb3 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3365,6 +3365,13 @@ namespace ts { return str.replace(templateSubstitutionRegExp, "\\${"); } + /** @internal */ + export function hasInvalidEscape(template: TemplateLiteral): boolean { + return template && !!(isNoSubstitutionTemplateLiteral(template) + ? template.templateFlags + : (template.head.templateFlags || some(template.templateSpans, span => !!span.literal.templateFlags))); + } + // This consists of the first 19 unprintable ASCII characters, canonical escapes, lineSeparator, // paragraphSeparator, and nextLine. The latter three are just desirable to suppress new lines in // the language service. These characters should be escaped when printing, and if any characters are added, diff --git a/src/services/classifier.ts b/src/services/classifier.ts index 69d1dcdf8e689..1d8f86195b8ae 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -135,7 +135,7 @@ namespace ts { const lastTemplateStackToken = lastOrUndefined(templateStack); if (lastTemplateStackToken === SyntaxKind.TemplateHead) { - token = scanner.reScanTemplateToken(); + token = scanner.reScanTemplateToken(/* isTaggedTemplate */ false); // Only pop on a TemplateTail; a TemplateMiddle indicates there is more for us. if (token === SyntaxKind.TemplateTail) { diff --git a/src/services/formatting/formattingScanner.ts b/src/services/formatting/formattingScanner.ts index 7449cdbb92edb..64e257f4a0834 100644 --- a/src/services/formatting/formattingScanner.ts +++ b/src/services/formatting/formattingScanner.ts @@ -242,7 +242,7 @@ namespace ts.formatting { case ScanAction.RescanTemplateToken: if (token === SyntaxKind.CloseBraceToken) { lastScanAction = ScanAction.RescanTemplateToken; - return scanner.reScanTemplateToken(); + return scanner.reScanTemplateToken(/* isTaggedTemplate */ false); } break; case ScanAction.RescanJsxIdentifier: diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 7eef5f9d425ee..dbc336fccce23 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3345,7 +3345,8 @@ declare namespace ts { isUnterminated(): boolean; reScanGreaterToken(): SyntaxKind; reScanSlashToken(): SyntaxKind; - reScanTemplateToken(): SyntaxKind; + reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind; + reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind; scanJsxIdentifier(): SyntaxKind; scanJsxAttributeValue(): SyntaxKind; reScanJsxAttributeValue(): SyntaxKind; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 46e972e402a56..8b600f90fdd41 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3345,7 +3345,8 @@ declare namespace ts { isUnterminated(): boolean; reScanGreaterToken(): SyntaxKind; reScanSlashToken(): SyntaxKind; - reScanTemplateToken(): SyntaxKind; + reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind; + reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind; scanJsxIdentifier(): SyntaxKind; scanJsxAttributeValue(): SyntaxKind; reScanJsxAttributeValue(): SyntaxKind; diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es2015).errors.txt b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es2015).errors.txt new file mode 100644 index 0000000000000..c8846ae349714 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es2015).errors.txt @@ -0,0 +1,49 @@ +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(7,18): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(8,15): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(8,33): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(8,75): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(9,18): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(9,27): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(9,51): error TS1125: Hexadecimal digit expected. + + +==== tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts (7 errors) ==== + function tag (str: any, ...args: any[]): any { + return str + } + + const a = tag`123` + const b = tag`123 ${100}` + const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; + +!!! error TS1125: Hexadecimal digit expected. + const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + + const a1 = tag`${ 100 }\0` // \0 + const a2 = tag`${ 100 }\00` // \\00 + const a3 = tag`${ 100 }\u` // \\u + const a4 = tag`${ 100 }\u0` // \\u0 + const a5 = tag`${ 100 }\u00` // \\u00 + const a6 = tag`${ 100 }\u000` // \\u000 + const a7 = tag`${ 100 }\u0000` // \u0000 + const a8 = tag`${ 100 }\u{` // \\u{ + const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF + const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 + const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} + const a12 = tag`${ 100 }\x` // \\x + const a13 = tag`${ 100 }\x0` // \\x0 + const a14 = tag`${ 100 }\x00` // \x00 + \ No newline at end of file diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es2015).js b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es2015).js new file mode 100644 index 0000000000000..1ad643d360de1 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es2015).js @@ -0,0 +1,54 @@ +//// [invalidTaggedTemplateEscapeSequences.ts] +function tag (str: any, ...args: any[]): any { + return str +} + +const a = tag`123` +const b = tag`123 ${100}` +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate + +const a1 = tag`${ 100 }\0` // \0 +const a2 = tag`${ 100 }\00` // \\00 +const a3 = tag`${ 100 }\u` // \\u +const a4 = tag`${ 100 }\u0` // \\u0 +const a5 = tag`${ 100 }\u00` // \\u00 +const a6 = tag`${ 100 }\u000` // \\u000 +const a7 = tag`${ 100 }\u0000` // \u0000 +const a8 = tag`${ 100 }\u{` // \\u{ +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +const a12 = tag`${ 100 }\x` // \\x +const a13 = tag`${ 100 }\x0` // \\x0 +const a14 = tag`${ 100 }\x00` // \x00 + + +//// [invalidTaggedTemplateEscapeSequences.js] +var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; +}; +function tag(str, ...args) { + return str; +} +const a = tag `123`; +const b = tag `123 ${100}`; +const x = tag(__makeTemplateObject([undefined, undefined, " wonderful ", undefined], ["\\u{hello} ", " \\xtraordinary ", " wonderful ", " \\uworld"]), 100, 200, 300); +const y = `\u{hello} ${100} \xtraordinary ${200} wonderful ${300} \uworld`; // should error with NoSubstitutionTemplate +const z = tag(__makeTemplateObject([undefined], ["\\u{hello} \\xtraordinary wonderful \\uworld"])); // should work with Tagged NoSubstitutionTemplate +const a1 = tag `${100}\0`; // \0 +const a2 = tag(__makeTemplateObject(["", undefined], ["", "\\00"]), 100); // \\00 +const a3 = tag(__makeTemplateObject(["", undefined], ["", "\\u"]), 100); // \\u +const a4 = tag(__makeTemplateObject(["", undefined], ["", "\\u0"]), 100); // \\u0 +const a5 = tag(__makeTemplateObject(["", undefined], ["", "\\u00"]), 100); // \\u00 +const a6 = tag(__makeTemplateObject(["", undefined], ["", "\\u000"]), 100); // \\u000 +const a7 = tag `${100}\u0000`; // \u0000 +const a8 = tag(__makeTemplateObject(["", undefined], ["", "\\u{"]), 100); // \\u{ +const a9 = tag `${100}\u{10FFFF}`; // \\u{10FFFF +const a10 = tag(__makeTemplateObject(["", undefined], ["", "\\u{1f622"]), 100); // \\u{1f622 +const a11 = tag `${100}\u{1f622}`; // \u{1f622} +const a12 = tag(__makeTemplateObject(["", undefined], ["", "\\x"]), 100); // \\x +const a13 = tag(__makeTemplateObject(["", undefined], ["", "\\x0"]), 100); // \\x0 +const a14 = tag `${100}\x00`; // \x00 diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es2015).symbols b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es2015).symbols new file mode 100644 index 0000000000000..1f9954dcec177 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es2015).symbols @@ -0,0 +1,85 @@ +=== tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts === +function tag (str: any, ...args: any[]): any { +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) +>str : Symbol(str, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 14)) +>args : Symbol(args, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 23)) + + return str +>str : Symbol(str, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 14)) +} + +const a = tag`123` +>a : Symbol(a, Decl(invalidTaggedTemplateEscapeSequences.ts, 4, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const b = tag`123 ${100}` +>b : Symbol(b, Decl(invalidTaggedTemplateEscapeSequences.ts, 5, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +>x : Symbol(x, Decl(invalidTaggedTemplateEscapeSequences.ts, 6, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +>y : Symbol(y, Decl(invalidTaggedTemplateEscapeSequences.ts, 7, 5)) + +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate +>z : Symbol(z, Decl(invalidTaggedTemplateEscapeSequences.ts, 8, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a1 = tag`${ 100 }\0` // \0 +>a1 : Symbol(a1, Decl(invalidTaggedTemplateEscapeSequences.ts, 10, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a2 = tag`${ 100 }\00` // \\00 +>a2 : Symbol(a2, Decl(invalidTaggedTemplateEscapeSequences.ts, 11, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a3 = tag`${ 100 }\u` // \\u +>a3 : Symbol(a3, Decl(invalidTaggedTemplateEscapeSequences.ts, 12, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a4 = tag`${ 100 }\u0` // \\u0 +>a4 : Symbol(a4, Decl(invalidTaggedTemplateEscapeSequences.ts, 13, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a5 = tag`${ 100 }\u00` // \\u00 +>a5 : Symbol(a5, Decl(invalidTaggedTemplateEscapeSequences.ts, 14, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a6 = tag`${ 100 }\u000` // \\u000 +>a6 : Symbol(a6, Decl(invalidTaggedTemplateEscapeSequences.ts, 15, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a7 = tag`${ 100 }\u0000` // \u0000 +>a7 : Symbol(a7, Decl(invalidTaggedTemplateEscapeSequences.ts, 16, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a8 = tag`${ 100 }\u{` // \\u{ +>a8 : Symbol(a8, Decl(invalidTaggedTemplateEscapeSequences.ts, 17, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +>a9 : Symbol(a9, Decl(invalidTaggedTemplateEscapeSequences.ts, 18, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +>a10 : Symbol(a10, Decl(invalidTaggedTemplateEscapeSequences.ts, 19, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +>a11 : Symbol(a11, Decl(invalidTaggedTemplateEscapeSequences.ts, 20, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a12 = tag`${ 100 }\x` // \\x +>a12 : Symbol(a12, Decl(invalidTaggedTemplateEscapeSequences.ts, 21, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a13 = tag`${ 100 }\x0` // \\x0 +>a13 : Symbol(a13, Decl(invalidTaggedTemplateEscapeSequences.ts, 22, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a14 = tag`${ 100 }\x00` // \x00 +>a14 : Symbol(a14, Decl(invalidTaggedTemplateEscapeSequences.ts, 23, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es2015).types b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es2015).types new file mode 100644 index 0000000000000..08b1ed6844442 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es2015).types @@ -0,0 +1,143 @@ +=== tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts === +function tag (str: any, ...args: any[]): any { +>tag : (str: any, ...args: any[]) => any +>str : any +>args : any[] + + return str +>str : any +} + +const a = tag`123` +>a : any +>tag`123` : any +>tag : (str: any, ...args: any[]) => any +>`123` : "123" + +const b = tag`123 ${100}` +>b : any +>tag`123 ${100}` : any +>tag : (str: any, ...args: any[]) => any +>`123 ${100}` : string +>100 : 100 + +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +>x : any +>tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld` : any +>tag : (str: any, ...args: any[]) => any +>`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld` : string +>100 : 100 +>200 : 200 +>300 : 300 + +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +>y : string +>`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld` : string +>100 : 100 +>200 : 200 +>300 : 300 + +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate +>z : any +>tag`\u{hello} \xtraordinary wonderful \uworld` : any +>tag : (str: any, ...args: any[]) => any +>`\u{hello} \xtraordinary wonderful \uworld` : "\\u{hello} \\xtraordinary wonderful \\uworld" + +const a1 = tag`${ 100 }\0` // \0 +>a1 : any +>tag`${ 100 }\0` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\0` : string +>100 : 100 + +const a2 = tag`${ 100 }\00` // \\00 +>a2 : any +>tag`${ 100 }\00` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\00` : string +>100 : 100 + +const a3 = tag`${ 100 }\u` // \\u +>a3 : any +>tag`${ 100 }\u` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u` : string +>100 : 100 + +const a4 = tag`${ 100 }\u0` // \\u0 +>a4 : any +>tag`${ 100 }\u0` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u0` : string +>100 : 100 + +const a5 = tag`${ 100 }\u00` // \\u00 +>a5 : any +>tag`${ 100 }\u00` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u00` : string +>100 : 100 + +const a6 = tag`${ 100 }\u000` // \\u000 +>a6 : any +>tag`${ 100 }\u000` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u000` : string +>100 : 100 + +const a7 = tag`${ 100 }\u0000` // \u0000 +>a7 : any +>tag`${ 100 }\u0000` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u0000` : string +>100 : 100 + +const a8 = tag`${ 100 }\u{` // \\u{ +>a8 : any +>tag`${ 100 }\u{` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{` : string +>100 : 100 + +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +>a9 : any +>tag`${ 100 }\u{10FFFF}` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{10FFFF}` : string +>100 : 100 + +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +>a10 : any +>tag`${ 100 }\u{1f622` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{1f622` : string +>100 : 100 + +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +>a11 : any +>tag`${ 100 }\u{1f622}` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{1f622}` : string +>100 : 100 + +const a12 = tag`${ 100 }\x` // \\x +>a12 : any +>tag`${ 100 }\x` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\x` : string +>100 : 100 + +const a13 = tag`${ 100 }\x0` // \\x0 +>a13 : any +>tag`${ 100 }\x0` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\x0` : string +>100 : 100 + +const a14 = tag`${ 100 }\x00` // \x00 +>a14 : any +>tag`${ 100 }\x00` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\x00` : string +>100 : 100 + diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es5).errors.txt b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es5).errors.txt new file mode 100644 index 0000000000000..c8846ae349714 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es5).errors.txt @@ -0,0 +1,49 @@ +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(7,18): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(8,15): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(8,33): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(8,75): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(9,18): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(9,27): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(9,51): error TS1125: Hexadecimal digit expected. + + +==== tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts (7 errors) ==== + function tag (str: any, ...args: any[]): any { + return str + } + + const a = tag`123` + const b = tag`123 ${100}` + const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; + +!!! error TS1125: Hexadecimal digit expected. + const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + + const a1 = tag`${ 100 }\0` // \0 + const a2 = tag`${ 100 }\00` // \\00 + const a3 = tag`${ 100 }\u` // \\u + const a4 = tag`${ 100 }\u0` // \\u0 + const a5 = tag`${ 100 }\u00` // \\u00 + const a6 = tag`${ 100 }\u000` // \\u000 + const a7 = tag`${ 100 }\u0000` // \u0000 + const a8 = tag`${ 100 }\u{` // \\u{ + const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF + const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 + const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} + const a12 = tag`${ 100 }\x` // \\x + const a13 = tag`${ 100 }\x0` // \\x0 + const a14 = tag`${ 100 }\x00` // \x00 + \ No newline at end of file diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es5).js b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es5).js new file mode 100644 index 0000000000000..362e2cf175cfc --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es5).js @@ -0,0 +1,58 @@ +//// [invalidTaggedTemplateEscapeSequences.ts] +function tag (str: any, ...args: any[]): any { + return str +} + +const a = tag`123` +const b = tag`123 ${100}` +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate + +const a1 = tag`${ 100 }\0` // \0 +const a2 = tag`${ 100 }\00` // \\00 +const a3 = tag`${ 100 }\u` // \\u +const a4 = tag`${ 100 }\u0` // \\u0 +const a5 = tag`${ 100 }\u00` // \\u00 +const a6 = tag`${ 100 }\u000` // \\u000 +const a7 = tag`${ 100 }\u0000` // \u0000 +const a8 = tag`${ 100 }\u{` // \\u{ +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +const a12 = tag`${ 100 }\x` // \\x +const a13 = tag`${ 100 }\x0` // \\x0 +const a14 = tag`${ 100 }\x00` // \x00 + + +//// [invalidTaggedTemplateEscapeSequences.js] +var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; +}; +function tag(str) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + return str; +} +var a = tag(__makeTemplateObject(["123"], ["123"])); +var b = tag(__makeTemplateObject(["123 ", ""], ["123 ", ""]), 100); +var x = tag(__makeTemplateObject([undefined, undefined, " wonderful ", undefined], ["\\u{hello} ", " \\xtraordinary ", " wonderful ", " \\uworld"]), 100, 200, 300); +var y = "hello} " + 100 + " traordinary " + 200 + " wonderful " + 300 + " world"; // should error with NoSubstitutionTemplate +var z = tag(__makeTemplateObject([undefined], ["\\u{hello} \\xtraordinary wonderful \\uworld"])); // should work with Tagged NoSubstitutionTemplate +var a1 = tag(__makeTemplateObject(["", "\0"], ["", "\\0"]), 100); // \0 +var a2 = tag(__makeTemplateObject(["", undefined], ["", "\\00"]), 100); // \\00 +var a3 = tag(__makeTemplateObject(["", undefined], ["", "\\u"]), 100); // \\u +var a4 = tag(__makeTemplateObject(["", undefined], ["", "\\u0"]), 100); // \\u0 +var a5 = tag(__makeTemplateObject(["", undefined], ["", "\\u00"]), 100); // \\u00 +var a6 = tag(__makeTemplateObject(["", undefined], ["", "\\u000"]), 100); // \\u000 +var a7 = tag(__makeTemplateObject(["", "\0"], ["", "\\u0000"]), 100); // \u0000 +var a8 = tag(__makeTemplateObject(["", undefined], ["", "\\u{"]), 100); // \\u{ +var a9 = tag(__makeTemplateObject(["", "\uDBFF\uDFFF"], ["", "\\u{10FFFF}"]), 100); // \\u{10FFFF +var a10 = tag(__makeTemplateObject(["", undefined], ["", "\\u{1f622"]), 100); // \\u{1f622 +var a11 = tag(__makeTemplateObject(["", "\uD83D\uDE22"], ["", "\\u{1f622}"]), 100); // \u{1f622} +var a12 = tag(__makeTemplateObject(["", undefined], ["", "\\x"]), 100); // \\x +var a13 = tag(__makeTemplateObject(["", undefined], ["", "\\x0"]), 100); // \\x0 +var a14 = tag(__makeTemplateObject(["", "\0"], ["", "\\x00"]), 100); // \x00 diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es5).symbols b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es5).symbols new file mode 100644 index 0000000000000..1f9954dcec177 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es5).symbols @@ -0,0 +1,85 @@ +=== tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts === +function tag (str: any, ...args: any[]): any { +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) +>str : Symbol(str, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 14)) +>args : Symbol(args, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 23)) + + return str +>str : Symbol(str, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 14)) +} + +const a = tag`123` +>a : Symbol(a, Decl(invalidTaggedTemplateEscapeSequences.ts, 4, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const b = tag`123 ${100}` +>b : Symbol(b, Decl(invalidTaggedTemplateEscapeSequences.ts, 5, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +>x : Symbol(x, Decl(invalidTaggedTemplateEscapeSequences.ts, 6, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +>y : Symbol(y, Decl(invalidTaggedTemplateEscapeSequences.ts, 7, 5)) + +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate +>z : Symbol(z, Decl(invalidTaggedTemplateEscapeSequences.ts, 8, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a1 = tag`${ 100 }\0` // \0 +>a1 : Symbol(a1, Decl(invalidTaggedTemplateEscapeSequences.ts, 10, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a2 = tag`${ 100 }\00` // \\00 +>a2 : Symbol(a2, Decl(invalidTaggedTemplateEscapeSequences.ts, 11, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a3 = tag`${ 100 }\u` // \\u +>a3 : Symbol(a3, Decl(invalidTaggedTemplateEscapeSequences.ts, 12, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a4 = tag`${ 100 }\u0` // \\u0 +>a4 : Symbol(a4, Decl(invalidTaggedTemplateEscapeSequences.ts, 13, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a5 = tag`${ 100 }\u00` // \\u00 +>a5 : Symbol(a5, Decl(invalidTaggedTemplateEscapeSequences.ts, 14, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a6 = tag`${ 100 }\u000` // \\u000 +>a6 : Symbol(a6, Decl(invalidTaggedTemplateEscapeSequences.ts, 15, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a7 = tag`${ 100 }\u0000` // \u0000 +>a7 : Symbol(a7, Decl(invalidTaggedTemplateEscapeSequences.ts, 16, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a8 = tag`${ 100 }\u{` // \\u{ +>a8 : Symbol(a8, Decl(invalidTaggedTemplateEscapeSequences.ts, 17, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +>a9 : Symbol(a9, Decl(invalidTaggedTemplateEscapeSequences.ts, 18, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +>a10 : Symbol(a10, Decl(invalidTaggedTemplateEscapeSequences.ts, 19, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +>a11 : Symbol(a11, Decl(invalidTaggedTemplateEscapeSequences.ts, 20, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a12 = tag`${ 100 }\x` // \\x +>a12 : Symbol(a12, Decl(invalidTaggedTemplateEscapeSequences.ts, 21, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a13 = tag`${ 100 }\x0` // \\x0 +>a13 : Symbol(a13, Decl(invalidTaggedTemplateEscapeSequences.ts, 22, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a14 = tag`${ 100 }\x00` // \x00 +>a14 : Symbol(a14, Decl(invalidTaggedTemplateEscapeSequences.ts, 23, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es5).types b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es5).types new file mode 100644 index 0000000000000..08b1ed6844442 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=es5).types @@ -0,0 +1,143 @@ +=== tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts === +function tag (str: any, ...args: any[]): any { +>tag : (str: any, ...args: any[]) => any +>str : any +>args : any[] + + return str +>str : any +} + +const a = tag`123` +>a : any +>tag`123` : any +>tag : (str: any, ...args: any[]) => any +>`123` : "123" + +const b = tag`123 ${100}` +>b : any +>tag`123 ${100}` : any +>tag : (str: any, ...args: any[]) => any +>`123 ${100}` : string +>100 : 100 + +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +>x : any +>tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld` : any +>tag : (str: any, ...args: any[]) => any +>`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld` : string +>100 : 100 +>200 : 200 +>300 : 300 + +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +>y : string +>`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld` : string +>100 : 100 +>200 : 200 +>300 : 300 + +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate +>z : any +>tag`\u{hello} \xtraordinary wonderful \uworld` : any +>tag : (str: any, ...args: any[]) => any +>`\u{hello} \xtraordinary wonderful \uworld` : "\\u{hello} \\xtraordinary wonderful \\uworld" + +const a1 = tag`${ 100 }\0` // \0 +>a1 : any +>tag`${ 100 }\0` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\0` : string +>100 : 100 + +const a2 = tag`${ 100 }\00` // \\00 +>a2 : any +>tag`${ 100 }\00` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\00` : string +>100 : 100 + +const a3 = tag`${ 100 }\u` // \\u +>a3 : any +>tag`${ 100 }\u` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u` : string +>100 : 100 + +const a4 = tag`${ 100 }\u0` // \\u0 +>a4 : any +>tag`${ 100 }\u0` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u0` : string +>100 : 100 + +const a5 = tag`${ 100 }\u00` // \\u00 +>a5 : any +>tag`${ 100 }\u00` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u00` : string +>100 : 100 + +const a6 = tag`${ 100 }\u000` // \\u000 +>a6 : any +>tag`${ 100 }\u000` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u000` : string +>100 : 100 + +const a7 = tag`${ 100 }\u0000` // \u0000 +>a7 : any +>tag`${ 100 }\u0000` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u0000` : string +>100 : 100 + +const a8 = tag`${ 100 }\u{` // \\u{ +>a8 : any +>tag`${ 100 }\u{` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{` : string +>100 : 100 + +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +>a9 : any +>tag`${ 100 }\u{10FFFF}` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{10FFFF}` : string +>100 : 100 + +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +>a10 : any +>tag`${ 100 }\u{1f622` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{1f622` : string +>100 : 100 + +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +>a11 : any +>tag`${ 100 }\u{1f622}` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{1f622}` : string +>100 : 100 + +const a12 = tag`${ 100 }\x` // \\x +>a12 : any +>tag`${ 100 }\x` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\x` : string +>100 : 100 + +const a13 = tag`${ 100 }\x0` // \\x0 +>a13 : any +>tag`${ 100 }\x0` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\x0` : string +>100 : 100 + +const a14 = tag`${ 100 }\x00` // \x00 +>a14 : any +>tag`${ 100 }\x00` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\x00` : string +>100 : 100 + diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=esnext).errors.txt b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=esnext).errors.txt new file mode 100644 index 0000000000000..c8846ae349714 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=esnext).errors.txt @@ -0,0 +1,49 @@ +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(7,18): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(8,15): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(8,33): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(8,75): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(9,18): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(9,27): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(9,51): error TS1125: Hexadecimal digit expected. + + +==== tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts (7 errors) ==== + function tag (str: any, ...args: any[]): any { + return str + } + + const a = tag`123` + const b = tag`123 ${100}` + const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; + +!!! error TS1125: Hexadecimal digit expected. + const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + + const a1 = tag`${ 100 }\0` // \0 + const a2 = tag`${ 100 }\00` // \\00 + const a3 = tag`${ 100 }\u` // \\u + const a4 = tag`${ 100 }\u0` // \\u0 + const a5 = tag`${ 100 }\u00` // \\u00 + const a6 = tag`${ 100 }\u000` // \\u000 + const a7 = tag`${ 100 }\u0000` // \u0000 + const a8 = tag`${ 100 }\u{` // \\u{ + const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF + const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 + const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} + const a12 = tag`${ 100 }\x` // \\x + const a13 = tag`${ 100 }\x0` // \\x0 + const a14 = tag`${ 100 }\x00` // \x00 + \ No newline at end of file diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=esnext).js b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=esnext).js new file mode 100644 index 0000000000000..97864caea188c --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=esnext).js @@ -0,0 +1,50 @@ +//// [invalidTaggedTemplateEscapeSequences.ts] +function tag (str: any, ...args: any[]): any { + return str +} + +const a = tag`123` +const b = tag`123 ${100}` +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate + +const a1 = tag`${ 100 }\0` // \0 +const a2 = tag`${ 100 }\00` // \\00 +const a3 = tag`${ 100 }\u` // \\u +const a4 = tag`${ 100 }\u0` // \\u0 +const a5 = tag`${ 100 }\u00` // \\u00 +const a6 = tag`${ 100 }\u000` // \\u000 +const a7 = tag`${ 100 }\u0000` // \u0000 +const a8 = tag`${ 100 }\u{` // \\u{ +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +const a12 = tag`${ 100 }\x` // \\x +const a13 = tag`${ 100 }\x0` // \\x0 +const a14 = tag`${ 100 }\x00` // \x00 + + +//// [invalidTaggedTemplateEscapeSequences.js] +function tag(str, ...args) { + return str; +} +const a = tag `123`; +const b = tag `123 ${100}`; +const x = tag `\u{hello} ${100} \xtraordinary ${200} wonderful ${300} \uworld`; +const y = `\u{hello} ${100} \xtraordinary ${200} wonderful ${300} \uworld`; // should error with NoSubstitutionTemplate +const z = tag `\u{hello} \xtraordinary wonderful \uworld`; // should work with Tagged NoSubstitutionTemplate +const a1 = tag `${100}\0`; // \0 +const a2 = tag `${100}\00`; // \\00 +const a3 = tag `${100}\u`; // \\u +const a4 = tag `${100}\u0`; // \\u0 +const a5 = tag `${100}\u00`; // \\u00 +const a6 = tag `${100}\u000`; // \\u000 +const a7 = tag `${100}\u0000`; // \u0000 +const a8 = tag `${100}\u{`; // \\u{ +const a9 = tag `${100}\u{10FFFF}`; // \\u{10FFFF +const a10 = tag `${100}\u{1f622`; // \\u{1f622 +const a11 = tag `${100}\u{1f622}`; // \u{1f622} +const a12 = tag `${100}\x`; // \\x +const a13 = tag `${100}\x0`; // \\x0 +const a14 = tag `${100}\x00`; // \x00 diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=esnext).symbols b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=esnext).symbols new file mode 100644 index 0000000000000..1f9954dcec177 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=esnext).symbols @@ -0,0 +1,85 @@ +=== tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts === +function tag (str: any, ...args: any[]): any { +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) +>str : Symbol(str, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 14)) +>args : Symbol(args, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 23)) + + return str +>str : Symbol(str, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 14)) +} + +const a = tag`123` +>a : Symbol(a, Decl(invalidTaggedTemplateEscapeSequences.ts, 4, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const b = tag`123 ${100}` +>b : Symbol(b, Decl(invalidTaggedTemplateEscapeSequences.ts, 5, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +>x : Symbol(x, Decl(invalidTaggedTemplateEscapeSequences.ts, 6, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +>y : Symbol(y, Decl(invalidTaggedTemplateEscapeSequences.ts, 7, 5)) + +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate +>z : Symbol(z, Decl(invalidTaggedTemplateEscapeSequences.ts, 8, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a1 = tag`${ 100 }\0` // \0 +>a1 : Symbol(a1, Decl(invalidTaggedTemplateEscapeSequences.ts, 10, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a2 = tag`${ 100 }\00` // \\00 +>a2 : Symbol(a2, Decl(invalidTaggedTemplateEscapeSequences.ts, 11, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a3 = tag`${ 100 }\u` // \\u +>a3 : Symbol(a3, Decl(invalidTaggedTemplateEscapeSequences.ts, 12, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a4 = tag`${ 100 }\u0` // \\u0 +>a4 : Symbol(a4, Decl(invalidTaggedTemplateEscapeSequences.ts, 13, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a5 = tag`${ 100 }\u00` // \\u00 +>a5 : Symbol(a5, Decl(invalidTaggedTemplateEscapeSequences.ts, 14, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a6 = tag`${ 100 }\u000` // \\u000 +>a6 : Symbol(a6, Decl(invalidTaggedTemplateEscapeSequences.ts, 15, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a7 = tag`${ 100 }\u0000` // \u0000 +>a7 : Symbol(a7, Decl(invalidTaggedTemplateEscapeSequences.ts, 16, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a8 = tag`${ 100 }\u{` // \\u{ +>a8 : Symbol(a8, Decl(invalidTaggedTemplateEscapeSequences.ts, 17, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +>a9 : Symbol(a9, Decl(invalidTaggedTemplateEscapeSequences.ts, 18, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +>a10 : Symbol(a10, Decl(invalidTaggedTemplateEscapeSequences.ts, 19, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +>a11 : Symbol(a11, Decl(invalidTaggedTemplateEscapeSequences.ts, 20, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a12 = tag`${ 100 }\x` // \\x +>a12 : Symbol(a12, Decl(invalidTaggedTemplateEscapeSequences.ts, 21, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a13 = tag`${ 100 }\x0` // \\x0 +>a13 : Symbol(a13, Decl(invalidTaggedTemplateEscapeSequences.ts, 22, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a14 = tag`${ 100 }\x00` // \x00 +>a14 : Symbol(a14, Decl(invalidTaggedTemplateEscapeSequences.ts, 23, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=esnext).types b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=esnext).types new file mode 100644 index 0000000000000..08b1ed6844442 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences(target=esnext).types @@ -0,0 +1,143 @@ +=== tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts === +function tag (str: any, ...args: any[]): any { +>tag : (str: any, ...args: any[]) => any +>str : any +>args : any[] + + return str +>str : any +} + +const a = tag`123` +>a : any +>tag`123` : any +>tag : (str: any, ...args: any[]) => any +>`123` : "123" + +const b = tag`123 ${100}` +>b : any +>tag`123 ${100}` : any +>tag : (str: any, ...args: any[]) => any +>`123 ${100}` : string +>100 : 100 + +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +>x : any +>tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld` : any +>tag : (str: any, ...args: any[]) => any +>`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld` : string +>100 : 100 +>200 : 200 +>300 : 300 + +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +>y : string +>`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld` : string +>100 : 100 +>200 : 200 +>300 : 300 + +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate +>z : any +>tag`\u{hello} \xtraordinary wonderful \uworld` : any +>tag : (str: any, ...args: any[]) => any +>`\u{hello} \xtraordinary wonderful \uworld` : "\\u{hello} \\xtraordinary wonderful \\uworld" + +const a1 = tag`${ 100 }\0` // \0 +>a1 : any +>tag`${ 100 }\0` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\0` : string +>100 : 100 + +const a2 = tag`${ 100 }\00` // \\00 +>a2 : any +>tag`${ 100 }\00` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\00` : string +>100 : 100 + +const a3 = tag`${ 100 }\u` // \\u +>a3 : any +>tag`${ 100 }\u` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u` : string +>100 : 100 + +const a4 = tag`${ 100 }\u0` // \\u0 +>a4 : any +>tag`${ 100 }\u0` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u0` : string +>100 : 100 + +const a5 = tag`${ 100 }\u00` // \\u00 +>a5 : any +>tag`${ 100 }\u00` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u00` : string +>100 : 100 + +const a6 = tag`${ 100 }\u000` // \\u000 +>a6 : any +>tag`${ 100 }\u000` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u000` : string +>100 : 100 + +const a7 = tag`${ 100 }\u0000` // \u0000 +>a7 : any +>tag`${ 100 }\u0000` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u0000` : string +>100 : 100 + +const a8 = tag`${ 100 }\u{` // \\u{ +>a8 : any +>tag`${ 100 }\u{` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{` : string +>100 : 100 + +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +>a9 : any +>tag`${ 100 }\u{10FFFF}` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{10FFFF}` : string +>100 : 100 + +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +>a10 : any +>tag`${ 100 }\u{1f622` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{1f622` : string +>100 : 100 + +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +>a11 : any +>tag`${ 100 }\u{1f622}` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{1f622}` : string +>100 : 100 + +const a12 = tag`${ 100 }\x` // \\x +>a12 : any +>tag`${ 100 }\x` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\x` : string +>100 : 100 + +const a13 = tag`${ 100 }\x0` // \\x0 +>a13 : any +>tag`${ 100 }\x0` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\x0` : string +>100 : 100 + +const a14 = tag`${ 100 }\x00` // \x00 +>a14 : any +>tag`${ 100 }\x00` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\x00` : string +>100 : 100 + diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences.errors.txt b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences.errors.txt new file mode 100644 index 0000000000000..c8846ae349714 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences.errors.txt @@ -0,0 +1,49 @@ +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(7,18): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(8,15): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(8,33): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(8,75): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(9,18): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(9,27): error TS1125: Hexadecimal digit expected. +tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts(9,51): error TS1125: Hexadecimal digit expected. + + +==== tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts (7 errors) ==== + function tag (str: any, ...args: any[]): any { + return str + } + + const a = tag`123` + const b = tag`123 ${100}` + const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; + +!!! error TS1125: Hexadecimal digit expected. + const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + +!!! error TS1125: Hexadecimal digit expected. + + const a1 = tag`${ 100 }\0` // \0 + const a2 = tag`${ 100 }\00` // \\00 + const a3 = tag`${ 100 }\u` // \\u + const a4 = tag`${ 100 }\u0` // \\u0 + const a5 = tag`${ 100 }\u00` // \\u00 + const a6 = tag`${ 100 }\u000` // \\u000 + const a7 = tag`${ 100 }\u0000` // \u0000 + const a8 = tag`${ 100 }\u{` // \\u{ + const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF + const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 + const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} + const a12 = tag`${ 100 }\x` // \\x + const a13 = tag`${ 100 }\x0` // \\x0 + const a14 = tag`${ 100 }\x00` // \x00 + \ No newline at end of file diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences.js b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences.js new file mode 100644 index 0000000000000..362e2cf175cfc --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences.js @@ -0,0 +1,58 @@ +//// [invalidTaggedTemplateEscapeSequences.ts] +function tag (str: any, ...args: any[]): any { + return str +} + +const a = tag`123` +const b = tag`123 ${100}` +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate + +const a1 = tag`${ 100 }\0` // \0 +const a2 = tag`${ 100 }\00` // \\00 +const a3 = tag`${ 100 }\u` // \\u +const a4 = tag`${ 100 }\u0` // \\u0 +const a5 = tag`${ 100 }\u00` // \\u00 +const a6 = tag`${ 100 }\u000` // \\u000 +const a7 = tag`${ 100 }\u0000` // \u0000 +const a8 = tag`${ 100 }\u{` // \\u{ +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +const a12 = tag`${ 100 }\x` // \\x +const a13 = tag`${ 100 }\x0` // \\x0 +const a14 = tag`${ 100 }\x00` // \x00 + + +//// [invalidTaggedTemplateEscapeSequences.js] +var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; +}; +function tag(str) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + return str; +} +var a = tag(__makeTemplateObject(["123"], ["123"])); +var b = tag(__makeTemplateObject(["123 ", ""], ["123 ", ""]), 100); +var x = tag(__makeTemplateObject([undefined, undefined, " wonderful ", undefined], ["\\u{hello} ", " \\xtraordinary ", " wonderful ", " \\uworld"]), 100, 200, 300); +var y = "hello} " + 100 + " traordinary " + 200 + " wonderful " + 300 + " world"; // should error with NoSubstitutionTemplate +var z = tag(__makeTemplateObject([undefined], ["\\u{hello} \\xtraordinary wonderful \\uworld"])); // should work with Tagged NoSubstitutionTemplate +var a1 = tag(__makeTemplateObject(["", "\0"], ["", "\\0"]), 100); // \0 +var a2 = tag(__makeTemplateObject(["", undefined], ["", "\\00"]), 100); // \\00 +var a3 = tag(__makeTemplateObject(["", undefined], ["", "\\u"]), 100); // \\u +var a4 = tag(__makeTemplateObject(["", undefined], ["", "\\u0"]), 100); // \\u0 +var a5 = tag(__makeTemplateObject(["", undefined], ["", "\\u00"]), 100); // \\u00 +var a6 = tag(__makeTemplateObject(["", undefined], ["", "\\u000"]), 100); // \\u000 +var a7 = tag(__makeTemplateObject(["", "\0"], ["", "\\u0000"]), 100); // \u0000 +var a8 = tag(__makeTemplateObject(["", undefined], ["", "\\u{"]), 100); // \\u{ +var a9 = tag(__makeTemplateObject(["", "\uDBFF\uDFFF"], ["", "\\u{10FFFF}"]), 100); // \\u{10FFFF +var a10 = tag(__makeTemplateObject(["", undefined], ["", "\\u{1f622"]), 100); // \\u{1f622 +var a11 = tag(__makeTemplateObject(["", "\uD83D\uDE22"], ["", "\\u{1f622}"]), 100); // \u{1f622} +var a12 = tag(__makeTemplateObject(["", undefined], ["", "\\x"]), 100); // \\x +var a13 = tag(__makeTemplateObject(["", undefined], ["", "\\x0"]), 100); // \\x0 +var a14 = tag(__makeTemplateObject(["", "\0"], ["", "\\x00"]), 100); // \x00 diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences.symbols b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences.symbols new file mode 100644 index 0000000000000..1f9954dcec177 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences.symbols @@ -0,0 +1,85 @@ +=== tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts === +function tag (str: any, ...args: any[]): any { +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) +>str : Symbol(str, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 14)) +>args : Symbol(args, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 23)) + + return str +>str : Symbol(str, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 14)) +} + +const a = tag`123` +>a : Symbol(a, Decl(invalidTaggedTemplateEscapeSequences.ts, 4, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const b = tag`123 ${100}` +>b : Symbol(b, Decl(invalidTaggedTemplateEscapeSequences.ts, 5, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +>x : Symbol(x, Decl(invalidTaggedTemplateEscapeSequences.ts, 6, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +>y : Symbol(y, Decl(invalidTaggedTemplateEscapeSequences.ts, 7, 5)) + +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate +>z : Symbol(z, Decl(invalidTaggedTemplateEscapeSequences.ts, 8, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a1 = tag`${ 100 }\0` // \0 +>a1 : Symbol(a1, Decl(invalidTaggedTemplateEscapeSequences.ts, 10, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a2 = tag`${ 100 }\00` // \\00 +>a2 : Symbol(a2, Decl(invalidTaggedTemplateEscapeSequences.ts, 11, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a3 = tag`${ 100 }\u` // \\u +>a3 : Symbol(a3, Decl(invalidTaggedTemplateEscapeSequences.ts, 12, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a4 = tag`${ 100 }\u0` // \\u0 +>a4 : Symbol(a4, Decl(invalidTaggedTemplateEscapeSequences.ts, 13, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a5 = tag`${ 100 }\u00` // \\u00 +>a5 : Symbol(a5, Decl(invalidTaggedTemplateEscapeSequences.ts, 14, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a6 = tag`${ 100 }\u000` // \\u000 +>a6 : Symbol(a6, Decl(invalidTaggedTemplateEscapeSequences.ts, 15, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a7 = tag`${ 100 }\u0000` // \u0000 +>a7 : Symbol(a7, Decl(invalidTaggedTemplateEscapeSequences.ts, 16, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a8 = tag`${ 100 }\u{` // \\u{ +>a8 : Symbol(a8, Decl(invalidTaggedTemplateEscapeSequences.ts, 17, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +>a9 : Symbol(a9, Decl(invalidTaggedTemplateEscapeSequences.ts, 18, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +>a10 : Symbol(a10, Decl(invalidTaggedTemplateEscapeSequences.ts, 19, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +>a11 : Symbol(a11, Decl(invalidTaggedTemplateEscapeSequences.ts, 20, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a12 = tag`${ 100 }\x` // \\x +>a12 : Symbol(a12, Decl(invalidTaggedTemplateEscapeSequences.ts, 21, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a13 = tag`${ 100 }\x0` // \\x0 +>a13 : Symbol(a13, Decl(invalidTaggedTemplateEscapeSequences.ts, 22, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + +const a14 = tag`${ 100 }\x00` // \x00 +>a14 : Symbol(a14, Decl(invalidTaggedTemplateEscapeSequences.ts, 23, 5)) +>tag : Symbol(tag, Decl(invalidTaggedTemplateEscapeSequences.ts, 0, 0)) + diff --git a/tests/baselines/reference/invalidTaggedTemplateEscapeSequences.types b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences.types new file mode 100644 index 0000000000000..08b1ed6844442 --- /dev/null +++ b/tests/baselines/reference/invalidTaggedTemplateEscapeSequences.types @@ -0,0 +1,143 @@ +=== tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts === +function tag (str: any, ...args: any[]): any { +>tag : (str: any, ...args: any[]) => any +>str : any +>args : any[] + + return str +>str : any +} + +const a = tag`123` +>a : any +>tag`123` : any +>tag : (str: any, ...args: any[]) => any +>`123` : "123" + +const b = tag`123 ${100}` +>b : any +>tag`123 ${100}` : any +>tag : (str: any, ...args: any[]) => any +>`123 ${100}` : string +>100 : 100 + +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +>x : any +>tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld` : any +>tag : (str: any, ...args: any[]) => any +>`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld` : string +>100 : 100 +>200 : 200 +>300 : 300 + +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +>y : string +>`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld` : string +>100 : 100 +>200 : 200 +>300 : 300 + +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate +>z : any +>tag`\u{hello} \xtraordinary wonderful \uworld` : any +>tag : (str: any, ...args: any[]) => any +>`\u{hello} \xtraordinary wonderful \uworld` : "\\u{hello} \\xtraordinary wonderful \\uworld" + +const a1 = tag`${ 100 }\0` // \0 +>a1 : any +>tag`${ 100 }\0` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\0` : string +>100 : 100 + +const a2 = tag`${ 100 }\00` // \\00 +>a2 : any +>tag`${ 100 }\00` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\00` : string +>100 : 100 + +const a3 = tag`${ 100 }\u` // \\u +>a3 : any +>tag`${ 100 }\u` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u` : string +>100 : 100 + +const a4 = tag`${ 100 }\u0` // \\u0 +>a4 : any +>tag`${ 100 }\u0` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u0` : string +>100 : 100 + +const a5 = tag`${ 100 }\u00` // \\u00 +>a5 : any +>tag`${ 100 }\u00` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u00` : string +>100 : 100 + +const a6 = tag`${ 100 }\u000` // \\u000 +>a6 : any +>tag`${ 100 }\u000` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u000` : string +>100 : 100 + +const a7 = tag`${ 100 }\u0000` // \u0000 +>a7 : any +>tag`${ 100 }\u0000` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u0000` : string +>100 : 100 + +const a8 = tag`${ 100 }\u{` // \\u{ +>a8 : any +>tag`${ 100 }\u{` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{` : string +>100 : 100 + +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +>a9 : any +>tag`${ 100 }\u{10FFFF}` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{10FFFF}` : string +>100 : 100 + +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +>a10 : any +>tag`${ 100 }\u{1f622` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{1f622` : string +>100 : 100 + +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +>a11 : any +>tag`${ 100 }\u{1f622}` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\u{1f622}` : string +>100 : 100 + +const a12 = tag`${ 100 }\x` // \\x +>a12 : any +>tag`${ 100 }\x` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\x` : string +>100 : 100 + +const a13 = tag`${ 100 }\x0` // \\x0 +>a13 : any +>tag`${ 100 }\x0` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\x0` : string +>100 : 100 + +const a14 = tag`${ 100 }\x00` // \x00 +>a14 : any +>tag`${ 100 }\x00` : any +>tag : (str: any, ...args: any[]) => any +>`${ 100 }\x00` : string +>100 : 100 + diff --git a/tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts b/tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts new file mode 100644 index 0000000000000..2b1bbd372181a --- /dev/null +++ b/tests/cases/conformance/es2018/invalidTaggedTemplateEscapeSequences.ts @@ -0,0 +1,26 @@ +// @target: ES5, ES2015, esnext + +function tag (str: any, ...args: any[]): any { + return str +} + +const a = tag`123` +const b = tag`123 ${100}` +const x = tag`\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; +const y = `\u{hello} ${ 100 } \xtraordinary ${ 200 } wonderful ${ 300 } \uworld`; // should error with NoSubstitutionTemplate +const z = tag`\u{hello} \xtraordinary wonderful \uworld` // should work with Tagged NoSubstitutionTemplate + +const a1 = tag`${ 100 }\0` // \0 +const a2 = tag`${ 100 }\00` // \\00 +const a3 = tag`${ 100 }\u` // \\u +const a4 = tag`${ 100 }\u0` // \\u0 +const a5 = tag`${ 100 }\u00` // \\u00 +const a6 = tag`${ 100 }\u000` // \\u000 +const a7 = tag`${ 100 }\u0000` // \u0000 +const a8 = tag`${ 100 }\u{` // \\u{ +const a9 = tag`${ 100 }\u{10FFFF}` // \\u{10FFFF +const a10 = tag`${ 100 }\u{1f622` // \\u{1f622 +const a11 = tag`${ 100 }\u{1f622}` // \u{1f622} +const a12 = tag`${ 100 }\x` // \\x +const a13 = tag`${ 100 }\x0` // \\x0 +const a14 = tag`${ 100 }\x00` // \x00