CallExpressionControlFlowReplacer.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { injectable, inject } from 'inversify';
  2. import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
  3. import * as ESTree from 'estree';
  4. import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
  5. import { TStatement } from '../../../types/node/TStatement';
  6. import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
  7. import { IOptions } from '../../../interfaces/options/IOptions';
  8. import { IStorage } from '../../../interfaces/storages/IStorage';
  9. import { CustomNodes } from '../../../enums/container/CustomNodes';
  10. import { AbstractControlFlowReplacer } from './AbstractControlFlowReplacer';
  11. import { Node } from '../../../node/Node';
  12. @injectable()
  13. export class CallExpressionControlFlowReplacer extends AbstractControlFlowReplacer {
  14. /**
  15. * @type {number}
  16. */
  17. private static readonly usingExistingIdentifierChance: number = 0.5;
  18. /**
  19. * @param customNodeFactory
  20. * @param options
  21. */
  22. constructor (
  23. @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
  24. @inject(ServiceIdentifiers.IOptions) options: IOptions
  25. ) {
  26. super(customNodeFactory, options);
  27. }
  28. /**
  29. * @param callExpressionNode
  30. * @param parentNode
  31. * @param controlFlowStorage
  32. * @returns {ESTree.Node}
  33. */
  34. public replace (
  35. callExpressionNode: ESTree.CallExpression,
  36. parentNode: ESTree.Node,
  37. controlFlowStorage: IStorage <ICustomNode>
  38. ): ESTree.Node {
  39. const callee: ESTree.Expression = <ESTree.Expression>callExpressionNode.callee;
  40. if (!Node.isIdentifierNode(callee)) {
  41. return callExpressionNode;
  42. }
  43. const replacerId: string = String(callExpressionNode.arguments.length);
  44. const callExpressionFunctionCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.CallExpressionFunctionNode);
  45. const expressionArguments: (ESTree.Expression | ESTree.SpreadElement)[] = callExpressionNode.arguments;
  46. callExpressionFunctionCustomNode.initialize(expressionArguments);
  47. const storageKey: string = this.insertCustomNodeToControlFlowStorage(
  48. callExpressionFunctionCustomNode,
  49. controlFlowStorage,
  50. replacerId,
  51. CallExpressionControlFlowReplacer.usingExistingIdentifierChance
  52. );
  53. return this.getControlFlowStorageCallNode(
  54. controlFlowStorage.getStorageId(),
  55. storageKey,
  56. callee,
  57. expressionArguments
  58. );
  59. }
  60. /**
  61. * @param controlFlowStorageId
  62. * @param storageKey
  63. * @param callee
  64. * @param expressionArguments
  65. * @param arguments
  66. * @returns {ESTree.Node}
  67. */
  68. protected getControlFlowStorageCallNode (
  69. controlFlowStorageId: string,
  70. storageKey: string,
  71. callee: ESTree.Expression,
  72. expressionArguments: (ESTree.Expression | ESTree.SpreadElement)[]
  73. ): ESTree.Node {
  74. const controlFlowStorageCallCustomNode: ICustomNode = this.customNodeFactory(
  75. CustomNodes.CallExpressionControlFlowStorageCallNode
  76. );
  77. controlFlowStorageCallCustomNode.initialize(controlFlowStorageId, storageKey, callee, expressionArguments);
  78. const statementNode: TStatement = controlFlowStorageCallCustomNode.getNode()[0];
  79. if (!statementNode || !Node.isExpressionStatementNode(statementNode)) {
  80. throw new Error(`\`controlFlowStorageCallCustomNode.getNode()[0]\` should returns array with \`ExpressionStatement\` node`);
  81. }
  82. return statementNode.expression;
  83. }
  84. }