UNPKG

ts-simple-ast

Version:

TypeScript compiler wrapper for AST navigation and code generation.

139 lines (137 loc) 5.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const ts = require("typescript"); const errors = require("./../../errors"); const manipulation_1 = require("./../../manipulation"); function ModifierableNode(Base) { return class extends Base { getModifiers() { return this.compilerNode.modifiers == null ? [] : this.compilerNode.modifiers.map(m => this.global.compilerFactory.getNodeFromCompilerNode(m, this.sourceFile)); } getFirstModifierByKindOrThrow(kind) { return errors.throwIfNullOrUndefined(this.getFirstModifierByKind(kind), `Expected a modifier of syntax kind: ${ts.SyntaxKind[kind]}`); } getFirstModifierByKind(kind) { for (const modifier of this.getModifiers()) { if (modifier.getKind() === kind) return modifier; } return undefined; } hasModifier(textOrKind) { if (typeof textOrKind === "string") return this.getModifiers().some(m => m.getText() === textOrKind); else return this.getModifiers().some(m => m.getKind() === textOrKind); } toggleModifier(text, value) { if (value == null) value = !this.hasModifier(text); if (value) this.addModifier(text); else this.removeModifier(text); return this; } addModifier(text) { const modifiers = this.getModifiers(); const hasModifier = modifiers.some(m => m.getText() === text); if (hasModifier) return this.getModifiers().find(m => m.getText() === text); // get insert position & index const { insertPos, insertIndex } = getInsertInfo(this); // insert setup let startPos; let newText; const isFirstModifier = modifiers.length === 0 || insertPos === modifiers[0].getStart(); if (isFirstModifier) { newText = text + " "; startPos = insertPos; } else { newText = " " + text; startPos = insertPos + 1; } // insert manipulation_1.insertIntoCreatableSyntaxList({ parent: this, insertPos, newText, syntaxList: modifiers.length === 0 ? undefined : modifiers[0].getParentSyntaxListOrThrow(), childIndex: insertIndex, insertItemsCount: 1 }); return this.getModifiers().find(m => m.getStart() === startPos); function getInsertInfo(node) { let pos = getInitialInsertPos(); let index = 0; for (const addAfterText of getAddAfterModifierTexts(text)) { for (let i = 0; i < modifiers.length; i++) { const modifier = modifiers[i]; if (modifier.getText() === addAfterText) { if (pos < modifier.getEnd()) { pos = modifier.getEnd(); index = i + 1; } break; } } } return { insertPos: pos, insertIndex: index }; function getInitialInsertPos() { if (modifiers.length > 0) return modifiers[0].getStart(); for (const child of node.getChildrenIterator()) { // skip over any initial syntax lists (ex. decorators) or js docs if (child.getKind() === ts.SyntaxKind.SyntaxList || ts.isJSDocCommentContainingNode(child.compilerNode)) continue; return child.getStart(); } return node.getStart(); } } } removeModifier(text) { const modifier = this.getModifiers().find(m => m.getText() === text); if (modifier == null) return false; manipulation_1.removeChildrenWithFormattingFromCollapsibleSyntaxList({ children: [modifier], getSiblingFormatting: () => manipulation_1.FormattingKind.Space }); return true; } }; } exports.ModifierableNode = ModifierableNode; /** * @returns The texts the specified text should appear after. */ function getAddAfterModifierTexts(text) { switch (text) { case "export": return []; case "default": return ["export"]; case "declare": return ["export", "default"]; case "abstract": return ["export", "default", "declare", "public", "private", "protected"]; case "readonly": return ["export", "default", "declare", "public", "private", "protected", "abstract", "static"]; case "public": case "protected": case "private": return []; case "static": return ["public", "protected", "private"]; case "async": return ["export", "public", "protected", "private", "static", "abstract"]; case "const": return []; /* istanbul ignore next */ default: throw new errors.NotImplementedError(`Not implemented modifier: ${text}`); } } //# sourceMappingURL=ModifierableNode.js.map