@xtrek/ts-migrate-plugins
Version:
Set of codemods, which are doing transformation of js/jsx to ts/tsx
94 lines • 3.68 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const typescript_1 = __importDefault(require("typescript"));
const updateSourceText_1 = __importDefault(require("../../utils/updateSourceText"));
/**
* Tracks updates to a ts.SourceFile as text changes.
* This is useful to preserve as much of the original whitespace in the source
* file as possible. Re-printing the entire file causes blank lines to be lost.
*
* See: https://github.com/microsoft/TypeScript/issues/843
*/
class UpdateTracker {
constructor(sourceFile) {
this.sourceFile = sourceFile;
this.updates = [];
this.printer = typescript_1.default.createPrinter();
}
insert(pos, text) {
this.updates.push({
kind: 'insert',
index: pos,
text,
});
}
/**
* Adds a return type annotation to a function.
* replaceNode would require reprinting the entire function body, losing all whitespace details.
*/
addReturnAnnotation(node, type) {
const paren = node
.getChildren(this.sourceFile)
.find((node) => node.kind === typescript_1.default.SyntaxKind.CloseParenToken);
let pos;
if (paren) {
pos = paren.pos + 1;
}
else {
// Must be an arrow function with single parameter and no parentheses.
// Add parentheses.
pos = node.parameters.end;
const [param] = node.parameters;
this.insert(param.getStart(), '(');
this.insert(pos, ')');
}
const text = this.printer.printNode(typescript_1.default.EmitHint.Unspecified, type, this.sourceFile);
this.insert(pos, `: ${text}`);
}
insertNodes(pos, nodes) {
const text = this.printer.printList(typescript_1.default.ListFormat.SpaceAfterList, nodes, this.sourceFile);
this.insert(pos, text);
}
replace(pos, length, text) {
this.updates.push({
kind: 'replace',
index: pos,
length,
text,
});
}
replaceNode(oldNode, newNode) {
if (oldNode && newNode && oldNode !== newNode) {
const printedNextNode = this.printer.printNode(typescript_1.default.EmitHint.Unspecified, newNode, this.sourceFile);
const text = oldNode
.getFullText(this.sourceFile)
.replace(/^(\s*)[^]*?(\s*)$/, `$1${printedNextNode}$2`);
this.updates.push({
kind: 'replace',
index: oldNode.pos,
length: oldNode.end - oldNode.pos,
text,
});
}
}
replaceNodes(oldNodes, newNodes, addParens = false) {
if (oldNodes !== newNodes) {
const listFormat = addParens ? typescript_1.default.ListFormat.Parenthesis : typescript_1.default.ListFormat.CommaListElements;
const printedNextNode = this.printer.printList(listFormat, newNodes, this.sourceFile);
const prevText = this.sourceFile.text.substring(oldNodes.pos, oldNodes.end);
const text = prevText.replace(/^(\s*)[^]*?(\s*)$/, `$1${printedNextNode}$2`);
this.replace(oldNodes.pos, oldNodes.end - oldNodes.pos, text);
}
}
/**
* Returns the result of applying all tracked changes to the source file.
*/
apply() {
return updateSourceText_1.default(this.sourceFile.text, this.updates);
}
}
exports.default = UpdateTracker;
//# sourceMappingURL=update.js.map