UNPKG

ts-simple-ast

Version:

TypeScript compiler wrapper for AST navigation and code generation.

338 lines (336 loc) 21.1 kB
"use strict"; 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