mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 12:32:08 -06:00
Improve inlining of string variables in template literals (#54849)
This commit is contained in:
parent
20f26a481b
commit
a0530722fc
@ -24,6 +24,9 @@ import {
|
||||
isObjectLiteralExpression,
|
||||
isPropertyAccessExpression,
|
||||
isShorthandPropertyAssignment,
|
||||
isStringLiteral,
|
||||
isTaggedTemplateExpression,
|
||||
isTemplateSpan,
|
||||
isTypeQueryNode,
|
||||
isVariableDeclarationInVariableStatement,
|
||||
isVariableStatement,
|
||||
@ -33,11 +36,14 @@ import {
|
||||
refactor,
|
||||
some,
|
||||
SourceFile,
|
||||
StringLiteral,
|
||||
SymbolFlags,
|
||||
TemplateSpan,
|
||||
textChanges,
|
||||
textRangeContainsPositionInclusive,
|
||||
TypeChecker,
|
||||
VariableDeclaration,
|
||||
walkUpParenthesizedExpressions,
|
||||
} from "../_namespaces/ts.js";
|
||||
import {
|
||||
RefactorErrorInfo,
|
||||
@ -115,7 +121,13 @@ registerRefactor(refactorName, {
|
||||
const { references, declaration, replacement } = info;
|
||||
const edits = textChanges.ChangeTracker.with(context, tracker => {
|
||||
for (const node of references) {
|
||||
tracker.replaceNode(file, node, getReplacementExpression(node, replacement));
|
||||
const closestStringIdentifierParent = isStringLiteral(replacement) && isIdentifier(node) && walkUpParenthesizedExpressions(node.parent);
|
||||
if (closestStringIdentifierParent && isTemplateSpan(closestStringIdentifierParent) && !isTaggedTemplateExpression(closestStringIdentifierParent.parent.parent)) {
|
||||
replaceTemplateStringVariableWithLiteral(tracker, file, closestStringIdentifierParent, replacement);
|
||||
}
|
||||
else {
|
||||
tracker.replaceNode(file, node, getReplacementExpression(node, replacement));
|
||||
}
|
||||
}
|
||||
tracker.delete(file, declaration);
|
||||
});
|
||||
@ -255,3 +267,17 @@ function getReplacementExpression(reference: Node, replacement: Expression) {
|
||||
|
||||
return replacement;
|
||||
}
|
||||
|
||||
function replaceTemplateStringVariableWithLiteral(tracker: textChanges.ChangeTracker, sourceFile: SourceFile, reference: TemplateSpan, replacement: StringLiteral) {
|
||||
const templateExpression = reference.parent;
|
||||
const index = templateExpression.templateSpans.indexOf(reference);
|
||||
const prevNode = index === 0 ? templateExpression.head : templateExpression.templateSpans[index - 1];
|
||||
tracker.replaceRangeWithText(
|
||||
sourceFile,
|
||||
{
|
||||
pos: prevNode.getEnd() - 2,
|
||||
end: reference.literal.getStart() + 1,
|
||||
},
|
||||
replacement.text.replace(/\\/g, "\\\\").replace(/`/g, "\\`"),
|
||||
);
|
||||
}
|
||||
|
||||
13
tests/cases/fourslash/inlineVariableTemplateString1.ts
Normal file
13
tests/cases/fourslash/inlineVariableTemplateString1.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////const /*a*/pizza/*b*/ = "🍕";
|
||||
////export const prompt = `Hello, would you like some ${pizza}?`;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorAvailable("Inline variable");
|
||||
edit.applyRefactor({
|
||||
refactorName: "Inline variable",
|
||||
actionName: "Inline variable",
|
||||
actionDescription: "Inline variable",
|
||||
newContent: "export const prompt = `Hello, would you like some 🍕?`;"
|
||||
});
|
||||
13
tests/cases/fourslash/inlineVariableTemplateString10.ts
Normal file
13
tests/cases/fourslash/inlineVariableTemplateString10.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////const /*a*/message/*b*/ = "Hello, World!";
|
||||
////await $`echo ${((message))}`;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorAvailable("Inline variable");
|
||||
edit.applyRefactor({
|
||||
refactorName: "Inline variable",
|
||||
actionName: "Inline variable",
|
||||
actionDescription: "Inline variable",
|
||||
newContent: 'await $`echo ${(("Hello, World!"))}`;',
|
||||
});
|
||||
13
tests/cases/fourslash/inlineVariableTemplateString11.ts
Normal file
13
tests/cases/fourslash/inlineVariableTemplateString11.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////const /*a*/pizza/*b*/ = "🍕";
|
||||
////export const prompt = `Hello, would you like some ${((pizza))}?`;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorAvailable("Inline variable");
|
||||
edit.applyRefactor({
|
||||
refactorName: "Inline variable",
|
||||
actionName: "Inline variable",
|
||||
actionDescription: "Inline variable",
|
||||
newContent: "export const prompt = `Hello, would you like some 🍕?`;"
|
||||
});
|
||||
13
tests/cases/fourslash/inlineVariableTemplateString2.ts
Normal file
13
tests/cases/fourslash/inlineVariableTemplateString2.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////const /*a*/codeText/*b*/ = "Code-formatted text looks `like this` and requires surrounding by backticks (\\`).";
|
||||
////export const mdTutorial = `Let's talk about markdown.\n${codeText}?`;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorAvailable("Inline variable");
|
||||
edit.applyRefactor({
|
||||
refactorName: "Inline variable",
|
||||
actionName: "Inline variable",
|
||||
actionDescription: "Inline variable",
|
||||
newContent: "export const mdTutorial = `Let's talk about markdown.\\nCode-formatted text looks \\`like this\\` and requires surrounding by backticks (\\\\\\\`).?`;"
|
||||
});
|
||||
15
tests/cases/fourslash/inlineVariableTemplateString3.ts
Normal file
15
tests/cases/fourslash/inlineVariableTemplateString3.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////const /*a*/pizza/*b*/ = "🍕";
|
||||
////export const prompt = `Hello, would you like some ${
|
||||
//// pizza
|
||||
//// }?`;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorAvailable("Inline variable");
|
||||
edit.applyRefactor({
|
||||
refactorName: "Inline variable",
|
||||
actionName: "Inline variable",
|
||||
actionDescription: "Inline variable",
|
||||
newContent: "export const prompt = `Hello, would you like some 🍕?`;"
|
||||
});
|
||||
13
tests/cases/fourslash/inlineVariableTemplateString4.ts
Normal file
13
tests/cases/fourslash/inlineVariableTemplateString4.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////const /*a*/pizza/*b*/ = "🍕";
|
||||
////export const prompt = `Hello, would you like some ${pizza} or ${pizza}?`;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorAvailable("Inline variable");
|
||||
edit.applyRefactor({
|
||||
refactorName: "Inline variable",
|
||||
actionName: "Inline variable",
|
||||
actionDescription: "Inline variable",
|
||||
newContent: "export const prompt = `Hello, would you like some 🍕 or 🍕?`;"
|
||||
});
|
||||
13
tests/cases/fourslash/inlineVariableTemplateString5.ts
Normal file
13
tests/cases/fourslash/inlineVariableTemplateString5.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////const /*a*/pizza/*b*/ = "🍕";
|
||||
////export const prompt = `Hello, would you like some ${pizza}`;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorAvailable("Inline variable");
|
||||
edit.applyRefactor({
|
||||
refactorName: "Inline variable",
|
||||
actionName: "Inline variable",
|
||||
actionDescription: "Inline variable",
|
||||
newContent: "export const prompt = `Hello, would you like some 🍕`;"
|
||||
});
|
||||
13
tests/cases/fourslash/inlineVariableTemplateString6.ts
Normal file
13
tests/cases/fourslash/inlineVariableTemplateString6.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////const /*a*/x/*b*/ = "\\`";
|
||||
////export const y = `${x}`;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorAvailable("Inline variable");
|
||||
edit.applyRefactor({
|
||||
refactorName: "Inline variable",
|
||||
actionName: "Inline variable",
|
||||
actionDescription: "Inline variable",
|
||||
newContent: "export const y = `\\\\\\``;"
|
||||
});
|
||||
13
tests/cases/fourslash/inlineVariableTemplateString7.ts
Normal file
13
tests/cases/fourslash/inlineVariableTemplateString7.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////const /*a*/x/*b*/ = "`";
|
||||
////export const y = `${x}`;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorAvailable("Inline variable");
|
||||
edit.applyRefactor({
|
||||
refactorName: "Inline variable",
|
||||
actionName: "Inline variable",
|
||||
actionDescription: "Inline variable",
|
||||
newContent: "export const y = `\\``;"
|
||||
});
|
||||
13
tests/cases/fourslash/inlineVariableTemplateString8.ts
Normal file
13
tests/cases/fourslash/inlineVariableTemplateString8.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////const /*a*/message/*b*/ = "Hello, World!";
|
||||
////await $`echo ${message}`;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorAvailable("Inline variable");
|
||||
edit.applyRefactor({
|
||||
refactorName: "Inline variable",
|
||||
actionName: "Inline variable",
|
||||
actionDescription: "Inline variable",
|
||||
newContent: 'await $`echo ${"Hello, World!"}`;',
|
||||
});
|
||||
13
tests/cases/fourslash/inlineVariableTemplateString9.ts
Normal file
13
tests/cases/fourslash/inlineVariableTemplateString9.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////const /*a*/message/*b*/ = "Hello, World!";
|
||||
////await $`echo ${(message)}`;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorAvailable("Inline variable");
|
||||
edit.applyRefactor({
|
||||
refactorName: "Inline variable",
|
||||
actionName: "Inline variable",
|
||||
actionDescription: "Inline variable",
|
||||
newContent: 'await $`echo ${("Hello, World!")}`;',
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user