import { injectable, inject } from 'inversify'; import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers'; import * as ESTree from 'estree'; import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory'; import { IControlFlowReplacer } from '../../../interfaces/node-transformers/IControlFlowReplacer'; import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode'; import { IOptions } from '../../../interfaces/options/IOptions'; import { IStorage } from '../../../interfaces/storages/IStorage'; import { RandomGeneratorUtils } from '../../../utils/RandomGeneratorUtils'; @injectable() export abstract class AbstractControlFlowReplacer implements IControlFlowReplacer { /** * @type {TCustomNodeFactory} */ protected readonly customNodeFactory: TCustomNodeFactory; /** * @type {IOptions} */ protected readonly options: IOptions; /** * @type {Map>} */ protected readonly replacerDataByControlFlowStorageId: Map > = new Map(); /** * @param customNodeFactory * @param options */ constructor ( @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory, @inject(ServiceIdentifiers.IOptions) options: IOptions ) { this.customNodeFactory = customNodeFactory; this.options = options; } /** * @param identifierDataByControlFlowStorageId * @param controlFlowStorageId * @returns {Map} */ protected static getStorageKeysByIdForCurrentStorage ( identifierDataByControlFlowStorageId: Map>, controlFlowStorageId: string ): Map { let storageKeysById: Map; if (identifierDataByControlFlowStorageId.has(controlFlowStorageId)) { storageKeysById = >identifierDataByControlFlowStorageId.get(controlFlowStorageId); } else { storageKeysById = new Map (); } return storageKeysById; } /** * @param node * @param parentNode * @param controlFlowStorage * @returns {ESTree.Node} */ public abstract replace (node: ESTree.Node, parentNode: ESTree.Node, controlFlowStorage: IStorage ): ESTree.Node; /** * @param customNode * @param controlFlowStorage * @param replacerId * @param usingExistingIdentifierChance * @returns {string} */ protected insertCustomNodeToControlFlowStorage ( customNode: ICustomNode, controlFlowStorage: IStorage , replacerId: string, usingExistingIdentifierChance: number ): string { const controlFlowStorageId: string = controlFlowStorage.getStorageId(); const storageKeysById: Map = AbstractControlFlowReplacer .getStorageKeysByIdForCurrentStorage(this.replacerDataByControlFlowStorageId, controlFlowStorageId); const storageKeysForCurrentId: string[] | undefined = storageKeysById.get(replacerId); if ( RandomGeneratorUtils.getMathRandom() > usingExistingIdentifierChance && storageKeysForCurrentId && storageKeysForCurrentId.length ) { return RandomGeneratorUtils.getRandomGenerator().pickone(storageKeysForCurrentId); } const generateStorageKey: (length: number) => string = (length: number) => { const storageKey: string = RandomGeneratorUtils.getRandomString(length); if (controlFlowStorage.getStorage().has(storageKey)) { return generateStorageKey(length); } return storageKey; }; const storageKey: string = generateStorageKey(3); storageKeysById.set(replacerId, [storageKey]); this.replacerDataByControlFlowStorageId.set(controlFlowStorageId, storageKeysById); controlFlowStorage.set(storageKey, customNode); return storageKey; } }