alm
Version:
The best IDE for TypeScript
106 lines (105 loc) • 4.57 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
function isBinaryAddition(node) {
return (node.kind == ts.SyntaxKind.BinaryExpression &&
node.operatorToken.kind == ts.SyntaxKind.PlusToken);
}
function isStringExpression(node, typeChecker) {
var type = typeChecker.getTypeAtLocation(node);
var flags = type.getFlags();
return !!(flags & ts.TypeFlags.String);
}
/** Returns the root (binary +) node if there is some otherwise returns undefined */
function isAPartOfAChainOfStringAdditions(node, typeChecker) {
// We are looking for the `largestSumNode`. Its set once we find one up our tree
var largestSumNode = undefined;
while (true) {
// Whenever we find a binary expression of type sum that evaluates to a string
if (isBinaryAddition(node) && isStringExpression(node, typeChecker)) {
largestSumNode = node;
}
// We've gone too far up
if (node.kind == ts.SyntaxKind.SourceFile) {
return largestSumNode;
}
// Next look at the parent to find a larger sum node
node = node.parent;
}
}
var StringConcatToTemplate = /** @class */ (function () {
function StringConcatToTemplate() {
this.key = StringConcatToTemplate.name;
}
StringConcatToTemplate.prototype.canProvideFix = function (info) {
// Algo
// Can provide a quick fix if we are part of an expression that
// is a part of a binary + expression
// and when these binary +es end we come to an expression which is of type `string`
// Based on algo we do not care about what the current thing is as long as its a part of a sum of additions
var strRoot = isAPartOfAChainOfStringAdditions(info.positionNode, info.typeChecker);
if (strRoot) {
return { display: 'String concatenations to a template string' };
}
};
StringConcatToTemplate.prototype.provideFix = function (info) {
var strRoot = isAPartOfAChainOfStringAdditions(info.positionNode, info.typeChecker);
var finalOutput = [];
var current = strRoot;
var backTickCharacter = '`';
var backTick = new RegExp(backTickCharacter, 'g');
var $regex = /\$/g;
var appendToFinal = function (node) {
// Each string literal needs :
// to be checked that it doesn't contain (`) and those need to be escaped.
// Also `$` needs escaping
// Also the quote characters at the limits need to be removed
if (node.kind == ts.SyntaxKind.StringLiteral) {
var text = node.getText();
var quoteCharacter = text.trim()[0];
var quoteRegex = new RegExp(quoteCharacter, 'g');
var escapedQuoteRegex = new RegExp("\\\\" + quoteCharacter, 'g');
var newText_1 = text
.replace(backTick, "\\" + backTickCharacter)
.replace(escapedQuoteRegex, quoteCharacter)
.replace($regex, '\\$');
newText_1 = newText_1.substr(1, newText_1.length - 2);
finalOutput.unshift(newText_1);
}
else if (node.kind == ts.SyntaxKind.TemplateExpression || node.kind == ts.SyntaxKind.NoSubstitutionTemplateLiteral) {
var text = node.getText();
text = text.trim();
text = text.substr(1, text.length - 2);
finalOutput.unshift(text);
}
else {
finalOutput.unshift('${' + node.getText() + '}');
}
};
// We pop of each left node one by one
while (true) {
// if we are still in some sequence of additions
if (current.kind == ts.SyntaxKind.BinaryExpression) {
var binary = current;
appendToFinal(binary.right);
// Continue with left
current = binary.left;
}
else {
appendToFinal(current);
break;
}
}
var newText = backTickCharacter + finalOutput.join('') + backTickCharacter;
var refactoring = {
span: {
start: strRoot.getStart(),
length: strRoot.end - strRoot.getStart()
},
newText: newText,
filePath: info.filePath
};
return [refactoring];
};
return StringConcatToTemplate;
}());
exports.StringConcatToTemplate = StringConcatToTemplate;