diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index b4cba8c615d..f52f48e56a3 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2193,13 +2193,7 @@ module ts { } function emitLiteral(node: LiteralExpression) { - var text = languageVersion < ScriptTarget.ES6 && (isTemplateLiteralKind(node.kind) || node.hasExtendedUnicodeEscape) - ? getDoubleQuotedStringTextOfLiteral(node) - : node.parent - ? getSourceTextOfNodeFromSourceFile(currentSourceFile, node) - : node.kind === SyntaxKind.NumericLiteral - ? node.text - : getDoubleQuotedStringTextOfLiteral(node); + var text = getLiteralText(node); if (compilerOptions.sourceMap && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { writer.writeLiteral(text); @@ -2213,11 +2207,41 @@ module ts { } } - function getDoubleQuotedStringTextOfLiteral(node: LiteralExpression): string { - var result = escapeString(node.text); - result = escapeNonAsciiCharacters(result); + function getLiteralText(node: LiteralExpression) { + // Any template literal or string literal with an extended escape + // (e.g. "\u{0067}") will need to be downleveled as a escaped string literal. + if (languageVersion < ScriptTarget.ES6 && (isTemplateLiteralKind(node.kind) || node.hasExtendedUnicodeEscape)) { + return getQuotedEscapedLiteralText('"', node.text, '"'); + } - return '"' + result + '"'; + // If we don't need to downlevel, and we can reach the original source text using + // the node's parent reference, then simply get the text as it was originally written. + if (node.parent) { + return getSourceTextOfNodeFromSourceFile(currentSourceFile, node); + } + + // If we can't reach the original source text, use the canonical form of it's a number, + // or a escaped quoted form of the original text if it's string-like. + switch (node.kind) { + case SyntaxKind.StringLiteral: + return getQuotedEscapedLiteralText('"', node.text, '"'); + case SyntaxKind.NoSubstitutionTemplateLiteral: + return getQuotedEscapedLiteralText('`', node.text, '`'); + case SyntaxKind.TemplateHead: + return getQuotedEscapedLiteralText('`', node.text, '${'); + case SyntaxKind.TemplateMiddle: + return getQuotedEscapedLiteralText('}', node.text, '${'); + case SyntaxKind.TemplateTail: + return getQuotedEscapedLiteralText('}', node.text, '`'); + case SyntaxKind.NumericLiteral: + return node.text; + } + + Debug.fail(`Literal kind '${node.kind}' not accounted for.`); + } + + function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) { + return leftQuote + escapeNonAsciiCharacters(escapeString(text)) + rightQuote; } function emitDownlevelRawTemplateLiteral(node: LiteralExpression) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 30b5a4a23a4..e6d2fffd06a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1130,7 +1130,7 @@ module ts { newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2)); } - return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength*/ newEndN - oldStartN); + return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength:*/ newEndN - oldStartN); } // @internal