StringArrayScopeCallsWrapperTransformer.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. import { inject, injectable, } from 'inversify';
  2. import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
  3. import * as ESTree from 'estree';
  4. import { TInitialData } from '../../types/TInitialData';
  5. import { TNodeWithLexicalScopeStatements } from '../../types/node/TNodeWithLexicalScopeStatements';
  6. import { TStatement } from '../../types/node/TStatement';
  7. import { TStringArrayScopeCallsWrapperNamesDataByEncoding } from '../../types/node-transformers/string-array-transformers/TStringArrayScopeCallsWrapperNamesDataByEncoding';
  8. import { TStringArrayCustomNodeFactory } from '../../types/container/custom-nodes/TStringArrayCustomNodeFactory';
  9. import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
  10. import { IOptions } from '../../interfaces/options/IOptions';
  11. import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
  12. import { IStringArrayScopeCallsWrapperLexicalScopeData } from '../../interfaces/node-transformers/string-array-transformers/IStringArrayScopeCallsWrapperLexicalScopeData';
  13. import { IStringArrayScopeCallsWrapperLexicalScopeDataStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayScopeCallsWrapperLexicalScopeDataStorage';
  14. import { IStringArrayScopeCallsWrapperNamesData } from '../../interfaces/node-transformers/string-array-transformers/IStringArrayScopeCallsWrapperNamesData';
  15. import { IStringArrayScopeCallsWrapperNamesDataStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayScopeCallsWrapperNamesDataStorage';
  16. import { IStringArrayStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayStorage';
  17. import { IVisitedLexicalScopeNodesStackStorage } from '../../interfaces/storages/string-array-transformers/IVisitedLexicalScopeNodesStackStorage';
  18. import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
  19. import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
  20. import { StringArrayCustomNode } from '../../enums/custom-nodes/StringArrayCustomNode';
  21. import { StringArrayWrappersType } from '../../enums/node-transformers/string-array-transformers/StringArrayWrappersType';
  22. import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
  23. import { NodeAppender } from '../../node/NodeAppender';
  24. import { NodeGuards } from '../../node/NodeGuards';
  25. import { StringArrayScopeCallsWrapperFunctionNode } from '../../custom-nodes/string-array-nodes/StringArrayScopeCallsWrapperFunctionNode';
  26. import { StringArrayScopeCallsWrapperVariableNode } from '../../custom-nodes/string-array-nodes/StringArrayScopeCallsWrapperVariableNode';
  27. @injectable()
  28. export class StringArrayScopeCallsWrapperTransformer extends AbstractNodeTransformer {
  29. /**
  30. * @type {IStringArrayStorage}
  31. */
  32. private readonly stringArrayStorage: IStringArrayStorage;
  33. /**
  34. * @type {IStringArrayScopeCallsWrapperLexicalScopeDataStorage}
  35. */
  36. private readonly stringArrayScopeCallsWrapperLexicalScopeDataStorage: IStringArrayScopeCallsWrapperLexicalScopeDataStorage;
  37. /**
  38. * @type {IStringArrayScopeCallsWrapperNamesDataStorage}
  39. */
  40. private readonly stringArrayScopeCallsWrapperNamesDataStorage: IStringArrayScopeCallsWrapperNamesDataStorage;
  41. /**
  42. * @type {TStringArrayCustomNodeFactory}
  43. */
  44. private readonly stringArrayTransformerCustomNodeFactory: TStringArrayCustomNodeFactory;
  45. /**
  46. * @type {IVisitedLexicalScopeNodesStackStorage}
  47. */
  48. private readonly visitedLexicalScopeNodesStackStorage: IVisitedLexicalScopeNodesStackStorage;
  49. /**
  50. * @param {IRandomGenerator} randomGenerator
  51. * @param {IOptions} options
  52. * @param {IVisitedLexicalScopeNodesStackStorage} visitedLexicalScopeNodesStackStorage
  53. * @param {IStringArrayStorage} stringArrayStorage
  54. * @param {IStringArrayScopeCallsWrapperNamesDataStorage} stringArrayScopeCallsWrapperNamesDataStorage
  55. * @param {IStringArrayScopeCallsWrapperLexicalScopeDataStorage} stringArrayScopeCallsWrapperLexicalScopeDataStorage
  56. * @param {TStringArrayCustomNodeFactory} stringArrayTransformerCustomNodeFactory
  57. */
  58. public constructor (
  59. @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
  60. @inject(ServiceIdentifiers.IOptions) options: IOptions,
  61. @inject(ServiceIdentifiers.IVisitedLexicalScopeNodesStackStorage) visitedLexicalScopeNodesStackStorage: IVisitedLexicalScopeNodesStackStorage,
  62. @inject(ServiceIdentifiers.IStringArrayStorage) stringArrayStorage: IStringArrayStorage,
  63. @inject(ServiceIdentifiers.IStringArrayScopeCallsWrapperNamesDataStorage) stringArrayScopeCallsWrapperNamesDataStorage: IStringArrayScopeCallsWrapperNamesDataStorage,
  64. @inject(ServiceIdentifiers.IStringArrayScopeCallsWrapperLexicalScopeDataStorage) stringArrayScopeCallsWrapperLexicalScopeDataStorage: IStringArrayScopeCallsWrapperLexicalScopeDataStorage,
  65. @inject(ServiceIdentifiers.Factory__IStringArrayCustomNode)
  66. stringArrayTransformerCustomNodeFactory: TStringArrayCustomNodeFactory
  67. ) {
  68. super(randomGenerator, options);
  69. this.visitedLexicalScopeNodesStackStorage = visitedLexicalScopeNodesStackStorage;
  70. this.stringArrayStorage = stringArrayStorage;
  71. this.stringArrayScopeCallsWrapperNamesDataStorage = stringArrayScopeCallsWrapperNamesDataStorage;
  72. this.stringArrayScopeCallsWrapperLexicalScopeDataStorage = stringArrayScopeCallsWrapperLexicalScopeDataStorage;
  73. this.stringArrayTransformerCustomNodeFactory = stringArrayTransformerCustomNodeFactory;
  74. }
  75. /**
  76. * @param {NodeTransformationStage} nodeTransformationStage
  77. * @returns {IVisitor | null}
  78. */
  79. public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null {
  80. if (!this.options.stringArrayWrappersCount) {
  81. return null;
  82. }
  83. switch (nodeTransformationStage) {
  84. case NodeTransformationStage.Strings:
  85. return {
  86. enter: (node: ESTree.Node, parentNode: ESTree.Node | null): void => {
  87. if (parentNode && NodeGuards.isNodeWithLexicalScopeStatements(node, parentNode)) {
  88. this.onLexicalScopeNodeEnter(node);
  89. }
  90. },
  91. leave: (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | undefined => {
  92. if (parentNode && NodeGuards.isNodeWithLexicalScopeStatements(node, parentNode)) {
  93. this.onLexicalScopeNodeLeave();
  94. return this.transformNode(node);
  95. }
  96. }
  97. };
  98. default:
  99. return null;
  100. }
  101. }
  102. /**
  103. * @param {TNodeWithLexicalScopeStatements} lexicalScopeBodyNode
  104. * @returns {TNodeWithLexicalScopeStatements}
  105. */
  106. public transformNode (
  107. lexicalScopeBodyNode: TNodeWithLexicalScopeStatements
  108. ): TNodeWithLexicalScopeStatements {
  109. const stringArrayScopeCallsWrapperNamesDataByEncoding: TStringArrayScopeCallsWrapperNamesDataByEncoding | null =
  110. this.stringArrayScopeCallsWrapperNamesDataStorage.get(lexicalScopeBodyNode) ?? null;
  111. const stringArrayScopeCallsWrapperNamesLexicalScopeData: IStringArrayScopeCallsWrapperLexicalScopeData | null =
  112. this.stringArrayScopeCallsWrapperLexicalScopeDataStorage.get(lexicalScopeBodyNode) ?? null;
  113. if (!stringArrayScopeCallsWrapperNamesDataByEncoding || !stringArrayScopeCallsWrapperNamesLexicalScopeData) {
  114. return lexicalScopeBodyNode;
  115. }
  116. const stringArrayScopeCallsWrapperNamesDataList: (IStringArrayScopeCallsWrapperNamesData | undefined)[] =
  117. Object.values(stringArrayScopeCallsWrapperNamesDataByEncoding);
  118. // iterates over data for each encoding type
  119. for (const stringArrayScopeCallsWrapperNamesData of stringArrayScopeCallsWrapperNamesDataList) {
  120. if (!stringArrayScopeCallsWrapperNamesData) {
  121. continue;
  122. }
  123. const {names} = stringArrayScopeCallsWrapperNamesData;
  124. const namesLength: number = names.length;
  125. /**
  126. * Iterates over each name of scope wrapper name
  127. * Reverse iteration appends wrappers at index `0` at the correct order
  128. */
  129. for (let i = namesLength - 1; i >= 0; i--) {
  130. const stringArrayScopeCallsWrapperName: string = names[i];
  131. const [
  132. upperStringArrayCallsWrapperName,
  133. upperStringArrayCallsWrapperShiftedIndex,
  134. ] = this.getUpperStringArrayCallsWrapperName(
  135. stringArrayScopeCallsWrapperNamesData,
  136. stringArrayScopeCallsWrapperNamesLexicalScopeData,
  137. );
  138. const stringArrayScopeCallsWrapperNode: TStatement[] = this.getStringArrayScopeCallsWrapperNode(
  139. stringArrayScopeCallsWrapperName,
  140. upperStringArrayCallsWrapperName,
  141. upperStringArrayCallsWrapperShiftedIndex
  142. );
  143. NodeAppender.prepend(
  144. lexicalScopeBodyNode,
  145. stringArrayScopeCallsWrapperNode
  146. );
  147. }
  148. }
  149. return lexicalScopeBodyNode;
  150. }
  151. /**
  152. * @param {IStringArrayScopeCallsWrapperNamesData} stringArrayScopeCallsWrapperNamesData
  153. * @param {IStringArrayScopeCallsWrapperLexicalScopeData} stringArrayScopeCallsWrapperNamesLexicalScopeData
  154. * @returns {[name: string, index: number]}
  155. */
  156. private getRootStringArrayCallsWrapperData (
  157. stringArrayScopeCallsWrapperNamesData: IStringArrayScopeCallsWrapperNamesData,
  158. stringArrayScopeCallsWrapperNamesLexicalScopeData: IStringArrayScopeCallsWrapperLexicalScopeData
  159. ): [name: string, index: number] {
  160. const {encoding} = stringArrayScopeCallsWrapperNamesData;
  161. const {resultShiftedIndex} = stringArrayScopeCallsWrapperNamesLexicalScopeData;
  162. return [
  163. this.stringArrayStorage.getStorageCallsWrapperName(encoding),
  164. resultShiftedIndex
  165. ];
  166. }
  167. /**
  168. * @param {IStringArrayScopeCallsWrapperNamesData} stringArrayScopeCallsWrapperNamesData
  169. * @param {IStringArrayScopeCallsWrapperLexicalScopeData} stringArrayScopeCallsWrapperNamesLexicalScopeData
  170. * @returns {[name: string, index: number]}
  171. */
  172. private getUpperStringArrayCallsWrapperName (
  173. stringArrayScopeCallsWrapperNamesData: IStringArrayScopeCallsWrapperNamesData,
  174. stringArrayScopeCallsWrapperNamesLexicalScopeData: IStringArrayScopeCallsWrapperLexicalScopeData
  175. ): [name: string, index: number] {
  176. const {encoding} = stringArrayScopeCallsWrapperNamesData;
  177. const {scopeShiftedIndex} = stringArrayScopeCallsWrapperNamesLexicalScopeData;
  178. const rootStringArrayCallsWrapperData = this.getRootStringArrayCallsWrapperData(
  179. stringArrayScopeCallsWrapperNamesData,
  180. stringArrayScopeCallsWrapperNamesLexicalScopeData
  181. );
  182. if (!this.options.stringArrayWrappersChainedCalls) {
  183. return rootStringArrayCallsWrapperData;
  184. }
  185. const parentLexicalScopeBodyNode: TNodeWithLexicalScopeStatements | null =
  186. this.visitedLexicalScopeNodesStackStorage.getLastElement()
  187. ?? null;
  188. if (!parentLexicalScopeBodyNode) {
  189. return rootStringArrayCallsWrapperData;
  190. }
  191. const parentLexicalScopeNamesDataByEncoding: TStringArrayScopeCallsWrapperNamesDataByEncoding | null = this.stringArrayScopeCallsWrapperNamesDataStorage
  192. .get(parentLexicalScopeBodyNode) ?? null;
  193. const parentLexicalScopeNames: string[] | null = parentLexicalScopeNamesDataByEncoding?.[encoding]?.names ?? null;
  194. if (!parentLexicalScopeNames?.length) {
  195. return rootStringArrayCallsWrapperData;
  196. }
  197. const upperStringArrayCallsWrapperName: string = this.randomGenerator
  198. .getRandomGenerator()
  199. .pickone(parentLexicalScopeNames);
  200. return [
  201. upperStringArrayCallsWrapperName,
  202. scopeShiftedIndex
  203. ];
  204. }
  205. /**
  206. * @param {string} stringArrayScopeCallsWrapperName
  207. * @param {string} upperStringArrayCallsWrapperName
  208. * @param {number} stringArrayScopeCallsWrapperShiftedIndex
  209. * @returns {TStatement[]}
  210. */
  211. private getStringArrayScopeCallsWrapperNode (
  212. stringArrayScopeCallsWrapperName: string,
  213. upperStringArrayCallsWrapperName: string,
  214. stringArrayScopeCallsWrapperShiftedIndex: number
  215. ): TStatement[] {
  216. switch (this.options.stringArrayWrappersType) {
  217. case StringArrayWrappersType.Function:
  218. return this.getStringArrayScopeCallsWrapperFunctionNode(
  219. stringArrayScopeCallsWrapperName,
  220. upperStringArrayCallsWrapperName,
  221. stringArrayScopeCallsWrapperShiftedIndex
  222. );
  223. case StringArrayWrappersType.Variable:
  224. default:
  225. return this.getStringArrayScopeCallsWrapperVariableNode(
  226. stringArrayScopeCallsWrapperName,
  227. upperStringArrayCallsWrapperName
  228. );
  229. }
  230. }
  231. /**
  232. * @param {string} stringArrayScopeCallsWrapperName
  233. * @param {string} upperStringArrayCallsWrapperName
  234. * @returns {TStatement[]}
  235. */
  236. private getStringArrayScopeCallsWrapperVariableNode (
  237. stringArrayScopeCallsWrapperName: string,
  238. upperStringArrayCallsWrapperName: string
  239. ): TStatement[] {
  240. const stringArrayScopeCallsWrapperVariableNode: ICustomNode<TInitialData<StringArrayScopeCallsWrapperVariableNode>> =
  241. this.stringArrayTransformerCustomNodeFactory(
  242. StringArrayCustomNode.StringArrayScopeCallsWrapperVariableNode
  243. );
  244. stringArrayScopeCallsWrapperVariableNode.initialize(
  245. stringArrayScopeCallsWrapperName,
  246. upperStringArrayCallsWrapperName
  247. );
  248. return stringArrayScopeCallsWrapperVariableNode.getNode();
  249. }
  250. /**
  251. * @param {string} stringArrayScopeCallsWrapperName
  252. * @param {string} upperStringArrayCallsWrapperName
  253. * @param {number} stringArrayScopeCallsWrapperShiftedIndex
  254. * @returns {TStatement[]}
  255. */
  256. private getStringArrayScopeCallsWrapperFunctionNode (
  257. stringArrayScopeCallsWrapperName: string,
  258. upperStringArrayCallsWrapperName: string,
  259. stringArrayScopeCallsWrapperShiftedIndex: number
  260. ): TStatement[] {
  261. const stringArrayScopeCallsWrapperFunctionNode: ICustomNode<TInitialData<StringArrayScopeCallsWrapperFunctionNode>> =
  262. this.stringArrayTransformerCustomNodeFactory(
  263. StringArrayCustomNode.StringArrayScopeCallsWrapperFunctionNode
  264. );
  265. stringArrayScopeCallsWrapperFunctionNode.initialize(
  266. stringArrayScopeCallsWrapperName,
  267. upperStringArrayCallsWrapperName,
  268. stringArrayScopeCallsWrapperShiftedIndex
  269. );
  270. return stringArrayScopeCallsWrapperFunctionNode.getNode();
  271. }
  272. /**
  273. * @param {TNodeWithLexicalScopeStatements} lexicalScopeBodyNode
  274. */
  275. private onLexicalScopeNodeEnter (lexicalScopeBodyNode: TNodeWithLexicalScopeStatements): void {
  276. this.visitedLexicalScopeNodesStackStorage.push(lexicalScopeBodyNode);
  277. }
  278. private onLexicalScopeNodeLeave (): void {
  279. this.visitedLexicalScopeNodesStackStorage.pop();
  280. }
  281. }