NodeUtils.spec.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. import * as chai from 'chai';
  2. import { IBlockStatementNode } from "../../src/interfaces/nodes/IBlockStatementNode";
  3. import { IExpressionStatementNode } from "../../src/interfaces/nodes/IExpressionStatementNode";
  4. import { IFunctionDeclarationNode } from "../../src/interfaces/nodes/IFunctionDeclarationNode";
  5. import { IIdentifierNode } from "../../src/interfaces/nodes/IIdentifierNode";
  6. import { IIfStatementNode } from "../../src/interfaces/nodes/IIfStatementNode";
  7. import { ILiteralNode } from "../../src/interfaces/nodes/ILiteralNode";
  8. import { INode } from "../../src/interfaces/nodes/INode";
  9. import { IProgramNode } from "../../src/interfaces/nodes/IProgramNode";
  10. import { IVariableDeclarationNode } from "../../src/interfaces/nodes/IVariableDeclarationNode";
  11. import { IVariableDeclaratorNode } from "../../src/interfaces/nodes/IVariableDeclaratorNode";
  12. import { NodeMocks } from '../mocks/NodeMocks';
  13. import { NodeUtils } from '../../src/NodeUtils';
  14. const assert: any = chai.assert;
  15. describe('NodeUtils', () => {
  16. describe('addXVerbatimPropertyToLiterals (node: INode): void', () => {
  17. let literalNode: any,
  18. expectedLiteralNode: any;
  19. beforeEach(() => {
  20. literalNode = NodeMocks.getLiteralNode();
  21. delete literalNode['x-verbatim-property'];
  22. expectedLiteralNode = NodeMocks.getLiteralNode();
  23. NodeUtils.addXVerbatimPropertyToLiterals(literalNode);
  24. });
  25. it('should add `x-verbatim-property` to `Literal` node', () => {
  26. assert.deepEqual(literalNode, expectedLiteralNode);
  27. });
  28. });
  29. describe('appendNode (blockScopeBody: INode[], node: INode): void', () => {
  30. let blockStatementNode: IBlockStatementNode,
  31. expectedBlockStatementNode: IBlockStatementNode,
  32. expressionStatementNode: IExpressionStatementNode;
  33. beforeEach(() => {
  34. expressionStatementNode = NodeMocks.getExpressionStatementNode();
  35. blockStatementNode = NodeMocks.getBlockStatementNode();
  36. expectedBlockStatementNode = NodeMocks.getBlockStatementNode([
  37. expressionStatementNode
  38. ]);
  39. NodeUtils.appendNode(blockStatementNode.body, expressionStatementNode);
  40. });
  41. it('should append given node to a `BlockStatement` node body', () => {
  42. assert.deepEqual(blockStatementNode, expectedBlockStatementNode);
  43. });
  44. it('should does not change `BlockStatement` node body if given node is not a valid Node', () => {
  45. assert.doesNotChange(
  46. () => NodeUtils.appendNode(blockStatementNode.body, <INode>{}),
  47. blockStatementNode,
  48. 'body'
  49. );
  50. });
  51. });
  52. describe('convertCodeToStructure (code: string): INode', () => {
  53. let code: string,
  54. identifierNode: IIdentifierNode,
  55. literalNode: ILiteralNode,
  56. programNode: IProgramNode,
  57. variableDeclarationNode: IVariableDeclarationNode,
  58. variableDeclaratorNode: IVariableDeclaratorNode;
  59. beforeEach(() => {
  60. code = `
  61. var abc = 'cde';
  62. `;
  63. identifierNode = NodeMocks.getIdentifierNode('abc');
  64. literalNode = NodeMocks.getLiteralNode('cde');
  65. variableDeclaratorNode = NodeMocks.getVariableDeclaratorNode(identifierNode, literalNode);
  66. variableDeclarationNode = NodeMocks.getVariableDeclarationNode([
  67. variableDeclaratorNode
  68. ]);
  69. programNode = NodeMocks.getProgramNode([
  70. variableDeclarationNode
  71. ]);
  72. programNode['parentNode'] = programNode;
  73. variableDeclarationNode['parentNode'] = programNode;
  74. variableDeclaratorNode['parentNode'] = variableDeclarationNode;
  75. identifierNode['parentNode'] = variableDeclaratorNode;
  76. literalNode['parentNode'] = variableDeclaratorNode;
  77. });
  78. it('should convert code to `INode` structure', () => {
  79. assert.deepEqual(NodeUtils.convertCodeToStructure(code), variableDeclarationNode);
  80. });
  81. });
  82. describe('getBlockStatementNodeByIndex (node: INode, index: number = 0): INode', () => {
  83. let blockStatementNode: IBlockStatementNode,
  84. expressionStatementNode1: IExpressionStatementNode,
  85. expressionStatementNode2: IExpressionStatementNode;
  86. beforeEach(() => {
  87. expressionStatementNode1 = NodeMocks.getExpressionStatementNode();
  88. expressionStatementNode2 = NodeMocks.getExpressionStatementNode();
  89. blockStatementNode = NodeMocks.getBlockStatementNode([
  90. expressionStatementNode1,
  91. expressionStatementNode2
  92. ]);
  93. });
  94. it('should return block-statement child node of given node if that node has block-statement', () => {
  95. assert.deepEqual(NodeUtils.getBlockStatementNodeByIndex(blockStatementNode), expressionStatementNode1);
  96. assert.deepEqual(NodeUtils.getBlockStatementNodeByIndex(blockStatementNode, 1), expressionStatementNode2);
  97. });
  98. it('should throw a `ReferenceError` if index is out of boundaries', () => {
  99. assert.throws(() => NodeUtils.getBlockStatementNodeByIndex(blockStatementNode, 2), ReferenceError);
  100. });
  101. it('should throw a `TypeError` if node have no a block-statement', () => {
  102. assert.throws(() => NodeUtils.getBlockStatementNodeByIndex(expressionStatementNode1, 1), TypeError);
  103. });
  104. });
  105. describe('getBlockScopeOfNode (node: INode, depth: number = 0): TNodeWithBlockStatement', () => {
  106. let functionDeclarationBlockStatementNode: IBlockStatementNode,
  107. ifStatementBlockStatementNode1: IBlockStatementNode,
  108. ifStatementBlockStatementNode2: IBlockStatementNode,
  109. ifStatementNode1: IIfStatementNode,
  110. ifStatementNode2: IIfStatementNode,
  111. expressionStatementNode1: IExpressionStatementNode,
  112. expressionStatementNode2: IExpressionStatementNode,
  113. expressionStatementNode3: IExpressionStatementNode,
  114. functionDeclarationNode: IFunctionDeclarationNode,
  115. programNode: IProgramNode;
  116. beforeEach(() => {
  117. expressionStatementNode1 = NodeMocks.getExpressionStatementNode();
  118. expressionStatementNode2 = NodeMocks.getExpressionStatementNode();
  119. expressionStatementNode3 = NodeMocks.getExpressionStatementNode();
  120. ifStatementBlockStatementNode2 = NodeMocks.getBlockStatementNode([
  121. expressionStatementNode1,
  122. expressionStatementNode2
  123. ]);
  124. ifStatementNode2 = NodeMocks.getIfStatementNode(ifStatementBlockStatementNode2);
  125. ifStatementBlockStatementNode1 = NodeMocks.getBlockStatementNode([
  126. ifStatementNode2
  127. ]);
  128. ifStatementNode1 = NodeMocks.getIfStatementNode(ifStatementBlockStatementNode1);
  129. functionDeclarationBlockStatementNode = NodeMocks.getBlockStatementNode([
  130. expressionStatementNode3,
  131. ifStatementNode1
  132. ]);
  133. functionDeclarationNode = NodeMocks.getFunctionDeclarationNode('test', functionDeclarationBlockStatementNode);
  134. programNode = NodeMocks.getProgramNode([
  135. functionDeclarationNode
  136. ]);
  137. programNode['parentNode'] = programNode;
  138. functionDeclarationNode['parentNode'] = programNode;
  139. functionDeclarationBlockStatementNode['parentNode'] = functionDeclarationNode;
  140. expressionStatementNode3['parentNode'] = functionDeclarationBlockStatementNode;
  141. ifStatementNode1['parentNode'] = functionDeclarationBlockStatementNode;
  142. ifStatementBlockStatementNode1['parentNode'] = ifStatementNode1;
  143. ifStatementNode2['parentNode'] = ifStatementBlockStatementNode1;
  144. ifStatementBlockStatementNode2['parentNode'] = ifStatementNode2;
  145. expressionStatementNode1['parentNode'] = ifStatementBlockStatementNode2;
  146. });
  147. it('should return block-scope node for given node', () => {
  148. assert.deepEqual(NodeUtils.getBlockScopeOfNode(expressionStatementNode3), functionDeclarationBlockStatementNode);
  149. assert.deepEqual(NodeUtils.getBlockScopeOfNode(expressionStatementNode3, 1), programNode);
  150. assert.deepEqual(NodeUtils.getBlockScopeOfNode(functionDeclarationNode), programNode);
  151. assert.deepEqual(NodeUtils.getBlockScopeOfNode(functionDeclarationBlockStatementNode), programNode);
  152. assert.deepEqual(NodeUtils.getBlockScopeOfNode(programNode), programNode);
  153. assert.deepEqual(NodeUtils.getBlockScopeOfNode(expressionStatementNode1), functionDeclarationBlockStatementNode);
  154. });
  155. it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
  156. assert.throws(() => NodeUtils.getBlockScopeOfNode(expressionStatementNode2), ReferenceError);
  157. });
  158. });
  159. describe('insertNodeAtIndex (blockScopeBody: INode[], node: INode, index: number): void', () => {
  160. let blockStatementNode: IBlockStatementNode,
  161. expectedBlockStatementNode: IBlockStatementNode,
  162. expressionStatementNode1: IExpressionStatementNode,
  163. expressionStatementNode2: IExpressionStatementNode;
  164. beforeEach(() => {
  165. expressionStatementNode1 = NodeMocks.getExpressionStatementNode();
  166. expressionStatementNode2 = NodeMocks.getExpressionStatementNode();
  167. blockStatementNode = NodeMocks.getBlockStatementNode([
  168. expressionStatementNode1
  169. ]);
  170. expectedBlockStatementNode = NodeMocks.getBlockStatementNode([
  171. expressionStatementNode1,
  172. expressionStatementNode1
  173. ]);
  174. NodeUtils.insertNodeAtIndex(blockStatementNode.body, expressionStatementNode2, 1);
  175. });
  176. it('should insert given node in `BlockStatement` node body at index', () => {
  177. assert.deepEqual(blockStatementNode, expectedBlockStatementNode);
  178. });
  179. it('should does not change `BlockStatement` node body if given node is not a valid Node', () => {
  180. assert.doesNotChange(
  181. () => NodeUtils.insertNodeAtIndex(blockStatementNode.body, <INode>{}, 1),
  182. blockStatementNode,
  183. 'body'
  184. );
  185. });
  186. });
  187. describe('parentize (node: INode): void', () => {
  188. let ifStatementNode: IIfStatementNode,
  189. ifStatementBlockStatementNode: IBlockStatementNode,
  190. expressionStatementNode1: IExpressionStatementNode,
  191. expressionStatementNode2: IExpressionStatementNode,
  192. programNode: IProgramNode;
  193. beforeEach(() => {
  194. expressionStatementNode1 = NodeMocks.getExpressionStatementNode();
  195. expressionStatementNode2 = NodeMocks.getExpressionStatementNode();
  196. ifStatementBlockStatementNode = NodeMocks.getBlockStatementNode([
  197. expressionStatementNode1,
  198. expressionStatementNode2
  199. ]);
  200. ifStatementNode = NodeMocks.getIfStatementNode(ifStatementBlockStatementNode);
  201. });
  202. it('should parentize given AST-tree with `ProgramNode` as root node', () => {
  203. programNode = NodeMocks.getProgramNode([
  204. ifStatementNode
  205. ]);
  206. NodeUtils.parentize(programNode);
  207. assert.deepEqual(programNode['parentNode'], programNode);
  208. assert.deepEqual(ifStatementNode['parentNode'], programNode);
  209. assert.deepEqual(ifStatementBlockStatementNode['parentNode'], ifStatementNode);
  210. assert.deepEqual(expressionStatementNode1['parentNode'], ifStatementBlockStatementNode);
  211. assert.deepEqual(expressionStatementNode2['parentNode'], ifStatementBlockStatementNode);
  212. });
  213. it('should parentize given AST-tree', () => {
  214. programNode = NodeMocks.getProgramNode([
  215. ifStatementNode
  216. ]);
  217. programNode['parentNode'] = programNode;
  218. NodeUtils.parentize(ifStatementNode);
  219. assert.deepEqual(ifStatementNode['parentNode'], programNode);
  220. assert.deepEqual(ifStatementBlockStatementNode['parentNode'], ifStatementNode);
  221. assert.deepEqual(expressionStatementNode1['parentNode'], ifStatementBlockStatementNode);
  222. assert.deepEqual(expressionStatementNode2['parentNode'], ifStatementBlockStatementNode);
  223. });
  224. });
  225. describe('prependNode (blockScopeBody: INode[], node: INode): void', () => {
  226. let blockStatementNode: IBlockStatementNode,
  227. expectedBlockStatementNode: IBlockStatementNode,
  228. expressionStatementNode1: IExpressionStatementNode,
  229. expressionStatementNode2: IExpressionStatementNode;
  230. beforeEach(() => {
  231. expressionStatementNode1 = NodeMocks.getExpressionStatementNode();
  232. expressionStatementNode2 = NodeMocks.getExpressionStatementNode();
  233. blockStatementNode = NodeMocks.getBlockStatementNode([
  234. expressionStatementNode1
  235. ]);
  236. expectedBlockStatementNode = NodeMocks.getBlockStatementNode([
  237. expressionStatementNode2,
  238. expressionStatementNode1
  239. ]);
  240. NodeUtils.prependNode(blockStatementNode.body, expressionStatementNode2);
  241. });
  242. it('should prepend given node to a `BlockStatement` node body', () => {
  243. assert.deepEqual(blockStatementNode, expectedBlockStatementNode);
  244. });
  245. it('should does not change `BlockStatement` node body if given node is not a valid Node', () => {
  246. assert.doesNotChange(
  247. () => NodeUtils.prependNode(blockStatementNode.body, <INode>{}),
  248. blockStatementNode,
  249. 'body'
  250. );
  251. });
  252. });
  253. });