Browse Source

refactoring

sanex3339 8 years ago
parent
commit
5b312fd6db
35 changed files with 846 additions and 484 deletions
  1. 308 233
      dist/index.js
  2. 23 1
      src/ObfuscationResult.ts
  3. 6 3
      src/Obfuscator.ts
  4. 5 0
      src/Utils.ts
  5. 12 2
      src/container/InversifyContainerFacade.ts
  6. 1 0
      src/container/ServiceIdentifiers.ts
  7. 30 2
      src/custom-nodes/AbstractCustomNode.ts
  8. 7 1
      src/custom-nodes/AbstractCustomNodesFactory.ts
  9. 16 15
      src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts
  10. 22 18
      src/custom-nodes/console-output-nodes/factory/ConsoleOutputCustomNodesFactory.ts
  11. 17 3
      src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionNode.ts
  12. 20 7
      src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallNode.ts
  13. 16 6
      src/custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode.ts
  14. 17 3
      src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionCallNode.ts
  15. 17 3
      src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionIntervalNode.ts
  16. 17 3
      src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionNode.ts
  17. 26 12
      src/custom-nodes/debug-protection-nodes/factory/DebugProtectionCustomNodesFactory.ts
  18. 16 15
      src/custom-nodes/domain-lock-nodes/DomainLockNode.ts
  19. 22 18
      src/custom-nodes/domain-lock-nodes/factory/DomainLockCustomNodesFactory.ts
  20. 17 16
      src/custom-nodes/node-calls-controller-nodes/NodeCallsControllerFunctionNode.ts
  21. 16 15
      src/custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode.ts
  22. 22 18
      src/custom-nodes/self-defending-nodes/factory/SelfDefendingCustomNodesFactory.ts
  23. 26 13
      src/custom-nodes/string-array-nodes/StringArrayCallsWrapper.ts
  24. 21 8
      src/custom-nodes/string-array-nodes/StringArrayNode.ts
  25. 22 9
      src/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.ts
  26. 32 43
      src/custom-nodes/string-array-nodes/factory/StringArrayCustomNodesFactory.ts
  27. 13 0
      src/interfaces/IInitializable.d.ts
  28. 3 1
      src/interfaces/IObfuscationResult.d.ts
  29. 1 0
      src/interfaces/container/IContainerServiceIdentifiers.d.ts
  30. 6 2
      src/interfaces/custom-nodes/ICustomNode.d.ts
  31. 0 3
      src/interfaces/custom-nodes/ICustomNodeWithIdentifier.d.ts
  32. 3 5
      src/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.ts
  33. 11 4
      src/node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.ts
  34. 53 1
      src/storages/custom-nodes/CustomNodesStorage.ts
  35. 2 1
      test/unit-tests/ObfuscationResult.spec.ts

File diff suppressed because it is too large
+ 308 - 233
dist/index.js


+ 23 - 1
src/ObfuscationResult.ts

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

+ 6 - 3
src/Obfuscator.ts

@@ -22,6 +22,7 @@ import { VisitorDirection } from './enums/VisitorDirection';
 
 import { Node } from './node/Node';
 import { NodeUtils } from './node/NodeUtils';
+import { IStackTraceData } from './interfaces/stack-trace-analyzer/IStackTraceData';
 
 @injectable()
 export class Obfuscator implements IObfuscator {
@@ -103,15 +104,17 @@ export class Obfuscator implements IObfuscator {
 
         NodeUtils.parentize(astTree);
 
+        const stackTraceData: IStackTraceData[] = this.stackTraceAnalyzer.analyze(astTree.body);
+
         // prepare custom nodes
-        customNodesStorage.initialize(this.stackTraceAnalyzer.analyze(astTree.body));
+        customNodesStorage.initialize(stackTraceData);
         customNodesStorage
             .getStorage()
             .forEach((customNode: ICustomNode) => {
                 this.obfuscationEventEmitter.once(customNode.getAppendEvent(), customNode.appendNode.bind(customNode));
             });
 
-        this.obfuscationEventEmitter.emit(ObfuscationEvents.BeforeObfuscation, astTree);
+        this.obfuscationEventEmitter.emit(ObfuscationEvents.BeforeObfuscation, astTree, stackTraceData);
 
         // first pass: control flow flattening
         if (this.options.controlFlowFlattening) {
@@ -129,7 +132,7 @@ export class Obfuscator implements IObfuscator {
             this.nodeTransformersFactory(Obfuscator.nodeObfuscatorsMap)
         );
 
-        this.obfuscationEventEmitter.emit(ObfuscationEvents.AfterObfuscation, astTree);
+        this.obfuscationEventEmitter.emit(ObfuscationEvents.AfterObfuscation, astTree, stackTraceData);
 
         return astTree;
     }

+ 5 - 0
src/Utils.ts

@@ -15,6 +15,11 @@ export class Utils {
      */
     public static readonly randomGeneratorPool: string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
 
+    /**
+     * @type {string}
+     */
+    public static readonly randomGeneratorPoolWithNumbers: string = `${Utils.randomGeneratorPool}0123456789`;
+
     /**
      * @type {Chance.Chance | Chance.SeededChance}
      */

+ 12 - 2
src/container/InversifyContainerFacade.ts

@@ -54,11 +54,21 @@ export class InversifyContainerFacade implements IInversifyContainerFacade {
             .to(Obfuscator)
             .inSingletonScope();
 
+        this.container
+            .bind<IObfuscationResult>(ServiceIdentifiers.IObfuscationResult)
+            .to(ObfuscationResult)
+            .inSingletonScope();
+
         this.container
             .bind<IObfuscationResult>(ServiceIdentifiers['Factory<IObfuscationResult>'])
-            .toFactory<IObfuscationResult>(() => {
+            .toFactory<IObfuscationResult>((context: interfaces.Context) => {
                 return (obfuscatedCode: string, sourceMap: string) => {
-                    return new ObfuscationResult(obfuscatedCode, sourceMap);
+                    const obfuscationResult: IObfuscationResult = context.container
+                        .get<IObfuscationResult>(ServiceIdentifiers.IObfuscationResult);
+
+                    obfuscationResult.initialize(obfuscatedCode, sourceMap);
+
+                    return obfuscationResult;
                 };
             });
 

+ 1 - 0
src/container/ServiceIdentifiers.ts

@@ -11,6 +11,7 @@ export const ServiceIdentifiers: IContainerServiceIdentifiers = {
     IJavaScriptObfuscator: Symbol('IJavaScriptObfuscator'),
     INodeTransformer: Symbol('INodeTransformer'),
     IObfuscationEventEmitter: Symbol('IObfuscationEventEmitter'),
+    IObfuscationResult: Symbol('IObfuscationResult'),
     IObfuscator: Symbol('IObfuscator'),
     IOptions: Symbol('IOptions'),
     IReplacer: Symbol('IReplacer'),

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

@@ -1,14 +1,24 @@
+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 {boolean}
+     */
+    public initialized: boolean = false;
+
     /**
      * @type {TObfuscationEvent}
      */
@@ -22,14 +32,30 @@ export abstract class AbstractCustomNode implements ICustomNode {
     /**
      * @param options
      */
-    constructor (options: IOptions) {
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
         this.options = options;
     }
 
+    public checkInitialization (): void {
+        if (!this.initialized) {
+            throw new Error(`Custom node should be initialized first by calling \`initialize\` method!`);
+        }
+    }
+
+    /**
+     * @param args
+     */
+    public initialize (...args: any[]): void {
+        this.initialized = true;
+    };
+
     /**
      * @param astTree
+     * @param stackTraceData
      */
-    public abstract appendNode (astTree: ESTree.Node): void;
+    public abstract appendNode (astTree: ESTree.Node, stackTraceData: IStackTraceData[]): void;
 
     /**
      * @returns {TObfuscationEvent}
@@ -47,6 +73,8 @@ export abstract class AbstractCustomNode implements ICustomNode {
      * @returns {TStatement[]}
      */
     public getNode (): TStatement[] {
+        this.checkInitialization();
+
         return this.getNodeStructure();
     }
 

+ 7 - 1
src/custom-nodes/AbstractCustomNodesFactory.ts

@@ -1,3 +1,6 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
+
 import { TObfuscationEvent } from '../types/event-emitters/TObfuscationEvent';
 
 import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
@@ -7,6 +10,7 @@ import { IStackTraceData } from '../interfaces/stack-trace-analyzer/IStackTraceD
 
 import { ObfuscationEvents } from '../enums/ObfuscationEvents';
 
+@injectable()
 export abstract class AbstractCustomNodesFactory implements ICustomNodesFactory {
     /**
      * @type {TObfuscationEvent}
@@ -26,7 +30,9 @@ export abstract class AbstractCustomNodesFactory implements ICustomNodesFactory
     /**
      * @param options
      */
-    constructor (options: IOptions) {
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
         this.options = options;
     }
 

+ 16 - 15
src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts

@@ -1,3 +1,6 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
 import * as format from 'string-template';
 
 import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
@@ -14,6 +17,7 @@ import { AbstractCustomNode } from '../AbstractCustomNode';
 import { NodeAppender } from '../../node/NodeAppender';
 import { Utils } from '../../Utils';
 
+@injectable()
 export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
     /**
      * @type {TObfuscationEvent}
@@ -31,35 +35,32 @@ export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
     protected randomStackTraceIndex: number;
 
     /**
-     * @type {IStackTraceData[]}
-     */
-    protected stackTraceData: IStackTraceData[];
-
-    /**
-     * @param stackTraceData
-     * @param callsControllerFunctionName
-     * @param randomStackTraceIndex
      * @param options
      */
     constructor (
-        stackTraceData: IStackTraceData[],
-        callsControllerFunctionName: string,
-        randomStackTraceIndex: number,
-        options: IOptions
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
+    }
 
-        this.stackTraceData = stackTraceData;
+    /**
+     * @param callsControllerFunctionName
+     * @param randomStackTraceIndex
+     */
+    public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
         this.randomStackTraceIndex = randomStackTraceIndex;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
         NodeAppender.appendNodeToOptimalBlockScope(
-            this.stackTraceData,
+            stackTraceData,
             blockScopeNode,
             this.getNode(),
             this.randomStackTraceIndex

+ 22 - 18
src/custom-nodes/console-output-nodes/factory/ConsoleOutputCustomNodesFactory.ts

@@ -1,4 +1,8 @@
+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 { ConsoleOutputDisableExpressionNode } from '../ConsoleOutputDisableExpressionNode';
@@ -8,7 +12,17 @@ import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { NodeAppender } from '../../../node/NodeAppender';
 import { Utils } from '../../../Utils';
 
+@injectable()
 export class ConsoleOutputCustomNodesFactory extends AbstractCustomNodesFactory {
+    /**
+     * @param options
+     */
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(options);
+    }
+
     /**
      * @param stackTraceData
      * @returns {Map<string, ICustomNode>}
@@ -21,25 +35,15 @@ export class ConsoleOutputCustomNodesFactory extends AbstractCustomNodesFactory
         const callsControllerFunctionName: string = Utils.getRandomVariableName();
         const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
 
+        const consoleOutputDisableExpressionNode: ICustomNode = new ConsoleOutputDisableExpressionNode(this.options);
+        const nodeCallsControllerFunctionNode: ICustomNode = new NodeCallsControllerFunctionNode(this.options);
+
+        consoleOutputDisableExpressionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
+        nodeCallsControllerFunctionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
+
         return this.syncCustomNodesWithNodesFactory(new Map <string, ICustomNode> ([
-            [
-                'consoleOutputDisableExpressionNode',
-                new ConsoleOutputDisableExpressionNode(
-                    stackTraceData,
-                    callsControllerFunctionName,
-                    randomStackTraceIndex,
-                    this.options
-                )
-            ],
-            [
-                'ConsoleOutputNodeCallsControllerFunctionNode',
-                new NodeCallsControllerFunctionNode(
-                    stackTraceData,
-                    callsControllerFunctionName,
-                    randomStackTraceIndex,
-                    this.options
-                )
-            ]
+            ['consoleOutputDisableExpressionNode', consoleOutputDisableExpressionNode],
+            ['ConsoleOutputNodeCallsControllerFunctionNode', nodeCallsControllerFunctionNode]
         ]));
     }
 }

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

@@ -1,9 +1,13 @@
+import { injectable, inject } from 'inversify';
+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';
 
@@ -12,6 +16,7 @@ import { BinaryExpressionFunctionTemplate } from '../../../templates/custom-node
 import { AbstractCustomNode } from '../../AbstractCustomNode';
 import { Utils } from '../../../Utils';
 
+@injectable()
 export class BinaryExpressionFunctionNode extends AbstractCustomNode {
     /**
      * @type {TObfuscationEvent}
@@ -24,19 +29,28 @@ export class BinaryExpressionFunctionNode extends AbstractCustomNode {
     private operator: string;
 
     /**
-     * @param operator
      * @param options
      */
-    constructor (operator: string, options: IOptions) {
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
         super(options);
+    }
 
+    /**
+     * @param operator
+     */
+    initialize (operator: string): void {
         this.operator = operator;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {}
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {}
 
     /**
      * @returns {string}

+ 20 - 7
src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallNode.ts

@@ -1,9 +1,13 @@
+import { injectable, inject } from 'inversify';
+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';
 
@@ -12,6 +16,7 @@ import { ControlFlowStorageCallTemplate } from '../../../templates/custom-nodes/
 import { AbstractCustomNode } from '../../AbstractCustomNode';
 import { NodeAppender } from '../../../node/NodeAppender';
 
+@injectable()
 export class ControlFlowStorageCallNode extends AbstractCustomNode {
     /**
      * @type {TObfuscationEvent}
@@ -38,32 +43,40 @@ export class ControlFlowStorageCallNode extends AbstractCustomNode {
      */
     private rightValue: string;
 
+    /**
+     * @param options
+     */
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(options);
+    }
+
     /**
      * @param controlFlowStorageName
      * @param controlFlowStorageKey
      * @param leftValue
      * @param rightValue
-     * @param options
      */
-    constructor (
+    public initialize (
         controlFlowStorageName: string,
         controlFlowStorageKey: string,
         leftValue: string,
         rightValue: string,
-        options: IOptions
-    ) {
-        super(options);
-
+    ): void {
         this.controlFlowStorageName = controlFlowStorageName;
         this.controlFlowStorageKey = controlFlowStorageKey;
         this.leftValue = leftValue;
         this.rightValue = rightValue;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
         NodeAppender.prependNode(blockScopeNode, this.getNode());
     }
 

+ 16 - 6
src/custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode.ts

@@ -1,3 +1,6 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
 import * as format from 'string-template';
 
 import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
@@ -5,6 +8,7 @@ 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';
@@ -14,6 +18,7 @@ import { ControlFlowStorageTemplate } from '../../templates/custom-nodes/control
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { NodeAppender } from '../../node/NodeAppender';
 
+@injectable()
 export class ControlFlowStorageNode extends AbstractCustomNode {
     /**
      * @type {TObfuscationEvent}
@@ -31,25 +36,30 @@ export class ControlFlowStorageNode extends AbstractCustomNode {
     private controlFlowStorageName: string;
 
     /**
-     * @param controlFlowStorage
-     * @param controlFlowStorageName
      * @param options
      */
     constructor (
-        controlFlowStorage: IStorage <ICustomNode>,
-        controlFlowStorageName: string,
-        options: IOptions
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
+    }
 
+    /**
+     * @param controlFlowStorage
+     * @param controlFlowStorageName
+     */
+    public initialize (controlFlowStorage: IStorage <ICustomNode>, controlFlowStorageName: string): void {
         this.controlFlowStorage = controlFlowStorage;
         this.controlFlowStorageName = controlFlowStorageName;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
         NodeAppender.prependNode(blockScopeNode, this.getNode());
     }
 

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

@@ -1,9 +1,13 @@
+import { injectable, inject } from 'inversify';
+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';
 
@@ -12,6 +16,7 @@ import { DebugProtectionFunctionCallTemplate } from '../../templates/custom-node
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { NodeAppender } from '../../node/NodeAppender';
 
+@injectable()
 export class DebugProtectionFunctionCallNode extends AbstractCustomNode {
     /**
      * @type {TObfuscationEvent}
@@ -24,19 +29,28 @@ export class DebugProtectionFunctionCallNode extends AbstractCustomNode {
     private debugProtectionFunctionName: string;
 
     /**
-     * @param debugProtectionFunctionName
      * @param options
      */
-    constructor (debugProtectionFunctionName: string, options: IOptions) {
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
         super(options);
+    }
 
+    /**
+     * @param debugProtectionFunctionName
+     */
+    public initialize (debugProtectionFunctionName: string): void {
         this.debugProtectionFunctionName = debugProtectionFunctionName;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
         NodeAppender.appendNode(blockScopeNode, this.getNode());
     }
 

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

@@ -1,9 +1,13 @@
+import { injectable, inject } from 'inversify';
+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';
 
@@ -12,6 +16,7 @@ import { DebugProtectionFunctionIntervalTemplate } from '../../templates/custom-
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { NodeAppender } from '../../node/NodeAppender';
 
+@injectable()
 export class DebugProtectionFunctionIntervalNode extends AbstractCustomNode {
     /**
      * @type {TObfuscationEvent}
@@ -24,19 +29,28 @@ export class DebugProtectionFunctionIntervalNode extends AbstractCustomNode {
     private debugProtectionFunctionName: string;
 
     /**
-     * @param debugProtectionFunctionName
      * @param options
      */
-    constructor (debugProtectionFunctionName: string, options: IOptions) {
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
         super(options);
+    }
 
+    /**
+     * @param debugProtectionFunctionName
+     */
+    public initialize (debugProtectionFunctionName: string): void {
         this.debugProtectionFunctionName = debugProtectionFunctionName;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
         NodeAppender.appendNode(blockScopeNode, this.getNode());
     }
 

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

@@ -1,9 +1,13 @@
+import { injectable, inject } from 'inversify';
+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';
 
@@ -13,6 +17,7 @@ import { AbstractCustomNode } from '../AbstractCustomNode';
 import { NodeAppender } from '../../node/NodeAppender';
 import { Utils } from '../../Utils';
 
+@injectable()
 export class DebugProtectionFunctionNode extends AbstractCustomNode {
     /**
      * @type {TObfuscationEvent}
@@ -25,19 +30,28 @@ export class DebugProtectionFunctionNode extends AbstractCustomNode {
     private debugProtectionFunctionName: string;
 
     /**
-     * @param debugProtectionFunctionName
      * @param options
      */
-    constructor (debugProtectionFunctionName: string, options: IOptions) {
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
         super(options);
+    }
 
+    /**
+     * @param debugProtectionFunctionName
+     */
+    public initialize (debugProtectionFunctionName: string): void {
         this.debugProtectionFunctionName = debugProtectionFunctionName;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
         let programBodyLength: number = blockScopeNode.body.length,
             randomIndex: number = Utils.getRandomInteger(0, programBodyLength);
 

+ 26 - 12
src/custom-nodes/debug-protection-nodes/factory/DebugProtectionCustomNodesFactory.ts

@@ -1,4 +1,8 @@
+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 { DebugProtectionFunctionCallNode } from '../DebugProtectionFunctionCallNode';
@@ -8,7 +12,17 @@ import { DebugProtectionFunctionNode } from '../DebugProtectionFunctionNode';
 import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { Utils } from '../../../Utils';
 
+@injectable()
 export class DebugProtectionCustomNodesFactory extends AbstractCustomNodesFactory {
+    /**
+     * @param options
+     */
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(options);
+    }
+
     /**
      * @param stackTraceData
      * @returns {Map<string, ICustomNode>}
@@ -19,22 +33,22 @@ export class DebugProtectionCustomNodesFactory extends AbstractCustomNodesFactor
         }
 
         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);
+
+        debugProtectionFunctionNode.initialize(debugProtectionFunctionName);
+        debugProtectionFunctionCallNode.initialize(debugProtectionFunctionName);
+        debugProtectionFunctionIntervalNode.initialize(debugProtectionFunctionName);
+
         const customNodes: Map <string, ICustomNode> = new Map <string, ICustomNode> ([
-            [
-                'debugProtectionFunctionNode',
-                new DebugProtectionFunctionNode(debugProtectionFunctionName, this.options)
-            ],
-            [
-                'debugProtectionFunctionCallNode',
-                new DebugProtectionFunctionCallNode(debugProtectionFunctionName, this.options)
-            ]
+            ['debugProtectionFunctionNode', debugProtectionFunctionNode],
+            ['debugProtectionFunctionCallNode', debugProtectionFunctionCallNode]
         ]);
 
         if (this.options.debugProtectionInterval) {
-            customNodes.set(
-                'debugProtectionFunctionIntervalNode',
-                new DebugProtectionFunctionIntervalNode(debugProtectionFunctionName, this.options)
-            );
+            customNodes.set('debugProtectionFunctionIntervalNode', debugProtectionFunctionIntervalNode);
         }
 
         return this.syncCustomNodesWithNodesFactory(customNodes);

+ 16 - 15
src/custom-nodes/domain-lock-nodes/DomainLockNode.ts

@@ -1,3 +1,6 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
 import * as format from 'string-template';
 
 import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
@@ -14,6 +17,7 @@ import { AbstractCustomNode } from '../AbstractCustomNode';
 import { NodeAppender } from '../../node/NodeAppender';
 import { Utils } from '../../Utils';
 
+@injectable()
 export class DomainLockNode extends AbstractCustomNode {
     /**
      * @type {TObfuscationEvent}
@@ -31,35 +35,32 @@ export class DomainLockNode extends AbstractCustomNode {
     protected randomStackTraceIndex: number;
 
     /**
-     * @type {IStackTraceData[]}
-     */
-    protected stackTraceData: IStackTraceData[];
-
-    /**
-     * @param stackTraceData
-     * @param callsControllerFunctionName
-     * @param randomStackTraceIndex
      * @param options
      */
     constructor (
-        stackTraceData: IStackTraceData[],
-        callsControllerFunctionName: string,
-        randomStackTraceIndex: number,
-        options: IOptions
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
+    }
 
-        this.stackTraceData = stackTraceData;
+    /**
+     * @param callsControllerFunctionName
+     * @param randomStackTraceIndex
+     */
+    public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
         this.randomStackTraceIndex = randomStackTraceIndex;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
         NodeAppender.appendNodeToOptimalBlockScope(
-            this.stackTraceData,
+            stackTraceData,
             blockScopeNode,
             this.getNode(),
             this.randomStackTraceIndex

+ 22 - 18
src/custom-nodes/domain-lock-nodes/factory/DomainLockCustomNodesFactory.ts

@@ -1,4 +1,8 @@
+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 { DomainLockNode } from '../DomainLockNode';
@@ -8,7 +12,17 @@ import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { NodeAppender } from '../../../node/NodeAppender';
 import { Utils } from '../../../Utils';
 
+@injectable()
 export class DomainLockCustomNodesFactory extends AbstractCustomNodesFactory {
+    /**
+     * @param options
+     */
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(options);
+    }
+
     /**
      * @param stackTraceData
      * @returns {Map<string, ICustomNode>}
@@ -21,25 +35,15 @@ export class DomainLockCustomNodesFactory extends AbstractCustomNodesFactory {
         const callsControllerFunctionName: string = Utils.getRandomVariableName();
         const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
 
+        const domainLockNode: ICustomNode = new DomainLockNode(this.options);
+        const nodeCallsControllerFunctionNode: ICustomNode = new NodeCallsControllerFunctionNode(this.options);
+
+        domainLockNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
+        nodeCallsControllerFunctionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
+
         return this.syncCustomNodesWithNodesFactory(new Map <string, ICustomNode> ([
-            [
-                'DomainLockNode',
-                new DomainLockNode(
-                    stackTraceData,
-                    callsControllerFunctionName,
-                    randomStackTraceIndex,
-                    this.options
-                )
-            ],
-            [
-                'DomainLockNodeCallsControllerFunctionNode',
-                new NodeCallsControllerFunctionNode(
-                    stackTraceData,
-                    callsControllerFunctionName,
-                    randomStackTraceIndex,
-                    this.options
-                )
-            ]
+            ['DomainLockNode', domainLockNode],
+            ['DomainLockNodeCallsControllerFunctionNode', nodeCallsControllerFunctionNode]
         ]));
     }
 }

+ 17 - 16
src/custom-nodes/node-calls-controller-nodes/NodeCallsControllerFunctionNode.ts

@@ -1,3 +1,6 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
 import * as format from 'string-template';
 
 import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
@@ -16,6 +19,7 @@ import { AbstractCustomNode } from '../AbstractCustomNode';
 import { JavaScriptObfuscator } from '../../JavaScriptObfuscator';
 import { NodeAppender } from '../../node/NodeAppender';
 
+@injectable()
 export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
     /**
      * @type {TObfuscationEvent}
@@ -33,38 +37,35 @@ export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
     protected randomStackTraceIndex: number;
 
     /**
-     * @type {IStackTraceData[]}
-     */
-    protected stackTraceData: IStackTraceData[];
-
-    /**
-     * @param stackTraceData
-     * @param callsControllerFunctionName
-     * @param randomStackTraceIndex
      * @param options
      */
     constructor (
-        stackTraceData: IStackTraceData[],
-        callsControllerFunctionName: string,
-        randomStackTraceIndex: number,
-        options: IOptions
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
+    }
 
-        this.stackTraceData = stackTraceData;
+    /**
+     * @param callsControllerFunctionName
+     * @param randomStackTraceIndex
+     */
+    public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
         this.randomStackTraceIndex = randomStackTraceIndex;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
         let targetBlockScope: TNodeWithBlockStatement;
 
-        if (this.stackTraceData.length) {
+        if (stackTraceData.length) {
             targetBlockScope = NodeAppender
-                .getOptimalBlockScope(this.stackTraceData, this.randomStackTraceIndex, 1);
+                .getOptimalBlockScope(stackTraceData, this.randomStackTraceIndex, 1);
         } else {
             targetBlockScope = blockScopeNode;
         }

+ 16 - 15
src/custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode.ts

@@ -1,3 +1,6 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
 import * as format from 'string-template';
 
 import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
@@ -17,6 +20,7 @@ import { NodeAppender } from '../../node/NodeAppender';
 import { JavaScriptObfuscator } from '../../JavaScriptObfuscator';
 import { Utils } from '../../Utils';
 
+@injectable()
 export class SelfDefendingUnicodeNode extends AbstractCustomNode {
     /**
      * @type {TObfuscationEvent}
@@ -34,35 +38,32 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
     protected randomStackTraceIndex: number;
 
     /**
-     * @type {IStackTraceData[]}
-     */
-    protected stackTraceData: IStackTraceData[];
-
-    /**
-     * @param stackTraceData
-     * @param callsControllerFunctionName
-     * @param randomStackTraceIndex
      * @param options
      */
     constructor (
-        stackTraceData: IStackTraceData[],
-        callsControllerFunctionName: string,
-        randomStackTraceIndex: number,
-        options: IOptions
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
+    }
 
-        this.stackTraceData = stackTraceData;
+    /**
+     * @param callsControllerFunctionName
+     * @param randomStackTraceIndex
+     */
+    public initialize (callsControllerFunctionName: string, randomStackTraceIndex: number): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
         this.randomStackTraceIndex = randomStackTraceIndex;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
         NodeAppender.appendNodeToOptimalBlockScope(
-            this.stackTraceData,
+            stackTraceData,
             blockScopeNode,
             this.getNode(),
             this.randomStackTraceIndex

+ 22 - 18
src/custom-nodes/self-defending-nodes/factory/SelfDefendingCustomNodesFactory.ts

@@ -1,6 +1,10 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
+
 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 { ObfuscationEvents } from '../../../enums/ObfuscationEvents';
@@ -12,12 +16,22 @@ 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;
 
+    /**
+     * @param options
+     */
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(options);
+    }
+
     /**
      * @param stackTraceData
      * @returns {Map<string, ICustomNode>}
@@ -30,25 +44,15 @@ export class SelfDefendingCustomNodesFactory extends AbstractCustomNodesFactory
         const callsControllerFunctionName: string = Utils.getRandomVariableName();
         const randomStackTraceIndex: number = NodeAppender.getRandomStackTraceIndex(stackTraceData.length);
 
+        const selfDefendingUnicodeNode: ICustomNode = new SelfDefendingUnicodeNode(this.options);
+        const nodeCallsControllerFunctionNode: ICustomNode = new NodeCallsControllerFunctionNode(this.options);
+
+        selfDefendingUnicodeNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
+        nodeCallsControllerFunctionNode.initialize(callsControllerFunctionName, randomStackTraceIndex);
+
         return this.syncCustomNodesWithNodesFactory(new Map <string, ICustomNode> ([
-            [
-                'selfDefendingUnicodeNode',
-                new SelfDefendingUnicodeNode(
-                    stackTraceData,
-                    callsControllerFunctionName,
-                    randomStackTraceIndex,
-                    this.options
-                )
-            ],
-            [
-                'SelfDefendingNodeCallsControllerFunctionNode',
-                new NodeCallsControllerFunctionNode(
-                    stackTraceData,
-                    callsControllerFunctionName,
-                    randomStackTraceIndex,
-                    this.options
-                )
-            ]
+            ['selfDefendingUnicodeNode', selfDefendingUnicodeNode],
+            ['SelfDefendingNodeCallsControllerFunctionNode', nodeCallsControllerFunctionNode]
         ]));
     }
 }

+ 26 - 13
src/custom-nodes/string-array-nodes/StringArrayCallsWrapper.ts

@@ -1,3 +1,6 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
 import * as format from 'string-template';
 
 import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
@@ -6,6 +9,7 @@ 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';
@@ -24,6 +28,7 @@ import { AbstractCustomNode } from '../AbstractCustomNode';
 import { JavaScriptObfuscator } from '../../JavaScriptObfuscator';
 import { NodeAppender } from '../../node/NodeAppender';
 
+@injectable()
 export class StringArrayCallsWrapper extends AbstractCustomNode implements ICustomNodeWithIdentifier {
     /**
      * @type {TObfuscationEvent}
@@ -38,36 +43,44 @@ export class StringArrayCallsWrapper extends AbstractCustomNode implements ICust
     /**
      * @type {string}
      */
-    private stringArrayName: string;
+    private stringArrayCallsWrapperName: string;
 
     /**
      * @type {string}
      */
-    private stringArrayCallsWrapperName: string;
+    private stringArrayName: string;
 
     /**
-     * @param stringArrayCallsWrapperName
-     * @param stringArrayName
-     * @param stringArray
      * @param options
      */
     constructor (
-        stringArrayCallsWrapperName: string,
-        stringArrayName: string,
-        stringArray: IStorage <string>,
-        options: IOptions
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
+    }
 
-        this.stringArrayCallsWrapperName = stringArrayCallsWrapperName;
-        this.stringArrayName = stringArrayName;
+    /**
+     * @param stringArray
+     * @param stringArrayName
+     * @param stringArrayCallsWrapperName
+     */
+    public initialize (
+        stringArray: IStorage <string>,
+        stringArrayName: string,
+        stringArrayCallsWrapperName: string
+    ): void {
         this.stringArray = stringArray;
+        this.stringArrayName = stringArrayName;
+        this.stringArrayCallsWrapperName = stringArrayCallsWrapperName;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
         if (!this.stringArray.getLength()) {
             return;
         }
@@ -110,7 +123,7 @@ export class StringArrayCallsWrapper extends AbstractCustomNode implements ICust
     /**
      * @returns {string}
      */
-    protected getDecodeStringArrayTemplate (): string {
+    private getDecodeStringArrayTemplate (): string {
         let decodeStringArrayTemplate: string = '',
             selfDefendingCode: string = '';
 

+ 21 - 8
src/custom-nodes/string-array-nodes/StringArrayNode.ts

@@ -1,3 +1,6 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
 import * as format from 'string-template';
 
 import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
@@ -6,6 +9,7 @@ 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';
@@ -16,6 +20,7 @@ import { AbstractCustomNode } from '../AbstractCustomNode';
 import { NodeAppender } from '../../node/NodeAppender';
 import { StringArrayStorage } from '../../storages/string-array/StringArrayStorage';
 
+@injectable()
 export class StringArrayNode extends AbstractCustomNode implements ICustomNodeWithData {
     /**
      * @type {number}
@@ -43,28 +48,36 @@ export class StringArrayNode extends AbstractCustomNode implements ICustomNodeWi
     private stringArrayRotateValue: number;
 
     /**
-     * @param stringArray
-     * @param stringArrayName
-     * @param stringArrayRotateValue
      * @param options
      */
     constructor (
-        stringArray: IStorage <string>,
-        stringArrayName: string,
-        stringArrayRotateValue: number = 0,
-        options: IOptions
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
+    }
 
+    /**
+     * @param stringArray
+     * @param stringArrayName
+     * @param stringArrayRotateValue
+     */
+    public initialize (
+        stringArray: IStorage <string>,
+        stringArrayName: string,
+        stringArrayRotateValue: number
+    ): void {
         this.stringArray = stringArray;
         this.stringArrayName = stringArrayName;
         this.stringArrayRotateValue = stringArrayRotateValue;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
         if (!this.stringArray.getLength()) {
             return;
         }

+ 22 - 9
src/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.ts

@@ -1,9 +1,13 @@
+import { injectable, inject } from 'inversify';
+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';
@@ -18,6 +22,7 @@ import { JavaScriptObfuscator } from '../../JavaScriptObfuscator';
 import { NodeAppender } from '../../node/NodeAppender';
 import { Utils } from '../../Utils';
 
+@injectable()
 export class StringArrayRotateFunctionNode extends AbstractCustomNode {
     /**
      * @type {TObfuscationEvent}
@@ -40,28 +45,36 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
     private stringArrayRotateValue: number;
 
     /**
-     * @param stringArrayName
-     * @param stringArray
-     * @param stringArrayRotateValue
      * @param options
      */
     constructor (
-        stringArrayName: string,
-        stringArray: IStorage <string>,
-        stringArrayRotateValue: number,
-        options: IOptions
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
+    }
 
-        this.stringArrayName = stringArrayName;
+    /**
+     * @param stringArray
+     * @param stringArrayName
+     * @param stringArrayRotateValue
+     */
+    public initialize (
+        stringArray: IStorage <string>,
+        stringArrayName: string,
+        stringArrayRotateValue: number
+    ): void {
         this.stringArray = stringArray;
+        this.stringArrayName = stringArrayName;
         this.stringArrayRotateValue = stringArrayRotateValue;
+
+        super.initialize();
     }
 
     /**
      * @param blockScopeNode
+     * @param stackTraceData
      */
-    public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+    public appendNode (blockScopeNode: TNodeWithBlockStatement, stackTraceData: IStackTraceData[]): void {
         if (!this.stringArray.getLength()) {
             return;
         }

+ 32 - 43
src/custom-nodes/string-array-nodes/factory/StringArrayCustomNodesFactory.ts

@@ -1,7 +1,12 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
+
 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';
 
@@ -12,8 +17,8 @@ import { StringArrayRotateFunctionNode } from '../StringArrayRotateFunctionNode'
 import { AbstractCustomNodesFactory } from '../../AbstractCustomNodesFactory';
 import { StringArrayStorage } from '../../../storages/string-array/StringArrayStorage';
 import { Utils } from '../../../Utils';
-import { IStorage } from '../../../interfaces/storages/IStorage';
 
+@injectable()
 export class StringArrayCustomNodesFactory extends AbstractCustomNodesFactory {
     /**
      * @type {TObfuscationEvent}
@@ -21,19 +26,13 @@ export class StringArrayCustomNodesFactory extends AbstractCustomNodesFactory {
     protected appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
 
     /**
-     * @type {string}
-     */
-    private stringArrayName: string = Utils.getRandomVariableName(StringArrayNode.ARRAY_RANDOM_LENGTH);
-
-    /**
-     * @type {string}
-     */
-    private stringArrayCallsWrapper: string = Utils.getRandomVariableName(StringArrayNode.ARRAY_RANDOM_LENGTH);
-
-    /**
-     * @type {number}
+     * @param options
      */
-    private stringArrayRotateValue: number;
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(options);
+    }
 
     /**
      * @param stackTraceData
@@ -44,44 +43,34 @@ export class StringArrayCustomNodesFactory extends AbstractCustomNodesFactory {
             return;
         }
 
+        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 stringArrayName: string = Utils.getRandomVariableName(StringArrayNode.ARRAY_RANDOM_LENGTH);
+        const stringArrayCallsWrapperName: string = Utils.getRandomVariableName(StringArrayNode.ARRAY_RANDOM_LENGTH);
+
+        let stringArrayRotateValue: number;
+
         if (this.options.rotateStringArray) {
-            this.stringArrayRotateValue = Utils.getRandomInteger(100, 500);
+            stringArrayRotateValue = Utils.getRandomInteger(100, 500);
         } else {
-            this.stringArrayRotateValue = 0;
+            stringArrayRotateValue = 0;
         }
 
-        const stringArray: IStorage <string> = new StringArrayStorage();
-        const stringArrayNode: ICustomNode = new StringArrayNode(
-            stringArray,
-            this.stringArrayName,
-            this.stringArrayRotateValue,
-            this.options
-        );
+        stringArrayNode.initialize(stringArray, stringArrayName, stringArrayRotateValue);
+        stringArrayCallsWrapper.initialize(stringArray, stringArrayName, stringArrayCallsWrapperName);
+        stringArrayRotateFunctionNode.initialize(stringArray, stringArrayName, stringArrayRotateValue);
+
         const customNodes: Map <string, ICustomNode> = new Map <string, ICustomNode> ([
-            [
-                'stringArrayNode', stringArrayNode,
-            ],
-            [
-                'stringArrayCallsWrapper',
-                new StringArrayCallsWrapper(
-                    this.stringArrayCallsWrapper,
-                    this.stringArrayName,
-                    stringArray,
-                    this.options
-                )
-            ]
+            ['stringArrayNode', stringArrayNode],
+            ['stringArrayCallsWrapper', stringArrayCallsWrapper]
         ]);
 
         if (this.options.rotateStringArray) {
-            customNodes.set(
-                'stringArrayRotateFunctionNode',
-                new StringArrayRotateFunctionNode(
-                    this.stringArrayName,
-                    stringArray,
-                    this.stringArrayRotateValue,
-                    this.options
-                )
-            );
+            customNodes.set('stringArrayRotateFunctionNode', stringArrayRotateFunctionNode);
         }
 
         return this.syncCustomNodesWithNodesFactory(customNodes);

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

@@ -0,0 +1,13 @@
+export interface IInitializable {
+    /**
+     * @type {boolean}
+     */
+    initialized: boolean;
+
+    checkInitialization (): void;
+
+    /**
+     * @param args
+     */
+    initialize (...args: any[]): void;
+}

+ 3 - 1
src/interfaces/IObfuscationResult.d.ts

@@ -1,4 +1,6 @@
-export interface IObfuscationResult {
+import { IInitializable } from './IInitializable';
+
+export interface IObfuscationResult extends IInitializable {
     /**
      * @return {string}
      */

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

@@ -11,6 +11,7 @@ export interface IContainerServiceIdentifiers {
     IJavaScriptObfuscator: interfaces.ServiceIdentifier<any>;
     INodeTransformer: interfaces.ServiceIdentifier<any>;
     IObfuscationEventEmitter: interfaces.ServiceIdentifier<any>;
+    IObfuscationResult: interfaces.ServiceIdentifier<any>;
     IObfuscator: interfaces.ServiceIdentifier<any>;
     IOptions: interfaces.ServiceIdentifier<any>;
     IReplacer: interfaces.ServiceIdentifier<any>;

+ 6 - 2
src/interfaces/custom-nodes/ICustomNode.d.ts

@@ -1,13 +1,17 @@
 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';
 
-export interface ICustomNode {
+import { IInitializable } from '../IInitializable';
+
+export interface ICustomNode extends IInitializable {
     /**
      * @param astTree
+     * @param stackTraceData
      */
-    appendNode (astTree: ESTree.Node): void;
+    appendNode (astTree: ESTree.Node, stackTraceData: IStackTraceData[]): void;
 
     /**
      * @returns {TObfuscationEvent}

+ 0 - 3
src/interfaces/custom-nodes/ICustomNodeWithIdentifier.d.ts

@@ -1,8 +1,5 @@
 import { ICustomNode } from './ICustomNode';
 
 export interface ICustomNodeWithIdentifier extends ICustomNode {
-    /**
-     * @returns {string}
-     */
     getNodeIdentifier (): string;
 }

+ 3 - 5
src/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.ts

@@ -95,11 +95,9 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
             return;
         }
 
-        const controlFlowStorageCustomNode: ICustomNode = new ControlFlowStorageNode(
-            controlFlowStorage,
-            controlFlowStorageCustomNodeName,
-            this.options
-        );
+        const controlFlowStorageCustomNode: ICustomNode = new ControlFlowStorageNode(this.options);
+
+        controlFlowStorageCustomNode.initialize(controlFlowStorage, controlFlowStorageCustomNodeName);
 
         NodeAppender.prependNode(functionNode.body, controlFlowStorageCustomNode.getNode());
     }

+ 11 - 4
src/node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.ts

@@ -49,15 +49,22 @@ export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowRepl
         controlFlowStorageCustomNodeName: string
     ): ICustomNode {
         const key: string = AbstractControlFlowReplacer.getStorageKey();
+        const binaryExpressionFunctionNode = new BinaryExpressionFunctionNode(this.options);
 
-        controlFlowStorage.set(key, new BinaryExpressionFunctionNode(binaryExpressionNode.operator, this.options));
+        // TODO: pass through real stackTraceData
+        binaryExpressionFunctionNode.initialize(binaryExpressionNode.operator);
 
-        return new ControlFlowStorageCallNode(
+        controlFlowStorage.set(key, binaryExpressionFunctionNode);
+
+        const controlFlowStorageCallNode: ICustomNode = new ControlFlowStorageCallNode(this.options);
+
+        controlFlowStorageCallNode.initialize(
             controlFlowStorageCustomNodeName,
             key,
             BinaryExpressionControlFlowReplacer.getExpressionValue(binaryExpressionNode.left),
-            BinaryExpressionControlFlowReplacer.getExpressionValue(binaryExpressionNode.right),
-            this.options
+            BinaryExpressionControlFlowReplacer.getExpressionValue(binaryExpressionNode.right)
         );
+
+        return controlFlowStorageCallNode;
     }
 }

+ 53 - 1
src/storages/custom-nodes/CustomNodesStorage.ts

@@ -13,9 +13,10 @@ import { DomainLockCustomNodesFactory } from '../../custom-nodes/domain-lock-nod
 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';
 
 @injectable()
-export class CustomNodesStorage extends MapStorage <ICustomNode> {
+export class CustomNodesStorage extends MapStorage <ICustomNode> implements IInitializable {
     /**
      * @type {TCustomNodesFactory[]}
      */
@@ -27,6 +28,11 @@ export class CustomNodesStorage extends MapStorage <ICustomNode> {
         StringArrayCustomNodesFactory
     ];
 
+    /**
+     * @type {boolean}
+     */
+    public initialized: boolean = false;
+
     /**
      * @type {IOptions}
      */
@@ -40,6 +46,13 @@ export class CustomNodesStorage extends MapStorage <ICustomNode> {
 
         this.options = options;
     }
+
+    public checkInitialization (): void {
+        if (!this.initialized) {
+            throw new Error(`\`CustomNodesStorage\` should be initialized first by calling \`initialize\` method!`);
+        }
+    }
+
     /**
      * @param stackTraceData
      */
@@ -59,5 +72,44 @@ export class CustomNodesStorage extends MapStorage <ICustomNode> {
         });
 
         this.storage = new Map <string, ICustomNode> (customNodes);
+        this.initialized = true;
+    }
+
+    /**
+     * @param key
+     * @returns {ICustomNode}
+     */
+    public get (key: string | number): ICustomNode {
+        this.checkInitialization();
+
+        return super.get(key);
+    }
+
+    /**
+     * @param value
+     * @returns {string | number | null}
+     */
+    public getKeyOf (value: ICustomNode): string | number | null {
+        this.checkInitialization();
+
+        return super.getKeyOf(value);
+    }
+
+    /**
+     * @returns {number}
+     */
+    public getLength (): number {
+        this.checkInitialization();
+
+        return super.getLength();
+    }
+
+    /**
+     * @returns {Map <string | number, ICustomNode>}
+     */
+    public getStorage (): Map <string | number, ICustomNode> {
+        this.checkInitialization();
+
+        return super.getStorage();
     }
 }

+ 2 - 1
test/unit-tests/ObfuscationResult.spec.ts

@@ -11,7 +11,8 @@ describe('ObfuscationResult', () => {
             sourceMap: string = 'sourceMap';
 
         beforeEach(() => {
-            obfuscationResult = new ObfuscationResult(obfuscatedCode, sourceMap);
+            obfuscationResult = new ObfuscationResult();
+            obfuscationResult.initialize(obfuscatedCode, sourceMap);
         });
 
         it('should returns obfuscated code if `.toString()` was called on `ObfuscationResult` object', () => {

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