NodeAppender.spec.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. import 'reflect-metadata';
  2. import { ServiceIdentifiers } from '../../../../src/container/ServiceIdentifiers';
  3. import * as ESTree from 'estree';
  4. import { assert } from 'chai';
  5. import { TStatement } from '../../../../src/types/node/TStatement';
  6. import { IInversifyContainerFacade } from '../../../../src/interfaces/container/IInversifyContainerFacade';
  7. import { ICallsGraphAnalyzer } from '../../../../src/interfaces/analyzers/calls-graph-analyzer/ICallsGraphAnalyzer';
  8. import { ICallsGraphData } from '../../../../src/interfaces/analyzers/calls-graph-analyzer/ICallsGraphData';
  9. import { readFileAsString } from '../../../helpers/readFileAsString';
  10. import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
  11. import { NodeAppender } from '../../../../src/node/NodeAppender';
  12. import { NodeFactory } from '../../../../src/node/NodeFactory';
  13. import { NodeUtils } from '../../../../src/node/NodeUtils';
  14. import { removeRangesFromStructure } from '../../../helpers/removeRangesFromStructure';
  15. /**
  16. * @param fixturePath
  17. * @return {TStatement[]}
  18. */
  19. const convertCodeToStructure: (fixturePath: string) => TStatement[] = (fixturePath) => {
  20. return removeRangesFromStructure(
  21. NodeUtils.convertCodeToStructure(
  22. readFileAsString(`${__dirname}${fixturePath}`)
  23. )
  24. );
  25. };
  26. /**
  27. * @param fixturePath
  28. * @return {ESTree.Program}
  29. */
  30. const convertCodeToAst: (fixturePath: string) => ESTree.Program = (fixturePath) => {
  31. return NodeFactory.programNode(convertCodeToStructure(fixturePath));
  32. };
  33. describe('NodeAppender', () => {
  34. describe('append', () => {
  35. let astTree: ESTree.Program,
  36. expectedAstTree: ESTree.Program,
  37. node: TStatement[];
  38. before(() => {
  39. node = convertCodeToStructure('/fixtures/simple-input.js');
  40. astTree = convertCodeToAst('/fixtures/append-node.js');
  41. expectedAstTree = convertCodeToAst('/fixtures/append-node-expected.js');
  42. astTree = NodeUtils.parentizeAst(astTree);
  43. expectedAstTree = NodeUtils.parentizeAst(expectedAstTree);
  44. NodeAppender.append(astTree, node);
  45. });
  46. it('should append given node to a `BlockStatement` node body', () => {
  47. assert.deepEqual(astTree, expectedAstTree);
  48. });
  49. });
  50. describe('appendToOptimalBlockScope', () => {
  51. let callsGraphAnalyzer: ICallsGraphAnalyzer,
  52. astTree: ESTree.Program,
  53. expectedAstTree: ESTree.Program,
  54. node: TStatement[],
  55. callsGraphData: ICallsGraphData[];
  56. before(() => {
  57. const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
  58. inversifyContainerFacade.load('', '', {});
  59. callsGraphAnalyzer = inversifyContainerFacade
  60. .get<ICallsGraphAnalyzer>(ServiceIdentifiers.ICallsGraphAnalyzer);
  61. });
  62. beforeEach(() => {
  63. node = convertCodeToStructure('/fixtures/simple-input.js');
  64. });
  65. describe('Variant #1: nested function calls', () => {
  66. beforeEach(() => {
  67. astTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/variant-1.js');
  68. expectedAstTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/variant-1-expected.js');
  69. callsGraphData = callsGraphAnalyzer.analyze(astTree);
  70. NodeAppender.appendToOptimalBlockScope(callsGraphData, astTree, node);
  71. });
  72. it('should append node into first and deepest function call in nested function calls', () => {
  73. assert.deepEqual(astTree, expectedAstTree);
  74. });
  75. });
  76. describe('Variant #2: nested function calls', () => {
  77. beforeEach(() => {
  78. astTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/variant-2.js');
  79. expectedAstTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/variant-2-expected.js');
  80. callsGraphData = callsGraphAnalyzer.analyze(astTree);
  81. NodeAppender.appendToOptimalBlockScope(callsGraphData, astTree, node);
  82. });
  83. it('should append node into first and deepest function call in nested function calls', () => {
  84. assert.deepEqual(astTree, expectedAstTree);
  85. });
  86. });
  87. describe('append by specific index', () => {
  88. let astTree: ESTree.Program;
  89. beforeEach(() => {
  90. astTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/by-index.js');
  91. });
  92. describe('Variant #1: append by specific index in nested function calls', () => {
  93. beforeEach(() => {
  94. expectedAstTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/by-index-variant-1-expected.js');
  95. callsGraphData = callsGraphAnalyzer.analyze(astTree);
  96. NodeAppender.appendToOptimalBlockScope(callsGraphData, astTree, node, 2);
  97. });
  98. it('should append node into deepest function call by specified index in nested function calls', () => {
  99. assert.deepEqual(astTree, expectedAstTree);
  100. });
  101. });
  102. describe('Variant #2: append by specific index in nested function calls', () => {
  103. beforeEach(() => {
  104. expectedAstTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/by-index-variant-2-expected.js');
  105. callsGraphData = callsGraphAnalyzer.analyze(astTree);
  106. NodeAppender.appendToOptimalBlockScope(callsGraphData, astTree, node, 1);
  107. });
  108. it('should append node into deepest function call by specified index in nested function calls', () => {
  109. assert.deepEqual(astTree, expectedAstTree);
  110. });
  111. });
  112. describe('Variant #3: append by specific index in nested function calls', () => {
  113. beforeEach(() => {
  114. astTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/by-index-variant-3.js');
  115. expectedAstTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/by-index-variant-3-expected.js');
  116. callsGraphData = callsGraphAnalyzer.analyze(astTree);
  117. NodeAppender.appendToOptimalBlockScope(
  118. callsGraphData,
  119. astTree,
  120. node,
  121. callsGraphData.length - 1
  122. );
  123. });
  124. it('should append node into deepest function call by specified index in nested function calls', () => {
  125. assert.deepEqual(astTree, expectedAstTree);
  126. });
  127. });
  128. });
  129. });
  130. describe('insertBefore', () => {
  131. let astTree: ESTree.Program,
  132. expectedAstTree: ESTree.Program,
  133. node: TStatement[],
  134. targetStatement: ESTree.Statement;
  135. before(() => {
  136. node = convertCodeToStructure('/fixtures/simple-input.js');
  137. astTree = convertCodeToAst('/fixtures/insert-node-before.js');
  138. expectedAstTree = convertCodeToAst('/fixtures/insert-node-before-expected.js');
  139. targetStatement = <ESTree.Statement>astTree.body[1];
  140. astTree = NodeUtils.parentizeAst(astTree);
  141. expectedAstTree = NodeUtils.parentizeAst(expectedAstTree);
  142. NodeAppender.insertBefore(astTree, node, targetStatement);
  143. });
  144. it('should insert given node in `BlockStatement` node body before target statement', () => {
  145. assert.deepEqual(astTree, expectedAstTree);
  146. });
  147. });
  148. describe('insertAfter', () => {
  149. let astTree: ESTree.Program,
  150. expectedAstTree: ESTree.Program,
  151. node: TStatement[],
  152. targetStatement: ESTree.Statement;
  153. before(() => {
  154. node = convertCodeToStructure('/fixtures/simple-input.js');
  155. astTree = convertCodeToAst('/fixtures/insert-node-after.js');
  156. expectedAstTree = convertCodeToAst('/fixtures/insert-node-after-expected.js');
  157. targetStatement = <ESTree.Statement>astTree.body[1];
  158. astTree = NodeUtils.parentizeAst(astTree);
  159. expectedAstTree = NodeUtils.parentizeAst(expectedAstTree);
  160. NodeAppender.insertAfter(astTree, node, targetStatement);
  161. });
  162. it('should insert given node in `BlockStatement` node body after target statement', () => {
  163. assert.deepEqual(astTree, expectedAstTree);
  164. });
  165. });
  166. describe('insertAtIndex', () => {
  167. let astTree: ESTree.Program,
  168. expectedAstTree: ESTree.Program,
  169. node: TStatement[];
  170. before(() => {
  171. node = convertCodeToStructure('/fixtures/simple-input.js');
  172. astTree = convertCodeToAst('/fixtures/insert-node-at-index.js');
  173. expectedAstTree = convertCodeToAst('/fixtures/insert-node-at-index-expected.js');
  174. astTree = NodeUtils.parentizeAst(astTree);
  175. expectedAstTree = NodeUtils.parentizeAst(expectedAstTree);
  176. NodeAppender.insertAtIndex(astTree, node, 2);
  177. });
  178. it('should insert given node in `BlockStatement` node body at index', () => {
  179. assert.deepEqual(astTree, expectedAstTree);
  180. });
  181. });
  182. describe('prepend', () => {
  183. let astTree: ESTree.Program,
  184. expectedAstTree: ESTree.Program,
  185. node: TStatement[];
  186. before(() => {
  187. node = convertCodeToStructure('/fixtures/simple-input.js');
  188. astTree = convertCodeToAst('/fixtures/prepend-node.js');
  189. expectedAstTree = convertCodeToAst('/fixtures/prepend-node-expected.js');
  190. astTree = NodeUtils.parentizeAst(astTree);
  191. expectedAstTree = NodeUtils.parentizeAst(expectedAstTree);
  192. NodeAppender.prepend(astTree, node);
  193. });
  194. it('should prepend given node to a `BlockStatement` node body', () => {
  195. assert.deepEqual(astTree, expectedAstTree);
  196. });
  197. });
  198. });