From e710645bf95ff0cc90d3d13d3c15a9cf1e326ae5 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 17 Sep 2018 11:06:39 -0700 Subject: [PATCH] Never escape string literals from textChanges (#26971) * Never escape string literals from textChanges * Use `boolean | undefined` --- src/compiler/emitter.ts | 12 ++++++------ src/compiler/types.ts | 3 ++- src/compiler/utilities.ts | 4 ++-- src/services/textChanges.ts | 2 +- .../fourslash/importNameCodeFixNewImportFile0.ts | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 62dfb46f7c..fe54402d43 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1041,7 +1041,7 @@ namespace ts { // SyntaxKind.TemplateMiddle // SyntaxKind.TemplateTail function emitLiteral(node: LiteralLikeNode) { - const text = getLiteralTextOfNode(node); + const text = getLiteralTextOfNode(node, printerOptions.neverAsciiEscape); if ((printerOptions.sourceMap || printerOptions.inlineSourceMap) && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { writeLiteral(text); @@ -1532,7 +1532,7 @@ namespace ts { expression = skipPartiallyEmittedExpressions(expression); if (isNumericLiteral(expression)) { // check if numeric literal is a decimal literal that was originally written with a dot - const text = getLiteralTextOfNode(expression); + const text = getLiteralTextOfNode(expression, /*neverAsciiEscape*/ true); return !expression.numericLiteralFlags && !stringContains(text, tokenToString(SyntaxKind.DotToken)!); } @@ -3306,20 +3306,20 @@ namespace ts { return getSourceTextOfNodeFromSourceFile(currentSourceFile, node, includeTrivia); } - function getLiteralTextOfNode(node: LiteralLikeNode): string { + function getLiteralTextOfNode(node: LiteralLikeNode, neverAsciiEscape: boolean | undefined): string { if (node.kind === SyntaxKind.StringLiteral && (node).textSourceNode) { const textSourceNode = (node).textSourceNode!; if (isIdentifier(textSourceNode)) { - return getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? + return neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? `"${escapeString(getTextOfNode(textSourceNode))}"` : `"${escapeNonAsciiString(getTextOfNode(textSourceNode))}"`; } else { - return getLiteralTextOfNode(textSourceNode); + return getLiteralTextOfNode(textSourceNode, neverAsciiEscape); } } - return getLiteralText(node, currentSourceFile); + return getLiteralText(node, currentSourceFile, neverAsciiEscape); } /** diff --git a/src/compiler/types.ts b/src/compiler/types.ts index df267415bc..e0d027ded2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4967,7 +4967,7 @@ namespace ts { /* @internal */ export interface EmitNode { annotatedNodes?: Node[]; // Tracks Parse-tree nodes with EmitNodes for eventual cleanup. - flags: EmitFlags; // Flags that customize emit + flags: EmitFlags; // Flags that customize emit leadingComments?: SynthesizedComment[]; // Synthesized leading comments trailingComments?: SynthesizedComment[]; // Synthesized trailing comments commentRange?: TextRange; // The text range to use when emitting leading or trailing comments @@ -5327,6 +5327,7 @@ namespace ts { /*@internal*/ inlineSourceMap?: boolean; /*@internal*/ extendedDiagnostics?: boolean; /*@internal*/ onlyPrintJsDocStyle?: boolean; + /*@internal*/ neverAsciiEscape?: boolean; } /* @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 28749ed01e..6b7cb3d30e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -524,14 +524,14 @@ namespace ts { return emitNode && emitNode.flags || 0; } - export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile) { + export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile, neverAsciiEscape: boolean | undefined) { // 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 (!nodeIsSynthesized(node) && node.parent && !(isNumericLiteral(node) && node.numericLiteralFlags & TokenFlags.ContainsSeparator)) { return getSourceTextOfNodeFromSourceFile(sourceFile, node); } - const escapeText = getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? escapeString : escapeNonAsciiString; + const escapeText = neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? escapeString : escapeNonAsciiString; // If we can't reach the original source text, use the canonical form if it's a number, // or a (possibly escaped) quoted form of the original text if it's string-like. diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index 32d6360e90..99b94c2cc8 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -781,7 +781,7 @@ namespace ts.textChanges { function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLineCharacter: string): { text: string, node: Node } { const writer = new Writer(newLineCharacter); const newLine = newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed; - createPrinter({ newLine }, writer).writeNode(EmitHint.Unspecified, node, sourceFile, writer); + createPrinter({ newLine, neverAsciiEscape: true }, writer).writeNode(EmitHint.Unspecified, node, sourceFile, writer); return { text: writer.getText(), node: assignPositionsToNode(node) }; } } diff --git a/tests/cases/fourslash/importNameCodeFixNewImportFile0.ts b/tests/cases/fourslash/importNameCodeFixNewImportFile0.ts index 12566de406..8d86324a93 100644 --- a/tests/cases/fourslash/importNameCodeFixNewImportFile0.ts +++ b/tests/cases/fourslash/importNameCodeFixNewImportFile0.ts @@ -2,12 +2,12 @@ //// [|f1/*0*/();|] -// @Filename: module.ts +// @Filename: jalapeño.ts //// export function f1() {} //// export var v1 = 5; verify.importFixAtPosition([ -`import { f1 } from "./module"; +`import { f1 } from "./jalapeño"; f1();` ]);