TransformersRunner.ts 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import { inject, injectable } from 'inversify';
  2. import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
  3. import * as estraverse from 'estraverse';
  4. import * as ESTree from 'estree';
  5. import { TNodeTransformerFactory } from '../types/container/node-transformers/TNodeTransformerFactory';
  6. import { TNormalizedNodeTransformers } from '../types/node-transformers/TNormalizedNodeTransformers';
  7. import { TTransformersRunnerData } from '../types/node-transformers/TTransformersRunnerData';
  8. import { TVisitorDirection } from '../types/node-transformers/TVisitorDirection';
  9. import { TVisitorFunction } from '../types/node-transformers/TVisitorFunction';
  10. import { TVisitorResult } from '../types/node-transformers/TVisitorResult';
  11. import { INodeTransformer } from '../interfaces/node-transformers/INodeTransformer';
  12. import { INodeTransformerNamesGroupsBuilder } from '../interfaces/utils/INodeTransformerNamesGroupsBuilder';
  13. import { ITransformersRunner } from '../interfaces/node-transformers/ITransformersRunner';
  14. import { IVisitor } from '../interfaces/node-transformers/IVisitor';
  15. import { NodeTransformer } from '../enums/node-transformers/NodeTransformer';
  16. import { TransformationStage } from '../enums/node-transformers/TransformationStage';
  17. import { VisitorDirection } from '../enums/node-transformers/VisitorDirection';
  18. import { NodeGuards } from '../node/NodeGuards';
  19. import { NodeMetadata } from '../node/NodeMetadata';
  20. @injectable()
  21. export class TransformersRunner implements ITransformersRunner {
  22. /**
  23. * @type {Map<NodeTransformer[], TTransformersRunnerData>}
  24. */
  25. private readonly cachedNodeTransformersData: Map<NodeTransformer[], TTransformersRunnerData> = new Map();
  26. /**
  27. * @type {TNodeTransformerFactory}
  28. */
  29. private readonly nodeTransformerFactory: TNodeTransformerFactory;
  30. /**
  31. * @type {INodeTransformerNamesGroupsBuilder}
  32. */
  33. private readonly nodeTransformerNamesGroupsBuilder: INodeTransformerNamesGroupsBuilder;
  34. /**
  35. * @param {TNodeTransformerFactory} nodeTransformerFactory
  36. * @param {INodeTransformerNamesGroupsBuilder} nodeTransformerNamesGroupsBuilder
  37. */
  38. public constructor (
  39. @inject(ServiceIdentifiers.Factory__INodeTransformer)
  40. nodeTransformerFactory: TNodeTransformerFactory,
  41. @inject(ServiceIdentifiers.INodeTransformerNamesGroupsBuilder)
  42. nodeTransformerNamesGroupsBuilder: INodeTransformerNamesGroupsBuilder,
  43. ) {
  44. this.nodeTransformerFactory = nodeTransformerFactory;
  45. this.nodeTransformerNamesGroupsBuilder = nodeTransformerNamesGroupsBuilder;
  46. }
  47. /**
  48. * @param {T} astTree
  49. * @param {NodeTransformer[]} nodeTransformerNames
  50. * @param {TransformationStage} transformationStage
  51. * @returns {T}
  52. */
  53. public transform <T extends ESTree.Node = ESTree.Program> (
  54. astTree: T,
  55. nodeTransformerNames: NodeTransformer[],
  56. transformationStage: TransformationStage
  57. ): T {
  58. if (!nodeTransformerNames.length) {
  59. return astTree;
  60. }
  61. let normalizedNodeTransformers: TNormalizedNodeTransformers;
  62. let nodeTransformerNamesGroups: NodeTransformer[][];
  63. if (!this.cachedNodeTransformersData.has(nodeTransformerNames)) {
  64. normalizedNodeTransformers = this.buildNormalizedNodeTransformers(nodeTransformerNames);
  65. nodeTransformerNamesGroups = this.nodeTransformerNamesGroupsBuilder.build(normalizedNodeTransformers);
  66. this.cachedNodeTransformersData.set(nodeTransformerNames, [normalizedNodeTransformers, nodeTransformerNamesGroups]);
  67. } else {
  68. [
  69. normalizedNodeTransformers,
  70. nodeTransformerNamesGroups
  71. ] = <TTransformersRunnerData>this.cachedNodeTransformersData.get(nodeTransformerNames);
  72. }
  73. for (const nodeTransformerNamesGroup of nodeTransformerNamesGroups) {
  74. const enterVisitors: IVisitor[] = [];
  75. const leaveVisitors: IVisitor[] = [];
  76. for (const nodeTransformerName of nodeTransformerNamesGroup) {
  77. const nodeTransformer: INodeTransformer = normalizedNodeTransformers[nodeTransformerName];
  78. const visitor: IVisitor | null = nodeTransformer.getVisitor(transformationStage);
  79. if (!visitor) {
  80. continue;
  81. }
  82. if (visitor.enter) {
  83. enterVisitors.push({ enter: visitor.enter });
  84. }
  85. if (visitor.leave) {
  86. leaveVisitors.push({ leave: visitor.leave });
  87. }
  88. }
  89. if (!enterVisitors.length && !leaveVisitors.length) {
  90. continue;
  91. }
  92. estraverse.replace(astTree, {
  93. enter: this.mergeVisitorsForDirection(enterVisitors, VisitorDirection.Enter),
  94. leave: this.mergeVisitorsForDirection(leaveVisitors, VisitorDirection.Leave)
  95. });
  96. }
  97. return astTree;
  98. }
  99. /**
  100. * @param {NodeTransformer[]} nodeTransformerNames
  101. * @returns {TNormalizedNodeTransformers}
  102. */
  103. private buildNormalizedNodeTransformers (nodeTransformerNames: NodeTransformer[]): TNormalizedNodeTransformers {
  104. return nodeTransformerNames
  105. .reduce<TNormalizedNodeTransformers>(
  106. (acc: TNormalizedNodeTransformers, nodeTransformerName: NodeTransformer) => ({
  107. ...acc,
  108. [nodeTransformerName]: this.nodeTransformerFactory(nodeTransformerName)
  109. }),
  110. {}
  111. );
  112. }
  113. /**
  114. * @param {IVisitor[]} visitors
  115. * @param {TVisitorDirection} direction
  116. * @returns {TVisitorFunction}
  117. */
  118. private mergeVisitorsForDirection (visitors: IVisitor[], direction: TVisitorDirection): TVisitorFunction {
  119. const visitorsLength: number = visitors.length;
  120. if (!visitorsLength) {
  121. return (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node => node;
  122. }
  123. return (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | estraverse.VisitorOption => {
  124. if (NodeMetadata.isIgnoredNode(node)) {
  125. return estraverse.VisitorOption.Skip;
  126. }
  127. for (let i: number = 0; i < visitorsLength; i++) {
  128. const visitorFunction: TVisitorFunction | undefined = visitors[i][direction];
  129. if (!visitorFunction) {
  130. continue;
  131. }
  132. const visitorResult: TVisitorResult = visitorFunction(node, parentNode);
  133. if (!visitorResult || !NodeGuards.isNode(visitorResult)) {
  134. continue;
  135. }
  136. node = visitorResult;
  137. }
  138. return node;
  139. };
  140. }
  141. }