Skip to content

Commit 16109df

Browse files
committed
optimize templateLiteral check
1 parent 2b08bd3 commit 16109df

5 files changed

+42
-23
lines changed

src/services/refactors/convertStringOrTemplateLiteral.ts

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,41 +12,32 @@ namespace ts.refactor.convertStringOrTemplateLiteral {
1212

1313
function getAvailableActions(context: RefactorContext): ReadonlyArray<ApplicableRefactorInfo> {
1414
const { file, startPosition } = context;
15-
const node = getNodeOrParentOfBraces(file, startPosition);
15+
const node = getNodeOrParentOfParentheses(file, startPosition);
1616
const maybeBinary = getParentBinaryExpression(node);
1717
const actions: RefactorActionInfo[] = [];
1818

1919
if ((isBinaryExpression(maybeBinary) || isStringLiteral(maybeBinary)) && isStringConcatenationValid(maybeBinary)) {
2020
actions.push({ name: toTemplateLiteralActionName, description: toTemplateLiteralDescription });
2121
}
2222

23-
if (isTemplateLike(node)) {
23+
const templateLiteral = findAncestor(node, n => isTemplateLiteral(n));
24+
25+
if (templateLiteral && !isTaggedTemplateExpression(templateLiteral.parent)) {
2426
actions.push({ name: toStringConcatenationActionName, description: toStringConcatenationDescription });
2527
}
2628

2729
return [{ name: refactorName, description: refactorDescription, actions }];
2830
}
2931

30-
function getNodeOrParentOfBraces(file: SourceFile, startPosition: number) {
32+
function getNodeOrParentOfParentheses(file: SourceFile, startPosition: number) {
3133
const node = getTokenAtPosition(file, startPosition);
3234
if (isParenthesizedExpression(node.parent) && isBinaryExpression(node.parent.parent)) return node.parent.parent;
3335
return node;
3436
}
3537

36-
function isTemplateLike(node: Node) {
37-
const isTemplateWithoutSubstitution = isNoSubstitutionTemplateLiteral(node) && isNotTagged(node);
38-
const isTemplate = (isTemplateHead(node) || isTemplateMiddleOrTemplateTail(node)) && isNotTagged(node.parent);
39-
const isTemplateFromExpression = isTemplateSpan(node.parent) && isNotTagged(node.parent.parent);
40-
return isTemplateWithoutSubstitution || isTemplate || isTemplateFromExpression;
41-
}
42-
43-
function isNotTagged(templateExpression: Node) {
44-
return !isTaggedTemplateExpression(templateExpression.parent);
45-
}
46-
4738
function getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined {
4839
const { file, startPosition } = context;
49-
const node = getNodeOrParentOfBraces(file, startPosition);
40+
const node = getNodeOrParentOfParentheses(file, startPosition);
5041

5142
switch (actionName) {
5243
case toTemplateLiteralActionName:
@@ -65,20 +56,20 @@ namespace ts.refactor.convertStringOrTemplateLiteral {
6556
}
6657

6758
function getEditsForToStringConcatenation(context: RefactorContext, node: Node) {
68-
if (isTemplateExpression(node.parent) || isTemplateSpan(node.parent)) {
69-
const templateLiteralExpression = isTemplateSpan(node.parent) ? node.parent.parent : node.parent;
70-
const { head, templateSpans } = templateLiteralExpression;
59+
const templateLiteral = findAncestor(node, n => isTemplateLiteral(n))! as TemplateLiteral;
60+
61+
if (isTemplateExpression(templateLiteral)) {
62+
const { head, templateSpans } = templateLiteral;
7163
const arrayOfNodes = templateSpans.map(templateSpanToExpressions)
7264
.reduce((accumulator, nextArray) => accumulator.concat(nextArray));
7365

7466
if (head.text.length !== 0) arrayOfNodes.unshift(createStringLiteral(head.text));
7567

7668
const binaryExpression = arrayToTree(arrayOfNodes);
77-
return textChanges.ChangeTracker.with(context, t => t.replaceNode(context.file, templateLiteralExpression, binaryExpression));
69+
return textChanges.ChangeTracker.with(context, t => t.replaceNode(context.file, templateLiteral, binaryExpression));
7870
}
7971
else {
80-
const templateWithoutSubstitution = node as NoSubstitutionTemplateLiteral;
81-
const stringLiteral = createStringLiteral(templateWithoutSubstitution.text);
72+
const stringLiteral = createStringLiteral(templateLiteral.text);
8273
return textChanges.ChangeTracker.with(context, t => t.replaceNode(context.file, node, stringLiteral));
8374
}
8475
}

tests/cases/fourslash/refactorConvertStringOrTemplateLiteral_ToStringAvailability.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ verify.refactorAvailable("Convert string concatenation or template literal", "Co
2525
verify.not.refactorAvailable("Convert string concatenation or template literal", "Convert to template literal");
2626

2727
goTo.select("p", "o");
28-
verify.not.refactorAvailable("Convert string concatenation or template literal", "Convert to string concatenation");
28+
verify.refactorAvailable("Convert string concatenation or template literal", "Convert to string concatenation");
2929
verify.not.refactorAvailable("Convert string concatenation or template literal", "Convert to template literal");
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// const age = 42
4+
//// const foo = `foobar is a ${ age < 18 ? 'child' : /*x*/`/*y*/grown-up ${ age > 40 ? 'who needs probaply assistance' : ''}` }`
5+
6+
goTo.select("x", "y");
7+
edit.applyRefactor({
8+
refactorName: "Convert string concatenation or template literal",
9+
actionName: "Convert to string concatenation",
10+
actionDescription: "Convert to string concatenation",
11+
newContent:
12+
`const age = 42
13+
const foo = \`foobar is a \${ age < 18 ? 'child' : "grown-up " + (age > 40 ? 'who needs probaply assistance' : '') }\``,
14+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// const age = 42
4+
//// const foo = `foobar is a ${ `/*x*/3/*y*/4` }`
5+
6+
goTo.select("x", "y");
7+
edit.applyRefactor({
8+
refactorName: "Convert string concatenation or template literal",
9+
actionName: "Convert to string concatenation",
10+
actionDescription: "Convert to string concatenation",
11+
newContent:
12+
`const age = 42
13+
const foo = \`foobar is a \${ "34" }\``,
14+
});

tests/cases/fourslash/refactorConvertStringOrTemplateLiteral_ToStringNested.ts renamed to tests/cases/fourslash/refactorConvertStringOrTemplateLiteral_ToStringNestedOuter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// <reference path='fourslash.ts' />
22

33
//// const age = 42
4-
//// const foo = `/*x*/f/*y*/oobar is a ${ age < 18 ? 'child' : `grown-up ${ age > 40 ? 'who needs probaply assistance': ''}` }`
4+
//// const foo = `foobar is a ${ /*x*/a/*y*/ge < 18 ? 'child' : `grown-up ${ age > 40 ? 'who needs probaply assistance': ''}` }`
55

66
goTo.select("x", "y");
77
edit.applyRefactor({

0 commit comments

Comments
 (0)