Improve "Convert to template string" with template-strings

Fixes #44396
This commit is contained in:
Eli Barzilay 2021-06-02 17:46:41 -04:00
parent 8e01a86c01
commit bb7de99e5a
3 changed files with 40 additions and 19 deletions

View File

@ -20,7 +20,7 @@ namespace ts.refactor.convertStringOrTemplateLiteral {
const maybeBinary = getParentBinaryExpression(node);
const refactorInfo: ApplicableRefactorInfo = { name: refactorName, description: refactorDescription, actions: [] };
if (isBinaryExpression(maybeBinary) && isStringConcatenationValid(maybeBinary)) {
if (isBinaryExpression(maybeBinary) && treeToArray(maybeBinary).isValidConcatenation) {
refactorInfo.actions.push(convertStringAction);
return [refactorInfo];
}
@ -36,7 +36,7 @@ namespace ts.refactor.convertStringOrTemplateLiteral {
function getNodeOrParentOfParentheses(file: SourceFile, startPosition: number) {
const node = getTokenAtPosition(file, startPosition);
const nestedBinary = getParentBinaryExpression(node);
const isNonStringBinary = !isStringConcatenationValid(nestedBinary);
const isNonStringBinary = !treeToArray(nestedBinary).isValidConcatenation;
if (
isNonStringBinary &&
@ -101,32 +101,31 @@ namespace ts.refactor.convertStringOrTemplateLiteral {
}
});
return container || expr;
return (container || expr) as Expression;
}
function isStringConcatenationValid(node: Node): boolean {
const { containsString, areOperatorsValid } = treeToArray(node);
return containsString && areOperatorsValid;
}
function treeToArray(current: Expression) {
const loop = (current: Node): { nodes: Expression[], operators: Token<BinaryOperator>[], hasString: boolean, validOperators: boolean} => {
if (!isBinaryExpression(current)) {
return { nodes: [current as Expression], operators: [], validOperators: true,
hasString: isStringLiteral(current) || isNoSubstitutionTemplateLiteral(current) };
}
const { nodes, operators, hasString: leftHasString, validOperators: leftOperatorValid } = loop(current.left);
function treeToArray(current: Node): { nodes: Expression[], operators: Token<BinaryOperator>[], containsString: boolean, areOperatorsValid: boolean} {
if (isBinaryExpression(current)) {
const { nodes, operators, containsString: leftHasString, areOperatorsValid: leftOperatorValid } = treeToArray(current.left);
if (!leftHasString && !isStringLiteral(current.right) && !isTemplateExpression(current.right)) {
return { nodes: [current], operators: [], containsString: false, areOperatorsValid: true };
if (!(leftHasString || isStringLiteral(current.right) || isTemplateExpression(current.right))) {
return { nodes: [current], operators: [], hasString: false, validOperators: true };
}
const currentOperatorValid = current.operatorToken.kind === SyntaxKind.PlusToken;
const areOperatorsValid = leftOperatorValid && currentOperatorValid;
const validOperators = leftOperatorValid && currentOperatorValid;
nodes.push(current.right);
operators.push(current.operatorToken);
return { nodes, operators, containsString: true, areOperatorsValid };
}
return { nodes: [current as Expression], operators: [], containsString: isStringLiteral(current), areOperatorsValid: true };
return { nodes, operators, hasString: true, validOperators };
};
const { nodes, operators, validOperators, hasString } = loop(current);
return { nodes, operators, isValidConcatenation: validOperators && hasString };
}
// to copy comments following the operator
@ -153,7 +152,7 @@ namespace ts.refactor.convertStringOrTemplateLiteral {
let text = "";
while (index < nodes.length) {
const node = nodes[index];
if (isStringLiteralLike(node)) {
if (isStringLiteralLike(node)) { // includes isNoSubstitutionTemplateLiteral(node)
text = text + node.text;
indexes.push(index);
index++;

View File

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
////const a = /*x*/`x` + `y` + text + "z"/*y*/;
goTo.select("x", "y");
edit.applyRefactor({
refactorName: "Convert to template string",
actionName: "Convert to template string",
actionDescription: ts.Diagnostics.Convert_to_template_string.message,
newContent: "const a = `xy${text}z`;"
});

View File

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
////const a = /*x*/`x` + `y` + text + `z`/*y*/;
goTo.select("x", "y");
edit.applyRefactor({
refactorName: "Convert to template string",
actionName: "Convert to template string",
actionDescription: ts.Diagnostics.Convert_to_template_string.message,
newContent: "const a = `xy${text}z`;"
});