UNPKG

ts-simple-ast

Version:

TypeScript compiler wrapper for AST navigation and code generation.

593 lines (592 loc) 28 kB
"use strict"; var __extends = (this && this.__extends)/* istanbul ignore next */ || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __values = (this && this.__values)/* istanbul ignore next */ || function (o) { var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; if (m) return m.call(o); return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; }; Object.defineProperty(exports, "__esModule", { value: true }); var ts = require("typescript"); var errors = require("./../../errors"); var manipulation_1 = require("./../../manipulation"); var utils_1 = require("./../../utils"); var structureToTexts = require("./../../structureToTexts"); var common_1 = require("./../common"); var base_1 = require("./../base"); var base_2 = require("./base"); var function_1 = require("./../function"); var namespace_1 = require("./../namespace"); var callBaseFill_1 = require("./../callBaseFill"); var MethodDeclaration_1 = require("./MethodDeclaration"); exports.ClassDeclarationBase = base_1.ChildOrderableNode(base_1.TextInsertableNode(base_1.ImplementsClauseableNode(base_1.HeritageClauseableNode(base_1.DecoratableNode(base_1.TypeParameteredNode(namespace_1.NamespaceChildableNode(base_1.JSDocableNode(base_1.AmbientableNode(base_2.AbstractableNode(base_1.ExportableNode(base_1.ModifierableNode(base_1.NamedNode(common_1.Node))))))))))))); var ClassDeclaration = /** @class */ (function (_super) { __extends(ClassDeclaration, _super); function ClassDeclaration() { return _super !== null && _super.apply(this, arguments) || this; } /** * Fills the node from a structure. * @param structure - Structure to fill. */ ClassDeclaration.prototype.fill = function (structure) { callBaseFill_1.callBaseFill(exports.ClassDeclarationBase.prototype, this, structure); if (structure.extends != null) this.setExtends(structure.extends); if (structure.ctor != null) this.addConstructor(structure.ctor); if (structure.properties != null) this.addProperties(structure.properties); if (structure.getAccessors != null) this.addGetAccessors(structure.getAccessors); if (structure.setAccessors != null) this.addSetAccessors(structure.setAccessors); if (structure.methods != null) this.addMethods(structure.methods); return this; }; /** * Sets the extends expression. * @param text - Text to set as the extends expression. */ ClassDeclaration.prototype.setExtends = function (text) { if (utils_1.StringUtils.isNullOrWhitespace(text)) return this.removeExtends(); var heritageClauses = this.getHeritageClauses(); var extendsClause = this.getHeritageClauseByKind(ts.SyntaxKind.ExtendsKeyword); if (extendsClause != null) { var childSyntaxList = extendsClause.getFirstChildByKindOrThrow(ts.SyntaxKind.SyntaxList); var childSyntaxListStart = childSyntaxList.getStart(); manipulation_1.insertIntoParent({ parent: extendsClause, childIndex: childSyntaxList.getChildIndex(), insertItemsCount: 1, newText: text, insertPos: childSyntaxListStart, replacing: { textLength: childSyntaxList.getEnd() - childSyntaxListStart, nodes: [childSyntaxList] } }); return this; } var implementsClause = this.getHeritageClauseByKind(ts.SyntaxKind.ImplementsKeyword); var insertPos; if (implementsClause != null) insertPos = implementsClause.getStart(); else insertPos = this.getFirstChildByKindOrThrow(ts.SyntaxKind.OpenBraceToken).getStart(); var isLastSpace = /\s/.test(this.getSourceFile().getFullText()[insertPos - 1]); var newText = "extends " + text + " "; if (!isLastSpace) newText = " " + newText; manipulation_1.insertIntoCreatableSyntaxList({ parent: this, insertPos: insertPos, newText: newText, syntaxList: implementsClause == null ? undefined : implementsClause.getParentSyntaxListOrThrow(), childIndex: 0, insertItemsCount: 1 }); return this; }; /** * Removes the extends expression, if it exists. */ ClassDeclaration.prototype.removeExtends = function () { var extendsClause = this.getHeritageClauseByKind(ts.SyntaxKind.ExtendsKeyword); if (extendsClause == null) return this; extendsClause.removeExpression(0); return this; }; /** * Gets the extends expression. */ ClassDeclaration.prototype.getExtends = function () { var extendsClause = this.getHeritageClauseByKind(ts.SyntaxKind.ExtendsKeyword); if (extendsClause == null) return undefined; var types = extendsClause.getTypes(); return types.length === 0 ? undefined : types[0]; }; /** * Adds a constructor. Will remove the previous constructor if it exists. * @param structure - Structure of the constructor. */ ClassDeclaration.prototype.addConstructor = function (structure) { if (structure === void 0) { structure = {}; } return this.insertConstructor(manipulation_1.getEndIndexFromArray(this.getBodyMembers()), structure); }; /** * Inserts a constructor. Will remove the previous constructor if it exists. * @param index - Index to insert at. * @param structure - Structure of the constructor. */ ClassDeclaration.prototype.insertConstructor = function (index, structure) { var _this = this; if (structure === void 0) { structure = {}; } try { for (var _a = __values(this.getConstructors()), _b = _a.next(); !_b.done; _b = _a.next()) { var c = _b.value; c.remove(); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_b && !_b.done && (_c = _a.return)) _c.call(_a); } finally { if (e_1) throw e_1.error; } } var writer = this.getChildWriter(); var structureToText = new structureToTexts.ConstructorDeclarationStructureToText(writer); structureToText.writeText(structure); var code = writer.toString(); return manipulation_1.insertIntoBracesOrSourceFileWithFillAndGetChildren({ getIndexedChildren: function () { return _this.getBodyMembers(); }, sourceFile: this.getSourceFile(), parent: this, index: index, childCodes: [code], structures: [structure], previousBlanklineWhen: function () { return true; }, nextBlanklineWhen: function () { return true; }, expectedKind: ts.SyntaxKind.Constructor, fillFunction: function (node, struct) { return node.fill(struct); } })[0]; var e_1, _c; }; /** * Gets the constructor declarations. */ ClassDeclaration.prototype.getConstructors = function () { return this.getAllMembers().filter(function (m) { return utils_1.TypeGuards.isConstructorDeclaration(m); }); }; /** * Add get accessor. * @param structure - Structure representing the get accessor. */ ClassDeclaration.prototype.addGetAccessor = function (structure) { return this.addGetAccessors([structure])[0]; }; /** * Add properties. * @param structures - Structures representing the properties. */ ClassDeclaration.prototype.addGetAccessors = function (structures) { return this.insertGetAccessors(manipulation_1.getEndIndexFromArray(this.getBodyMembers()), structures); }; /** * Insert get accessor. * @param index - Index to insert at. * @param structure - Structure representing the get accessor. */ ClassDeclaration.prototype.insertGetAccessor = function (index, structure) { return this.insertGetAccessors(index, [structure])[0]; }; /** * Insert properties. * @param index - Index to insert at. * @param structures - Structures representing the properties. */ ClassDeclaration.prototype.insertGetAccessors = function (index, structures) { var _this = this; var indentationText = this.getChildIndentationText(); // create code var codes = structures.map(function (s) { // todo: pass in the StructureToText to the function below var writer = _this.getChildWriter(); var structureToText = new structureToTexts.GetAccessorDeclarationStructureToText(writer); structureToText.writeText(s); return writer.toString(); }); return manipulation_1.insertIntoBracesOrSourceFileWithFillAndGetChildren({ getIndexedChildren: function () { return _this.getBodyMembers(); }, sourceFile: this.getSourceFile(), parent: this, index: index, childCodes: codes, structures: structures, previousBlanklineWhen: function () { return true; }, separatorNewlineWhen: function () { return true; }, nextBlanklineWhen: function () { return true; }, expectedKind: ts.SyntaxKind.GetAccessor, fillFunction: function (node, structure) { return node.fill(structure); } }); }; /** * Add set accessor. * @param structure - Structure representing the set accessor. */ ClassDeclaration.prototype.addSetAccessor = function (structure) { return this.addSetAccessors([structure])[0]; }; /** * Add properties. * @param structures - Structures representing the properties. */ ClassDeclaration.prototype.addSetAccessors = function (structures) { return this.insertSetAccessors(manipulation_1.getEndIndexFromArray(this.getBodyMembers()), structures); }; /** * Insert set accessor. * @param index - Index to insert at. * @param structure - Structure representing the set accessor. */ ClassDeclaration.prototype.insertSetAccessor = function (index, structure) { return this.insertSetAccessors(index, [structure])[0]; }; /** * Insert properties. * @param index - Index to insert at. * @param structures - Structures representing the properties. */ ClassDeclaration.prototype.insertSetAccessors = function (index, structures) { var _this = this; var indentationText = this.getChildIndentationText(); var newLineKind = this.global.manipulationSettings.getNewLineKind(); // create code var codes = structures.map(function (s) { // todo: pass in the StructureToText to the function below var writer = _this.getChildWriter(); var structureToText = new structureToTexts.SetAccessorDeclarationStructureToText(writer); structureToText.writeText(s); return writer.toString(); }); return manipulation_1.insertIntoBracesOrSourceFileWithFillAndGetChildren({ getIndexedChildren: function () { return _this.getBodyMembers(); }, sourceFile: this.getSourceFile(), parent: this, index: index, childCodes: codes, structures: structures, previousBlanklineWhen: function () { return true; }, separatorNewlineWhen: function () { return true; }, nextBlanklineWhen: function () { return true; }, expectedKind: ts.SyntaxKind.SetAccessor, fillFunction: function (node, structure) { return node.fill(structure); } }); }; /** * Add property. * @param structure - Structure representing the property. */ ClassDeclaration.prototype.addProperty = function (structure) { return this.addProperties([structure])[0]; }; /** * Add properties. * @param structures - Structures representing the properties. */ ClassDeclaration.prototype.addProperties = function (structures) { return this.insertProperties(manipulation_1.getEndIndexFromArray(this.getBodyMembers()), structures); }; /** * Insert property. * @param index - Index to insert at. * @param structure - Structure representing the property. */ ClassDeclaration.prototype.insertProperty = function (index, structure) { return this.insertProperties(index, [structure])[0]; }; /** * Insert properties. * @param index - Index to insert at. * @param structures - Structures representing the properties. */ ClassDeclaration.prototype.insertProperties = function (index, structures) { var _this = this; var indentationText = this.getChildIndentationText(); // create code var codes = structures.map(function (s) { // todo: pass in the StructureToText to the function below var writer = _this.getChildWriter(); var structureToText = new structureToTexts.PropertyDeclarationStructureToText(writer); structureToText.writeText(s); return writer.toString(); }); return manipulation_1.insertIntoBracesOrSourceFileWithFillAndGetChildren({ getIndexedChildren: function () { return _this.getBodyMembers(); }, sourceFile: this.getSourceFile(), parent: this, index: index, childCodes: codes, structures: structures, previousBlanklineWhen: function (n) { return utils_1.TypeGuards.isBodyableNode(n) || utils_1.TypeGuards.isBodiedNode(n); }, nextBlanklineWhen: function (n) { return utils_1.TypeGuards.isBodyableNode(n) || utils_1.TypeGuards.isBodiedNode(n); }, expectedKind: ts.SyntaxKind.PropertyDeclaration, fillFunction: function (node, structure) { return node.fill(structure); } }); }; ClassDeclaration.prototype.getInstanceProperty = function (nameOrFindFunction) { return utils_1.getNamedNodeByNameOrFindFunction(this.getInstanceProperties(), nameOrFindFunction); }; ClassDeclaration.prototype.getInstancePropertyOrThrow = function (nameOrFindFunction) { return errors.throwIfNullOrUndefined(this.getInstanceProperty(nameOrFindFunction), function () { return utils_1.getNotFoundErrorMessageForNameOrFindFunction("class instance property", nameOrFindFunction); }); }; /** * Gets the class instance property declarations. */ ClassDeclaration.prototype.getInstanceProperties = function () { return this.getInstanceMembers() .filter(function (m) { return isClassPropertyType(m); }); }; ClassDeclaration.prototype.getStaticProperty = function (nameOrFindFunction) { return utils_1.getNamedNodeByNameOrFindFunction(this.getStaticProperties(), nameOrFindFunction); }; ClassDeclaration.prototype.getStaticPropertyOrThrow = function (nameOrFindFunction) { return errors.throwIfNullOrUndefined(this.getStaticProperty(nameOrFindFunction), function () { return utils_1.getNotFoundErrorMessageForNameOrFindFunction("class static property", nameOrFindFunction); }); }; /** * Gets the class instance property declarations. */ ClassDeclaration.prototype.getStaticProperties = function () { return this.getStaticMembers() .filter(function (m) { return isClassPropertyType(m); }); }; /** * Add method. * @param structure - Structure representing the method. */ ClassDeclaration.prototype.addMethod = function (structure) { return this.addMethods([structure])[0]; }; /** * Add methods. * @param structures - Structures representing the methods. */ ClassDeclaration.prototype.addMethods = function (structures) { return this.insertMethods(manipulation_1.getEndIndexFromArray(this.getBodyMembers()), structures); }; /** * Insert method. * @param index - Index to insert at. * @param structure - Structure representing the method. */ ClassDeclaration.prototype.insertMethod = function (index, structure) { return this.insertMethods(index, [structure])[0]; }; /** * Insert methods. * @param index - Index to insert at. * @param structures - Structures representing the methods. */ ClassDeclaration.prototype.insertMethods = function (index, structures) { var _this = this; var indentationText = this.getChildIndentationText(); var newLineKind = this.global.manipulationSettings.getNewLineKind(); var isAmbient = this.isAmbient(); // create code var codes = structures.map(function (s) { // todo: pass in the StructureToText to the function below var writer = _this.getChildWriter(); var structureToText = new structureToTexts.MethodDeclarationStructureToText(writer, { isAmbient: isAmbient }); structureToText.writeText(s); return writer.toString(); }); // insert, fill, and get created nodes return manipulation_1.insertIntoBracesOrSourceFileWithFillAndGetChildren({ getIndexedChildren: function () { return _this.getBodyMembers(); }, sourceFile: this.getSourceFile(), parent: this, index: index, childCodes: codes, structures: structures, previousBlanklineWhen: function () { return !isAmbient; }, nextBlanklineWhen: function () { return !isAmbient; }, separatorNewlineWhen: function () { return !isAmbient; }, expectedKind: ts.SyntaxKind.MethodDeclaration, fillFunction: function (node, structure) { return node.fill(structure); } }); }; ClassDeclaration.prototype.getInstanceMethod = function (nameOrFindFunction) { return utils_1.getNamedNodeByNameOrFindFunction(this.getInstanceMethods(), nameOrFindFunction); }; ClassDeclaration.prototype.getInstanceMethodOrThrow = function (nameOrFindFunction) { return errors.throwIfNullOrUndefined(this.getInstanceMethod(nameOrFindFunction), function () { return utils_1.getNotFoundErrorMessageForNameOrFindFunction("class instance method", nameOrFindFunction); }); }; /** * Gets the class instance method declarations. */ ClassDeclaration.prototype.getInstanceMethods = function () { return this.getInstanceMembers().filter(function (m) { return m instanceof MethodDeclaration_1.MethodDeclaration; }); }; ClassDeclaration.prototype.getStaticMethod = function (nameOrFindFunction) { return utils_1.getNamedNodeByNameOrFindFunction(this.getStaticMethods(), nameOrFindFunction); }; ClassDeclaration.prototype.getStaticMethodOrThrow = function (nameOrFindFunction) { return errors.throwIfNullOrUndefined(this.getStaticMethod(nameOrFindFunction), function () { return utils_1.getNotFoundErrorMessageForNameOrFindFunction("class static method", nameOrFindFunction); }); }; /** * Gets the class instance method declarations. */ ClassDeclaration.prototype.getStaticMethods = function () { return this.getStaticMembers().filter(function (m) { return m instanceof MethodDeclaration_1.MethodDeclaration; }); }; ClassDeclaration.prototype.getInstanceMember = function (nameOrFindFunction) { return utils_1.getNamedNodeByNameOrFindFunction(this.getInstanceMembers(), nameOrFindFunction); }; ClassDeclaration.prototype.getInstanceMemberOrThrow = function (nameOrFindFunction) { return errors.throwIfNullOrUndefined(this.getInstanceMember(nameOrFindFunction), function () { return utils_1.getNotFoundErrorMessageForNameOrFindFunction("class instance member", nameOrFindFunction); }); }; /** * Gets the instance members. */ ClassDeclaration.prototype.getInstanceMembers = function () { return this.getAllMembers().filter(function (m) { return !utils_1.TypeGuards.isConstructorDeclaration(m) && (utils_1.TypeGuards.isParameterDeclaration(m) || !m.isStatic()); }); }; ClassDeclaration.prototype.getStaticMember = function (nameOrFindFunction) { return utils_1.getNamedNodeByNameOrFindFunction(this.getStaticMembers(), nameOrFindFunction); }; ClassDeclaration.prototype.getStaticMemberOrThrow = function (nameOrFindFunction) { return errors.throwIfNullOrUndefined(this.getStaticMember(nameOrFindFunction), function () { return utils_1.getNotFoundErrorMessageForNameOrFindFunction("class static member", nameOrFindFunction); }); }; /** * Gets the static members. */ ClassDeclaration.prototype.getStaticMembers = function () { return this.getAllMembers().filter(function (m) { return !utils_1.TypeGuards.isConstructorDeclaration(m) && !(m instanceof function_1.ParameterDeclaration) && m.isStatic(); }); }; /** * Gets the constructors, methods, properties, and class parameter properties. */ ClassDeclaration.prototype.getAllMembers = function () { var members = this.getBodyMembers(); var implementationCtors = members.filter(function (c) { return utils_1.TypeGuards.isConstructorDeclaration(c) && c.isImplementation(); }); try { for (var implementationCtors_1 = __values(implementationCtors), implementationCtors_1_1 = implementationCtors_1.next(); !implementationCtors_1_1.done; implementationCtors_1_1 = implementationCtors_1.next()) { var ctor = implementationCtors_1_1.value; // insert after the constructor var insertIndex = members.indexOf(ctor) + 1; try { for (var _a = __values(ctor.getParameters()), _b = _a.next(); !_b.done; _b = _a.next()) { var param = _b.value; if (param.isParameterProperty()) { members.splice(insertIndex, 0, param); insertIndex++; } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_b && !_b.done && (_c = _a.return)) _c.call(_a); } finally { if (e_2) throw e_2.error; } } } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (implementationCtors_1_1 && !implementationCtors_1_1.done && (_d = implementationCtors_1.return)) _d.call(implementationCtors_1); } finally { if (e_3) throw e_3.error; } } return members; var e_3, _d, e_2, _c; }; /** * Gets all the derived classes. */ ClassDeclaration.prototype.getDerivedClasses = function () { var classes = this.getImmediateDerivedClasses(); for (var i = 0; i < classes.length; i++) { var derivedClasses = classes[i].getImmediateDerivedClasses(); try { for (var derivedClasses_1 = __values(derivedClasses), derivedClasses_1_1 = derivedClasses_1.next(); !derivedClasses_1_1.done; derivedClasses_1_1 = derivedClasses_1.next()) { var derivedClass = derivedClasses_1_1.value; // don't allow circular references if (derivedClass !== this && classes.indexOf(derivedClass) === -1) classes.push(derivedClass); } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (derivedClasses_1_1 && !derivedClasses_1_1.done && (_a = derivedClasses_1.return)) _a.call(derivedClasses_1); } finally { if (e_4) throw e_4.error; } } } return classes; var e_4, _a; }; /** * Removes this class declaration. */ ClassDeclaration.prototype.remove = function () { manipulation_1.removeStatementedNodeChild(this); }; ClassDeclaration.prototype.getImmediateDerivedClasses = function () { var references = this.getNameNode().findReferences(); var classes = []; try { for (var references_1 = __values(references), references_1_1 = references_1.next(); !references_1_1.done; references_1_1 = references_1.next()) { var reference = references_1_1.value; try { for (var _a = __values(reference.getReferences()), _b = _a.next(); !_b.done; _b = _a.next()) { var ref = _b.value; if (ref.isDefinition()) continue; var node = ref.getNode(); var nodeParent = node.getParentIfKind(ts.SyntaxKind.ExpressionWithTypeArguments); if (nodeParent == null) continue; var heritageClause = nodeParent.getParentIfKind(ts.SyntaxKind.HeritageClause); if (heritageClause == null || heritageClause.getToken() !== ts.SyntaxKind.ExtendsKeyword) continue; classes.push(heritageClause.getFirstAncestorByKindOrThrow(ts.SyntaxKind.ClassDeclaration)); } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (_b && !_b.done && (_c = _a.return)) _c.call(_a); } finally { if (e_5) throw e_5.error; } } } } catch (e_6_1) { e_6 = { error: e_6_1 }; } finally { try { if (references_1_1 && !references_1_1.done && (_d = references_1.return)) _d.call(references_1); } finally { if (e_6) throw e_6.error; } } return classes; var e_6, _d, e_5, _c; }; ClassDeclaration.prototype.getBodyMembers = function () { var _this = this; var members = this.compilerNode.members.map(function (m) { return _this.global.compilerFactory.getNodeFromCompilerNode(m, _this.sourceFile); }); // filter out the method declarations or constructor declarations without a body if not ambient return this.isAmbient() ? members : members.filter(function (m) { if (!(utils_1.TypeGuards.isConstructorDeclaration(m) || utils_1.TypeGuards.isMethodDeclaration(m))) return true; if (utils_1.TypeGuards.isMethodDeclaration(m) && m.isAbstract()) return true; return m.isImplementation(); }); }; return ClassDeclaration; }(exports.ClassDeclarationBase)); exports.ClassDeclaration = ClassDeclaration; function isClassPropertyType(m) { return utils_1.TypeGuards.isPropertyDeclaration(m) || utils_1.TypeGuards.isSetAccessorDeclaration(m) || utils_1.TypeGuards.isGetAccessorDeclaration(m) || utils_1.TypeGuards.isParameterDeclaration(m); }