sanex3339 8 лет назад
Родитель
Сommit
7205a9bd0d
70 измененных файлов с 1391 добавлено и 940 удалено
  1. 513 276
      dist/index.js
  2. 4 4
      package.json
  3. 17 17
      src/JavaScriptObfuscatorInternal.ts
  4. 2 2
      src/Obfuscator.ts
  5. 1 1
      src/SourceMapCorrector.ts
  6. 1 1
      src/container/InversifyContainerFacade.ts
  7. 12 12
      src/container/ServiceIdentifiers.ts
  8. 51 33
      src/container/modules/custom-nodes/CustomNodesModule.ts
  9. 1 1
      src/container/modules/node-transformers/NodeControlFlowTransformersModule.ts
  10. 1 1
      src/container/modules/node-transformers/NodeObfuscatorsModule.ts
  11. 1 1
      src/container/modules/node-transformers/NodeTransformersModule.ts
  12. 1 1
      src/container/modules/stack-trace-analyzer/StackTraceAnalyzerModule.ts
  13. 14 11
      src/container/modules/storages/StoragesModule.ts
  14. 21 10
      src/custom-nodes/AbstractCustomNode.ts
  15. 10 0
      src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts
  16. 6 6
      src/custom-nodes/console-output-nodes/group/ConsoleOutputCustomNodeGroup.ts
  17. 27 12
      src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionNode.ts
  18. 25 19
      src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallNode.ts
  19. 26 9
      src/custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode.ts
  20. 10 0
      src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionCallNode.ts
  21. 10 0
      src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionIntervalNode.ts
  22. 10 0
      src/custom-nodes/debug-protection-nodes/DebugProtectionFunctionNode.ts
  23. 6 6
      src/custom-nodes/debug-protection-nodes/group/DebugProtectionCustomNodeGroup.ts
  24. 12 2
      src/custom-nodes/domain-lock-nodes/DomainLockNode.ts
  25. 6 6
      src/custom-nodes/domain-lock-nodes/group/DomainLockCustomNodeGroup.ts
  26. 13 4
      src/custom-nodes/node-calls-controller-nodes/NodeCallsControllerFunctionNode.ts
  27. 10 0
      src/custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode.ts
  28. 6 6
      src/custom-nodes/self-defending-nodes/group/SelfDefendingCustomNodeGroup.ts
  29. 34 24
      src/custom-nodes/string-array-nodes/StringArrayCallsWrapper.ts
  30. 8 0
      src/custom-nodes/string-array-nodes/StringArrayNode.ts
  31. 14 3
      src/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.ts
  32. 8 8
      src/custom-nodes/string-array-nodes/group/StringArrayCustomNodeGroup.ts
  33. 17 40
      src/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.ts
  34. 1 1
      src/node-transformers/node-control-flow-transformers/control-flow-replacers/AbstractControlFlowReplacer.ts
  35. 5 5
      src/node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.ts
  36. 1 1
      src/node-transformers/node-obfuscators/CatchClauseObfuscator.ts
  37. 1 1
      src/node-transformers/node-obfuscators/FunctionDeclarationObfuscator.ts
  38. 2 2
      src/node-transformers/node-obfuscators/FunctionObfuscator.ts
  39. 1 1
      src/node-transformers/node-obfuscators/LabeledStatementObfuscator.ts
  40. 1 1
      src/node-transformers/node-obfuscators/LiteralObfuscator.ts
  41. 24 32
      src/node-transformers/node-obfuscators/MemberExpressionObfuscator.ts
  42. 5 5
      src/node-transformers/node-obfuscators/MethodDefinitionObfuscator.ts
  43. 1 1
      src/node-transformers/node-obfuscators/VariableDeclarationObfuscator.ts
  44. 1 1
      src/node-transformers/node-obfuscators/replacers/AbstractReplacer.ts
  45. 10 12
      src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts
  46. 272 0
      src/node/Nodes.ts
  47. 1 1
      src/stack-trace-analyzer/StackTraceAnalyzer.ts
  48. 1 1
      src/storages/MapStorage.ts
  49. 0 14
      src/storages/control-flow/ControlFlowStorage.ts
  50. 2 2
      src/storages/custom-node-group/CustomNodeGroupStorage.ts
  51. 1 1
      src/storages/string-array/StringArrayStorage.ts
  52. 0 10
      src/templates/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionTemplate.ts
  53. 0 6
      src/templates/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallTemplate.ts
  54. 0 8
      src/templates/custom-nodes/control-flow-storage-nodes/ControlFlowStorageTemplate.ts
  55. 4 0
      src/types/storages/TControlFlowStorage.d.ts
  56. 4 0
      src/types/storages/TCustomNodeGroupStorage.d.ts
  57. 3 0
      src/types/storages/TStringArrayStorage.d.ts
  58. 17 3
      src/utils/Utils.ts
  59. 2 1
      test/dev/dev.ts
  60. 1 0
      test/fixtures/node-transformers/node-obfuscators/literal-obfuscator/literal-obfuscator-unicode-sequence.js
  61. 29 0
      test/functional-tests/node-transformers/node-obfuscators/LiteralObfuscator.spec.ts
  62. 11 11
      test/functional-tests/stack-trace-analyzer/StackTraceAnalyzer.spec.ts
  63. 0 1
      test/index.spec.ts
  64. 0 194
      test/mocks/NodeMocks.ts
  65. 16 16
      test/unit-tests/node/NodeAppender.spec.ts
  66. 59 44
      test/unit-tests/node/NodeUtils.spec.ts
  67. 0 42
      test/unit-tests/storages/ControlFlowStorage.spec.ts
  68. 8 3
      test/unit-tests/utils/Utils.spec.ts
  69. 2 2
      tslint.json
  70. 7 1
      webpack.config.js

Разница между файлами не показана из-за своего большого размера
+ 513 - 276
dist/index.js


+ 4 - 4
package.json

@@ -1,6 +1,6 @@
 {
   "name": "javascript-obfuscator",
-  "version": "0.9.0-dev.2",
+  "version": "0.9.0-dev.3",
   "description": "JavaScript obfuscator",
   "keywords": [
     "obfuscator",
@@ -44,10 +44,9 @@
     "@types/esprima": "2.1.33",
     "@types/estraverse": "0.0.6",
     "@types/estree": "0.0.34",
-    "@types/joi": "9.0.33",
-    "@types/lodash": "^4.14.43",
+    "@types/lodash": "^4.14.44",
     "@types/mkdirp": "0.3.29",
-    "@types/mocha": "2.2.33",
+    "@types/mocha": "2.2.34",
     "@types/node": "6.0.52",
     "@types/sinon": "1.16.33",
     "@types/string-template": "1.0.2",
@@ -63,6 +62,7 @@
     "sinon": "2.0.0-pre.3",
     "ts-node": "1.7.2",
     "tslint": "4.1.1",
+    "tslint-loader": "^3.3.0",
     "typescript": "2.1.4",
     "webpack": "2.1.0-beta.27",
     "webpack-node-externals": "1.5.4"

+ 17 - 17
src/JavaScriptObfuscatorInternal.ts

@@ -59,6 +59,23 @@ export class JavaScriptObfuscatorInternal implements IJavaScriptObfuscator {
         this.options = options;
     }
 
+    /**
+     * @param sourceCode
+     * @returns {IObfuscationResult}
+     */
+    public obfuscate (sourceCode: string): IObfuscationResult {
+        // parse AST tree
+        const astTree: ESTree.Program = esprima.parse(sourceCode, JavaScriptObfuscatorInternal.esprimaParams);
+
+        // obfuscate AST tree
+        const obfuscatedAstTree: ESTree.Program = this.obfuscator.obfuscateAstTree(astTree);
+
+        // generate code
+        const generatorOutput: IGeneratorOutput = this.generateCode(sourceCode, obfuscatedAstTree);
+
+        return this.getObfuscationResult(generatorOutput);
+    }
+
     /**
      * @param sourceCode
      * @param astTree
@@ -94,21 +111,4 @@ export class JavaScriptObfuscatorInternal implements IJavaScriptObfuscator {
             generatorOutput.map
         );
     }
-
-    /**
-     * @param sourceCode
-     * @returns {IObfuscationResult}
-     */
-    public obfuscate (sourceCode: string): IObfuscationResult {
-        // parse AST tree
-        const astTree: ESTree.Program = esprima.parse(sourceCode, JavaScriptObfuscatorInternal.esprimaParams);
-
-        // obfuscate AST tree
-        const obfuscatedAstTree: ESTree.Program = this.obfuscator.obfuscateAstTree(astTree);
-
-        // generate code
-        const generatorOutput: IGeneratorOutput = this.generateCode(sourceCode, obfuscatedAstTree);
-
-        return this.getObfuscationResult(generatorOutput);
-    }
 }

+ 2 - 2
src/Obfuscator.ts

@@ -89,8 +89,8 @@ export class Obfuscator implements IObfuscator {
     constructor (
         @inject(ServiceIdentifiers.IStackTraceAnalyzer) stackTraceAnalyzer: IStackTraceAnalyzer,
         @inject(ServiceIdentifiers.IObfuscationEventEmitter) obfuscationEventEmitter: IObfuscationEventEmitter,
-        @inject(ServiceIdentifiers['IStorage<ICustomNodeGroup>']) customNodeGroupStorage: IStorage<ICustomNodeGroup>,
-        @inject(ServiceIdentifiers['Factory<INodeTransformer[]>']) nodeTransformersFactory: TNodeTransformersFactory,
+        @inject(ServiceIdentifiers.TCustomNodeGroupStorage) customNodeGroupStorage: IStorage<ICustomNodeGroup>,
+        @inject(ServiceIdentifiers.Factory__INodeTransformer) nodeTransformersFactory: TNodeTransformersFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         this.stackTraceAnalyzer = stackTraceAnalyzer;

+ 1 - 1
src/SourceMapCorrector.ts

@@ -28,7 +28,7 @@ export class SourceMapCorrector implements ISourceMapCorrector {
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['Factory<IObfuscationResult>']) obfuscationResultFactory: TObfuscationResultFactory,
+        @inject(ServiceIdentifiers.Factory__IObfuscationResult) obfuscationResultFactory: TObfuscationResultFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         this.obfuscationResultFactory = obfuscationResultFactory;

+ 1 - 1
src/container/InversifyContainerFacade.ts

@@ -60,7 +60,7 @@ export class InversifyContainerFacade implements IInversifyContainerFacade {
             .inSingletonScope();
 
         this.container
-            .bind<IObfuscationResult>(ServiceIdentifiers['Factory<IObfuscationResult>'])
+            .bind<IObfuscationResult>(ServiceIdentifiers.Factory__IObfuscationResult)
             .toFactory<IObfuscationResult>((context: interfaces.Context) => {
                 return (obfuscatedCode: string, sourceMap: string) => {
                     const obfuscationResult: IObfuscationResult = context.container

+ 12 - 12
src/container/ServiceIdentifiers.ts

@@ -1,14 +1,13 @@
 export const ServiceIdentifiers: any = {
-    'Factory<ICalleeDataExtractor>': Symbol('Factory<ICalleeDataExtractor>'),
-    'Factory<IControlFlowReplacer>': Symbol('Factory<IControlFlowReplacer>'),
-    'Factory<ICustomNode>': Symbol('Factory<ICustomNode>'),
-    'Factory<ICustomNodeGroup>': Symbol('Factory<ICustomNodeGroup>'),
-    'Factory<INodeTransformer[]>': Symbol('Factory<INodeTransformer[]>'),
-    'Factory<IObfuscationResult>': Symbol('Factory<IObfuscationResult>'),
-    'Factory<IObfuscatorReplacer>': Symbol('Factory<IObfuscatorReplacer>'),
-    'Factory<IStorage<ICustomNode>>': Symbol('Factory<IStorage<ICustomNode>>'),
+    Factory__ICalleeDataExtractor: Symbol('Factory<ICalleeDataExtractor>'),
+    Factory__IControlFlowReplacer: Symbol('Factory<IControlFlowReplacer>'),
+    Factory__ICustomNode: Symbol('Factory<ICustomNode>'),
+    Factory__ICustomNodeGroup: Symbol('Factory<ICustomNodeGroup>'),
+    Factory__INodeTransformer: Symbol('Factory<INodeTransformer[]>'),
+    Factory__IObfuscationResult: Symbol('Factory<IObfuscationResult>'),
+    Factory__IObfuscatorReplacer: Symbol('Factory<IObfuscatorReplacer>'),
+    Factory__TControlFlowStorage: Symbol('Factory<TControlFlowStorage>'),
     ICalleeDataExtractor: Symbol('ICalleeDataExtractor'),
-    ICustomNode: Symbol('ICustomNode'),
     ICustomNodeGroup: Symbol('ICustomNodeGroup'),
     IControlFlowReplacer: Symbol('IControlFlowReplacer'),
     IJavaScriptObfuscator: Symbol('IJavaScriptObfuscator'),
@@ -20,7 +19,8 @@ export const ServiceIdentifiers: any = {
     IObfuscatorReplacer: Symbol('IObfuscatorReplacer'),
     ISourceMapCorrector: Symbol('ISourceMapCorrector'),
     IStackTraceAnalyzer: Symbol('IStackTraceAnalyzer'),
-    'IStorage<ICustomNode>': Symbol('IStorage<ICustomNode>'),
-    'IStorage<ICustomNodeGroup>': Symbol('IStorage<ICustomNodeGroup>'),
-    'IStorage<string>': Symbol('IStorage<string>')
+    Newable__ICustomNode: Symbol('Newable<ICustomNode>'),
+    Newable__TControlFlowStorage: Symbol('Newable<TControlFlowStorage>'),
+    TCustomNodeGroupStorage: Symbol('TCustomNodeGroupStorage'),
+    TStringArrayStorage: Symbol('TStringArrayStorage')
 };

+ 51 - 33
src/container/modules/custom-nodes/CustomNodesModule.ts

@@ -3,6 +3,7 @@ import { ServiceIdentifiers } from '../../ServiceIdentifiers';
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { ICustomNodeGroup } from '../../../interfaces/custom-nodes/ICustomNodeGroup';
+import { IOptions } from '../../../interfaces/options/IOptions';
 
 import { CustomNodes } from '../../../enums/container/CustomNodes';
 import { CustomNodeGroups } from '../../../enums/container/CustomNodeGroups';
@@ -29,56 +30,56 @@ import { StringArrayRotateFunctionNode } from '../../../custom-nodes/string-arra
 
 export const customNodesModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
     // custom nodes
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(BinaryExpressionFunctionNode)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(BinaryExpressionFunctionNode)
         .whenTargetNamed(CustomNodes.BinaryExpressionFunctionNode);
 
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(ControlFlowStorageCallNode)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(ControlFlowStorageCallNode)
         .whenTargetNamed(CustomNodes.ControlFlowStorageCallNode);
 
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(ControlFlowStorageNode)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(ControlFlowStorageNode)
         .whenTargetNamed(CustomNodes.ControlFlowStorageNode);
 
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(ConsoleOutputDisableExpressionNode)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(ConsoleOutputDisableExpressionNode)
         .whenTargetNamed(CustomNodes.ConsoleOutputDisableExpressionNode);
 
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(DebugProtectionFunctionCallNode)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(DebugProtectionFunctionCallNode)
         .whenTargetNamed(CustomNodes.DebugProtectionFunctionCallNode);
 
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(DebugProtectionFunctionIntervalNode)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(DebugProtectionFunctionIntervalNode)
         .whenTargetNamed(CustomNodes.DebugProtectionFunctionIntervalNode);
 
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(DebugProtectionFunctionNode)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(DebugProtectionFunctionNode)
         .whenTargetNamed(CustomNodes.DebugProtectionFunctionNode);
 
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(DomainLockNode)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(DomainLockNode)
         .whenTargetNamed(CustomNodes.DomainLockNode);
 
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(NodeCallsControllerFunctionNode)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(NodeCallsControllerFunctionNode)
         .whenTargetNamed(CustomNodes.NodeCallsControllerFunctionNode);
 
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(SelfDefendingUnicodeNode)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(SelfDefendingUnicodeNode)
         .whenTargetNamed(CustomNodes.SelfDefendingUnicodeNode);
 
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(StringArrayCallsWrapper)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(StringArrayCallsWrapper)
         .whenTargetNamed(CustomNodes.StringArrayCallsWrapper);
 
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(StringArrayNode)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(StringArrayNode)
         .whenTargetNamed(CustomNodes.StringArrayNode);
 
-    bind<ICustomNode>(ServiceIdentifiers.ICustomNode)
-        .to(StringArrayRotateFunctionNode)
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(StringArrayRotateFunctionNode)
         .whenTargetNamed(CustomNodes.StringArrayRotateFunctionNode);
 
     // node groups
@@ -103,18 +104,35 @@ export const customNodesModule: interfaces.ContainerModule = new ContainerModule
         .whenTargetNamed(CustomNodeGroups.StringArrayCustomNodeGroup);
 
     // customNode factory
-    bind<ICustomNode>(ServiceIdentifiers['Factory<ICustomNode>'])
+    bind<ICustomNode>(ServiceIdentifiers.Factory__ICustomNode)
         .toFactory<ICustomNode>((context: interfaces.Context) => {
+            const cache: Map <CustomNodes, interfaces.Newable<ICustomNode>> = new Map();
+
+            let cachedOptions: IOptions;
+
             return (customNodeName: CustomNodes) => {
-                return context.container.getNamed<ICustomNode>(
-                    ServiceIdentifiers.ICustomNode,
-                    customNodeName
-                );
+                if (!cachedOptions) {
+                    cachedOptions = context.container.get<IOptions>(ServiceIdentifiers.IOptions);
+                }
+
+                if (cache.has(customNodeName)) {
+                    return new (<interfaces.Newable<ICustomNode>>cache.get(customNodeName));
+                }
+
+                const constructor: interfaces.Newable<ICustomNode> = context.container
+                    .getNamed<interfaces.Newable<ICustomNode>>(
+                        ServiceIdentifiers.Newable__ICustomNode,
+                        customNodeName
+                    );
+
+                cache.set(customNodeName, constructor);
+
+                return new constructor(cachedOptions);
             };
         });
 
-    // CustomNodeGroup factory
-    bind<ICustomNodeGroup>(ServiceIdentifiers['Factory<ICustomNodeGroup>'])
+    // customNodeGroup factory
+    bind<ICustomNodeGroup>(ServiceIdentifiers.Factory__ICustomNodeGroup)
         .toFactory<ICustomNodeGroup>((context: interfaces.Context) => {
             return (customNodeGroupName: CustomNodeGroups) => {
                 return context.container.getNamed<ICustomNodeGroup>(

+ 1 - 1
src/container/modules/node-transformers/NodeControlFlowTransformersModule.ts

@@ -12,7 +12,7 @@ export const nodeControlFlowTransformersModule: interfaces.ContainerModule = new
         .to(BinaryExpressionControlFlowReplacer)
         .whenTargetNamed(NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer);
 
-    bind<IControlFlowReplacer>(ServiceIdentifiers['Factory<IControlFlowReplacer>'])
+    bind<IControlFlowReplacer>(ServiceIdentifiers.Factory__IControlFlowReplacer)
         .toFactory<IControlFlowReplacer>((context: interfaces.Context) => {
             const cache: Map <NodeControlFlowReplacers, IControlFlowReplacer> = new Map();
 

+ 1 - 1
src/container/modules/node-transformers/NodeObfuscatorsModule.ts

@@ -27,7 +27,7 @@ export const nodeObfuscatorsModule: interfaces.ContainerModule = new ContainerMo
         .to(StringLiteralReplacer)
         .whenTargetNamed(NodeObfuscatorsReplacers.StringLiteralReplacer);
 
-    bind<IObfuscatorReplacer>(ServiceIdentifiers['Factory<IObfuscatorReplacer>'])
+    bind<IObfuscatorReplacer>(ServiceIdentifiers.Factory__IObfuscatorReplacer)
         .toFactory<IObfuscatorReplacer>((context: interfaces.Context) => {
             const cache: Map <NodeObfuscatorsReplacers, IObfuscatorReplacer> = new Map();
 

+ 1 - 1
src/container/modules/node-transformers/NodeTransformersModule.ts

@@ -61,7 +61,7 @@ export const nodeTransformersModule: interfaces.ContainerModule = new ContainerM
         .whenTargetNamed(NodeTransformers.VariableDeclarationObfuscator);
 
     // node transformers factory
-    bind<INodeTransformer[]>(ServiceIdentifiers['Factory<INodeTransformer[]>'])
+    bind<INodeTransformer[]>(ServiceIdentifiers.Factory__INodeTransformer)
         .toFactory<INodeTransformer[]>((context: interfaces.Context) => {
             const cache: Map <NodeTransformers, INodeTransformer> = new Map();
 

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

@@ -30,7 +30,7 @@ export const stackTraceAnalyzerModule: interfaces.ContainerModule = new Containe
         .whenTargetNamed(CalleeDataExtractors.ObjectExpressionCalleeDataExtractor);
 
     // node transformers factory
-    bind<ICalleeDataExtractor>(ServiceIdentifiers['Factory<ICalleeDataExtractor>'])
+    bind<ICalleeDataExtractor>(ServiceIdentifiers.Factory__ICalleeDataExtractor)
         .toFactory<ICalleeDataExtractor>((context: interfaces.Context) => {
             const cache: Map <CalleeDataExtractors, ICalleeDataExtractor> = new Map();
 

+ 14 - 11
src/container/modules/storages/StoragesModule.ts

@@ -1,9 +1,9 @@
 import { ContainerModule, interfaces } from 'inversify';
 import { ServiceIdentifiers } from '../../ServiceIdentifiers';
 
-import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
-import { ICustomNodeGroup } from '../../../interfaces/custom-nodes/ICustomNodeGroup';
-import { IStorage } from '../../../interfaces/storages/IStorage';
+import { TControlFlowStorage } from '../../../types/storages/TControlFlowStorage';
+import { TCustomNodeGroupStorage } from '../../../types/storages/TCustomNodeGroupStorage';
+import { TStringArrayStorage } from '../../../types/storages/TStringArrayStorage';
 
 import { ControlFlowStorage } from '../../../storages/control-flow/ControlFlowStorage';
 import { CustomNodeGroupStorage } from '../../../storages/custom-node-group/CustomNodeGroupStorage';
@@ -11,22 +11,25 @@ import { StringArrayStorage } from '../../../storages/string-array/StringArraySt
 
 export const storagesModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
     // storages
-    bind<IStorage<ICustomNodeGroup>>(ServiceIdentifiers['IStorage<ICustomNodeGroup>'])
+    bind<TCustomNodeGroupStorage>(ServiceIdentifiers.TCustomNodeGroupStorage)
         .to(CustomNodeGroupStorage)
         .inSingletonScope();
 
-    bind<IStorage<ICustomNode>>(ServiceIdentifiers['IStorage<ICustomNode>'])
-        .to(ControlFlowStorage);
-
-    bind<IStorage<string>>(ServiceIdentifiers['IStorage<string>'])
+    bind<TStringArrayStorage>(ServiceIdentifiers.TStringArrayStorage)
         .to(StringArrayStorage)
         .inSingletonScope();
 
+    bind<interfaces.Newable<TControlFlowStorage>>(ServiceIdentifiers.Newable__TControlFlowStorage)
+        .toConstructor(ControlFlowStorage);
+
     // controlFlowStorage factory
-    bind<IStorage<ICustomNode>>(ServiceIdentifiers['Factory<IStorage<ICustomNode>>'])
-        .toFactory<IStorage<ICustomNode>>((context: interfaces.Context) => {
+    bind<TControlFlowStorage>(ServiceIdentifiers.Factory__TControlFlowStorage)
+        .toFactory<TControlFlowStorage>((context: interfaces.Context) => {
             return () => {
-                return context.container.get<IStorage<ICustomNode>>(ServiceIdentifiers['IStorage<ICustomNode>']);
+                const constructor: interfaces.Newable<TControlFlowStorage> = context.container
+                    .get<interfaces.Newable<TControlFlowStorage>>(ServiceIdentifiers.Newable__TControlFlowStorage);
+
+                return new constructor();
             };
         });
 });

+ 21 - 10
src/custom-nodes/AbstractCustomNode.ts

@@ -9,6 +9,16 @@ import { NodeUtils } from '../node/NodeUtils';
 
 @injectable()
 export abstract class AbstractCustomNode implements ICustomNode {
+    /**
+     * @type {string}
+     */
+    protected cachedCode: string;
+
+    /**
+     * @type {TStatement[]}
+     */
+    protected cachedNode: TStatement[];
+
     /**
      * @type {IOptions}
      */
@@ -32,25 +42,26 @@ export abstract class AbstractCustomNode implements ICustomNode {
      * @returns {string}
      */
     public getCode (): string {
-        return NodeUtils.convertStructureToCode(this.getNode());
+        if (!this.cachedCode) {
+            this.cachedCode = NodeUtils.convertStructureToCode(this.getNode());
+        }
+
+        return this.cachedCode;
     }
 
     /**
      * @returns {TStatement[]}
      */
     public getNode (): TStatement[] {
-        return this.getNodeStructure();
-    }
+        if (!this.cachedNode) {
+            this.cachedNode = this.getNodeStructure();
+        }
 
-    /**
-     * @returns {TStatement[]}
-     */
-    protected getNodeStructure (): TStatement[] {
-        return NodeUtils.convertCodeToStructure(this.getTemplate());
+        return this.cachedNode;
     }
 
     /**
-     * @returns {string}
+     * @returns {TStatement[]}
      */
-    protected abstract getTemplate (): string;
+    protected abstract getNodeStructure (): TStatement[];
 }

+ 10 - 0
src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts

@@ -3,6 +3,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
+import { TStatement } from '../../types/node/TStatement';
+
 import { IOptions } from '../../interfaces/options/IOptions';
 
 import { ConsoleOutputDisableExpressionTemplate } from '../../templates/custom-nodes/console-output-nodes/console-output-disable-expression-node/ConsoleOutputDisableExpressionTemplate';
@@ -10,6 +12,7 @@ import { ConsoleOutputDisableExpressionTemplate } from '../../templates/custom-n
 import { initializable } from '../../decorators/Initializable';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
+import { NodeUtils } from '../../node/NodeUtils';
 import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
 
 @injectable()
@@ -36,6 +39,13 @@ export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
         this.callsControllerFunctionName = callsControllerFunctionName;
     }
 
+    /**
+     * @returns {TStatement[]}
+     */
+    protected getNodeStructure (): TStatement[] {
+        return NodeUtils.convertCodeToStructure(this.getTemplate());
+    }
+
     /**
      * @returns {string}
      */

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

@@ -26,17 +26,17 @@ export class ConsoleOutputCustomNodeGroup extends AbstractCustomNodeGroup {
      */
     protected readonly appendEvent: TObfuscationEvent = ObfuscationEvents.BeforeObfuscation;
 
-    /**
-     * @type {TCustomNodeFactory}
-     */
-    private readonly customNodeFactory: TCustomNodeFactory;
-
     /**
      * @type {Map<CustomNodes, ICustomNode>}
      */
     @initializable()
     protected customNodes: Map <CustomNodes, ICustomNode>;
 
+    /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
     /**
      * @type {IObfuscationEventEmitter}
      */
@@ -48,7 +48,7 @@ export class ConsoleOutputCustomNodeGroup extends AbstractCustomNodeGroup {
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IObfuscationEventEmitter) obfuscationEventEmitter: IObfuscationEventEmitter,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {

+ 27 - 12
src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionNode.ts

@@ -1,24 +1,25 @@
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
-import * as format from 'string-template';
+import { BinaryOperator } from 'estree';
+
+import { TStatement } from '../../../types/node/TStatement';
 
 import { IOptions } from '../../../interfaces/options/IOptions';
 
 import { initializable } from '../../../decorators/Initializable';
 
-import { BinaryExpressionFunctionTemplate } from '../../../templates/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionTemplate';
-
 import { AbstractCustomNode } from '../../AbstractCustomNode';
+import { Nodes } from '../../../node/Nodes';
 import { RandomGeneratorUtils } from '../../../utils/RandomGeneratorUtils';
 
 @injectable()
 export class BinaryExpressionFunctionNode extends AbstractCustomNode {
     /**
-     * @type {string}
+     * @type {BinaryOperator}
      */
     @initializable()
-    private operator: string;
+    private operator: BinaryOperator;
 
     /**
      * @param options
@@ -32,17 +33,31 @@ export class BinaryExpressionFunctionNode extends AbstractCustomNode {
     /**
      * @param operator
      */
-    public initialize (operator: string): void {
+    public initialize (operator: BinaryOperator): void {
         this.operator = operator;
     }
 
     /**
-     * @returns {string}
+     * @returns {TStatement[]}
      */
-    protected getTemplate (): string {
-        return format(BinaryExpressionFunctionTemplate(), {
-            functionName: RandomGeneratorUtils.getRandomVariableName(1),
-            operator: this.operator
-        });
+    protected getNodeStructure (): TStatement[] {
+        return [
+            Nodes.getFunctionDeclarationNode(
+                RandomGeneratorUtils.getRandomVariableName(1),
+                [
+                    Nodes.getIdentifierNode('x'),
+                    Nodes.getIdentifierNode('y')
+                ],
+                Nodes.getBlockStatementNode([
+                    Nodes.getReturnStatementNode(
+                        Nodes.getBinaryExpressionNode(
+                            this.operator,
+                            Nodes.getIdentifierNode('x'),
+                            Nodes.getIdentifierNode('y')
+                        )
+                    )
+                ])
+            )
+        ];
     }
 }

+ 25 - 19
src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallNode.ts

@@ -1,15 +1,16 @@
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
-import * as format from 'string-template';
+import { Expression } from 'estree';
+
+import { TStatement } from '../../../types/node/TStatement';
 
 import { IOptions } from '../../../interfaces/options/IOptions';
 
 import { initializable } from '../../../decorators/Initializable';
 
-import { ControlFlowStorageCallTemplate } from '../../../templates/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallTemplate';
-
 import { AbstractCustomNode } from '../../AbstractCustomNode';
+import { Nodes } from '../../../node/Nodes';
 
 @injectable()
 export class ControlFlowStorageCallNode extends AbstractCustomNode {
@@ -26,16 +27,16 @@ export class ControlFlowStorageCallNode extends AbstractCustomNode {
     private controlFlowStorageName: string;
 
     /**
-     * @type {string}
+     * @type {Expression}
      */
     @initializable()
-    private leftValue: string;
+    private leftValue: Expression;
 
     /**
-     * @type {string}
+     * @type {ESTree.Expression}
      */
     @initializable()
-    private rightValue: string;
+    private rightValue: Expression;
 
     /**
      * @param options
@@ -55,8 +56,8 @@ export class ControlFlowStorageCallNode extends AbstractCustomNode {
     public initialize (
         controlFlowStorageName: string,
         controlFlowStorageKey: string,
-        leftValue: string,
-        rightValue: string,
+        leftValue: Expression,
+        rightValue: Expression,
     ): void {
         this.controlFlowStorageName = controlFlowStorageName;
         this.controlFlowStorageKey = controlFlowStorageKey;
@@ -64,15 +65,20 @@ export class ControlFlowStorageCallNode extends AbstractCustomNode {
         this.rightValue = rightValue;
     }
 
-    /**
-     * @returns {string}
-     */
-    protected getTemplate (): string {
-        return format(ControlFlowStorageCallTemplate(), {
-            controlFlowStorageKey: this.controlFlowStorageKey,
-            controlFlowStorageName: this.controlFlowStorageName,
-            leftValue: this.leftValue,
-            rightValue: this.rightValue
-        });
+    protected getNodeStructure (): TStatement[] {
+        return [
+            Nodes.getExpressionStatementNode(
+                Nodes.getCallExpressionNode(
+                    Nodes.getMemberExpressionNode(
+                        Nodes.getIdentifierNode(this.controlFlowStorageName),
+                        Nodes.getIdentifierNode(this.controlFlowStorageKey)
+                    ),
+                    [
+                        this.leftValue,
+                        this.rightValue
+                    ]
+                )
+            )
+        ];
     }
 }

+ 26 - 9
src/custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode.ts

@@ -1,7 +1,9 @@
 import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
-import * as format from 'string-template';
+import * as ESTree from 'estree';
+
+import { TStatement } from '../../types/node/TStatement';
 
 import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
@@ -9,9 +11,9 @@ import { IStorage } from '../../interfaces/storages/IStorage';
 
 import { initializable } from '../../decorators/Initializable';
 
-import { ControlFlowStorageTemplate } from '../../templates/custom-nodes/control-flow-storage-nodes/ControlFlowStorageTemplate';
-
 import { AbstractCustomNode } from '../AbstractCustomNode';
+import { Nodes } from '../../node/Nodes';
+import { NodeUtils } from '../../node/NodeUtils';
 
 @injectable()
 export class ControlFlowStorageNode extends AbstractCustomNode {
@@ -38,12 +40,27 @@ export class ControlFlowStorageNode extends AbstractCustomNode {
     }
 
     /**
-     * @returns {string}
+     * @returns {TStatement[]}
      */
-    protected getTemplate (): string {
-        return format(ControlFlowStorageTemplate(), {
-            controlFlowStorage: this.controlFlowStorage.toString(),
-            controlFlowStorageName: this.controlFlowStorage.getStorageId()
-        });
+    protected getNodeStructure (): TStatement[] {
+        const structure: ESTree.Node = Nodes.getVariableDeclarationNode([
+            Nodes.getVariableDeclaratorNode(
+                Nodes.getIdentifierNode(this.controlFlowStorage.getStorageId()),
+                Nodes.getObjectExpressionNode(
+                    Array
+                        .from(this.controlFlowStorage.getStorage())
+                        .map(([key, value]: [string, ICustomNode]) => {
+                            return Nodes.getPropertyNode(
+                                Nodes.getIdentifierNode(key),
+                                <any>value.getNode()[0]
+                            );
+                        })
+                )
+            )
+        ]);
+
+        NodeUtils.parentize(structure);
+
+        return [structure];
     }
 }

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

@@ -3,6 +3,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
+import { TStatement } from '../../types/node/TStatement';
+
 import { IOptions } from '../../interfaces/options/IOptions';
 
 import { initializable } from '../../decorators/Initializable';
@@ -10,6 +12,7 @@ import { initializable } from '../../decorators/Initializable';
 import { DebugProtectionFunctionCallTemplate } from '../../templates/custom-nodes/debug-protection-nodes/debug-protection-function-call-node/DebufProtectionFunctionCallTemplate';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
+import { NodeUtils } from '../../node/NodeUtils';
 
 @injectable()
 export class DebugProtectionFunctionCallNode extends AbstractCustomNode {
@@ -35,6 +38,13 @@ export class DebugProtectionFunctionCallNode extends AbstractCustomNode {
         this.debugProtectionFunctionName = debugProtectionFunctionName;
     }
 
+    /**
+     * @returns {TStatement[]}
+     */
+    protected getNodeStructure (): TStatement[] {
+        return NodeUtils.convertCodeToStructure(this.getTemplate());
+    }
+
     /**
      * @returns {string}
      */

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

@@ -3,6 +3,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
+import { TStatement } from '../../types/node/TStatement';
+
 import { IOptions } from '../../interfaces/options/IOptions';
 
 import { initializable } from '../../decorators/Initializable';
@@ -10,6 +12,7 @@ import { initializable } from '../../decorators/Initializable';
 import { DebugProtectionFunctionIntervalTemplate } from '../../templates/custom-nodes/debug-protection-nodes/debug-protection-function-interval-node/DebugProtectionFunctionIntervalTemplate';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
+import { NodeUtils } from '../../node/NodeUtils';
 
 @injectable()
 export class DebugProtectionFunctionIntervalNode extends AbstractCustomNode {
@@ -35,6 +38,13 @@ export class DebugProtectionFunctionIntervalNode extends AbstractCustomNode {
         this.debugProtectionFunctionName = debugProtectionFunctionName;
     }
 
+    /**
+     * @returns {TStatement[]}
+     */
+    protected getNodeStructure (): TStatement[] {
+        return NodeUtils.convertCodeToStructure(this.getTemplate());
+    }
+
     /**
      * @returns {string}
      */

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

@@ -3,6 +3,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
+import { TStatement } from '../../types/node/TStatement';
+
 import { IOptions } from '../../interfaces/options/IOptions';
 
 import { initializable } from '../../decorators/Initializable';
@@ -10,6 +12,7 @@ import { initializable } from '../../decorators/Initializable';
 import { DebugProtectionFunctionTemplate } from '../../templates/custom-nodes/debug-protection-nodes/debug-protection-function-node/DebugProtectionFunctionTemplate';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
+import { NodeUtils } from '../../node/NodeUtils';
 
 @injectable()
 export class DebugProtectionFunctionNode extends AbstractCustomNode {
@@ -35,6 +38,13 @@ export class DebugProtectionFunctionNode extends AbstractCustomNode {
         this.debugProtectionFunctionName = debugProtectionFunctionName;
     }
 
+    /**
+     * @returns {TStatement[]}
+     */
+    protected getNodeStructure (): TStatement[] {
+        return NodeUtils.convertCodeToStructure(this.getTemplate());
+    }
+
     /**
      * @returns {string}
      */

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

@@ -26,17 +26,17 @@ export class DebugProtectionCustomNodeGroup extends AbstractCustomNodeGroup {
      */
     protected readonly appendEvent: TObfuscationEvent = ObfuscationEvents.BeforeObfuscation;
 
-    /**
-     * @type {TCustomNodeFactory}
-     */
-    private readonly customNodeFactory: TCustomNodeFactory;
-
     /**
      * @type {Map<CustomNodes, ICustomNode>}
      */
     @initializable()
     protected customNodes: Map <CustomNodes, ICustomNode>;
 
+    /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
     /**
      * @type {IObfuscationEventEmitter}
      */
@@ -48,7 +48,7 @@ export class DebugProtectionCustomNodeGroup extends AbstractCustomNodeGroup {
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IObfuscationEventEmitter) obfuscationEventEmitter: IObfuscationEventEmitter,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {

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

@@ -3,6 +3,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
+import { TStatement } from '../../types/node/TStatement';
+
 import { IOptions } from '../../interfaces/options/IOptions';
 
 import { initializable } from '../../decorators/Initializable';
@@ -11,6 +13,7 @@ import { DomainLockNodeTemplate } from '../../templates/custom-nodes/domain-lock
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { CryptUtils } from '../../utils/CryptUtils';
+import { NodeUtils } from '../../node/NodeUtils';
 import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
 
 @injectable()
@@ -37,12 +40,19 @@ export class DomainLockNode extends AbstractCustomNode {
         this.callsControllerFunctionName = callsControllerFunctionName;
     }
 
+    /**
+     * @returns {TStatement[]}
+     */
+    protected getNodeStructure (): TStatement[] {
+        return NodeUtils.convertCodeToStructure(this.getTemplate());
+    }
+
     /**
      * @returns {string}
      */
     protected getTemplate (): string {
-        let domainsString: string = this.options.domainLock.join(';'),
-            [hiddenDomainsString, diff]: string[] = CryptUtils.hideString(domainsString, domainsString.length * 3);
+        const domainsString: string = this.options.domainLock.join(';');
+        const [hiddenDomainsString, diff]: string[] = CryptUtils.hideString(domainsString, domainsString.length * 3);
 
         return format(DomainLockNodeTemplate(), {
             domainLockFunctionName: RandomGeneratorUtils.getRandomVariableName(),

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

@@ -26,17 +26,17 @@ export class DomainLockCustomNodeGroup extends AbstractCustomNodeGroup {
      */
     protected readonly appendEvent: TObfuscationEvent = ObfuscationEvents.BeforeObfuscation;
 
-    /**
-     * @type {TCustomNodeFactory}
-     */
-    private readonly customNodeFactory: TCustomNodeFactory;
-
     /**
      * @type {Map<CustomNodes, ICustomNode>}
      */
     @initializable()
     protected customNodes: Map <CustomNodes, ICustomNode>;
 
+    /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
     /**
      * @type {IObfuscationEventEmitter}
      */
@@ -48,7 +48,7 @@ export class DomainLockCustomNodeGroup extends AbstractCustomNodeGroup {
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IObfuscationEventEmitter) obfuscationEventEmitter: IObfuscationEventEmitter,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {

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

@@ -4,6 +4,7 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 import * as format from 'string-template';
 
 import { TObfuscationEvent } from '../../types/event-emitters/TObfuscationEvent';
+import { TStatement } from '../../types/node/TStatement';
 
 import { IOptions } from '../../interfaces/options/IOptions';
 
@@ -17,20 +18,21 @@ import { NO_CUSTOM_NODES_PRESET } from '../../options/presets/NoCustomNodes';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { JavaScriptObfuscator } from '../../JavaScriptObfuscator';
+import { NodeUtils } from '../../node/NodeUtils';
 
 @injectable()
 export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
     /**
-     * @type {TObfuscationEvent}
+     * @type {string}
      */
     @initializable()
-    private appendEvent: TObfuscationEvent;
+    protected callsControllerFunctionName: string;
 
     /**
-     * @type {string}
+     * @type {TObfuscationEvent}
      */
     @initializable()
-    protected callsControllerFunctionName: string;
+    private appendEvent: TObfuscationEvent;
 
     /**
      * @param options
@@ -50,6 +52,13 @@ export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
         this.callsControllerFunctionName = callsControllerFunctionName;
     }
 
+    /**
+     * @returns {TStatement[]}
+     */
+    protected getNodeStructure (): TStatement[] {
+        return NodeUtils.convertCodeToStructure(this.getTemplate());
+    }
+
     /**
      * @returns {string}
      */

+ 10 - 0
src/custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode.ts

@@ -3,6 +3,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
+import { TStatement } from '../../types/node/TStatement';
+
 import { IOptions } from '../../interfaces/options/IOptions';
 
 import { initializable } from '../../decorators/Initializable';
@@ -13,6 +15,7 @@ import { SelfDefendingTemplate } from '../../templates/custom-nodes/self-defendi
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { JavaScriptObfuscator } from '../../JavaScriptObfuscator';
+import { NodeUtils } from '../../node/NodeUtils';
 import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
 
 @injectable()
@@ -39,6 +42,13 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
         this.callsControllerFunctionName = callsControllerFunctionName;
     }
 
+    /**
+     * @returns {TStatement[]}
+     */
+    protected getNodeStructure (): TStatement[] {
+        return NodeUtils.convertCodeToStructure(this.getTemplate());
+    }
+
     /**
      * @returns {string}
      */

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

@@ -26,17 +26,17 @@ export class SelfDefendingCustomNodeGroup extends AbstractCustomNodeGroup {
      */
     protected appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
 
-    /**
-     * @type {TCustomNodeFactory}
-     */
-    private readonly customNodeFactory: TCustomNodeFactory;
-
     /**
      * @type {Map<CustomNodes, ICustomNode>}
      */
     @initializable()
     protected customNodes: Map <CustomNodes, ICustomNode>;
 
+    /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
     /**
      * @type {IObfuscationEventEmitter}
      */
@@ -48,7 +48,7 @@ export class SelfDefendingCustomNodeGroup extends AbstractCustomNodeGroup {
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IObfuscationEventEmitter) obfuscationEventEmitter: IObfuscationEventEmitter,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {

+ 34 - 24
src/custom-nodes/string-array-nodes/StringArrayCallsWrapper.ts

@@ -3,6 +3,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
+import { TStatement } from '../../types/node/TStatement';
+
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IStorage } from '../../interfaces/storages/IStorage';
 
@@ -21,6 +23,7 @@ import { StringArrayRc4DecodeNodeTemplate } from '../../templates/custom-nodes/s
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { JavaScriptObfuscator } from '../../JavaScriptObfuscator';
+import { NodeUtils } from '../../node/NodeUtils';
 
 @injectable()
 export class StringArrayCallsWrapper extends AbstractCustomNode {
@@ -66,6 +69,32 @@ export class StringArrayCallsWrapper extends AbstractCustomNode {
         this.stringArrayCallsWrapperName = stringArrayCallsWrapperName;
     }
 
+    /**
+     * @returns {TStatement[]}
+     */
+    protected getNodeStructure (): TStatement[] {
+        return NodeUtils.convertCodeToStructure(this.getTemplate());
+    }
+
+    /**
+     * @returns {string}
+     */
+    protected getTemplate (): string {
+        const decodeNodeTemplate: string = this.getDecodeStringArrayTemplate();
+
+        return JavaScriptObfuscator.obfuscate(
+            format(StringArrayCallsWrapperTemplate(), {
+                decodeNodeTemplate,
+                stringArrayCallsWrapperName: this.stringArrayCallsWrapperName,
+                stringArrayName: this.stringArrayName
+            }),
+            {
+                ...NO_CUSTOM_NODES_PRESET,
+                seed: this.options.seed
+            }
+        ).getObfuscatedCode();
+    }
+
     /**
      * @returns {string}
      */
@@ -81,19 +110,19 @@ export class StringArrayCallsWrapper extends AbstractCustomNode {
         }
 
         switch (this.options.stringArrayEncoding) {
-            case StringArrayEncoding.base64:
-                decodeStringArrayTemplate = format(StringArrayBase64DecodeNodeTemplate(), {
+            case StringArrayEncoding.rc4:
+                decodeStringArrayTemplate = format(StringArrayRc4DecodeNodeTemplate(), {
                     atobPolyfill: AtobTemplate(),
+                    rc4Polyfill: Rc4Template(),
                     selfDefendingCode,
                     stringArrayCallsWrapperName: this.stringArrayCallsWrapperName
                 });
 
                 break;
 
-            case StringArrayEncoding.rc4:
-                decodeStringArrayTemplate = format(StringArrayRc4DecodeNodeTemplate(), {
+            case StringArrayEncoding.base64:
+                decodeStringArrayTemplate = format(StringArrayBase64DecodeNodeTemplate(), {
                     atobPolyfill: AtobTemplate(),
-                    rc4Polyfill: Rc4Template(),
                     selfDefendingCode,
                     stringArrayCallsWrapperName: this.stringArrayCallsWrapperName
                 });
@@ -103,23 +132,4 @@ export class StringArrayCallsWrapper extends AbstractCustomNode {
 
         return decodeStringArrayTemplate;
     }
-
-    /**
-     * @returns {string}
-     */
-    protected getTemplate (): string {
-        const decodeNodeTemplate: string = this.getDecodeStringArrayTemplate();
-
-        return JavaScriptObfuscator.obfuscate(
-            format(StringArrayCallsWrapperTemplate(), {
-                decodeNodeTemplate,
-                stringArrayCallsWrapperName: this.stringArrayCallsWrapperName,
-                stringArrayName: this.stringArrayName
-            }),
-            {
-                ...NO_CUSTOM_NODES_PRESET,
-                seed: this.options.seed
-            }
-        ).getObfuscatedCode();
-    }
 }

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

@@ -13,6 +13,7 @@ import { initializable } from '../../decorators/Initializable';
 import { StringArrayTemplate } from '../../templates/custom-nodes/string-array-nodes/string-array-node/StringArrayTemplate';
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
+import { NodeUtils } from '../../node/NodeUtils';
 import { StringArrayStorage } from '../../storages/string-array/StringArrayStorage';
 
 @injectable()
@@ -68,6 +69,13 @@ export class StringArrayNode extends AbstractCustomNode {
         return super.getNode();
     }
 
+    /**
+     * @returns {TStatement[]}
+     */
+    protected getNodeStructure (): TStatement[] {
+        return NodeUtils.convertCodeToStructure(this.getTemplate());
+    }
+
     /**
      * @returns {string}
      */

+ 14 - 3
src/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.ts

@@ -3,6 +3,8 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as format from 'string-template';
 
+import { TStatement } from '../../types/node/TStatement';
+
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IStorage } from '../../interfaces/storages/IStorage';
 
@@ -15,6 +17,7 @@ import { StringArrayRotateFunctionTemplate } from '../../templates/custom-nodes/
 
 import { AbstractCustomNode } from '../AbstractCustomNode';
 import { JavaScriptObfuscator } from '../../JavaScriptObfuscator';
+import { NodeUtils } from '../../node/NodeUtils';
 import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
 import { Utils } from '../../utils/Utils';
 
@@ -62,13 +65,21 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
         this.stringArrayRotateValue = stringArrayRotateValue;
     }
 
+    /**
+     * @returns {TStatement[]}
+     */
+    protected getNodeStructure (): TStatement[] {
+        return NodeUtils.convertCodeToStructure(this.getTemplate());
+    }
+
     /**
      * @returns {string}
      */
     protected getTemplate (): string {
-        let code: string = '',
-            timesName: string = RandomGeneratorUtils.getRandomVariableName(),
-            whileFunctionName: string = RandomGeneratorUtils.getRandomVariableName();
+        const timesName: string = RandomGeneratorUtils.getRandomVariableName();
+        const whileFunctionName: string = RandomGeneratorUtils.getRandomVariableName();
+
+        let code: string = '';
 
         if (this.options.selfDefending) {
             code = format(SelfDefendingTemplate(), {

+ 8 - 8
src/custom-nodes/string-array-nodes/group/StringArrayCustomNodeGroup.ts

@@ -28,17 +28,17 @@ export class StringArrayCustomNodeGroup extends AbstractCustomNodeGroup {
      */
     protected appendEvent: TObfuscationEvent = ObfuscationEvents.AfterObfuscation;
 
-    /**
-     * @type {TCustomNodeFactory}
-     */
-    private readonly customNodeFactory: TCustomNodeFactory;
-
     /**
      * @type {Map<CustomNodes, ICustomNode>}
      */
     @initializable()
     protected customNodes: Map <CustomNodes, ICustomNode>;
 
+    /**
+     * @type {TCustomNodeFactory}
+     */
+    private readonly customNodeFactory: TCustomNodeFactory;
+
     /**
      * @type {IObfuscationEventEmitter}
      */
@@ -57,9 +57,9 @@ export class StringArrayCustomNodeGroup extends AbstractCustomNodeGroup {
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IObfuscationEventEmitter) obfuscationEventEmitter: IObfuscationEventEmitter,
-        @inject(ServiceIdentifiers['IStorage<string>']) stringArrayStorage: IStorage<string>,
+        @inject(ServiceIdentifiers.TStringArrayStorage) stringArrayStorage: IStorage<string>,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
@@ -108,7 +108,7 @@ export class StringArrayCustomNodeGroup extends AbstractCustomNodeGroup {
         const stringArrayStorageId: string = this.stringArrayStorage.getStorageId();
 
         const stringArrayName: string = `_${Utils.hexadecimalPrefix}${stringArrayStorageId}`;
-        const stringArrayCallsWrapperName: string = `_${Utils.hexadecimalPrefix}${Utils.stringRotate(stringArrayStorageId, 2)}`;
+        const stringArrayCallsWrapperName: string = `_${Utils.hexadecimalPrefix}${Utils.stringRotate(stringArrayStorageId, 1)}`;
 
         let stringArrayRotateValue: number;
 

+ 17 - 40
src/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.ts

@@ -3,7 +3,6 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
-import * as _ from 'lodash';
 
 import { TControlFlowReplacerFactory } from '../../types/container/TControlFlowReplacerFactory';
 import { TControlFlowStorageFactory } from '../../types/container/TControlFlowStorageFactory';
@@ -50,9 +49,9 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
     private controlFlowData: Map <ESTree.Node, IStorage<ICustomNode>> = new Map();
 
     /**
-     * @type {TStatement[][]}
+     * @type {TNodeWithBlockStatement[]}
      */
-    private readonly controlFlowNodesList: TStatement[][] = [];
+    private readonly hostNodesWithControlFlowNode: TNodeWithBlockStatement[] = [];
 
     /**
      * @type {TControlFlowReplacerFactory}
@@ -76,9 +75,9 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['Factory<IStorage<ICustomNode>>']) controlFlowStorageFactory: TControlFlowStorageFactory,
-        @inject(ServiceIdentifiers['Factory<IControlFlowReplacer>']) controlFlowReplacerFactory: TControlFlowReplacerFactory,
-        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__TControlFlowStorage) controlFlowStorageFactory: TControlFlowStorageFactory,
+        @inject(ServiceIdentifiers.Factory__IControlFlowReplacer) controlFlowReplacerFactory: TControlFlowReplacerFactory,
+        @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
@@ -112,27 +111,6 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
         return RandomGeneratorUtils.getRandomGenerator().pickone(blockScopesOfNode);
     }
 
-    /**
-     * @param hostNodeBody
-     * @param controlFlowNodesList
-     */
-    private static removeOldControlFlowNodeFromHostNodeBody (
-        hostNodeBody: TStatement[],
-        controlFlowNodesList: TStatement[][]
-    ): TStatement[] {
-        for (let controlFlowNode of controlFlowNodesList) {
-            const firstIndexOfNode: number = hostNodeBody.indexOf(controlFlowNode[0]);
-
-            if (firstIndexOfNode === -1) {
-                continue;
-            }
-
-            return _.difference(hostNodeBody, controlFlowNode);
-        }
-
-        return hostNodeBody;
-    }
-
     /**
      * @param functionNode
      */
@@ -151,32 +129,31 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
         const controlFlowStorage: IStorage <ICustomNode> = this.controlFlowStorageFactory();
         const hostNode: TNodeWithBlockStatement = FunctionControlFlowTransformer.getHostNode(functionNode);
 
-        if (!this.controlFlowData.has(hostNode)) {
-            this.controlFlowData.set(hostNode, controlFlowStorage);
-        } else {
-            hostNode.body = <ESTree.Statement[]>FunctionControlFlowTransformer
-                .removeOldControlFlowNodeFromHostNodeBody(hostNode.body, this.controlFlowNodesList);
+        if (this.controlFlowData.has(hostNode)) {
+            if (this.hostNodesWithControlFlowNode.indexOf(hostNode) !== -1) {
+                hostNode.body.shift();
+            }
 
             const hostControlFlowStorage: IStorage<ICustomNode> = <IStorage<ICustomNode>>this.controlFlowData.get(hostNode);
 
             controlFlowStorage.mergeWith(hostControlFlowStorage, true);
-
-            this.controlFlowData.set(hostNode, controlFlowStorage);
         }
 
+        this.controlFlowData.set(hostNode, controlFlowStorage);
+
         estraverse.replace(functionNode.body, {
             enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
-                if (RandomGeneratorUtils.getRandomFloat(0, 1) > this.options.controlFlowFlatteningThreshold) {
+                if (!FunctionControlFlowTransformer.controlFlowReplacersMap.has(node.type)) {
                     return;
                 }
 
-                const controlFlowReplacerName: NodeControlFlowReplacers | undefined = FunctionControlFlowTransformer
-                    .controlFlowReplacersMap.get(node.type);
-
-                if (controlFlowReplacerName === undefined) {
+                if (RandomGeneratorUtils.getRandomFloat(0, 1) > this.options.controlFlowFlatteningThreshold) {
                     return;
                 }
 
+                const controlFlowReplacerName: NodeControlFlowReplacers = <NodeControlFlowReplacers>FunctionControlFlowTransformer
+                    .controlFlowReplacersMap.get(node.type);
+
                 return {
                     ...this.controlFlowReplacerFactory(controlFlowReplacerName)
                         .replace(node, parentNode, controlFlowStorage),
@@ -195,7 +172,7 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
 
         const controlFlowStorageNode: TStatement[] = controlFlowStorageCustomNode.getNode();
 
-        this.controlFlowNodesList.push(controlFlowStorageNode);
         NodeAppender.prependNode(hostNode, controlFlowStorageNode);
+        this.hostNodesWithControlFlowNode.push(hostNode);
     }
 }

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

@@ -13,7 +13,7 @@ export abstract class AbstractControlFlowReplacer implements IControlFlowReplace
     /**
      * @type {IOptions}
      */
-    protected readonly options : IOptions;
+    protected readonly options: IOptions;
 
     /**
      * @param options

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

@@ -14,7 +14,6 @@ import { CustomNodes } from '../../../enums/container/CustomNodes';
 
 import { AbstractControlFlowReplacer } from './AbstractControlFlowReplacer';
 import { Node } from '../../../node/Node';
-import { NodeUtils } from '../../../node/NodeUtils';
 import { RandomGeneratorUtils } from '../../../utils/RandomGeneratorUtils';
 
 @injectable()
@@ -39,7 +38,7 @@ export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowRepl
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
@@ -87,7 +86,8 @@ export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowRepl
                 controlFlowStorageId
             );
 
-        let storageKeysForCurrentOperator: string[] | undefined = storageKeysByBinaryOperator.get(binaryExpressionNode.operator);
+        const storageKeysForCurrentOperator: string[] | undefined = storageKeysByBinaryOperator.get(binaryExpressionNode.operator);
+
         let storageKey: string;
 
         if (
@@ -110,8 +110,8 @@ export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowRepl
         controlFlowStorageCallCustomNode.initialize(
             controlFlowStorageId,
             storageKey,
-            NodeUtils.convertStructureToCode([binaryExpressionNode.left]),
-            NodeUtils.convertStructureToCode([binaryExpressionNode.right])
+            binaryExpressionNode.left,
+            binaryExpressionNode.right
         );
 
         const statementNode: TStatement = controlFlowStorageCallCustomNode.getNode()[0];

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

@@ -36,7 +36,7 @@ export class CatchClauseObfuscator extends AbstractNodeTransformer {
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['Factory<IObfuscatorReplacer>']) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
+        @inject(ServiceIdentifiers.Factory__IObfuscatorReplacer) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);

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

@@ -39,7 +39,7 @@ export class FunctionDeclarationObfuscator extends AbstractNodeTransformer {
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['Factory<IObfuscatorReplacer>']) nodeObfuscatorsReplacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
+        @inject(ServiceIdentifiers.Factory__IObfuscatorReplacer) nodeObfuscatorsReplacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);

+ 2 - 2
src/node-transformers/node-obfuscators/FunctionObfuscator.ts

@@ -36,7 +36,7 @@ export class FunctionObfuscator extends AbstractNodeTransformer {
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['Factory<IObfuscatorReplacer>']) nodeObfuscatorsReplacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
+        @inject(ServiceIdentifiers.Factory__IObfuscatorReplacer) nodeObfuscatorsReplacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
@@ -72,7 +72,7 @@ export class FunctionObfuscator extends AbstractNodeTransformer {
      * @param nodeIdentifier
      */
     private replaceFunctionParams (functionNode: ESTree.Function, nodeIdentifier: string): void {
-        let traverseVisitor: estraverse.Visitor = {
+        const traverseVisitor: estraverse.Visitor = {
             enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
                 if (Node.isReplaceableIdentifierNode(node, parentNode)) {
                     const newNodeName: string = this.identifierReplacer.replace(node.name, nodeIdentifier);

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

@@ -44,7 +44,7 @@ export class LabeledStatementObfuscator extends AbstractNodeTransformer {
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['Factory<IObfuscatorReplacer>']) nodeObfuscatorsReplacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
+        @inject(ServiceIdentifiers.Factory__IObfuscatorReplacer) nodeObfuscatorsReplacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);

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

@@ -24,7 +24,7 @@ export class LiteralObfuscator extends AbstractNodeTransformer {
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['Factory<IObfuscatorReplacer>']) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
+        @inject(ServiceIdentifiers.Factory__IObfuscatorReplacer) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);

+ 24 - 32
src/node-transformers/node-obfuscators/MemberExpressionObfuscator.ts

@@ -2,7 +2,6 @@ import { injectable, inject } from 'inversify';
 import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as escodegen from 'escodegen';
-import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
 import { IOptions } from '../../interfaces/options/IOptions';
@@ -26,7 +25,7 @@ export class MemberExpressionObfuscator extends AbstractNodeTransformer {
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['Factory<IObfuscatorReplacer>']) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
+        @inject(ServiceIdentifiers.Factory__IObfuscatorReplacer) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
@@ -38,24 +37,18 @@ export class MemberExpressionObfuscator extends AbstractNodeTransformer {
      * @param memberExpressionNode
      */
     public transformNode (memberExpressionNode: ESTree.MemberExpression): void {
-        estraverse.traverse(memberExpressionNode.property, {
-            enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
-                if (Node.isLiteralNode(node)) {
-                    this.obfuscateLiteralProperty(node);
-
-                    return;
-                }
-
-                if (Node.isIdentifierNode(node)) {
-                    if (memberExpressionNode.computed) {
-                        return;
-                    }
+        if (Node.isLiteralNode(memberExpressionNode.property)) {
+            memberExpressionNode.property = this.obfuscateLiteralProperty(memberExpressionNode.property);
+        }
 
-                    memberExpressionNode.computed = true;
-                    this.obfuscateIdentifierProperty(node);
-                }
+        if (Node.isIdentifierNode(memberExpressionNode.property)) {
+            if (memberExpressionNode.computed) {
+                return;
             }
-        });
+
+            memberExpressionNode.computed = true;
+            memberExpressionNode.property = this.obfuscateIdentifierProperty(memberExpressionNode.property);
+        }
     }
 
     /**
@@ -69,22 +62,18 @@ export class MemberExpressionObfuscator extends AbstractNodeTransformer {
      *     object[identifier] = 1;
      *
      * @param node
+     * @returns {ESTree.Literal}
      */
-    private obfuscateIdentifierProperty (node: ESTree.Identifier): void {
-        const nodeValue: string = node.name;
-        const literalNode: ESTree.Literal = {
-            raw: `'${nodeValue}'`,
+    private obfuscateIdentifierProperty (node: ESTree.Identifier): ESTree.Literal {
+        return {
+            type: NodeType.Literal,
+            value: node.name,
+            raw: `'${node.name}'`,
             'x-verbatim-property': {
-                content: this.stringLiteralReplacer.replace(nodeValue),
+                content: this.stringLiteralReplacer.replace(node.name),
                 precedence: escodegen.Precedence.Primary
-            },
-            type: NodeType.Literal,
-            value: nodeValue
+            }
         };
-
-        delete node.name;
-
-        Object.assign(node, literalNode);
     }
 
     /**
@@ -95,13 +84,16 @@ export class MemberExpressionObfuscator extends AbstractNodeTransformer {
      *     object[_0x23d45[25]] = 1;
      *
      * @param node
+     * @returns {ESTree.Literal}
      */
-    private obfuscateLiteralProperty (node: ESTree.Literal): void {
+    private obfuscateLiteralProperty (node: ESTree.Literal): ESTree.Literal {
         if (typeof node.value === 'string' && !node['x-verbatim-property']) {
             node['x-verbatim-property'] = {
-                content : this.stringLiteralReplacer.replace(node.value),
+                content: this.stringLiteralReplacer.replace(node.value),
                 precedence: escodegen.Precedence.Primary
             };
         }
+
+        return node;
     }
 }

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

@@ -22,21 +22,21 @@ import { Node } from '../../node/Node';
 @injectable()
 export class MethodDefinitionObfuscator extends AbstractNodeTransformer {
     /**
-     * @type {IObfuscatorReplacer}
+     * @type {string[]}
      */
-    private readonly stringLiteralReplacer: IObfuscatorReplacer;
+    private static readonly ignoredNames: string[] = ['constructor'];
 
     /**
-     * @type {string[]}
+     * @type {IObfuscatorReplacer}
      */
-    private static readonly ignoredNames: string[] = ['constructor'];
+    private readonly stringLiteralReplacer: IObfuscatorReplacer;
 
     /**
      * @param replacersFactory
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['Factory<IObfuscatorReplacer>']) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
+        @inject(ServiceIdentifiers.Factory__IObfuscatorReplacer) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);

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

@@ -40,7 +40,7 @@ export class VariableDeclarationObfuscator extends AbstractNodeTransformer {
      * @param options
      */
     constructor(
-        @inject(ServiceIdentifiers['Factory<IObfuscatorReplacer>']) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
+        @inject(ServiceIdentifiers.Factory__IObfuscatorReplacer) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IObfuscatorReplacer,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);

+ 1 - 1
src/node-transformers/node-obfuscators/replacers/AbstractReplacer.ts

@@ -9,7 +9,7 @@ export abstract class AbstractReplacer implements IObfuscatorReplacer {
     /**
      * @type {IOptions}
      */
-    protected readonly options : IOptions;
+    protected readonly options: IOptions;
 
     /**
      * @param options

+ 10 - 12
src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts

@@ -41,8 +41,8 @@ export class StringLiteralReplacer extends AbstractReplacer {
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['IStorage<ICustomNodeGroup>']) customNodeGroupStorage: IStorage<ICustomNodeGroup>,
-        @inject(ServiceIdentifiers['IStorage<string>']) stringArrayStorage: IStorage<string>,
+        @inject(ServiceIdentifiers.TCustomNodeGroupStorage) customNodeGroupStorage: IStorage<ICustomNodeGroup>,
+        @inject(ServiceIdentifiers.TStringArrayStorage) stringArrayStorage: IStorage<string>,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super(options);
@@ -65,7 +65,7 @@ export class StringLiteralReplacer extends AbstractReplacer {
             return this.replaceStringLiteralWithStringArrayCall(nodeValue);
         }
 
-        return `'${Utils.stringToUnicodeEscapeSequence(nodeValue)}'`;
+        return `'${Utils.stringToUnicodeEscapeSequence(nodeValue, !this.options.unicodeEscapeSequence)}'`;
     }
 
     /**
@@ -76,22 +76,20 @@ export class StringLiteralReplacer extends AbstractReplacer {
         let rc4Key: string = '';
 
         switch (this.options.stringArrayEncoding) {
-            case StringArrayEncoding.base64:
-                value = CryptUtils.btoa(value);
-
-                break;
-
             case StringArrayEncoding.rc4:
                 rc4Key = RandomGeneratorUtils.getRandomGenerator().pickone(StringLiteralReplacer.rc4Keys);
                 value = CryptUtils.btoa(CryptUtils.rc4(value, rc4Key));
 
                 break;
-        }
 
-        if (this.options.unicodeEscapeSequence) {
-            value = Utils.stringToUnicodeEscapeSequence(value);
+            case StringArrayEncoding.base64:
+                value = CryptUtils.btoa(value);
+
+                break;
         }
 
+        value = Utils.stringToUnicodeEscapeSequence(value, !this.options.unicodeEscapeSequence);
+
         const indexOfExistingValue: number = <number>this.stringArrayStorage.getKeyOf(value);
 
         let indexOfValue: number;
@@ -103,7 +101,7 @@ export class StringLiteralReplacer extends AbstractReplacer {
             this.stringArrayStorage.set(null, value);
         }
 
-        const rotatedStringArrayStorageId: string = Utils.stringRotate(this.stringArrayStorage.getStorageId(), 2);
+        const rotatedStringArrayStorageId: string = Utils.stringRotate(this.stringArrayStorage.getStorageId(), 1);
         const stringArrayStorageCallsWrapperName: string = `_${Utils.hexadecimalPrefix}${rotatedStringArrayStorageId}`;
         const hexadecimalIndex: string = `${Utils.hexadecimalPrefix}${Utils.decToHex(indexOfValue)}`;
 

+ 272 - 0
src/node/Nodes.ts

@@ -0,0 +1,272 @@
+import * as escodegen from 'escodegen';
+import * as ESTree from 'estree';
+
+import { TStatement } from '../types/node/TStatement';
+
+import { NodeType } from '../enums/NodeType';
+
+export class Nodes {
+    /**
+     * @param body
+     * @returns {ESTree.Program}
+     */
+    public static getProgramNode (body: TStatement[] = []): ESTree.Program {
+        return {
+            type: NodeType.Program,
+            body,
+            sourceType: 'script',
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param operator
+     * @param left
+     * @param right
+     * @returns {ESTree.BinaryExpression}
+     */
+    public static getBinaryExpressionNode (
+        operator: ESTree.BinaryOperator,
+        left: ESTree.Expression,
+        right: ESTree.Expression,
+    ): ESTree.BinaryExpression {
+        return {
+            type: NodeType.BinaryExpression,
+            operator,
+            left,
+            right,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param body
+     * @returns {ESTree.BlockStatement}
+     */
+    public static getBlockStatementNode (body: ESTree.Statement[] = []): ESTree.BlockStatement {
+        return {
+            type: NodeType.BlockStatement,
+            body,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param body
+     * @returns {ESTree.CatchClause}
+     */
+    public static getCatchClauseNode (body: ESTree.Statement[] = []): ESTree.CatchClause {
+        return {
+            type: NodeType.CatchClause,
+            param: Nodes.getIdentifierNode('err'),
+            body: Nodes.getBlockStatementNode(body),
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param callee
+     * @param args
+     * @returns {ESTree.CallExpression}
+     */
+    public static getCallExpressionNode (
+        callee: ESTree.Expression,
+        args: ESTree.Expression[] | ESTree.SpreadElement[] = []
+    ): ESTree.CallExpression {
+        return {
+            type: NodeType.CallExpression,
+            callee,
+            arguments: args,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param expression
+     * @returns {ESTree.ExpressionStatement}
+     */
+    public static getExpressionStatementNode (expression: ESTree.Expression): ESTree.ExpressionStatement {
+        return {
+            type: NodeType.ExpressionStatement,
+            expression,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param functionName
+     * @param params
+     * @param body
+     * @returns {ESTree.FunctionDeclaration}
+     */
+    public static getFunctionDeclarationNode (
+        functionName: string,
+        params: ESTree.Identifier[],
+        body: ESTree.BlockStatement
+    ): ESTree.FunctionDeclaration {
+        return {
+            type: NodeType.FunctionDeclaration,
+            id: Nodes.getIdentifierNode(functionName),
+            params,
+            body,
+            generator: false,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param params
+     * @param body
+     * @returns {ESTree.FunctionExpression}
+     */
+    public static getFunctionExpressionNode (
+        params: ESTree.Identifier[],
+        body: ESTree.BlockStatement
+    ): ESTree.FunctionExpression {
+        return {
+            type: NodeType.FunctionExpression,
+            params,
+            body,
+            generator: false,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param test
+     * @param consequent
+     * @returns {ESTree.IfStatement}
+     */
+    public static getIfStatementNode (test: ESTree.Expression, consequent: ESTree.BlockStatement): ESTree.IfStatement {
+        return {
+            type: NodeType.IfStatement,
+            test,
+            consequent,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param name
+     * @returns {ESTree.Identifier}
+     */
+    public static getIdentifierNode (name: string): ESTree.Identifier {
+        return {
+            type: NodeType.Identifier,
+            name,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param value
+     * @returns {ESTree.Literal}
+     */
+    public static getLiteralNode (value: boolean|number|string): ESTree.Literal {
+        return {
+            type: NodeType.Literal,
+            value,
+            raw: `'${value}'`,
+            'x-verbatim-property': {
+                content: `'${value}'`,
+                precedence: escodegen.Precedence.Primary
+            },
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param object
+     * @param property
+     * @param computed
+     * @return {ESTree.MemberExpression}
+     */
+    public static getMemberExpressionNode (
+        object: ESTree.Identifier,
+        property: ESTree.Identifier|ESTree.Literal,
+        computed: boolean = false
+    ): ESTree.MemberExpression {
+        return {
+            type: NodeType.MemberExpression,
+            computed,
+            object,
+            property,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param properties
+     * @return {ESTree.ObjectExpression}
+     */
+    public static getObjectExpressionNode (properties: ESTree.Property[]): ESTree.ObjectExpression {
+        return {
+            type: NodeType.ObjectExpression,
+            properties,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @return {ESTree.Property}
+     */
+    public static getPropertyNode (
+        key: ESTree.Expression,
+        value: ESTree.Expression | ESTree.Pattern,
+        computed: boolean = false
+    ): ESTree.Property {
+        return {
+            type: NodeType.Property,
+            key,
+            value,
+            kind: 'init',
+            method: false,
+            shorthand: false,
+            computed,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param argument
+     * @return {ReturnStatement}
+     */
+    public static getReturnStatementNode (argument: ESTree.Expression): ESTree.ReturnStatement {
+        return {
+            type: NodeType.ReturnStatement,
+            argument,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param declarations
+     * @param kind
+     * @returns {ESTree.VariableDeclaration}
+     */
+    public static getVariableDeclarationNode (
+        declarations: ESTree.VariableDeclarator[] = [],
+        kind: 'var' | 'let' | 'const' = 'var'
+    ): ESTree.VariableDeclaration {
+        return {
+            type: NodeType.VariableDeclaration,
+            declarations,
+            kind,
+            obfuscated: false
+        };
+    }
+
+    /**
+     * @param id
+     * @param init
+     * @returns {ESTree.VariableDeclarator}
+     */
+    public static getVariableDeclaratorNode (id: ESTree.Identifier, init: any): ESTree.VariableDeclarator {
+        return {
+            type: NodeType.VariableDeclarator,
+            id,
+            init,
+            obfuscated: false
+        };
+    }
+}

+ 1 - 1
src/stack-trace-analyzer/StackTraceAnalyzer.ts

@@ -74,7 +74,7 @@ export class StackTraceAnalyzer implements IStackTraceAnalyzer {
     private calleeDataExtractorsFactory: (calleeDataExtractorName: CalleeDataExtractors) => ICalleeDataExtractor;
 
     constructor (
-        @inject(ServiceIdentifiers['Factory<ICalleeDataExtractor>']) calleeDataExtractorsFactory: TCalleeDataExtractorsFactory
+        @inject(ServiceIdentifiers.Factory__ICalleeDataExtractor) calleeDataExtractorsFactory: TCalleeDataExtractorsFactory
     ) {
         this.calleeDataExtractorsFactory = calleeDataExtractorsFactory;
     }

+ 1 - 1
src/storages/MapStorage.ts

@@ -47,7 +47,7 @@ export abstract class MapStorage <T> implements IStorage <T> {
      * @returns {number}
      */
     public getLength (): number {
-        return Array.from(this.storage).length;
+        return this.storage.size;
     }
 
     /**

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

@@ -8,18 +8,4 @@ export class ControlFlowStorage extends MapStorage <ICustomNode> {
 
         this.initialize();
     }
-
-    /**
-     * @returns {string}
-     */
-    public toString (): string {
-        return Array
-            .from(this.storage)
-            .reduce((controlFlowStorageItems: string[], [key, value]: [string, ICustomNode]) => {
-                controlFlowStorageItems.push(`${key}: ${value.getCode()}`);
-
-                return controlFlowStorageItems;
-            }, [])
-            .join(',');
-    }
 }

+ 2 - 2
src/storages/custom-node-group/CustomNodeGroupStorage.ts

@@ -39,7 +39,7 @@ export class CustomNodeGroupStorage extends MapStorage <ICustomNodeGroup> {
      * @param options
      */
     constructor (
-        @inject(ServiceIdentifiers['Factory<ICustomNodeGroup>']) customNodeGroupFactory: TCustomNodeGroupFactory,
+        @inject(ServiceIdentifiers.Factory__ICustomNodeGroup) customNodeGroupFactory: TCustomNodeGroupFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
         super();
@@ -66,4 +66,4 @@ export class CustomNodeGroupStorage extends MapStorage <ICustomNodeGroup> {
             this.storage.set(customNodeGroupName, customNodeGroup);
         });
     }
-}
+}

+ 1 - 1
src/storages/string-array/StringArrayStorage.ts

@@ -36,4 +36,4 @@ export class StringArrayStorage extends ArrayStorage <string> {
             return `'${value}'`;
         }).toString();
     }
-}
+}

+ 0 - 10
src/templates/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionTemplate.ts

@@ -1,10 +0,0 @@
-/**
- * @returns {string}
- */
-export function BinaryExpressionFunctionTemplate (): string {
-    return `
-        function {functionName} (x, y) {
-            return x {operator} y;
-        }
-    `;
-}

+ 0 - 6
src/templates/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallTemplate.ts

@@ -1,6 +0,0 @@
-/**
- * @returns {string}
- */
-export function ControlFlowStorageCallTemplate (): string {
-    return '{controlFlowStorageName}.{controlFlowStorageKey}({leftValue}, {rightValue})';
-}

+ 0 - 8
src/templates/custom-nodes/control-flow-storage-nodes/ControlFlowStorageTemplate.ts

@@ -1,8 +0,0 @@
-/**
- * @returns {string}
- */
-export function ControlFlowStorageTemplate (): string {
-    return `
-        var {controlFlowStorageName} = { {controlFlowStorage} };
-    `;
-}

+ 4 - 0
src/types/storages/TControlFlowStorage.d.ts

@@ -0,0 +1,4 @@
+import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
+import { IStorage } from '../../interfaces/storages/IStorage';
+
+export type TControlFlowStorage = IStorage<ICustomNode>;

+ 4 - 0
src/types/storages/TCustomNodeGroupStorage.d.ts

@@ -0,0 +1,4 @@
+import { ICustomNodeGroup } from '../../interfaces/custom-nodes/ICustomNodeGroup';
+import { IStorage } from '../../interfaces/storages/IStorage';
+
+export type TCustomNodeGroupStorage = IStorage<ICustomNodeGroup>;

+ 3 - 0
src/types/storages/TStringArrayStorage.d.ts

@@ -0,0 +1,3 @@
+import { IStorage } from '../../interfaces/storages/IStorage';
+
+export type TStringArrayStorage = IStorage<string>;

+ 17 - 3
src/utils/Utils.ts

@@ -98,7 +98,15 @@ export class Utils {
      * @returns {string}
      */
     public static stringRotate (string: string, times: number): string {
-        return Utils.arrayRotate(Array.from(string), times).join('');
+        if (!string) {
+            throw new ReferenceError(`Cannot rotate empty string.`);
+        }
+
+        for (let i: number = 0; i < times; i++) {
+            string = string[string.length - 1] + string.substring(0, string.length - 1);
+        }
+
+        return string;
     }
 
     /**
@@ -116,16 +124,22 @@ export class Utils {
 
     /**
      * @param string
+     * @param nonLatinAndNonDigitsOnly
      * @returns {string}
      */
-    public static stringToUnicodeEscapeSequence (string: string): string {
+    public static stringToUnicodeEscapeSequence (string: string, nonLatinAndNonDigitsOnly: boolean = false): string {
         const radix: number = 16;
         const regexp: RegExp = new RegExp('[\x00-\x7F]');
+        const escapeRegExp: RegExp = new RegExp('[^a-zA-Z0-9]');
 
         let prefix: string,
             template: string;
 
         return `${string.replace(/[\s\S]/g, (escape: string): string => {
+            if (nonLatinAndNonDigitsOnly && !escapeRegExp.test(escape)) {
+                return escape;
+            }
+            
             if (regexp.test(escape)) {
                 prefix = '\\x';
                 template = '0'.repeat(2);
@@ -133,7 +147,7 @@ export class Utils {
                 prefix = '\\u';
                 template = '0'.repeat(4);
             }
-
+            
             return `${prefix}${(template + escape.charCodeAt(0).toString(radix)).slice(-template.length)}`;
         })}`;
     }

+ 2 - 1
test/dev/dev.ts

@@ -84,7 +84,8 @@ if (!(<any>global)._babelPolyfill) {
         {
             compact: false,
             controlFlowFlattening: true,
-            disableConsoleOutput: false
+            disableConsoleOutput: false,
+            unicodeEscapeSequence: false
         }
     ).getObfuscatedCode();
 

+ 1 - 0
test/fixtures/node-transformers/node-obfuscators/literal-obfuscator/literal-obfuscator-unicode-sequence.js

@@ -0,0 +1 @@
+var test = '\nreturn \n//# sourceURL= there can only be \'^\' and \'!\' markers in a subscription marble diagram.';

+ 29 - 0
test/functional-tests/node-transformers/node-obfuscators/LiteralObfuscator.spec.ts

@@ -4,6 +4,8 @@ import { IObfuscationResult } from '../../../../src/interfaces/IObfuscationResul
 
 import { NO_CUSTOM_NODES_PRESET } from '../../../../src/options/presets/NoCustomNodes';
 
+import { readFileAsString } from '../../../helpers/readFileAsString';
+
 import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscator';
 
 describe('LiteralObfuscator', () => {
@@ -54,6 +56,33 @@ describe('LiteralObfuscator', () => {
             assert.match(obfuscationResult.getObfuscatedCode(),  /var *test *= *_0x([a-z0-9]){4}\('0x0'\);/);
         });
 
+        it('should replace literal node value with raw value from unicode array if `unicodeEscapeSequence` and `stringArray` are disabled', () => {
+            let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                `var test = 'test';`,
+                {
+                    ...NO_CUSTOM_NODES_PRESET,
+                    unicodeEscapeSequence: false
+                }
+            );
+
+            assert.match(
+                obfuscationResult.getObfuscatedCode(),
+                /^var *test *= *'test';/
+            );
+        });
+
+        it('should\'t throw an error when string contains non-latin and non-digit characters and `unicodeEscapeSequence` is disabled', () => {
+            assert.doesNotThrow(() => JavaScriptObfuscator.obfuscate(
+                readFileAsString('./test/fixtures/node-transformers/node-obfuscators/literal-obfuscator/literal-obfuscator-unicode-sequence.js'),
+                {
+                    ...NO_CUSTOM_NODES_PRESET,
+                    stringArray: true,
+                    stringArrayThreshold: 1,
+                    unicodeEscapeSequence: false
+                }
+            ));
+        });
+
         it('shouldn\'t replace short literal node value with unicode array value', () => {
             let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
                 `var test = 'te';`,

+ 11 - 11
test/functional-tests/stack-trace-analyzer/StackTraceAnalyzer.spec.ts

@@ -15,7 +15,7 @@ import { readFileAsString } from '../../helpers/readFileAsString';
 
 import { InversifyContainerFacade } from '../../../src/container/InversifyContainerFacade';
 import { Node } from '../../../src/node/Node';
-import { NodeMocks } from '../../mocks/NodeMocks';
+import { Nodes } from '../../../src/node/Nodes';
 import { NodeUtils } from '../../../src/node/NodeUtils';
 
 /**
@@ -157,7 +157,7 @@ describe('StackTraceAnalyzer', () => {
             expectedStackTraceData: IStackTraceData[];
 
         it('should returns correct IStackTraceData - variant #1: basic-1', () => {
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/basic-1.js')
                 )
@@ -204,7 +204,7 @@ describe('StackTraceAnalyzer', () => {
         });
 
         it('should returns correct IStackTraceData - variant #2: basic-2', () => {
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/basic-2.js')
                 )
@@ -240,7 +240,7 @@ describe('StackTraceAnalyzer', () => {
         });
 
         it('should returns correct IStackTraceData - variant #3: deep conditions nesting', () => {
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/deep-conditions-nesting.js')
                 )
@@ -276,7 +276,7 @@ describe('StackTraceAnalyzer', () => {
         });
 
         it('should returns correct IStackTraceData - variant #4: call before declaration', () => {
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/call-before-declaration.js')
                 )
@@ -296,7 +296,7 @@ describe('StackTraceAnalyzer', () => {
         });
 
         it('should returns correct IStackTraceData - variant #5: call expression of object member #1', () => {
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/call-expression-of-object-member-1.js')
                 )
@@ -352,7 +352,7 @@ describe('StackTraceAnalyzer', () => {
         });
 
         it('should returns correct IStackTraceData - variant #5: call expression of object member #2', () => {
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/call-expression-of-object-member-2.js')
                 )
@@ -377,7 +377,7 @@ describe('StackTraceAnalyzer', () => {
         });
 
         it('should returns correct IStackTraceData - variant #6: no call expressions', () => {
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/no-call-expressions.js')
                 )
@@ -391,7 +391,7 @@ describe('StackTraceAnalyzer', () => {
         });
 
         it('should returns correct IStackTraceData - variant #7: only call expression', () => {
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/only-call-expression.js')
                 )
@@ -405,7 +405,7 @@ describe('StackTraceAnalyzer', () => {
         });
 
         it('should returns correct IStackTraceData - variant #8: self-invoking functions', () => {
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/self-invoking-functions.js')
                 )
@@ -437,7 +437,7 @@ describe('StackTraceAnalyzer', () => {
         });
 
         it('should returns correct IStackTraceData - variant #9: no recursion', () => {
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/no-recursion.js')
                 )

+ 0 - 1
test/index.spec.ts

@@ -15,7 +15,6 @@ import './unit-tests/decorators/Initializable.spec';
 import './unit-tests/node/NodeAppender.spec';
 import './unit-tests/node/NodeUtils.spec';
 import './unit-tests/stack-trace-analyzer/StackTraceAnalyzer.spec';
-import './unit-tests/storages/ControlFlowStorage.spec';
 import './unit-tests/utils/CryptUtils.spec';
 import './unit-tests/utils/RandomGeneratorUtils.spec';
 import './unit-tests/utils/Utils.spec';

+ 0 - 194
test/mocks/NodeMocks.ts

@@ -1,194 +0,0 @@
-import * as escodegen from 'escodegen';
-import * as ESTree from 'estree';
-
-import { TStatement } from '../../src/types/node/TStatement';
-
-import { NodeType } from '../../src/enums/NodeType';
-
-export class NodeMocks {
-    /**
-     * @param bodyNodes
-     * @returns {ESTree.Program}
-     */
-    public static getProgramNode (bodyNodes: TStatement[] = []): ESTree.Program {
-        return {
-            type: NodeType.Program,
-            body: bodyNodes,
-            sourceType: 'script',
-            obfuscated: false
-        };
-    }
-
-    /**
-     * @param bodyNodes
-     * @returns {ESTree.BlockStatement}
-     */
-    public static getBlockStatementNode (bodyNodes: ESTree.Statement[] = []): ESTree.BlockStatement {
-        return {
-            type: NodeType.BlockStatement,
-            body: bodyNodes,
-            obfuscated: false
-        };
-    }
-
-    /**
-     * @param bodyNodes
-     * @returns {ESTree.CatchClause}
-     */
-    public static getCatchClauseNode (bodyNodes: ESTree.Statement[] = []): ESTree.CatchClause {
-        return {
-            type: NodeType.CatchClause,
-            param: NodeMocks.getIdentifierNode('err'),
-            body: NodeMocks.getBlockStatementNode(bodyNodes),
-            obfuscated: false
-        };
-    }
-
-    /**
-     * @param callee
-     * @param args
-     * @returns {ESTree.CallExpression}
-     */
-    public static getCallExpressionNode (
-        callee: ESTree.Expression,
-        args: ESTree.Expression[] | ESTree.SpreadElement[] = []
-    ): ESTree.CallExpression {
-        return {
-            type: NodeType.CallExpression,
-            callee: callee,
-            arguments: args,
-            obfuscated: false
-        };
-    }
-
-    /**
-     * @param expression
-     * @returns {ESTree.ExpressionStatement}
-     */
-    public static getExpressionStatementNode (
-        expression: ESTree.Expression = NodeMocks.getIdentifierNode()
-    ): ESTree.ExpressionStatement {
-        return {
-            type: NodeType.ExpressionStatement,
-            expression: expression,
-            obfuscated: false
-        };
-    }
-
-    /**
-     * @param functionName
-     * @param blockStatementNode
-     * @param params
-     * @returns {ESTree.FunctionDeclaration}
-     */
-    public static getFunctionDeclarationNode (
-        functionName: string,
-        blockStatementNode: ESTree.BlockStatement,
-        params: ESTree.Identifier[] = []
-    ): ESTree.FunctionDeclaration {
-        return {
-            type: NodeType.FunctionDeclaration,
-            id: NodeMocks.getIdentifierNode(functionName),
-            params: params,
-            body: blockStatementNode,
-            generator: false,
-            obfuscated: false
-        };
-    }
-
-    /**
-     * @param blockStatementNode
-     * @returns {ESTree.IfStatement}
-     */
-    public static getIfStatementNode (blockStatementNode: ESTree.BlockStatement): ESTree.IfStatement {
-        return {
-            type: 'IfStatement',
-            test: {
-                type: 'Literal',
-                value: true,
-                raw: 'true',
-                obfuscated: false
-            },
-            consequent: blockStatementNode,
-            obfuscated: false
-        };
-    }
-
-    /**
-     * @param identifierName
-     * @returns {ESTree.Identifier}
-     */
-    public static getIdentifierNode (identifierName: string = 'identifier'): ESTree.Identifier {
-        return {
-            type: NodeType.Identifier,
-            name: identifierName,
-            obfuscated: false
-        };
-    }
-
-    /**
-     * @param value
-     * @returns {ESTree.Literal}
-     */
-    public static getLiteralNode (value: boolean|number|string = 'value'): ESTree.Literal {
-        return {
-            type: NodeType.Literal,
-            value: value,
-            raw: `'${value}'`,
-            'x-verbatim-property': {
-                content: `'${value}'`,
-                precedence: escodegen.Precedence.Primary
-            },
-            obfuscated: false
-        };
-    }
-
-    /**
-     * @param object
-     * @param property
-     * @return {ESTree.MemberExpression}
-     */
-    public static getMemberExpressionNode (
-        object: ESTree.Identifier,
-        property: ESTree.Identifier|ESTree.Literal
-    ): ESTree.MemberExpression {
-        return {
-            type: NodeType.MemberExpression,
-            computed: false,
-            object: object,
-            property: property,
-            obfuscated: false
-        };
-    }
-
-    /**
-     * @param declarations
-     * @param kind
-     * @returns {ESTree.VariableDeclaration}
-     */
-    public static getVariableDeclarationNode (
-        declarations: ESTree.VariableDeclarator[] = [],
-        kind: 'var' | 'let' | 'const' = 'var'
-    ): ESTree.VariableDeclaration {
-        return {
-            type: NodeType.VariableDeclaration,
-            declarations: declarations,
-            kind: kind,
-            obfuscated: false
-        };
-    }
-
-    /**
-     * @param id
-     * @param init
-     * @returns {ESTree.VariableDeclarator}
-     */
-    public static getVariableDeclaratorNode (id: ESTree.Identifier, init: any): ESTree.VariableDeclarator {
-        return {
-            type: NodeType.VariableDeclarator,
-            id: id,
-            init: init,
-            obfuscated: false
-        };
-    }
-}

+ 16 - 16
test/unit-tests/node/NodeAppender.spec.ts

@@ -14,7 +14,7 @@ import { readFileAsString } from '../../helpers/readFileAsString';
 
 import { InversifyContainerFacade } from '../../../src/container/InversifyContainerFacade';
 import { NodeAppender } from '../../../src/node/NodeAppender';
-import { NodeMocks } from '../../mocks/NodeMocks';
+import { Nodes } from '../../../src/node/Nodes';
 import { NodeUtils } from '../../../src/node/NodeUtils';
 
 describe('NodeAppender', () => {
@@ -28,13 +28,13 @@ describe('NodeAppender', () => {
                 var test = 1;
             `);
 
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/node-appender/append-node.js')
                 )
             );
 
-            expectedAstTree = NodeMocks.getProgramNode(
+            expectedAstTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/node-appender/append-node-expected.js')
                 )
@@ -68,13 +68,13 @@ describe('NodeAppender', () => {
         });
 
         it('should append node into first and deepest function call in calls trace - variant #1', () => {
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/node-appender/append-node-to-optimal-block-scope/variant-1.js')
                 )
             );
 
-            expectedAstTree = NodeMocks.getProgramNode(
+            expectedAstTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/node-appender/append-node-to-optimal-block-scope/variant-1-expected.js')
                 )
@@ -87,13 +87,13 @@ describe('NodeAppender', () => {
         });
 
         it('should append node into first and deepest function call in calls trace - variant #2', () => {
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/node-appender/append-node-to-optimal-block-scope/variant-2.js')
                 )
             );
 
-            expectedAstTree = NodeMocks.getProgramNode(
+            expectedAstTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/node-appender/append-node-to-optimal-block-scope/variant-2-expected.js')
                 )
@@ -109,7 +109,7 @@ describe('NodeAppender', () => {
             let astTree: ESTree.Program;
 
             beforeEach(() => {
-                astTree = NodeMocks.getProgramNode(
+                astTree = Nodes.getProgramNode(
                     NodeUtils.convertCodeToStructure(
                         readFileAsString('./test/fixtures/node-appender/append-node-to-optimal-block-scope/by-index.js')
 
@@ -118,7 +118,7 @@ describe('NodeAppender', () => {
             });
 
             it('should append node into deepest function call by specified index in calls trace - variant #1', () => {
-                expectedAstTree = NodeMocks.getProgramNode(
+                expectedAstTree = Nodes.getProgramNode(
                     NodeUtils.convertCodeToStructure(
                         readFileAsString('./test/fixtures/node-appender/append-node-to-optimal-block-scope/by-index-variant-1-expected.js')
 
@@ -132,7 +132,7 @@ describe('NodeAppender', () => {
             });
 
             it('should append node into deepest function call by specified index in calls trace - variant #2', () => {
-                expectedAstTree = NodeMocks.getProgramNode(
+                expectedAstTree = Nodes.getProgramNode(
                     NodeUtils.convertCodeToStructure(
                         readFileAsString('./test/fixtures/node-appender/append-node-to-optimal-block-scope/by-index-variant-2-expected.js')
 
@@ -146,12 +146,12 @@ describe('NodeAppender', () => {
             });
 
             it('should append node into deepest function call by specified index in calls trace - variant #3', () => {
-                astTree = NodeMocks.getProgramNode(
+                astTree = Nodes.getProgramNode(
                     NodeUtils.convertCodeToStructure(
                         readFileAsString('./test/fixtures/node-appender/append-node-to-optimal-block-scope/by-index-variant-3.js')
                     )
                 );
-                expectedAstTree = NodeMocks.getProgramNode(
+                expectedAstTree = Nodes.getProgramNode(
                     NodeUtils.convertCodeToStructure(
                         readFileAsString('./test/fixtures/node-appender/append-node-to-optimal-block-scope/by-index-variant-3-expected.js')
                     )
@@ -193,13 +193,13 @@ describe('NodeAppender', () => {
                 var test = 1;
             `);
 
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/node-appender/insert-node-at-index.js')
                 )
             );
 
-            expectedAstTree = NodeMocks.getProgramNode(
+            expectedAstTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/node-appender/insert-node-at-index-expected.js')
                 )
@@ -226,13 +226,13 @@ describe('NodeAppender', () => {
                 var test = 1;
             `);
 
-            astTree = NodeMocks.getProgramNode(
+            astTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/node-appender/prepend-node.js')
                 )
             );
 
-            expectedAstTree = NodeMocks.getProgramNode(
+            expectedAstTree = Nodes.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/node-appender/prepend-node-expected.js')
                 )

+ 59 - 44
test/unit-tests/node/NodeUtils.spec.ts

@@ -2,7 +2,7 @@ import * as ESTree from 'estree';
 
 import { assert } from 'chai';
 
-import { NodeMocks } from '../../mocks/NodeMocks';
+import { Nodes } from '../../../src/node/Nodes';
 import { NodeUtils } from '../../../src/node/NodeUtils';
 
 describe('NodeUtils', () => {
@@ -11,10 +11,10 @@ describe('NodeUtils', () => {
             expectedLiteralNode: any;
 
         beforeEach(() => {
-            literalNode = NodeMocks.getLiteralNode();
+            literalNode = Nodes.getLiteralNode('value');
             delete literalNode['x-verbatim-property'];
 
-            expectedLiteralNode = NodeMocks.getLiteralNode();
+            expectedLiteralNode = Nodes.getLiteralNode('value');
 
             NodeUtils.addXVerbatimPropertyToLiterals(literalNode);
         });
@@ -37,17 +37,17 @@ describe('NodeUtils', () => {
                 var abc = 'cde';
             `;
 
-            identifierNode = NodeMocks.getIdentifierNode('abc');
+            identifierNode = Nodes.getIdentifierNode('abc');
 
-            literalNode = NodeMocks.getLiteralNode('cde');
+            literalNode = Nodes.getLiteralNode('cde');
 
-            variableDeclaratorNode = NodeMocks.getVariableDeclaratorNode(identifierNode, literalNode);
+            variableDeclaratorNode = Nodes.getVariableDeclaratorNode(identifierNode, literalNode);
 
-            variableDeclarationNode = NodeMocks.getVariableDeclarationNode([
+            variableDeclarationNode = Nodes.getVariableDeclarationNode([
                 variableDeclaratorNode
             ]);
 
-            programNode = NodeMocks.getProgramNode([
+            programNode = Nodes.getProgramNode([
                 variableDeclarationNode
             ]);
 
@@ -69,11 +69,11 @@ describe('NodeUtils', () => {
 
         beforeEach(() => {
             structure = [
-                NodeMocks.getProgramNode([
-                    NodeMocks.getVariableDeclarationNode([
-                        NodeMocks.getVariableDeclaratorNode(
-                            NodeMocks.getIdentifierNode('abc'),
-                            NodeMocks.getLiteralNode('cde')
+                Nodes.getProgramNode([
+                    Nodes.getVariableDeclarationNode([
+                        Nodes.getVariableDeclaratorNode(
+                            Nodes.getIdentifierNode('abc'),
+                            Nodes.getLiteralNode('cde')
                         )
                     ])
                 ])
@@ -92,10 +92,10 @@ describe('NodeUtils', () => {
             expressionStatementNode2: ESTree.ExpressionStatement;
 
         beforeEach(() => {
-            expressionStatementNode1 = NodeMocks.getExpressionStatementNode();
-            expressionStatementNode2 = NodeMocks.getExpressionStatementNode();
+            expressionStatementNode1 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier'));
+            expressionStatementNode2 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier'));
 
-            blockStatementNode = NodeMocks.getBlockStatementNode([
+            blockStatementNode = Nodes.getBlockStatementNode([
                 expressionStatementNode1,
                 expressionStatementNode2
             ]);
@@ -128,31 +128,37 @@ describe('NodeUtils', () => {
             programNode: ESTree.Program;
 
         beforeEach(() => {
-            expressionStatementNode1 = NodeMocks.getExpressionStatementNode();
-            expressionStatementNode2 = NodeMocks.getExpressionStatementNode();
-            expressionStatementNode3 = NodeMocks.getExpressionStatementNode();
+            expressionStatementNode1 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier'));
+            expressionStatementNode2 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier'));
+            expressionStatementNode3 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier'));
 
-            ifStatementBlockStatementNode2 = NodeMocks.getBlockStatementNode([
+            ifStatementBlockStatementNode2 = Nodes.getBlockStatementNode([
                 expressionStatementNode2,
                 expressionStatementNode3
             ]);
 
-            ifStatementNode2 = NodeMocks.getIfStatementNode(ifStatementBlockStatementNode2);
+            ifStatementNode2 = Nodes.getIfStatementNode(
+                Nodes.getLiteralNode(true),
+                ifStatementBlockStatementNode2
+            );
 
-            ifStatementBlockStatementNode1 = NodeMocks.getBlockStatementNode([
+            ifStatementBlockStatementNode1 = Nodes.getBlockStatementNode([
                 ifStatementNode2
             ]);
 
-            ifStatementNode1 = NodeMocks.getIfStatementNode(ifStatementBlockStatementNode1);
+            ifStatementNode1 = Nodes.getIfStatementNode(
+                Nodes.getLiteralNode(true),
+                ifStatementBlockStatementNode1
+            );
 
-            functionDeclarationBlockStatementNode = NodeMocks.getBlockStatementNode([
+            functionDeclarationBlockStatementNode = Nodes.getBlockStatementNode([
                 expressionStatementNode1,
                 ifStatementNode1
             ]);
 
-            functionDeclarationNode = NodeMocks.getFunctionDeclarationNode('test', functionDeclarationBlockStatementNode);
+            functionDeclarationNode = Nodes.getFunctionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
 
-            programNode = NodeMocks.getProgramNode([
+            programNode = Nodes.getProgramNode([
                 functionDeclarationNode
             ]);
 
@@ -203,37 +209,43 @@ describe('NodeUtils', () => {
             programNode: ESTree.Program;
 
         beforeEach(() => {
-            expressionStatementNode1 = NodeMocks.getExpressionStatementNode();
-            expressionStatementNode2 = NodeMocks.getExpressionStatementNode();
-            expressionStatementNode3 = NodeMocks.getExpressionStatementNode();
+            expressionStatementNode1 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier'));
+            expressionStatementNode2 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier'));
+            expressionStatementNode3 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier'));
 
-            ifStatementBlockStatementNode2 = NodeMocks.getBlockStatementNode([
+            ifStatementBlockStatementNode2 = Nodes.getBlockStatementNode([
                 expressionStatementNode3
             ]);
 
-            ifStatementNode2 = NodeMocks.getIfStatementNode(ifStatementBlockStatementNode2);
+            ifStatementNode2 = Nodes.getIfStatementNode(
+                Nodes.getLiteralNode(true),
+                ifStatementBlockStatementNode2
+            );
 
-            functionDeclarationBlockStatementNode2 = NodeMocks.getBlockStatementNode([
+            functionDeclarationBlockStatementNode2 = Nodes.getBlockStatementNode([
                 ifStatementNode2,
                 expressionStatementNode2
             ]);
 
-            functionDeclarationNode2 = NodeMocks.getFunctionDeclarationNode('test', functionDeclarationBlockStatementNode2);
+            functionDeclarationNode2 = Nodes.getFunctionDeclarationNode('test', [], functionDeclarationBlockStatementNode2);
 
-            ifStatementBlockStatementNode1 = NodeMocks.getBlockStatementNode([
+            ifStatementBlockStatementNode1 = Nodes.getBlockStatementNode([
                 functionDeclarationNode2
             ]);
 
-            ifStatementNode1 = NodeMocks.getIfStatementNode(ifStatementBlockStatementNode1);
+            ifStatementNode1 = Nodes.getIfStatementNode(
+                Nodes.getLiteralNode(true),
+                ifStatementBlockStatementNode1
+            );
 
-            functionDeclarationBlockStatementNode1 = NodeMocks.getBlockStatementNode([
+            functionDeclarationBlockStatementNode1 = Nodes.getBlockStatementNode([
                 expressionStatementNode1,
                 ifStatementNode1
             ]);
 
-            functionDeclarationNode1 = NodeMocks.getFunctionDeclarationNode('test', functionDeclarationBlockStatementNode1);
+            functionDeclarationNode1 = Nodes.getFunctionDeclarationNode('test', [], functionDeclarationBlockStatementNode1);
 
-            programNode = NodeMocks.getProgramNode([
+            programNode = Nodes.getProgramNode([
                 functionDeclarationNode1
             ]);
 
@@ -277,19 +289,22 @@ describe('NodeUtils', () => {
             programNode: ESTree.Program;
 
         beforeEach(() => {
-            expressionStatementNode1 = NodeMocks.getExpressionStatementNode();
-            expressionStatementNode2 = NodeMocks.getExpressionStatementNode();
+            expressionStatementNode1 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier'));
+            expressionStatementNode2 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier'));
 
-            ifStatementBlockStatementNode = NodeMocks.getBlockStatementNode([
+            ifStatementBlockStatementNode = Nodes.getBlockStatementNode([
                 expressionStatementNode1,
                 expressionStatementNode2
             ]);
 
-            ifStatementNode = NodeMocks.getIfStatementNode(ifStatementBlockStatementNode);
+            ifStatementNode = Nodes.getIfStatementNode(
+                Nodes.getLiteralNode(true),
+                ifStatementBlockStatementNode
+            );
         });
 
         it('should parentize given AST-tree with `ProgramNode` as root node', () => {
-            programNode = NodeMocks.getProgramNode([
+            programNode = Nodes.getProgramNode([
                 ifStatementNode
             ]);
 
@@ -303,7 +318,7 @@ describe('NodeUtils', () => {
         });
 
         it('should parentize given AST-tree', () => {
-            programNode = NodeMocks.getProgramNode([
+            programNode = Nodes.getProgramNode([
                 ifStatementNode
             ]);
             programNode['parentNode'] = programNode;

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

@@ -1,42 +0,0 @@
-import { ServiceIdentifiers } from '../../../src/container/ServiceIdentifiers';
-
-import { assert } from 'chai';
-
-import { TCustomNodeFactory } from '../../../src/types/container/TCustomNodeFactory';
-
-import { ICustomNode } from '../../../src/interfaces/custom-nodes/ICustomNode';
-import { IInversifyContainerFacade } from '../../../src/interfaces/container/IInversifyContainerFacade';
-import { IStorage } from '../../../src/interfaces/storages/IStorage';
-
-import { CustomNodes } from '../../../src/enums/container/CustomNodes';
-
-import { InversifyContainerFacade } from '../../../src/container/InversifyContainerFacade';
-
-describe('ControlFlowStorage', () => {
-    describe('toString (): string', () => {
-        it('should return correct ControlFlowStorage data after `.toString()` call', () => {
-            const key1: string = 'key1';
-            const key2: string = 'key2';
-            const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade({
-                controlFlowFlattening: true
-            });
-            const customNodeFactory: TCustomNodeFactory = inversifyContainerFacade
-                .get<TCustomNodeFactory>(ServiceIdentifiers['Factory<ICustomNode>']);
-            const controlFlowStorage: IStorage <ICustomNode> = inversifyContainerFacade
-                .get<IStorage<ICustomNode>>(ServiceIdentifiers['IStorage<ICustomNode>']);
-            const controlFlowStorageCallNode1: ICustomNode = customNodeFactory(CustomNodes.ControlFlowStorageCallNode);
-            const controlFlowStorageCallNode2: ICustomNode = customNodeFactory(CustomNodes.ControlFlowStorageCallNode);
-
-            controlFlowStorageCallNode1.initialize('controlFlowStorageName', key1, 1, 2);
-            controlFlowStorageCallNode2.initialize('controlFlowStorageName', key2, 3, 4);
-
-            controlFlowStorage.set(key1, controlFlowStorageCallNode1);
-            controlFlowStorage.set(key2, controlFlowStorageCallNode2);
-
-            assert.equal(
-                controlFlowStorage.toString(),
-                `${key1}: ${controlFlowStorageCallNode1.getCode()},${key2}: ${controlFlowStorageCallNode2.getCode()}`
-            );
-        });
-    });
-});

+ 8 - 3
test/unit-tests/utils/Utils.spec.ts

@@ -111,11 +111,16 @@ describe('Utils', () => {
         });
     });
 
-    describe('stringToUnicodeEscapeSequence (string: string): string', () => {
-        let expected: string = '\\x73\\x74\\x72\\x69\\x6e\\x67';
+    describe('stringToUnicodeEscapeSequence (string: string, nonLatinAndNonDigitsOnly: boolean = false): string', () => {
+        const expected1: string = '\\x73\\x74\\x72\\x69\\x6e\\x67';
+        const expected2: string = 'abc\\x21\\u0434\\u0435';
 
         it('should return a unicode escape sequence based on a given string', () => {
-            assert.equal(Utils.stringToUnicodeEscapeSequence('string'), expected);
+            assert.equal(Utils.stringToUnicodeEscapeSequence('string'), expected1);
+        });
+
+        it('should return a string where only non-digits and non-latin letters are escaped', () => {
+            assert.equal(Utils.stringToUnicodeEscapeSequence('abc!де', true), expected2);
         });
     });
 });

+ 2 - 2
tslint.json

@@ -37,7 +37,7 @@
       true,
       { "order": "fields-first" }
     ],
-    "new-parens": true,
+    "new-parens": false,
     "no-angle-bracket-type-assertion": false,
     "no-any": false,
     "no-arg": true,
@@ -87,7 +87,7 @@
     "quotemark": false,
     "radix": true,
     "semicolon": [true, "always"],
-    "switch-default": true,
+    "switch-default": false,
     "trailing-comma": false,
     "triple-equals": [
       true,

+ 7 - 1
webpack.config.js

@@ -18,7 +18,13 @@ module.exports = {
     target: 'node',
     externals: [nodeExternals()],
     module: {
-        loaders: [
+        rules: [
+            {
+                enforce: 'pre',
+                test: /\.ts$/,
+                loader: 'tslint-loader',
+                exclude: /(node_modules)/,
+            },
             {
                 test: /\.ts(x?)$/,
                 loader: 'awesome-typescript-loader',

Некоторые файлы не были показаны из-за большого количества измененных файлов