ts-simple-ast
Version:
TypeScript compiler wrapper for AST navigation and code generation.
338 lines (336 loc) • 21.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const ts = require("typescript");
const chai_1 = require("chai");
const compiler_1 = require("./../../../compiler");
const utils_1 = require("./../../../utils");
const testHelpers_1 = require("./../testHelpers");
describe("Node", () => {
describe("compilerNode", () => {
it("should get the underlying compiler node", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("enum MyEnum {}\n");
// just compare that the texts are the same
chai_1.expect(sourceFile.getFullText()).to.equal(sourceFile.compilerNode.getFullText());
});
it("should throw an error when using a removed node", () => {
const { firstChild } = testHelpers_1.getInfoFromText("enum MyEnum { member }\n");
const member = firstChild.getMembers()[0];
member.remove();
chai_1.expect(() => member.compilerNode).to.throw();
});
});
describe("getKind", () => {
it("should return the syntax kind", () => {
const { firstChild } = testHelpers_1.getInfoFromText("enum MyEnum {}");
chai_1.expect(firstChild.getKind()).to.equal(ts.SyntaxKind.EnumDeclaration);
});
});
describe("getKindName", () => {
it("should return the syntax kind name", () => {
const { firstChild } = testHelpers_1.getInfoFromText("enum MyEnum {}");
chai_1.expect(firstChild.getKindName()).to.equal("EnumDeclaration");
});
});
describe("containsRange", () => {
const { firstChild } = testHelpers_1.getInfoFromText("enum MyEnum {}");
it("should contain the range when equal to the pos and end", () => {
chai_1.expect(firstChild.containsRange(firstChild.getPos(), firstChild.getEnd())).to.be.true;
});
it("should contain the range when inside", () => {
chai_1.expect(firstChild.containsRange(firstChild.getPos() + 1, firstChild.getEnd() - 1)).to.be.true;
});
it("should not contain the range when the position is outside", () => {
chai_1.expect(firstChild.containsRange(firstChild.getPos() - 1, firstChild.getEnd())).to.be.false;
});
it("should not contain the range when the end is outside", () => {
chai_1.expect(firstChild.containsRange(firstChild.getPos(), firstChild.getEnd() + 1)).to.be.false;
});
});
describe("offsetPositions", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("enum MyEnum {}");
const allNodes = [sourceFile, ...sourceFile.getDescendants()];
// easiest to just compare the sum of the positions
const originalStartPosSum = allNodes.map(n => n.getPos()).reduce((a, b) => a + b, 0);
const originalEndPosSum = allNodes.map(n => n.getEnd()).reduce((a, b) => a + b, 0);
it("should offset all the positions", () => {
sourceFile.offsetPositions(5);
const adjustedStartPosSum = allNodes.map(n => n.getPos() - 5).reduce((a, b) => a + b, 0);
const adjustedEndPosSum = allNodes.map(n => n.getEnd() - 5).reduce((a, b) => a + b, 0);
chai_1.expect(adjustedStartPosSum).to.equal(originalStartPosSum);
chai_1.expect(adjustedEndPosSum).to.equal(originalEndPosSum);
});
});
describe("getFirstChildByKind", () => {
const { firstChild } = testHelpers_1.getInfoFromText("enum MyEnum {}");
it("should return the first node of the specified syntax kind", () => {
chai_1.expect(firstChild.getFirstChildByKind(ts.SyntaxKind.OpenBraceToken).getText()).to.equal("{");
});
it("should return null when the specified syntax kind doesn't exist", () => {
chai_1.expect(firstChild.getFirstChildByKind(ts.SyntaxKind.ClassDeclaration)).to.be.undefined;
});
});
describe("getChildAtPos", () => {
const { firstChild, sourceFile } = testHelpers_1.getInfoFromText("function myFunction() { const v = 5; }");
const syntaxList = sourceFile.getChildSyntaxList();
const variableStatement = firstChild.getVariableStatements()[0];
it("should return undefined when providing a value less than the node pos", () => {
chai_1.expect(syntaxList.getChildAtPos(sourceFile.getPos() - 1)).to.be.undefined;
});
it("should return undefined when providing a value equal to the end", () => {
chai_1.expect(syntaxList.getChildAtPos(sourceFile.getEnd())).to.be.undefined;
});
it("should return the child at the specified position", () => {
chai_1.expect(syntaxList.getChildAtPos(1).getKind()).to.equal(ts.SyntaxKind.FunctionDeclaration);
});
it("should return only a child and not a descendant", () => {
chai_1.expect(syntaxList.getChildAtPos(variableStatement.getPos()).getKind()).to.equal(ts.SyntaxKind.FunctionDeclaration);
});
});
describe("getDescendantAtPos", () => {
const { firstChild, sourceFile } = testHelpers_1.getInfoFromText("function myFunction() { const v = 5; }");
const variableStatement = firstChild.getVariableStatements()[0];
it("should return undefined when providing a value less than the pos", () => {
chai_1.expect(sourceFile.getDescendantAtPos(sourceFile.getPos() - 1)).to.be.undefined;
});
it("should return undefined when providing a value equal to the end", () => {
chai_1.expect(sourceFile.getDescendantAtPos(sourceFile.getEnd())).to.be.undefined;
});
it("should return the descendant at the specified position", () => {
chai_1.expect(sourceFile.getDescendantAtPos(1).getKind()).to.equal(ts.SyntaxKind.FunctionKeyword);
});
it("should return a very descendant descendant", () => {
chai_1.expect(sourceFile.getDescendantAtPos(variableStatement.getPos()).getKind()).to.equal(ts.SyntaxKind.ConstKeyword);
});
it("should return a the node at the specified pos when specifying a space", () => {
chai_1.expect(sourceFile.getDescendantAtPos(variableStatement.getPos() - 1).getKind()).to.equal(ts.SyntaxKind.FirstPunctuation);
});
});
describe("getIndentationText", () => {
it("should return a blank string when it's at the start of the file", () => {
const { firstChild } = testHelpers_1.getInfoFromText("enum MyEnum {\n}\n");
chai_1.expect(firstChild.getIndentationText()).to.equal("");
});
it("should return a blank string when it's at the start of a line", () => {
const { firstChild } = testHelpers_1.getInfoFromText("\r\n\nenum MyEnum {\n}\n");
chai_1.expect(firstChild.getIndentationText()).to.equal("");
});
it("should return the indentation text when it's spaces", () => {
const { firstChild } = testHelpers_1.getInfoFromText(" enum MyEnum {\n}\n");
chai_1.expect(firstChild.getIndentationText()).to.equal(" ");
});
it("should return the indentation text when it includes tabs", () => {
const { firstChild } = testHelpers_1.getInfoFromText("\n \tenum MyEnum {\n}\n");
chai_1.expect(firstChild.getIndentationText()).to.equal(" \t");
});
it("should go up to the comment", () => {
const { firstChild } = testHelpers_1.getInfoFromText("\n /* comment */ \tenum MyEnum {\n}\n");
chai_1.expect(firstChild.getIndentationText()).to.equal(" ");
});
});
describe("getStartLinePos", () => {
it("should return the start of the file when it's on the first line", () => {
const { firstChild } = testHelpers_1.getInfoFromText("enum MyEnum {\n}\n");
chai_1.expect(firstChild.getStartLinePos()).to.equal(0);
});
it("should return the start of the file when it's on the first line", () => {
const { firstChild } = testHelpers_1.getInfoFromText(" enum MyEnum {\n}\n");
chai_1.expect(firstChild.getStartLinePos()).to.equal(0);
});
it("should return the start of the line when it's not on the first line", () => {
const { firstChild } = testHelpers_1.getInfoFromText("enum MyEnum {\n myMember = 1\n}\n");
const memberDeclaration = firstChild.getMembers()[0];
chai_1.expect(memberDeclaration.getStartLinePos()).to.equal(14);
});
it("should return the start of the line when the past line is a \\r\\n", () => {
const { firstChild } = testHelpers_1.getInfoFromText("\n \t \r\nenum MyEnum {\n}\n");
chai_1.expect(firstChild.getStartLinePos()).to.equal(8);
});
});
describe("getStart", () => {
it("should return the pos without trivia", () => {
const { firstChild } = testHelpers_1.getInfoFromText("\n \t /* comment */ //comment \r\n \t enum MyEnum {\n}\n");
chai_1.expect(firstChild.getStart()).to.equal(37);
});
});
describe("getCombinedModifierFlags", () => {
const { firstChild } = testHelpers_1.getInfoFromText("export class Identifier {}");
it("should get the combined modifier flags", () => {
chai_1.expect(firstChild.getCombinedModifierFlags()).to.equal(ts.ModifierFlags.Export);
});
});
describe("getParentIfKind", () => {
const { firstChild } = testHelpers_1.getInfoFromText("export class Identifier { prop: string; }");
const child = firstChild.getInstanceProperty("prop");
it("should get the parent when it's the right kind", () => {
chai_1.expect(child.getParentIfKind(ts.SyntaxKind.ClassDeclaration)).to.not.be.undefined;
});
it("should not get the parent when it's not the right kind", () => {
chai_1.expect(child.getParentIfKind(ts.SyntaxKind.InterfaceDeclaration)).to.be.undefined;
});
});
describe("getParentIfKindOrThrow", () => {
const { firstChild } = testHelpers_1.getInfoFromText("export class Identifier { prop: string; }");
const child = firstChild.getInstanceProperty("prop");
it("should get the parent when it's the right kind", () => {
chai_1.expect(child.getParentIfKindOrThrow(ts.SyntaxKind.ClassDeclaration)).to.not.be.undefined;
});
it("should throw when it's not the right kind", () => {
chai_1.expect(() => child.getParentIfKindOrThrow(ts.SyntaxKind.InterfaceDeclaration)).to.throw();
});
});
describe("getFirstChildOrThrow", () => {
const { sourceFile, firstChild } = testHelpers_1.getInfoFromText("class Identifier { prop: string; }\ninterface MyInterface {}");
const syntaxList = sourceFile.getChildSyntaxListOrThrow();
it("should get the first child by a condition", () => {
chai_1.expect(syntaxList.getFirstChildOrThrow(n => n.getKind() === ts.SyntaxKind.InterfaceDeclaration)).to.be.instanceOf(compiler_1.InterfaceDeclaration);
});
it("should throw when it can't find the child", () => {
chai_1.expect(() => syntaxList.getFirstChildOrThrow(n => n.getKind() === ts.SyntaxKind.IsKeyword)).to.throw();
});
});
describe("getLastChildOrThrow", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("interface Identifier { prop: string; }\ninterface MyInterface {}");
const syntaxList = sourceFile.getChildSyntaxListOrThrow();
it("should get the last child by a condition", () => {
const interfaceDec = syntaxList.getLastChildOrThrow(n => n.getKind() === ts.SyntaxKind.InterfaceDeclaration);
chai_1.expect(interfaceDec.getName()).to.equal("MyInterface");
});
it("should throw when it can't find the child", () => {
chai_1.expect(() => syntaxList.getLastChildOrThrow(n => n.getKind() === ts.SyntaxKind.IsKeyword)).to.throw();
});
});
describe("getFirstDescendant", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("interface Identifier { prop: string; }\ninterface MyInterface { nextProp: string; }");
it("should get the first descendant by a condition", () => {
const prop = sourceFile.getFirstDescendant(n => n.getKind() === ts.SyntaxKind.PropertySignature);
chai_1.expect(prop).to.be.instanceOf(compiler_1.PropertySignature);
chai_1.expect(prop.getName()).to.equal("prop");
});
it("should return undefined when it can't find it", () => {
const privateKeyword = sourceFile.getFirstDescendant(n => n.getKind() === ts.SyntaxKind.PrivateKeyword);
chai_1.expect(privateKeyword).to.be.undefined;
});
});
describe("getFirstDescendantOrThrow", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("interface Identifier { prop: string; }\ninterface MyInterface { nextProp: string; }");
it("should get the first descendant by a condition", () => {
const prop = sourceFile.getFirstDescendantOrThrow(n => n.getKind() === ts.SyntaxKind.PropertySignature);
chai_1.expect(prop).to.be.instanceOf(compiler_1.PropertySignature);
chai_1.expect(prop.getName()).to.equal("prop");
});
it("should return undefined when it can't find it", () => {
chai_1.expect(() => sourceFile.getFirstDescendantOrThrow(n => n.getKind() === ts.SyntaxKind.PrivateKeyword)).to.throw();
});
});
describe("getDescendantsOfKind", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("interface Identifier { prop: string; }\ninterface MyInterface { nextProp: string; }");
it("should get the descendant by a kind", () => {
const properties = sourceFile.getDescendantsOfKind(ts.SyntaxKind.PropertySignature);
chai_1.expect(properties.length).to.equal(2);
chai_1.expect(properties[0]).to.be.instanceOf(compiler_1.PropertySignature);
chai_1.expect(properties[1]).to.be.instanceOf(compiler_1.PropertySignature);
});
});
describe("getFirstDescendantByKind", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("interface Identifier { prop: string; }\ninterface MyInterface { nextProp: string; }");
it("should get the first descendant by a condition", () => {
const prop = sourceFile.getFirstDescendantByKind(ts.SyntaxKind.PropertySignature);
chai_1.expect(prop).to.be.instanceOf(compiler_1.PropertySignature);
chai_1.expect(prop.getName()).to.equal("prop");
});
it("should return undefined when it can't find it", () => {
const privateKeyword = sourceFile.getFirstDescendantByKind(ts.SyntaxKind.PrivateKeyword);
chai_1.expect(privateKeyword).to.be.undefined;
});
});
describe("getFirstDescendantByKindOrThrow", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("interface Identifier { prop: string; }\ninterface MyInterface { nextProp: string; }");
it("should get the first descendant by a condition", () => {
const prop = sourceFile.getFirstDescendantByKindOrThrow(ts.SyntaxKind.PropertySignature);
chai_1.expect(prop).to.be.instanceOf(compiler_1.PropertySignature);
chai_1.expect(prop.getName()).to.equal("prop");
});
it("should return undefined when it can't find it", () => {
chai_1.expect(() => sourceFile.getFirstDescendantByKindOrThrow(ts.SyntaxKind.PrivateKeyword)).to.throw();
});
});
describe("getPreviousSibling", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("interface Interface1 {}\ninterface Interface2 {}\ninterface Interface3 {}");
it("should get the previous sibling based on a condition", () => {
chai_1.expect(sourceFile.getInterfaces()[2].getPreviousSibling(s => utils_1.TypeGuards.isInterfaceDeclaration(s) && s.getName() === "Interface1").getText())
.to.equal("interface Interface1 {}");
});
it("should get the previous sibling when not supplying a condition", () => {
chai_1.expect(sourceFile.getInterfaces()[2].getPreviousSibling().getText()).to.equal("interface Interface2 {}");
});
it("should return undefined when it can't find the sibling based on a condition", () => {
chai_1.expect(sourceFile.getInterfaces()[2].getPreviousSibling(s => false)).to.be.undefined;
});
it("should return undefined when there isn't a previous sibling", () => {
chai_1.expect(sourceFile.getInterfaces()[0].getPreviousSibling()).to.be.undefined;
});
});
describe("getPreviousSiblingOrThrow", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("interface Interface1 {}\ninterface Interface2 {}\ninterface Interface3 {}");
it("should get the previous sibling based on a condition", () => {
chai_1.expect(sourceFile.getInterfaces()[2].getPreviousSiblingOrThrow(s => utils_1.TypeGuards.isInterfaceDeclaration(s) && s.getName() === "Interface1").getText())
.to.equal("interface Interface1 {}");
});
it("should get the previous sibling when not supplying a condition", () => {
chai_1.expect(sourceFile.getInterfaces()[2].getPreviousSiblingOrThrow().getText()).to.equal("interface Interface2 {}");
});
it("should throw when it can't find the sibling based on a condition", () => {
chai_1.expect(() => sourceFile.getInterfaces()[2].getPreviousSiblingOrThrow(s => false)).to.throw();
});
it("should throw when there isn't a previous sibling", () => {
chai_1.expect(() => sourceFile.getInterfaces()[0].getPreviousSiblingOrThrow()).to.throw();
});
});
describe("getNextSibling", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("interface Interface1 {}\ninterface Interface2 {}\ninterface Interface3 {}");
it("should get the next sibling based on a condition", () => {
chai_1.expect(sourceFile.getInterfaces()[0].getNextSibling(s => utils_1.TypeGuards.isInterfaceDeclaration(s) && s.getName() === "Interface3").getText())
.to.equal("interface Interface3 {}");
});
it("should get the next sibling when not supplying a condition", () => {
chai_1.expect(sourceFile.getInterfaces()[0].getNextSibling().getText()).to.equal("interface Interface2 {}");
});
it("should return undefined when it can't find the sibling based on a condition", () => {
chai_1.expect(sourceFile.getInterfaces()[0].getNextSibling(s => false)).to.be.undefined;
});
it("should return undefined when there isn't a next sibling", () => {
chai_1.expect(sourceFile.getInterfaces()[2].getNextSibling()).to.be.undefined;
});
});
describe("getNextSiblingOrThrow", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("interface Interface1 {}\ninterface Interface2 {}\ninterface Interface3 {}");
it("should get the next sibling based on a condition", () => {
chai_1.expect(sourceFile.getInterfaces()[0].getNextSiblingOrThrow(s => utils_1.TypeGuards.isInterfaceDeclaration(s) && s.getName() === "Interface3").getText())
.to.equal("interface Interface3 {}");
});
it("should get the next sibling when not supplying a condition", () => {
chai_1.expect(sourceFile.getInterfaces()[0].getNextSiblingOrThrow().getText()).to.equal("interface Interface2 {}");
});
it("should throw when it can't find the sibling based on a condition", () => {
chai_1.expect(() => sourceFile.getInterfaces()[0].getNextSiblingOrThrow(s => false)).to.throw();
});
it("should throw when there isn't a next sibling", () => {
chai_1.expect(() => sourceFile.getInterfaces()[2].getNextSiblingOrThrow()).to.throw();
});
});
describe("getPreviousSiblings", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("interface Interface1 {}\ninterface Interface2 {}\ninterface Interface3 {}");
it("should get the previous siblings going away in order", () => {
chai_1.expect(sourceFile.getInterfaces()[2].getPreviousSiblings().map(s => s.getName()))
.to.deep.equal(["Interface2", "Interface1"]);
});
});
describe("getNextSiblings", () => {
const { sourceFile } = testHelpers_1.getInfoFromText("interface Interface1 {}\ninterface Interface2 {}\ninterface Interface3 {}");
it("should get the previous siblings going away in order", () => {
chai_1.expect(sourceFile.getInterfaces()[0].getNextSiblings().map(s => s.getName()))
.to.deep.equal(["Interface2", "Interface3"]);
});
});
});
//# sourceMappingURL=nodeTests.js.map