ts-simple-ast
Version:
TypeScript compiler wrapper for static analysis and code manipulation.
192 lines (191 loc) • 8.24 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var typescript_1 = require("../../typescript");
var utils_1 = require("../../utils");
var helpers_1 = require("../helpers");
var nodeHandlers_1 = require("../nodeHandlers");
var textManipulators_1 = require("../textManipulators");
var doManipulation_1 = require("./doManipulation");
/**
* Inserts a text range into a parent.
*/
function insertIntoParentTextRange(opts) {
var insertPos = opts.insertPos, newText = opts.newText, parent = opts.parent;
// todo: this should only forget the existing node if the kind changes
doManipulation_1.doManipulation(parent._sourceFile, new textManipulators_1.InsertionTextManipulator({
insertPos: insertPos,
newText: newText,
replacingLength: opts.replacing == null ? undefined : opts.replacing.textLength
}), new nodeHandlers_1.NodeHandlerFactory().getForParentRange({
parent: parent,
start: insertPos,
end: insertPos + newText.length,
replacingLength: opts.replacing == null ? undefined : opts.replacing.textLength,
replacingNodes: opts.replacing == null ? undefined : opts.replacing.nodes,
customMappings: opts.customMappings
}));
}
exports.insertIntoParentTextRange = insertIntoParentTextRange;
/**
* Inserts a text range into a source file.
*/
function insertIntoTextRange(opts) {
var insertPos = opts.insertPos, newText = opts.newText, sourceFile = opts.sourceFile;
doManipulation_1.doManipulation(sourceFile, new textManipulators_1.InsertionTextManipulator({
insertPos: insertPos,
newText: newText
}), new nodeHandlers_1.NodeHandlerFactory().getForRange({
sourceFile: sourceFile,
start: insertPos,
end: insertPos + newText.length
}));
}
exports.insertIntoTextRange = insertIntoTextRange;
var endsWithComma = /\,\s*$/;
var startsWithComma = /^\s*\,/;
function insertIntoCommaSeparatedNodes(opts) {
var currentNodes = opts.currentNodes, insertIndex = opts.insertIndex, parent = opts.parent;
var nextNode = currentNodes[insertIndex];
var previousNode = currentNodes[insertIndex - 1];
var separator = opts.useNewLines ? parent._context.manipulationSettings.getNewLineKindAsString() : " ";
var parentNextSibling = parent.getNextSibling();
var isContained = parentNextSibling != null && (parentNextSibling.getKind() === typescript_1.SyntaxKind.CloseBraceToken || parentNextSibling.getKind() === typescript_1.SyntaxKind.CloseBracketToken);
var newText = opts.newText;
if (previousNode != null) {
prependCommaAndSeparator();
if (nextNode != null)
appendCommaAndSeparator();
else if (opts.useNewLines || opts.surroundWithSpaces)
appendSeparator();
else
appendIndentation();
var nextEndStart = nextNode == null ? (isContained ? parentNextSibling.getStart(true) : parent.getEnd()) : nextNode.getStart(true);
var insertPos = previousNode.getEnd();
insertIntoParentTextRange({
insertPos: insertPos,
newText: newText,
parent: parent,
replacing: { textLength: nextEndStart - insertPos }
});
}
else if (nextNode != null) {
if (opts.useNewLines || opts.surroundWithSpaces)
prependSeparator();
appendCommaAndSeparator();
var insertPos = isContained ? parent.getPos() : parent.getStart(true);
insertIntoParentTextRange({
insertPos: insertPos,
newText: newText,
parent: parent,
replacing: { textLength: nextNode.getStart(true) - insertPos }
});
}
else {
if (opts.useNewLines || opts.surroundWithSpaces) {
prependSeparator();
appendSeparator();
}
else
appendIndentation();
insertIntoParentTextRange({
insertPos: parent.getPos(),
newText: newText,
parent: parent,
replacing: { textLength: parent.getNextSiblingOrThrow().getStart() - parent.getPos() }
});
}
function prependCommaAndSeparator() {
if (!startsWithComma.test(newText)) {
prependSeparator();
newText = "," + newText;
}
}
function prependSeparator() {
if (!utils_1.StringUtils.startsWithNewLine(newText))
newText = separator + newText;
}
function appendCommaAndSeparator() {
if (!endsWithComma.test(newText)) {
newText = utils_1.StringUtils.insertAtLastNonWhitespace(newText, ",");
appendSeparator();
}
else
appendIndentation();
}
function appendSeparator() {
if (!utils_1.StringUtils.endsWithNewLine(newText))
newText += separator;
appendIndentation();
}
function appendIndentation() {
if (opts.useNewLines || utils_1.StringUtils.endsWithNewLine(newText)) {
if (nextNode != null)
newText += parent.getParentOrThrow().getChildIndentationText();
else
newText += parent.getParentOrThrow().getIndentationText();
}
}
}
exports.insertIntoCommaSeparatedNodes = insertIntoCommaSeparatedNodes;
/**
* Used to insert non-comma separated nodes into braces or a source file.
*/
function insertIntoBracesOrSourceFile(opts) {
var parent = opts.parent, index = opts.index, children = opts.children;
var fullText = parent._sourceFile.getFullText();
var insertPos = helpers_1.getInsertPosFromIndex(index, parent.getChildSyntaxListOrThrow(), children);
var endPos = helpers_1.getEndPosFromIndex(index, parent, children, fullText);
var replacingLength = endPos - insertPos;
var newText = getNewText();
doManipulation_1.doManipulation(parent._sourceFile, new textManipulators_1.InsertionTextManipulator({ insertPos: insertPos, replacingLength: replacingLength, newText: newText }), new nodeHandlers_1.NodeHandlerFactory().getForParentRange({
parent: parent.getChildSyntaxListOrThrow(),
start: insertPos,
end: insertPos + newText.length,
replacingLength: replacingLength
}));
function getNewText() {
// todo: make this configurable
var writer = parent._getWriterWithChildIndentation();
opts.write(writer, {
previousMember: getChild(children[index - 1]),
nextMember: getChild(children[index]),
isStartOfFile: insertPos === 0
});
return writer.toString();
function getChild(child) {
// ensure it passes the implementation
if (child == null)
return child;
else if (utils_1.TypeGuards.isOverloadableNode(child))
return child.getImplementation() || child;
else
return child;
}
}
}
exports.insertIntoBracesOrSourceFile = insertIntoBracesOrSourceFile;
/**
* Glues together insertIntoBracesOrSourceFile and getRangeFromArray.
* @param opts - Options to do this operation.
*/
function insertIntoBracesOrSourceFileWithGetChildren(opts) {
if (opts.structures.length === 0)
return [];
var startChildren = opts.getIndexedChildren();
var parentSyntaxList = opts.parent.getChildSyntaxListOrThrow();
var index = helpers_1.verifyAndGetIndex(opts.index, startChildren.length);
insertIntoBracesOrSourceFile({
parent: opts.parent,
index: getChildIndex(),
children: parentSyntaxList.getChildren(),
write: opts.write
});
return helpers_1.getRangeFromArray(opts.getIndexedChildren(), opts.index, opts.structures.length, opts.expectedKind);
function getChildIndex() {
if (index === 0)
return 0;
// get the previous member in order to get the implementation signature + 1
return startChildren[index - 1].getChildIndex() + 1;
}
}
exports.insertIntoBracesOrSourceFileWithGetChildren = insertIntoBracesOrSourceFileWithGetChildren;