Jelajahi Sumber

refactoring + inversify integration

sanex3339 8 tahun lalu
induk
melakukan
47b85720e5
41 mengubah file dengan 708 tambahan dan 320 penghapusan
  1. 211 181
      dist/index.js
  2. 4 19
      src/ObfuscationResult.ts
  3. 2 0
      src/container/InversifyContainerFacade.ts
  4. 4 0
      src/container/ServiceIdentifiers.ts
  5. 131 0
      src/container/modules/custom-nodes/CustomNodesModule.ts
  6. 1 1
      src/container/modules/stack-trace-analyzer/StackTraceAnalyzerModule.ts
  7. 1 16
      src/custom-nodes/AbstractCustomNode.ts
  8. 5 3
      src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts
  9. 14 4
      src/custom-nodes/console-output-nodes/factory/ConsoleOutputCustomNodesFactory.ts
  10. 3 2
      src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionNode.ts
  11. 6 2
      src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallNode.ts
  12. 4 2
      src/custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode.ts
  13. 3 2
      src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionCallNode.ts
  14. 3 2
      src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionIntervalNode.ts
  15. 3 2
      src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionNode.ts
  16. 15 6
      src/custom-nodes/debug-protection-nodes/factory/DebugProtectionCustomNodesFactory.ts
  17. 4 2
      src/custom-nodes/domain-lock-nodes/DomainLockNode.ts
  18. 14 4
      src/custom-nodes/domain-lock-nodes/factory/DomainLockCustomNodesFactory.ts
  19. 4 2
      src/custom-nodes/node-calls-controller-nodes/NodeCallsControllerFunctionNode.ts
  20. 4 2
      src/custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode.ts
  21. 13 5
      src/custom-nodes/self-defending-nodes/factory/SelfDefendingCustomNodesFactory.ts
  22. 5 2
      src/custom-nodes/string-array-nodes/StringArrayCallsWrapper.ts
  23. 5 2
      src/custom-nodes/string-array-nodes/StringArrayNode.ts
  24. 5 2
      src/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.ts
  25. 14 5
      src/custom-nodes/string-array-nodes/factory/StringArrayCustomNodesFactory.ts
  26. 56 0
      src/decorators/Initializable.ts
  27. 15 0
      src/enums/container/CustomNodes.ts
  28. 7 0
      src/enums/container/CustomNodesFactories.ts
  29. 0 7
      src/interfaces/IInitializable.d.ts
  30. 4 0
      src/interfaces/container/IContainerServiceIdentifiers.d.ts
  31. 3 1
      src/interfaces/storages/IStorage.d.ts
  32. 7 2
      src/storages/ArrayStorage.ts
  33. 7 2
      src/storages/MapStorage.ts
  34. 6 0
      src/storages/control-flow/ControlFlowStorage.ts
  35. 22 36
      src/storages/custom-nodes/CustomNodesStorage.ts
  36. 6 0
      src/storages/string-array/StringArrayStorage.ts
  37. 5 0
      src/types/container/TCustomNodeFactory.d.ts
  38. 5 0
      src/types/container/TCustomNodesFactoriesFactory.d.ts
  39. 0 4
      src/types/container/TCustomNodesFactory.d.ts
  40. 1 0
      test/index.spec.ts
  41. 86 0
      test/unit-tests/decorators/Initializable.spec.ts

File diff ditekan karena terlalu besar
+ 211 - 181
dist/index.js


+ 4 - 19
src/ObfuscationResult.ts

@@ -2,29 +2,22 @@ import { injectable } from 'inversify';
 
 
 import { IObfuscationResult } from './interfaces/IObfuscationResult';
 import { IObfuscationResult } from './interfaces/IObfuscationResult';
 
 
+import { initializable } from './decorators/Initializable';
+
 @injectable()
 @injectable()
 export class ObfuscationResult implements IObfuscationResult {
 export class ObfuscationResult implements IObfuscationResult {
-    /**
-     * @type {boolean}
-     */
-    public initialized: boolean = false;
-
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private obfuscatedCode: string;
     private obfuscatedCode: string;
 
 
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private sourceMap: string;
     private sourceMap: string;
 
 
-    public checkInitialization (): void {
-        if (!this.initialized) {
-            throw new Error(`\`ObfuscationResult\` should be initialized first by calling \`initialize\` method!`);
-        }
-    }
-
     /**
     /**
      * @param obfuscatedCode
      * @param obfuscatedCode
      * @param sourceMap
      * @param sourceMap
@@ -32,16 +25,12 @@ export class ObfuscationResult implements IObfuscationResult {
     public initialize (obfuscatedCode: string, sourceMap: string): void {
     public initialize (obfuscatedCode: string, sourceMap: string): void {
         this.obfuscatedCode = obfuscatedCode;
         this.obfuscatedCode = obfuscatedCode;
         this.sourceMap = sourceMap;
         this.sourceMap = sourceMap;
-
-        this.initialized = true;
     }
     }
 
 
     /**
     /**
      * @returns {string}
      * @returns {string}
      */
      */
     public getObfuscatedCode (): string {
     public getObfuscatedCode (): string {
-        this.checkInitialization();
-
         return this.obfuscatedCode;
         return this.obfuscatedCode;
     }
     }
 
 
@@ -49,8 +38,6 @@ export class ObfuscationResult implements IObfuscationResult {
      * @returns {string}
      * @returns {string}
      */
      */
     public getSourceMap (): string {
     public getSourceMap (): string {
-        this.checkInitialization();
-
         return this.sourceMap;
         return this.sourceMap;
     }
     }
 
 
@@ -58,8 +45,6 @@ export class ObfuscationResult implements IObfuscationResult {
      * @returns {string}
      * @returns {string}
      */
      */
     public toString (): string {
     public toString (): string {
-        this.checkInitialization();
-
         return this.obfuscatedCode;
         return this.obfuscatedCode;
     }
     }
 }
 }

+ 2 - 0
src/container/InversifyContainerFacade.ts

@@ -1,6 +1,7 @@
 import { Container, interfaces } from 'inversify';
 import { Container, interfaces } from 'inversify';
 import { ServiceIdentifiers } from './ServiceIdentifiers';
 import { ServiceIdentifiers } from './ServiceIdentifiers';
 
 
+import { customNodesModule } from './modules/custom-nodes/CustomNodesModule';
 import { nodeControlFlowTransformersModule } from './modules/node-transformers/NodeControlFlowTransformersModule';
 import { nodeControlFlowTransformersModule } from './modules/node-transformers/NodeControlFlowTransformersModule';
 import { nodeObfuscatorsModule } from './modules/node-transformers/NodeObfuscatorsModule';
 import { nodeObfuscatorsModule } from './modules/node-transformers/NodeObfuscatorsModule';
 import { nodeTransformersModule } from './modules/node-transformers/NodeTransformersModule';
 import { nodeTransformersModule } from './modules/node-transformers/NodeTransformersModule';
@@ -89,6 +90,7 @@ export class InversifyContainerFacade implements IInversifyContainerFacade {
 
 
         // modules
         // modules
         this.container.load(stackTraceAnalyzerModule);
         this.container.load(stackTraceAnalyzerModule);
+        this.container.load(customNodesModule);
         this.container.load(nodeTransformersModule);
         this.container.load(nodeTransformersModule);
         this.container.load(nodeControlFlowTransformersModule);
         this.container.load(nodeControlFlowTransformersModule);
         this.container.load(nodeObfuscatorsModule);
         this.container.load(nodeObfuscatorsModule);

+ 4 - 0
src/container/ServiceIdentifiers.ts

@@ -3,10 +3,14 @@ import { IContainerServiceIdentifiers } from '../interfaces/container/IContainer
 export const ServiceIdentifiers: IContainerServiceIdentifiers = {
 export const ServiceIdentifiers: IContainerServiceIdentifiers = {
     'Factory<ICalleeDataExtractor>': Symbol('Factory<ICalleeDataExtractor>'),
     'Factory<ICalleeDataExtractor>': Symbol('Factory<ICalleeDataExtractor>'),
     'Factory<IControlFlowReplacer>': Symbol('Factory<IControlFlowReplacer>'),
     'Factory<IControlFlowReplacer>': Symbol('Factory<IControlFlowReplacer>'),
+    'Factory<ICustomNode>': Symbol('Factory<ICustomNode>'),
+    'Factory<ICustomNodesFactory>': Symbol('Factory<ICustomNodesFactory>'),
     'Factory<INodeTransformer[]>': Symbol('Factory<INodeTransformer[]>'),
     'Factory<INodeTransformer[]>': Symbol('Factory<INodeTransformer[]>'),
     'Factory<IObfuscationResult>': Symbol('Factory<IObfuscationResult>'),
     'Factory<IObfuscationResult>': Symbol('Factory<IObfuscationResult>'),
     'Factory<IReplacer>': Symbol('Factory<IReplacer>'),
     'Factory<IReplacer>': Symbol('Factory<IReplacer>'),
     ICalleeDataExtractor: Symbol('ICalleeDataExtractor'),
     ICalleeDataExtractor: Symbol('ICalleeDataExtractor'),
+    ICustomNode: Symbol('ICustomNode'),
+    ICustomNodesFactory: Symbol('ICustomNodesFactory'),
     IControlFlowReplacer: Symbol('IControlFlowReplacer'),
     IControlFlowReplacer: Symbol('IControlFlowReplacer'),
     IJavaScriptObfuscator: Symbol('IJavaScriptObfuscator'),
     IJavaScriptObfuscator: Symbol('IJavaScriptObfuscator'),
     INodeTransformer: Symbol('INodeTransformer'),
     INodeTransformer: Symbol('INodeTransformer'),

+ 131 - 0
src/container/modules/custom-nodes/CustomNodesModule.ts

@@ -0,0 +1,131 @@
+import { ContainerModule, interfaces } from 'inversify';
+import { ServiceIdentifiers } from '../../ServiceIdentifiers';
+
+import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
+import { ICustomNodesFactory } from '../../../interfaces/custom-nodes/ICustomNodesFactory';
+
+import { CustomNodes } from '../../../enums/container/CustomNodes';
+import { CustomNodesFactories } from '../../../enums/container/CustomNodesFactories';
+
+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 { 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';
+import { ControlFlowStorageNode } from '../../../custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode';
+import { ConsoleOutputDisableExpressionNode } from '../../../custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode';
+import { DebugProtectionFunctionCallNode } from '../../../custom-nodes/debug-protection-nodes/DebugProtectionFunctionCallNode';
+import { DebugProtectionFunctionIntervalNode } from '../../../custom-nodes/debug-protection-nodes/DebugProtectionFunctionIntervalNode';
+import { DebugProtectionFunctionNode } from '../../../custom-nodes/debug-protection-nodes/DebugProtectionFunctionNode';
+import { DomainLockNode } from '../../../custom-nodes/domain-lock-nodes/DomainLockNode';
+import { NodeCallsControllerFunctionNode } from '../../../custom-nodes/node-calls-controller-nodes/NodeCallsControllerFunctionNode';
+import { SelfDefendingUnicodeNode } from '../../../custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode';
+import { StringArrayCallsWrapper } from '../../../custom-nodes/string-array-nodes/StringArrayCallsWrapper';
+import { StringArrayNode } from '../../../custom-nodes/string-array-nodes/StringArrayNode';
+import { StringArrayRotateFunctionNode } from '../../../custom-nodes/string-array-nodes/StringArrayRotateFunctionNode';
+
+export const customNodesModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
+    const customNodesTag: string = 'customNodes';
+    const customNodesConcreteFactoriesTag: string = 'customNodesConcreteFactories';
+
+    // custom nodes
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(BinaryExpressionFunctionNode)
+        .whenTargetTagged(customNodesTag, CustomNodes.BinaryExpressionFunctionNode);
+
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(ControlFlowStorageCallNode)
+        .whenTargetTagged(customNodesTag, CustomNodes.ControlFlowStorageCallNode);
+
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(ControlFlowStorageNode)
+        .whenTargetTagged(customNodesTag, CustomNodes.ControlFlowStorageNode);
+
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(ConsoleOutputDisableExpressionNode)
+        .whenTargetTagged(customNodesTag, CustomNodes.ConsoleOutputDisableExpressionNode);
+
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(DebugProtectionFunctionCallNode)
+        .whenTargetTagged(customNodesTag, CustomNodes.DebugProtectionFunctionCallNode);
+
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(DebugProtectionFunctionIntervalNode)
+        .whenTargetTagged(customNodesTag, CustomNodes.DebugProtectionFunctionIntervalNode);
+
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(DebugProtectionFunctionNode)
+        .whenTargetTagged(customNodesTag, CustomNodes.DebugProtectionFunctionNode);
+
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(DomainLockNode)
+        .whenTargetTagged(customNodesTag, CustomNodes.DomainLockNode);
+
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(NodeCallsControllerFunctionNode)
+        .whenTargetTagged(customNodesTag, CustomNodes.NodeCallsControllerFunctionNode);
+
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(SelfDefendingUnicodeNode)
+        .whenTargetTagged(customNodesTag, CustomNodes.SelfDefendingUnicodeNode);
+
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(StringArrayCallsWrapper)
+        .whenTargetTagged(customNodesTag, CustomNodes.StringArrayCallsWrapper);
+
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(StringArrayNode)
+        .whenTargetTagged(customNodesTag, CustomNodes.StringArrayNode);
+
+    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
+        .to(StringArrayRotateFunctionNode)
+        .whenTargetTagged(customNodesTag, CustomNodes.StringArrayRotateFunctionNode);
+
+    // custom nodes concrete factories
+    bind<ICustomNodesFactory>(ServiceIdentifiers.ICustomNodesFactory)
+        .to(ConsoleOutputCustomNodesFactory)
+        .whenTargetTagged(customNodesConcreteFactoriesTag, CustomNodesFactories.ConsoleOutputCustomNodesFactory);
+
+    bind<ICustomNodesFactory>(ServiceIdentifiers.ICustomNodesFactory)
+        .to(DebugProtectionCustomNodesFactory)
+        .whenTargetTagged(customNodesConcreteFactoriesTag, CustomNodesFactories.DebugProtectionCustomNodesFactory);
+
+    bind<ICustomNodesFactory>(ServiceIdentifiers.ICustomNodesFactory)
+        .to(DomainLockCustomNodesFactory)
+        .whenTargetTagged(customNodesConcreteFactoriesTag, CustomNodesFactories.DomainLockCustomNodesFactory);
+
+    bind<ICustomNodesFactory>(ServiceIdentifiers.ICustomNodesFactory)
+        .to(SelfDefendingCustomNodesFactory)
+        .whenTargetTagged(customNodesConcreteFactoriesTag, CustomNodesFactories.SelfDefendingCustomNodesFactory);
+
+    bind<ICustomNodesFactory>(ServiceIdentifiers.ICustomNodesFactory)
+        .to(StringArrayCustomNodesFactory)
+        .whenTargetTagged(customNodesConcreteFactoriesTag, CustomNodesFactories.StringArrayCustomNodesFactory);
+
+    // customNode factory
+    bind<ICustomNode>(ServiceIdentifiers['Factory<ICustomNode>'])
+        .toFactory<ICustomNode>((context: interfaces.Context) => {
+            return (customNodeName: CustomNodes) => {
+                return context.container.getTagged<ICustomNode>(
+                    ServiceIdentifiers.ICustomNode,
+                    customNodesTag,
+                    customNodeName
+                );
+            };
+        });
+
+    // customNodesFactory factory
+    bind<ICustomNodesFactory>(ServiceIdentifiers['Factory<ICustomNodesFactory>'])
+        .toFactory<ICustomNodesFactory>((context: interfaces.Context) => {
+            return (customNodesFactoryName: CustomNodesFactories) => {
+                return context.container.getTagged<ICustomNodesFactory>(
+                    ServiceIdentifiers.ICustomNodesFactory,
+                    customNodesConcreteFactoriesTag,
+                    customNodesFactoryName
+                );
+            };
+        });
+});

+ 1 - 1
src/container/modules/stack-trace-analyzer/StackTraceAnalyzerModule.ts

@@ -4,11 +4,11 @@ import { ServiceIdentifiers } from '../../ServiceIdentifiers';
 import { ICalleeDataExtractor } from '../../../interfaces/stack-trace-analyzer/ICalleeDataExtractor';
 import { ICalleeDataExtractor } from '../../../interfaces/stack-trace-analyzer/ICalleeDataExtractor';
 import { IStackTraceAnalyzer } from '../../../interfaces/stack-trace-analyzer/IStackTraceAnalyzer';
 import { IStackTraceAnalyzer } from '../../../interfaces/stack-trace-analyzer/IStackTraceAnalyzer';
 
 
+import { CalleeDataExtractors } from '../../../enums/container/CalleeDataExtractors';
 import { FunctionDeclarationCalleeDataExtractor } from '../../../stack-trace-analyzer/callee-data-extractors/FunctionDeclarationCalleeDataExtractor';
 import { FunctionDeclarationCalleeDataExtractor } from '../../../stack-trace-analyzer/callee-data-extractors/FunctionDeclarationCalleeDataExtractor';
 import { FunctionExpressionCalleeDataExtractor } from '../../../stack-trace-analyzer/callee-data-extractors/FunctionExpressionCalleeDataExtractor';
 import { FunctionExpressionCalleeDataExtractor } from '../../../stack-trace-analyzer/callee-data-extractors/FunctionExpressionCalleeDataExtractor';
 import { ObjectExpressionCalleeDataExtractor } from '../../../stack-trace-analyzer/callee-data-extractors/ObjectExpressionCalleeDataExtractor';
 import { ObjectExpressionCalleeDataExtractor } from '../../../stack-trace-analyzer/callee-data-extractors/ObjectExpressionCalleeDataExtractor';
 import { StackTraceAnalyzer } from '../../../stack-trace-analyzer/StackTraceAnalyzer';
 import { StackTraceAnalyzer } from '../../../stack-trace-analyzer/StackTraceAnalyzer';
-import { CalleeDataExtractors } from '../../../enums/container/CalleeDataExtractors';
 
 
 export const stackTraceAnalyzerModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
 export const stackTraceAnalyzerModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
     const calleeDataExtractorsTag: string = 'calleeDataExtractors';
     const calleeDataExtractorsTag: string = 'calleeDataExtractors';

+ 1 - 16
src/custom-nodes/AbstractCustomNode.ts

@@ -14,11 +14,6 @@ import { NodeUtils } from '../node/NodeUtils';
 
 
 @injectable()
 @injectable()
 export abstract class AbstractCustomNode implements ICustomNode {
 export abstract class AbstractCustomNode implements ICustomNode {
-    /**
-     * @type {boolean}
-     */
-    public initialized: boolean = false;
-
     /**
     /**
      * @type {TObfuscationEvent}
      * @type {TObfuscationEvent}
      */
      */
@@ -38,18 +33,10 @@ export abstract class AbstractCustomNode implements ICustomNode {
         this.options = options;
         this.options = options;
     }
     }
 
 
-    public checkInitialization (): void {
-        if (!this.initialized) {
-            throw new Error(`Custom node should be initialized first by calling \`initialize\` method!`);
-        }
-    }
-
     /**
     /**
      * @param args
      * @param args
      */
      */
-    public initialize (...args: any[]): void {
-        this.initialized = true;
-    };
+    public abstract initialize (...args: any[]): void;
 
 
     /**
     /**
      * @param astTree
      * @param astTree
@@ -73,8 +60,6 @@ export abstract class AbstractCustomNode implements ICustomNode {
      * @returns {TStatement[]}
      * @returns {TStatement[]}
      */
      */
     public getNode (): TStatement[] {
     public getNode (): TStatement[] {
-        this.checkInitialization();
-
         return this.getNodeStructure();
         return this.getNodeStructure();
     }
     }
 
 

+ 5 - 3
src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts

@@ -13,13 +13,15 @@ import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
 
 import { ConsoleOutputDisableExpressionTemplate } from '../../templates/custom-nodes/console-output-nodes/console-output-disable-expression-node/ConsoleOutputDisableExpressionTemplate';
 import { ConsoleOutputDisableExpressionTemplate } from '../../templates/custom-nodes/console-output-nodes/console-output-disable-expression-node/ConsoleOutputDisableExpressionTemplate';
 
 
+import { initializable } from '../../decorators/Initializable';
+
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { NodeAppender } from '../../node/NodeAppender';
 import { NodeAppender } from '../../node/NodeAppender';
 import { Utils } from '../../Utils';
 import { Utils } from '../../Utils';
 
 
 @injectable()
 @injectable()
 export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
 export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
-    /**
+/**
      * @type {TObfuscationEvent}
      * @type {TObfuscationEvent}
      */
      */
     protected readonly appendEvent: TObfuscationEvent = ObfuscationEvents.BeforeObfuscation;
     protected readonly appendEvent: TObfuscationEvent = ObfuscationEvents.BeforeObfuscation;
@@ -27,11 +29,13 @@ export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     protected callsControllerFunctionName: string;
     protected callsControllerFunctionName: string;
 
 
     /**
     /**
      * @type {number}
      * @type {number}
      */
      */
+    @initializable()
     protected randomStackTraceIndex: number;
     protected randomStackTraceIndex: number;
 
 
     /**
     /**
@@ -50,8 +54,6 @@ export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
     public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
     public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
         this.callsControllerFunctionName = callsControllerFunctionName;
         this.randomStackTraceIndex = randomStackTraceIndex;
         this.randomStackTraceIndex = randomStackTraceIndex;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 14 - 4
src/custom-nodes/console-output-nodes/factory/ConsoleOutputCustomNodesFactory.ts

@@ -1,12 +1,13 @@
 import { injectable, inject } from 'inversify';
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 
+import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
+
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 
-import { ConsoleOutputDisableExpressionNode } from '../ConsoleOutputDisableExpressionNode';
-import { NodeCallsControllerFunctionNode } from '../../node-calls-controller-nodes/NodeCallsControllerFunctionNode';
+import { CustomNodes } from '../../../enums/container/CustomNodes';
 
 
 import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { NodeAppender } from '../../../node/NodeAppender';
 import { NodeAppender } from '../../../node/NodeAppender';
@@ -15,12 +16,21 @@ import { Utils } from '../../../Utils';
 @injectable()
 @injectable()
 export class ConsoleOutputCustomNodesFactory extends AbstractCustomNodesFactory {
 export class ConsoleOutputCustomNodesFactory extends AbstractCustomNodesFactory {
     /**
     /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
+    /**
+     * @param customNodeFactory
      * @param options
      * @param options
      */
      */
     constructor (
     constructor (
+        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
     ) {
         super(options);
         super(options);
+
+        this.customNodeFactory = customNodeFactory;
     }
     }
 
 
     /**
     /**
@@ -35,8 +45,8 @@ export class ConsoleOutputCustomNodesFactory extends AbstractCustomNodesFactory
         const callsControllerFunctionName: string = Utils.getRandomVariableName();
         const callsControllerFunctionName: string = Utils.getRandomVariableName();
         const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
         const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
 
 
-        const consoleOutputDisableExpressionNode: ICustomNode = new ConsoleOutputDisableExpressionNode(this.options);
-        const nodeCallsControllerFunctionNode: ICustomNode = new NodeCallsControllerFunctionNode(this.options);
+        const consoleOutputDisableExpressionNode: ICustomNode = this.customNodeFactory(CustomNodes.ConsoleOutputDisableExpressionNode);
+        const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.NodeCallsControllerFunctionNode);
 
 
         consoleOutputDisableExpressionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
         consoleOutputDisableExpressionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
         nodeCallsControllerFunctionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
         nodeCallsControllerFunctionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);

+ 3 - 2
src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionNode.ts

@@ -11,6 +11,8 @@ import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStack
 
 
 import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
 
 
+import { initializable } from '../../../decorators/Initializable';
+
 import { BinaryExpressionFunctionTemplate } from '../../../templates/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionTemplate';
 import { BinaryExpressionFunctionTemplate } from '../../../templates/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionTemplate';
 
 
 import { AbstractCustomNode } from '../../AbstractCustomNode';
 import { AbstractCustomNode } from '../../AbstractCustomNode';
@@ -26,6 +28,7 @@ export class BinaryExpressionFunctionNode extends AbstractCustomNode {
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private operator: string;
     private operator: string;
 
 
     /**
     /**
@@ -42,8 +45,6 @@ export class BinaryExpressionFunctionNode extends AbstractCustomNode {
      */
      */
     initialize (operator: string): void {
     initialize (operator: string): void {
         this.operator = operator;
         this.operator = operator;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 6 - 2
src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallNode.ts

@@ -11,6 +11,8 @@ import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStack
 
 
 import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
 
 
+import { initializable } from '../../../decorators/Initializable';
+
 import { ControlFlowStorageCallTemplate } from '../../../templates/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallTemplate';
 import { ControlFlowStorageCallTemplate } from '../../../templates/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallTemplate';
 
 
 import { AbstractCustomNode } from '../../AbstractCustomNode';
 import { AbstractCustomNode } from '../../AbstractCustomNode';
@@ -26,21 +28,25 @@ export class ControlFlowStorageCallNode extends AbstractCustomNode {
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private controlFlowStorageKey: string;
     private controlFlowStorageKey: string;
 
 
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private controlFlowStorageName: string;
     private controlFlowStorageName: string;
 
 
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private leftValue: string;
     private leftValue: string;
 
 
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private rightValue: string;
     private rightValue: string;
 
 
     /**
     /**
@@ -68,8 +74,6 @@ export class ControlFlowStorageCallNode extends AbstractCustomNode {
         this.controlFlowStorageKey = controlFlowStorageKey;
         this.controlFlowStorageKey = controlFlowStorageKey;
         this.leftValue = leftValue;
         this.leftValue = leftValue;
         this.rightValue = rightValue;
         this.rightValue = rightValue;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 4 - 2
src/custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode.ts

@@ -13,6 +13,8 @@ import { IStorage } from '../../interfaces/storages/IStorage';
 
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
 
+import { initializable } from '../../decorators/Initializable';
+
 import { ControlFlowStorageTemplate } from '../../templates/custom-nodes/control-flow-storage-nodes/ControlFlowStorageTemplate';
 import { ControlFlowStorageTemplate } from '../../templates/custom-nodes/control-flow-storage-nodes/ControlFlowStorageTemplate';
 
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { AbstractCustomNode } from '../AbstractCustomNode';
@@ -28,11 +30,13 @@ export class ControlFlowStorageNode extends AbstractCustomNode {
     /**
     /**
      * @type {IStorage <ICustomNode>}
      * @type {IStorage <ICustomNode>}
      */
      */
+    @initializable()
     private controlFlowStorage: IStorage <ICustomNode>;
     private controlFlowStorage: IStorage <ICustomNode>;
 
 
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private controlFlowStorageName: string;
     private controlFlowStorageName: string;
 
 
     /**
     /**
@@ -51,8 +55,6 @@ export class ControlFlowStorageNode extends AbstractCustomNode {
     public initialize (controlFlowStorage: IStorage <ICustomNode>, controlFlowStorageName: string): void {
     public initialize (controlFlowStorage: IStorage <ICustomNode>, controlFlowStorageName: string): void {
         this.controlFlowStorage = controlFlowStorage;
         this.controlFlowStorage = controlFlowStorage;
         this.controlFlowStorageName = controlFlowStorageName;
         this.controlFlowStorageName = controlFlowStorageName;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 3 - 2
src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionCallNode.ts

@@ -11,6 +11,8 @@ import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTra
 
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
 
+import { initializable } from '../../decorators/Initializable';
+
 import { DebugProtectionFunctionCallTemplate } from '../../templates/custom-nodes/debug-protection-nodes/debug-protection-function-call-node/DebufProtectionFunctionCallTemplate';
 import { DebugProtectionFunctionCallTemplate } from '../../templates/custom-nodes/debug-protection-nodes/debug-protection-function-call-node/DebufProtectionFunctionCallTemplate';
 
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { AbstractCustomNode } from '../AbstractCustomNode';
@@ -26,6 +28,7 @@ export class DebugProtectionFunctionCallNode extends AbstractCustomNode {
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private debugProtectionFunctionName: string;
     private debugProtectionFunctionName: string;
 
 
     /**
     /**
@@ -42,8 +45,6 @@ export class DebugProtectionFunctionCallNode extends AbstractCustomNode {
      */
      */
     public initialize (debugProtectionFunctionName: string): void {
     public initialize (debugProtectionFunctionName: string): void {
         this.debugProtectionFunctionName = debugProtectionFunctionName;
         this.debugProtectionFunctionName = debugProtectionFunctionName;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 3 - 2
src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionIntervalNode.ts

@@ -11,6 +11,8 @@ import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTra
 
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
 
+import { initializable } from '../../decorators/Initializable';
+
 import { DebugProtectionFunctionIntervalTemplate } from '../../templates/custom-nodes/debug-protection-nodes/debug-protection-function-interval-node/DebugProtectionFunctionIntervalTemplate';
 import { DebugProtectionFunctionIntervalTemplate } from '../../templates/custom-nodes/debug-protection-nodes/debug-protection-function-interval-node/DebugProtectionFunctionIntervalTemplate';
 
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { AbstractCustomNode } from '../AbstractCustomNode';
@@ -26,6 +28,7 @@ export class DebugProtectionFunctionIntervalNode extends AbstractCustomNode {
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private debugProtectionFunctionName: string;
     private debugProtectionFunctionName: string;
 
 
     /**
     /**
@@ -42,8 +45,6 @@ export class DebugProtectionFunctionIntervalNode extends AbstractCustomNode {
      */
      */
     public initialize (debugProtectionFunctionName: string): void {
     public initialize (debugProtectionFunctionName: string): void {
         this.debugProtectionFunctionName = debugProtectionFunctionName;
         this.debugProtectionFunctionName = debugProtectionFunctionName;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 3 - 2
src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionNode.ts

@@ -11,6 +11,8 @@ import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTra
 
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
 
+import { initializable } from '../../decorators/Initializable';
+
 import { DebugProtectionFunctionTemplate } from '../../templates/custom-nodes/debug-protection-nodes/debug-protection-function-node/DebugProtectionFunctionTemplate';
 import { DebugProtectionFunctionTemplate } from '../../templates/custom-nodes/debug-protection-nodes/debug-protection-function-node/DebugProtectionFunctionTemplate';
 
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { AbstractCustomNode } from '../AbstractCustomNode';
@@ -27,6 +29,7 @@ export class DebugProtectionFunctionNode extends AbstractCustomNode {
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private debugProtectionFunctionName: string;
     private debugProtectionFunctionName: string;
 
 
     /**
     /**
@@ -43,8 +46,6 @@ export class DebugProtectionFunctionNode extends AbstractCustomNode {
      */
      */
     public initialize (debugProtectionFunctionName: string): void {
     public initialize (debugProtectionFunctionName: string): void {
         this.debugProtectionFunctionName = debugProtectionFunctionName;
         this.debugProtectionFunctionName = debugProtectionFunctionName;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 15 - 6
src/custom-nodes/debug-protection-nodes/factory/DebugProtectionCustomNodesFactory.ts

@@ -1,13 +1,13 @@
 import { injectable, inject } from 'inversify';
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 
+import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
+
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 
-import { DebugProtectionFunctionCallNode } from '../DebugProtectionFunctionCallNode';
-import { DebugProtectionFunctionIntervalNode } from '../DebugProtectionFunctionIntervalNode';
-import { DebugProtectionFunctionNode } from '../DebugProtectionFunctionNode';
+import { CustomNodes } from '../../../enums/container/CustomNodes';
 
 
 import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { Utils } from '../../../Utils';
 import { Utils } from '../../../Utils';
@@ -15,12 +15,21 @@ import { Utils } from '../../../Utils';
 @injectable()
 @injectable()
 export class DebugProtectionCustomNodesFactory extends AbstractCustomNodesFactory {
 export class DebugProtectionCustomNodesFactory extends AbstractCustomNodesFactory {
     /**
     /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
+    /**
+     * @param customNodeFactory
      * @param options
      * @param options
      */
      */
     constructor (
     constructor (
+        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
     ) {
         super(options);
         super(options);
+
+        this.customNodeFactory = customNodeFactory;
     }
     }
 
 
     /**
     /**
@@ -34,9 +43,9 @@ export class DebugProtectionCustomNodesFactory extends AbstractCustomNodesFactor
 
 
         const debugProtectionFunctionName: string = Utils.getRandomVariableName();
         const debugProtectionFunctionName: string = Utils.getRandomVariableName();
 
 
-        const debugProtectionFunctionNode: ICustomNode = new DebugProtectionFunctionNode(this.options);
-        const debugProtectionFunctionCallNode: ICustomNode = new DebugProtectionFunctionCallNode(this.options);
-        const debugProtectionFunctionIntervalNode: ICustomNode = new DebugProtectionFunctionIntervalNode(this.options);
+        const debugProtectionFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.DebugProtectionFunctionNode);
+        const debugProtectionFunctionCallNode: ICustomNode = this.customNodeFactory(CustomNodes.DebugProtectionFunctionCallNode);
+        const debugProtectionFunctionIntervalNode: ICustomNode = this.customNodeFactory(CustomNodes.DebugProtectionFunctionIntervalNode);
 
 
         debugProtectionFunctionNode.initialize(debugProtectionFunctionName);
         debugProtectionFunctionNode.initialize(debugProtectionFunctionName);
         debugProtectionFunctionCallNode.initialize(debugProtectionFunctionName);
         debugProtectionFunctionCallNode.initialize(debugProtectionFunctionName);

+ 4 - 2
src/custom-nodes/domain-lock-nodes/DomainLockNode.ts

@@ -11,6 +11,8 @@ import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTra
 
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
 
+import { initializable } from '../../decorators/Initializable';
+
 import { DomainLockNodeTemplate } from '../../templates/custom-nodes/domain-lock-nodes/domain-lock-node/DomainLockNodeTemplate';
 import { DomainLockNodeTemplate } from '../../templates/custom-nodes/domain-lock-nodes/domain-lock-node/DomainLockNodeTemplate';
 
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { AbstractCustomNode } from '../AbstractCustomNode';
@@ -27,11 +29,13 @@ export class DomainLockNode extends AbstractCustomNode {
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     protected callsControllerFunctionName: string;
     protected callsControllerFunctionName: string;
 
 
     /**
     /**
      * @type {number}
      * @type {number}
      */
      */
+    @initializable()
     protected randomStackTraceIndex: number;
     protected randomStackTraceIndex: number;
 
 
     /**
     /**
@@ -50,8 +54,6 @@ export class DomainLockNode extends AbstractCustomNode {
     public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
     public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
         this.callsControllerFunctionName = callsControllerFunctionName;
         this.randomStackTraceIndex = randomStackTraceIndex;
         this.randomStackTraceIndex = randomStackTraceIndex;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 14 - 4
src/custom-nodes/domain-lock-nodes/factory/DomainLockCustomNodesFactory.ts

@@ -1,12 +1,13 @@
 import { injectable, inject } from 'inversify';
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 
+import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
+
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 
-import { DomainLockNode } from '../DomainLockNode';
-import { NodeCallsControllerFunctionNode } from '../../node-calls-controller-nodes/NodeCallsControllerFunctionNode';
+import { CustomNodes } from '../../../enums/container/CustomNodes';
 
 
 import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { NodeAppender } from '../../../node/NodeAppender';
 import { NodeAppender } from '../../../node/NodeAppender';
@@ -15,12 +16,21 @@ import { Utils } from '../../../Utils';
 @injectable()
 @injectable()
 export class DomainLockCustomNodesFactory extends AbstractCustomNodesFactory {
 export class DomainLockCustomNodesFactory extends AbstractCustomNodesFactory {
     /**
     /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
+    /**
+     * @param customNodeFactory
      * @param options
      * @param options
      */
      */
     constructor (
     constructor (
+        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
     ) {
         super(options);
         super(options);
+
+        this.customNodeFactory = customNodeFactory;
     }
     }
 
 
     /**
     /**
@@ -35,8 +45,8 @@ export class DomainLockCustomNodesFactory extends AbstractCustomNodesFactory {
         const callsControllerFunctionName: string = Utils.getRandomVariableName();
         const callsControllerFunctionName: string = Utils.getRandomVariableName();
         const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
         const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
 
 
-        const domainLockNode: ICustomNode = new DomainLockNode(this.options);
-        const nodeCallsControllerFunctionNode: ICustomNode = new NodeCallsControllerFunctionNode(this.options);
+        const domainLockNode: ICustomNode = this.customNodeFactory(CustomNodes.DomainLockNode);
+        const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.NodeCallsControllerFunctionNode);
 
 
         domainLockNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
         domainLockNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
         nodeCallsControllerFunctionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
         nodeCallsControllerFunctionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);

+ 4 - 2
src/custom-nodes/node-calls-controller-nodes/NodeCallsControllerFunctionNode.ts

@@ -11,6 +11,8 @@ import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTra
 
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
 
+import { initializable } from '../../decorators/Initializable';
+
 import { SingleNodeCallControllerTemplate } from '../../templates/custom-nodes/SingleNodeCallControllerTemplate';
 import { SingleNodeCallControllerTemplate } from '../../templates/custom-nodes/SingleNodeCallControllerTemplate';
 
 
 import { NO_CUSTOM_NODES_PRESET } from '../../preset-options/NoCustomNodesPreset';
 import { NO_CUSTOM_NODES_PRESET } from '../../preset-options/NoCustomNodesPreset';
@@ -29,11 +31,13 @@ export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     protected callsControllerFunctionName: string;
     protected callsControllerFunctionName: string;
 
 
     /**
     /**
      * @type {number}
      * @type {number}
      */
      */
+    @initializable()
     protected randomStackTraceIndex: number;
     protected randomStackTraceIndex: number;
 
 
     /**
     /**
@@ -52,8 +56,6 @@ export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
     public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
     public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
         this.callsControllerFunctionName = callsControllerFunctionName;
         this.randomStackTraceIndex = randomStackTraceIndex;
         this.randomStackTraceIndex = randomStackTraceIndex;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 4 - 2
src/custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode.ts

@@ -11,6 +11,8 @@ import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTra
 
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
 
+import { initializable } from '../../decorators/Initializable';
+
 import { NO_CUSTOM_NODES_PRESET } from '../../preset-options/NoCustomNodesPreset';
 import { NO_CUSTOM_NODES_PRESET } from '../../preset-options/NoCustomNodesPreset';
 
 
 import { SelfDefendingTemplate } from '../../templates/custom-nodes/self-defending-nodes/self-defending-unicode-node/SelfDefendingTemplate';
 import { SelfDefendingTemplate } from '../../templates/custom-nodes/self-defending-nodes/self-defending-unicode-node/SelfDefendingTemplate';
@@ -30,11 +32,13 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     protected callsControllerFunctionName: string;
     protected callsControllerFunctionName: string;
 
 
     /**
     /**
      * @type {number}
      * @type {number}
      */
      */
+    @initializable()
     protected randomStackTraceIndex: number;
     protected randomStackTraceIndex: number;
 
 
     /**
     /**
@@ -53,8 +57,6 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
     public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
     public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
         this.callsControllerFunctionName = callsControllerFunctionName;
         this.randomStackTraceIndex = randomStackTraceIndex;
         this.randomStackTraceIndex = randomStackTraceIndex;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 13 - 5
src/custom-nodes/self-defending-nodes/factory/SelfDefendingCustomNodesFactory.ts

@@ -1,17 +1,16 @@
 import { injectable, inject } from 'inversify';
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 
+import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
 import { TObfuscationEvent } from '../../../types/event-emitters/TObfuscationEvent';
 import { TObfuscationEvent } from '../../../types/event-emitters/TObfuscationEvent';
 
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 
+import { CustomNodes } from '../../../enums/container/CustomNodes';
 import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
 
 
-import { NodeCallsControllerFunctionNode } from '../../node-calls-controller-nodes/NodeCallsControllerFunctionNode';
-import { SelfDefendingUnicodeNode } from '../SelfDefendingUnicodeNode';
-
 import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { NodeAppender } from '../../../node/NodeAppender';
 import { NodeAppender } from '../../../node/NodeAppender';
 import { Utils } from '../../../Utils';
 import { Utils } from '../../../Utils';
@@ -24,12 +23,21 @@ export class SelfDefendingCustomNodesFactory extends AbstractCustomNodesFactory
     protected appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
     protected appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
 
 
     /**
     /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
+    /**
+     * @param customNodeFactory
      * @param options
      * @param options
      */
      */
     constructor (
     constructor (
+        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
     ) {
         super(options);
         super(options);
+
+        this.customNodeFactory = customNodeFactory;
     }
     }
 
 
     /**
     /**
@@ -44,8 +52,8 @@ export class SelfDefendingCustomNodesFactory extends AbstractCustomNodesFactory
         const callsControllerFunctionName: string = Utils.getRandomVariableName();
         const callsControllerFunctionName: string = Utils.getRandomVariableName();
         const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
         const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
 
 
-        const selfDefendingUnicodeNode: ICustomNode = new SelfDefendingUnicodeNode(this.options);
-        const nodeCallsControllerFunctionNode: ICustomNode = new NodeCallsControllerFunctionNode(this.options);
+        const selfDefendingUnicodeNode: ICustomNode = this.customNodeFactory(CustomNodes.SelfDefendingUnicodeNode);
+        const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.NodeCallsControllerFunctionNode);
 
 
         selfDefendingUnicodeNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
         selfDefendingUnicodeNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
         nodeCallsControllerFunctionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
         nodeCallsControllerFunctionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);

+ 5 - 2
src/custom-nodes/string-array-nodes/StringArrayCallsWrapper.ts

@@ -15,6 +15,8 @@ import { IStorage } from '../../interfaces/storages/IStorage';
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 import { StringArrayEncoding } from '../../enums/StringArrayEncoding';
 import { StringArrayEncoding } from '../../enums/StringArrayEncoding';
 
 
+import { initializable } from '../../decorators/Initializable';
+
 import { NO_CUSTOM_NODES_PRESET } from '../../preset-options/NoCustomNodesPreset';
 import { NO_CUSTOM_NODES_PRESET } from '../../preset-options/NoCustomNodesPreset';
 
 
 import { AtobTemplate } from '../../templates/custom-nodes/AtobTemplate';
 import { AtobTemplate } from '../../templates/custom-nodes/AtobTemplate';
@@ -38,16 +40,19 @@ export class StringArrayCallsWrapper extends AbstractCustomNode implements ICust
     /**
     /**
      * @type {IStorage <string>}
      * @type {IStorage <string>}
      */
      */
+    @initializable()
     private stringArray: IStorage <string>;
     private stringArray: IStorage <string>;
 
 
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private stringArrayCallsWrapperName: string;
     private stringArrayCallsWrapperName: string;
 
 
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private stringArrayName: string;
     private stringArrayName: string;
 
 
     /**
     /**
@@ -72,8 +77,6 @@ export class StringArrayCallsWrapper extends AbstractCustomNode implements ICust
         this.stringArray = stringArray;
         this.stringArray = stringArray;
         this.stringArrayName = stringArrayName;
         this.stringArrayName = stringArrayName;
         this.stringArrayCallsWrapperName = stringArrayCallsWrapperName;
         this.stringArrayCallsWrapperName = stringArrayCallsWrapperName;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 5 - 2
src/custom-nodes/string-array-nodes/StringArrayNode.ts

@@ -14,6 +14,8 @@ import { IStorage } from '../../interfaces/storages/IStorage';
 
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
 
+import { initializable } from '../../decorators/Initializable';
+
 import { StringArrayTemplate } from '../../templates/custom-nodes/string-array-nodes/string-array-node/StringArrayTemplate';
 import { StringArrayTemplate } from '../../templates/custom-nodes/string-array-nodes/string-array-node/StringArrayTemplate';
 
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { AbstractCustomNode } from '../AbstractCustomNode';
@@ -35,16 +37,19 @@ export class StringArrayNode extends AbstractCustomNode implements ICustomNodeWi
     /**
     /**
      * @type {IStorage <string>}
      * @type {IStorage <string>}
      */
      */
+    @initializable()
     private stringArray: IStorage <string>;
     private stringArray: IStorage <string>;
 
 
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private stringArrayName: string;
     private stringArrayName: string;
 
 
     /**
     /**
      * @type {number}
      * @type {number}
      */
      */
+    @initializable()
     private stringArrayRotateValue: number;
     private stringArrayRotateValue: number;
 
 
     /**
     /**
@@ -69,8 +74,6 @@ export class StringArrayNode extends AbstractCustomNode implements ICustomNodeWi
         this.stringArray = stringArray;
         this.stringArray = stringArray;
         this.stringArrayName = stringArrayName;
         this.stringArrayName = stringArrayName;
         this.stringArrayRotateValue = stringArrayRotateValue;
         this.stringArrayRotateValue = stringArrayRotateValue;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 5 - 2
src/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.ts

@@ -12,6 +12,8 @@ import { IStorage } from '../../interfaces/storages/IStorage';
 
 
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../enums/ObfuscationEvents';
 
 
+import { initializable } from '../../decorators/Initializable';
+
 import { NO_CUSTOM_NODES_PRESET } from '../../preset-options/NoCustomNodesPreset';
 import { NO_CUSTOM_NODES_PRESET } from '../../preset-options/NoCustomNodesPreset';
 
 
 import { SelfDefendingTemplate } from '../../templates/custom-nodes/string-array-nodes/string-array-rotate-function-node/SelfDefendingTemplate';
 import { SelfDefendingTemplate } from '../../templates/custom-nodes/string-array-nodes/string-array-rotate-function-node/SelfDefendingTemplate';
@@ -32,16 +34,19 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
     /**
     /**
      * @type {IStorage <string>}
      * @type {IStorage <string>}
      */
      */
+    @initializable()
     private stringArray: IStorage <string>;
     private stringArray: IStorage <string>;
 
 
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
+    @initializable()
     private stringArrayName: string;
     private stringArrayName: string;
 
 
     /**
     /**
      * @param {number}
      * @param {number}
      */
      */
+    @initializable()
     private stringArrayRotateValue: number;
     private stringArrayRotateValue: number;
 
 
     /**
     /**
@@ -66,8 +71,6 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
         this.stringArray = stringArray;
         this.stringArray = stringArray;
         this.stringArrayName = stringArrayName;
         this.stringArrayName = stringArrayName;
         this.stringArrayRotateValue = stringArrayRotateValue;
         this.stringArrayRotateValue = stringArrayRotateValue;
-
-        super.initialize();
     }
     }
 
 
     /**
     /**

+ 14 - 5
src/custom-nodes/string-array-nodes/factory/StringArrayCustomNodesFactory.ts

@@ -1,6 +1,7 @@
 import { injectable, inject } from 'inversify';
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 
+import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
 import { TObfuscationEvent } from '../../../types/event-emitters/TObfuscationEvent';
 import { TObfuscationEvent } from '../../../types/event-emitters/TObfuscationEvent';
 
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
@@ -8,11 +9,10 @@ import { IOptions } from '../../../interfaces/options/IOptions';
 import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 import { IStackTraceData } from '../../../interfaces/stack-trace-analyzer/IStackTraceData';
 import { IStorage } from '../../../interfaces/storages/IStorage';
 import { IStorage } from '../../../interfaces/storages/IStorage';
 
 
+import { CustomNodes } from '../../../enums/container/CustomNodes';
 import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
 import { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
 
 
-import { StringArrayCallsWrapper } from '../StringArrayCallsWrapper';
 import { StringArrayNode } from '../StringArrayNode';
 import { StringArrayNode } from '../StringArrayNode';
-import { StringArrayRotateFunctionNode } from '../StringArrayRotateFunctionNode';
 
 
 import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { StringArrayStorage } from '../../../storages/string-array/StringArrayStorage';
 import { StringArrayStorage } from '../../../storages/string-array/StringArrayStorage';
@@ -26,12 +26,21 @@ export class StringArrayCustomNodesFactory extends AbstractCustomNodesFactory {
     protected appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
     protected appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
 
 
     /**
     /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
+    /**
+     * @param customNodeFactory
      * @param options
      * @param options
      */
      */
     constructor (
     constructor (
+        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
     ) {
         super(options);
         super(options);
+
+        this.customNodeFactory = customNodeFactory;
     }
     }
 
 
     /**
     /**
@@ -45,9 +54,9 @@ export class StringArrayCustomNodesFactory extends AbstractCustomNodesFactory {
 
 
         const stringArray: IStorage <string> = new StringArrayStorage();
         const stringArray: IStorage <string> = new StringArrayStorage();
 
 
-        const stringArrayNode: ICustomNode = new StringArrayNode(this.options);
-        const stringArrayCallsWrapper: ICustomNode = new StringArrayCallsWrapper(this.options);
-        const stringArrayRotateFunctionNode: ICustomNode = new StringArrayRotateFunctionNode(this.options);
+        const stringArrayNode: ICustomNode = this.customNodeFactory(CustomNodes.StringArrayNode);
+        const stringArrayCallsWrapper: ICustomNode = this.customNodeFactory(CustomNodes.StringArrayCallsWrapper);
+        const stringArrayRotateFunctionNode: ICustomNode = this.customNodeFactory(CustomNodes.StringArrayRotateFunctionNode);
 
 
         const stringArrayName: string = Utils.getRandomVariableName(StringArrayNode.ARRAY_RANDOM_LENGTH);
         const stringArrayName: string = Utils.getRandomVariableName(StringArrayNode.ARRAY_RANDOM_LENGTH);
         const stringArrayCallsWrapperName: string = Utils.getRandomVariableName(StringArrayNode.ARRAY_RANDOM_LENGTH);
         const stringArrayCallsWrapperName: string = Utils.getRandomVariableName(StringArrayNode.ARRAY_RANDOM_LENGTH);

+ 56 - 0
src/decorators/Initializable.ts

@@ -0,0 +1,56 @@
+import { IInitializable } from '../interfaces/IInitializable';
+
+/**
+ * @param initializeMethodKey
+ * @returns {(target:IInitializable, propertyKey:(string|symbol))=>PropertyDescriptor}
+ */
+export function initializable (
+    initializeMethodKey: string = 'initialize'
+): (target: IInitializable, propertyKey: string | symbol) => any {
+    const decoratorName: string = Object.keys(this)[0];
+
+    return (target: IInitializable, propertyKey: string | symbol): any => {
+        const initializeMethod: any = (<any>target)[initializeMethodKey];
+
+        if (!initializeMethod || typeof initializeMethod !== 'function') {
+           throw new Error(`\`${initializeMethodKey}\` method with initialization logic not found. \`@${decoratorName}\` decorator requires \`${initializeMethodKey}\` method`);
+        }
+
+        const methodDescriptor: PropertyDescriptor = Object.getOwnPropertyDescriptor(target, initializeMethodKey) || {
+            configurable: true,
+            enumerable: true
+        };
+        const originalMethod: Function = methodDescriptor.value;
+
+        methodDescriptor.value = function () {
+            originalMethod.apply(this, arguments);
+
+            // call property getter to activate initialization check inside it
+            if (this[propertyKey]) {}
+        };
+
+        Object.defineProperty(target, initializeMethodKey, methodDescriptor);
+
+        const metadataPropertyKey: string = `_${propertyKey}`;
+        const propertyDescriptor: PropertyDescriptor = Object.getOwnPropertyDescriptor(target, metadataPropertyKey) || {
+            configurable: true,
+            enumerable: true
+        };
+
+        propertyDescriptor.get = function(): any {
+            if (this[metadataPropertyKey] === undefined) {
+                throw new Error(`Property \`${propertyKey}\` is not initialized! Initialize it first!`);
+            }
+
+            return this[metadataPropertyKey];
+        };
+
+        propertyDescriptor.set = function (newVal: any) {
+            this[metadataPropertyKey] = newVal;
+        };
+
+        Object.defineProperty(target, propertyKey, propertyDescriptor);
+
+        return propertyDescriptor;
+    }
+}

+ 15 - 0
src/enums/container/CustomNodes.ts

@@ -0,0 +1,15 @@
+export enum CustomNodes {
+    BinaryExpressionFunctionNode,
+    ControlFlowStorageCallNode,
+    ControlFlowStorageNode,
+    ConsoleOutputDisableExpressionNode,
+    DebugProtectionFunctionCallNode,
+    DebugProtectionFunctionIntervalNode,
+    DebugProtectionFunctionNode,
+    DomainLockNode,
+    NodeCallsControllerFunctionNode,
+    SelfDefendingUnicodeNode,
+    StringArrayCallsWrapper,
+    StringArrayNode,
+    StringArrayRotateFunctionNode
+}

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

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

+ 0 - 7
src/interfaces/IInitializable.d.ts

@@ -1,11 +1,4 @@
 export interface IInitializable {
 export interface IInitializable {
-    /**
-     * @type {boolean}
-     */
-    initialized: boolean;
-
-    checkInitialization (): void;
-
     /**
     /**
      * @param args
      * @param args
      */
      */

+ 4 - 0
src/interfaces/container/IContainerServiceIdentifiers.d.ts

@@ -3,11 +3,15 @@ import { interfaces } from 'inversify';
 export interface IContainerServiceIdentifiers {
 export interface IContainerServiceIdentifiers {
     'Factory<ICalleeDataExtractor>': interfaces.ServiceIdentifier<any>;
     'Factory<ICalleeDataExtractor>': interfaces.ServiceIdentifier<any>;
     'Factory<IControlFlowReplacer>': interfaces.ServiceIdentifier<any>;
     'Factory<IControlFlowReplacer>': interfaces.ServiceIdentifier<any>;
+    'Factory<ICustomNode>': interfaces.ServiceIdentifier<any>;
+    'Factory<ICustomNodesFactory>': interfaces.ServiceIdentifier<any>;
     'Factory<INodeTransformer[]>': interfaces.ServiceIdentifier<any>;
     'Factory<INodeTransformer[]>': interfaces.ServiceIdentifier<any>;
     'Factory<IObfuscationResult>': interfaces.ServiceIdentifier<any>;
     'Factory<IObfuscationResult>': interfaces.ServiceIdentifier<any>;
     'Factory<IReplacer>': interfaces.ServiceIdentifier<any>;
     'Factory<IReplacer>': interfaces.ServiceIdentifier<any>;
     ICalleeDataExtractor: interfaces.ServiceIdentifier<any>;
     ICalleeDataExtractor: interfaces.ServiceIdentifier<any>;
     IControlFlowReplacer: interfaces.ServiceIdentifier<any>;
     IControlFlowReplacer: interfaces.ServiceIdentifier<any>;
+    ICustomNode: interfaces.ServiceIdentifier<any>;
+    ICustomNodesFactory: interfaces.ServiceIdentifier<any>;
     IJavaScriptObfuscator: interfaces.ServiceIdentifier<any>;
     IJavaScriptObfuscator: interfaces.ServiceIdentifier<any>;
     INodeTransformer: interfaces.ServiceIdentifier<any>;
     INodeTransformer: interfaces.ServiceIdentifier<any>;
     IObfuscationEventEmitter: interfaces.ServiceIdentifier<any>;
     IObfuscationEventEmitter: interfaces.ServiceIdentifier<any>;

+ 3 - 1
src/interfaces/storages/IStorage.d.ts

@@ -1,4 +1,6 @@
-export interface IStorage <T> {
+import { IInitializable } from '../IInitializable';
+
+export interface IStorage <T> extends IInitializable {
     get (key: string | number): T;
     get (key: string | number): T;
     getKeyOf (value: T): string | number | null;
     getKeyOf (value: T): string | number | null;
     getLength (): number;
     getLength (): number;

+ 7 - 2
src/storages/ArrayStorage.ts

@@ -1,10 +1,13 @@
 import { IStorage } from '../interfaces/storages/IStorage';
 import { IStorage } from '../interfaces/storages/IStorage';
 
 
+import { initializable } from '../decorators/Initializable';
+
 export abstract class ArrayStorage <T> implements IStorage <T> {
 export abstract class ArrayStorage <T> implements IStorage <T> {
     /**
     /**
      * @type {T[]}
      * @type {T[]}
      */
      */
-    protected storage: T[] = [];
+    @initializable()
+    protected storage: T[];
 
 
     /**
     /**
      * @param key
      * @param key
@@ -45,7 +48,9 @@ export abstract class ArrayStorage <T> implements IStorage <T> {
     /**
     /**
      * @param args
      * @param args
      */
      */
-    public initialize (...args: any[]): void {}
+    public initialize (...args: any[]): void {
+        this.storage = [];
+    }
 
 
     /**
     /**
      * @param key
      * @param key

+ 7 - 2
src/storages/MapStorage.ts

@@ -2,6 +2,8 @@ import { injectable } from 'inversify';
 
 
 import { IStorage } from '../interfaces/storages/IStorage';
 import { IStorage } from '../interfaces/storages/IStorage';
 
 
+import { initializable } from '../decorators/Initializable';
+
 import { Utils } from '../Utils';
 import { Utils } from '../Utils';
 
 
 @injectable()
 @injectable()
@@ -9,7 +11,8 @@ export abstract class MapStorage <T> implements IStorage <T> {
     /**
     /**
      * @type {Map <string | number, T>}
      * @type {Map <string | number, T>}
      */
      */
-    protected storage: Map <string | number, T> = new Map <string | number, T> ();
+    @initializable()
+    protected storage: Map <string | number, T>;
 
 
     /**
     /**
      * @param key
      * @param key
@@ -50,7 +53,9 @@ export abstract class MapStorage <T> implements IStorage <T> {
     /**
     /**
      * @param args
      * @param args
      */
      */
-    public initialize (...args: any[]): void {}
+    public initialize (...args: any[]): void {
+        this.storage = new Map <string | number, T> ();
+    }
 
 
     /**
     /**
      * @param key
      * @param key

+ 6 - 0
src/storages/control-flow/ControlFlowStorage.ts

@@ -3,6 +3,12 @@ import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { MapStorage } from '../MapStorage';
 import { MapStorage } from '../MapStorage';
 
 
 export class ControlFlowStorage extends MapStorage <ICustomNode> {
 export class ControlFlowStorage extends MapStorage <ICustomNode> {
+    constructor () {
+        super();
+
+        this.initialize();
+    }
+
     /**
     /**
      * @returns {string}
      * @returns {string}
      */
      */

+ 22 - 36
src/storages/custom-nodes/CustomNodesStorage.ts

@@ -1,37 +1,33 @@
 import { injectable, inject } from 'inversify';
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 
-import { TCustomNodesFactory } from '../../types/container/TCustomNodesFactory';
-
 import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
+import { IInitializable } from '../../interfaces/IInitializable';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
 import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
 
 
-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 { CustomNodesFactories } from '../../enums/container/CustomNodesFactories';
+
 import { MapStorage } from '../MapStorage';
 import { MapStorage } from '../MapStorage';
-import { SelfDefendingCustomNodesFactory } from '../../custom-nodes/self-defending-nodes/factory/SelfDefendingCustomNodesFactory';
-import { StringArrayCustomNodesFactory } from '../../custom-nodes/string-array-nodes/factory/StringArrayCustomNodesFactory';
-import { IInitializable } from '../../interfaces/IInitializable';
+import { TCustomNodesFactoriesFactory } from '../../types/container/TCustomNodesFactoriesFactory';
 
 
 @injectable()
 @injectable()
 export class CustomNodesStorage extends MapStorage <ICustomNode> implements IInitializable {
 export class CustomNodesStorage extends MapStorage <ICustomNode> implements IInitializable {
     /**
     /**
-     * @type {TCustomNodesFactory[]}
+     * @type {CustomNodesFactories[]}
      */
      */
-    private static readonly customNodesFactories: TCustomNodesFactory[] = [
-        DomainLockCustomNodesFactory,
-        SelfDefendingCustomNodesFactory,
-        ConsoleOutputCustomNodesFactory,
-        DebugProtectionCustomNodesFactory,
-        StringArrayCustomNodesFactory
+    private static readonly customNodesFactoriesList: CustomNodesFactories[] = [
+        CustomNodesFactories.ConsoleOutputCustomNodesFactory,
+        CustomNodesFactories.DebugProtectionCustomNodesFactory,
+        CustomNodesFactories.DomainLockCustomNodesFactory,
+        CustomNodesFactories.SelfDefendingCustomNodesFactory,
+        CustomNodesFactories.StringArrayCustomNodesFactory
     ];
     ];
 
 
     /**
     /**
-     * @type {boolean}
+     * @type {TCustomNodesFactoriesFactory}
      */
      */
-    public initialized: boolean = false;
+    private readonly customNodesFactoriesFactory: TCustomNodesFactoriesFactory;
 
 
     /**
     /**
      * @type {IOptions}
      * @type {IOptions}
@@ -39,29 +35,28 @@ export class CustomNodesStorage extends MapStorage <ICustomNode> implements IIni
     private readonly options: IOptions;
     private readonly options: IOptions;
 
 
     /**
     /**
+     * @param customNodesFactoriesFactory
      * @param options
      * @param options
      */
      */
-    constructor (@inject(ServiceIdentifiers.IOptions) options: IOptions) {
+    constructor (
+        @inject(ServiceIdentifiers['Factory<ICustomNodesFactory>']) customNodesFactoriesFactory: TCustomNodesFactoriesFactory,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
         super();
         super();
 
 
+        this.customNodesFactoriesFactory = customNodesFactoriesFactory;
         this.options = options;
         this.options = options;
     }
     }
 
 
-    public checkInitialization (): void {
-        if (!this.initialized) {
-            throw new Error(`\`CustomNodesStorage\` should be initialized first by calling \`initialize\` method!`);
-        }
-    }
-
     /**
     /**
      * @param stackTraceData
      * @param stackTraceData
      */
      */
     public initialize (stackTraceData: IStackTraceData[]): void {
     public initialize (stackTraceData: IStackTraceData[]): void {
         const customNodes: [string, ICustomNode][] = [];
         const customNodes: [string, ICustomNode][] = [];
 
 
-        CustomNodesStorage.customNodesFactories.forEach((customNodesFactoryConstructor: TCustomNodesFactory) => {
-            const customNodesFactory: Map <string, ICustomNode> | undefined = new customNodesFactoryConstructor(
-                this.options
+        CustomNodesStorage.customNodesFactoriesList.forEach((customNodesFactoryName: CustomNodesFactories) => {
+            const customNodesFactory: Map <string, ICustomNode> | undefined = this.customNodesFactoriesFactory(
+                customNodesFactoryName
             ).initializeCustomNodes(stackTraceData);
             ).initializeCustomNodes(stackTraceData);
 
 
             if (!customNodesFactory) {
             if (!customNodesFactory) {
@@ -72,7 +67,6 @@ export class CustomNodesStorage extends MapStorage <ICustomNode> implements IIni
         });
         });
 
 
         this.storage = new Map <string, ICustomNode> (customNodes);
         this.storage = new Map <string, ICustomNode> (customNodes);
-        this.initialized = true;
     }
     }
 
 
     /**
     /**
@@ -80,8 +74,6 @@ export class CustomNodesStorage extends MapStorage <ICustomNode> implements IIni
      * @returns {ICustomNode}
      * @returns {ICustomNode}
      */
      */
     public get (key: string | number): ICustomNode {
     public get (key: string | number): ICustomNode {
-        this.checkInitialization();
-
         return super.get(key);
         return super.get(key);
     }
     }
 
 
@@ -90,8 +82,6 @@ export class CustomNodesStorage extends MapStorage <ICustomNode> implements IIni
      * @returns {string | number | null}
      * @returns {string | number | null}
      */
      */
     public getKeyOf (value: ICustomNode): string | number | null {
     public getKeyOf (value: ICustomNode): string | number | null {
-        this.checkInitialization();
-
         return super.getKeyOf(value);
         return super.getKeyOf(value);
     }
     }
 
 
@@ -99,8 +89,6 @@ export class CustomNodesStorage extends MapStorage <ICustomNode> implements IIni
      * @returns {number}
      * @returns {number}
      */
      */
     public getLength (): number {
     public getLength (): number {
-        this.checkInitialization();
-
         return super.getLength();
         return super.getLength();
     }
     }
 
 
@@ -108,8 +96,6 @@ export class CustomNodesStorage extends MapStorage <ICustomNode> implements IIni
      * @returns {Map <string | number, ICustomNode>}
      * @returns {Map <string | number, ICustomNode>}
      */
      */
     public getStorage (): Map <string | number, ICustomNode> {
     public getStorage (): Map <string | number, ICustomNode> {
-        this.checkInitialization();
-
         return super.getStorage();
         return super.getStorage();
     }
     }
 }
 }

+ 6 - 0
src/storages/string-array/StringArrayStorage.ts

@@ -2,6 +2,12 @@ import { ArrayStorage } from '../ArrayStorage';
 import { Utils } from '../../Utils';
 import { Utils } from '../../Utils';
 
 
 export class StringArrayStorage extends ArrayStorage <string> {
 export class StringArrayStorage extends ArrayStorage <string> {
+    constructor () {
+        super();
+
+        this.initialize();
+    }
+
     /**
     /**
      * @param rotationValue
      * @param rotationValue
      */
      */

+ 5 - 0
src/types/container/TCustomNodeFactory.d.ts

@@ -0,0 +1,5 @@
+import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
+
+import { CustomNodes } from '../../enums/container/CustomNodes';
+
+export type TCustomNodeFactory = (customNodeName: CustomNodes) => ICustomNode;

+ 5 - 0
src/types/container/TCustomNodesFactoriesFactory.d.ts

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

+ 0 - 4
src/types/container/TCustomNodesFactory.d.ts

@@ -1,4 +0,0 @@
-import { ICustomNodesFactory } from '../../interfaces/custom-nodes/ICustomNodesFactory';
-import { IOptions } from '../../interfaces/options/IOptions';
-
-export type TCustomNodesFactory = new (options: IOptions) => ICustomNodesFactory;

+ 1 - 0
test/index.spec.ts

@@ -7,6 +7,7 @@ BabelPolyfill.append();
 /**
 /**
  * Unit tests
  * Unit tests
  */
  */
+import './unit-tests/decorators/Initializable.spec';
 import './unit-tests/node/NodeAppender.spec';
 import './unit-tests/node/NodeAppender.spec';
 import './unit-tests/node/NodeUtils.spec';
 import './unit-tests/node/NodeUtils.spec';
 import './unit-tests/ObfuscationResult.spec';
 import './unit-tests/ObfuscationResult.spec';

+ 86 - 0
test/unit-tests/decorators/Initializable.spec.ts

@@ -0,0 +1,86 @@
+import { initializable } from '../../../src/decorators/Initializable';
+import { IInitializable } from '../../../src/interfaces/IInitializable';
+
+const assert: Chai.AssertStatic = require('chai').assert;
+
+describe('@initializable', () => {
+    describe('initializable (initializeMethodKey: string): any', () => {
+        it('shouldn\'t throws an errors if property was initialized', () => {
+            assert.doesNotThrow(() => {
+                class Foo implements IInitializable {
+                    @initializable()
+                    public property: string;
+
+                    public initialize (property: string): void {
+                        this.property = property;
+                    }
+                }
+
+                const foo: Foo = new Foo();
+
+                foo.initialize('baz');
+
+                foo.property;
+            }, Error);
+        });
+
+        it('shouldn\'t throws an errors if custom initialization method name is passed', () => {
+            assert.doesNotThrow(() => {
+                class Foo implements IInitializable {
+                    @initializable()
+                    public property: string;
+
+                    public initialize (): void {
+                    }
+
+                    public bar (property: string): void {
+                        this.property = property;
+                    }
+                }
+
+                const foo: Foo = new Foo();
+
+                foo.bar('baz');
+
+                foo.property;
+            }, Error);
+        });
+
+        it('should throws an error if property didn\'t initialized', () => {
+            assert.throws(() => {
+                class Foo implements IInitializable {
+                    @initializable()
+                    public property: string;
+
+                    public initialize (property: string): void {
+                    }
+                }
+
+                const foo: Foo = new Foo();
+
+                foo.initialize('baz');
+
+                foo.property;
+            }, /Property `property` is not initialized/);
+        });
+
+        it('should throws an error if `initialize` method with custom name wasn\'t found', () => {
+            assert.throws(() => {
+                class Foo {
+                    @initializable('bar')
+                    public property: string;
+
+                    public initialize (property: string): void {
+                        this.property = property;
+                    }
+                }
+
+                const foo: Foo = new Foo();
+
+                foo.initialize('baz');
+
+                foo.property;
+            }, /method with initialization logic not found/);
+        });
+    });
+});

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini