ts-simple-ast
Version:
TypeScript compiler wrapper for AST navigation and code generation.
593 lines (592 loc) • 28 kB
JavaScript
"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);
}