NodeUtils.spec.ts 14 KB

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