UNPKG

ts-simple-ast

Version:

TypeScript compiler wrapper for static analysis and code manipulation.

192 lines (191 loc) 8.24 kB
"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;