sanex3339 8 years ago
parent
commit
f0fe518cf3
61 changed files with 969 additions and 1226 deletions
  1. 244 358
      dist/index.js
  2. 1 1
      package.json
  3. 1 11
      src/JavaScriptObfuscatorInternal.ts
  4. 27 12
      src/Obfuscator.ts
  5. 9 8
      src/container/InversifyContainerFacade.ts
  6. 3 4
      src/container/ServiceIdentifiers.ts
  7. 45 30
      src/container/modules/custom-nodes/CustomNodesModule.ts
  8. 0 30
      src/custom-nodes/AbstractCustomNode.ts
  9. 24 13
      src/custom-nodes/AbstractCustomNodeGroup.ts
  10. 4 23
      src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts
  11. 0 59
      src/custom-nodes/console-output-nodes/factory/ConsoleOutputCustomNodesFactory.ts
  12. 106 0
      src/custom-nodes/console-output-nodes/group/ConsoleOutputCustomNodeGroup.ts
  13. 0 8
      src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionNode.ts
  14. 0 11
      src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallNode.ts
  15. 0 11
      src/custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode.ts
  16. 0 11
      src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionCallNode.ts
  17. 0 11
      src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionIntervalNode.ts
  18. 0 15
      src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionNode.ts
  19. 0 65
      src/custom-nodes/debug-protection-nodes/factory/DebugProtectionCustomNodesFactory.ts
  20. 114 0
      src/custom-nodes/debug-protection-nodes/group/DebugProtectionCustomNodeGroup.ts
  21. 1 25
      src/custom-nodes/domain-lock-nodes/DomainLockNode.ts
  22. 0 59
      src/custom-nodes/domain-lock-nodes/factory/DomainLockCustomNodesFactory.ts
  23. 106 0
      src/custom-nodes/domain-lock-nodes/group/DomainLockCustomNodeGroup.ts
  24. 5 30
      src/custom-nodes/node-calls-controller-nodes/NodeCallsControllerFunctionNode.ts
  25. 1 34
      src/custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode.ts
  26. 0 66
      src/custom-nodes/self-defending-nodes/factory/SelfDefendingCustomNodesFactory.ts
  27. 113 0
      src/custom-nodes/self-defending-nodes/group/SelfDefendingCustomNodeGroup.ts
  28. 0 22
      src/custom-nodes/string-array-nodes/StringArrayCallsWrapper.ts
  29. 0 23
      src/custom-nodes/string-array-nodes/StringArrayNode.ts
  30. 0 24
      src/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.ts
  31. 56 12
      src/custom-nodes/string-array-nodes/group/StringArrayCustomNodeGroup.ts
  32. 7 0
      src/enums/container/CustomNodeGroups.ts
  33. 0 7
      src/enums/container/CustomNodesFactories.ts
  34. 1 4
      src/interfaces/IObfuscator.d.ts
  35. 9 0
      src/interfaces/container/IInversifyContainerFacade.d.ts
  36. 0 20
      src/interfaces/custom-nodes/ICustomNode.d.ts
  37. 20 0
      src/interfaces/custom-nodes/ICustomNodeGroup.d.ts
  38. 0 11
      src/interfaces/custom-nodes/ICustomNodesFactory.d.ts
  39. 0 10
      src/node-transformers/AbstractNodeTransformer.ts
  40. 1 4
      src/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.ts
  41. 0 8
      src/node-transformers/node-control-flow-transformers/control-flow-replacers/AbstractControlFlowReplacer.ts
  42. 1 3
      src/node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.ts
  43. 1 5
      src/node-transformers/node-obfuscators/CatchClauseObfuscator.ts
  44. 1 5
      src/node-transformers/node-obfuscators/FunctionDeclarationObfuscator.ts
  45. 1 5
      src/node-transformers/node-obfuscators/FunctionObfuscator.ts
  46. 1 5
      src/node-transformers/node-obfuscators/LabeledStatementObfuscator.ts
  47. 1 5
      src/node-transformers/node-obfuscators/LiteralObfuscator.ts
  48. 1 5
      src/node-transformers/node-obfuscators/MemberExpressionObfuscator.ts
  49. 1 5
      src/node-transformers/node-obfuscators/MethodDefinitionObfuscator.ts
  50. 1 5
      src/node-transformers/node-obfuscators/ObjectExpressionObfuscator.ts
  51. 1 5
      src/node-transformers/node-obfuscators/VariableDeclarationObfuscator.ts
  52. 0 10
      src/node-transformers/node-obfuscators/replacers/AbstractReplacer.ts
  53. 1 5
      src/node-transformers/node-obfuscators/replacers/BooleanLiteralReplacer.ts
  54. 1 5
      src/node-transformers/node-obfuscators/replacers/IdentifierReplacer.ts
  55. 1 5
      src/node-transformers/node-obfuscators/replacers/NumberLiteralReplacer.ts
  56. 20 5
      src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts
  57. 0 100
      src/storages/custom-nodes/CustomNodesStorage.ts
  58. 3 3
      src/types/container/TCustomNodesFactoriesFactory.d.ts
  59. 1 3
      src/types/node-transformers/TControlFlowReplacer.d.ts
  60. 3 2
      test/index.spec.ts
  61. 31 0
      test/unit-tests/storages/ControlFlowStorage.spec.ts

File diff suppressed because it is too large
+ 244 - 358
dist/index.js


+ 1 - 1
package.json

@@ -27,7 +27,7 @@
     "escodegen": "1.8.1",
     "esprima": "3.1.2",
     "estraverse": "4.2.0",
-    "inversify": "^3.0.0-beta.3",
+    "inversify": "^3.0.0-rc.1",
     "is-equal": "^1.5.3",
     "mkdirp": "0.5.1",
     "reflect-metadata": "^0.1.8",

+ 1 - 11
src/JavaScriptObfuscatorInternal.ts

@@ -5,14 +5,12 @@ import * as esprima from 'esprima';
 import * as escodegen from 'escodegen';
 import * as ESTree from 'estree';
 
-import { ICustomNode } from './interfaces/custom-nodes/ICustomNode';
 import { IJavaScriptObfuscator } from './interfaces/IJavaScriptObfsucator';
 import { IObfuscationResult } from './interfaces/IObfuscationResult';
 import { IObfuscator } from './interfaces/IObfuscator';
 import { IGeneratorOutput } from './interfaces/IGeneratorOutput';
 import { IOptions } from './interfaces/options/IOptions';
 import { ISourceMapCorrector } from './interfaces/ISourceMapCorrector';
-import { IStorage } from './interfaces/storages/IStorage';
 
 import { Utils } from './Utils';
 
@@ -33,11 +31,6 @@ export class JavaScriptObfuscatorInternal implements IJavaScriptObfuscator {
         loc: true
     };
 
-    /**
-     * @type {IStorage<ICustomNode>}
-     */
-    private readonly customNodesStorage: IStorage<ICustomNode>;
-
     /**
      * @type {IObfuscator}
      */
@@ -56,18 +49,15 @@ export class JavaScriptObfuscatorInternal implements IJavaScriptObfuscator {
     /**
      * @param obfuscator
      * @param sourceMapCorrector
-     * @param customNodesStorage
      * @param options
      */
     constructor (
         @inject(ServiceIdentifiers.IObfuscator) obfuscator: IObfuscator,
         @inject(ServiceIdentifiers.ISourceMapCorrector) sourceMapCorrector: ISourceMapCorrector,
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         this.obfuscator = obfuscator;
         this.sourceMapCorrector = sourceMapCorrector;
-        this.customNodesStorage = customNodesStorage;
         this.options = options;
     }
 
@@ -121,7 +111,7 @@ export class JavaScriptObfuscatorInternal implements IJavaScriptObfuscator {
         const astTree: ESTree.Program = esprima.parse(sourceCode, JavaScriptObfuscatorInternal.esprimaParams);
 
         // obfuscate AST tree
-        const obfuscatedAstTree: ESTree.Program = this.obfuscator.obfuscateAstTree(astTree, this.customNodesStorage);
+        const obfuscatedAstTree: ESTree.Program = this.obfuscator.obfuscateAstTree(astTree);
 
         // generate code
         const generatorOutput: IGeneratorOutput = this.generateCode(sourceCode, obfuscatedAstTree);

+ 27 - 12
src/Obfuscator.ts

@@ -7,14 +7,14 @@ import * as ESTree from 'estree';
 import { TNodeTransformersFactory } from './types/container/TNodeTransformersFactory';
 import { TVisitorDirection } from './types/TVisitorDirection';
 
-import { ICustomNode } from './interfaces/custom-nodes/ICustomNode';
 import { IObfuscationEventEmitter } from './interfaces/event-emitters/IObfuscationEventEmitter';
 import { IObfuscator } from './interfaces/IObfuscator';
 import { IOptions } from './interfaces/options/IOptions';
 import { INodeTransformer } from './interfaces/node-transformers/INodeTransformer';
 import { IStackTraceAnalyzer } from './interfaces/stack-trace-analyzer/IStackTraceAnalyzer';
-import { IStorage } from './interfaces/storages/IStorage';
+import { IStackTraceData } from './interfaces/stack-trace-analyzer/IStackTraceData';
 
+import { CustomNodeGroups } from './enums/container/CustomNodeGroups';
 import { NodeTransformers } from './enums/container/NodeTransformers';
 import { NodeType } from './enums/NodeType';
 import { ObfuscationEvents } from './enums/ObfuscationEvents';
@@ -22,10 +22,21 @@ import { VisitorDirection } from './enums/VisitorDirection';
 
 import { Node } from './node/Node';
 import { NodeUtils } from './node/NodeUtils';
-import { IStackTraceData } from './interfaces/stack-trace-analyzer/IStackTraceData';
+import { TCustomNodeGroupsFactory } from './types/container/TCustomNodesFactoriesFactory';
 
 @injectable()
 export class Obfuscator implements IObfuscator {
+    /**
+     * @type {CustomNodeGroups[]}
+     */
+    private static readonly customNodeGroupsList: CustomNodeGroups[] = [
+        CustomNodeGroups.ConsoleOutputCustomNodeGroup,
+        CustomNodeGroups.DebugProtectionCustomNodeGroup,
+        CustomNodeGroups.DomainLockCustomNodeGroup,
+        CustomNodeGroups.SelfDefendingCustomNodeGroup,
+        CustomNodeGroups.StringArrayCustomNodeGroup
+    ];
+
     /**
      * @type {Map<string, NodeTransformers[]>}
      */
@@ -54,6 +65,11 @@ export class Obfuscator implements IObfuscator {
         [NodeType.Literal, [NodeTransformers.LiteralObfuscator]]
     ]);
 
+    /**
+     * @type {TCustomNodeGroupsFactory}
+     */
+    private readonly customNodeGroupsFactory: TCustomNodeGroupsFactory;
+
     /**
      * @type {TNodeTransformersFactory}
      */
@@ -77,27 +93,29 @@ export class Obfuscator implements IObfuscator {
     /**
      * @param stackTraceAnalyzer
      * @param obfuscationEventEmitter
+     * @param customNodeGroupsFactory
      * @param nodeTransformersFactory
      * @param options
      */
     constructor (
         @inject(ServiceIdentifiers.IStackTraceAnalyzer) stackTraceAnalyzer: IStackTraceAnalyzer,
         @inject(ServiceIdentifiers.IObfuscationEventEmitter) obfuscationEventEmitter: IObfuscationEventEmitter,
+        @inject(ServiceIdentifiers['Factory<ICustomNodeGroup>']) customNodeGroupsFactory: TCustomNodeGroupsFactory,
         @inject(ServiceIdentifiers['Factory<INodeTransformer[]>']) nodeTransformersFactory: TNodeTransformersFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         this.stackTraceAnalyzer = stackTraceAnalyzer;
         this.obfuscationEventEmitter = obfuscationEventEmitter;
+        this.customNodeGroupsFactory = customNodeGroupsFactory;
         this.nodeTransformersFactory = nodeTransformersFactory;
         this.options = options;
     }
 
     /**
      * @param astTree
-     * @param customNodesStorage
      * @returns {ESTree.Program}
      */
-    public obfuscateAstTree (astTree: ESTree.Program, customNodesStorage: IStorage<ICustomNode>): ESTree.Program {
+    public obfuscateAstTree (astTree: ESTree.Program): ESTree.Program {
         if (Node.isProgramNode(astTree) && !astTree.body.length) {
             return astTree;
         }
@@ -106,13 +124,10 @@ export class Obfuscator implements IObfuscator {
 
         const stackTraceData: IStackTraceData[] = this.stackTraceAnalyzer.analyze(astTree.body);
 
-        // prepare custom nodes
-        customNodesStorage.initialize(stackTraceData);
-        customNodesStorage
-            .getStorage()
-            .forEach((customNode: ICustomNode) => {
-                this.obfuscationEventEmitter.once(customNode.getAppendEvent(), customNode.appendNode.bind(customNode));
-            });
+        // initialize custom node groups
+        Obfuscator.customNodeGroupsList.forEach((customNodeGroupName: CustomNodeGroups) => {
+            this.customNodeGroupsFactory(customNodeGroupName).initialize(stackTraceData);
+        });
 
         this.obfuscationEventEmitter.emit(ObfuscationEvents.BeforeObfuscation, astTree, stackTraceData);
 

+ 9 - 8
src/container/InversifyContainerFacade.ts

@@ -7,7 +7,6 @@ import { nodeObfuscatorsModule } from './modules/node-transformers/NodeObfuscato
 import { nodeTransformersModule } from './modules/node-transformers/NodeTransformersModule';
 import { stackTraceAnalyzerModule } from './modules/stack-trace-analyzer/StackTraceAnalyzerModule';
 
-import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
 import { IInputOptions } from '../interfaces/options/IInputOptions';
 import { IInversifyContainerFacade } from '../interfaces/container/IInversifyContainerFacade';
 import { IJavaScriptObfuscator } from '../interfaces/IJavaScriptObfsucator';
@@ -16,9 +15,7 @@ import { IObfuscationResult } from '../interfaces/IObfuscationResult';
 import { IObfuscator } from '../interfaces/IObfuscator';
 import { IOptions } from '../interfaces/options/IOptions';
 import { ISourceMapCorrector } from '../interfaces/ISourceMapCorrector';
-import { IStorage } from '../interfaces/storages/IStorage';
 
-import { CustomNodesStorage } from '../storages/custom-nodes/CustomNodesStorage';
 import { JavaScriptObfuscatorInternal } from '../JavaScriptObfuscatorInternal';
 import { ObfuscationEventEmitter } from '../event-emitters/ObfuscationEventEmitter';
 import { ObfuscationResult } from '../ObfuscationResult';
@@ -83,11 +80,6 @@ export class InversifyContainerFacade implements IInversifyContainerFacade {
             .to(ObfuscationEventEmitter)
             .inSingletonScope();
 
-        this.container
-            .bind<IStorage<ICustomNode>>(ServiceIdentifiers['IStorage<ICustomNode>'])
-            .to(CustomNodesStorage)
-            .inSingletonScope();
-
         // modules
         this.container.load(stackTraceAnalyzerModule);
         this.container.load(customNodesModule);
@@ -103,4 +95,13 @@ export class InversifyContainerFacade implements IInversifyContainerFacade {
     public get <T> (serviceIdentifier: interfaces.ServiceIdentifier<T>): T {
         return this.container.get<T>(serviceIdentifier);
     }
+
+    /**
+     * @param serviceIdentifier
+     * @param named
+     * @returns {T}
+     */
+    public getNamed <T> (serviceIdentifier: interfaces.ServiceIdentifier<T>, named: string | number | symbol): T {
+        return this.container.getNamed<T>(serviceIdentifier, named);
+    }
 }

+ 3 - 4
src/container/ServiceIdentifiers.ts

@@ -2,13 +2,13 @@ export const ServiceIdentifiers: any = {
     'Factory<ICalleeDataExtractor>': Symbol('Factory<ICalleeDataExtractor>'),
     'Factory<IControlFlowReplacer>': Symbol('Factory<IControlFlowReplacer>'),
     'Factory<ICustomNode>': Symbol('Factory<ICustomNode>'),
-    'Factory<ICustomNodesFactory>': Symbol('Factory<ICustomNodesFactory>'),
+    'Factory<ICustomNodeGroup>': Symbol('Factory<ICustomNodeGroup>'),
     'Factory<INodeTransformer[]>': Symbol('Factory<INodeTransformer[]>'),
     'Factory<IObfuscationResult>': Symbol('Factory<IObfuscationResult>'),
     'Factory<IReplacer>': Symbol('Factory<IReplacer>'),
     ICalleeDataExtractor: Symbol('ICalleeDataExtractor'),
     ICustomNode: Symbol('ICustomNode'),
-    ICustomNodesFactory: Symbol('ICustomNodesFactory'),
+    ICustomNodeGroup: Symbol('ICustomNodeGroup'),
     IControlFlowReplacer: Symbol('IControlFlowReplacer'),
     IJavaScriptObfuscator: Symbol('IJavaScriptObfuscator'),
     INodeTransformer: Symbol('INodeTransformer'),
@@ -18,6 +18,5 @@ export const ServiceIdentifiers: any = {
     IOptions: Symbol('IOptions'),
     IReplacer: Symbol('IReplacer'),
     ISourceMapCorrector: Symbol('ISourceMapCorrector'),
-    IStackTraceAnalyzer: Symbol('IStackTraceAnalyzer'),
-    'IStorage<ICustomNode>': Symbol('IStorage<ICustomNode>')
+    IStackTraceAnalyzer: Symbol('IStackTraceAnalyzer')
 };

+ 45 - 30
src/container/modules/custom-nodes/CustomNodesModule.ts

@@ -2,16 +2,16 @@ import { ContainerModule, interfaces } from 'inversify';
 import { ServiceIdentifiers } from '../../ServiceIdentifiers';
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
-import { ICustomNodesFactory } from '../../../interfaces/custom-nodes/ICustomNodesFactory';
+import { ICustomNodeGroup } from '../../../interfaces/custom-nodes/ICustomNodeGroup';
 
 import { CustomNodes } from '../../../enums/container/CustomNodes';
-import { CustomNodesFactories } from '../../../enums/container/CustomNodesFactories';
+import { CustomNodeGroups } from '../../../enums/container/CustomNodeGroups';
 
-import { ConsoleOutputCustomNodesFactory } from '../../../custom-nodes/console-output-nodes/factory/ConsoleOutputCustomNodesFactory';
-import { DebugProtectionCustomNodesFactory } from '../../../custom-nodes/debug-protection-nodes/factory/DebugProtectionCustomNodesFactory';
-import { DomainLockCustomNodesFactory } from '../../../custom-nodes/domain-lock-nodes/factory/DomainLockCustomNodesFactory';
-import { SelfDefendingCustomNodesFactory } from '../../../custom-nodes/self-defending-nodes/factory/SelfDefendingCustomNodesFactory';
-import { StringArrayCustomNodesFactory } from '../../../custom-nodes/string-array-nodes/factory/StringArrayCustomNodesFactory';
+import { ConsoleOutputCustomNodeGroup } from '../../../custom-nodes/console-output-nodes/group/ConsoleOutputCustomNodeGroup';
+import { DebugProtectionCustomNodeGroup } from '../../../custom-nodes/debug-protection-nodes/group/DebugProtectionCustomNodeGroup';
+import { DomainLockCustomNodeGroup } from '../../../custom-nodes/domain-lock-nodes/group/DomainLockCustomNodeGroup';
+import { SelfDefendingCustomNodeGroup } from '../../../custom-nodes/self-defending-nodes/group/SelfDefendingCustomNodeGroup';
+import { StringArrayCustomNodeGroup } from '../../../custom-nodes/string-array-nodes/group/StringArrayCustomNodeGroup';
 
 import { BinaryExpressionFunctionNode } from '../../../custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionNode';
 import { ControlFlowStorageCallNode } from '../../../custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallNode';
@@ -81,26 +81,31 @@ export const customNodesModule: interfaces.ContainerModule = new ContainerModule
         .to(StringArrayRotateFunctionNode)
         .whenTargetNamed(CustomNodes.StringArrayRotateFunctionNode);
 
-    // custom nodes concrete factories
-    bind<ICustomNodesFactory>(ServiceIdentifiers.ICustomNodesFactory)
-        .to(ConsoleOutputCustomNodesFactory)
-        .whenTargetNamed(CustomNodesFactories.ConsoleOutputCustomNodesFactory);
+    // node groups
+    bind<ICustomNodeGroup>(ServiceIdentifiers.ICustomNodeGroup)
+        .to(ConsoleOutputCustomNodeGroup)
+        .inSingletonScope()
+        .whenTargetNamed(CustomNodeGroups.ConsoleOutputCustomNodeGroup);
 
-    bind<ICustomNodesFactory>(ServiceIdentifiers.ICustomNodesFactory)
-        .to(DebugProtectionCustomNodesFactory)
-        .whenTargetNamed(CustomNodesFactories.DebugProtectionCustomNodesFactory);
+    bind<ICustomNodeGroup>(ServiceIdentifiers.ICustomNodeGroup)
+        .to(DebugProtectionCustomNodeGroup)
+        .inSingletonScope()
+        .whenTargetNamed(CustomNodeGroups.DebugProtectionCustomNodeGroup);
 
-    bind<ICustomNodesFactory>(ServiceIdentifiers.ICustomNodesFactory)
-        .to(DomainLockCustomNodesFactory)
-        .whenTargetNamed(CustomNodesFactories.DomainLockCustomNodesFactory);
+    bind<ICustomNodeGroup>(ServiceIdentifiers.ICustomNodeGroup)
+        .to(DomainLockCustomNodeGroup)
+        .inSingletonScope()
+        .whenTargetNamed(CustomNodeGroups.DomainLockCustomNodeGroup);
 
-    bind<ICustomNodesFactory>(ServiceIdentifiers.ICustomNodesFactory)
-        .to(SelfDefendingCustomNodesFactory)
-        .whenTargetNamed(CustomNodesFactories.SelfDefendingCustomNodesFactory);
+    bind<ICustomNodeGroup>(ServiceIdentifiers.ICustomNodeGroup)
+        .to(SelfDefendingCustomNodeGroup)
+        .inSingletonScope()
+        .whenTargetNamed(CustomNodeGroups.SelfDefendingCustomNodeGroup);
 
-    bind<ICustomNodesFactory>(ServiceIdentifiers.ICustomNodesFactory)
-        .to(StringArrayCustomNodesFactory)
-        .whenTargetNamed(CustomNodesFactories.StringArrayCustomNodesFactory);
+    bind<ICustomNodeGroup>(ServiceIdentifiers.ICustomNodeGroup)
+        .to(StringArrayCustomNodeGroup)
+        .inSingletonScope()
+        .whenTargetNamed(CustomNodeGroups.StringArrayCustomNodeGroup);
 
     // customNode factory
     bind<ICustomNode>(ServiceIdentifiers['Factory<ICustomNode>'])
@@ -113,14 +118,24 @@ export const customNodesModule: interfaces.ContainerModule = new ContainerModule
             };
         });
 
-    // customNodesFactory factory
-    bind<ICustomNodesFactory>(ServiceIdentifiers['Factory<ICustomNodesFactory>'])
-        .toFactory<ICustomNodesFactory>((context: interfaces.Context) => {
-            return (customNodesFactoryName: CustomNodesFactories) => {
-                return context.container.getNamed<ICustomNodesFactory>(
-                    ServiceIdentifiers.ICustomNodesFactory,
-                    customNodesFactoryName
+    // CustomNodeGroup factory
+    bind<ICustomNodeGroup>(ServiceIdentifiers['Factory<ICustomNodeGroup>'])
+        .toFactory<ICustomNodeGroup>((context: interfaces.Context) => {
+            const cache: Map <CustomNodeGroups, ICustomNodeGroup> = new Map <CustomNodeGroups, ICustomNodeGroup> ();
+
+            return (customNodeGroupName: CustomNodeGroups) => {
+                if (cache.has(customNodeGroupName)) {
+                    return <ICustomNodeGroup>cache.get(customNodeGroupName);
+                }
+
+                const customNodeGroup: ICustomNodeGroup = context.container.getNamed<ICustomNodeGroup>(
+                    ServiceIdentifiers.ICustomNodeGroup,
+                    customNodeGroupName
                 );
+
+                cache.set(customNodeGroupName, customNodeGroup);
+
+                return customNodeGroup;
             };
         });
 });

+ 0 - 30
src/custom-nodes/AbstractCustomNode.ts

@@ -1,24 +1,14 @@
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
 
-import * as ESTree from 'estree';
-
-import { TObfuscationEvent } from '../types/event-emitters/TObfuscationEvent';
-
 import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../interfaces/options/IOptions';
-import { IStackTraceData } from '../interfaces/stack-trace-analyzer/IStackTraceData';
 import { TStatement } from '../types/node/TStatement';
 
 import { NodeUtils } from '../node/NodeUtils';
 
 @injectable()
 export abstract class AbstractCustomNode implements ICustomNode {
-    /**
-     * @type {TObfuscationEvent}
-     */
-    protected abstract appendEvent: TObfuscationEvent;
-
     /**
      * @type {IOptions}
      */
@@ -38,19 +28,6 @@ export abstract class AbstractCustomNode implements ICustomNode {
      */
     public abstract initialize (...args: any[]): void;
 
-    /**
-     * @param astTree
-     * @param stackTraceData
-     */
-    public abstract appendNode (astTree: ESTree.Node, stackTraceData: IStackTraceData[]): void;
-
-    /**
-     * @returns {TObfuscationEvent}
-     */
-    public getAppendEvent (): TObfuscationEvent {
-        return this.appendEvent;
-    }
-
     /**
      * @returns {string}
      */
@@ -63,13 +40,6 @@ export abstract class AbstractCustomNode implements ICustomNode {
         return this.getNodeStructure();
     }
 
-    /**
-     * @param appendEvent
-     */
-    public setAppendEvent (appendEvent: TObfuscationEvent): void {
-        this.appendEvent = appendEvent;
-    }
-
     /**
      * @returns {TStatement[]}
      */

+ 24 - 13
src/custom-nodes/AbstractCustomNodesFactory.ts → src/custom-nodes/AbstractCustomNodeGroup.ts

@@ -4,19 +4,29 @@ import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
 import { TObfuscationEvent } from '../types/event-emitters/TObfuscationEvent';
 
 import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
-import { ICustomNodesFactory } from '../interfaces/custom-nodes/ICustomNodesFactory';
+import { ICustomNodeGroup } from '../interfaces/custom-nodes/ICustomNodeGroup';
 import { IOptions } from '../interfaces/options/IOptions';
 import { IStackTraceData } from '../interfaces/stack-trace-analyzer/IStackTraceData';
 
 import { ObfuscationEvents } from '../enums/ObfuscationEvents';
 
 @injectable()
-export abstract class AbstractCustomNodesFactory implements ICustomNodesFactory {
+export abstract class AbstractCustomNodeGroup implements ICustomNodeGroup {
     /**
      * @type {TObfuscationEvent}
      */
     protected readonly appendEvent: TObfuscationEvent = ObfuscationEvents.BeforeObfuscation;
 
+    /**
+     * @type {Map<string, ICustomNode>}
+     */
+    protected abstract customNodes: Map <string, ICustomNode>;
+
+    /**
+     * @type {string}
+     */
+    protected abstract readonly groupName: string;
+
     /**
      * @type {IStackTraceData[]}
      */
@@ -37,20 +47,21 @@ export abstract class AbstractCustomNodesFactory implements ICustomNodesFactory
     }
 
     /**
-     * @param stackTraceData
-     * @returns {Map<string, ICustomNode> | undefined}
+     * @returns {Map<string, ICustomNode>}
      */
-    public abstract initializeCustomNodes (stackTraceData: IStackTraceData[]): Map <string, ICustomNode> | undefined;
+    public getCustomNodes (): Map <string, ICustomNode> {
+        return this.customNodes;
+    }
 
     /**
-     * @param customNodes
-     * @returns {Map<string, ICustomNode>}
+     * @returns {string}
      */
-    protected syncCustomNodesWithNodesFactory (customNodes: Map <string, ICustomNode>): Map <string, ICustomNode> {
-        customNodes.forEach((customNode: ICustomNode) => {
-            customNode.setAppendEvent(this.appendEvent);
-        });
-
-        return customNodes;
+    public getGroupName (): string {
+        return this.groupName;
     }
+
+    /**
+     * @param stackTraceData
+     */
+    public abstract initialize (stackTraceData: IStackTraceData[]): void;
 }

+ 4 - 23
src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts

@@ -3,11 +3,9 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
 import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
 
 import { IOptions } from '../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
@@ -16,12 +14,11 @@ import { ConsoleOutputDisableExpressionTemplate } from '../../templates/custom-n
 import { initializable } from '../../decorators/Initializable';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
-import { NodeAppender } from '../../node/NodeAppender';
 import { Utils } from '../../Utils';
 
 @injectable()
 export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
-/**
+    /**
      * @type {TObfuscationEvent}
      */
     protected readonly appendEvent: TObfuscationEvent = ObfuscationEvents.BeforeObfuscation;
@@ -33,10 +30,9 @@ export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
     protected callsControllerFunctionName: string;
 
     /**
-     * @type {number}
+     * @type {string}
      */
-    @initializable()
-    protected randomStackTraceIndex: number;
+    protected readonly groupName: string = 'consoleOutputDisableExpressionNode';
 
     /**
      * @param options
@@ -49,24 +45,9 @@ export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
 
     /**
      * @param callsControllerFunctionName
-     * @param randomStackTraceIndex
      */
-    public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
+    public initialize (callsControllerFunctionName: string): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
-        this.randomStackTraceIndex = randomStackTraceIndex;
-    }
-
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
-        NodeAppender.appendNodeToOptimalBlockScope(
-            stackTraceData,
-            blockScopeNode,
-            this.getNode(),
-            this.randomStackTraceIndex
-        );
     }
 
     /**

+ 0 - 59
src/custom-nodes/console-output-nodes/factory/ConsoleOutputCustomNodesFactory.ts

@@ -1,59 +0,0 @@
-import { injectable, inject } from 'inversify';
-import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
-
-import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
-
-import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
-import { IOptions } from '../../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
-
-import { CustomNodes } from '../../../enums/container/CustomNodes';
-
-import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
-import { NodeAppender } from '../../../node/NodeAppender';
-import { Utils } from '../../../Utils';
-
-@injectable()
-export class ConsoleOutputCustomNodesFactory extends AbstractCustomNodesFactory {
-    /**
-     * @type {TCustomNodeFactory}
-     */
-    private readonly customNodeFactory: TCustomNodeFactory;
-
-    /**
-     * @param customNodeFactory
-     * @param options
-     */
-    constructor (
-        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
-        @inject(ServiceIdentifiers.IOptions) options: IOptions
-    ) {
-        super(options);
-
-        this.customNodeFactory = customNodeFactory;
-    }
-
-    /**
-     * @param stackTraceData
-     * @returns {Map<string, ICustomNode>}
-     */
-    public initializeCustomNodes (stackTraceData: IStackTraceData[]): Map <string, ICustomNode> | undefined {
-        if (!this.options.disableConsoleOutput) {
-            return;
-        }
-
-        const callsControllerFunctionName: string = Utils.getRandomVariableName();
-        const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
-
-        const consoleOutputDisableExpressionNode: ICustomNode = this.customNodeFactory(CustomNodes.ConsoleOutputDisableExpressionNode);
-        const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.NodeCallsControllerFunctionNode);
-
-        consoleOutputDisableExpressionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
-        nodeCallsControllerFunctionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
-
-        return this.syncCustomNodesWithNodesFactory(new Map <string, ICustomNode> ([
-            ['consoleOutputDisableExpressionNode', consoleOutputDisableExpressionNode],
-            ['ConsoleOutputNodeCallsControllerFunctionNode', nodeCallsControllerFunctionNode]
-        ]));
-    }
-}

+ 106 - 0
src/custom-nodes/console-output-nodes/group/ConsoleOutputCustomNodeGroup.ts

@@ -0,0 +1,106 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
+
+import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
+import { TNodeWithBlockStatement } from '../../../types/node/TNodeWithBlockStatement';
+
+import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
+import { IObfuscationEventEmitter } from '../../../interfaces/event-emitters/IObfuscationEventEmitter';
+import { IOptions } from '../../../interfaces/options/IOptions';
+import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
+
+import { initializable } from '../../../decorators/Initializable';
+
+import { CustomNodes } from '../../../enums/container/CustomNodes';
+
+import { AbstractCustomNodeGroup } from '../../AbstractCustomNodeGroup';
+import { NodeAppender } from '../../../node/NodeAppender';
+import { Utils } from '../../../Utils';
+
+@injectable()
+export class ConsoleOutputCustomNodeGroup extends AbstractCustomNodeGroup {
+    /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
+    /**
+     * @type {Map<string, ICustomNode>}
+     */
+    @initializable()
+    protected customNodes: Map <string, ICustomNode>;
+
+    /**
+     * @type {string}
+     */
+    protected readonly groupName: string = 'consoleOutputCustomNodeGroup';
+
+    /**
+     * @type {IObfuscationEventEmitter}
+     */
+    private readonly obfuscationEventEmitter: IObfuscationEventEmitter;
+
+    /**
+     * @param customNodeFactory
+     * @param obfuscationEventEmitter
+     * @param options
+     */
+    constructor (
+        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.IObfuscationEventEmitter) obfuscationEventEmitter: IObfuscationEventEmitter,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(options);
+
+        this.customNodeFactory = customNodeFactory;
+        this.obfuscationEventEmitter = obfuscationEventEmitter;
+    }
+
+    /**
+     * @param stackTraceData
+     */
+    public initialize (stackTraceData: IStackTraceData[]): void {
+        const callsControllerFunctionName: string = Utils.getRandomVariableName();
+        const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
+
+        const consoleOutputDisableExpressionNode: ICustomNode = this.customNodeFactory(CustomNodes.ConsoleOutputDisableExpressionNode);
+        const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.NodeCallsControllerFunctionNode);
+
+        consoleOutputDisableExpressionNode.initialize(callsControllerFunctionName);
+        nodeCallsControllerFunctionNode.initialize(this.appendEvent, callsControllerFunctionName);
+
+        this.customNodes = new Map <string, ICustomNode> ([
+            ['consoleOutputDisableExpressionNode', consoleOutputDisableExpressionNode],
+            ['nodeCallsControllerFunctionNode', nodeCallsControllerFunctionNode]
+        ]);
+
+        if (!this.options.disableConsoleOutput) {
+            return;
+        }
+
+        this.obfuscationEventEmitter.once(
+            this.appendEvent,
+            (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]) => {
+                // consoleOutputDisableExpressionNode append
+                NodeAppender.appendNodeToOptimalBlockScope(
+                    stackTraceData,
+                    blockScopeNode,
+                    consoleOutputDisableExpressionNode.getNode(),
+                    randomStackTraceIndex
+                );
+
+                // nodeCallsControllerFunctionNode append
+                let targetBlockScope: TNodeWithBlockStatement;
+
+                if (stackTraceData.length) {
+                    targetBlockScope = NodeAppender
+                        .getOptimalBlockScope(stackTraceData, randomStackTraceIndex, 1);
+                } else {
+                    targetBlockScope = blockScopeNode;
+                }
+
+                NodeAppender.prependNode(targetBlockScope, nodeCallsControllerFunctionNode.getNode());
+            }
+        );
+    }
+}

+ 0 - 8
src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionNode.ts

@@ -3,11 +3,9 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../../types/node/TNodeWithBlockStatement';
 import { TObfuscationEvent } from '../../../types/event-emitters/TObfuscationEvent';
 
 import { IOptions } from '../../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
 
@@ -47,12 +45,6 @@ export class BinaryExpressionFunctionNode extends AbstractCustomNode {
         this.operator = operator;
     }
 
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {}
-
     /**
      * @returns {string}
      */

+ 0 - 11
src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallNode.ts

@@ -3,11 +3,9 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../../types/node/TNodeWithBlockStatement';
 import { TObfuscationEvent } from '../../../types/event-emitters/TObfuscationEvent';
 
 import { IOptions } from '../../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
 
@@ -16,7 +14,6 @@ import { initializable } from '../../../decorators/Initializable';
 import { ControlFlowStorageCallTemplate } from '../../../templates/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallTemplate';
 
 import { AbstractCustomNode } from '../../AbstractCustomNode';
-import { NodeAppender } from '../../../node/NodeAppender';
 
 @injectable()
 export class ControlFlowStorageCallNode extends AbstractCustomNode {
@@ -76,14 +73,6 @@ export class ControlFlowStorageCallNode extends AbstractCustomNode {
         this.rightValue = rightValue;
     }
 
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
-        NodeAppender.prependNode(blockScopeNode, this.getNode());
-    }
-
     /**
      * @returns {string}
      */

+ 0 - 11
src/custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode.ts

@@ -3,12 +3,10 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
 import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
 
 import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
 import { IStorage } from '../../interfaces/storages/IStorage';
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
@@ -18,7 +16,6 @@ import { initializable } from '../../decorators/Initializable';
 import { ControlFlowStorageTemplate } from '../../templates/custom-nodes/control-flow-storage-nodes/ControlFlowStorageTemplate';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
-import { NodeAppender } from '../../node/NodeAppender';
 
 @injectable()
 export class ControlFlowStorageNode extends AbstractCustomNode {
@@ -57,14 +54,6 @@ export class ControlFlowStorageNode extends AbstractCustomNode {
         this.controlFlowStorageName = controlFlowStorageName;
     }
 
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
-        NodeAppender.prependNode(blockScopeNode, this.getNode());
-    }
-
     /**
      * @returns {string}
      */

+ 0 - 11
src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionCallNode.ts

@@ -3,11 +3,9 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
 import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
 
 import { IOptions } from '../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
@@ -16,7 +14,6 @@ import { initializable } from '../../decorators/Initializable';
 import { DebugProtectionFunctionCallTemplate } from '../../templates/custom-nodes/debug-protection-nodes/debug-protection-function-call-node/DebufProtectionFunctionCallTemplate';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
-import { NodeAppender } from '../../node/NodeAppender';
 
 @injectable()
 export class DebugProtectionFunctionCallNode extends AbstractCustomNode {
@@ -47,14 +44,6 @@ export class DebugProtectionFunctionCallNode extends AbstractCustomNode {
         this.debugProtectionFunctionName = debugProtectionFunctionName;
     }
 
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
-        NodeAppender.appendNode(blockScopeNode, this.getNode());
-    }
-
     /**
      * @returns {string}
      */

+ 0 - 11
src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionIntervalNode.ts

@@ -3,11 +3,9 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
 import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
 
 import { IOptions } from '../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
@@ -16,7 +14,6 @@ import { initializable } from '../../decorators/Initializable';
 import { DebugProtectionFunctionIntervalTemplate } from '../../templates/custom-nodes/debug-protection-nodes/debug-protection-function-interval-node/DebugProtectionFunctionIntervalTemplate';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
-import { NodeAppender } from '../../node/NodeAppender';
 
 @injectable()
 export class DebugProtectionFunctionIntervalNode extends AbstractCustomNode {
@@ -47,14 +44,6 @@ export class DebugProtectionFunctionIntervalNode extends AbstractCustomNode {
         this.debugProtectionFunctionName = debugProtectionFunctionName;
     }
 
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
-        NodeAppender.appendNode(blockScopeNode, this.getNode());
-    }
-
     /**
      * @returns {string}
      */

+ 0 - 15
src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionNode.ts

@@ -3,11 +3,9 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
 import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
 
 import { IOptions } from '../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
@@ -16,8 +14,6 @@ import { initializable } from '../../decorators/Initializable';
 import { DebugProtectionFunctionTemplate } from '../../templates/custom-nodes/debug-protection-nodes/debug-protection-function-node/DebugProtectionFunctionTemplate';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
-import { NodeAppender } from '../../node/NodeAppender';
-import { Utils } from '../../Utils';
 
 @injectable()
 export class DebugProtectionFunctionNode extends AbstractCustomNode {
@@ -48,17 +44,6 @@ export class DebugProtectionFunctionNode extends AbstractCustomNode {
         this.debugProtectionFunctionName = debugProtectionFunctionName;
     }
 
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
-        let programBodyLength: number = blockScopeNode.body.length,
-            randomIndex: number = Utils.getRandomInteger(0, programBodyLength);
-
-        NodeAppender.insertNodeAtIndex(blockScopeNode, this.getNode(), randomIndex);
-    }
-
     /**
      * @returns {string}
      */

+ 0 - 65
src/custom-nodes/debug-protection-nodes/factory/DebugProtectionCustomNodesFactory.ts

@@ -1,65 +0,0 @@
-import { injectable, inject } from 'inversify';
-import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
-
-import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
-
-import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
-import { IOptions } from '../../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
-
-import { CustomNodes } from '../../../enums/container/CustomNodes';
-
-import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
-import { Utils } from '../../../Utils';
-
-@injectable()
-export class DebugProtectionCustomNodesFactory extends AbstractCustomNodesFactory {
-    /**
-     * @type {TCustomNodeFactory}
-     */
-    private readonly customNodeFactory: TCustomNodeFactory;
-
-    /**
-     * @param customNodeFactory
-     * @param options
-     */
-    constructor (
-        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
-        @inject(ServiceIdentifiers.IOptions) options: IOptions
-    ) {
-        super(options);
-
-        this.customNodeFactory = customNodeFactory;
-    }
-
-    /**
-     * @param stackTraceData
-     * @returns {Map<string, ICustomNode>}
-     */
-    public initializeCustomNodes (stackTraceData: IStackTraceData[]): Map <string, ICustomNode> | undefined {
-        if (!this.options.debugProtection) {
-            return;
-        }
-
-        const debugProtectionFunctionName: string = Utils.getRandomVariableName();
-
-        const debugProtectionFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.DebugProtectionFunctionNode);
-        const debugProtectionFunctionCallNode: ICustomNode = this.customNodeFactory(CustomNodes.DebugProtectionFunctionCallNode);
-        const debugProtectionFunctionIntervalNode: ICustomNode = this.customNodeFactory(CustomNodes.DebugProtectionFunctionIntervalNode);
-
-        debugProtectionFunctionNode.initialize(debugProtectionFunctionName);
-        debugProtectionFunctionCallNode.initialize(debugProtectionFunctionName);
-        debugProtectionFunctionIntervalNode.initialize(debugProtectionFunctionName);
-
-        const customNodes: Map <string, ICustomNode> = new Map <string, ICustomNode> ([
-            ['debugProtectionFunctionNode', debugProtectionFunctionNode],
-            ['debugProtectionFunctionCallNode', debugProtectionFunctionCallNode]
-        ]);
-
-        if (this.options.debugProtectionInterval) {
-            customNodes.set('debugProtectionFunctionIntervalNode', debugProtectionFunctionIntervalNode);
-        }
-
-        return this.syncCustomNodesWithNodesFactory(customNodes);
-    }
-}

+ 114 - 0
src/custom-nodes/debug-protection-nodes/group/DebugProtectionCustomNodeGroup.ts

@@ -0,0 +1,114 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
+
+import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
+import { TNodeWithBlockStatement } from '../../../types/node/TNodeWithBlockStatement';
+
+import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
+import { IObfuscationEventEmitter } from '../../../interfaces/event-emitters/IObfuscationEventEmitter';
+import { IOptions } from '../../../interfaces/options/IOptions';
+import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
+
+import { initializable } from '../../../decorators/Initializable';
+
+import { CustomNodes } from '../../../enums/container/CustomNodes';
+
+import { AbstractCustomNodeGroup } from '../../AbstractCustomNodeGroup';
+import { NodeAppender } from '../../../node/NodeAppender';
+import { Utils } from '../../../Utils';
+
+@injectable()
+export class DebugProtectionCustomNodeGroup extends AbstractCustomNodeGroup {
+    /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
+    /**
+     * @type {Map<string, ICustomNode>}
+     */
+    @initializable()
+    protected customNodes: Map <string, ICustomNode>;
+
+    /**
+     * @type {string}
+     */
+    protected readonly groupName: string = 'debugProtectionCustomNodeGroup';
+
+    /**
+     * @type {IObfuscationEventEmitter}
+     */
+    private readonly obfuscationEventEmitter: IObfuscationEventEmitter;
+
+    /**
+     * @param customNodeFactory
+     * @param obfuscationEventEmitter
+     * @param options
+     */
+    constructor (
+        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.IObfuscationEventEmitter) obfuscationEventEmitter: IObfuscationEventEmitter,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(options);
+
+        this.customNodeFactory = customNodeFactory;
+        this.obfuscationEventEmitter = obfuscationEventEmitter;
+    }
+
+    /**
+     * @param stackTraceData
+     */
+    public initialize (stackTraceData: IStackTraceData[]): void {
+        const debugProtectionFunctionName: string = Utils.getRandomVariableName();
+
+        const debugProtectionFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.DebugProtectionFunctionNode);
+        const debugProtectionFunctionCallNode: ICustomNode = this.customNodeFactory(CustomNodes.DebugProtectionFunctionCallNode);
+        const debugProtectionFunctionIntervalNode: ICustomNode = this.customNodeFactory(CustomNodes.DebugProtectionFunctionIntervalNode);
+
+        debugProtectionFunctionNode.initialize(debugProtectionFunctionName);
+        debugProtectionFunctionCallNode.initialize(debugProtectionFunctionName);
+        debugProtectionFunctionIntervalNode.initialize(debugProtectionFunctionName);
+
+        const customNodes: Map <string, ICustomNode> = new Map <string, ICustomNode> ([
+            ['debugProtectionFunctionNode', debugProtectionFunctionNode],
+            ['debugProtectionFunctionCallNode', debugProtectionFunctionCallNode]
+        ]);
+
+        this.obfuscationEventEmitter.once(
+            this.appendEvent,
+            (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]) => {
+                if (!this.options.debugProtection) {
+                    return;
+                }
+
+                // debugProtectionFunctionNode append
+                NodeAppender.appendNode(blockScopeNode, debugProtectionFunctionNode.getNode());
+
+                // debugProtectionFunctionCallNode append
+                NodeAppender.appendNode(blockScopeNode, debugProtectionFunctionCallNode.getNode());
+            }
+        );
+
+        if (this.options.debugProtectionInterval) {
+            customNodes.set('debugProtectionFunctionIntervalNode', debugProtectionFunctionIntervalNode);
+
+            this.obfuscationEventEmitter.once(
+                this.appendEvent,
+                (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]) => {
+                    if (!this.options.debugProtection) {
+                        return;
+                    }
+
+                    // debugProtectionFunctionIntervalNode append
+                    let programBodyLength: number = blockScopeNode.body.length,
+                        randomIndex: number = Utils.getRandomInteger(0, programBodyLength);
+
+                    NodeAppender.insertNodeAtIndex(blockScopeNode, debugProtectionFunctionIntervalNode.getNode(), randomIndex);
+                }
+            );
+        }
+
+        this.customNodes = customNodes;
+    }
+}

+ 1 - 25
src/custom-nodes/domain-lock-nodes/DomainLockNode.ts

@@ -3,11 +3,9 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
 import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
 
 import { IOptions } from '../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
@@ -16,7 +14,6 @@ import { initializable } from '../../decorators/Initializable';
 import { DomainLockNodeTemplate } from '../../templates/custom-nodes/domain-lock-nodes/domain-lock-node/DomainLockNodeTemplate';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
-import { NodeAppender } from '../../node/NodeAppender';
 import { Utils } from '../../Utils';
 
 @injectable()
@@ -32,12 +29,6 @@ export class DomainLockNode extends AbstractCustomNode {
     @initializable()
     protected callsControllerFunctionName: string;
 
-    /**
-     * @type {number}
-     */
-    @initializable()
-    protected randomStackTraceIndex: number;
-
     /**
      * @param options
      */
@@ -49,24 +40,9 @@ export class DomainLockNode extends AbstractCustomNode {
 
     /**
      * @param callsControllerFunctionName
-     * @param randomStackTraceIndex
      */
-    public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
+    public initialize (callsControllerFunctionName: string): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
-        this.randomStackTraceIndex = randomStackTraceIndex;
-    }
-
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
-        NodeAppender.appendNodeToOptimalBlockScope(
-            stackTraceData,
-            blockScopeNode,
-            this.getNode(),
-            this.randomStackTraceIndex
-        );
     }
 
     /**

+ 0 - 59
src/custom-nodes/domain-lock-nodes/factory/DomainLockCustomNodesFactory.ts

@@ -1,59 +0,0 @@
-import { injectable, inject } from 'inversify';
-import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
-
-import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
-
-import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
-import { IOptions } from '../../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
-
-import { CustomNodes } from '../../../enums/container/CustomNodes';
-
-import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
-import { NodeAppender } from '../../../node/NodeAppender';
-import { Utils } from '../../../Utils';
-
-@injectable()
-export class DomainLockCustomNodesFactory extends AbstractCustomNodesFactory {
-    /**
-     * @type {TCustomNodeFactory}
-     */
-    private readonly customNodeFactory: TCustomNodeFactory;
-
-    /**
-     * @param customNodeFactory
-     * @param options
-     */
-    constructor (
-        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
-        @inject(ServiceIdentifiers.IOptions) options: IOptions
-    ) {
-        super(options);
-
-        this.customNodeFactory = customNodeFactory;
-    }
-
-    /**
-     * @param stackTraceData
-     * @returns {Map<string, ICustomNode>}
-     */
-    public initializeCustomNodes (stackTraceData: IStackTraceData[]): Map <string, ICustomNode> | undefined {
-        if (!this.options.domainLock.length) {
-            return;
-        }
-
-        const callsControllerFunctionName: string = Utils.getRandomVariableName();
-        const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
-
-        const domainLockNode: ICustomNode = this.customNodeFactory(CustomNodes.DomainLockNode);
-        const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.NodeCallsControllerFunctionNode);
-
-        domainLockNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
-        nodeCallsControllerFunctionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
-
-        return this.syncCustomNodesWithNodesFactory(new Map <string, ICustomNode> ([
-            ['DomainLockNode', domainLockNode],
-            ['DomainLockNodeCallsControllerFunctionNode', nodeCallsControllerFunctionNode]
-        ]));
-    }
-}

+ 106 - 0
src/custom-nodes/domain-lock-nodes/group/DomainLockCustomNodeGroup.ts

@@ -0,0 +1,106 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
+
+import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
+import { TNodeWithBlockStatement } from '../../../types/node/TNodeWithBlockStatement';
+
+import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
+import { IObfuscationEventEmitter } from '../../../interfaces/event-emitters/IObfuscationEventEmitter';
+import { IOptions } from '../../../interfaces/options/IOptions';
+import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
+
+import { initializable } from '../../../decorators/Initializable';
+
+import { CustomNodes } from '../../../enums/container/CustomNodes';
+
+import { AbstractCustomNodeGroup } from '../../AbstractCustomNodeGroup';
+import { NodeAppender } from '../../../node/NodeAppender';
+import { Utils } from '../../../Utils';
+
+@injectable()
+export class DomainLockCustomNodeGroup extends AbstractCustomNodeGroup {
+    /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
+    /**
+     * @type {Map<string, ICustomNode>}
+     */
+    @initializable()
+    protected customNodes: Map <string, ICustomNode>;
+
+    /**
+     * @type {string}
+     */
+    protected readonly groupName: string = 'domainLockCustomNodeGroup';
+
+    /**
+     * @type {IObfuscationEventEmitter}
+     */
+    private readonly obfuscationEventEmitter: IObfuscationEventEmitter;
+
+    /**
+     * @param customNodeFactory
+     * @param obfuscationEventEmitter
+     * @param options
+     */
+    constructor (
+        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.IObfuscationEventEmitter) obfuscationEventEmitter: IObfuscationEventEmitter,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(options);
+
+        this.customNodeFactory = customNodeFactory;
+        this.obfuscationEventEmitter = obfuscationEventEmitter;
+    }
+
+    /**
+     * @param stackTraceData
+     */
+    public initialize (stackTraceData: IStackTraceData[]): void {
+        const callsControllerFunctionName: string = Utils.getRandomVariableName();
+        const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
+
+        const domainLockNode: ICustomNode = this.customNodeFactory(CustomNodes.DomainLockNode);
+        const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.NodeCallsControllerFunctionNode);
+
+        domainLockNode.initialize(callsControllerFunctionName);
+        nodeCallsControllerFunctionNode.initialize(this.appendEvent, callsControllerFunctionName);
+
+        this.customNodes = new Map <string, ICustomNode> ([
+            ['domainLockNode', domainLockNode],
+            ['nodeCallsControllerFunctionNode', nodeCallsControllerFunctionNode]
+        ]);
+
+        if (!this.options.domainLock.length) {
+            return;
+        }
+
+        this.obfuscationEventEmitter.once(
+            this.appendEvent,
+            (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]) => {
+                // domainLockNode append
+                NodeAppender.appendNodeToOptimalBlockScope(
+                    stackTraceData,
+                    blockScopeNode,
+                    domainLockNode.getNode(),
+                    randomStackTraceIndex
+                );
+
+                // nodeCallsControllerFunctionNode append
+                let targetBlockScope: TNodeWithBlockStatement;
+
+                if (stackTraceData.length) {
+                    targetBlockScope = NodeAppender
+                        .getOptimalBlockScope(stackTraceData, randomStackTraceIndex, 1);
+                } else {
+                    targetBlockScope = blockScopeNode;
+                }
+
+                NodeAppender.prependNode(targetBlockScope, nodeCallsControllerFunctionNode.getNode());
+            }
+        );
+    }
+}

+ 5 - 30
src/custom-nodes/node-calls-controller-nodes/NodeCallsControllerFunctionNode.ts

@@ -3,11 +3,9 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
 import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
 
 import { IOptions } from '../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
@@ -19,14 +17,14 @@ import { NO_CUSTOM_NODES_PRESET } from '../../preset-options/NoCustomNodesPreset
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { JavaScriptObfuscator } from '../../JavaScriptObfuscator';
-import { NodeAppender } from '../../node/NodeAppender';
 
 @injectable()
 export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
     /**
      * @type {TObfuscationEvent}
      */
-    protected readonly appendEvent: TObfuscationEvent = ObfuscationEvents.BeforeObfuscation;
+    @initializable()
+    private appendEvent: TObfuscationEvent;
 
     /**
      * @type {string}
@@ -34,12 +32,6 @@ export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
     @initializable()
     protected callsControllerFunctionName: string;
 
-    /**
-     * @type {number}
-     */
-    @initializable()
-    protected randomStackTraceIndex: number;
-
     /**
      * @param options
      */
@@ -50,29 +42,12 @@ export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
     }
 
     /**
+     * @param appendEvent
      * @param callsControllerFunctionName
-     * @param randomStackTraceIndex
      */
-    public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
+    public initialize (appendEvent: TObfuscationEvent, callsControllerFunctionName: string): void {
+        this.appendEvent = appendEvent;
         this.callsControllerFunctionName = callsControllerFunctionName;
-        this.randomStackTraceIndex = randomStackTraceIndex;
-    }
-
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
-        let targetBlockScope: TNodeWithBlockStatement;
-
-        if (stackTraceData.length) {
-            targetBlockScope = NodeAppender
-                .getOptimalBlockScope(stackTraceData, this.randomStackTraceIndex, 1);
-        } else {
-            targetBlockScope = blockScopeNode;
-        }
-
-        NodeAppender.prependNode(targetBlockScope, this.getNode());
     }
 
     /**

+ 1 - 34
src/custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode.ts

@@ -3,13 +3,7 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
-import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
-
 import { IOptions } from '../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
-
-import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
 import { initializable } from '../../decorators/Initializable';
 
@@ -18,29 +12,17 @@ import { NO_CUSTOM_NODES_PRESET } from '../../preset-options/NoCustomNodesPreset
 import { SelfDefendingTemplate } from '../../templates/custom-nodes/self-defending-nodes/self-defending-unicode-node/SelfDefendingTemplate';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
-import { NodeAppender } from '../../node/NodeAppender';
 import { JavaScriptObfuscator } from '../../JavaScriptObfuscator';
 import { Utils } from '../../Utils';
 
 @injectable()
 export class SelfDefendingUnicodeNode extends AbstractCustomNode {
-    /**
-     * @type {TObfuscationEvent}
-     */
-    protected readonly appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
-
     /**
      * @type {string}
      */
     @initializable()
     protected callsControllerFunctionName: string;
 
-    /**
-     * @type {number}
-     */
-    @initializable()
-    protected randomStackTraceIndex: number;
-
     /**
      * @param options
      */
@@ -52,24 +34,9 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
 
     /**
      * @param callsControllerFunctionName
-     * @param randomStackTraceIndex
      */
-    public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
+    public initialize (callsControllerFunctionName: string): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
-        this.randomStackTraceIndex = randomStackTraceIndex;
-    }
-
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
-        NodeAppender.appendNodeToOptimalBlockScope(
-            stackTraceData,
-            blockScopeNode,
-            this.getNode(),
-            this.randomStackTraceIndex
-        );
     }
 
     /**

+ 0 - 66
src/custom-nodes/self-defending-nodes/factory/SelfDefendingCustomNodesFactory.ts

@@ -1,66 +0,0 @@
-import { injectable, inject } from 'inversify';
-import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
-
-import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
-import { TObfuscationEvent } from '../../../types/event-emitters/TObfuscationEvent';
-
-import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
-import { IOptions } from '../../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
-
-import { CustomNodes } from '../../../enums/container/CustomNodes';
-import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
-
-import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
-import { NodeAppender } from '../../../node/NodeAppender';
-import { Utils } from '../../../Utils';
-
-@injectable()
-export class SelfDefendingCustomNodesFactory extends AbstractCustomNodesFactory {
-    /**
-     * @type {TObfuscationEvent}
-     */
-    protected appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
-
-    /**
-     * @type {TCustomNodeFactory}
-     */
-    private readonly customNodeFactory: TCustomNodeFactory;
-
-    /**
-     * @param customNodeFactory
-     * @param options
-     */
-    constructor (
-        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
-        @inject(ServiceIdentifiers.IOptions) options: IOptions
-    ) {
-        super(options);
-
-        this.customNodeFactory = customNodeFactory;
-    }
-
-    /**
-     * @param stackTraceData
-     * @returns {Map<string, ICustomNode>}
-     */
-    public initializeCustomNodes (stackTraceData: IStackTraceData[]): Map <string, ICustomNode> | undefined {
-        if (!this.options.selfDefending) {
-            return;
-        }
-
-        const callsControllerFunctionName: string = Utils.getRandomVariableName();
-        const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
-
-        const selfDefendingUnicodeNode: ICustomNode = this.customNodeFactory(CustomNodes.SelfDefendingUnicodeNode);
-        const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.NodeCallsControllerFunctionNode);
-
-        selfDefendingUnicodeNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
-        nodeCallsControllerFunctionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
-
-        return this.syncCustomNodesWithNodesFactory(new Map <string, ICustomNode> ([
-            ['selfDefendingUnicodeNode', selfDefendingUnicodeNode],
-            ['SelfDefendingNodeCallsControllerFunctionNode', nodeCallsControllerFunctionNode]
-        ]));
-    }
-}

+ 113 - 0
src/custom-nodes/self-defending-nodes/group/SelfDefendingCustomNodeGroup.ts

@@ -0,0 +1,113 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
+
+import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
+import { TObfuscationEvent } from '../../../types/event-emitters/TObfuscationEvent';
+import { TNodeWithBlockStatement } from '../../../types/node/TNodeWithBlockStatement';
+
+import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
+import { IObfuscationEventEmitter } from '../../../interfaces/event-emitters/IObfuscationEventEmitter';
+import { IOptions } from '../../../interfaces/options/IOptions';
+import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
+
+import { initializable } from '../../../decorators/Initializable';
+
+import { CustomNodes } from '../../../enums/container/CustomNodes';
+import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
+
+import { AbstractCustomNodeGroup } from '../../AbstractCustomNodeGroup';
+import { NodeAppender } from '../../../node/NodeAppender';
+import { Utils } from '../../../Utils';
+
+@injectable()
+export class SelfDefendingCustomNodeGroup extends AbstractCustomNodeGroup {
+    /**
+     * @type {TObfuscationEvent}
+     */
+    protected appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
+
+    /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
+    /**
+     * @type {Map<string, ICustomNode>}
+     */
+    @initializable()
+    protected customNodes: Map <string, ICustomNode>;
+
+    /**
+     * @type {string}
+     */
+    protected readonly groupName: string = 'selfDefendingCustomNodeGroup';
+
+    /**
+     * @type {IObfuscationEventEmitter}
+     */
+    private readonly obfuscationEventEmitter: IObfuscationEventEmitter;
+
+    /**
+     * @param customNodeFactory
+     * @param obfuscationEventEmitter
+     * @param options
+     */
+    constructor (
+        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.IObfuscationEventEmitter) obfuscationEventEmitter: IObfuscationEventEmitter,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(options);
+
+        this.customNodeFactory = customNodeFactory;
+        this.obfuscationEventEmitter = obfuscationEventEmitter;
+    }
+
+    /**
+     * @param stackTraceData
+     */
+    public initialize (stackTraceData: IStackTraceData[]): void {
+        const callsControllerFunctionName: string = Utils.getRandomVariableName();
+        const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
+
+        const selfDefendingUnicodeNode: ICustomNode = this.customNodeFactory(CustomNodes.SelfDefendingUnicodeNode);
+        const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.NodeCallsControllerFunctionNode);
+
+        selfDefendingUnicodeNode.initialize(callsControllerFunctionName);
+        nodeCallsControllerFunctionNode.initialize(this.appendEvent, callsControllerFunctionName);
+
+        this.customNodes = new Map <string, ICustomNode> ([
+            ['selfDefendingUnicodeNode', selfDefendingUnicodeNode],
+            ['nodeCallsControllerFunctionNode', nodeCallsControllerFunctionNode]
+        ]);
+
+        if (!this.options.selfDefending) {
+            return;
+        }
+
+        this.obfuscationEventEmitter.once(
+            this.appendEvent,
+            (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]) => {
+                // selfDefendingUnicodeNode append
+                NodeAppender.appendNodeToOptimalBlockScope(
+                    stackTraceData,
+                    blockScopeNode,
+                    selfDefendingUnicodeNode.getNode(),
+                    randomStackTraceIndex
+                );
+
+                // nodeCallsControllerFunctionNode append
+                let targetBlockScope: TNodeWithBlockStatement;
+
+                if (stackTraceData.length) {
+                    targetBlockScope = NodeAppender
+                        .getOptimalBlockScope(stackTraceData, randomStackTraceIndex, 1);
+                } else {
+                    targetBlockScope = blockScopeNode;
+                }
+
+                NodeAppender.prependNode(targetBlockScope, nodeCallsControllerFunctionNode.getNode());
+            }
+        );
+    }
+}

+ 0 - 22
src/custom-nodes/string-array-nodes/StringArrayCallsWrapper.ts

@@ -3,16 +3,12 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
-import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
 import { TStatement } from '../../types/node/TStatement';
 
 import { ICustomNodeWithIdentifier } from '../../interfaces/custom-nodes/ICustomNodeWithIdentifier';
 import { IOptions } from '../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
 import { IStorage } from '../../interfaces/storages/IStorage';
 
-import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 import { StringArrayEncoding } from '../../enums/StringArrayEncoding';
 
 import { initializable } from '../../decorators/Initializable';
@@ -28,15 +24,9 @@ import { StringArrayRc4DecodeNodeTemplate } from '../../templates/custom-nodes/s
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { JavaScriptObfuscator } from '../../JavaScriptObfuscator';
-import { NodeAppender } from '../../node/NodeAppender';
 
 @injectable()
 export class StringArrayCallsWrapper extends AbstractCustomNode implements ICustomNodeWithIdentifier {
-    /**
-     * @type {TObfuscationEvent}
-     */
-    protected readonly appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
-
     /**
      * @type {IStorage <string>}
      */
@@ -79,18 +69,6 @@ export class StringArrayCallsWrapper extends AbstractCustomNode implements ICust
         this.stringArrayCallsWrapperName = stringArrayCallsWrapperName;
     }
 
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
-        if (!this.stringArray.getLength()) {
-            return;
-        }
-
-        NodeAppender.insertNodeAtIndex(blockScopeNode, this.getNode(), 1);
-    }
-
     /**
      * @returns {string}
      */

+ 0 - 23
src/custom-nodes/string-array-nodes/StringArrayNode.ts

@@ -3,23 +3,17 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
-import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
 import { TStatement } from '../../types/node/TStatement';
 
 import { ICustomNodeWithData } from '../../interfaces/custom-nodes/ICustomNodeWithData';
 import { IOptions } from '../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
 import { IStorage } from '../../interfaces/storages/IStorage';
 
-import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
-
 import { initializable } from '../../decorators/Initializable';
 
 import { StringArrayTemplate } from '../../templates/custom-nodes/string-array-nodes/string-array-node/StringArrayTemplate';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
-import { NodeAppender } from '../../node/NodeAppender';
 import { StringArrayStorage } from '../../storages/string-array/StringArrayStorage';
 
 @injectable()
@@ -29,11 +23,6 @@ export class StringArrayNode extends AbstractCustomNode implements ICustomNodeWi
      */
     public static ARRAY_RANDOM_LENGTH: number = 4;
 
-    /**
-     * @type {TObfuscationEvent}
-     */
-    protected readonly appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
-
     /**
      * @type {IStorage <string>}
      */
@@ -76,18 +65,6 @@ export class StringArrayNode extends AbstractCustomNode implements ICustomNodeWi
         this.stringArrayRotateValue = stringArrayRotateValue;
     }
 
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
-        if (!this.stringArray.getLength()) {
-            return;
-        }
-
-        NodeAppender.prependNode(blockScopeNode, this.getNode());
-    }
-
     /**
      * @returns {string}
      */

+ 0 - 24
src/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.ts

@@ -3,15 +3,9 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
-import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
-import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
-
 import { IOptions } from '../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
 import { IStorage } from '../../interfaces/storages/IStorage';
 
-import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
-
 import { initializable } from '../../decorators/Initializable';
 
 import { NO_CUSTOM_NODES_PRESET } from '../../preset-options/NoCustomNodesPreset';
@@ -21,16 +15,10 @@ import { StringArrayRotateFunctionTemplate } from '../../templates/custom-nodes/
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { JavaScriptObfuscator } from '../../JavaScriptObfuscator';
-import { NodeAppender } from '../../node/NodeAppender';
 import { Utils } from '../../Utils';
 
 @injectable()
 export class StringArrayRotateFunctionNode extends AbstractCustomNode {
-    /**
-     * @type {TObfuscationEvent}
-     */
-    protected readonly appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
-
     /**
      * @type {IStorage <string>}
      */
@@ -73,18 +61,6 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
         this.stringArrayRotateValue = stringArrayRotateValue;
     }
 
-    /**
-     * @param blockScopeNode
-     * @param stackTraceData
-     */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
-        if (!this.stringArray.getLength()) {
-            return;
-        }
-
-        NodeAppender.insertNodeAtIndex(blockScopeNode, this.getNode(), 1);
-    }
-
     /**
      * @returns {string}
      */

+ 56 - 12
src/custom-nodes/string-array-nodes/factory/StringArrayCustomNodesFactory.ts → src/custom-nodes/string-array-nodes/group/StringArrayCustomNodeGroup.ts

@@ -2,24 +2,29 @@ import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
+import { TNodeWithBlockStatement } from '../../../types/node/TNodeWithBlockStatement';
 import { TObfuscationEvent } from '../../../types/event-emitters/TObfuscationEvent';
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
+import { IObfuscationEventEmitter } from '../../../interfaces/event-emitters/IObfuscationEventEmitter';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 import { IStorage } from '../../../interfaces/storages/IStorage';
 
+import { initializable } from '../../../decorators/Initializable';
+
 import { CustomNodes } from '../../../enums/container/CustomNodes';
 import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
 
 import { StringArrayNode } from '../StringArrayNode';
 
-import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
+import { AbstractCustomNodeGroup } from '../../AbstractCustomNodeGroup';
+import { NodeAppender } from '../../../node/NodeAppender';
 import { StringArrayStorage } from '../../../storages/string-array/StringArrayStorage';
 import { Utils } from '../../../Utils';
 
 @injectable()
-export class StringArrayCustomNodesFactory extends AbstractCustomNodesFactory {
+export class StringArrayCustomNodeGroup extends AbstractCustomNodeGroup {
     /**
      * @type {TObfuscationEvent}
      */
@@ -30,28 +35,42 @@ export class StringArrayCustomNodesFactory extends AbstractCustomNodesFactory {
      */
     private readonly customNodeFactory: TCustomNodeFactory;
 
+    /**
+     * @type {Map<string, ICustomNode>}
+     */
+    @initializable()
+    protected customNodes: Map <string, ICustomNode>;
+
+    /**
+     * @type {string}
+     */
+    protected readonly groupName: string = 'stringArrayCustomNodeGroup';
+
+    /**
+     * @type {IObfuscationEventEmitter}
+     */
+    private readonly obfuscationEventEmitter: IObfuscationEventEmitter;
+
     /**
      * @param customNodeFactory
+     * @param obfuscationEventEmitter
      * @param options
      */
     constructor (
         @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.IObfuscationEventEmitter) obfuscationEventEmitter: IObfuscationEventEmitter,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
 
         this.customNodeFactory = customNodeFactory;
+        this.obfuscationEventEmitter = obfuscationEventEmitter;
     }
 
     /**
      * @param stackTraceData
-     * @returns {Map<string, ICustomNode>}
      */
-    public initializeCustomNodes (stackTraceData: IStackTraceData[]): Map <string, ICustomNode> | undefined {
-        if (!this.options.stringArray) {
-            return;
-        }
-
+    public initialize (stackTraceData: IStackTraceData[]): void {
         const stringArray: IStorage <string> = new StringArrayStorage();
 
         const stringArrayNode: ICustomNode = this.customNodeFactory(CustomNodes.StringArrayNode);
@@ -73,15 +92,40 @@ export class StringArrayCustomNodesFactory extends AbstractCustomNodesFactory {
         stringArrayCallsWrapper.initialize(stringArray, stringArrayName, stringArrayCallsWrapperName);
         stringArrayRotateFunctionNode.initialize(stringArray, stringArrayName, stringArrayRotateValue);
 
-        const customNodes: Map <string, ICustomNode> = new Map <string, ICustomNode> ([
+        this.customNodes = new Map <string, ICustomNode> ([
             ['stringArrayNode', stringArrayNode],
             ['stringArrayCallsWrapper', stringArrayCallsWrapper]
         ]);
 
+        this.obfuscationEventEmitter.once(
+            this.appendEvent,
+            (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]) => {
+                if (!this.options.stringArray || !stringArray.getLength()) {
+                    return;
+                }
+
+                // stringArrayNode append
+                NodeAppender.prependNode(blockScopeNode, stringArrayNode.getNode());
+
+                // stringArrayCallsWrapper append
+                NodeAppender.insertNodeAtIndex(blockScopeNode, stringArrayCallsWrapper.getNode(), 1);
+            }
+        );
+
         if (this.options.rotateStringArray) {
-            customNodes.set('stringArrayRotateFunctionNode', stringArrayRotateFunctionNode);
+            this.customNodes.set('stringArrayRotateFunctionNode', stringArrayRotateFunctionNode);
+
+            this.obfuscationEventEmitter.once(
+                this.appendEvent,
+                (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]) => {
+                    if (!this.options.stringArray || !stringArray.getLength()) {
+                        return;
+                    }
+
+                    // stringArrayRotateFunctionNode append
+                    NodeAppender.insertNodeAtIndex(blockScopeNode, stringArrayRotateFunctionNode.getNode(), 1);
+                }
+            );
         }
-
-        return this.syncCustomNodesWithNodesFactory(customNodes);
     }
 }

+ 7 - 0
src/enums/container/CustomNodeGroups.ts

@@ -0,0 +1,7 @@
+export enum CustomNodeGroups {
+    ConsoleOutputCustomNodeGroup,
+    DebugProtectionCustomNodeGroup,
+    DomainLockCustomNodeGroup,
+    SelfDefendingCustomNodeGroup,
+    StringArrayCustomNodeGroup
+}

+ 0 - 7
src/enums/container/CustomNodesFactories.ts

@@ -1,7 +0,0 @@
-export enum CustomNodesFactories {
-    ConsoleOutputCustomNodesFactory,
-    DebugProtectionCustomNodesFactory,
-    DomainLockCustomNodesFactory,
-    SelfDefendingCustomNodesFactory,
-    StringArrayCustomNodesFactory
-}

+ 1 - 4
src/interfaces/IObfuscator.d.ts

@@ -1,8 +1,5 @@
 import * as ESTree from 'estree';
 
-import { ICustomNode } from './custom-nodes/ICustomNode';
-import { IStorage } from './storages/IStorage';
-
 export interface IObfuscator {
-    obfuscateAstTree (astTree: ESTree.Program, customNodesStorage: IStorage<ICustomNode>): ESTree.Program;
+    obfuscateAstTree (astTree: ESTree.Program): ESTree.Program;
 }

+ 9 - 0
src/interfaces/container/IInversifyContainerFacade.d.ts

@@ -1,5 +1,14 @@
 import { interfaces } from 'inversify';
 
 export interface IInversifyContainerFacade {
+    /**
+     * @param serviceIdentifier
+     */
     get <T> (serviceIdentifier: interfaces.ServiceIdentifier<T>): T;
+
+    /**
+     * @param serviceIdentifier
+     * @param named
+     */
+    getNamed <T> (serviceIdentifier: interfaces.ServiceIdentifier<T>, named: string | number | symbol): T;
 }

+ 0 - 20
src/interfaces/custom-nodes/ICustomNode.d.ts

@@ -1,23 +1,8 @@
-import * as ESTree from 'estree';
-
-import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
-import { IStackTraceData } from '../stack-trace-analyzer/IStackTraceData';
 import { TStatement } from '../../types/node/TStatement';
 
 import { IInitializable } from '../IInitializable';
 
 export interface ICustomNode extends IInitializable {
-    /**
-     * @param astTree
-     * @param stackTraceData
-     */
-    appendNode (astTree: ESTree.Node, stackTraceData: IStackTraceData[]): void;
-
-    /**
-     * @returns {TObfuscationEvent}
-     */
-    getAppendEvent (): TObfuscationEvent;
-
     /**
      * @returns {string}
      */
@@ -27,9 +12,4 @@ export interface ICustomNode extends IInitializable {
      * @returns ESTree.Node[]
      */
     getNode (): TStatement[];
-
-    /**
-     * @param appendState
-     */
-    setAppendEvent (appendState: TObfuscationEvent): void;
 }

+ 20 - 0
src/interfaces/custom-nodes/ICustomNodeGroup.d.ts

@@ -0,0 +1,20 @@
+import { ICustomNode } from './ICustomNode';
+import { IInitializable } from '../IInitializable';
+import { IStackTraceData } from '../stack-trace-analyzer/IStackTraceData';
+
+export interface ICustomNodeGroup extends IInitializable {
+    /**
+     * @type {Map <string, ICustomNode>}
+     */
+    getCustomNodes (): Map <string, ICustomNode>;
+
+    /**
+     * @type {string}
+     */
+    getGroupName (): string;
+
+    /**
+     * @returns {Map <string, ICustomNode> | undefined}
+     */
+    initialize (stackTraceData: IStackTraceData[]): void;
+}

+ 0 - 11
src/interfaces/custom-nodes/ICustomNodesFactory.d.ts

@@ -1,11 +0,0 @@
-import { EventEmitter } from 'events';
-
-import { ICustomNode } from './ICustomNode';
-import { IStackTraceData } from '../stack-trace-analyzer/IStackTraceData';
-
-export interface ICustomNodesFactory {
-    /**
-     * @returns {Map <string, ICustomNode> | undefined}
-     */
-    initializeCustomNodes (stackTraceData: IStackTraceData[]): Map <string, ICustomNode> | undefined;
-}

+ 0 - 10
src/node-transformers/AbstractNodeTransformer.ts

@@ -2,33 +2,23 @@ import { injectable, inject } from 'inversify';
 
 import * as ESTree from 'estree';
 
-import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
 import { INodeTransformer } from '../interfaces/node-transformers/INodeTransformer';
 import { IOptions } from '../interfaces/options/IOptions';
-import { IStorage } from '../interfaces/storages/IStorage';
 import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
 
 @injectable()
 export abstract class AbstractNodeTransformer implements INodeTransformer {
-    /**
-     * @type IStorage<ICustomNode>
-     */
-    protected readonly customNodesStorage: IStorage<ICustomNode>;
-
     /**
      * @type {IOptions}
      */
     protected readonly options: IOptions;
 
     /**
-     * @param customNodesStorage
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        this.customNodesStorage = customNodesStorage;
         this.options = options;
     }
 

+ 1 - 4
src/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.ts

@@ -31,14 +31,12 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
     ]);
 
     /**
-     * @param customNodesStorage
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
     }
 
     /**
@@ -69,7 +67,6 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
                 }
 
                 const controlFlowStorageCallCustomNode: ICustomNode | undefined = new controlFlowReplacer(
-                    this.customNodesStorage,
                     this.options
                 ).replace(node, parentNode, controlFlowStorage, controlFlowStorageCustomNodeName);
 

+ 0 - 8
src/node-transformers/node-control-flow-transformers/control-flow-replacers/AbstractControlFlowReplacer.ts

@@ -12,25 +12,17 @@ import { Utils } from '../../../Utils';
 
 @injectable()
 export abstract class AbstractControlFlowReplacer implements IControlFlowReplacer {
-    /**
-     * @type IStorage<ICustomNode>
-     */
-    protected readonly customNodesStorage: IStorage<ICustomNode>;
-
     /**
      * @type {IOptions}
      */
     protected readonly options : IOptions;
 
     /**
-     * @param customNodesStorage
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        this.customNodesStorage = customNodesStorage;
         this.options = options;
     }
 

+ 1 - 3
src/node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.ts

@@ -15,14 +15,12 @@ import { ControlFlowStorageCallNode } from '../../../custom-nodes/control-flow-r
 @injectable()
 export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowReplacer {
     /**
-     * @param customNodesStorage
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
     }
 
     /**

+ 1 - 5
src/node-transformers/node-obfuscators/CatchClauseObfuscator.ts

@@ -4,10 +4,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
-import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IReplacer } from '../../interfaces/node-transformers/IReplacer';
-import { IStorage } from '../../interfaces/storages/IStorage';
 
 import { NodeObfuscatorsReplacers } from '../../enums/container/NodeObfuscatorsReplacers';
 import { NodeType } from '../../enums/NodeType';
@@ -34,16 +32,14 @@ export class CatchClauseObfuscator extends AbstractNodeTransformer {
     private readonly identifierReplacer: IReplacer & IdentifierReplacer;
 
     /**
-     * @param customNodesStorage
      * @param replacersFactory
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers['Factory<IReplacer>']) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
 
         this.identifierReplacer = <IdentifierReplacer>replacersFactory(NodeObfuscatorsReplacers.IdentifierReplacer);
     }

+ 1 - 5
src/node-transformers/node-obfuscators/FunctionDeclarationObfuscator.ts

@@ -6,10 +6,8 @@ import * as ESTree from 'estree';
 
 import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
 
-import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IReplacer } from '../../interfaces/node-transformers/IReplacer';
-import { IStorage } from '../../interfaces/storages/IStorage';
 
 import { NodeObfuscatorsReplacers } from '../../enums/container/NodeObfuscatorsReplacers';
 import { NodeType } from '../../enums/NodeType';
@@ -37,16 +35,14 @@ export class FunctionDeclarationObfuscator extends AbstractNodeTransformer {
     private readonly identifierReplacer: IdentifierReplacer;
 
     /**
-     * @param customNodesStorage
      * @param nodeObfuscatorsReplacersFactory
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers['Factory<IReplacer>']) nodeObfuscatorsReplacersFactory: (replacer: NodeObfuscatorsReplacers) => IReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
 
         this.identifierReplacer = <IdentifierReplacer>nodeObfuscatorsReplacersFactory(NodeObfuscatorsReplacers.IdentifierReplacer);
     }

+ 1 - 5
src/node-transformers/node-obfuscators/FunctionObfuscator.ts

@@ -4,10 +4,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
-import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IReplacer } from '../../interfaces/node-transformers/IReplacer';
-import { IStorage } from '../../interfaces/storages/IStorage';
 
 import { NodeObfuscatorsReplacers } from '../../enums/container/NodeObfuscatorsReplacers';
 import { NodeType } from '../../enums/NodeType';
@@ -34,16 +32,14 @@ export class FunctionObfuscator extends AbstractNodeTransformer {
     private readonly identifierReplacer: IdentifierReplacer;
 
     /**
-     * @param customNodesStorage
      * @param nodeObfuscatorsReplacersFactory
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers['Factory<IReplacer>']) nodeObfuscatorsReplacersFactory: (replacer: NodeObfuscatorsReplacers) => IReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
 
         this.identifierReplacer = <IdentifierReplacer>nodeObfuscatorsReplacersFactory(NodeObfuscatorsReplacers.IdentifierReplacer);
     }

+ 1 - 5
src/node-transformers/node-obfuscators/LabeledStatementObfuscator.ts

@@ -4,10 +4,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
-import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IReplacer } from '../../interfaces/node-transformers/IReplacer';
-import { IStorage } from '../../interfaces/storages/IStorage';
 
 import { NodeObfuscatorsReplacers } from '../../enums/container/NodeObfuscatorsReplacers';
 import { NodeType } from '../../enums/NodeType';
@@ -42,16 +40,14 @@ export class LabeledStatementObfuscator extends AbstractNodeTransformer {
     private readonly identifierReplacer: IdentifierReplacer;
 
     /**
-     * @param customNodesStorage
      * @param nodeObfuscatorsReplacersFactory
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers['Factory<IReplacer>']) nodeObfuscatorsReplacersFactory: (replacer: NodeObfuscatorsReplacers) => IReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
 
         this.identifierReplacer = <IdentifierReplacer>nodeObfuscatorsReplacersFactory(NodeObfuscatorsReplacers.IdentifierReplacer);
     }

+ 1 - 5
src/node-transformers/node-obfuscators/LiteralObfuscator.ts

@@ -4,10 +4,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 import * as escodegen from 'escodegen';
 import * as ESTree from 'estree';
 
-import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IReplacer } from '../../interfaces/node-transformers/IReplacer';
-import { IStorage } from '../../interfaces/storages/IStorage';
 
 import { NodeObfuscatorsReplacers } from '../../enums/container/NodeObfuscatorsReplacers';
 
@@ -22,16 +20,14 @@ export class LiteralObfuscator extends AbstractNodeTransformer {
     private readonly replacersFactory: (replacer: NodeObfuscatorsReplacers) => IReplacer;
 
     /**
-     * @param customNodesStorage
      * @param replacersFactory
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers['Factory<IReplacer>']) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
 
         this.replacersFactory = replacersFactory;
     }

+ 1 - 5
src/node-transformers/node-obfuscators/MemberExpressionObfuscator.ts

@@ -5,10 +5,8 @@ import * as escodegen from 'escodegen';
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
-import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IReplacer } from '../../interfaces/node-transformers/IReplacer';
-import { IStorage } from '../../interfaces/storages/IStorage';
 
 import { NodeObfuscatorsReplacers } from '../../enums/container/NodeObfuscatorsReplacers';
 import { NodeType } from '../../enums/NodeType';
@@ -24,16 +22,14 @@ export class MemberExpressionObfuscator extends AbstractNodeTransformer {
     private readonly stringLiteralReplacer: IReplacer;
 
     /**
-     * @param customNodesStorage
      * @param replacersFactory
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers['Factory<IReplacer>']) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
 
         this.stringLiteralReplacer = replacersFactory(NodeObfuscatorsReplacers.StringLiteralReplacer);
     }

+ 1 - 5
src/node-transformers/node-obfuscators/MethodDefinitionObfuscator.ts

@@ -4,10 +4,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
-import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IReplacer } from '../../interfaces/node-transformers/IReplacer';
-import { IStorage } from '../../interfaces/storages/IStorage';
 
 import { NodeObfuscatorsReplacers } from '../../enums/container/NodeObfuscatorsReplacers';
 
@@ -35,16 +33,14 @@ export class MethodDefinitionObfuscator extends AbstractNodeTransformer {
     private static readonly ignoredNames: string[] = ['constructor'];
 
     /**
-     * @param customNodesStorage
      * @param replacersFactory
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers['Factory<IReplacer>']) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
 
         this.stringLiteralReplacer = replacersFactory(NodeObfuscatorsReplacers.StringLiteralReplacer);
     }

+ 1 - 5
src/node-transformers/node-obfuscators/ObjectExpressionObfuscator.ts

@@ -5,9 +5,7 @@ import * as escodegen from 'escodegen';
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
-import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
-import { IStorage } from '../../interfaces/storages/IStorage';
 
 import { NodeType } from '../../enums/NodeType';
 
@@ -28,14 +26,12 @@ import { Utils } from '../../Utils';
 @injectable()
 export class ObjectExpressionObfuscator extends AbstractNodeTransformer {
     /**
-     * @param customNodesStorage
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
     }
 
     /**

+ 1 - 5
src/node-transformers/node-obfuscators/VariableDeclarationObfuscator.ts

@@ -6,10 +6,8 @@ import * as ESTree from 'estree';
 
 import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
 
-import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IReplacer } from '../../interfaces/node-transformers/IReplacer';
-import { IStorage } from '../../interfaces/storages/IStorage';
 
 import { NodeObfuscatorsReplacers } from '../../enums/container/NodeObfuscatorsReplacers';
 import { NodeType } from '../../enums/NodeType';
@@ -38,16 +36,14 @@ export class VariableDeclarationObfuscator extends AbstractNodeTransformer {
     private readonly identifierReplacer: IReplacer & IdentifierReplacer;
 
     /**
-     * @param customNodesStorage
      * @param replacersFactory
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers['Factory<IReplacer>']) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
 
         this.identifierReplacer = <IdentifierReplacer>replacersFactory(NodeObfuscatorsReplacers.IdentifierReplacer);
     }

+ 0 - 10
src/node-transformers/node-obfuscators/replacers/AbstractReplacer.ts

@@ -1,32 +1,22 @@
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
-import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IReplacer } from '../../../interfaces/node-transformers/IReplacer';
-import { IStorage } from '../../../interfaces/storages/IStorage';
 
 @injectable()
 export abstract class AbstractReplacer implements IReplacer {
-    /**
-     * @type IStorage<ICustomNode>
-     */
-    protected readonly customNodesStorage: IStorage<ICustomNode>;
-
     /**
      * @type {IOptions}
      */
     protected readonly options : IOptions;
 
     /**
-     * @param customNodesStorage
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        this.customNodesStorage = customNodesStorage;
         this.options = options;
     }
 

+ 1 - 5
src/node-transformers/node-obfuscators/replacers/BooleanLiteralReplacer.ts

@@ -1,9 +1,7 @@
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
-import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
-import { IStorage } from '../../../interfaces/storages/IStorage';
 
 import { JSFuck } from '../../../enums/JSFuck';
 
@@ -12,14 +10,12 @@ import { AbstractReplacer } from './AbstractReplacer';
 @injectable()
 export class BooleanLiteralReplacer extends AbstractReplacer {
     /**
-     * @param customNodesStorage
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
     }
 
     /**

+ 1 - 5
src/node-transformers/node-obfuscators/replacers/IdentifierReplacer.ts

@@ -1,9 +1,7 @@
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
-import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
-import { IStorage } from '../../../interfaces/storages/IStorage';
 
 import { AbstractReplacer } from './AbstractReplacer';
 import { Utils } from '../../../Utils';
@@ -21,14 +19,12 @@ export class IdentifierReplacer extends AbstractReplacer {
     private uniquePrefix: string;
 
     /**
-     * @param customNodesStorage
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
     }
 
     /**

+ 1 - 5
src/node-transformers/node-obfuscators/replacers/NumberLiteralReplacer.ts

@@ -1,9 +1,7 @@
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
-import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
-import { IStorage } from '../../../interfaces/storages/IStorage';
 
 import { AbstractReplacer } from './AbstractReplacer';
 import { Utils } from '../../../Utils';
@@ -11,14 +9,12 @@ import { Utils } from '../../../Utils';
 @injectable()
 export class NumberLiteralReplacer extends AbstractReplacer {
     /**
-     * @param customNodesStorage
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
     }
 
     /**

+ 20 - 5
src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts

@@ -1,6 +1,8 @@
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
+import { TCustomNodeGroupsFactory } from '../../../types/container/TCustomNodesFactoriesFactory';
+
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { ICustomNodeWithData } from '../../../interfaces/custom-nodes/ICustomNodeWithData';
 import { ICustomNodeWithIdentifier } from '../../../interfaces/custom-nodes/ICustomNodeWithIdentifier';
@@ -10,6 +12,7 @@ import { IStorage } from '../../../interfaces/storages/IStorage';
 import { StringArrayEncoding } from '../../../enums/StringArrayEncoding';
 
 import { AbstractReplacer } from './AbstractReplacer';
+import { CustomNodeGroups } from '../../../enums/container/CustomNodeGroups';
 import { Utils } from '../../../Utils';
 
 @injectable()
@@ -26,14 +29,21 @@ export class StringLiteralReplacer extends AbstractReplacer {
         .n(() => Utils.getRandomGenerator().string({length: 4}), 50);
 
     /**
-     * @param customNodesStorage
+     * @type {TCustomNodeGroupsFactory}
+     */
+    private readonly customNodeGroupsFactory: TCustomNodeGroupsFactory;
+
+    /**
+     * @param customNodeGroupsFactory
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
+        @inject(ServiceIdentifiers['Factory<ICustomNodeGroup>']) customNodeGroupsFactory: TCustomNodeGroupsFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(customNodesStorage, options);
+        super(options);
+
+        this.customNodeGroupsFactory = customNodeGroupsFactory;
     }
 
     /**
@@ -58,7 +68,11 @@ export class StringLiteralReplacer extends AbstractReplacer {
      * @returns {string}
      */
     private replaceStringLiteralWithStringArrayCall (value: string): string {
-        const stringArrayNode: ICustomNodeWithData = <ICustomNodeWithData>this.customNodesStorage.get('stringArrayNode');
+        const stringArrayCustomNodeGroupNodes: Map <string, ICustomNode> = this.customNodeGroupsFactory(
+            CustomNodeGroups.StringArrayCustomNodeGroup
+        ).getCustomNodes();
+
+        const stringArrayNode: ICustomNodeWithData = <ICustomNodeWithData>stringArrayCustomNodeGroupNodes.get('stringArrayNode');
 
         let rc4Key: string = '';
 
@@ -91,7 +105,8 @@ export class StringLiteralReplacer extends AbstractReplacer {
             stringArray.set(null, value);
         }
 
-        const stringArrayCallsWrapper: ICustomNodeWithIdentifier = <ICustomNodeWithIdentifier>this.customNodesStorage.get('stringArrayCallsWrapper');
+        const stringArrayCallsWrapper: ICustomNodeWithIdentifier = <ICustomNodeWithIdentifier>stringArrayCustomNodeGroupNodes
+            .get('stringArrayCallsWrapper');
         const hexadecimalIndex: string = `${Utils.hexadecimalPrefix}${Utils.decToHex(indexOfValue)}`;
 
         if (this.options.stringArrayEncoding === StringArrayEncoding.rc4) {

+ 0 - 100
src/storages/custom-nodes/CustomNodesStorage.ts

@@ -1,100 +0,0 @@
-import { injectable, inject } from 'inversify';
-import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
-
-import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
-import { IOptions } from '../../interfaces/options/IOptions';
-import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
-
-import { CustomNodesFactories } from '../../enums/container/CustomNodesFactories';
-
-import { MapStorage } from '../MapStorage';
-import { TCustomNodesFactoriesFactory } from '../../types/container/TCustomNodesFactoriesFactory';
-
-@injectable()
-export class CustomNodesStorage extends MapStorage <ICustomNode> {
-    /**
-     * @type {CustomNodesFactories[]}
-     */
-    private static readonly customNodesFactoriesList: CustomNodesFactories[] = [
-        CustomNodesFactories.ConsoleOutputCustomNodesFactory,
-        CustomNodesFactories.DebugProtectionCustomNodesFactory,
-        CustomNodesFactories.DomainLockCustomNodesFactory,
-        CustomNodesFactories.SelfDefendingCustomNodesFactory,
-        CustomNodesFactories.StringArrayCustomNodesFactory
-    ];
-
-    /**
-     * @type {TCustomNodesFactoriesFactory}
-     */
-    private readonly customNodesFactoriesFactory: TCustomNodesFactoriesFactory;
-
-    /**
-     * @type {IOptions}
-     */
-    private readonly options: IOptions;
-
-    /**
-     * @param customNodesFactoriesFactory
-     * @param options
-     */
-    constructor (
-        @inject(ServiceIdentifiers['Factory<ICustomNodesFactory>']) customNodesFactoriesFactory: TCustomNodesFactoriesFactory,
-        @inject(ServiceIdentifiers.IOptions) options: IOptions
-    ) {
-        super();
-
-        this.customNodesFactoriesFactory = customNodesFactoriesFactory;
-        this.options = options;
-    }
-
-    /**
-     * @param stackTraceData
-     */
-    public initialize (stackTraceData: IStackTraceData[]): void {
-        const customNodes: [string, ICustomNode][] = [];
-
-        CustomNodesStorage.customNodesFactoriesList.forEach((customNodesFactoryName: CustomNodesFactories) => {
-            const customNodesFactory: Map <string, ICustomNode> | undefined = this.customNodesFactoriesFactory(
-                customNodesFactoryName
-            ).initializeCustomNodes(stackTraceData);
-
-            if (!customNodesFactory) {
-                return;
-            }
-
-            customNodes.push(...customNodesFactory);
-        });
-
-        this.storage = new Map <string, ICustomNode> (customNodes);
-    }
-
-    /**
-     * @param key
-     * @returns {ICustomNode}
-     */
-    public get (key: string | number): ICustomNode {
-        return super.get(key);
-    }
-
-    /**
-     * @param value
-     * @returns {string | number | null}
-     */
-    public getKeyOf (value: ICustomNode): string | number | null {
-        return super.getKeyOf(value);
-    }
-
-    /**
-     * @returns {number}
-     */
-    public getLength (): number {
-        return super.getLength();
-    }
-
-    /**
-     * @returns {Map <string | number, ICustomNode>}
-     */
-    public getStorage (): Map <string | number, ICustomNode> {
-        return super.getStorage();
-    }
-}

+ 3 - 3
src/types/container/TCustomNodesFactoriesFactory.d.ts

@@ -1,5 +1,5 @@
-import { ICustomNodesFactory } from '../../interfaces/custom-nodes/ICustomNodesFactory';
+import { ICustomNodeGroup } from '../../interfaces/custom-nodes/ICustomNodeGroup';
 
-import { CustomNodesFactories } from '../../enums/container/CustomNodesFactories';
+import { CustomNodeGroups } from '../../enums/container/CustomNodeGroups';
 
-export type TCustomNodesFactoriesFactory = (customNodesFactoryName: CustomNodesFactories) => ICustomNodesFactory;
+export type TCustomNodeGroupsFactory = (customNodeGroupsName: CustomNodeGroups) => ICustomNodeGroup;

+ 1 - 3
src/types/node-transformers/TControlFlowReplacer.d.ts

@@ -1,6 +1,4 @@
 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';
 
-export type TControlFlowReplacer = (new (customNodesStorage: IStorage<ICustomNode>, options: IOptions) => IControlFlowReplacer);
+export type TControlFlowReplacer = (new (options: IOptions) => IControlFlowReplacer);

+ 3 - 2
test/index.spec.ts

@@ -7,15 +7,16 @@ BabelPolyfill.append();
 /**
  * Unit tests
  */
+import './unit-tests/cli/CLIUtils.spec';
 import './unit-tests/decorators/Initializable.spec';
 import './unit-tests/node/NodeAppender.spec';
 import './unit-tests/node/NodeUtils.spec';
 import './unit-tests/ObfuscationResult.spec';
 import './unit-tests/OptionsNormalizer.spec';
 import './unit-tests/SourceMapCorrector.spec';
-import './unit-tests/Utils.spec';
-import './unit-tests/cli/CLIUtils.spec';
 import './unit-tests/stack-trace-analyzer/StackTraceAnalyzer.spec';
+import './unit-tests/storages/ControlFlowStorage.spec';
+import './unit-tests/Utils.spec';
 
 /**
  * Functional tests

+ 31 - 0
test/unit-tests/storages/ControlFlowStorage.spec.ts

@@ -0,0 +1,31 @@
+/*
+import { ServiceIdentifiers } from '../../../src/container/ServiceIdentifiers';
+
+import { ICustomNode } from '../../../src/interfaces/custom-nodes/ICustomNode';
+import { IInversifyContainerFacade } from '../../../src/interfaces/container/IInversifyContainerFacade';
+import { IStorage } from '../../../src/interfaces/storages/IStorage';
+
+import { CustomNodes } from '../../../src/enums/container/CustomNodes';
+
+import { InversifyContainerFacade } from '../../../src/container/InversifyContainerFacade';
+
+const assert: Chai.AssertStatic = require('chai').assert;
+
+describe('ControlFlowStorage', () => {
+    describe('toString (): string', () => {
+        it('should returns obfuscated code if `.toString()` was called on `ObfuscationResult` object', () => {
+            const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade({
+                controlFlowFlattening: true
+            });
+            const controlFlowStorage: IStorage <ICustomNode> = inversifyContainerFacade
+                .get<IStorage<ICustomNode>>(ServiceIdentifiers['IStorage<ICustomNode>']);
+            const controlFlowStorageCallNode: ICustomNode = inversifyContainerFacade
+                .getNamed<ICustomNode>(ServiceIdentifiers.ICustomNode, CustomNodes.ControlFlowStorageCallNode);
+
+            controlFlowStorage.set('key1', controlFlowStorageCallNode);
+
+            assert.equal(controlFlowStorage.toString(), [`key1: ${controlFlowStorageCallNode.getCode()}`]);
+        });
+    });
+});
+*/

Some files were not shown because too many files changed in this diff