Browse Source

Refactoring related on splitting between nodes with statements and nodes with lexical scopes

sanex3339 6 năm trước cách đây
mục cha
commit
66640b4152
46 tập tin đã thay đổi với 1814 bổ sung15728 xóa
  1. 0 0
      dist/index.browser.js
  2. 0 1201
      dist/index.cli.js
  3. 0 13030
      dist/index.js
  4. 7 7
      package.json
  5. 2 2
      src/analyzers/stack-trace-analyzer/StackTraceAnalyzer.ts
  6. 2 2
      src/analyzers/stack-trace-analyzer/callee-data-extractors/FunctionDeclarationCalleeDataExtractor.ts
  7. 2 2
      src/analyzers/stack-trace-analyzer/callee-data-extractors/FunctionExpressionCalleeDataExtractor.ts
  8. 2 2
      src/analyzers/stack-trace-analyzer/callee-data-extractors/ObjectExpressionCalleeDataExtractor.ts
  9. 3 3
      src/custom-nodes/AbstractCustomNodeGroup.ts
  10. 8 12
      src/custom-nodes/console-output-nodes/group/ConsoleOutputCustomNodeGroup.ts
  11. 14 15
      src/custom-nodes/debug-protection-nodes/group/DebugProtectionCustomNodeGroup.ts
  12. 8 12
      src/custom-nodes/domain-lock-nodes/group/DomainLockCustomNodeGroup.ts
  13. 8 12
      src/custom-nodes/self-defending-nodes/group/SelfDefendingCustomNodeGroup.ts
  14. 6 6
      src/custom-nodes/string-array-nodes/group/StringArrayCustomNodeGroup.ts
  15. 3 3
      src/interfaces/custom-nodes/ICustomNodeGroup.d.ts
  16. 5 5
      src/interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer.d.ts
  17. 3 3
      src/interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IObfuscatingReplacer.d.ts
  18. 15 11
      src/node-transformers/control-flow-transformers/FunctionControlFlowTransformer.ts
  19. 18 15
      src/node-transformers/converting-transformers/properties-extractors/AbstractPropertiesExtractor.ts
  20. 19 12
      src/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.ts
  21. 15 11
      src/node-transformers/obfuscating-transformers/CatchClauseTransformer.ts
  22. 26 21
      src/node-transformers/obfuscating-transformers/ClassDeclarationTransformer.ts
  23. 26 21
      src/node-transformers/obfuscating-transformers/FunctionDeclarationTransformer.ts
  24. 17 15
      src/node-transformers/obfuscating-transformers/FunctionTransformer.ts
  25. 23 19
      src/node-transformers/obfuscating-transformers/ImportDeclarationTransformer.ts
  26. 15 11
      src/node-transformers/obfuscating-transformers/LabeledStatementTransformer.ts
  27. 23 18
      src/node-transformers/obfuscating-transformers/VariableDeclarationTransformer.ts
  28. 3 3
      src/node-transformers/obfuscating-transformers/obfuscating-replacers/AbstractObfuscatingReplacer.ts
  29. 17 17
      src/node-transformers/obfuscating-transformers/obfuscating-replacers/identifier-obfuscating-replacers/BaseIdentifierObfuscatingReplacer.ts
  30. 42 39
      src/node/NodeAppender.ts
  31. 17 14
      src/node/NodeGuards.ts
  32. 57 0
      src/node/NodeLexicalScopeUtils.ts
  33. 135 0
      src/node/NodeStatementUtils.ts
  34. 0 144
      src/node/NodeUtils.ts
  35. 0 3
      src/types/node/TNodeWithBlockScope.d.ts
  36. 3 0
      src/types/node/TNodeWithLexicalScope.d.ts
  37. 0 3
      src/types/node/TNodeWithScope.d.ts
  38. 3 0
      src/types/node/TNodeWithStatements.d.ts
  39. 11 11
      test/functional-tests/analyzers/stack-trace-analyzer/StackTraceAnalyzer.spec.ts
  40. 1 1
      test/functional-tests/node-transformers/obfuscating-transformers/function-transformer/FunctionTransformer.spec.ts
  41. 2 0
      test/index.spec.ts
  42. 26 26
      test/unit-tests/node/node-guards/NodeGuards.spec.ts
  43. 222 0
      test/unit-tests/node/node-lexical-scope-utils/NodeLexicalScopeUtils.spec.ts
  44. 625 0
      test/unit-tests/node/node-statement-utils/NodeStatementUtils.spec.ts
  45. 0 616
      test/unit-tests/node/node-utils/NodeUtils.spec.ts
  46. 380 380
      yarn.lock

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/index.browser.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 1201
dist/index.cli.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 13030
dist/index.js


+ 7 - 7
package.json

@@ -21,7 +21,7 @@
   },
   "types": "index.d.ts",
   "dependencies": {
-    "@babel/runtime": "7.0.0-beta.54",
+    "@babel/runtime": "7.0.0-beta.55",
     "chalk": "2.4.1",
     "chance": "1.0.16",
     "class-validator": "0.9.1",
@@ -41,10 +41,10 @@
     "tslib": "1.9.3"
   },
   "devDependencies": {
-    "@babel/cli": "7.0.0-beta.54",
-    "@babel/core": "7.0.0-beta.54",
-    "@babel/plugin-transform-runtime": "7.0.0-beta.54",
-    "@babel/preset-env": "7.0.0-beta.54",
+    "@babel/cli": "7.0.0-beta.55",
+    "@babel/core": "7.0.0-beta.55",
+    "@babel/plugin-transform-runtime": "7.0.0-beta.55",
+    "@babel/preset-env": "7.0.0-beta.55",
     "@types/chai": "4.1.4",
     "@types/chance": "1.0.1",
     "@types/escodegen": "0.0.6",
@@ -54,7 +54,7 @@
     "@types/mkdirp": "0.5.2",
     "@types/mocha": "5.2.5",
     "@types/multimatch": "2.1.2",
-    "@types/node": "10.5.2",
+    "@types/node": "10.5.4",
     "@types/rimraf": "2.0.2",
     "@types/sinon": "5.0.1",
     "@types/string-template": "1.0.2",
@@ -77,7 +77,7 @@
     "tslint-microsoft-contrib": "5.1.0",
     "tslint-webpack-plugin": "1.2.2",
     "typescript": "2.9.2",
-    "webpack": "4.16.1",
+    "webpack": "4.16.3",
     "webpack-cli": "3.1.0",
     "webpack-node-externals": "1.7.2"
   },

+ 2 - 2
src/analyzers/stack-trace-analyzer/StackTraceAnalyzer.ts

@@ -13,7 +13,7 @@ import { IStackTraceData } from '../../interfaces/analyzers/stack-trace-analyzer
 import { CalleeDataExtractor } from '../../enums/analyzers/stack-trace-analyzer/CalleeDataExtractor';
 
 import { NodeGuards } from '../../node/NodeGuards';
-import { NodeUtils } from '../../node/NodeUtils';
+import { NodeStatementUtils } from '../../node/NodeStatementUtils';
 
 /**
  * This class generates a data with a stack trace of functions calls
@@ -131,7 +131,7 @@ export class StackTraceAnalyzer implements IStackTraceAnalyzer {
                         return;
                     }
 
-                    if (blockScopeBodyNode.parentNode !== NodeUtils.getBlockScopeOfNode(node)) {
+                    if (blockScopeBodyNode.parentNode !== NodeStatementUtils.getParentNodeWithStatements(node)) {
                         return estraverse.VisitorOption.Skip;
                     }
 

+ 2 - 2
src/analyzers/stack-trace-analyzer/callee-data-extractors/FunctionDeclarationCalleeDataExtractor.ts

@@ -7,7 +7,7 @@ import { ICalleeData } from '../../../interfaces/analyzers/stack-trace-analyzer/
 
 import { AbstractCalleeDataExtractor } from './AbstractCalleeDataExtractor';
 import { NodeGuards } from '../../../node/NodeGuards';
-import { NodeUtils } from '../../../node/NodeUtils';
+import { NodeStatementUtils } from '../../../node/NodeStatementUtils';
 
 @injectable()
 export class FunctionDeclarationCalleeDataExtractor extends AbstractCalleeDataExtractor {
@@ -22,7 +22,7 @@ export class FunctionDeclarationCalleeDataExtractor extends AbstractCalleeDataEx
         }
 
         const calleeBlockStatement: ESTree.BlockStatement | null = this.getCalleeBlockStatement(
-            NodeUtils.getBlockScopeOfNode(blockScopeBody[0]),
+            NodeStatementUtils.getParentNodeWithStatements(blockScopeBody[0]),
             callee.name
         );
 

+ 2 - 2
src/analyzers/stack-trace-analyzer/callee-data-extractors/FunctionExpressionCalleeDataExtractor.ts

@@ -7,7 +7,7 @@ import { ICalleeData } from '../../../interfaces/analyzers/stack-trace-analyzer/
 
 import { AbstractCalleeDataExtractor } from './AbstractCalleeDataExtractor';
 import { NodeGuards } from '../../../node/NodeGuards';
-import { NodeUtils } from '../../../node/NodeUtils';
+import { NodeStatementUtils } from '../../../node/NodeStatementUtils';
 
 @injectable()
 export class FunctionExpressionCalleeDataExtractor extends AbstractCalleeDataExtractor {
@@ -21,7 +21,7 @@ export class FunctionExpressionCalleeDataExtractor extends AbstractCalleeDataExt
 
         if (NodeGuards.isIdentifierNode(callee)) {
             calleeBlockStatement = this.getCalleeBlockStatement(
-                NodeUtils.getBlockScopeOfNode(blockScopeBody[0]),
+                NodeStatementUtils.getParentNodeWithStatements(blockScopeBody[0]),
                 callee.name
             );
         }

+ 2 - 2
src/analyzers/stack-trace-analyzer/callee-data-extractors/ObjectExpressionCalleeDataExtractor.ts

@@ -9,7 +9,7 @@ import { ICalleeData } from '../../../interfaces/analyzers/stack-trace-analyzer/
 
 import { AbstractCalleeDataExtractor } from './AbstractCalleeDataExtractor';
 import { NodeGuards } from '../../../node/NodeGuards';
-import { NodeUtils } from '../../../node/NodeUtils';
+import { NodeStatementUtils } from '../../../node/NodeStatementUtils';
 
 @injectable()
 export class ObjectExpressionCalleeDataExtractor extends AbstractCalleeDataExtractor {
@@ -51,7 +51,7 @@ export class ObjectExpressionCalleeDataExtractor extends AbstractCalleeDataExtra
 
         const functionExpressionName: string | number | null = objectMembersCallsChain[objectMembersCallsChain.length - 1];
         const calleeBlockStatement: ESTree.BlockStatement | null = this.getCalleeBlockStatement(
-            NodeUtils.getBlockScopeOfNode(blockScopeBody[0]),
+            NodeStatementUtils.getParentNodeWithStatements(blockScopeBody[0]),
             objectMembersCallsChain
         );
 

+ 3 - 3
src/custom-nodes/AbstractCustomNodeGroup.ts

@@ -2,7 +2,7 @@ import { inject, injectable } from 'inversify';
 import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
 
 import { TIdentifierNamesGeneratorFactory } from '../types/container/generators/TIdentifierNamesGeneratorFactory';
-import { TNodeWithBlockScope } from '../types/node/TNodeWithBlockScope';
+import { TNodeWithStatements } from '../types/node/TNodeWithStatements';
 
 import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
 import { ICustomNodeGroup } from '../interfaces/custom-nodes/ICustomNodeGroup';
@@ -58,10 +58,10 @@ export abstract class AbstractCustomNodeGroup implements ICustomNodeGroup {
     }
 
     /**
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {IStackTraceData[]} stackTraceData
      */
-    public abstract appendCustomNodes (blockScopeNode: TNodeWithBlockScope, stackTraceData: IStackTraceData[]): void;
+    public abstract appendCustomNodes (nodeWithStatements: TNodeWithStatements, stackTraceData: IStackTraceData[]): void;
 
     /**
      * @returns {ObfuscationEvent}

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

@@ -3,7 +3,7 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 import { TCustomNodeFactory } from '../../../types/container/custom-nodes/TCustomNodeFactory';
 import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
-import { TNodeWithBlockScope } from '../../../types/node/TNodeWithBlockScope';
+import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
@@ -55,17 +55,17 @@ export class ConsoleOutputCustomNodeGroup extends AbstractCustomNodeGroup {
     }
 
     /**
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {IStackTraceData[]} stackTraceData
      */
-    public appendCustomNodes (blockScopeNode: TNodeWithBlockScope, stackTraceData: IStackTraceData[]): void {
+    public appendCustomNodes (nodeWithStatements: TNodeWithStatements, stackTraceData: IStackTraceData[]): void {
         const randomStackTraceIndex: number = this.getRandomStackTraceIndex(stackTraceData.length);
 
         // consoleOutputDisableExpressionNode append
         this.appendCustomNodeIfExist(CustomNode.ConsoleOutputDisableExpressionNode, (customNode: ICustomNode) => {
             NodeAppender.appendToOptimalBlockScope(
                 stackTraceData,
-                blockScopeNode,
+                nodeWithStatements,
                 customNode.getNode(),
                 randomStackTraceIndex
             );
@@ -73,15 +73,11 @@ export class ConsoleOutputCustomNodeGroup extends AbstractCustomNodeGroup {
 
         // nodeCallsControllerFunctionNode append
         this.appendCustomNodeIfExist(CustomNode.NodeCallsControllerFunctionNode, (customNode: ICustomNode) => {
-            let targetBlockScope: TNodeWithBlockScope;
+            const targetNodeWithStatements: TNodeWithStatements = stackTraceData.length
+                ? NodeAppender.getOptimalBlockScope(stackTraceData, randomStackTraceIndex, 1)
+                : nodeWithStatements;
 
-            if (stackTraceData.length) {
-                targetBlockScope = NodeAppender.getOptimalBlockScope(stackTraceData, randomStackTraceIndex, 1);
-            } else {
-                targetBlockScope = blockScopeNode;
-            }
-
-            NodeAppender.prepend(targetBlockScope, customNode.getNode());
+            NodeAppender.prepend(targetNodeWithStatements, customNode.getNode());
         });
     }
 

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

@@ -3,7 +3,7 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 import { TCustomNodeFactory } from '../../../types/container/custom-nodes/TCustomNodeFactory';
 import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
-import { TNodeWithBlockScope } from '../../../types/node/TNodeWithBlockScope';
+import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
@@ -17,6 +17,7 @@ import { ObfuscationEvent } from '../../../enums/event-emitters/ObfuscationEvent
 
 import { AbstractCustomNodeGroup } from '../../AbstractCustomNodeGroup';
 import { NodeAppender } from '../../../node/NodeAppender';
+import { NodeGuards } from '../../../node/NodeGuards';
 
 @injectable()
 export class DebugProtectionCustomNodeGroup extends AbstractCustomNodeGroup {
@@ -55,17 +56,17 @@ export class DebugProtectionCustomNodeGroup extends AbstractCustomNodeGroup {
     }
 
     /**
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {IStackTraceData[]} stackTraceData
      */
-    public appendCustomNodes (blockScopeNode: TNodeWithBlockScope, stackTraceData: IStackTraceData[]): void {
+    public appendCustomNodes (nodeWithStatements: TNodeWithStatements, stackTraceData: IStackTraceData[]): void {
         const randomStackTraceIndex: number = this.getRandomStackTraceIndex(stackTraceData.length);
 
         // debugProtectionFunctionCallNode append
         this.appendCustomNodeIfExist(CustomNode.DebugProtectionFunctionCallNode, (customNode: ICustomNode) => {
             NodeAppender.appendToOptimalBlockScope(
                 stackTraceData,
-                blockScopeNode,
+                nodeWithStatements,
                 customNode.getNode(),
                 randomStackTraceIndex
             );
@@ -73,28 +74,26 @@ export class DebugProtectionCustomNodeGroup extends AbstractCustomNodeGroup {
 
         // debugProtectionFunctionNode append
         this.appendCustomNodeIfExist(CustomNode.DebugProtectionFunctionNode, (customNode: ICustomNode) => {
-            NodeAppender.append(blockScopeNode, customNode.getNode());
+            NodeAppender.append(nodeWithStatements, customNode.getNode());
         });
 
         // debugProtectionFunctionIntervalNode append
         this.appendCustomNodeIfExist(CustomNode.DebugProtectionFunctionIntervalNode, (customNode: ICustomNode) => {
-            const programBodyLength: number = blockScopeNode.body.length;
+            const programBodyLength: number = NodeGuards.isSwitchCaseNode(nodeWithStatements)
+                ? nodeWithStatements.consequent.length
+                : nodeWithStatements.body.length;
             const randomIndex: number = this.randomGenerator.getRandomInteger(0, programBodyLength);
 
-            NodeAppender.insertAtIndex(blockScopeNode, customNode.getNode(), randomIndex);
+            NodeAppender.insertAtIndex(nodeWithStatements, customNode.getNode(), randomIndex);
         });
 
         // nodeCallsControllerFunctionNode append
         this.appendCustomNodeIfExist(CustomNode.NodeCallsControllerFunctionNode, (customNode: ICustomNode) => {
-            let targetBlockScope: TNodeWithBlockScope;
+            const targetNodeWithStatements: TNodeWithStatements = stackTraceData.length
+                ? NodeAppender.getOptimalBlockScope(stackTraceData, randomStackTraceIndex, 1)
+                : nodeWithStatements;
 
-            if (stackTraceData.length) {
-                targetBlockScope = NodeAppender.getOptimalBlockScope(stackTraceData, randomStackTraceIndex, 1);
-            } else {
-                targetBlockScope = blockScopeNode;
-            }
-
-            NodeAppender.prepend(targetBlockScope, customNode.getNode());
+            NodeAppender.prepend(targetNodeWithStatements, customNode.getNode());
         });
     }
 

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

@@ -3,7 +3,7 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 import { TCustomNodeFactory } from '../../../types/container/custom-nodes/TCustomNodeFactory';
 import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
-import { TNodeWithBlockScope } from '../../../types/node/TNodeWithBlockScope';
+import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
@@ -55,17 +55,17 @@ export class DomainLockCustomNodeGroup extends AbstractCustomNodeGroup {
     }
 
     /**
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {IStackTraceData[]} stackTraceData
      */
-    public appendCustomNodes (blockScopeNode: TNodeWithBlockScope, stackTraceData: IStackTraceData[]): void {
+    public appendCustomNodes (nodeWithStatements: TNodeWithStatements, stackTraceData: IStackTraceData[]): void {
         const randomStackTraceIndex: number = this.getRandomStackTraceIndex(stackTraceData.length);
 
         // domainLockNode append
         this.appendCustomNodeIfExist(CustomNode.DomainLockNode, (customNode: ICustomNode) => {
             NodeAppender.appendToOptimalBlockScope(
                 stackTraceData,
-                blockScopeNode,
+                nodeWithStatements,
                 customNode.getNode(),
                 randomStackTraceIndex
             );
@@ -73,15 +73,11 @@ export class DomainLockCustomNodeGroup extends AbstractCustomNodeGroup {
 
         // nodeCallsControllerFunctionNode append
         this.appendCustomNodeIfExist(CustomNode.NodeCallsControllerFunctionNode, (customNode: ICustomNode) => {
-            let targetBlockScope: TNodeWithBlockScope;
+            const targetNodeWithStatements: TNodeWithStatements = stackTraceData.length
+                ? NodeAppender.getOptimalBlockScope(stackTraceData, randomStackTraceIndex, 1)
+                : nodeWithStatements;
 
-            if (stackTraceData.length) {
-                targetBlockScope = NodeAppender.getOptimalBlockScope(stackTraceData, randomStackTraceIndex, 1);
-            } else {
-                targetBlockScope = blockScopeNode;
-            }
-
-            NodeAppender.prepend(targetBlockScope, customNode.getNode());
+            NodeAppender.prepend(targetNodeWithStatements, customNode.getNode());
         });
     }
 

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

@@ -3,7 +3,7 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 import { TCustomNodeFactory } from '../../../types/container/custom-nodes/TCustomNodeFactory';
 import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
-import { TNodeWithBlockScope } from '../../../types/node/TNodeWithBlockScope';
+import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
@@ -55,17 +55,17 @@ export class SelfDefendingCustomNodeGroup extends AbstractCustomNodeGroup {
     }
 
     /**
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {IStackTraceData[]} stackTraceData
      */
-    public appendCustomNodes (blockScopeNode: TNodeWithBlockScope, stackTraceData: IStackTraceData[]): void {
+    public appendCustomNodes (nodeWithStatements: TNodeWithStatements, stackTraceData: IStackTraceData[]): void {
         const randomStackTraceIndex: number = this.getRandomStackTraceIndex(stackTraceData.length);
 
         // selfDefendingUnicodeNode append
         this.appendCustomNodeIfExist(CustomNode.SelfDefendingUnicodeNode, (customNode: ICustomNode) => {
             NodeAppender.appendToOptimalBlockScope(
                 stackTraceData,
-                blockScopeNode,
+                nodeWithStatements,
                 customNode.getNode(),
                 randomStackTraceIndex
             );
@@ -73,15 +73,11 @@ export class SelfDefendingCustomNodeGroup extends AbstractCustomNodeGroup {
 
         // nodeCallsControllerFunctionNode append
         this.appendCustomNodeIfExist(CustomNode.NodeCallsControllerFunctionNode, (customNode: ICustomNode) => {
-            let targetBlockScope: TNodeWithBlockScope;
+            const targetNodeWithStatements: TNodeWithStatements = stackTraceData.length
+                ? NodeAppender.getOptimalBlockScope(stackTraceData, randomStackTraceIndex, 1)
+                : nodeWithStatements;
 
-            if (stackTraceData.length) {
-                targetBlockScope = NodeAppender.getOptimalBlockScope(stackTraceData, randomStackTraceIndex, 1);
-            } else {
-                targetBlockScope = blockScopeNode;
-            }
-
-            NodeAppender.prepend(targetBlockScope, customNode.getNode());
+            NodeAppender.prepend(targetNodeWithStatements, customNode.getNode());
         });
     }
 

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

@@ -3,7 +3,7 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 import { TCustomNodeFactory } from '../../../types/container/custom-nodes/TCustomNodeFactory';
 import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
-import { TNodeWithBlockScope } from '../../../types/node/TNodeWithBlockScope';
+import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
 import { TStringArrayStorage } from '../../../types/storages/TStringArrayStorage';
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
@@ -64,27 +64,27 @@ export class StringArrayCustomNodeGroup extends AbstractCustomNodeGroup {
     }
 
     /**
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {IStackTraceData[]} stackTraceData
      */
-    public appendCustomNodes (blockScopeNode: TNodeWithBlockScope, stackTraceData: IStackTraceData[]): void {
+    public appendCustomNodes (nodeWithStatements: TNodeWithStatements, stackTraceData: IStackTraceData[]): void {
         if (!this.stringArrayStorage.getLength()) {
             return;
         }
 
         // stringArrayNode append
         this.appendCustomNodeIfExist(CustomNode.StringArrayNode, (customNode: ICustomNode) => {
-            NodeAppender.prepend(blockScopeNode, customNode.getNode());
+            NodeAppender.prepend(nodeWithStatements, customNode.getNode());
         });
 
         // stringArrayCallsWrapper append
         this.appendCustomNodeIfExist(CustomNode.StringArrayCallsWrapper, (customNode: ICustomNode) => {
-            NodeAppender.insertAtIndex(blockScopeNode, customNode.getNode(), 1);
+            NodeAppender.insertAtIndex(nodeWithStatements, customNode.getNode(), 1);
         });
 
         // stringArrayRotateFunctionNode append
         this.appendCustomNodeIfExist(CustomNode.StringArrayRotateFunctionNode, (customNode: ICustomNode) => {
-            NodeAppender.insertAtIndex(blockScopeNode, customNode.getNode(), 1);
+            NodeAppender.insertAtIndex(nodeWithStatements, customNode.getNode(), 1);
         });
     }
 

+ 3 - 3
src/interfaces/custom-nodes/ICustomNodeGroup.d.ts

@@ -1,4 +1,4 @@
-import { TNodeWithBlockScope } from '../../types/node/TNodeWithBlockScope';
+import { TNodeWithStatements } from '../../types/node/TNodeWithStatements';
 
 import { ICustomNode } from './ICustomNode';
 import { IInitializable } from '../IInitializable';
@@ -9,10 +9,10 @@ import { ObfuscationEvent } from '../../enums/event-emitters/ObfuscationEvent';
 
 export interface ICustomNodeGroup extends IInitializable {
     /**
-     * @param blockScopeNode
+     * @param nodeWithStatements
      * @param stackTraceData
      */
-    appendCustomNodes (blockScopeNode: TNodeWithBlockScope, stackTraceData: IStackTraceData[]): void;
+    appendCustomNodes (nodeWithStatements: TNodeWithStatements, stackTraceData: IStackTraceData[]): void;
 
     /**
      * @returns {ObfuscationEvent}

+ 5 - 5
src/interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer.d.ts

@@ -1,19 +1,19 @@
 import * as ESTree from 'estree';
 
-import { TNodeWithBlockScope } from '../../../../types/node/TNodeWithBlockScope';
+import { TNodeWithLexicalScope } from '../../../../types/node/TNodeWithLexicalScope';
 
 import { IObfuscatingReplacer } from './IObfuscatingReplacer';
 
 export interface IIdentifierObfuscatingReplacer extends IObfuscatingReplacer <ESTree.Identifier> {
     /**
      * @param {string} nodeValue
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
-    storeGlobalName (nodeValue: string, blockScopeNode: TNodeWithBlockScope): void;
+    storeGlobalName (nodeValue: string, lexicalScopeNode: TNodeWithLexicalScope): void;
 
     /**
      * @param {string} nodeValue
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
-    storeLocalName (nodeValue: string, blockScopeNode: TNodeWithBlockScope): void;
+    storeLocalName (nodeValue: string, lexicalScopeNode: TNodeWithLexicalScope): void;
 }

+ 3 - 3
src/interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IObfuscatingReplacer.d.ts

@@ -1,13 +1,13 @@
 import * as ESTree from 'estree';
 
-import { TNodeWithBlockScope } from '../../../../types/node/TNodeWithBlockScope';
+import { TNodeWithLexicalScope } from '../../../../types/node/TNodeWithLexicalScope';
 
 export interface IObfuscatingReplacer <T = ESTree.Node> {
     /**
      * @param {SimpleLiteral["value"]} nodeValue
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      * @param {number} nodeIdentifier
      * @returns {T}
      */
-    replace (nodeValue: ESTree.SimpleLiteral['value'], blockScopeNode?: TNodeWithBlockScope, nodeIdentifier?: number): T;
+    replace (nodeValue: ESTree.SimpleLiteral['value'], lexicalScopeNode?: TNodeWithLexicalScope, nodeIdentifier?: number): T;
 }

+ 15 - 11
src/node-transformers/control-flow-transformers/FunctionControlFlowTransformer.ts

@@ -8,7 +8,7 @@ import { TControlFlowCustomNodeFactory } from '../../types/container/custom-node
 import { TControlFlowReplacerFactory } from '../../types/container/node-transformers/TControlFlowReplacerFactory';
 import { TControlFlowStorage } from '../../types/storages/TControlFlowStorage';
 import { TControlFlowStorageFactory } from '../../types/container/node-transformers/TControlFlowStorageFactory';
-import { TNodeWithBlockScope } from '../../types/node/TNodeWithBlockScope';
+import { TNodeWithStatements } from '../../types/node/TNodeWithStatements';
 
 import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
@@ -24,7 +24,7 @@ import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeAppender } from '../../node/NodeAppender';
 import { NodeGuards } from '../../node/NodeGuards';
 import { NodeMetadata } from '../../node/NodeMetadata';
-import { NodeUtils } from '../../node/NodeUtils';
+import { NodeStatementUtils } from '../../node/NodeStatementUtils';
 
 @injectable()
 export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
@@ -59,9 +59,9 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
     private readonly visitedFunctionNodes: Set<ESTree.Function> = new Set();
 
     /**
-     * @type {Set<TNodeWithBlockScope>}
+     * @type {Set<TNodeWithStatements>}
      */
-    private readonly hostNodesWithControlFlowNode: Set<TNodeWithBlockScope> = new Set();
+    private readonly hostNodesWithControlFlowNode: Set<TNodeWithStatements> = new Set();
 
     /**
      * @type {TControlFlowReplacerFactory}
@@ -140,7 +140,7 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
             return functionNode;
         }
 
-        const hostNode: TNodeWithBlockScope = this.getHostNode(functionNode.body);
+        const hostNode: TNodeWithStatements = this.getHostNode(functionNode.body);
         const controlFlowStorage: TControlFlowStorage = this.getControlFlowStorage(hostNode);
 
         this.controlFlowData.set(hostNode, controlFlowStorage);
@@ -162,15 +162,19 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
     }
 
     /**
-     * @param {TNodeWithBlockScope} hostNode
+     * @param {TNodeWithStatements} hostNode
      * @returns {TControlFlowStorage}
      */
-    private getControlFlowStorage (hostNode: TNodeWithBlockScope): TControlFlowStorage {
+    private getControlFlowStorage (hostNode: TNodeWithStatements): TControlFlowStorage {
         const controlFlowStorage: TControlFlowStorage = this.controlFlowStorageFactory();
 
         if (this.controlFlowData.has(hostNode)) {
             if (this.hostNodesWithControlFlowNode.has(hostNode)) {
-                hostNode.body.shift();
+                if (NodeGuards.isSwitchCaseNode(hostNode)) {
+                    hostNode.consequent.shift();
+                } else {
+                    hostNode.body.shift();
+                }
             }
 
             const hostControlFlowStorage: TControlFlowStorage = <TControlFlowStorage>this.controlFlowData.get(hostNode);
@@ -183,10 +187,10 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {BlockStatement} functionNodeBody
-     * @returns {TNodeWithBlockScope}
+     * @returns {TNodeWithStatements}
      */
-    private getHostNode (functionNodeBody: ESTree.BlockStatement): TNodeWithBlockScope {
-        const blockScopesOfNode: TNodeWithBlockScope[] = NodeUtils.getBlockScopesOfNode(functionNodeBody);
+    private getHostNode (functionNodeBody: ESTree.BlockStatement): TNodeWithStatements {
+        const blockScopesOfNode: TNodeWithStatements[] = NodeStatementUtils.getParentNodesWithStatements(functionNodeBody);
 
         if (blockScopesOfNode.length === 1) {
             return functionNodeBody;

+ 18 - 15
src/node-transformers/converting-transformers/properties-extractors/AbstractPropertiesExtractor.ts

@@ -3,7 +3,7 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 import * as ESTree from 'estree';
 
-import { TNodeWithScope } from '../../../types/node/TNodeWithScope';
+import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
 
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IPropertiesExtractor } from '../../../interfaces/node-transformers/converting-transformers/properties-extractors/IPropertiesExtractor';
@@ -12,14 +12,14 @@ import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
 import { NodeAppender } from '../../../node/NodeAppender';
 import { NodeFactory } from '../../../node/NodeFactory';
 import { NodeGuards } from '../../../node/NodeGuards';
-import { NodeUtils } from '../../../node/NodeUtils';
+import { NodeStatementUtils } from '../../../node/NodeStatementUtils';
 
 @injectable()
 export abstract class AbstractPropertiesExtractor implements IPropertiesExtractor {
     /**
-     * @type {Map<ESTree.ObjectExpression, TNodeWithScope>}
+     * @type {Map<ESTree.ObjectExpression, TNodeWithStatements>}
      */
-    protected readonly cachedHostScopesMap: Map <ESTree.ObjectExpression, TNodeWithScope> = new Map();
+    protected readonly cachedHostNodesWithStatementsMap: Map <ESTree.ObjectExpression, TNodeWithStatements> = new Map();
 
     /**
      * @type {Map<ESTree.ObjectExpression, ESTree.Statement>}
@@ -179,10 +179,13 @@ export abstract class AbstractPropertiesExtractor implements IPropertiesExtracto
             .extractPropertiesToExpressionStatements(properties, memberExpressionHostNode);
 
         const hostStatement: ESTree.Statement = this.getHostStatement(objectExpressionNode);
-        const scopeNode: TNodeWithScope = this.getHostScopeNode(objectExpressionNode, hostStatement);
+        const hostNodeWithStatements: TNodeWithStatements = this.getHostNodeWithStatements(
+            objectExpressionNode,
+            hostStatement
+        );
 
         this.filterExtractedObjectExpressionProperties(objectExpressionNode, removablePropertyIds);
-        NodeAppender.insertAfter(scopeNode, expressionStatements, hostStatement);
+        NodeAppender.insertAfter(hostNodeWithStatements, expressionStatements, hostStatement);
 
         return objectExpressionNode;
     }
@@ -190,21 +193,21 @@ export abstract class AbstractPropertiesExtractor implements IPropertiesExtracto
     /**
      * @param {ObjectExpression} objectExpressionNode
      * @param {Statement} hostStatement
-     * @returns {TNodeWithScope}
+     * @returns {TNodeWithStatements}
      */
-    protected getHostScopeNode (
+    protected getHostNodeWithStatements (
         objectExpressionNode: ESTree.ObjectExpression,
         hostStatement: ESTree.Statement
-    ): TNodeWithScope {
-        if (this.cachedHostScopesMap.has(objectExpressionNode)) {
-            return <TNodeWithScope>this.cachedHostScopesMap.get(objectExpressionNode);
+    ): TNodeWithStatements {
+        if (this.cachedHostNodesWithStatementsMap.has(objectExpressionNode)) {
+            return <TNodeWithStatements>this.cachedHostNodesWithStatementsMap.get(objectExpressionNode);
         }
 
-        const scopeNode: TNodeWithScope = NodeUtils.getScopeOfNode(hostStatement);
+        const nodeWithStatements: TNodeWithStatements = NodeStatementUtils.getScopeOfNode(hostStatement);
 
-        this.cachedHostScopesMap.set(objectExpressionNode, scopeNode);
+        this.cachedHostNodesWithStatementsMap.set(objectExpressionNode, nodeWithStatements);
 
-        return scopeNode;
+        return nodeWithStatements;
     }
 
     /**
@@ -218,7 +221,7 @@ export abstract class AbstractPropertiesExtractor implements IPropertiesExtracto
             return <ESTree.Statement>this.cachedHostStatementsMap.get(objectExpressionNode);
         }
 
-        const hostStatement: ESTree.Statement = NodeUtils.getRootStatementOfNode(objectExpressionNode);
+        const hostStatement: ESTree.Statement = NodeStatementUtils.getRootStatementOfNode(objectExpressionNode);
 
         this.cachedHostStatementsMap.set(objectExpressionNode, hostStatement);
 

+ 19 - 12
src/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.ts

@@ -5,8 +5,7 @@ import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
 import { TDeadNodeInjectionCustomNodeFactory } from '../../types/container/custom-nodes/TDeadNodeInjectionCustomNodeFactory';
-import { TNodeWithBlockScope } from '../../types/node/TNodeWithBlockScope';
-import { TNodeWithScope } from '../../types/node/TNodeWithScope';
+import { TNodeWithStatements } from '../../types/node/TNodeWithStatements';
 
 import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
@@ -22,6 +21,7 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeFactory } from '../../node/NodeFactory';
 import { NodeGuards } from '../../node/NodeGuards';
+import { NodeStatementUtils } from '../../node/NodeStatementUtils';
 import { NodeUtils } from '../../node/NodeUtils';
 
 @injectable()
@@ -117,7 +117,7 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
             return false;
         }
 
-        const scopeNode: TNodeWithScope = NodeUtils.getScopeOfNode(targetNode);
+        const scopeNode: TNodeWithStatements = NodeStatementUtils.getScopeOfNode(targetNode);
         const scopeBody: ESTree.Statement[] = !NodeGuards.isSwitchCaseNode(scopeNode)
             ? <ESTree.Statement[]>scopeNode.body
             : scopeNode.consequent;
@@ -204,10 +204,10 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
             return false;
         }
 
-        const blockScopeOfBlockStatementNode: TNodeWithBlockScope = NodeUtils
-            .getBlockScopeOfNode(blockStatementNode);
+        const parentNodeWithStatements: TNodeWithStatements = NodeStatementUtils
+            .getParentNodeWithStatements(blockStatementNode);
 
-        return blockScopeOfBlockStatementNode.type !== NodeType.Program;
+        return parentNodeWithStatements.type !== NodeType.Program;
     }
 
     /**
@@ -261,7 +261,7 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
                     return;
                 }
 
-                let clonedBlockStatementNode: ESTree.BlockStatement = NodeUtils.clone(node);
+                const clonedBlockStatementNode: ESTree.BlockStatement = NodeUtils.clone(node);
 
                 if (!DeadCodeInjectionTransformer.isValidCollectedBlockStatementNode(clonedBlockStatementNode)) {
                     return;
@@ -270,10 +270,10 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
                 /**
                  * We should transform identifiers in the dead code block statement to avoid conflicts with original code
                  */
-                NodeUtils.parentizeNode(clonedBlockStatementNode, clonedBlockStatementNode);
-                clonedBlockStatementNode = this.makeClonedBlockStatementNodeUnique(clonedBlockStatementNode);
+                const transformedBlockStatementNode: ESTree.BlockStatement =
+                    this.makeClonedBlockStatementNodeUnique(clonedBlockStatementNode);
 
-                this.collectedBlockStatements.push(clonedBlockStatementNode);
+                this.collectedBlockStatements.push(transformedBlockStatementNode);
             }
         });
 
@@ -346,11 +346,18 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
      * @returns {BlockStatement}
      */
     private makeClonedBlockStatementNodeUnique (clonedBlockStatementNode: ESTree.BlockStatement): ESTree.BlockStatement {
+        // should wrap cloned block statement node into function node for correct scope encapsulation
+        const hostNode: ESTree.FunctionExpression = NodeFactory
+            .functionExpressionNode([], clonedBlockStatementNode);
+
+        NodeUtils.parentizeNode(hostNode, hostNode);
+        NodeUtils.parentizeNode(clonedBlockStatementNode, hostNode);
+
         return this.transformersRunner.transform(
-            clonedBlockStatementNode,
+            hostNode,
             DeadCodeInjectionTransformer.transformersToRenameBlockScopeIdentifiers,
             TransformationStage.Obfuscating
-        );
+        ).body;
     }
 
     /**

+ 15 - 11
src/node-transformers/obfuscating-transformers/CatchClauseTransformer.ts

@@ -5,7 +5,7 @@ import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
 import { TIdentifierObfuscatingReplacerFactory } from '../../types/container/node-transformers/TIdentifierObfuscatingReplacerFactory';
-import { TNodeWithBlockScope } from '../../types/node/TNodeWithBlockScope';
+import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
 
 import { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer';
 import { IOptions } from '../../interfaces/options/IOptions';
@@ -17,8 +17,8 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
 
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeGuards } from '../../node/NodeGuards';
+import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
 import { NodeMetadata } from '../../node/NodeMetadata';
-import { NodeUtils } from '../../node/NodeUtils';
 
 /**
  * replaces:
@@ -79,40 +79,44 @@ export class CatchClauseTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (catchClauseNode: ESTree.CatchClause, parentNode: ESTree.Node): ESTree.Node {
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopeOfNode(catchClauseNode);
+        const lexicalScopeNode: TNodeWithLexicalScope | undefined = NodeLexicalScopeUtils.getLexicalScope(catchClauseNode);
 
-        this.storeCatchClauseParam(catchClauseNode, blockScopeNode);
-        this.replaceCatchClauseParam(catchClauseNode, blockScopeNode);
+        if (!lexicalScopeNode) {
+            return catchClauseNode;
+        }
+
+        this.storeCatchClauseParam(catchClauseNode, lexicalScopeNode);
+        this.replaceCatchClauseParam(catchClauseNode, lexicalScopeNode);
 
         return catchClauseNode;
     }
 
     /**
      * @param {CatchClause} catchClauseNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
     private storeCatchClauseParam (
         catchClauseNode: ESTree.CatchClause,
-        blockScopeNode: TNodeWithBlockScope
+        lexicalScopeNode: TNodeWithLexicalScope
     ): void {
         if (NodeGuards.isIdentifierNode(catchClauseNode.param)) {
-            this.identifierObfuscatingReplacer.storeLocalName(catchClauseNode.param.name, blockScopeNode);
+            this.identifierObfuscatingReplacer.storeLocalName(catchClauseNode.param.name, lexicalScopeNode);
         }
     }
 
     /**
      * @param {CatchClause} catchClauseNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
     private replaceCatchClauseParam (
         catchClauseNode: ESTree.CatchClause,
-        blockScopeNode: TNodeWithBlockScope
+        lexicalScopeNode: TNodeWithLexicalScope
     ): void {
         estraverse.replace(catchClauseNode, {
             enter: (node: ESTree.Node, parentNode: ESTree.Node | null): void => {
                 if (parentNode && NodeGuards.isReplaceableIdentifierNode(node, parentNode)) {
                     const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                        .replace(node.name, blockScopeNode);
+                        .replace(node.name, lexicalScopeNode);
                     const newIdentifierName: string = newIdentifier.name;
 
                     if (node.name !== newIdentifierName) {

+ 26 - 21
src/node-transformers/obfuscating-transformers/ClassDeclarationTransformer.ts

@@ -5,7 +5,7 @@ import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
 import { TIdentifierObfuscatingReplacerFactory } from "../../types/container/node-transformers/TIdentifierObfuscatingReplacerFactory";
-import { TNodeWithBlockScope } from '../../types/node/TNodeWithBlockScope';
+import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
 import { TReplaceableIdentifiers } from '../../types/node-transformers/TReplaceableIdentifiers';
 import { TReplaceableIdentifiersNames } from '../../types/node-transformers/TReplaceableIdentifiersNames';
 
@@ -20,8 +20,8 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
 
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeGuards } from '../../node/NodeGuards';
+import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
 import { NodeMetadata } from '../../node/NodeMetadata';
-import { NodeUtils } from '../../node/NodeUtils';
 
 /**
  * replaces:
@@ -92,20 +92,25 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (classDeclarationNode: ESTree.ClassDeclaration, parentNode: ESTree.Node): ESTree.Node {
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopeOfNode(classDeclarationNode);
-        const isGlobalDeclaration: boolean = blockScopeNode.type === NodeType.Program;
+        const lexicalScopeNode: TNodeWithLexicalScope | undefined = NodeLexicalScopeUtils.getLexicalScope(classDeclarationNode);
+
+        if (!lexicalScopeNode) {
+            return classDeclarationNode;
+        }
+
+        const isGlobalDeclaration: boolean = lexicalScopeNode.type === NodeType.Program;
 
         if (!this.options.renameGlobals && isGlobalDeclaration) {
             return classDeclarationNode;
         }
 
-        this.storeClassName(classDeclarationNode, blockScopeNode, isGlobalDeclaration);
+        this.storeClassName(classDeclarationNode, lexicalScopeNode, isGlobalDeclaration);
 
         // check for cached identifiers for current scope node. If exist - loop through them.
-        if (this.replaceableIdentifiers.has(blockScopeNode)) {
-            this.replaceScopeCachedIdentifiers(classDeclarationNode, blockScopeNode);
+        if (this.replaceableIdentifiers.has(lexicalScopeNode)) {
+            this.replaceScopeCachedIdentifiers(classDeclarationNode, lexicalScopeNode);
         } else {
-            this.replaceScopeIdentifiers(blockScopeNode);
+            this.replaceScopeIdentifiers(lexicalScopeNode);
         }
 
         return classDeclarationNode;
@@ -113,31 +118,31 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {ClassDeclaration} classDeclarationNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      * @param {boolean} isGlobalDeclaration
      */
     private storeClassName (
         classDeclarationNode: ESTree.ClassDeclaration,
-        blockScopeNode: TNodeWithBlockScope,
+        lexicalScopeNode: TNodeWithLexicalScope,
         isGlobalDeclaration: boolean
     ): void {
         if (isGlobalDeclaration) {
-            this.identifierObfuscatingReplacer.storeGlobalName(classDeclarationNode.id.name, blockScopeNode);
+            this.identifierObfuscatingReplacer.storeGlobalName(classDeclarationNode.id.name, lexicalScopeNode);
         } else {
-            this.identifierObfuscatingReplacer.storeLocalName(classDeclarationNode.id.name, blockScopeNode);
+            this.identifierObfuscatingReplacer.storeLocalName(classDeclarationNode.id.name, lexicalScopeNode);
         }
     }
 
     /**
      * @param {ClassDeclaration} classDeclarationNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
     private replaceScopeCachedIdentifiers (
         classDeclarationNode: ESTree.ClassDeclaration,
-        blockScopeNode: TNodeWithBlockScope
+        lexicalScopeNode: TNodeWithLexicalScope
     ): void {
         const cachedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames =
-            <TReplaceableIdentifiersNames>this.replaceableIdentifiers.get(blockScopeNode);
+            <TReplaceableIdentifiersNames>this.replaceableIdentifiers.get(lexicalScopeNode);
 
         const cachedReplaceableIdentifiers: ESTree.Identifier[] | undefined = cachedReplaceableIdentifiersNamesMap
             .get(classDeclarationNode.id.name);
@@ -151,7 +156,7 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
         for (let i: number = 0; i < cachedReplaceableIdentifierLength; i++) {
             const replaceableIdentifier: ESTree.Identifier = cachedReplaceableIdentifiers[i];
             const newReplaceableIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                .replace(replaceableIdentifier.name, blockScopeNode);
+                .replace(replaceableIdentifier.name, lexicalScopeNode);
 
             replaceableIdentifier.name = newReplaceableIdentifier.name;
             NodeMetadata.set(replaceableIdentifier, { renamedIdentifier: true });
@@ -159,12 +164,12 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
     }
 
     /**
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
-    private replaceScopeIdentifiers (blockScopeNode: TNodeWithBlockScope): void {
+    private replaceScopeIdentifiers (lexicalScopeNode: TNodeWithLexicalScope): void {
         const storedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames = new Map();
 
-        estraverse.replace(blockScopeNode, {
+        estraverse.replace(lexicalScopeNode, {
             enter: (node: ESTree.Node, parentNode: ESTree.Node | null): void => {
                 if (
                     parentNode
@@ -172,7 +177,7 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
                     && !NodeMetadata.isRenamedIdentifier(node)
                 ) {
                     const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                        .replace(node.name, blockScopeNode);
+                        .replace(node.name, lexicalScopeNode);
                     const newIdentifierName: string = newIdentifier.name;
 
                     if (node.name !== newIdentifierName) {
@@ -189,6 +194,6 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
             }
         });
 
-        this.replaceableIdentifiers.set(blockScopeNode, storedReplaceableIdentifiersNamesMap);
+        this.replaceableIdentifiers.set(lexicalScopeNode, storedReplaceableIdentifiersNamesMap);
     }
 }

+ 26 - 21
src/node-transformers/obfuscating-transformers/FunctionDeclarationTransformer.ts

@@ -5,7 +5,7 @@ import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
 import { TIdentifierObfuscatingReplacerFactory } from "../../types/container/node-transformers/TIdentifierObfuscatingReplacerFactory";
-import { TNodeWithBlockScope } from '../../types/node/TNodeWithBlockScope';
+import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
 import { TReplaceableIdentifiers } from '../../types/node-transformers/TReplaceableIdentifiers';
 import { TReplaceableIdentifiersNames } from '../../types/node-transformers/TReplaceableIdentifiersNames';
 
@@ -20,8 +20,8 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
 
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeGuards } from '../../node/NodeGuards';
+import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
 import { NodeMetadata } from '../../node/NodeMetadata';
-import { NodeUtils } from '../../node/NodeUtils';
 
 /**
  * replaces:
@@ -92,20 +92,25 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (functionDeclarationNode: ESTree.FunctionDeclaration, parentNode: ESTree.Node): ESTree.Node {
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopeOfNode(functionDeclarationNode);
-        const isGlobalDeclaration: boolean = blockScopeNode.type === NodeType.Program;
+        const lexicalScopeNode: TNodeWithLexicalScope | undefined = NodeLexicalScopeUtils.getLexicalScope(parentNode);
+
+        if (!lexicalScopeNode) {
+            return functionDeclarationNode;
+        }
+
+        const isGlobalDeclaration: boolean = lexicalScopeNode.type === NodeType.Program;
 
         if (!this.options.renameGlobals && isGlobalDeclaration) {
             return functionDeclarationNode;
         }
 
-        this.storeFunctionName(functionDeclarationNode, blockScopeNode, isGlobalDeclaration);
+        this.storeFunctionName(functionDeclarationNode, lexicalScopeNode, isGlobalDeclaration);
 
         // check for cached identifiers for current scope node. If exist - loop through them.
-        if (this.replaceableIdentifiers.has(blockScopeNode)) {
-            this.replaceScopeCachedIdentifiers(functionDeclarationNode, blockScopeNode);
+        if (this.replaceableIdentifiers.has(lexicalScopeNode)) {
+            this.replaceScopeCachedIdentifiers(functionDeclarationNode, lexicalScopeNode);
         } else {
-            this.replaceScopeIdentifiers(blockScopeNode);
+            this.replaceScopeIdentifiers(lexicalScopeNode);
         }
 
         return functionDeclarationNode;
@@ -113,31 +118,31 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {FunctionDeclaration} functionDeclarationNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      * @param {boolean} isGlobalDeclaration
      */
     private storeFunctionName (
         functionDeclarationNode: ESTree.FunctionDeclaration,
-        blockScopeNode: TNodeWithBlockScope,
+        lexicalScopeNode: TNodeWithLexicalScope,
         isGlobalDeclaration: boolean
     ): void {
         if (isGlobalDeclaration) {
-            this.identifierObfuscatingReplacer.storeGlobalName(functionDeclarationNode.id.name, blockScopeNode);
+            this.identifierObfuscatingReplacer.storeGlobalName(functionDeclarationNode.id.name, lexicalScopeNode);
         } else {
-            this.identifierObfuscatingReplacer.storeLocalName(functionDeclarationNode.id.name, blockScopeNode);
+            this.identifierObfuscatingReplacer.storeLocalName(functionDeclarationNode.id.name, lexicalScopeNode);
         }
     }
 
     /**
      * @param {FunctionDeclaration} functionDeclarationNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
     private replaceScopeCachedIdentifiers (
         functionDeclarationNode: ESTree.FunctionDeclaration,
-        blockScopeNode: TNodeWithBlockScope
+        lexicalScopeNode: TNodeWithLexicalScope
     ): void {
         const cachedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames =
-            <TReplaceableIdentifiersNames>this.replaceableIdentifiers.get(blockScopeNode);
+            <TReplaceableIdentifiersNames>this.replaceableIdentifiers.get(lexicalScopeNode);
 
         const cachedReplaceableIdentifiers: ESTree.Identifier[] | undefined = cachedReplaceableIdentifiersNamesMap
             .get(functionDeclarationNode.id.name);
@@ -151,7 +156,7 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
         for (let i: number = 0; i < cachedReplaceableIdentifierLength; i++) {
             const replaceableIdentifier: ESTree.Identifier = cachedReplaceableIdentifiers[i];
             const newReplaceableIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                .replace(replaceableIdentifier.name, blockScopeNode);
+                .replace(replaceableIdentifier.name, lexicalScopeNode);
 
             replaceableIdentifier.name = newReplaceableIdentifier.name;
             NodeMetadata.set(replaceableIdentifier, { renamedIdentifier: true });
@@ -159,12 +164,12 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
     }
 
     /**
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
-    private replaceScopeIdentifiers (blockScopeNode: TNodeWithBlockScope): void {
+    private replaceScopeIdentifiers (lexicalScopeNode: TNodeWithLexicalScope): void {
         const storedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames = new Map();
 
-        estraverse.replace(blockScopeNode, {
+        estraverse.replace(lexicalScopeNode, {
             enter: (node: ESTree.Node, parentNode: ESTree.Node | null): void => {
                 if (
                     parentNode
@@ -172,7 +177,7 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
                     && !NodeMetadata.isRenamedIdentifier(node)
                 ) {
                     const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                        .replace(node.name, blockScopeNode);
+                        .replace(node.name, lexicalScopeNode);
                     const newIdentifierName: string = newIdentifier.name;
 
                     if (node.name !== newIdentifierName) {
@@ -189,6 +194,6 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
             }
         });
 
-        this.replaceableIdentifiers.set(blockScopeNode, storedReplaceableIdentifiersNamesMap);
+        this.replaceableIdentifiers.set(lexicalScopeNode, storedReplaceableIdentifiersNamesMap);
     }
 }

+ 17 - 15
src/node-transformers/obfuscating-transformers/FunctionTransformer.ts

@@ -5,7 +5,7 @@ import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
 import { TIdentifierObfuscatingReplacerFactory } from '../../types/container/node-transformers/TIdentifierObfuscatingReplacerFactory';
-import { TNodeWithBlockScope } from '../../types/node/TNodeWithBlockScope';
+import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
 
 import { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer';
 import { IOptions } from '../../interfaces/options/IOptions';
@@ -17,8 +17,8 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
 
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeGuards } from '../../node/NodeGuards';
+import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
 import { NodeMetadata } from '../../node/NodeMetadata';
-import { NodeUtils } from '../../node/NodeUtils';
 
 /**
  * replaces:
@@ -89,21 +89,23 @@ export class FunctionTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (functionNode: ESTree.Function, parentNode: ESTree.Node): ESTree.Node {
-        const blockScopeNode: TNodeWithBlockScope = NodeGuards.isBlockStatementNode(functionNode.body)
-            ? functionNode.body
-            : NodeUtils.getBlockScopeOfNode(functionNode.body);
+        const lexicalScopeNode: TNodeWithLexicalScope | undefined = NodeLexicalScopeUtils.getLexicalScope(functionNode);
 
-        this.storeFunctionParams(functionNode, blockScopeNode);
-        this.replaceFunctionParams(functionNode, blockScopeNode);
+        if (!lexicalScopeNode) {
+            return functionNode;
+        }
+
+        this.storeFunctionParams(functionNode, lexicalScopeNode);
+        this.replaceFunctionParams(functionNode, lexicalScopeNode);
 
         return functionNode;
     }
 
     /**
      * @param {Function} functionNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
-    private storeFunctionParams (functionNode: ESTree.Function, blockScopeNode: TNodeWithBlockScope): void {
+    private storeFunctionParams (functionNode: ESTree.Function, lexicalScopeNode: TNodeWithLexicalScope): void {
         functionNode.params
             .forEach((paramsNode: ESTree.Node) => {
                 estraverse.traverse(paramsNode, {
@@ -113,13 +115,13 @@ export class FunctionTransformer extends AbstractNodeTransformer {
                         }
 
                         if (NodeGuards.isAssignmentPatternNode(node) && NodeGuards.isIdentifierNode(node.left)) {
-                            this.identifierObfuscatingReplacer.storeLocalName(node.left.name, blockScopeNode);
+                            this.identifierObfuscatingReplacer.storeLocalName(node.left.name, lexicalScopeNode);
 
                             return estraverse.VisitorOption.Skip;
                         }
 
                         if (NodeGuards.isIdentifierNode(node)) {
-                            this.identifierObfuscatingReplacer.storeLocalName(node.name, blockScopeNode);
+                            this.identifierObfuscatingReplacer.storeLocalName(node.name, lexicalScopeNode);
                         }
                     }
                 });
@@ -128,12 +130,12 @@ export class FunctionTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {Function} functionNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      * @param {Set<string>} ignoredIdentifierNamesSet
      */
     private replaceFunctionParams (
         functionNode: ESTree.Function,
-        blockScopeNode: TNodeWithBlockScope,
+        lexicalScopeNode: TNodeWithLexicalScope,
         ignoredIdentifierNamesSet: Set <string> = new Set()
     ): void {
         const replaceVisitor: estraverse.Visitor = {
@@ -142,7 +144,7 @@ export class FunctionTransformer extends AbstractNodeTransformer {
                  * Should to process nested functions in different traverse loop to avoid wrong code generation
                  */
                 if (NodeGuards.isFunctionNode(node)) {
-                    this.replaceFunctionParams(node, blockScopeNode, new Set(ignoredIdentifierNamesSet));
+                    this.replaceFunctionParams(node, lexicalScopeNode, new Set(ignoredIdentifierNamesSet));
 
                     return estraverse.VisitorOption.Skip;
                 }
@@ -160,7 +162,7 @@ export class FunctionTransformer extends AbstractNodeTransformer {
                     && !ignoredIdentifierNamesSet.has(node.name)
                 ) {
                     const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                        .replace(node.name, blockScopeNode);
+                        .replace(node.name, lexicalScopeNode);
                     const newIdentifierName: string = newIdentifier.name;
 
                     if (node.name !== newIdentifierName) {

+ 23 - 19
src/node-transformers/obfuscating-transformers/ImportDeclarationTransformer.ts

@@ -6,7 +6,7 @@ import * as ESTree from 'estree';
 
 import { TIdentifierObfuscatingReplacerFactory } from "../../types/container/node-transformers/TIdentifierObfuscatingReplacerFactory";
 import { TImportSpecifier } from '../../types/node/TimportSpecifier';
-import { TNodeWithBlockScope } from '../../types/node/TNodeWithBlockScope';
+import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
 
 import { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer';
 import { IOptions } from '../../interfaces/options/IOptions';
@@ -18,8 +18,8 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
 
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeGuards } from '../../node/NodeGuards';
+import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
 import { NodeMetadata } from '../../node/NodeMetadata';
-import { NodeUtils } from '../../node/NodeUtils';
 
 /**
  * replaces:
@@ -95,15 +95,19 @@ export class ImportDeclarationTransformer extends AbstractNodeTransformer {
      * @returns {Node}
      */
     public transformNode (importDeclarationNode: ESTree.ImportDeclaration, parentNode: ESTree.Node): ESTree.Node {
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopeOfNode(importDeclarationNode);
+        const lexicalScopeNode: TNodeWithLexicalScope | undefined = NodeLexicalScopeUtils.getLexicalScope(importDeclarationNode);
 
-        this.storeImportSpecifierNames(importDeclarationNode, blockScopeNode);
+        if (!lexicalScopeNode) {
+            return importDeclarationNode;
+        }
+
+        this.storeImportSpecifierNames(importDeclarationNode, lexicalScopeNode);
 
         // check for cached identifiers for current scope node. If exist - loop through them.
-        if (this.replaceableIdentifiers.has(blockScopeNode)) {
-            this.replaceScopeCachedIdentifiers(blockScopeNode);
+        if (this.replaceableIdentifiers.has(lexicalScopeNode)) {
+            this.replaceScopeCachedIdentifiers(lexicalScopeNode);
         } else {
-            this.replaceScopeIdentifiers(blockScopeNode);
+            this.replaceScopeIdentifiers(lexicalScopeNode);
         }
 
         return importDeclarationNode;
@@ -111,31 +115,31 @@ export class ImportDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {ImportDeclaration} importDeclarationNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
     private storeImportSpecifierNames (
         importDeclarationNode: ESTree.ImportDeclaration,
-        blockScopeNode: TNodeWithBlockScope
+        lexicalScopeNode: TNodeWithLexicalScope
     ): void {
         importDeclarationNode.specifiers.forEach((importSpecifierNode: TImportSpecifier) => {
             if (ImportDeclarationTransformer.isProhibitedImportSpecifierNode(importSpecifierNode)) {
                 return;
             }
 
-            this.identifierObfuscatingReplacer.storeGlobalName(importSpecifierNode.local.name, blockScopeNode);
+            this.identifierObfuscatingReplacer.storeGlobalName(importSpecifierNode.local.name, lexicalScopeNode);
         });
     }
 
     /**
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
-    private replaceScopeCachedIdentifiers (blockScopeNode: TNodeWithBlockScope): void {
+    private replaceScopeCachedIdentifiers (lexicalScopeNode: TNodeWithLexicalScope): void {
         const cachedReplaceableIdentifiers: ESTree.Identifier[] =
-            <ESTree.Identifier[]>this.replaceableIdentifiers.get(blockScopeNode);
+            <ESTree.Identifier[]>this.replaceableIdentifiers.get(lexicalScopeNode);
 
         cachedReplaceableIdentifiers.forEach((replaceableIdentifier: ESTree.Identifier) => {
             const newReplaceableIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                .replace(replaceableIdentifier.name, blockScopeNode);
+                .replace(replaceableIdentifier.name, lexicalScopeNode);
 
             replaceableIdentifier.name = newReplaceableIdentifier.name;
             NodeMetadata.set(replaceableIdentifier, { renamedIdentifier: true });
@@ -143,12 +147,12 @@ export class ImportDeclarationTransformer extends AbstractNodeTransformer {
     }
 
     /**
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
-    private replaceScopeIdentifiers (blockScopeNode: TNodeWithBlockScope): void {
+    private replaceScopeIdentifiers (lexicalScopeNode: TNodeWithLexicalScope): void {
         const storedReplaceableIdentifiers: ESTree.Identifier[] = [];
 
-        estraverse.replace(blockScopeNode, {
+        estraverse.replace(lexicalScopeNode, {
             enter: (node: ESTree.Node, parentNode: ESTree.Node | null): void => {
                 if (
                     parentNode
@@ -156,7 +160,7 @@ export class ImportDeclarationTransformer extends AbstractNodeTransformer {
                     && !NodeMetadata.isRenamedIdentifier(node)
                 ) {
                     const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                        .replace(node.name, blockScopeNode);
+                        .replace(node.name, lexicalScopeNode);
                     const newIdentifierName: string = newIdentifier.name;
 
                     if (node.name !== newIdentifierName) {
@@ -169,6 +173,6 @@ export class ImportDeclarationTransformer extends AbstractNodeTransformer {
             }
         });
 
-        this.replaceableIdentifiers.set(blockScopeNode, storedReplaceableIdentifiers);
+        this.replaceableIdentifiers.set(lexicalScopeNode, storedReplaceableIdentifiers);
     }
 }

+ 15 - 11
src/node-transformers/obfuscating-transformers/LabeledStatementTransformer.ts

@@ -5,6 +5,7 @@ import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
 import { TIdentifierObfuscatingReplacerFactory } from '../../types/container/node-transformers/TIdentifierObfuscatingReplacerFactory';
+import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
 
 import { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer';
 import { IOptions } from '../../interfaces/options/IOptions';
@@ -16,8 +17,7 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
 
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeGuards } from '../../node/NodeGuards';
-import { TNodeWithBlockScope } from '../../types/node/TNodeWithBlockScope';
-import { NodeUtils } from '../../node/NodeUtils';
+import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
 
 /**
  * replaces:
@@ -86,38 +86,42 @@ export class LabeledStatementTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (labeledStatementNode: ESTree.LabeledStatement, parentNode: ESTree.Node): ESTree.Node {
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopeOfNode(labeledStatementNode);
+        const lexicalScopeNode: TNodeWithLexicalScope | undefined = NodeLexicalScopeUtils.getLexicalScope(labeledStatementNode);
 
-        this.storeLabeledStatementName(labeledStatementNode, blockScopeNode);
-        this.replaceLabeledStatementName(labeledStatementNode, blockScopeNode);
+        if (!lexicalScopeNode) {
+            return labeledStatementNode;
+        }
+
+        this.storeLabeledStatementName(labeledStatementNode, lexicalScopeNode);
+        this.replaceLabeledStatementName(labeledStatementNode, lexicalScopeNode);
 
         return labeledStatementNode;
     }
 
     /**
      * @param {LabeledStatement} labeledStatementNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
     private storeLabeledStatementName (
         labeledStatementNode: ESTree.LabeledStatement,
-        blockScopeNode: TNodeWithBlockScope
+        lexicalScopeNode: TNodeWithLexicalScope
     ): void {
-        this.identifierObfuscatingReplacer.storeLocalName(labeledStatementNode.label.name, blockScopeNode);
+        this.identifierObfuscatingReplacer.storeLocalName(labeledStatementNode.label.name, lexicalScopeNode);
     }
 
     /**
      * @param {LabeledStatement} labeledStatementNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
     private replaceLabeledStatementName (
         labeledStatementNode: ESTree.LabeledStatement,
-        blockScopeNode: TNodeWithBlockScope
+        lexicalScopeNode: TNodeWithLexicalScope
     ): void {
         estraverse.replace(labeledStatementNode, {
             enter: (node: ESTree.Node, parentNode: ESTree.Node | null): void => {
                 if (parentNode && NodeGuards.isLabelIdentifierNode(node, parentNode)) {
                     const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                        .replace(node.name, blockScopeNode);
+                        .replace(node.name, lexicalScopeNode);
 
                     node.name = newIdentifier.name;
                 }

+ 23 - 18
src/node-transformers/obfuscating-transformers/VariableDeclarationTransformer.ts

@@ -5,7 +5,7 @@ import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
 import { TIdentifierObfuscatingReplacerFactory } from '../../types/container/node-transformers/TIdentifierObfuscatingReplacerFactory';
-import { TNodeWithBlockScope } from '../../types/node/TNodeWithBlockScope';
+import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
 import { TReplaceableIdentifiers } from '../../types/node-transformers/TReplaceableIdentifiers';
 import { TReplaceableIdentifiersNames } from '../../types/node-transformers/TReplaceableIdentifiersNames';
 
@@ -20,8 +20,8 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
 
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeGuards } from '../../node/NodeGuards';
+import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
 import { NodeMetadata } from '../../node/NodeMetadata';
-import { NodeUtils } from '../../node/NodeUtils';
 
 /**
  * replaces:
@@ -93,24 +93,29 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (variableDeclarationNode: ESTree.VariableDeclaration, parentNode: ESTree.Node): ESTree.Node {
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopeOfNode(variableDeclarationNode);
-        const isGlobalDeclaration: boolean = blockScopeNode.type === NodeType.Program;
+        const lexicalScopeNode: TNodeWithLexicalScope | undefined = NodeLexicalScopeUtils.getLexicalScope(variableDeclarationNode);
+
+        if (!lexicalScopeNode) {
+            return variableDeclarationNode;
+        }
+
+        const isGlobalDeclaration: boolean = lexicalScopeNode.type === NodeType.Program;
 
         if (!this.options.renameGlobals && isGlobalDeclaration) {
             return variableDeclarationNode;
         }
 
         const scopeNode: ESTree.Node = variableDeclarationNode.kind === 'var'
-            ? blockScopeNode
+            ? lexicalScopeNode
             : parentNode;
 
-        this.storeVariableNames(variableDeclarationNode, blockScopeNode, isGlobalDeclaration);
+        this.storeVariableNames(variableDeclarationNode, lexicalScopeNode, isGlobalDeclaration);
 
         // check for cached identifiers for current scope node. If exist - loop through them.
         if (this.replaceableIdentifiers.has(scopeNode)) {
-            this.replaceScopeCachedIdentifiers(variableDeclarationNode, blockScopeNode, scopeNode);
+            this.replaceScopeCachedIdentifiers(variableDeclarationNode, lexicalScopeNode, scopeNode);
         } else {
-            this.replaceScopeIdentifiers(scopeNode, blockScopeNode);
+            this.replaceScopeIdentifiers(scopeNode, lexicalScopeNode);
         }
 
         return variableDeclarationNode;
@@ -118,31 +123,31 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {VariableDeclaration} variableDeclarationNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      * @param {boolean} isGlobalDeclaration
      */
     private storeVariableNames (
         variableDeclarationNode: ESTree.VariableDeclaration,
-        blockScopeNode: TNodeWithBlockScope,
+        lexicalScopeNode: TNodeWithLexicalScope,
         isGlobalDeclaration: boolean
     ): void {
         this.traverseDeclarationIdentifiers(variableDeclarationNode, (identifierNode: ESTree.Identifier) => {
             if (isGlobalDeclaration) {
-                this.identifierObfuscatingReplacer.storeGlobalName(identifierNode.name, blockScopeNode);
+                this.identifierObfuscatingReplacer.storeGlobalName(identifierNode.name, lexicalScopeNode);
             } else {
-                this.identifierObfuscatingReplacer.storeLocalName(identifierNode.name, blockScopeNode);
+                this.identifierObfuscatingReplacer.storeLocalName(identifierNode.name, lexicalScopeNode);
             }
         });
     }
 
     /**
      * @param {VariableDeclaration} variableDeclarationNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      * @param {Node} scopeNode
      */
     private replaceScopeCachedIdentifiers (
         variableDeclarationNode: ESTree.VariableDeclaration,
-        blockScopeNode: TNodeWithBlockScope,
+        lexicalScopeNode: TNodeWithLexicalScope,
         scopeNode: ESTree.Node
     ): void {
         const cachedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames =
@@ -172,7 +177,7 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
                 }
 
                 const newReplaceableIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                    .replace(replaceableIdentifier.name, blockScopeNode);
+                    .replace(replaceableIdentifier.name, lexicalScopeNode);
 
                 replaceableIdentifier.name = newReplaceableIdentifier.name;
                 NodeMetadata.set(replaceableIdentifier, { renamedIdentifier: true });
@@ -182,9 +187,9 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {Node} scopeNode
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
-    private replaceScopeIdentifiers (scopeNode: ESTree.Node, blockScopeNode: TNodeWithBlockScope): void {
+    private replaceScopeIdentifiers (scopeNode: ESTree.Node, lexicalScopeNode: TNodeWithLexicalScope): void {
         const storedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames = new Map();
 
         estraverse.replace(scopeNode, {
@@ -195,7 +200,7 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
                     && !NodeMetadata.isRenamedIdentifier(node)
                 ) {
                     const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                        .replace(node.name, blockScopeNode);
+                        .replace(node.name, lexicalScopeNode);
                     const newIdentifierName: string = newIdentifier.name;
 
                     if (node.name !== newIdentifierName) {

+ 3 - 3
src/node-transformers/obfuscating-transformers/obfuscating-replacers/AbstractObfuscatingReplacer.ts

@@ -3,7 +3,7 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 import * as ESTree from 'estree';
 
-import { TNodeWithBlockScope } from '../../../types/node/TNodeWithBlockScope';
+import { TNodeWithLexicalScope } from '../../../types/node/TNodeWithLexicalScope';
 
 import { IObfuscatingReplacer } from '../../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IObfuscatingReplacer';
 import { IOptions } from '../../../interfaces/options/IOptions';
@@ -26,8 +26,8 @@ export abstract class AbstractObfuscatingReplacer implements IObfuscatingReplace
 
     /**
      * @param {SimpleLiteral["value"]} nodeValue
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      * @returns {Node}
      */
-    public abstract replace (nodeValue: ESTree.SimpleLiteral['value'], blockScopeNode?: TNodeWithBlockScope): ESTree.Node;
+    public abstract replace (nodeValue: ESTree.SimpleLiteral['value'], lexicalScopeNode?: TNodeWithLexicalScope): ESTree.Node;
 }

+ 17 - 17
src/node-transformers/obfuscating-transformers/obfuscating-replacers/identifier-obfuscating-replacers/BaseIdentifierObfuscatingReplacer.ts

@@ -4,7 +4,7 @@ import { ServiceIdentifiers } from '../../../../container/ServiceIdentifiers';
 import * as ESTree from 'estree';
 
 import { TIdentifierNamesGeneratorFactory } from '../../../../types/container/generators/TIdentifierNamesGeneratorFactory';
-import { TNodeWithBlockScope } from '../../../../types/node/TNodeWithBlockScope';
+import { TNodeWithLexicalScope } from '../../../../types/node/TNodeWithLexicalScope';
 
 import { IIdentifierNamesGenerator } from '../../../../interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
 import { IIdentifierObfuscatingReplacer } from '../../../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer';
@@ -21,9 +21,9 @@ export class BaseIdentifierObfuscatingReplacer extends AbstractObfuscatingReplac
     private readonly identifierNamesGenerator: IIdentifierNamesGenerator;
 
     /**
-     * @type {Map<TNodeWithBlockScope, Map<string, string>>}
+     * @type {Map<TNodeWithLexicalScope, Map<string, string>>}
      */
-    private readonly blockScopesMap: Map<TNodeWithBlockScope, Map<string, string>> = new Map();
+    private readonly blockScopesMap: Map<TNodeWithLexicalScope, Map<string, string>> = new Map();
 
     /**
      * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
@@ -41,12 +41,12 @@ export class BaseIdentifierObfuscatingReplacer extends AbstractObfuscatingReplac
 
     /**
      * @param {string} nodeValue
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      * @returns {Identifier}
      */
-    public replace (nodeValue: string, blockScopeNode: TNodeWithBlockScope): ESTree.Identifier {
-        if (this.blockScopesMap.has(blockScopeNode)) {
-            const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(blockScopeNode);
+    public replace (nodeValue: string, lexicalScopeNode: TNodeWithLexicalScope): ESTree.Identifier {
+        if (this.blockScopesMap.has(lexicalScopeNode)) {
+            const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(lexicalScopeNode);
 
             if (namesMap.has(nodeValue)) {
                 nodeValue = <string>namesMap.get(nodeValue);
@@ -61,20 +61,20 @@ export class BaseIdentifierObfuscatingReplacer extends AbstractObfuscatingReplac
      * Reserved name will be ignored.
      *
      * @param {string} nodeName
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
-    public storeGlobalName (nodeName: string, blockScopeNode: TNodeWithBlockScope): void {
+    public storeGlobalName (nodeName: string, lexicalScopeNode: TNodeWithLexicalScope): void {
         if (this.isReservedName(nodeName)) {
             return;
         }
 
         const identifierName: string = this.identifierNamesGenerator.generateWithPrefix();
 
-        if (!this.blockScopesMap.has(blockScopeNode)) {
-            this.blockScopesMap.set(blockScopeNode, new Map());
+        if (!this.blockScopesMap.has(lexicalScopeNode)) {
+            this.blockScopesMap.set(lexicalScopeNode, new Map());
         }
 
-        const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(blockScopeNode);
+        const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(lexicalScopeNode);
 
         namesMap.set(nodeName, identifierName);
     }
@@ -84,20 +84,20 @@ export class BaseIdentifierObfuscatingReplacer extends AbstractObfuscatingReplac
      * Reserved name will be ignored.
      *
      * @param {string} nodeName
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
      */
-    public storeLocalName (nodeName: string, blockScopeNode: TNodeWithBlockScope): void {
+    public storeLocalName (nodeName: string, lexicalScopeNode: TNodeWithLexicalScope): void {
         if (this.isReservedName(nodeName)) {
             return;
         }
 
         const identifierName: string = this.identifierNamesGenerator.generate();
 
-        if (!this.blockScopesMap.has(blockScopeNode)) {
-            this.blockScopesMap.set(blockScopeNode, new Map());
+        if (!this.blockScopesMap.has(lexicalScopeNode)) {
+            this.blockScopesMap.set(lexicalScopeNode, new Map());
         }
 
-        const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(blockScopeNode);
+        const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(lexicalScopeNode);
 
         namesMap.set(nodeName, identifierName);
     }

+ 42 - 39
src/node/NodeAppender.ts

@@ -1,22 +1,22 @@
 import * as ESTree from 'estree';
 
-import { TNodeWithBlockScope } from '../types/node/TNodeWithBlockScope';
+import { TNodeWithStatements } from '../types/node/TNodeWithStatements';
 import { TStatement } from '../types/node/TStatement';
 
 import { IStackTraceData } from '../interfaces/analyzers/stack-trace-analyzer/IStackTraceData';
-import { TNodeWithScope } from '../types/node/TNodeWithScope';
+
 import { NodeGuards } from './NodeGuards';
 
 export class NodeAppender {
     /**
-     * @param {TNodeWithScope} scope
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {TStatement[]} statements
      */
-    public static append (scope: TNodeWithScope, statements: TStatement[]): void {
-        statements = NodeAppender.parentizeScopeStatementsBeforeAppend(scope, statements);
+    public static append (nodeWithStatements: TNodeWithStatements, statements: TStatement[]): void {
+        statements = NodeAppender.parentizeScopeStatementsBeforeAppend(nodeWithStatements, statements);
 
-        NodeAppender.setScopeStatements(scope, [
-            ...NodeAppender.getScopeStatements(scope),
+        NodeAppender.setScopeStatements(nodeWithStatements, [
+            ...NodeAppender.getScopeStatements(nodeWithStatements),
             ...statements
         ]);
     }
@@ -39,19 +39,19 @@ export class NodeAppender {
      * Appends node into block statement of `baz` function expression
      *
      * @param {IStackTraceData[]} stackTraceData
-     * @param {TNodeWithBlockScope} blockScopeNode
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {TStatement[]} bodyStatements
      * @param {number} index
      */
     public static appendToOptimalBlockScope (
         stackTraceData: IStackTraceData[],
-        blockScopeNode: TNodeWithBlockScope,
+        nodeWithStatements: TNodeWithStatements,
         bodyStatements: TStatement[],
         index: number = 0
     ): void {
-        const targetBlockScope: TNodeWithBlockScope = stackTraceData.length
+        const targetBlockScope: TNodeWithStatements = stackTraceData.length
             ? NodeAppender.getOptimalBlockScope(stackTraceData, index)
-            : blockScopeNode;
+            : nodeWithStatements;
 
         NodeAppender.prepend(targetBlockScope, bodyStatements);
     }
@@ -83,90 +83,93 @@ export class NodeAppender {
     }
 
     /**
-     * @param {TNodeWithScope} scope
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {TStatement[]} statements
      * @param {Node} target
      */
     public static insertAfter (
-        scope: TNodeWithScope,
+        nodeWithStatements: TNodeWithStatements,
         statements: TStatement[],
         target: ESTree.Statement
     ): void {
         const indexInScopeStatement: number = NodeAppender
-            .getScopeStatements(scope)
+            .getScopeStatements(nodeWithStatements)
             .indexOf(target);
 
-        NodeAppender.insertAtIndex(scope, statements, indexInScopeStatement + 1);
+        NodeAppender.insertAtIndex(nodeWithStatements, statements, indexInScopeStatement + 1);
     }
 
     /**
-     * @param {TNodeWithScope} scope
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {TStatement[]} statements
      * @param {number} index
      */
     public static insertAtIndex (
-        scope: TNodeWithScope,
+        nodeWithStatements: TNodeWithStatements,
         statements: TStatement[],
         index: number
     ): void {
-        statements = NodeAppender.parentizeScopeStatementsBeforeAppend(scope, statements);
+        statements = NodeAppender.parentizeScopeStatementsBeforeAppend(nodeWithStatements, statements);
 
-        NodeAppender.setScopeStatements(scope, [
-            ...NodeAppender.getScopeStatements(scope).slice(0, index),
+        NodeAppender.setScopeStatements(nodeWithStatements, [
+            ...NodeAppender.getScopeStatements(nodeWithStatements).slice(0, index),
             ...statements,
-            ...NodeAppender.getScopeStatements(scope).slice(index)
+            ...NodeAppender.getScopeStatements(nodeWithStatements).slice(index)
         ]);
     }
 
     /**
-     * @param {TNodeWithScope} scope
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {TStatement[]} statements
      */
-    public static prepend (scope: TNodeWithScope, statements: TStatement[]): void {
-        statements = NodeAppender.parentizeScopeStatementsBeforeAppend(scope, statements);
+    public static prepend (nodeWithStatements: TNodeWithStatements, statements: TStatement[]): void {
+        statements = NodeAppender.parentizeScopeStatementsBeforeAppend(nodeWithStatements, statements);
 
-        NodeAppender.setScopeStatements(scope, [
+        NodeAppender.setScopeStatements(nodeWithStatements, [
             ...statements,
-            ...NodeAppender.getScopeStatements(scope),
+            ...NodeAppender.getScopeStatements(nodeWithStatements),
         ]);
     }
 
     /**
-     * @param {TNodeWithScope} scope
+     * @param {TNodeWithStatements} nodeWithStatements
      * @returns {TStatement[]}
      */
-    private static getScopeStatements (scope: TNodeWithScope): TStatement[] {
-        if (NodeGuards.isSwitchCaseNode(scope)) {
-            return scope.consequent;
+    private static getScopeStatements (nodeWithStatements: TNodeWithStatements): TStatement[] {
+        if (NodeGuards.isSwitchCaseNode(nodeWithStatements)) {
+            return nodeWithStatements.consequent;
         }
 
-        return scope.body;
+        return nodeWithStatements.body;
     }
 
     /**
-     * @param {TNodeWithScope} scope
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {TStatement[]} statements
      * @returns {TStatement[]}
      */
-    private static parentizeScopeStatementsBeforeAppend (scope: TNodeWithScope, statements: TStatement[]): TStatement[] {
+    private static parentizeScopeStatementsBeforeAppend (
+        nodeWithStatements: TNodeWithStatements,
+        statements: TStatement[]
+    ): TStatement[] {
         statements.forEach((statement: TStatement) => {
-            statement.parentNode = scope;
+            statement.parentNode = nodeWithStatements;
         });
 
         return statements;
     }
 
     /**
-     * @param {TNodeWithScope} scope
+     * @param {TNodeWithStatements} nodeWithStatements
      * @param {TStatement[]} statements
      */
-    private static setScopeStatements (scope: TNodeWithScope, statements: TStatement[]): void {
-        if (NodeGuards.isSwitchCaseNode(scope)) {
-            scope.consequent = <ESTree.Statement[]>statements;
+    private static setScopeStatements (nodeWithStatements: TNodeWithStatements, statements: TStatement[]): void {
+        if (NodeGuards.isSwitchCaseNode(nodeWithStatements)) {
+            nodeWithStatements.consequent = <ESTree.Statement[]>statements;
 
             return;
         }
 
-        scope.body = statements;
+        nodeWithStatements.body = statements;
     }
 }

+ 17 - 14
src/node/NodeGuards.ts

@@ -1,7 +1,7 @@
 import * as ESTree from 'estree';
 
-import { TNodeWithBlockScope } from '../types/node/TNodeWithBlockScope';
-import { TNodeWithScope } from '../types/node/TNodeWithScope';
+import { TNodeWithLexicalScope } from '../types/node/TNodeWithLexicalScope';
+import { TNodeWithStatements } from '../types/node/TNodeWithStatements';
 
 import { NodeType } from '../enums/node/NodeType';
 
@@ -9,7 +9,7 @@ export class NodeGuards {
     /**
      * @type {string[]}
      */
-    private static readonly nodesWithBlockScope: string[] = [
+    private static readonly nodesWithLexicalStatements: string[] = [
         NodeType.ArrowFunctionExpression,
         NodeType.FunctionDeclaration,
         NodeType.FunctionExpression,
@@ -247,30 +247,33 @@ export class NodeGuards {
         return object && !object.type !== undefined;
     }
 
+    /**
+     * @param {Node} node
+     * @returns {boolean}
+     */
+    public static isNodeWithLexicalScope (node: ESTree.Node): node is TNodeWithLexicalScope {
+        return NodeGuards.isProgramNode(node) || NodeGuards.isFunctionNode(node);
+    }
+
     /**
      * @param {Node} node
      * @param {Node} parentNode
      * @returns {boolean}
      */
-    public static isNodeHasBlockScope (node: ESTree.Node, parentNode: ESTree.Node): node is TNodeWithBlockScope {
+    public static isNodeWithLexicalScopeStatements (
+        node: ESTree.Node,
+        parentNode: ESTree.Node
+    ): node is TNodeWithStatements {
         return NodeGuards.isProgramNode(node)
-            /**
-             * Should correctly check arrow functions with expression body
-             */
-            || (NodeGuards.isArrowFunctionExpressionNode(node) && !NodeGuards.isBlockStatementNode(node.body))
-            || (NodeGuards.isBlockStatementNode(node) && NodeGuards.nodesWithBlockScope.includes(parentNode.type));
+            || (NodeGuards.isBlockStatementNode(node) && NodeGuards.nodesWithLexicalStatements.includes(parentNode.type));
     }
 
     /**
      * @param {Node} node
      * @returns {boolean}
      */
-    public static isNodeHasScope (node: ESTree.Node): node is TNodeWithScope {
+    public static isNodeWithStatements (node: ESTree.Node): node is TNodeWithStatements {
         return NodeGuards.isProgramNode(node)
-            /**
-             * Should correctly check arrow functions with expression body
-             */
-            || (NodeGuards.isArrowFunctionExpressionNode(node) && !NodeGuards.isBlockStatementNode(node.body))
             || NodeGuards.isBlockStatementNode(node)
             || NodeGuards.isSwitchCaseNode(node);
     }

+ 57 - 0
src/node/NodeLexicalScopeUtils.ts

@@ -0,0 +1,57 @@
+import * as ESTree from 'estree';
+
+import { TNodeWithLexicalScope } from '../types/node/TNodeWithLexicalScope';
+
+import { NodeGuards } from './NodeGuards';
+
+export class NodeLexicalScopeUtils {
+    /**
+     * @param {Node} node
+     * @returns {TNodeWithLexicalScope}
+     */
+    public static getLexicalScope (node: ESTree.Node): TNodeWithLexicalScope | undefined {
+        return NodeLexicalScopeUtils.getLexicalScopesRecursive(node, 1)[0];
+    }
+
+    /**
+     * @param {Node} node
+     * @returns {TNodeWithLexicalScope[]}
+     */
+    public static getLexicalScopes (node: ESTree.Node): TNodeWithLexicalScope[] {
+        return NodeLexicalScopeUtils.getLexicalScopesRecursive(node);
+    }
+
+    /***
+     * @param {Node} node
+     * @param {number} maxSize
+     * @param {TNodeWithLexicalScope[]} nodesWithLexicalScope
+     * @param {number} depth
+     * @returns {TNodeWithLexicalScope[]}
+     */
+    private static getLexicalScopesRecursive (
+        node: ESTree.Node,
+        maxSize: number = Infinity,
+        nodesWithLexicalScope: TNodeWithLexicalScope[] = [],
+        depth: number = 0
+    ): TNodeWithLexicalScope[] {
+        if (nodesWithLexicalScope.length >= maxSize) {
+            return nodesWithLexicalScope;
+        }
+
+        const parentNode: ESTree.Node | undefined = node.parentNode;
+
+        if (!parentNode) {
+            throw new ReferenceError('`parentNode` property of given node is `undefined`');
+        }
+
+        if (NodeGuards.isNodeWithLexicalScope(node)) {
+            nodesWithLexicalScope.push(node);
+        }
+
+        if (node !== parentNode) {
+            return NodeLexicalScopeUtils.getLexicalScopesRecursive(parentNode, maxSize, nodesWithLexicalScope, ++depth);
+        }
+
+        return nodesWithLexicalScope;
+    }
+}

+ 135 - 0
src/node/NodeStatementUtils.ts

@@ -0,0 +1,135 @@
+import * as ESTree from 'estree';
+
+import { TNodeWithStatements } from '../types/node/TNodeWithStatements';
+import { TStatement } from '../types/node/TStatement';
+
+import { NodeGuards } from './NodeGuards';
+
+export class NodeStatementUtils {
+    /**
+     * @param {Node} node
+     * @returns {TNodeWithStatements}
+     */
+    public static getParentNodeWithStatements (node: ESTree.Node): TNodeWithStatements {
+        return NodeStatementUtils.getParentNodesWithStatementsRecursive(node, 1)[0];
+    }
+
+    /**
+     * @param {Node} node
+     * @returns {TNodeWithStatements[]}
+     */
+    public static getParentNodesWithStatements (node: ESTree.Node): TNodeWithStatements[] {
+        return NodeStatementUtils.getParentNodesWithStatementsRecursive(node);
+    }
+
+    /**
+     * @param {Statement} statement
+     * @returns {TStatement | null}
+     */
+    public static getNextSiblingStatement (statement: ESTree.Statement): TStatement | null {
+        return NodeStatementUtils.getSiblingStatementByOffset(statement, 1);
+    }
+
+    /**
+     * @param {Statement} statement
+     * @returns {TStatement | null}
+     */
+    public static getPreviousSiblingStatement (statement: ESTree.Statement): TStatement | null {
+        return NodeStatementUtils.getSiblingStatementByOffset(statement, -1);
+    }
+
+    /**
+     * @param {Node} node
+     * @returns {Statement}
+     */
+    public static getRootStatementOfNode (node: ESTree.Node): ESTree.Statement {
+        if (NodeGuards.isProgramNode(node)) {
+            throw new Error('Unable to find root statement for `Program` node');
+        }
+
+        const parentNode: ESTree.Node | undefined = node.parentNode;
+
+        if (!parentNode) {
+            throw new ReferenceError('`parentNode` property of given node is `undefined`');
+        }
+
+        if (!NodeGuards.isNodeWithStatements(parentNode)) {
+            return NodeStatementUtils.getRootStatementOfNode(parentNode);
+        }
+
+        return <ESTree.Statement>node;
+    }
+
+    /**
+     * @param {NodeGuards} node
+     * @returns {TNodeWithStatements}
+     */
+    public static getScopeOfNode (node: ESTree.Node): TNodeWithStatements {
+        const parentNode: ESTree.Node | undefined = node.parentNode;
+
+        if (!parentNode) {
+            throw new ReferenceError('`parentNode` property of given node is `undefined`');
+        }
+
+        if (!NodeGuards.isNodeWithStatements(parentNode)) {
+            return NodeStatementUtils.getScopeOfNode(parentNode);
+        }
+
+        return parentNode;
+    }
+
+    /***
+     * @param {Node} node
+     * @param {number} maxSize
+     * @param {TNodeWithStatements[]} nodesWithStatements
+     * @param {number} depth
+     * @returns {TNodeWithStatements[]}
+     */
+    private static getParentNodesWithStatementsRecursive (
+        node: ESTree.Node,
+        maxSize: number = Infinity,
+        nodesWithStatements: TNodeWithStatements[] = [],
+        depth: number = 0
+    ): TNodeWithStatements[] {
+        if (nodesWithStatements.length >= maxSize) {
+            return nodesWithStatements;
+        }
+
+        const parentNode: ESTree.Node | undefined = node.parentNode;
+
+        if (!parentNode) {
+            throw new ReferenceError('`parentNode` property of given node is `undefined`');
+        }
+
+        if (
+            /**
+             * we can add program node instantly
+             */
+            NodeGuards.isProgramNode(node) ||
+            (NodeGuards.isNodeWithLexicalScopeStatements(node, parentNode) && depth > 0)
+        ) {
+            nodesWithStatements.push(node);
+        }
+
+        if (node !== parentNode) {
+            return NodeStatementUtils.getParentNodesWithStatementsRecursive(parentNode, maxSize, nodesWithStatements, ++depth);
+        }
+
+        return nodesWithStatements;
+    }
+
+    /**
+     * @param {Statement} statement
+     * @param {number} offset
+     * @returns {TStatement | null}
+     */
+    private static getSiblingStatementByOffset (statement: ESTree.Statement, offset: number): TStatement | null {
+        const scopeNode: TNodeWithStatements = NodeStatementUtils.getScopeOfNode(statement);
+        const scopeBody: TStatement[] = !NodeGuards.isSwitchCaseNode(scopeNode)
+            ? scopeNode.body
+            : scopeNode.consequent;
+        const indexInScope: number = scopeBody.indexOf(statement);
+
+        return scopeBody[indexInScope + offset] || null;
+    }
+}

+ 0 - 144
src/node/NodeUtils.ts

@@ -3,10 +3,7 @@ import * as espree from 'espree';
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
-import { TNodeWithBlockScope } from '../types/node/TNodeWithBlockScope';
-import { TNodeWithScope } from '../types/node/TNodeWithScope';
 import { TObject } from '../types/TObject';
-import { TStatement } from '../types/node/TStatement';
 
 import { NodeGuards } from './NodeGuards';
 import { NodeMetadata } from './NodeMetadata';
@@ -69,78 +66,6 @@ export class NodeUtils {
         }, '');
     }
 
-    /**
-     * @param {Node} node
-     * @returns {TNodeWithBlockScope}
-     */
-    public static getBlockScopeOfNode (node: ESTree.Node): TNodeWithBlockScope {
-        return NodeUtils.getBlockScopesOfNodeRecursive(node, 1)[0];
-    }
-
-    /**
-     * @param {Node} node
-     * @returns {TNodeWithBlockScope[]}
-     */
-    public static getBlockScopesOfNode (node: ESTree.Node): TNodeWithBlockScope[] {
-        return NodeUtils.getBlockScopesOfNodeRecursive(node);
-    }
-
-    /**
-     * @param {Statement} statement
-     * @returns {TStatement | null}
-     */
-    public static getNextSiblingStatement (statement: ESTree.Statement): TStatement | null {
-        return NodeUtils.getSiblingStatementByOffset(statement, 1);
-    }
-
-    /**
-     * @param {Statement} statement
-     * @returns {TStatement | null}
-     */
-    public static getPreviousSiblingStatement (statement: ESTree.Statement): TStatement | null {
-        return NodeUtils.getSiblingStatementByOffset(statement, -1);
-    }
-
-    /**
-     * @param {Node} node
-     * @returns {Statement}
-     */
-    public static getRootStatementOfNode (node: ESTree.Node): ESTree.Statement {
-        if (NodeGuards.isProgramNode(node)) {
-            throw new Error('Unable to find root statement for `Program` node');
-        }
-
-        const parentNode: ESTree.Node | undefined = node.parentNode;
-
-        if (!parentNode) {
-            throw new ReferenceError('`parentNode` property of given node is `undefined`');
-        }
-
-        if (!NodeGuards.isNodeHasScope(parentNode)) {
-            return NodeUtils.getRootStatementOfNode(parentNode);
-        }
-
-        return <ESTree.Statement>node;
-    }
-
-    /**
-     * @param {NodeGuards} node
-     * @returns {TNodeWithScope}
-     */
-    public static getScopeOfNode (node: ESTree.Node): TNodeWithScope {
-        const parentNode: ESTree.Node | undefined = node.parentNode;
-
-        if (!parentNode) {
-            throw new ReferenceError('`parentNode` property of given node is `undefined`');
-        }
-
-        if (!NodeGuards.isNodeHasScope(parentNode)) {
-            return NodeUtils.getScopeOfNode(parentNode);
-        }
-
-        return parentNode;
-    }
-
     /**
      * @param {UnaryExpression} unaryExpressionNode
      * @returns {NodeGuards}
@@ -213,73 +138,4 @@ export class NodeUtils {
 
         return <T>copy;
     }
-
-    /***
-     * @param {Node} node
-     * @param {number} maxSize
-     * @param {TNodeWithBlockScope[]} blockScopes
-     * @param {number} depth
-     * @returns {TNodeWithBlockScope[]}
-     */
-    private static getBlockScopesOfNodeRecursive (
-        node: ESTree.Node,
-        maxSize: number = Infinity,
-        blockScopes: TNodeWithBlockScope[] = [],
-        depth: number = 0
-    ): TNodeWithBlockScope[] {
-        if (blockScopes.length >= maxSize) {
-            return blockScopes;
-        }
-
-        const parentNode: ESTree.Node | undefined = node.parentNode;
-
-        if (!parentNode) {
-            throw new ReferenceError('`parentNode` property of given node is `undefined`');
-        }
-
-        /**
-         * Stage 1: process root block statement node of the slice of AST-tree
-         */
-        if (NodeGuards.isBlockStatementNode(node) && parentNode === node) {
-            blockScopes.push(node);
-        }
-
-        /**
-         * Stage 2: process any other nodes
-         */
-        if (
-            /**
-             * we can add program node instantly
-             */
-            NodeGuards.isProgramNode(node) ||
-            /**
-             * we shouldn't add to the array input node that is node with block scope itself
-             * so, on depth 0 we will skip push to the array of block scopes
-             */
-            (depth && NodeGuards.isNodeHasBlockScope(node, parentNode))
-        ) {
-            blockScopes.push(node);
-        }
-
-        if (node !== parentNode) {
-            return NodeUtils.getBlockScopesOfNodeRecursive(parentNode, maxSize, blockScopes, ++depth);
-        }
-
-        return blockScopes;
-    }
-
-    /**
-     * @param {Statement} statement
-     * @param {number} offset
-     * @returns {TStatement | null}
-     */
-    private static getSiblingStatementByOffset (statement: ESTree.Statement, offset: number): TStatement | null {
-        const scopeNode: TNodeWithScope = NodeUtils.getScopeOfNode(statement);
-        const scopeBody: TStatement[] = !NodeGuards.isSwitchCaseNode(scopeNode)
-            ? scopeNode.body
-            : scopeNode.consequent;
-        const indexInScope: number = scopeBody.indexOf(statement);
-
-        return scopeBody[indexInScope + offset] || null;
-    }
 }

+ 0 - 3
src/types/node/TNodeWithBlockScope.d.ts

@@ -1,3 +0,0 @@
-import * as ESTree from 'estree';
-
-export type TNodeWithBlockScope = ESTree.Program | ESTree.BlockStatement;

+ 3 - 0
src/types/node/TNodeWithLexicalScope.d.ts

@@ -0,0 +1,3 @@
+import * as ESTree from 'estree';
+
+export type TNodeWithLexicalScope = ESTree.Program | ESTree.Function;

+ 0 - 3
src/types/node/TNodeWithScope.d.ts

@@ -1,3 +0,0 @@
-import * as ESTree from 'estree';
-
-export type TNodeWithScope = ESTree.Program | ESTree.BlockStatement | ESTree.SwitchCase;

+ 3 - 0
src/types/node/TNodeWithStatements.d.ts

@@ -0,0 +1,3 @@
+import * as ESTree from 'estree';
+
+export type TNodeWithStatements = ESTree.Program | ESTree.BlockStatement | ESTree.SwitchCase;

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

@@ -7,7 +7,7 @@ import * as ESTree from 'estree';
 
 import { assert } from 'chai';
 
-import { TNodeWithBlockScope } from '../../../../src/types/node/TNodeWithBlockScope';
+import { TNodeWithStatements } from '../../../../src/types/node/TNodeWithStatements';
 
 import { IInversifyContainerFacade } from '../../../../src/interfaces/container/IInversifyContainerFacade';
 import { IStackTraceAnalyzer } from '../../../../src/interfaces/analyzers/stack-trace-analyzer/IStackTraceAnalyzer';
@@ -165,7 +165,7 @@ describe('StackTraceAnalyzer', () => {
         describe('Variant #1: basic-1', () => {
             before(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/basic-1.js');
-                const astTree: TNodeWithBlockScope = NodeFactory.programNode(
+                const astTree: TNodeWithStatements = NodeFactory.programNode(
                     NodeUtils.convertCodeToStructure(code)
                 );
 
@@ -215,7 +215,7 @@ describe('StackTraceAnalyzer', () => {
         describe('Variant #2: basic-2', () => {
             before(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/basic-2.js');
-                const astTree: TNodeWithBlockScope = NodeFactory.programNode(
+                const astTree: TNodeWithStatements = NodeFactory.programNode(
                     NodeUtils.convertCodeToStructure(code)
                 );
 
@@ -254,7 +254,7 @@ describe('StackTraceAnalyzer', () => {
         describe('Variant #3: deep conditions nesting', () => {
             before(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/deep-conditions-nesting.js');
-                const astTree: TNodeWithBlockScope = NodeFactory.programNode(
+                const astTree: TNodeWithStatements = NodeFactory.programNode(
                     NodeUtils.convertCodeToStructure(code)
                 );
 
@@ -293,7 +293,7 @@ describe('StackTraceAnalyzer', () => {
         describe('Variant #4: call before declaration', () => {
             before(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/call-before-declaration.js');
-                const astTree: TNodeWithBlockScope = NodeFactory.programNode(
+                const astTree: TNodeWithStatements = NodeFactory.programNode(
                     NodeUtils.convertCodeToStructure(code)
                 );
 
@@ -316,7 +316,7 @@ describe('StackTraceAnalyzer', () => {
         describe('Variant #5: call expression of object member #1', () => {
             before(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/call-expression-of-object-member-1.js');
-                const astTree: TNodeWithBlockScope = NodeFactory.programNode(
+                const astTree: TNodeWithStatements = NodeFactory.programNode(
                     NodeUtils.convertCodeToStructure(code)
                 );
 
@@ -375,7 +375,7 @@ describe('StackTraceAnalyzer', () => {
         describe('Variant #5: call expression of object member #2', () => {
             before(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/call-expression-of-object-member-2.js');
-                const astTree: TNodeWithBlockScope = NodeFactory.programNode(
+                const astTree: TNodeWithStatements = NodeFactory.programNode(
                     NodeUtils.convertCodeToStructure(code)
                 );
 
@@ -403,7 +403,7 @@ describe('StackTraceAnalyzer', () => {
         describe('Variant #6: no call expressions', () => {
             before(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/no-call-expressions.js');
-                const astTree: TNodeWithBlockScope = NodeFactory.programNode(
+                const astTree: TNodeWithStatements = NodeFactory.programNode(
                     NodeUtils.convertCodeToStructure(code)
                 );
 
@@ -420,7 +420,7 @@ describe('StackTraceAnalyzer', () => {
         describe('Variant #7: only call expression', () => {
             before(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/only-call-expression.js');
-                const astTree: TNodeWithBlockScope = NodeFactory.programNode(
+                const astTree: TNodeWithStatements = NodeFactory.programNode(
                     NodeUtils.convertCodeToStructure(code)
                 );
 
@@ -437,7 +437,7 @@ describe('StackTraceAnalyzer', () => {
         describe('Variant #8: self-invoking functions', () => {
             before(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/self-invoking-functions.js');
-                const astTree: TNodeWithBlockScope = NodeFactory.programNode(
+                const astTree: TNodeWithStatements = NodeFactory.programNode(
                     NodeUtils.convertCodeToStructure(code)
                 );
 
@@ -472,7 +472,7 @@ describe('StackTraceAnalyzer', () => {
         describe('Variant #9: no recursion', () => {
             before(() => {
                 const code: string = readFileAsString(__dirname + '/fixtures/no-recursion.js');
-                const astTree: TNodeWithBlockScope = NodeFactory.programNode(
+                const astTree: TNodeWithStatements = NodeFactory.programNode(
                     NodeUtils.convertCodeToStructure(code)
                 );
 

+ 1 - 1
test/functional-tests/node-transformers/obfuscating-transformers/function-transformer/FunctionTransformer.spec.ts

@@ -465,7 +465,7 @@ describe('FunctionTransformer', () => {
             });
         });
 
-        describe('Variant #1: expression statement body', () => {
+        describe('Variant #2: expression statement body', () => {
             const regExpMatch: string = `` +
                 `\\[]` +
                 `\\['map']\\(_0x[a-f0-9]{4,6} *=> *0x1\\)` +

+ 2 - 0
test/index.spec.ts

@@ -23,6 +23,8 @@ import './unit-tests/logger/Logger.spec';
 import './unit-tests/node/node-appender/NodeAppender.spec';
 import './unit-tests/node/node-guards/NodeGuards.spec';
 import './unit-tests/node/node-metadata/NodeMetadata.spec';
+import './unit-tests/node/node-lexical-scope-utils/NodeLexicalScopeUtils.spec';
+import './unit-tests/node/node-statement-utils/NodeStatementUtils.spec';
 import './unit-tests/node/node-utils/NodeUtils.spec';
 import './unit-tests/node-transformers/preparing-transformers/ObfuscatingGuardsTransformer.spec';
 import './unit-tests/obfuscation-result/ObfuscationResult.spec';

+ 26 - 26
test/unit-tests/node/node-guards/NodeGuards.spec.ts

@@ -7,7 +7,7 @@ import { NodeFactory } from '../../../../src/node/NodeFactory';
 import { NodeUtils } from '../../../../src/node/NodeUtils';
 
 describe('NodeGuards', () => {
-    describe('isNodeHasBlockScope', () => {
+    describe('isNodeWithLexicalScopeStatements', () => {
         describe('truthful checks', () => {
             describe('Variant #1: block statement of function declaration', () => {
                 const expectedResult: boolean = true;
@@ -22,10 +22,10 @@ describe('NodeGuards', () => {
 
                 before(() => {
                     NodeUtils.parentizeAst(parentNode);
-                    result = NodeGuards.isNodeHasBlockScope(node, parentNode);
+                    result = NodeGuards.isNodeWithLexicalScopeStatements(node, parentNode);
                 });
 
-                it('should check if node has block scope', () => {
+                it('should check if node has statements', () => {
                     assert.equal(result, expectedResult);
                 });
             });
@@ -42,10 +42,10 @@ describe('NodeGuards', () => {
 
                 before(() => {
                     NodeUtils.parentizeAst(parentNode);
-                    result = NodeGuards.isNodeHasBlockScope(node, parentNode);
+                    result = NodeGuards.isNodeWithLexicalScopeStatements(node, parentNode);
                 });
 
-                it('should check if node has block scope', () => {
+                it('should check if node has statements', () => {
                     assert.equal(result, expectedResult);
                 });
             });
@@ -80,10 +80,10 @@ describe('NodeGuards', () => {
 
                 before(() => {
                     NodeUtils.parentizeAst(parentNode);
-                    result = NodeGuards.isNodeHasBlockScope(node, parentNode);
+                    result = NodeGuards.isNodeWithLexicalScopeStatements(node, parentNode);
                 });
 
-                it('should check if node has block scope', () => {
+                it('should check if node has statements', () => {
                     assert.equal(result, expectedResult);
                 });
             });
@@ -108,10 +108,10 @@ describe('NodeGuards', () => {
 
                 before(() => {
                     NodeUtils.parentizeAst(parentNode);
-                    result = NodeGuards.isNodeHasBlockScope(node, parentNode);
+                    result = NodeGuards.isNodeWithLexicalScopeStatements(node, parentNode);
                 });
 
-                it('should check if node has block scope', () => {
+                it('should check if node has statements', () => {
                     assert.equal(result, expectedResult);
                 });
             });
@@ -128,17 +128,17 @@ describe('NodeGuards', () => {
 
                 before(() => {
                     NodeUtils.parentizeAst(parentNode);
-                    result = NodeGuards.isNodeHasBlockScope(node, parentNode);
+                    result = NodeGuards.isNodeWithLexicalScopeStatements(node, parentNode);
                 });
 
-                it('should check if node has block scope', () => {
+                it('should check if node has statements', () => {
                     assert.equal(result, expectedResult);
                 });
             });
         });
     });
 
-    describe('isNodeHasScope', () => {
+    describe('isNodeWithStatements', () => {
         describe('truthful checks', () => {
             describe('Variant #1: program node', () => {
                 const expectedResult: boolean = true;
@@ -147,10 +147,10 @@ describe('NodeGuards', () => {
                 let result: boolean;
 
                 before(() => {
-                    result = NodeGuards.isNodeHasScope(node);
+                    result = NodeGuards.isNodeWithStatements(node);
                 });
 
-                it('should check if node has scope', () => {
+                it('should check if node has statements', () => {
                     assert.equal(result, expectedResult);
                 });
             });
@@ -162,10 +162,10 @@ describe('NodeGuards', () => {
                 let result: boolean;
 
                 before(() => {
-                    result = NodeGuards.isNodeHasScope(node);
+                    result = NodeGuards.isNodeWithStatements(node);
                 });
 
-                it('should check if node has scope', () => {
+                it('should check if node has statements', () => {
                     assert.equal(result, expectedResult);
                 });
             });
@@ -180,10 +180,10 @@ describe('NodeGuards', () => {
                 let result: boolean;
 
                 before(() => {
-                    result = NodeGuards.isNodeHasScope(node);
+                    result = NodeGuards.isNodeWithStatements(node);
                 });
 
-                it('should check if node has scope', () => {
+                it('should check if node has statements', () => {
                     assert.equal(result, expectedResult);
                 });
             });
@@ -197,10 +197,10 @@ describe('NodeGuards', () => {
                 let result: boolean;
 
                 before(() => {
-                    result = NodeGuards.isNodeHasScope(node);
+                    result = NodeGuards.isNodeWithStatements(node);
                 });
 
-                it('should check if node has scope', () => {
+                it('should check if node has statements', () => {
                     assert.equal(result, expectedResult);
                 });
             });
@@ -212,10 +212,10 @@ describe('NodeGuards', () => {
                 let result: boolean;
 
                 before(() => {
-                    result = NodeGuards.isNodeHasScope(node);
+                    result = NodeGuards.isNodeWithStatements(node);
                 });
 
-                it('should check if node has scope', () => {
+                it('should check if node has statements', () => {
                     assert.equal(result, expectedResult);
                 });
             });
@@ -230,10 +230,10 @@ describe('NodeGuards', () => {
                 let result: boolean;
 
                 before(() => {
-                    result = NodeGuards.isNodeHasScope(node);
+                    result = NodeGuards.isNodeWithStatements(node);
                 });
 
-                it('should check if node has scope', () => {
+                it('should check if node has statements', () => {
                     assert.equal(result, expectedResult);
                 });
             });
@@ -248,10 +248,10 @@ describe('NodeGuards', () => {
                 let result: boolean;
 
                 before(() => {
-                    result = NodeGuards.isNodeHasScope(node);
+                    result = NodeGuards.isNodeWithStatements(node);
                 });
 
-                it('should check if node has scope', () => {
+                it('should check if node has statements', () => {
                     assert.equal(result, expectedResult);
                 });
             });

+ 222 - 0
test/unit-tests/node/node-lexical-scope-utils/NodeLexicalScopeUtils.spec.ts

@@ -0,0 +1,222 @@
+import * as ESTree from 'estree';
+
+import { assert } from 'chai';
+
+import { NodeFactory } from '../../../../src/node/NodeFactory';
+import { NodeLexicalScopeUtils } from '../../../../src/node/NodeLexicalScopeUtils';
+
+describe('NodeLexicalScopeUtils', () => {
+    describe('getParentScope', () => {
+        let functionDeclarationBlockStatementNode: ESTree.BlockStatement,
+            ifStatementBlockStatementNode1: ESTree.BlockStatement,
+            ifStatementBlockStatementNode2: ESTree.BlockStatement,
+            ifStatementNode1: ESTree.IfStatement,
+            ifStatementNode2: ESTree.IfStatement,
+            expressionStatementNode3: ESTree.ExpressionStatement,
+            expressionStatementNode2: ESTree.ExpressionStatement,
+            expressionStatementNode1: ESTree.ExpressionStatement,
+            functionDeclarationNode: ESTree.FunctionDeclaration,
+            programNode: ESTree.Program;
+
+        before(() => {
+            expressionStatementNode1 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+            expressionStatementNode2 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+            expressionStatementNode3 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+
+            ifStatementBlockStatementNode2 = NodeFactory.blockStatementNode([
+                expressionStatementNode2,
+                expressionStatementNode3
+            ]);
+
+            ifStatementNode2 = NodeFactory.ifStatementNode(
+                NodeFactory.literalNode(true),
+                ifStatementBlockStatementNode2
+            );
+
+            ifStatementBlockStatementNode1 = NodeFactory.blockStatementNode([
+                ifStatementNode2
+            ]);
+
+            ifStatementNode1 = NodeFactory.ifStatementNode(
+                NodeFactory.literalNode(true),
+                ifStatementBlockStatementNode1
+            );
+
+            functionDeclarationBlockStatementNode = NodeFactory.blockStatementNode([
+                expressionStatementNode1,
+                ifStatementNode1
+            ]);
+
+            functionDeclarationNode = NodeFactory.functionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
+
+            programNode = NodeFactory.programNode([
+                functionDeclarationNode
+            ]);
+
+            programNode.parentNode = programNode;
+            functionDeclarationNode.parentNode = programNode;
+            functionDeclarationBlockStatementNode.parentNode = functionDeclarationNode;
+            expressionStatementNode1.parentNode = functionDeclarationBlockStatementNode;
+            ifStatementNode1.parentNode = functionDeclarationBlockStatementNode;
+            ifStatementBlockStatementNode1.parentNode = ifStatementNode1;
+            ifStatementNode2.parentNode = ifStatementBlockStatementNode1;
+            ifStatementBlockStatementNode2.parentNode = ifStatementNode2;
+            expressionStatementNode3.parentNode = ifStatementBlockStatementNode2;
+        });
+
+        it('should return lexical scope node for `program` node child node', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScope(programNode), programNode);
+        });
+
+        it('should return lexical scope node for `functionDeclaration` node child node', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScope(functionDeclarationNode), functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `functionDeclaration blockStatement` node child node', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScope(functionDeclarationBlockStatementNode), functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `expressionStatement` node #1 child node', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScope(expressionStatementNode1), functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `ifStatement` node child node', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScope(ifStatementNode1), functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `ifStatement blockStatement` node #1 child node', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScope(ifStatementBlockStatementNode1), functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `ifStatement blockStatement` node #2 child node', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScope(ifStatementBlockStatementNode2), functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `expressionStatement` node #3 child node', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScope(expressionStatementNode3), functionDeclarationNode);
+        });
+
+        it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
+            assert.throws(() => NodeLexicalScopeUtils.getLexicalScope(expressionStatementNode2), ReferenceError);
+        });
+    });
+
+    describe('getParentScopes', () => {
+        let functionDeclarationBlockStatementNode: ESTree.BlockStatement,
+            ifStatementBlockStatementNode1: ESTree.BlockStatement,
+            ifStatementBlockStatementNode2: ESTree.BlockStatement,
+            ifStatementNode1: ESTree.IfStatement,
+            ifStatementNode2: ESTree.IfStatement,
+            expressionStatementNode3: ESTree.ExpressionStatement,
+            expressionStatementNode2: ESTree.ExpressionStatement,
+            expressionStatementNode1: ESTree.ExpressionStatement,
+            functionDeclarationNode: ESTree.FunctionDeclaration,
+            programNode: ESTree.Program;
+
+        before(() => {
+            expressionStatementNode1 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+            expressionStatementNode2 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+            expressionStatementNode3 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+
+            ifStatementBlockStatementNode2 = NodeFactory.blockStatementNode([
+                expressionStatementNode2,
+                expressionStatementNode3
+            ]);
+
+            ifStatementNode2 = NodeFactory.ifStatementNode(
+                NodeFactory.literalNode(true),
+                ifStatementBlockStatementNode2
+            );
+
+            ifStatementBlockStatementNode1 = NodeFactory.blockStatementNode([
+                ifStatementNode2
+            ]);
+
+            ifStatementNode1 = NodeFactory.ifStatementNode(
+                NodeFactory.literalNode(true),
+                ifStatementBlockStatementNode1
+            );
+
+            functionDeclarationBlockStatementNode = NodeFactory.blockStatementNode([
+                expressionStatementNode1,
+                ifStatementNode1
+            ]);
+
+            functionDeclarationNode = NodeFactory.functionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
+
+            programNode = NodeFactory.programNode([
+                functionDeclarationNode
+            ]);
+
+            programNode.parentNode = programNode;
+            functionDeclarationNode.parentNode = programNode;
+            functionDeclarationBlockStatementNode.parentNode = functionDeclarationNode;
+            expressionStatementNode1.parentNode = functionDeclarationBlockStatementNode;
+            ifStatementNode1.parentNode = functionDeclarationBlockStatementNode;
+            ifStatementBlockStatementNode1.parentNode = ifStatementNode1;
+            ifStatementNode2.parentNode = ifStatementBlockStatementNode1;
+            ifStatementBlockStatementNode2.parentNode = ifStatementNode2;
+            expressionStatementNode3.parentNode = ifStatementBlockStatementNode2;
+        });
+
+        it('should return lexical scope node for `program` node child node', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(programNode)[0], programNode);
+        });
+
+        it('should return lexical scope node for `functionDeclaration` node child node #1', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(functionDeclarationNode)[0], functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `functionDeclaration` node child node #2', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(functionDeclarationNode)[1], programNode);
+        });
+
+        it('should return lexical scope node for `functionDeclaration blockStatement` node child node #1', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(functionDeclarationBlockStatementNode)[0], functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `expressionStatement` node #1 child node #1', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(expressionStatementNode1)[0], functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `expressionStatement` node #1 child node #2', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(expressionStatementNode1)[1], programNode);
+        });
+
+        it('should return lexical scope node for `ifStatement` node child node #1', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(ifStatementNode1)[0], functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `ifStatement` node child node #2', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(ifStatementNode1)[1], programNode);
+        });
+
+        it('should return lexical scope node for `ifStatement blockStatement` node #1 child node #1', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(ifStatementBlockStatementNode1)[0], functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `ifStatement blockStatement` node #1 child node #2', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(ifStatementBlockStatementNode1)[1], programNode);
+        });
+
+        it('should return lexical scope node for `ifStatement blockStatement` node #2 child node #1', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(ifStatementBlockStatementNode2)[0], functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `ifStatement blockStatement` node #1 child node #2', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(ifStatementBlockStatementNode2)[1], programNode);
+        });
+
+        it('should return lexical scope node for `expressionStatement` node #3 child node #1', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(expressionStatementNode3)[0], functionDeclarationNode);
+        });
+
+        it('should return lexical scope node for `expressionStatement` node #3 child node #2', () => {
+            assert.deepEqual(NodeLexicalScopeUtils.getLexicalScopes(expressionStatementNode3)[1], programNode);
+        });
+
+        it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
+            assert.throws(() => NodeLexicalScopeUtils.getLexicalScopes(expressionStatementNode2)[0], ReferenceError);
+        });
+    });
+});

+ 625 - 0
test/unit-tests/node/node-statement-utils/NodeStatementUtils.spec.ts

@@ -0,0 +1,625 @@
+import * as ESTree from 'estree';
+
+import { assert } from 'chai';
+
+import { NodeFactory } from '../../../../src/node/NodeFactory';
+import { NodeStatementUtils } from '../../../../src/node/NodeStatementUtils';
+import { NodeUtils } from '../../../../src/node/NodeUtils';
+
+describe('NodeStatementUtils', () => {
+    describe('getParentNodeWithStatements', () => {
+        let functionDeclarationBlockStatementNode: ESTree.BlockStatement,
+            ifStatementBlockStatementNode1: ESTree.BlockStatement,
+            ifStatementBlockStatementNode2: ESTree.BlockStatement,
+            ifStatementNode1: ESTree.IfStatement,
+            ifStatementNode2: ESTree.IfStatement,
+            expressionStatementNode3: ESTree.ExpressionStatement,
+            expressionStatementNode2: ESTree.ExpressionStatement,
+            expressionStatementNode1: ESTree.ExpressionStatement,
+            functionDeclarationNode: ESTree.FunctionDeclaration,
+            programNode: ESTree.Program;
+
+        before(() => {
+            expressionStatementNode1 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+            expressionStatementNode2 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+            expressionStatementNode3 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+
+            ifStatementBlockStatementNode2 = NodeFactory.blockStatementNode([
+                expressionStatementNode2,
+                expressionStatementNode3
+            ]);
+
+            ifStatementNode2 = NodeFactory.ifStatementNode(
+                NodeFactory.literalNode(true),
+                ifStatementBlockStatementNode2
+            );
+
+            ifStatementBlockStatementNode1 = NodeFactory.blockStatementNode([
+                ifStatementNode2
+            ]);
+
+            ifStatementNode1 = NodeFactory.ifStatementNode(
+                NodeFactory.literalNode(true),
+                ifStatementBlockStatementNode1
+            );
+
+            functionDeclarationBlockStatementNode = NodeFactory.blockStatementNode([
+                expressionStatementNode1,
+                ifStatementNode1
+            ]);
+
+            functionDeclarationNode = NodeFactory.functionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
+
+            programNode = NodeFactory.programNode([
+                functionDeclarationNode
+            ]);
+
+            programNode.parentNode = programNode;
+            functionDeclarationNode.parentNode = programNode;
+            functionDeclarationBlockStatementNode.parentNode = functionDeclarationNode;
+            expressionStatementNode1.parentNode = functionDeclarationBlockStatementNode;
+            ifStatementNode1.parentNode = functionDeclarationBlockStatementNode;
+            ifStatementBlockStatementNode1.parentNode = ifStatementNode1;
+            ifStatementNode2.parentNode = ifStatementBlockStatementNode1;
+            ifStatementBlockStatementNode2.parentNode = ifStatementNode2;
+            expressionStatementNode3.parentNode = ifStatementBlockStatementNode2;
+        });
+
+        it('should return parent node with statements for `program` node child node', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodeWithStatements(programNode), programNode);
+        });
+
+        it('should return parent node with statements node for `functionDeclaration` node child node', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodeWithStatements(functionDeclarationNode), programNode);
+        });
+
+        it('should return parent node with statements node for `functionDeclaration blockStatement` node child node', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodeWithStatements(functionDeclarationBlockStatementNode), programNode);
+        });
+
+        it('should return parent node with statements node for `expressionStatement` node #1 child node', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodeWithStatements(expressionStatementNode1), functionDeclarationBlockStatementNode);
+        });
+
+        it('should return parent node with statements node for `ifStatement` node child node', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodeWithStatements(ifStatementNode1), functionDeclarationBlockStatementNode);
+        });
+
+        it('should return parent node with statements node for `ifStatement blockStatement` node #1 child node', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodeWithStatements(ifStatementBlockStatementNode1), functionDeclarationBlockStatementNode);
+        });
+
+        it('should return parent node with statements node for `ifStatement blockStatement` node #2 child node', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodeWithStatements(ifStatementBlockStatementNode2), functionDeclarationBlockStatementNode);
+        });
+
+        it('should return parent node with statements node for `expressionStatement` node #3 child node', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodeWithStatements(expressionStatementNode3), functionDeclarationBlockStatementNode);
+        });
+
+        it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
+            assert.throws(() => NodeStatementUtils.getParentNodeWithStatements(expressionStatementNode2), ReferenceError);
+        });
+    });
+
+    describe('getParentNodesWithStatements', () => {
+        let functionDeclarationBlockStatementNode: ESTree.BlockStatement,
+            ifStatementBlockStatementNode1: ESTree.BlockStatement,
+            ifStatementBlockStatementNode2: ESTree.BlockStatement,
+            ifStatementNode1: ESTree.IfStatement,
+            ifStatementNode2: ESTree.IfStatement,
+            expressionStatementNode3: ESTree.ExpressionStatement,
+            expressionStatementNode2: ESTree.ExpressionStatement,
+            expressionStatementNode1: ESTree.ExpressionStatement,
+            functionDeclarationNode: ESTree.FunctionDeclaration,
+            programNode: ESTree.Program;
+
+        before(() => {
+            expressionStatementNode1 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+            expressionStatementNode2 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+            expressionStatementNode3 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+
+            ifStatementBlockStatementNode2 = NodeFactory.blockStatementNode([
+                expressionStatementNode2,
+                expressionStatementNode3
+            ]);
+
+            ifStatementNode2 = NodeFactory.ifStatementNode(
+                NodeFactory.literalNode(true),
+                ifStatementBlockStatementNode2
+            );
+
+            ifStatementBlockStatementNode1 = NodeFactory.blockStatementNode([
+                ifStatementNode2
+            ]);
+
+            ifStatementNode1 = NodeFactory.ifStatementNode(
+                NodeFactory.literalNode(true),
+                ifStatementBlockStatementNode1
+            );
+
+            functionDeclarationBlockStatementNode = NodeFactory.blockStatementNode([
+                expressionStatementNode1,
+                ifStatementNode1
+            ]);
+
+            functionDeclarationNode = NodeFactory.functionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
+
+            programNode = NodeFactory.programNode([
+                functionDeclarationNode
+            ]);
+
+            programNode.parentNode = programNode;
+            functionDeclarationNode.parentNode = programNode;
+            functionDeclarationBlockStatementNode.parentNode = functionDeclarationNode;
+            expressionStatementNode1.parentNode = functionDeclarationBlockStatementNode;
+            ifStatementNode1.parentNode = functionDeclarationBlockStatementNode;
+            ifStatementBlockStatementNode1.parentNode = ifStatementNode1;
+            ifStatementNode2.parentNode = ifStatementBlockStatementNode1;
+            ifStatementBlockStatementNode2.parentNode = ifStatementNode2;
+            expressionStatementNode3.parentNode = ifStatementBlockStatementNode2;
+        });
+
+        it('should return parent node with statements node for `program` node child node', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(programNode)[0], programNode);
+        });
+
+        it('should return parent node with statements node for `functionDeclaration` node child node #1', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(functionDeclarationNode)[0], programNode);
+        });
+
+        it('should return parent node with statements node for `functionDeclaration blockStatement` node child node #1', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(functionDeclarationBlockStatementNode)[0], programNode);
+        });
+
+        it('should return parent node with statements node for `expressionStatement` node #1 child node #1', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(expressionStatementNode1)[0], functionDeclarationBlockStatementNode);
+        });
+
+        it('should return parent node with statements node for `expressionStatement` node #1 child node #2', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(expressionStatementNode1)[1], programNode);
+        });
+
+        it('should return parent node with statements node for `ifStatement` node child node #1', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(ifStatementNode1)[0], functionDeclarationBlockStatementNode);
+        });
+
+        it('should return parent node with statements node for `ifStatement` node child node #2', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(ifStatementNode1)[1], programNode);
+        });
+
+        it('should return parent node with statements node for `ifStatement blockStatement` node #1 child node #1', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(ifStatementBlockStatementNode1)[0], functionDeclarationBlockStatementNode);
+        });
+
+        it('should return parent node with statements node for `ifStatement blockStatement` node #1 child node #2', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(ifStatementBlockStatementNode1)[1], programNode);
+        });
+
+        it('should return parent node with statements node for `ifStatement blockStatement` node #2 child node #1', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(ifStatementBlockStatementNode2)[0], functionDeclarationBlockStatementNode);
+        });
+
+        it('should return parent node with statements node for `ifStatement blockStatement` node #1 child node #2', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(ifStatementBlockStatementNode2)[1], programNode);
+        });
+
+        it('should return parent node with statements node for `expressionStatement` node #3 child node #1', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(expressionStatementNode3)[0], functionDeclarationBlockStatementNode);
+        });
+
+        it('should return parent node with statements node for `expressionStatement` node #3 child node #2', () => {
+            assert.deepEqual(NodeStatementUtils.getParentNodesWithStatements(expressionStatementNode3)[1], programNode);
+        });
+
+        it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
+            assert.throws(() => NodeStatementUtils.getParentNodesWithStatements(expressionStatementNode2)[0], ReferenceError);
+        });
+    });
+
+    describe('getNextSiblingStatement', () => {
+        describe('Variant #1: block statement node as scope node', () => {
+                let statementNode1: ESTree.Statement,
+                statementNode2: ESTree.Statement,
+                statementNode3: ESTree.Statement;
+
+            before(() => {
+                statementNode1 = NodeFactory.expressionStatementNode(
+                    NodeFactory.identifierNode('a')
+                );
+                statementNode2 = NodeFactory.expressionStatementNode(
+                    NodeFactory.identifierNode('b')
+                );
+                statementNode3 = NodeFactory.expressionStatementNode(
+                    NodeFactory.identifierNode('c')
+                );
+
+                const blockStatementNode: ESTree.BlockStatement = NodeFactory.blockStatementNode([
+                    statementNode1,
+                    statementNode2,
+                    statementNode3
+                ]);
+
+                statementNode1.parentNode = blockStatementNode;
+                statementNode2.parentNode = blockStatementNode;
+                statementNode3.parentNode = blockStatementNode;
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeStatementUtils.getNextSiblingStatement(statementNode1), statementNode2);
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeStatementUtils.getNextSiblingStatement(statementNode2), statementNode3);
+            });
+
+            it('should return `null` if given statement node is last node in the scope', () => {
+                assert.deepEqual(NodeStatementUtils.getNextSiblingStatement(statementNode3), null);
+            });
+        });
+
+        describe('Variant #2: switch case node as scope node', () => {
+            let statementNode1: ESTree.Statement,
+                statementNode2: ESTree.Statement,
+                statementNode3: ESTree.Statement;
+
+            before(() => {
+                statementNode1 = NodeFactory.expressionStatementNode(
+                    NodeFactory.identifierNode('a')
+                );
+                statementNode2 = NodeFactory.expressionStatementNode(
+                    NodeFactory.identifierNode('b')
+                );
+                statementNode3 = NodeFactory.expressionStatementNode(
+                    NodeFactory.identifierNode('c')
+                );
+
+                const switchCaseNode: ESTree.SwitchCase = NodeFactory.switchCaseNode(
+                    NodeFactory.literalNode(true),
+                    [
+                        statementNode1,
+                        statementNode2,
+                        statementNode3
+                    ]
+                );
+
+                statementNode1.parentNode = switchCaseNode;
+                statementNode2.parentNode = switchCaseNode;
+                statementNode3.parentNode = switchCaseNode;
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeStatementUtils.getNextSiblingStatement(statementNode1), statementNode2);
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeStatementUtils.getNextSiblingStatement(statementNode2), statementNode3);
+            });
+
+            it('should return `null` if given statement node is last node in the scope', () => {
+                assert.deepEqual(NodeStatementUtils.getNextSiblingStatement(statementNode3), null);
+            });
+        });
+    });
+
+    describe('getPreviousSiblingStatement', () => {
+        describe('Variant #1: block statement node as scope node', () => {
+            let statementNode1: ESTree.Statement,
+                statementNode2: ESTree.Statement,
+                statementNode3: ESTree.Statement;
+
+            before(() => {
+                statementNode1 = NodeFactory.expressionStatementNode(
+                    NodeFactory.identifierNode('a')
+                );
+                statementNode2 = NodeFactory.expressionStatementNode(
+                    NodeFactory.identifierNode('b')
+                );
+                statementNode3 = NodeFactory.expressionStatementNode(
+                    NodeFactory.identifierNode('c')
+                );
+
+                const blockStatementNode: ESTree.BlockStatement = NodeFactory.blockStatementNode([
+                    statementNode1,
+                    statementNode2,
+                    statementNode3
+                ]);
+
+                statementNode1.parentNode = blockStatementNode;
+                statementNode2.parentNode = blockStatementNode;
+                statementNode3.parentNode = blockStatementNode;
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeStatementUtils.getPreviousSiblingStatement(statementNode1), null);
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeStatementUtils.getPreviousSiblingStatement(statementNode2), statementNode1);
+            });
+
+            it('should return `null` if given statement node is last node in the scope', () => {
+                assert.deepEqual(NodeStatementUtils.getPreviousSiblingStatement(statementNode3), statementNode2);
+            });
+        });
+
+        describe('Variant #2: switch case node as scope node', () => {
+            let statementNode1: ESTree.Statement,
+                statementNode2: ESTree.Statement,
+                statementNode3: ESTree.Statement;
+
+            before(() => {
+                statementNode1 = NodeFactory.expressionStatementNode(
+                    NodeFactory.identifierNode('a')
+                );
+                statementNode2 = NodeFactory.expressionStatementNode(
+                    NodeFactory.identifierNode('b')
+                );
+                statementNode3 = NodeFactory.expressionStatementNode(
+                    NodeFactory.identifierNode('c')
+                );
+
+                const switchCaseNode: ESTree.SwitchCase = NodeFactory.switchCaseNode(
+                    NodeFactory.literalNode(true),
+                    [
+                        statementNode1,
+                        statementNode2,
+                        statementNode3
+                    ]
+                );
+
+                statementNode1.parentNode = switchCaseNode;
+                statementNode2.parentNode = switchCaseNode;
+                statementNode3.parentNode = switchCaseNode;
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeStatementUtils.getPreviousSiblingStatement(statementNode1), null);
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeStatementUtils.getPreviousSiblingStatement(statementNode2), statementNode1);
+            });
+
+            it('should return `null` if given statement node is last node in the scope', () => {
+                assert.deepEqual(NodeStatementUtils.getPreviousSiblingStatement(statementNode3), statementNode2);
+            });
+        });
+    });
+
+    describe('getRootStatementOfNode', () => {
+        let assignmentExpression: ESTree.AssignmentExpression,
+            expressionStatement: ESTree.ExpressionStatement,
+            identifierNode1: ESTree.Identifier,
+            identifierNode2: ESTree.Identifier,
+            identifierNode3: ESTree.Identifier,
+            identifierNode4: ESTree.Identifier,
+            identifierNode5: ESTree.Identifier,
+            functionDeclarationNode: ESTree.FunctionDeclaration,
+            functionDeclarationBlockStatementNode: ESTree.BlockStatement,
+            programNode: ESTree.Program,
+            variableDeclarationNode: ESTree.VariableDeclaration;
+
+        before(() => {
+            identifierNode1 = NodeFactory.identifierNode('identifier');
+            identifierNode2 = NodeFactory.identifierNode('identifier');
+            identifierNode3 = NodeFactory.identifierNode('identifier');
+            identifierNode4 = NodeFactory.identifierNode('foo');
+            identifierNode5 = NodeFactory.identifierNode('bar');
+
+            assignmentExpression = NodeFactory.assignmentExpressionNode(
+                '=',
+                identifierNode4,
+                identifierNode5
+            );
+
+            expressionStatement = NodeFactory.expressionStatementNode(
+                assignmentExpression
+            );
+
+            variableDeclarationNode = NodeFactory.variableDeclarationNode([
+                NodeFactory.variableDeclaratorNode(
+                    identifierNode1,
+                    NodeFactory.binaryExpressionNode(
+                        '+',
+                        identifierNode2,
+                        identifierNode3
+                    )
+                )
+            ]);
+
+            functionDeclarationBlockStatementNode = NodeFactory.blockStatementNode([
+                variableDeclarationNode
+            ]);
+
+            functionDeclarationNode = NodeFactory.functionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
+
+            programNode = NodeFactory.programNode([
+                functionDeclarationNode,
+                NodeFactory.ifStatementNode(
+                    NodeFactory.literalNode(true),
+                    NodeFactory.blockStatementNode([
+                        expressionStatement
+                    ])
+                )
+            ]);
+
+            NodeUtils.parentizeAst(programNode);
+
+            identifierNode3.parentNode = undefined;
+        });
+
+        it('should return root statement in scope for `program` node child', () => {
+            assert.throws(() => NodeStatementUtils.getRootStatementOfNode(programNode), Error);
+        });
+
+        it('should return root statement in scope for `functionDeclaration` node #1', () => {
+            assert.deepEqual(NodeStatementUtils.getRootStatementOfNode(functionDeclarationNode), functionDeclarationNode);
+        });
+
+        it('should return root statement in scope for `functionDeclaration blockStatement` node #1', () => {
+            assert.deepEqual(NodeStatementUtils.getRootStatementOfNode(functionDeclarationBlockStatementNode), functionDeclarationNode);
+        });
+
+        it('should return root statement in scope for `identifier` node #1', () => {
+            assert.deepEqual(NodeStatementUtils.getRootStatementOfNode(identifierNode1), variableDeclarationNode);
+        });
+
+        it('should return root statement in scope for `identifier` node #2', () => {
+            assert.deepEqual(NodeStatementUtils.getRootStatementOfNode(identifierNode2), variableDeclarationNode);
+        });
+
+        it('should return root statement in scope for `identifier` node #4', () => {
+            assert.deepEqual(NodeStatementUtils.getRootStatementOfNode(identifierNode4), expressionStatement);
+        });
+
+        it('should return root statement in scope for `identifier` node #5', () => {
+            assert.deepEqual(NodeStatementUtils.getRootStatementOfNode(identifierNode5), expressionStatement);
+        });
+
+        it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
+            assert.throws(() => NodeStatementUtils.getRootStatementOfNode(identifierNode3), ReferenceError);
+        });
+    });
+
+    describe('getScopeOfNode', () => {
+        let functionDeclarationBlockStatementNode: ESTree.BlockStatement,
+            ifStatementBlockStatementNode1: ESTree.BlockStatement,
+            ifStatementBlockStatementNode2: ESTree.BlockStatement,
+            ifStatementBlockStatementNode3: ESTree.BlockStatement,
+            ifStatementNode1: ESTree.IfStatement,
+            ifStatementNode2: ESTree.IfStatement,
+            ifStatementNode3: ESTree.IfStatement,
+            switchCaseNode: ESTree.SwitchCase,
+            switchStatementNode: ESTree.SwitchStatement,
+            expressionStatementNode3: ESTree.ExpressionStatement,
+            expressionStatementNode2: ESTree.ExpressionStatement,
+            expressionStatementNode1: ESTree.ExpressionStatement,
+            functionDeclarationNode: ESTree.FunctionDeclaration,
+            programNode: ESTree.Program;
+
+        before(() => {
+            expressionStatementNode1 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+            expressionStatementNode2 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+            expressionStatementNode3 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
+
+            ifStatementBlockStatementNode3 = NodeFactory.blockStatementNode([
+                expressionStatementNode2,
+                expressionStatementNode3
+            ]);
+
+            ifStatementNode3 = NodeFactory.ifStatementNode(
+                NodeFactory.literalNode(true),
+                ifStatementBlockStatementNode3
+            );
+
+            ifStatementBlockStatementNode2 = NodeFactory.blockStatementNode();
+
+            ifStatementBlockStatementNode1 = NodeFactory.blockStatementNode([
+                ifStatementNode3
+            ]);
+
+            ifStatementNode2 = NodeFactory.ifStatementNode(
+                NodeFactory.literalNode(true),
+                ifStatementBlockStatementNode2
+            );
+
+            ifStatementNode1 = NodeFactory.ifStatementNode(
+                NodeFactory.literalNode(true),
+                ifStatementBlockStatementNode1
+            );
+
+            switchCaseNode = NodeFactory.switchCaseNode(
+                NodeFactory.literalNode(1),
+                [
+                    ifStatementNode2
+                ]
+            );
+
+            switchStatementNode = NodeFactory.switchStatementNode(
+                NodeFactory.literalNode(1),
+                [
+                    switchCaseNode
+                ]
+            );
+
+            functionDeclarationBlockStatementNode = NodeFactory.blockStatementNode([
+                expressionStatementNode1,
+                ifStatementNode1,
+                switchStatementNode
+            ]);
+
+            functionDeclarationNode = NodeFactory.functionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
+
+            programNode = NodeFactory.programNode([
+                functionDeclarationNode
+            ]);
+
+            programNode.parentNode = programNode;
+            functionDeclarationNode.parentNode = programNode;
+            functionDeclarationBlockStatementNode.parentNode = functionDeclarationNode;
+            expressionStatementNode1.parentNode = functionDeclarationBlockStatementNode;
+            ifStatementNode1.parentNode = functionDeclarationBlockStatementNode;
+            ifStatementBlockStatementNode1.parentNode = ifStatementNode1;
+            switchStatementNode.parentNode = functionDeclarationBlockStatementNode;
+            switchCaseNode.parentNode = switchStatementNode;
+            ifStatementNode2.parentNode = switchCaseNode;
+            ifStatementBlockStatementNode2.parentNode = ifStatementNode2;
+            ifStatementNode3.parentNode = ifStatementBlockStatementNode1;
+            ifStatementBlockStatementNode3.parentNode = ifStatementNode3;
+            expressionStatementNode3.parentNode = ifStatementBlockStatementNode3;
+        });
+
+        it('should return scope node for `program` node child', () => {
+            assert.deepEqual(NodeStatementUtils.getScopeOfNode(programNode), programNode);
+        });
+
+        it('should return scope node for `functionDeclaration` node child node #1', () => {
+            assert.deepEqual(NodeStatementUtils.getScopeOfNode(functionDeclarationNode), programNode);
+        });
+
+        it('should return scope node for `functionDeclaration blockStatement` node child node #1', () => {
+            assert.deepEqual(NodeStatementUtils.getScopeOfNode(functionDeclarationBlockStatementNode), programNode);
+        });
+
+        it('should return scope node for `expressionStatement` node #1 child node', () => {
+            assert.deepEqual(NodeStatementUtils.getScopeOfNode(expressionStatementNode1), functionDeclarationBlockStatementNode);
+        });
+
+        it('should return scope node for `ifStatement` node #1 child node', () => {
+            assert.deepEqual(NodeStatementUtils.getScopeOfNode(ifStatementNode1), functionDeclarationBlockStatementNode);
+        });
+
+        it('should return scope node for `switchStatement` node child node', () => {
+            assert.deepEqual(NodeStatementUtils.getScopeOfNode(switchStatementNode), functionDeclarationBlockStatementNode);
+        });
+
+        it('should return scope node for `switchCase` node child node', () => {
+            assert.deepEqual(NodeStatementUtils.getScopeOfNode(switchCaseNode), functionDeclarationBlockStatementNode);
+        });
+
+        it('should return scope node for `ifStatement` node #2 child node', () => {
+            assert.deepEqual(NodeStatementUtils.getScopeOfNode(ifStatementNode2), switchCaseNode);
+        });
+
+        it('should return scope node for `ifStatement blockStatement` node #2 child node', () => {
+            assert.deepEqual(NodeStatementUtils.getScopeOfNode(ifStatementBlockStatementNode2), switchCaseNode);
+        });
+
+        it('should return scope node for `ifStatement blockStatement` node #1 child node', () => {
+            assert.deepEqual(NodeStatementUtils.getScopeOfNode(ifStatementBlockStatementNode1), functionDeclarationBlockStatementNode);
+        });
+
+        it('should return scope node for `ifStatement blockStatement` node #3 child node', () => {
+            assert.deepEqual(NodeStatementUtils.getScopeOfNode(ifStatementBlockStatementNode3), ifStatementBlockStatementNode1);
+        });
+
+        it('should return scope node for `expressionStatement` node #3 child node', () => {
+            assert.deepEqual(NodeStatementUtils.getScopeOfNode(expressionStatementNode3), ifStatementBlockStatementNode3);
+        });
+
+        it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
+            assert.throws(() => NodeStatementUtils.getScopeOfNode(expressionStatementNode2), ReferenceError);
+        });
+    });
+});

+ 0 - 616
test/unit-tests/node/node-utils/NodeUtils.spec.ts

@@ -181,622 +181,6 @@ describe('NodeUtils', () => {
         });
     });
 
-    describe('getBlockScopeOfNode', () => {
-        let functionDeclarationBlockStatementNode: ESTree.BlockStatement,
-            ifStatementBlockStatementNode1: ESTree.BlockStatement,
-            ifStatementBlockStatementNode2: ESTree.BlockStatement,
-            ifStatementNode1: ESTree.IfStatement,
-            ifStatementNode2: ESTree.IfStatement,
-            expressionStatementNode3: ESTree.ExpressionStatement,
-            expressionStatementNode2: ESTree.ExpressionStatement,
-            expressionStatementNode1: ESTree.ExpressionStatement,
-            functionDeclarationNode: ESTree.FunctionDeclaration,
-            programNode: ESTree.Program;
-
-        before(() => {
-            expressionStatementNode1 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
-            expressionStatementNode2 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
-            expressionStatementNode3 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
-
-            ifStatementBlockStatementNode2 = NodeFactory.blockStatementNode([
-                expressionStatementNode2,
-                expressionStatementNode3
-            ]);
-
-            ifStatementNode2 = NodeFactory.ifStatementNode(
-                NodeFactory.literalNode(true),
-                ifStatementBlockStatementNode2
-            );
-
-            ifStatementBlockStatementNode1 = NodeFactory.blockStatementNode([
-                ifStatementNode2
-            ]);
-
-            ifStatementNode1 = NodeFactory.ifStatementNode(
-                NodeFactory.literalNode(true),
-                ifStatementBlockStatementNode1
-            );
-
-            functionDeclarationBlockStatementNode = NodeFactory.blockStatementNode([
-                expressionStatementNode1,
-                ifStatementNode1
-            ]);
-
-            functionDeclarationNode = NodeFactory.functionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
-
-            programNode = NodeFactory.programNode([
-                functionDeclarationNode
-            ]);
-
-            programNode.parentNode = programNode;
-            functionDeclarationNode.parentNode = programNode;
-            functionDeclarationBlockStatementNode.parentNode = functionDeclarationNode;
-            expressionStatementNode1.parentNode = functionDeclarationBlockStatementNode;
-            ifStatementNode1.parentNode = functionDeclarationBlockStatementNode;
-            ifStatementBlockStatementNode1.parentNode = ifStatementNode1;
-            ifStatementNode2.parentNode = ifStatementBlockStatementNode1;
-            ifStatementBlockStatementNode2.parentNode = ifStatementNode2;
-            expressionStatementNode3.parentNode = ifStatementBlockStatementNode2;
-        });
-
-        it('should return block-scope node for `program` node child node', () => {
-            assert.deepEqual(NodeUtils.getBlockScopeOfNode(programNode), programNode);
-        });
-
-        it('should return block-scope node for `functionDeclaration` node child node', () => {
-            assert.deepEqual(NodeUtils.getBlockScopeOfNode(functionDeclarationNode), programNode);
-        });
-
-        it('should return block-scope node for `functionDeclaration blockStatement` node child node', () => {
-            assert.deepEqual(NodeUtils.getBlockScopeOfNode(functionDeclarationBlockStatementNode), programNode);
-        });
-
-        it('should return block-scope node for `expressionStatement` node #1 child node', () => {
-            assert.deepEqual(NodeUtils.getBlockScopeOfNode(expressionStatementNode1), functionDeclarationBlockStatementNode);
-        });
-
-        it('should return block-scope node for `ifStatement` node child node', () => {
-            assert.deepEqual(NodeUtils.getBlockScopeOfNode(ifStatementNode1), functionDeclarationBlockStatementNode);
-        });
-
-        it('should return block-scope node for `ifStatement blockStatement` node #1 child node', () => {
-            assert.deepEqual(NodeUtils.getBlockScopeOfNode(ifStatementBlockStatementNode1), functionDeclarationBlockStatementNode);
-        });
-
-        it('should return block-scope node for `ifStatement blockStatement` node #2 child node', () => {
-            assert.deepEqual(NodeUtils.getBlockScopeOfNode(ifStatementBlockStatementNode2), functionDeclarationBlockStatementNode);
-        });
-
-        it('should return block-scope node for `expressionStatement` node #3 child node', () => {
-            assert.deepEqual(NodeUtils.getBlockScopeOfNode(expressionStatementNode3), functionDeclarationBlockStatementNode);
-        });
-
-        it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
-            assert.throws(() => NodeUtils.getBlockScopeOfNode(expressionStatementNode2), ReferenceError);
-        });
-    });
-
-    describe('getBlockScopesOfNode', () => {
-        let functionDeclarationBlockStatementNode: ESTree.BlockStatement,
-            ifStatementBlockStatementNode1: ESTree.BlockStatement,
-            ifStatementBlockStatementNode2: ESTree.BlockStatement,
-            ifStatementNode1: ESTree.IfStatement,
-            ifStatementNode2: ESTree.IfStatement,
-            expressionStatementNode3: ESTree.ExpressionStatement,
-            expressionStatementNode2: ESTree.ExpressionStatement,
-            expressionStatementNode1: ESTree.ExpressionStatement,
-            functionDeclarationNode: ESTree.FunctionDeclaration,
-            programNode: ESTree.Program;
-
-        before(() => {
-            expressionStatementNode1 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
-            expressionStatementNode2 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
-            expressionStatementNode3 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
-
-            ifStatementBlockStatementNode2 = NodeFactory.blockStatementNode([
-                expressionStatementNode2,
-                expressionStatementNode3
-            ]);
-
-            ifStatementNode2 = NodeFactory.ifStatementNode(
-                NodeFactory.literalNode(true),
-                ifStatementBlockStatementNode2
-            );
-
-            ifStatementBlockStatementNode1 = NodeFactory.blockStatementNode([
-                ifStatementNode2
-            ]);
-
-            ifStatementNode1 = NodeFactory.ifStatementNode(
-                NodeFactory.literalNode(true),
-                ifStatementBlockStatementNode1
-            );
-
-            functionDeclarationBlockStatementNode = NodeFactory.blockStatementNode([
-                expressionStatementNode1,
-                ifStatementNode1
-            ]);
-
-            functionDeclarationNode = NodeFactory.functionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
-
-            programNode = NodeFactory.programNode([
-                functionDeclarationNode
-            ]);
-
-            programNode.parentNode = programNode;
-            functionDeclarationNode.parentNode = programNode;
-            functionDeclarationBlockStatementNode.parentNode = functionDeclarationNode;
-            expressionStatementNode1.parentNode = functionDeclarationBlockStatementNode;
-            ifStatementNode1.parentNode = functionDeclarationBlockStatementNode;
-            ifStatementBlockStatementNode1.parentNode = ifStatementNode1;
-            ifStatementNode2.parentNode = ifStatementBlockStatementNode1;
-            ifStatementBlockStatementNode2.parentNode = ifStatementNode2;
-            expressionStatementNode3.parentNode = ifStatementBlockStatementNode2;
-        });
-
-        it('should return block-scope node for `program` node child node', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(programNode)[0], programNode);
-        });
-
-        it('should return block-scope node for `functionDeclaration` node child node #1', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(functionDeclarationNode)[0], programNode);
-        });
-
-        it('should return block-scope node for `functionDeclaration blockStatement` node child node #1', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(functionDeclarationBlockStatementNode)[0], programNode);
-        });
-
-        it('should return block-scope node for `expressionStatement` node #1 child node #1', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(expressionStatementNode1)[0], functionDeclarationBlockStatementNode);
-        });
-
-        it('should return block-scope node for `expressionStatement` node #1 child node #2', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(expressionStatementNode1)[1], programNode);
-        });
-
-        it('should return block-scope node for `ifStatement` node child node #1', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementNode1)[0], functionDeclarationBlockStatementNode);
-        });
-
-        it('should return block-scope node for `ifStatement` node child node #2', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementNode1)[1], programNode);
-        });
-
-        it('should return block-scope node for `ifStatement blockStatement` node #1 child node #1', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementBlockStatementNode1)[0], functionDeclarationBlockStatementNode);
-        });
-
-        it('should return block-scope node for `ifStatement blockStatement` node #1 child node #2', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementBlockStatementNode1)[1], programNode);
-        });
-
-        it('should return block-scope node for `ifStatement blockStatement` node #2 child node #1', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementBlockStatementNode2)[0], functionDeclarationBlockStatementNode);
-        });
-
-        it('should return block-scope node for `ifStatement blockStatement` node #1 child node #2', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementBlockStatementNode2)[1], programNode);
-        });
-
-        it('should return block-scope node for `expressionStatement` node #3 child node #1', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(expressionStatementNode3)[0], functionDeclarationBlockStatementNode);
-        });
-
-        it('should return block-scope node for `expressionStatement` node #3 child node #2', () => {
-            assert.deepEqual(NodeUtils.getBlockScopesOfNode(expressionStatementNode3)[1], programNode);
-        });
-
-        it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
-            assert.throws(() => NodeUtils.getBlockScopesOfNode(expressionStatementNode2)[0], ReferenceError);
-        });
-    });
-
-    describe('getNextSiblingStatement', () => {
-        describe('Variant #1: block statement node as scope node', () => {
-                let statementNode1: ESTree.Statement,
-                statementNode2: ESTree.Statement,
-                statementNode3: ESTree.Statement;
-
-            before(() => {
-                statementNode1 = NodeFactory.expressionStatementNode(
-                    NodeFactory.identifierNode('a')
-                );
-                statementNode2 = NodeFactory.expressionStatementNode(
-                    NodeFactory.identifierNode('b')
-                );
-                statementNode3 = NodeFactory.expressionStatementNode(
-                    NodeFactory.identifierNode('c')
-                );
-
-                const blockStatementNode: ESTree.BlockStatement = NodeFactory.blockStatementNode([
-                    statementNode1,
-                    statementNode2,
-                    statementNode3
-                ]);
-
-                statementNode1.parentNode = blockStatementNode;
-                statementNode2.parentNode = blockStatementNode;
-                statementNode3.parentNode = blockStatementNode;
-            });
-
-            it('should return next sibling statement node', () => {
-                assert.deepEqual(NodeUtils.getNextSiblingStatement(statementNode1), statementNode2);
-            });
-
-            it('should return next sibling statement node', () => {
-                assert.deepEqual(NodeUtils.getNextSiblingStatement(statementNode2), statementNode3);
-            });
-
-            it('should return `null` if given statement node is last node in the scope', () => {
-                assert.deepEqual(NodeUtils.getNextSiblingStatement(statementNode3), null);
-            });
-        });
-
-        describe('Variant #2: switch case node as scope node', () => {
-            let statementNode1: ESTree.Statement,
-                statementNode2: ESTree.Statement,
-                statementNode3: ESTree.Statement;
-
-            before(() => {
-                statementNode1 = NodeFactory.expressionStatementNode(
-                    NodeFactory.identifierNode('a')
-                );
-                statementNode2 = NodeFactory.expressionStatementNode(
-                    NodeFactory.identifierNode('b')
-                );
-                statementNode3 = NodeFactory.expressionStatementNode(
-                    NodeFactory.identifierNode('c')
-                );
-
-                const switchCaseNode: ESTree.SwitchCase = NodeFactory.switchCaseNode(
-                    NodeFactory.literalNode(true),
-                    [
-                        statementNode1,
-                        statementNode2,
-                        statementNode3
-                    ]
-                );
-
-                statementNode1.parentNode = switchCaseNode;
-                statementNode2.parentNode = switchCaseNode;
-                statementNode3.parentNode = switchCaseNode;
-            });
-
-            it('should return next sibling statement node', () => {
-                assert.deepEqual(NodeUtils.getNextSiblingStatement(statementNode1), statementNode2);
-            });
-
-            it('should return next sibling statement node', () => {
-                assert.deepEqual(NodeUtils.getNextSiblingStatement(statementNode2), statementNode3);
-            });
-
-            it('should return `null` if given statement node is last node in the scope', () => {
-                assert.deepEqual(NodeUtils.getNextSiblingStatement(statementNode3), null);
-            });
-        });
-    });
-
-    describe('getPreviousSiblingStatement', () => {
-        describe('Variant #1: block statement node as scope node', () => {
-            let statementNode1: ESTree.Statement,
-                statementNode2: ESTree.Statement,
-                statementNode3: ESTree.Statement;
-
-            before(() => {
-                statementNode1 = NodeFactory.expressionStatementNode(
-                    NodeFactory.identifierNode('a')
-                );
-                statementNode2 = NodeFactory.expressionStatementNode(
-                    NodeFactory.identifierNode('b')
-                );
-                statementNode3 = NodeFactory.expressionStatementNode(
-                    NodeFactory.identifierNode('c')
-                );
-
-                const blockStatementNode: ESTree.BlockStatement = NodeFactory.blockStatementNode([
-                    statementNode1,
-                    statementNode2,
-                    statementNode3
-                ]);
-
-                statementNode1.parentNode = blockStatementNode;
-                statementNode2.parentNode = blockStatementNode;
-                statementNode3.parentNode = blockStatementNode;
-            });
-
-            it('should return next sibling statement node', () => {
-                assert.deepEqual(NodeUtils.getPreviousSiblingStatement(statementNode1), null);
-            });
-
-            it('should return next sibling statement node', () => {
-                assert.deepEqual(NodeUtils.getPreviousSiblingStatement(statementNode2), statementNode1);
-            });
-
-            it('should return `null` if given statement node is last node in the scope', () => {
-                assert.deepEqual(NodeUtils.getPreviousSiblingStatement(statementNode3), statementNode2);
-            });
-        });
-
-        describe('Variant #2: switch case node as scope node', () => {
-            let statementNode1: ESTree.Statement,
-                statementNode2: ESTree.Statement,
-                statementNode3: ESTree.Statement;
-
-            before(() => {
-                statementNode1 = NodeFactory.expressionStatementNode(
-                    NodeFactory.identifierNode('a')
-                );
-                statementNode2 = NodeFactory.expressionStatementNode(
-                    NodeFactory.identifierNode('b')
-                );
-                statementNode3 = NodeFactory.expressionStatementNode(
-                    NodeFactory.identifierNode('c')
-                );
-
-                const switchCaseNode: ESTree.SwitchCase = NodeFactory.switchCaseNode(
-                    NodeFactory.literalNode(true),
-                    [
-                        statementNode1,
-                        statementNode2,
-                        statementNode3
-                    ]
-                );
-
-                statementNode1.parentNode = switchCaseNode;
-                statementNode2.parentNode = switchCaseNode;
-                statementNode3.parentNode = switchCaseNode;
-            });
-
-            it('should return next sibling statement node', () => {
-                assert.deepEqual(NodeUtils.getPreviousSiblingStatement(statementNode1), null);
-            });
-
-            it('should return next sibling statement node', () => {
-                assert.deepEqual(NodeUtils.getPreviousSiblingStatement(statementNode2), statementNode1);
-            });
-
-            it('should return `null` if given statement node is last node in the scope', () => {
-                assert.deepEqual(NodeUtils.getPreviousSiblingStatement(statementNode3), statementNode2);
-            });
-        });
-    });
-
-    describe('getRootStatementOfNode', () => {
-        let assignmentExpression: ESTree.AssignmentExpression,
-            expressionStatement: ESTree.ExpressionStatement,
-            identifierNode1: ESTree.Identifier,
-            identifierNode2: ESTree.Identifier,
-            identifierNode3: ESTree.Identifier,
-            identifierNode4: ESTree.Identifier,
-            identifierNode5: ESTree.Identifier,
-            functionDeclarationNode: ESTree.FunctionDeclaration,
-            functionDeclarationBlockStatementNode: ESTree.BlockStatement,
-            programNode: ESTree.Program,
-            variableDeclarationNode: ESTree.VariableDeclaration;
-
-        before(() => {
-            identifierNode1 = NodeFactory.identifierNode('identifier');
-            identifierNode2 = NodeFactory.identifierNode('identifier');
-            identifierNode3 = NodeFactory.identifierNode('identifier');
-            identifierNode4 = NodeFactory.identifierNode('foo');
-            identifierNode5 = NodeFactory.identifierNode('bar');
-
-            assignmentExpression = NodeFactory.assignmentExpressionNode(
-                '=',
-                identifierNode4,
-                identifierNode5
-            );
-
-            expressionStatement = NodeFactory.expressionStatementNode(
-                assignmentExpression
-            );
-
-            variableDeclarationNode = NodeFactory.variableDeclarationNode([
-                NodeFactory.variableDeclaratorNode(
-                    identifierNode1,
-                    NodeFactory.binaryExpressionNode(
-                        '+',
-                        identifierNode2,
-                        identifierNode3
-                    )
-                )
-            ]);
-
-            functionDeclarationBlockStatementNode = NodeFactory.blockStatementNode([
-                variableDeclarationNode
-            ]);
-
-            functionDeclarationNode = NodeFactory.functionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
-
-            programNode = NodeFactory.programNode([
-                functionDeclarationNode,
-                NodeFactory.ifStatementNode(
-                    NodeFactory.literalNode(true),
-                    NodeFactory.blockStatementNode([
-                        expressionStatement
-                    ])
-                )
-            ]);
-
-            NodeUtils.parentizeAst(programNode);
-
-            identifierNode3.parentNode = undefined;
-        });
-
-        it('should return root statement in scope for `program` node child', () => {
-            assert.throws(() => NodeUtils.getRootStatementOfNode(programNode), Error);
-        });
-
-        it('should return root statement in scope for `functionDeclaration` node #1', () => {
-            assert.deepEqual(NodeUtils.getRootStatementOfNode(functionDeclarationNode), functionDeclarationNode);
-        });
-
-        it('should return root statement in scope for `functionDeclaration blockStatement` node #1', () => {
-            assert.deepEqual(NodeUtils.getRootStatementOfNode(functionDeclarationBlockStatementNode), functionDeclarationNode);
-        });
-
-        it('should return root statement in scope for `identifier` node #1', () => {
-            assert.deepEqual(NodeUtils.getRootStatementOfNode(identifierNode1), variableDeclarationNode);
-        });
-
-        it('should return root statement in scope for `identifier` node #2', () => {
-            assert.deepEqual(NodeUtils.getRootStatementOfNode(identifierNode2), variableDeclarationNode);
-        });
-
-        it('should return root statement in scope for `identifier` node #4', () => {
-            assert.deepEqual(NodeUtils.getRootStatementOfNode(identifierNode4), expressionStatement);
-        });
-
-        it('should return root statement in scope for `identifier` node #5', () => {
-            assert.deepEqual(NodeUtils.getRootStatementOfNode(identifierNode5), expressionStatement);
-        });
-
-        it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
-            assert.throws(() => NodeUtils.getRootStatementOfNode(identifierNode3), ReferenceError);
-        });
-    });
-
-    describe('getScopeOfNode', () => {
-        let functionDeclarationBlockStatementNode: ESTree.BlockStatement,
-            ifStatementBlockStatementNode1: ESTree.BlockStatement,
-            ifStatementBlockStatementNode2: ESTree.BlockStatement,
-            ifStatementBlockStatementNode3: ESTree.BlockStatement,
-            ifStatementNode1: ESTree.IfStatement,
-            ifStatementNode2: ESTree.IfStatement,
-            ifStatementNode3: ESTree.IfStatement,
-            switchCaseNode: ESTree.SwitchCase,
-            switchStatementNode: ESTree.SwitchStatement,
-            expressionStatementNode3: ESTree.ExpressionStatement,
-            expressionStatementNode2: ESTree.ExpressionStatement,
-            expressionStatementNode1: ESTree.ExpressionStatement,
-            functionDeclarationNode: ESTree.FunctionDeclaration,
-            programNode: ESTree.Program;
-
-        before(() => {
-            expressionStatementNode1 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
-            expressionStatementNode2 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
-            expressionStatementNode3 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
-
-            ifStatementBlockStatementNode3 = NodeFactory.blockStatementNode([
-                expressionStatementNode2,
-                expressionStatementNode3
-            ]);
-
-            ifStatementNode3 = NodeFactory.ifStatementNode(
-                NodeFactory.literalNode(true),
-                ifStatementBlockStatementNode3
-            );
-
-            ifStatementBlockStatementNode2 = NodeFactory.blockStatementNode();
-
-            ifStatementBlockStatementNode1 = NodeFactory.blockStatementNode([
-                ifStatementNode3
-            ]);
-
-            ifStatementNode2 = NodeFactory.ifStatementNode(
-                NodeFactory.literalNode(true),
-                ifStatementBlockStatementNode2
-            );
-
-            ifStatementNode1 = NodeFactory.ifStatementNode(
-                NodeFactory.literalNode(true),
-                ifStatementBlockStatementNode1
-            );
-
-            switchCaseNode = NodeFactory.switchCaseNode(
-                NodeFactory.literalNode(1),
-                [
-                    ifStatementNode2
-                ]
-            );
-
-            switchStatementNode = NodeFactory.switchStatementNode(
-                NodeFactory.literalNode(1),
-                [
-                    switchCaseNode
-                ]
-            );
-
-            functionDeclarationBlockStatementNode = NodeFactory.blockStatementNode([
-                expressionStatementNode1,
-                ifStatementNode1,
-                switchStatementNode
-            ]);
-
-            functionDeclarationNode = NodeFactory.functionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
-
-            programNode = NodeFactory.programNode([
-                functionDeclarationNode
-            ]);
-
-            programNode.parentNode = programNode;
-            functionDeclarationNode.parentNode = programNode;
-            functionDeclarationBlockStatementNode.parentNode = functionDeclarationNode;
-            expressionStatementNode1.parentNode = functionDeclarationBlockStatementNode;
-            ifStatementNode1.parentNode = functionDeclarationBlockStatementNode;
-            ifStatementBlockStatementNode1.parentNode = ifStatementNode1;
-            switchStatementNode.parentNode = functionDeclarationBlockStatementNode;
-            switchCaseNode.parentNode = switchStatementNode;
-            ifStatementNode2.parentNode = switchCaseNode;
-            ifStatementBlockStatementNode2.parentNode = ifStatementNode2;
-            ifStatementNode3.parentNode = ifStatementBlockStatementNode1;
-            ifStatementBlockStatementNode3.parentNode = ifStatementNode3;
-            expressionStatementNode3.parentNode = ifStatementBlockStatementNode3;
-        });
-
-        it('should return scope node for `program` node child', () => {
-            assert.deepEqual(NodeUtils.getScopeOfNode(programNode), programNode);
-        });
-
-        it('should return scope node for `functionDeclaration` node child node #1', () => {
-            assert.deepEqual(NodeUtils.getScopeOfNode(functionDeclarationNode), programNode);
-        });
-
-        it('should return scope node for `functionDeclaration blockStatement` node child node #1', () => {
-            assert.deepEqual(NodeUtils.getScopeOfNode(functionDeclarationBlockStatementNode), programNode);
-        });
-
-        it('should return scope node for `expressionStatement` node #1 child node', () => {
-            assert.deepEqual(NodeUtils.getScopeOfNode(expressionStatementNode1), functionDeclarationBlockStatementNode);
-        });
-
-        it('should return scope node for `ifStatement` node #1 child node', () => {
-            assert.deepEqual(NodeUtils.getScopeOfNode(ifStatementNode1), functionDeclarationBlockStatementNode);
-        });
-
-        it('should return scope node for `switchStatement` node child node', () => {
-            assert.deepEqual(NodeUtils.getScopeOfNode(switchStatementNode), functionDeclarationBlockStatementNode);
-        });
-
-        it('should return scope node for `switchCase` node child node', () => {
-            assert.deepEqual(NodeUtils.getScopeOfNode(switchCaseNode), functionDeclarationBlockStatementNode);
-        });
-
-        it('should return scope node for `ifStatement` node #2 child node', () => {
-            assert.deepEqual(NodeUtils.getScopeOfNode(ifStatementNode2), switchCaseNode);
-        });
-
-        it('should return scope node for `ifStatement blockStatement` node #2 child node', () => {
-            assert.deepEqual(NodeUtils.getScopeOfNode(ifStatementBlockStatementNode2), switchCaseNode);
-        });
-
-        it('should return scope node for `ifStatement blockStatement` node #1 child node', () => {
-            assert.deepEqual(NodeUtils.getScopeOfNode(ifStatementBlockStatementNode1), functionDeclarationBlockStatementNode);
-        });
-
-        it('should return scope node for `ifStatement blockStatement` node #3 child node', () => {
-            assert.deepEqual(NodeUtils.getScopeOfNode(ifStatementBlockStatementNode3), ifStatementBlockStatementNode1);
-        });
-
-        it('should return scope node for `expressionStatement` node #3 child node', () => {
-            assert.deepEqual(NodeUtils.getScopeOfNode(expressionStatementNode3), ifStatementBlockStatementNode3);
-        });
-
-        it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
-            assert.throws(() => NodeUtils.getScopeOfNode(expressionStatementNode2), ReferenceError);
-        });
-    });
-
     describe('getUnaryExpressionArgumentNode', () => {
         let expectedNode: ESTree.Literal,
             unaryExpressionArgumentNode: ESTree.Node;

+ 380 - 380
yarn.lock

@@ -2,15 +2,15 @@
 # yarn lockfile v1
 
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.0.0-beta.54.tgz#c3b9766ad3218988f120e4058509adff0b72b183"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.0.0-beta.55.tgz#ac658b254103cb5e59ba13e662a6174842070b33"
   dependencies:
     commander "^2.8.1"
     convert-source-map "^1.1.0"
     fs-readdir-recursive "^1.0.0"
     glob "^7.0.0"
-    lodash "^4.17.5"
+    lodash "^4.17.10"
     mkdirp "^0.5.1"
     output-file-sync "^2.0.0"
     slash "^1.0.0"
@@ -18,523 +18,523 @@
   optionalDependencies:
     chokidar "^2.0.3"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.54.tgz#0024f96fdf7028a21d68e273afd4e953214a1ead"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.55.tgz#71f530e7b010af5eb7a7df7752f78921dd57e9ee"
   dependencies:
-    "@babel/highlight" "7.0.0-beta.54"
+    "@babel/highlight" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.0.0-beta.54.tgz#253c54d0095403a5cfa764e7d9b458194692d02b"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.0.0-beta.55.tgz#9e17c34b5ac855e427c98f570915a17fcc6bab4a"
   dependencies:
-    "@babel/code-frame" "7.0.0-beta.54"
-    "@babel/generator" "7.0.0-beta.54"
-    "@babel/helpers" "7.0.0-beta.54"
-    "@babel/parser" "7.0.0-beta.54"
-    "@babel/template" "7.0.0-beta.54"
-    "@babel/traverse" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/code-frame" "7.0.0-beta.55"
+    "@babel/generator" "7.0.0-beta.55"
+    "@babel/helpers" "7.0.0-beta.55"
+    "@babel/parser" "7.0.0-beta.55"
+    "@babel/template" "7.0.0-beta.55"
+    "@babel/traverse" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
     convert-source-map "^1.1.0"
     debug "^3.1.0"
     json5 "^0.5.0"
-    lodash "^4.17.5"
+    lodash "^4.17.10"
     resolve "^1.3.2"
     semver "^5.4.1"
     source-map "^0.5.0"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.54.tgz#c043c7eebeebfd7e665d95c281a4aafc83d4e1c9"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.55.tgz#8ec11152dcc398bae35dd181122704415c383a01"
   dependencies:
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/types" "7.0.0-beta.55"
     jsesc "^2.5.1"
-    lodash "^4.17.5"
+    lodash "^4.17.10"
     source-map "^0.5.0"
     trim-right "^1.0.1"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0-beta.54.tgz#1626126a3f9fc4ed280ac942372c7d39653d7121"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0-beta.55.tgz#3c3e4c00e14e7dea917938e35ed5d9156cdd35ce"
   dependencies:
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.0.0-beta.54.tgz#d0a1967635b9eebcafdba80491917ee4981c12fa"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.0.0-beta.55.tgz#4d02128acff5c368a2d43ea8608260ce49aeec5d"
   dependencies:
-    "@babel/helper-explode-assignable-expression" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/helper-explode-assignable-expression" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.0.0-beta.54.tgz#f6b72cfd832fb26eb2a806e18de05f88d3a8f302"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.0.0-beta.55.tgz#13f68c85c2adfe87c02f7ab4d2a63d35cd67d724"
   dependencies:
-    "@babel/helper-hoist-variables" "7.0.0-beta.54"
-    "@babel/traverse" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/helper-hoist-variables" "7.0.0-beta.55"
+    "@babel/traverse" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.0.0-beta.54.tgz#2036d7c49365987f091db9702ce2f3b55f677730"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.0.0-beta.55.tgz#b62bcb37b753be416db7f21563f0162cd933403a"
   dependencies:
-    "@babel/helper-function-name" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
-    lodash "^4.17.5"
+    "@babel/helper-function-name" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
+    lodash "^4.17.10"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.0.0-beta.54.tgz#cf067f3330965c2048bf087ea06f62c76d94a792"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.0.0-beta.55.tgz#f5c096f261ca4efc6154b2633317eec1ed9029ea"
   dependencies:
-    "@babel/traverse" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/traverse" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.54.tgz#307875507a1eda2482a09a9a4df6a25632ffb34b"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.55.tgz#16aab21380a2eabcee3328d21b9586ba3427dbef"
   dependencies:
-    "@babel/helper-get-function-arity" "7.0.0-beta.54"
-    "@babel/template" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/helper-get-function-arity" "7.0.0-beta.55"
+    "@babel/template" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.54.tgz#757bd189b077074a004028cfde5f083c306cc6c4"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.55.tgz#8559ded96ecd3b626f9c1f57494edc4fa3cc6a94"
   dependencies:
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0-beta.54.tgz#8635be8095135ff73f753ed189e449f68b4f43cb"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0-beta.55.tgz#a88c5d992dca109199cf95b25907534a959dc461"
   dependencies:
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0-beta.54.tgz#bce9ddc484317b13d2615bafe2b524d0d56d99df"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0-beta.55.tgz#823d254bc9bd019a529fe2ab7f9e1d26870c5e50"
   dependencies:
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.54.tgz#c2d8e14ff034225bf431356db77ef467b8d35aac"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.55.tgz#93f927c6631d0689b8bbd1991d3fb2aa63eeb3f2"
   dependencies:
-    "@babel/types" "7.0.0-beta.54"
-    lodash "^4.17.5"
+    "@babel/types" "7.0.0-beta.55"
+    lodash "^4.17.10"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.0.0-beta.54.tgz#8cc57eb0db5f0945d866524d555abd084e30cc35"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.0.0-beta.55.tgz#2bd12f0e9187e5d69599ffa7c11fe9a3a67b03d2"
   dependencies:
-    "@babel/helper-module-imports" "7.0.0-beta.54"
-    "@babel/helper-simple-access" "7.0.0-beta.54"
-    "@babel/helper-split-export-declaration" "7.0.0-beta.54"
-    "@babel/template" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
-    lodash "^4.17.5"
+    "@babel/helper-module-imports" "7.0.0-beta.55"
+    "@babel/helper-simple-access" "7.0.0-beta.55"
+    "@babel/helper-split-export-declaration" "7.0.0-beta.55"
+    "@babel/template" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
+    lodash "^4.17.10"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0-beta.54.tgz#4af8dd4ff90dbd29b3bcf85fff43952e2ae1016e"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0-beta.55.tgz#57fdc6898bc53f02da78bf4a39509d4dfc3b33cb"
   dependencies:
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0-beta.54.tgz#61d2a9a0f9a3e31838a458debb9eebd7bdd249b4"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0-beta.55.tgz#31f40777efd6b961da8496a923c22d2b062b3f73"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.0.0-beta.54.tgz#8ac562f855f132fc68dfd10b132552555ac870d9"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.0.0-beta.55.tgz#74e6c063d1ef9f7e58b7a84c06e6ee4a5bb5a5da"
   dependencies:
-    lodash "^4.17.5"
+    lodash "^4.17.10"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.0.0-beta.54.tgz#39a50052aadd74d40c73b7c58eb963b90fac56d3"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.0.0-beta.55.tgz#e762d1b8f7f06121ed3e40befb1f9847d4658a7d"
   dependencies:
-    "@babel/helper-annotate-as-pure" "7.0.0-beta.54"
-    "@babel/helper-wrap-function" "7.0.0-beta.54"
-    "@babel/template" "7.0.0-beta.54"
-    "@babel/traverse" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/helper-annotate-as-pure" "7.0.0-beta.55"
+    "@babel/helper-wrap-function" "7.0.0-beta.55"
+    "@babel/template" "7.0.0-beta.55"
+    "@babel/traverse" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.0.0-beta.54.tgz#901f5a1493a410799fd3ab3e0c0d29d18071c89f"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.0.0-beta.55.tgz#d588ad863990f35d8b0f67aa94ef8eec24171855"
   dependencies:
-    "@babel/helper-member-expression-to-functions" "7.0.0-beta.54"
-    "@babel/helper-optimise-call-expression" "7.0.0-beta.54"
-    "@babel/traverse" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/helper-member-expression-to-functions" "7.0.0-beta.55"
+    "@babel/helper-optimise-call-expression" "7.0.0-beta.55"
+    "@babel/traverse" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.0.0-beta.54.tgz#5f760a19589a9b6f07e80a65ef4bcbd4fba8c253"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.0.0-beta.55.tgz#f3f3ce279f20fc90c166c4fea1667646857ba559"
   dependencies:
-    "@babel/template" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
-    lodash "^4.17.5"
+    "@babel/template" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
+    lodash "^4.17.10"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.54.tgz#89cd8833c95481a0827ac6a1bfccddb92b75a109"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.55.tgz#ecb8074bf2d22c6518a252282535def137a8704f"
   dependencies:
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.0.0-beta.54.tgz#dc1b7a483a3074a3531b36523e03156d910a3a2a"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.0.0-beta.55.tgz#3053e77647057b29b88d9625503e033b1bd349b4"
   dependencies:
-    "@babel/helper-function-name" "7.0.0-beta.54"
-    "@babel/template" "7.0.0-beta.54"
-    "@babel/traverse" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/helper-function-name" "7.0.0-beta.55"
+    "@babel/template" "7.0.0-beta.55"
+    "@babel/traverse" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.0.0-beta.54.tgz#b86a99a80efd81668caef307610b961197446a74"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.0.0-beta.55.tgz#d0b4b9a327dba42d58890011deb905c820739617"
   dependencies:
-    "@babel/template" "7.0.0-beta.54"
-    "@babel/traverse" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
+    "@babel/template" "7.0.0-beta.55"
+    "@babel/traverse" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.54.tgz#155d507358329b8e7068970017c3fd74a9b08584"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.55.tgz#988653647d629c261dae156e74d5f0252ba520c0"
   dependencies:
     chalk "^2.0.0"
     esutils "^2.0.2"
     js-tokens "^3.0.0"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.0.0-beta.54.tgz#c01aa63b57c9c8dce8744796c81d9df121f20db4"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.0.0-beta.55.tgz#0a527efc148c6c8cd85d5ffddacad817a2daeeb2"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.0.0-beta.54.tgz#19871bd655b5d748b0ae3e9ecebe247be8b7f83b"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.0.0-beta.55.tgz#512bb28c0401769811818d6b4453ce9bdf5f21ca"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    "@babel/helper-remap-async-to-generator" "7.0.0-beta.54"
-    "@babel/plugin-syntax-async-generators" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    "@babel/helper-remap-async-to-generator" "7.0.0-beta.55"
+    "@babel/plugin-syntax-async-generators" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0-beta.54.tgz#5481269a020dd0d38715a8094fed015d30ef4c2a"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0-beta.55.tgz#b611bb83901bf05196237c516a8bb1117a2a9396"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    "@babel/plugin-syntax-object-rest-spread" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    "@babel/plugin-syntax-object-rest-spread" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0-beta.54.tgz#931f69298fa0c411b2596616cf5a1d82925b87a9"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0-beta.55.tgz#365727b214a3e3e5cbeb92c471635a5f51839735"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    "@babel/plugin-syntax-optional-catch-binding" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    "@babel/plugin-syntax-optional-catch-binding" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0-beta.54.tgz#1624631faf688bcbde4918712bd0af7186f7d245"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0-beta.55.tgz#987f851d4f50fbb91c17ba51cc113d8d3f558c5b"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    "@babel/helper-regex" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    "@babel/helper-regex" "7.0.0-beta.55"
     regexpu-core "^4.2.0"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0-beta.54.tgz#ffac8f64927614762897cc9643495fd38097dd41"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0-beta.55.tgz#e72b3857eb80b695c77c3721237b149072cda46b"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0-beta.54.tgz#e0f445612081ab573e2535adbabc7b710d17940c"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0-beta.55.tgz#990ea47e790d7d9a9d28469c6bcc15f580bf19e9"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0-beta.54.tgz#2eb8ddde19ddf73a343d087a087159ed44e54809"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0-beta.55.tgz#ef903fee2dbc3621773d7db2dec9861c8f976c12"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0-beta.54.tgz#44a977b8e61e4efcc7658bbbe260f204ca1bcf72"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0-beta.55.tgz#eacb446ffc67e5135a4a29ac72bffac1ada181f6"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.0.0-beta.54.tgz#d035e65c50884937d64dbe68d16498c032f8bbec"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.0.0-beta.55.tgz#490a4715540807bd89f5858e8aac30d1561bdd65"
   dependencies:
-    "@babel/helper-module-imports" "7.0.0-beta.54"
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    "@babel/helper-remap-async-to-generator" "7.0.0-beta.54"
+    "@babel/helper-module-imports" "7.0.0-beta.55"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    "@babel/helper-remap-async-to-generator" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0-beta.54.tgz#938a77fb12f0e11661bdf5386e4aeca47f0c053b"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0-beta.55.tgz#0670d0a149435eea73f72e3392a51b38de607270"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.0.0-beta.54.tgz#bcae1c2ffae4cc3b7b3e5455f0a98daecc09a3c6"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.0.0-beta.55.tgz#c826f8c20304ac39f6cdd11d14f1cd7d90aa5470"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    lodash "^4.17.5"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    lodash "^4.17.10"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.0.0-beta.54.tgz#b15781d2e499ce25438e73fea2fa5a09858568ff"
-  dependencies:
-    "@babel/helper-annotate-as-pure" "7.0.0-beta.54"
-    "@babel/helper-define-map" "7.0.0-beta.54"
-    "@babel/helper-function-name" "7.0.0-beta.54"
-    "@babel/helper-optimise-call-expression" "7.0.0-beta.54"
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    "@babel/helper-replace-supers" "7.0.0-beta.54"
-    "@babel/helper-split-export-declaration" "7.0.0-beta.54"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.0.0-beta.55.tgz#fa260266943f7a1e144ef9783d9a07e987755022"
+  dependencies:
+    "@babel/helper-annotate-as-pure" "7.0.0-beta.55"
+    "@babel/helper-define-map" "7.0.0-beta.55"
+    "@babel/helper-function-name" "7.0.0-beta.55"
+    "@babel/helper-optimise-call-expression" "7.0.0-beta.55"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    "@babel/helper-replace-supers" "7.0.0-beta.55"
+    "@babel/helper-split-export-declaration" "7.0.0-beta.55"
     globals "^11.1.0"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0-beta.54.tgz#b28494942b94fb86d01994763d2b5c43bdd986af"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0-beta.55.tgz#a04f101f305695031ffda61501728c00180237b9"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.0.0-beta.54.tgz#81f649a3e4fcb62c2b2ad497f783a800b994472f"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.0.0-beta.55.tgz#1d44216cbbdb5d873819abb71fe033c14a1c1723"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0-beta.54.tgz#2835b7f4141b19fa0648eb96ffe3c4fccd1eca20"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0-beta.55.tgz#2b9c2d13b79b660789b40f9f49873525d7d77437"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    "@babel/helper-regex" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    "@babel/helper-regex" "7.0.0-beta.55"
     regexpu-core "^4.1.3"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0-beta.54.tgz#4b8f4fb349902a800679191f59d0fa53fca49400"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0-beta.55.tgz#d1300c60703d5b5205f65ea178b7b5715d0b9687"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.0.0-beta.54.tgz#1017096366fb43ebca8ed8d8d0cdd1ebd64febb2"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.0.0-beta.55.tgz#ddcac0ea80e6641681a473a703093cd2f623a59e"
   dependencies:
-    "@babel/helper-builder-binary-assignment-operator-visitor" "7.0.0-beta.54"
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-builder-binary-assignment-operator-visitor" "7.0.0-beta.55"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0-beta.54.tgz#261d2992058a9e09234b9ff67820054ffc55f79c"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0-beta.55.tgz#cf3058c6d81a3d69e5df086294688dac28a42710"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.0.0-beta.54.tgz#cc722f9973931337def3d1e6c55138581edd371e"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.0.0-beta.55.tgz#114384d56e1739492bd4ce9337dd158acde14801"
   dependencies:
-    "@babel/helper-function-name" "7.0.0-beta.54"
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-function-name" "7.0.0-beta.55"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0-beta.54.tgz#70f07ecc2f3b7bc9f542a578e82eec18a5504098"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0-beta.55.tgz#8bc92cd24e6419301ef3867e4667b77aa6374e11"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.0.0-beta.54.tgz#fb50740741420bb485ee1315d2e1133db4e433d2"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.0.0-beta.55.tgz#c8b59b84d6f4987512667c6f9410af3ddd562e12"
   dependencies:
-    "@babel/helper-module-transforms" "7.0.0-beta.54"
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-module-transforms" "7.0.0-beta.55"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.0.0-beta.54.tgz#07d912a7a24dad2d9bf5d44ce322ddc457a8db37"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.0.0-beta.55.tgz#748af5037e28a78694df71be2e8d02c5c84b8aaf"
   dependencies:
-    "@babel/helper-module-transforms" "7.0.0-beta.54"
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    "@babel/helper-simple-access" "7.0.0-beta.54"
+    "@babel/helper-module-transforms" "7.0.0-beta.55"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    "@babel/helper-simple-access" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.0.0-beta.54.tgz#0923f012ac252e037467245ff27f8954f4ce6803"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.0.0-beta.55.tgz#9e36a7d48c9137781484c5442da426873289594e"
   dependencies:
-    "@babel/helper-hoist-variables" "7.0.0-beta.54"
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-hoist-variables" "7.0.0-beta.55"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.0.0-beta.54.tgz#3af0e2cf8f533b2984a8ca6da316246850c3aeda"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.0.0-beta.55.tgz#028c96f64e89313657c6d5f5ff0660fc99f6ee0a"
   dependencies:
-    "@babel/helper-module-transforms" "7.0.0-beta.54"
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-module-transforms" "7.0.0-beta.55"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0-beta.54.tgz#634ee57fa805720195cd31086c973f1fc5c9949b"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0-beta.55.tgz#0164ad758b68f67fc39dbef1b7d61e37f5a9bfd5"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.0.0-beta.54.tgz#d25fad66eff90de03ee62f8384f0af57bcd065d9"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.0.0-beta.55.tgz#b518d13a90352128191514d7d5db8e5a78c9992b"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    "@babel/helper-replace-supers" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    "@babel/helper-replace-supers" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.0.0-beta.54.tgz#76306f19b9acac6cf13721af15ecb9f382864ff7"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.0.0-beta.55.tgz#f211f18a560a4d928d9649da11c28dd89f15effe"
   dependencies:
-    "@babel/helper-call-delegate" "7.0.0-beta.54"
-    "@babel/helper-get-function-arity" "7.0.0-beta.54"
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-call-delegate" "7.0.0-beta.55"
+    "@babel/helper-get-function-arity" "7.0.0-beta.55"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0-beta.54.tgz#8b46e192f3bfe096bbbf86e27764e7662e5f9a0f"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0-beta.55.tgz#a12ba1376c647cf0b777dea8a7b55fe4665ed1ff"
   dependencies:
     regenerator-transform "^0.13.3"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.0.0-beta.54.tgz#ad45d1e84a9d0cfc48df148dda609ff09c121fd2"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.0.0-beta.55.tgz#f9bb5fab9372275d2a10c1e1261f4e99100c7dbe"
   dependencies:
-    "@babel/helper-module-imports" "7.0.0-beta.54"
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-module-imports" "7.0.0-beta.55"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0-beta.54.tgz#50e73c2afc5898b1055510ddf60ee13a6301517f"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0-beta.55.tgz#75e97575b87c6fe31c008fc3d755fddcd6cb908a"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0-beta.54.tgz#4f0852df0f4b1db2426c40facd8fe5f028a3dbc9"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0-beta.55.tgz#d5a1c320aac86469d6d311e136a89fb5a1f65600"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0-beta.54.tgz#568f35eb5118ae96fad82eac36374d7923b47883"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0-beta.55.tgz#d0b80b2deb8b4db03bc6459ebe79ad8b39b40546"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    "@babel/helper-regex" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    "@babel/helper-regex" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0-beta.54.tgz#cb1f6303cafb8442a6c6c69a0dfbb60699f327bc"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0-beta.55.tgz#b00a6496d4c8384507559598aaf49d8c1ad892e6"
   dependencies:
-    "@babel/helper-annotate-as-pure" "7.0.0-beta.54"
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-annotate-as-pure" "7.0.0-beta.55"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0-beta.54.tgz#6d068686239c9ebaf534d1c0d8032953f7b521bc"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0-beta.55.tgz#62326918560b765bbe9f362ad3a4ce3bc71477bc"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0-beta.54.tgz#1dc7e9150b39aaeb19fca1c863e082f6096afc60"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0-beta.55.tgz#87e7bedbba103f784a7999f82064f47c0b35c796"
   dependencies:
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    "@babel/helper-regex" "7.0.0-beta.54"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    "@babel/helper-regex" "7.0.0-beta.55"
     regexpu-core "^4.1.3"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.0.0-beta.54.tgz#4b05c4e3aaed64a509098e4e854dfc0e02edf053"
-  dependencies:
-    "@babel/helper-module-imports" "7.0.0-beta.54"
-    "@babel/helper-plugin-utils" "7.0.0-beta.54"
-    "@babel/plugin-proposal-async-generator-functions" "7.0.0-beta.54"
-    "@babel/plugin-proposal-object-rest-spread" "7.0.0-beta.54"
-    "@babel/plugin-proposal-optional-catch-binding" "7.0.0-beta.54"
-    "@babel/plugin-proposal-unicode-property-regex" "7.0.0-beta.54"
-    "@babel/plugin-syntax-async-generators" "7.0.0-beta.54"
-    "@babel/plugin-syntax-object-rest-spread" "7.0.0-beta.54"
-    "@babel/plugin-syntax-optional-catch-binding" "7.0.0-beta.54"
-    "@babel/plugin-transform-arrow-functions" "7.0.0-beta.54"
-    "@babel/plugin-transform-async-to-generator" "7.0.0-beta.54"
-    "@babel/plugin-transform-block-scoped-functions" "7.0.0-beta.54"
-    "@babel/plugin-transform-block-scoping" "7.0.0-beta.54"
-    "@babel/plugin-transform-classes" "7.0.0-beta.54"
-    "@babel/plugin-transform-computed-properties" "7.0.0-beta.54"
-    "@babel/plugin-transform-destructuring" "7.0.0-beta.54"
-    "@babel/plugin-transform-dotall-regex" "7.0.0-beta.54"
-    "@babel/plugin-transform-duplicate-keys" "7.0.0-beta.54"
-    "@babel/plugin-transform-exponentiation-operator" "7.0.0-beta.54"
-    "@babel/plugin-transform-for-of" "7.0.0-beta.54"
-    "@babel/plugin-transform-function-name" "7.0.0-beta.54"
-    "@babel/plugin-transform-literals" "7.0.0-beta.54"
-    "@babel/plugin-transform-modules-amd" "7.0.0-beta.54"
-    "@babel/plugin-transform-modules-commonjs" "7.0.0-beta.54"
-    "@babel/plugin-transform-modules-systemjs" "7.0.0-beta.54"
-    "@babel/plugin-transform-modules-umd" "7.0.0-beta.54"
-    "@babel/plugin-transform-new-target" "7.0.0-beta.54"
-    "@babel/plugin-transform-object-super" "7.0.0-beta.54"
-    "@babel/plugin-transform-parameters" "7.0.0-beta.54"
-    "@babel/plugin-transform-regenerator" "7.0.0-beta.54"
-    "@babel/plugin-transform-shorthand-properties" "7.0.0-beta.54"
-    "@babel/plugin-transform-spread" "7.0.0-beta.54"
-    "@babel/plugin-transform-sticky-regex" "7.0.0-beta.54"
-    "@babel/plugin-transform-template-literals" "7.0.0-beta.54"
-    "@babel/plugin-transform-typeof-symbol" "7.0.0-beta.54"
-    "@babel/plugin-transform-unicode-regex" "7.0.0-beta.54"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.0.0-beta.55.tgz#d3d997517761890144081d53c0c669ba7e8334e0"
+  dependencies:
+    "@babel/helper-module-imports" "7.0.0-beta.55"
+    "@babel/helper-plugin-utils" "7.0.0-beta.55"
+    "@babel/plugin-proposal-async-generator-functions" "7.0.0-beta.55"
+    "@babel/plugin-proposal-object-rest-spread" "7.0.0-beta.55"
+    "@babel/plugin-proposal-optional-catch-binding" "7.0.0-beta.55"
+    "@babel/plugin-proposal-unicode-property-regex" "7.0.0-beta.55"
+    "@babel/plugin-syntax-async-generators" "7.0.0-beta.55"
+    "@babel/plugin-syntax-object-rest-spread" "7.0.0-beta.55"
+    "@babel/plugin-syntax-optional-catch-binding" "7.0.0-beta.55"
+    "@babel/plugin-transform-arrow-functions" "7.0.0-beta.55"
+    "@babel/plugin-transform-async-to-generator" "7.0.0-beta.55"
+    "@babel/plugin-transform-block-scoped-functions" "7.0.0-beta.55"
+    "@babel/plugin-transform-block-scoping" "7.0.0-beta.55"
+    "@babel/plugin-transform-classes" "7.0.0-beta.55"
+    "@babel/plugin-transform-computed-properties" "7.0.0-beta.55"
+    "@babel/plugin-transform-destructuring" "7.0.0-beta.55"
+    "@babel/plugin-transform-dotall-regex" "7.0.0-beta.55"
+    "@babel/plugin-transform-duplicate-keys" "7.0.0-beta.55"
+    "@babel/plugin-transform-exponentiation-operator" "7.0.0-beta.55"
+    "@babel/plugin-transform-for-of" "7.0.0-beta.55"
+    "@babel/plugin-transform-function-name" "7.0.0-beta.55"
+    "@babel/plugin-transform-literals" "7.0.0-beta.55"
+    "@babel/plugin-transform-modules-amd" "7.0.0-beta.55"
+    "@babel/plugin-transform-modules-commonjs" "7.0.0-beta.55"
+    "@babel/plugin-transform-modules-systemjs" "7.0.0-beta.55"
+    "@babel/plugin-transform-modules-umd" "7.0.0-beta.55"
+    "@babel/plugin-transform-new-target" "7.0.0-beta.55"
+    "@babel/plugin-transform-object-super" "7.0.0-beta.55"
+    "@babel/plugin-transform-parameters" "7.0.0-beta.55"
+    "@babel/plugin-transform-regenerator" "7.0.0-beta.55"
+    "@babel/plugin-transform-shorthand-properties" "7.0.0-beta.55"
+    "@babel/plugin-transform-spread" "7.0.0-beta.55"
+    "@babel/plugin-transform-sticky-regex" "7.0.0-beta.55"
+    "@babel/plugin-transform-template-literals" "7.0.0-beta.55"
+    "@babel/plugin-transform-typeof-symbol" "7.0.0-beta.55"
+    "@babel/plugin-transform-unicode-regex" "7.0.0-beta.55"
     browserslist "^3.0.0"
     invariant "^2.2.2"
     js-levenshtein "^1.1.3"
     semver "^5.3.0"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-beta.54.tgz#39ebb42723fe7ca4b3e1b00e967e80138d47cadf"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-beta.55.tgz#0bc33aa5a6ac0b012f37e25b9e6aaa2e489a916b"
   dependencies:
     core-js "^2.5.7"
     regenerator-runtime "^0.12.0"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.54.tgz#d5b0d2d2d55c0e78b048c61a058f36cfd7d91af3"
-  dependencies:
-    "@babel/code-frame" "7.0.0-beta.54"
-    "@babel/parser" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
-    lodash "^4.17.5"
-
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.54.tgz#2c17f98dcdbf19aa918fde128f0e1a0bc089e05a"
-  dependencies:
-    "@babel/code-frame" "7.0.0-beta.54"
-    "@babel/generator" "7.0.0-beta.54"
-    "@babel/helper-function-name" "7.0.0-beta.54"
-    "@babel/helper-split-export-declaration" "7.0.0-beta.54"
-    "@babel/parser" "7.0.0-beta.54"
-    "@babel/types" "7.0.0-beta.54"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.55.tgz#c6cab0e2722ba5e33fe034073b6d31673aba326e"
+  dependencies:
+    "@babel/code-frame" "7.0.0-beta.55"
+    "@babel/parser" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
+    lodash "^4.17.10"
+
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.55.tgz#50be5d0fcc5cc4ac020a7b0c519be8dae345d4be"
+  dependencies:
+    "@babel/code-frame" "7.0.0-beta.55"
+    "@babel/generator" "7.0.0-beta.55"
+    "@babel/helper-function-name" "7.0.0-beta.55"
+    "@babel/helper-split-export-declaration" "7.0.0-beta.55"
+    "@babel/parser" "7.0.0-beta.55"
+    "@babel/types" "7.0.0-beta.55"
     debug "^3.1.0"
     globals "^11.1.0"
-    lodash "^4.17.5"
+    lodash "^4.17.10"
 
-"@babel/[email protected]4":
-  version "7.0.0-beta.54"
-  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.54.tgz#025ad68492fed542c13f14c579a44c848e531063"
+"@babel/[email protected]5":
+  version "7.0.0-beta.55"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.55.tgz#7755c9d2e58315a64f05d8cf3322379be16d9199"
   dependencies:
     esutils "^2.0.2"
-    lodash "^4.17.5"
+    lodash "^4.17.10"
     to-fast-properties "^2.0.0"
 
 "@sinonjs/formatio@^2.0.0":
@@ -609,9 +609,9 @@
   version "10.0.3"
   resolved "https://registry.yarnpkg.com/@types/node/-/node-10.0.3.tgz#1f89840c7aac2406cc43a2ecad98fc02a8e130e4"
 
-"@types/[email protected].2":
-  version "10.5.2"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.2.tgz#f19f05314d5421fe37e74153254201a7bf00a707"
+"@types/[email protected].4":
+  version "10.5.4"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.4.tgz#6eccc158504357d1da91434d75e86acde94bb10b"
 
 "@types/[email protected]":
   version "2.0.2"
@@ -2857,7 +2857,7 @@ lodash.get@^4.4.2:
   version "4.4.2"
   resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
 
-lodash@^4.14.0, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0:
+lodash@^4.14.0, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0:
   version "4.17.10"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
 
@@ -4643,9 +4643,9 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0:
     source-list-map "^2.0.0"
     source-map "~0.6.1"
 
[email protected].1:
-  version "4.16.1"
-  resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.1.tgz#2c4b89ea648125c3e67bcca6adf49ce2c14b2d31"
[email protected].3:
+  version "4.16.3"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.3.tgz#861be3176d81e7e3d71c66c8acc9bba35588b525"
   dependencies:
     "@webassemblyjs/ast" "1.5.13"
     "@webassemblyjs/helper-module-context" "1.5.13"

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác