Skip to content

Commit bb7de99

Browse files
committed
Improve "Convert to template string" with template-strings
Fixes #44396
1 parent 8e01a86 commit bb7de99

File tree

3 files changed

+40
-19
lines changed

3 files changed

+40
-19
lines changed

src/services/refactors/convertStringOrTemplateLiteral.ts

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace ts.refactor.convertStringOrTemplateLiteral {
2020
const maybeBinary = getParentBinaryExpression(node);
2121
const refactorInfo: ApplicableRefactorInfo = { name: refactorName, description: refactorDescription, actions: [] };
2222

23-
if (isBinaryExpression(maybeBinary) && isStringConcatenationValid(maybeBinary)) {
23+
if (isBinaryExpression(maybeBinary) && treeToArray(maybeBinary).isValidConcatenation) {
2424
refactorInfo.actions.push(convertStringAction);
2525
return [refactorInfo];
2626
}
@@ -36,7 +36,7 @@ namespace ts.refactor.convertStringOrTemplateLiteral {
3636
function getNodeOrParentOfParentheses(file: SourceFile, startPosition: number) {
3737
const node = getTokenAtPosition(file, startPosition);
3838
const nestedBinary = getParentBinaryExpression(node);
39-
const isNonStringBinary = !isStringConcatenationValid(nestedBinary);
39+
const isNonStringBinary = !treeToArray(nestedBinary).isValidConcatenation;
4040

4141
if (
4242
isNonStringBinary &&
@@ -101,32 +101,31 @@ namespace ts.refactor.convertStringOrTemplateLiteral {
101101
}
102102
});
103103

104-
return container || expr;
104+
return (container || expr) as Expression;
105105
}
106106

107-
function isStringConcatenationValid(node: Node): boolean {
108-
const { containsString, areOperatorsValid } = treeToArray(node);
109-
return containsString && areOperatorsValid;
110-
}
111-
112-
function treeToArray(current: Node): { nodes: Expression[], operators: Token<BinaryOperator>[], containsString: boolean, areOperatorsValid: boolean} {
113-
if (isBinaryExpression(current)) {
114-
const { nodes, operators, containsString: leftHasString, areOperatorsValid: leftOperatorValid } = treeToArray(current.left);
107+
function treeToArray(current: Expression) {
108+
const loop = (current: Node): { nodes: Expression[], operators: Token<BinaryOperator>[], hasString: boolean, validOperators: boolean} => {
109+
if (!isBinaryExpression(current)) {
110+
return { nodes: [current as Expression], operators: [], validOperators: true,
111+
hasString: isStringLiteral(current) || isNoSubstitutionTemplateLiteral(current) };
112+
}
113+
const { nodes, operators, hasString: leftHasString, validOperators: leftOperatorValid } = loop(current.left);
115114

116-
if (!leftHasString && !isStringLiteral(current.right) && !isTemplateExpression(current.right)) {
117-
return { nodes: [current], operators: [], containsString: false, areOperatorsValid: true };
115+
if (!(leftHasString || isStringLiteral(current.right) || isTemplateExpression(current.right))) {
116+
return { nodes: [current], operators: [], hasString: false, validOperators: true };
118117
}
119118

120119
const currentOperatorValid = current.operatorToken.kind === SyntaxKind.PlusToken;
121-
const areOperatorsValid = leftOperatorValid && currentOperatorValid;
120+
const validOperators = leftOperatorValid && currentOperatorValid;
122121

123122
nodes.push(current.right);
124123
operators.push(current.operatorToken);
125124

126-
return { nodes, operators, containsString: true, areOperatorsValid };
127-
}
128-
129-
return { nodes: [current as Expression], operators: [], containsString: isStringLiteral(current), areOperatorsValid: true };
125+
return { nodes, operators, hasString: true, validOperators };
126+
};
127+
const { nodes, operators, validOperators, hasString } = loop(current);
128+
return { nodes, operators, isValidConcatenation: validOperators && hasString };
130129
}
131130

132131
// to copy comments following the operator
@@ -153,7 +152,7 @@ namespace ts.refactor.convertStringOrTemplateLiteral {
153152
let text = "";
154153
while (index < nodes.length) {
155154
const node = nodes[index];
156-
if (isStringLiteralLike(node)) {
155+
if (isStringLiteralLike(node)) { // includes isNoSubstitutionTemplateLiteral(node)
157156
text = text + node.text;
158157
indexes.push(index);
159158
index++;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////const a = /*x*/`x` + `y` + text + "z"/*y*/;
4+
5+
goTo.select("x", "y");
6+
edit.applyRefactor({
7+
refactorName: "Convert to template string",
8+
actionName: "Convert to template string",
9+
actionDescription: ts.Diagnostics.Convert_to_template_string.message,
10+
newContent: "const a = `xy${text}z`;"
11+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////const a = /*x*/`x` + `y` + text + `z`/*y*/;
4+
5+
goTo.select("x", "y");
6+
edit.applyRefactor({
7+
refactorName: "Convert to template string",
8+
actionName: "Convert to template string",
9+
actionDescription: ts.Diagnostics.Convert_to_template_string.message,
10+
newContent: "const a = `xy${text}z`;"
11+
});

0 commit comments

Comments
 (0)