Переглянути джерело

Merge pull request #280 from javascript-obfuscator/block-statement-instead-transformer-identifier

Block statement instead transformer identifier
Timofey Kachalov 7 роки тому
батько
коміт
828c541413
23 змінених файлів з 289 додано та 151 видалено
  1. 0 0
      dist/index.browser.js
  2. 0 0
      dist/index.cli.js
  3. 0 0
      dist/index.js
  4. 1 1
      src/JavaScriptObfuscator.ts
  5. 1 1
      src/analyzers/stack-trace-analyzer/StackTraceAnalyzer.ts
  6. 1 1
      src/analyzers/stack-trace-analyzer/callee-data-extractors/FunctionDeclarationCalleeDataExtractor.ts
  7. 1 1
      src/analyzers/stack-trace-analyzer/callee-data-extractors/FunctionExpressionCalleeDataExtractor.ts
  8. 1 1
      src/analyzers/stack-trace-analyzer/callee-data-extractors/ObjectExpressionCalleeDataExtractor.ts
  9. 6 4
      src/interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer.d.ts
  10. 5 2
      src/interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IObfuscatingReplacer.d.ts
  11. 2 16
      src/node-transformers/AbstractNodeTransformer.ts
  12. 2 2
      src/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.ts
  13. 17 9
      src/node-transformers/obfuscating-transformers/CatchClauseTransformer.ts
  14. 15 17
      src/node-transformers/obfuscating-transformers/ClassDeclarationTransformer.ts
  15. 17 19
      src/node-transformers/obfuscating-transformers/FunctionDeclarationTransformer.ts
  16. 15 10
      src/node-transformers/obfuscating-transformers/FunctionTransformer.ts
  17. 17 16
      src/node-transformers/obfuscating-transformers/ImportDeclarationTransformer.ts
  18. 17 9
      src/node-transformers/obfuscating-transformers/LabeledStatementTransformer.ts
  19. 26 23
      src/node-transformers/obfuscating-transformers/VariableDeclarationTransformer.ts
  20. 5 3
      src/node-transformers/obfuscating-transformers/obfuscating-replacers/AbstractObfuscatingReplacer.ts
  21. 28 13
      src/node-transformers/obfuscating-transformers/obfuscating-replacers/identifier-obfuscating-replacers/BaseIdentifierObfuscatingReplacer.ts
  22. 16 2
      src/node/NodeUtils.ts
  23. 96 1
      test/unit-tests/node/node-utils/NodeUtils.spec.ts

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
dist/index.browser.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 0
dist/index.cli.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 0
dist/index.js


+ 1 - 1
src/JavaScriptObfuscator.ts

@@ -126,7 +126,7 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator {
      */
     public obfuscate (sourceCode: string): IObfuscationResult {
         const timeStart: number = Date.now();
-        this.logger.info(LoggingMessage.Version, '0.16.0');
+        this.logger.info(LoggingMessage.Version, process.env.VERSION);
         this.logger.info(LoggingMessage.ObfuscationStarted);
         this.logger.info(LoggingMessage.RandomGeneratorSeed, this.randomGenerator.getSeed());
 

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

@@ -131,7 +131,7 @@ export class StackTraceAnalyzer implements IStackTraceAnalyzer {
                         return;
                     }
 
-                    if (blockScopeBodyNode.parentNode !== NodeUtils.getBlockScopesOfNode(node)[0]) {
+                    if (blockScopeBodyNode.parentNode !== NodeUtils.getBlockScopeOfNode(node)) {
                         return estraverse.VisitorOption.Skip;
                     }
 

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

@@ -22,7 +22,7 @@ export class FunctionDeclarationCalleeDataExtractor extends AbstractCalleeDataEx
         }
 
         const calleeBlockStatement: ESTree.BlockStatement | null = this.getCalleeBlockStatement(
-            NodeUtils.getBlockScopesOfNode(blockScopeBody[0])[0],
+            NodeUtils.getBlockScopeOfNode(blockScopeBody[0]),
             callee.name
         );
 

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

@@ -21,7 +21,7 @@ export class FunctionExpressionCalleeDataExtractor extends AbstractCalleeDataExt
 
         if (NodeGuards.isIdentifierNode(callee)) {
             calleeBlockStatement = this.getCalleeBlockStatement(
-                NodeUtils.getBlockScopesOfNode(blockScopeBody[0])[0],
+                NodeUtils.getBlockScopeOfNode(blockScopeBody[0]),
                 callee.name
             );
         }

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

@@ -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.getBlockScopesOfNode(blockScopeBody[0])[0],
+            NodeUtils.getBlockScopeOfNode(blockScopeBody[0]),
             objectMembersCallsChain
         );
 

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

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

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

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

+ 2 - 16
src/node-transformers/AbstractNodeTransformer.ts

@@ -1,27 +1,18 @@
-import { inject, injectable, postConstruct } from 'inversify';
+import { inject, injectable } from 'inversify';
 import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
 
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
-import { IInitializable } from '../interfaces/IInitializable';
 import { INodeTransformer } from '../interfaces/node-transformers/INodeTransformer';
 import { IOptions } from '../interfaces/options/IOptions';
 import { IRandomGenerator } from '../interfaces/utils/IRandomGenerator';
 import { IVisitor } from '../interfaces/node-transformers/IVisitor';
 
-import { initializable } from '../decorators/Initializable';
-
 import { TransformationStage } from '../enums/node-transformers/TransformationStage';
 
 @injectable()
-export abstract class AbstractNodeTransformer implements INodeTransformer, IInitializable {
-    /**
-     * @type {number}
-     */
-    @initializable()
-    protected nodeIdentifier!: number;
-
+export abstract class AbstractNodeTransformer implements INodeTransformer {
     /**
      * @type {IOptions}
      */
@@ -44,11 +35,6 @@ export abstract class AbstractNodeTransformer implements INodeTransformer, IInit
         this.options = options;
     }
 
-    @postConstruct()
-    public initialize (): void {
-        this.nodeIdentifier = this.randomGenerator.getRandomInteger(0, 10000);
-    }
-
     /**
      * @param {TransformationStage} transformationStage
      * @returns {IVisitor | null}

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

@@ -205,7 +205,7 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
         }
 
         const blockScopeOfBlockStatementNode: TNodeWithBlockScope = NodeUtils
-            .getBlockScopesOfNode(blockStatementNode)[0];
+            .getBlockScopeOfNode(blockStatementNode);
 
         return blockScopeOfBlockStatementNode.type !== NodeType.Program;
     }
@@ -345,7 +345,7 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
      * @param {BlockStatement} clonedBlockStatementNode
      * @returns {BlockStatement}
      */
-    private makeClonedBlockStatementNodeUnique(clonedBlockStatementNode: ESTree.BlockStatement): ESTree.BlockStatement {
+    private makeClonedBlockStatementNodeUnique (clonedBlockStatementNode: ESTree.BlockStatement): ESTree.BlockStatement {
         return this.transformersRunner.transform(
             clonedBlockStatementNode,
             DeadCodeInjectionTransformer.transformersToRenameBlockScopeIdentifiers,

+ 17 - 9
src/node-transformers/obfuscating-transformers/CatchClauseTransformer.ts

@@ -5,6 +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 { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer';
 import { IOptions } from '../../interfaces/options/IOptions';
@@ -17,6 +18,7 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeGuards } from '../../node/NodeGuards';
 import { NodeMetadata } from '../../node/NodeMetadata';
+import { NodeUtils } from '../../node/NodeUtils';
 
 /**
  * replaces:
@@ -77,34 +79,40 @@ export class CatchClauseTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (catchClauseNode: ESTree.CatchClause, parentNode: ESTree.Node): ESTree.Node {
-        const nodeIdentifier: number = this.nodeIdentifier++;
+        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopeOfNode(catchClauseNode);
 
-        this.storeCatchClauseParam(catchClauseNode, nodeIdentifier);
-        this.replaceCatchClauseParam(catchClauseNode, nodeIdentifier);
+        this.storeCatchClauseParam(catchClauseNode, blockScopeNode);
+        this.replaceCatchClauseParam(catchClauseNode, blockScopeNode);
 
         return catchClauseNode;
     }
 
     /**
      * @param {CatchClause} catchClauseNode
-     * @param {number} nodeIdentifier
+     * @param {TNodeWithBlockScope} blockScopeNode
      */
-    private storeCatchClauseParam (catchClauseNode: ESTree.CatchClause, nodeIdentifier: number): void {
+    private storeCatchClauseParam (
+        catchClauseNode: ESTree.CatchClause,
+        blockScopeNode: TNodeWithBlockScope
+    ): void {
         if (NodeGuards.isIdentifierNode(catchClauseNode.param)) {
-            this.identifierObfuscatingReplacer.storeLocalName(catchClauseNode.param.name, nodeIdentifier);
+            this.identifierObfuscatingReplacer.storeLocalName(catchClauseNode.param.name, blockScopeNode);
         }
     }
 
     /**
      * @param {CatchClause} catchClauseNode
-     * @param {number} nodeIdentifier
+     * @param {TNodeWithBlockScope} blockScopeNode
      */
-    private replaceCatchClauseParam (catchClauseNode: ESTree.CatchClause, nodeIdentifier: number): void {
+    private replaceCatchClauseParam (
+        catchClauseNode: ESTree.CatchClause,
+        blockScopeNode: TNodeWithBlockScope
+    ): 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, nodeIdentifier);
+                        .replace(node.name, blockScopeNode);
                     const newIdentifierName: string = newIdentifier.name;
 
                     if (node.name !== newIdentifierName) {

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

@@ -90,21 +90,20 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (classDeclarationNode: ESTree.ClassDeclaration, parentNode: ESTree.Node): ESTree.Node {
-        const nodeIdentifier: number = this.nodeIdentifier++;
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopesOfNode(classDeclarationNode)[0];
+        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopeOfNode(classDeclarationNode);
         const isGlobalDeclaration: boolean = blockScopeNode.type === NodeType.Program;
 
         if (!this.options.renameGlobals && isGlobalDeclaration) {
             return classDeclarationNode;
         }
 
-        this.storeClassName(classDeclarationNode, isGlobalDeclaration, nodeIdentifier);
+        this.storeClassName(classDeclarationNode, blockScopeNode, isGlobalDeclaration);
 
         // check for cached identifiers for current scope node. If exist - loop through them.
         if (this.replaceableIdentifiers.has(blockScopeNode)) {
-            this.replaceScopeCachedIdentifiers(blockScopeNode, nodeIdentifier);
+            this.replaceScopeCachedIdentifiers(blockScopeNode);
         } else {
-            this.replaceScopeIdentifiers(blockScopeNode, nodeIdentifier);
+            this.replaceScopeIdentifiers(blockScopeNode);
         }
 
         return classDeclarationNode;
@@ -112,31 +111,31 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {ClassDeclaration} classDeclarationNode
+     * @param {TNodeWithBlockScope} blockScopeNode
      * @param {boolean} isGlobalDeclaration
-     * @param {number} nodeIdentifier
      */
     private storeClassName (
         classDeclarationNode: ESTree.ClassDeclaration,
-        isGlobalDeclaration: boolean,
-        nodeIdentifier: number
+        blockScopeNode: TNodeWithBlockScope,
+        isGlobalDeclaration: boolean
     ): void {
         if (isGlobalDeclaration) {
-            this.identifierObfuscatingReplacer.storeGlobalName(classDeclarationNode.id.name, nodeIdentifier);
+            this.identifierObfuscatingReplacer.storeGlobalName(classDeclarationNode.id.name, blockScopeNode);
         } else {
-            this.identifierObfuscatingReplacer.storeLocalName(classDeclarationNode.id.name, nodeIdentifier);
+            this.identifierObfuscatingReplacer.storeLocalName(classDeclarationNode.id.name, blockScopeNode);
         }
     }
 
     /**
      * @param {TNodeWithBlockScope} blockScopeNode
-     * @param {number} nodeIdentifier
      */
-    private replaceScopeCachedIdentifiers (blockScopeNode: TNodeWithBlockScope, nodeIdentifier: number): void {
-        const cachedReplaceableIdentifiers: ESTree.Identifier[] = <ESTree.Identifier[]>this.replaceableIdentifiers.get(blockScopeNode);
+    private replaceScopeCachedIdentifiers (blockScopeNode: TNodeWithBlockScope): void {
+        const cachedReplaceableIdentifiers: ESTree.Identifier[] =
+            <ESTree.Identifier[]>this.replaceableIdentifiers.get(blockScopeNode);
 
         cachedReplaceableIdentifiers.forEach((replaceableIdentifier: ESTree.Identifier) => {
             const newReplaceableIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                .replace(replaceableIdentifier.name, nodeIdentifier);
+                .replace(replaceableIdentifier.name, blockScopeNode);
 
             replaceableIdentifier.name = newReplaceableIdentifier.name;
             NodeMetadata.set(replaceableIdentifier, { renamedIdentifier: true });
@@ -145,9 +144,8 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {TNodeWithBlockScope} blockScopeNode
-     * @param {number} nodeIdentifier
      */
-    private replaceScopeIdentifiers (blockScopeNode: TNodeWithBlockScope, nodeIdentifier: number): void {
+    private replaceScopeIdentifiers (blockScopeNode: TNodeWithBlockScope): void {
         const storedReplaceableIdentifiers: ESTree.Identifier[] = [];
 
         estraverse.replace(blockScopeNode, {
@@ -158,7 +156,7 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
                     && !NodeMetadata.isRenamedIdentifier(node)
                 ) {
                     const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                        .replace(node.name, nodeIdentifier);
+                        .replace(node.name, blockScopeNode);
                     const newIdentifierName: string = newIdentifier.name;
 
                     if (node.name !== newIdentifierName) {

+ 17 - 19
src/node-transformers/obfuscating-transformers/FunctionDeclarationTransformer.ts

@@ -92,21 +92,20 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (functionDeclarationNode: ESTree.FunctionDeclaration, parentNode: ESTree.Node): ESTree.Node {
-        const nodeIdentifier: number = this.nodeIdentifier++;
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopesOfNode(functionDeclarationNode)[0];
+        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopeOfNode(functionDeclarationNode);
         const isGlobalDeclaration: boolean = blockScopeNode.type === NodeType.Program;
 
         if (!this.options.renameGlobals && isGlobalDeclaration) {
             return functionDeclarationNode;
         }
 
-        this.storeFunctionName(functionDeclarationNode, isGlobalDeclaration, nodeIdentifier);
+        this.storeFunctionName(functionDeclarationNode, blockScopeNode, isGlobalDeclaration);
 
         // check for cached identifiers for current scope node. If exist - loop through them.
         if (this.replaceableIdentifiers.has(blockScopeNode)) {
-            this.replaceScopeCachedIdentifiers(functionDeclarationNode, blockScopeNode, nodeIdentifier);
+            this.replaceScopeCachedIdentifiers(functionDeclarationNode, blockScopeNode);
         } else {
-            this.replaceScopeIdentifiers(blockScopeNode, nodeIdentifier);
+            this.replaceScopeIdentifiers(blockScopeNode);
         }
 
         return functionDeclarationNode;
@@ -114,32 +113,31 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {FunctionDeclaration} functionDeclarationNode
+     * @param {TNodeWithBlockScope} blockScopeNode
      * @param {boolean} isGlobalDeclaration
-     * @param {number} nodeIdentifier
      */
     private storeFunctionName (
         functionDeclarationNode: ESTree.FunctionDeclaration,
-        isGlobalDeclaration: boolean,
-        nodeIdentifier: number
+        blockScopeNode: TNodeWithBlockScope,
+        isGlobalDeclaration: boolean
     ): void {
         if (isGlobalDeclaration) {
-            this.identifierObfuscatingReplacer.storeGlobalName(functionDeclarationNode.id.name, nodeIdentifier);
+            this.identifierObfuscatingReplacer.storeGlobalName(functionDeclarationNode.id.name, blockScopeNode);
         } else {
-            this.identifierObfuscatingReplacer.storeLocalName(functionDeclarationNode.id.name, nodeIdentifier);
+            this.identifierObfuscatingReplacer.storeLocalName(functionDeclarationNode.id.name, blockScopeNode);
         }
     }
 
     /**
      * @param {FunctionDeclaration} functionDeclarationNode
      * @param {TNodeWithBlockScope} blockScopeNode
-     * @param {number} nodeIdentifier
      */
     private replaceScopeCachedIdentifiers (
         functionDeclarationNode: ESTree.FunctionDeclaration,
-        blockScopeNode: TNodeWithBlockScope,
-        nodeIdentifier: number
+        blockScopeNode: TNodeWithBlockScope
     ): void {
-        const cachedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames | undefined = this.replaceableIdentifiers.get(blockScopeNode);
+        const cachedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames | undefined =
+            this.replaceableIdentifiers.get(blockScopeNode);
 
         if (!cachedReplaceableIdentifiersNamesMap) {
             return;
@@ -157,7 +155,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, nodeIdentifier);
+                .replace(replaceableIdentifier.name, blockScopeNode);
 
             replaceableIdentifier.name = newReplaceableIdentifier.name;
             NodeMetadata.set(replaceableIdentifier, { renamedIdentifier: true });
@@ -166,9 +164,8 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {TNodeWithBlockScope} blockScopeNode
-     * @param {number} nodeIdentifier
      */
-    private replaceScopeIdentifiers (blockScopeNode: TNodeWithBlockScope, nodeIdentifier: number): void {
+    private replaceScopeIdentifiers (blockScopeNode: TNodeWithBlockScope): void {
         const storedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames = new Map();
 
         estraverse.replace(blockScopeNode, {
@@ -179,14 +176,15 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
                     && !NodeMetadata.isRenamedIdentifier(node)
                 ) {
                     const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                        .replace(node.name, nodeIdentifier);
+                        .replace(node.name, blockScopeNode);
                     const newIdentifierName: string = newIdentifier.name;
 
                     if (node.name !== newIdentifierName) {
                         node.name = newIdentifierName;
                         NodeMetadata.set(node, { renamedIdentifier: true });
                     } else {
-                        const storedReplaceableIdentifiers: ESTree.Identifier[] = storedReplaceableIdentifiersNamesMap.get(node.name) || [];
+                        const storedReplaceableIdentifiers: ESTree.Identifier[] =
+                            storedReplaceableIdentifiersNamesMap.get(node.name) || [];
 
                         storedReplaceableIdentifiers.push(node);
                         storedReplaceableIdentifiersNamesMap.set(node.name, storedReplaceableIdentifiers);

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

@@ -5,6 +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 { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer';
 import { IOptions } from '../../interfaces/options/IOptions';
@@ -17,6 +18,7 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeGuards } from '../../node/NodeGuards';
 import { NodeMetadata } from '../../node/NodeMetadata';
+import { NodeUtils } from '../../node/NodeUtils';
 
 /**
  * replaces:
@@ -83,19 +85,21 @@ export class FunctionTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (functionNode: ESTree.Function, parentNode: ESTree.Node): ESTree.Node {
-        const nodeIdentifier: number = this.nodeIdentifier++;
+        const blockScopeNode: TNodeWithBlockScope = NodeGuards.isBlockStatementNode(functionNode.body)
+            ? functionNode.body
+            : NodeUtils.getBlockScopeOfNode(functionNode.body);
 
-        this.storeFunctionParams(functionNode, nodeIdentifier);
-        this.replaceFunctionParams(functionNode, nodeIdentifier);
+        this.storeFunctionParams(functionNode, blockScopeNode);
+        this.replaceFunctionParams(functionNode, blockScopeNode);
 
         return functionNode;
     }
 
     /**
      * @param {Function} functionNode
-     * @param {number} nodeIdentifier
+     * @param {TNodeWithBlockScope} blockScopeNode
      */
-    private storeFunctionParams (functionNode: ESTree.Function, nodeIdentifier: number): void {
+    private storeFunctionParams (functionNode: ESTree.Function, blockScopeNode: TNodeWithBlockScope): void {
         functionNode.params
             .forEach((paramsNode: ESTree.Node) => {
                 estraverse.traverse(paramsNode, {
@@ -105,13 +109,13 @@ export class FunctionTransformer extends AbstractNodeTransformer {
                         }
 
                         if (NodeGuards.isAssignmentPatternNode(node) && NodeGuards.isIdentifierNode(node.left)) {
-                            this.identifierObfuscatingReplacer.storeLocalName(node.left.name, nodeIdentifier);
+                            this.identifierObfuscatingReplacer.storeLocalName(node.left.name, blockScopeNode);
 
                             return estraverse.VisitorOption.Skip;
                         }
 
                         if (NodeGuards.isIdentifierNode(node)) {
-                            this.identifierObfuscatingReplacer.storeLocalName(node.name, nodeIdentifier);
+                            this.identifierObfuscatingReplacer.storeLocalName(node.name, blockScopeNode);
                         }
                     }
                 });
@@ -137,9 +141,9 @@ export class FunctionTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {Function} functionNode
-     * @param {number} nodeIdentifier
+     * @param {TNodeWithBlockScope} blockScopeNode
      */
-    private replaceFunctionParams (functionNode: ESTree.Function, nodeIdentifier: number): void {
+    private replaceFunctionParams (functionNode: ESTree.Function, blockScopeNode: TNodeWithBlockScope): void {
         const ignoredIdentifierNamesSet: Set<string> = new Set();
 
         const replaceVisitor: estraverse.Visitor = {
@@ -153,7 +157,8 @@ export class FunctionTransformer extends AbstractNodeTransformer {
                     NodeGuards.isReplaceableIdentifierNode(node, parentNode) &&
                     !ignoredIdentifierNamesSet.has(node.name)
                 ) {
-                    const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer.replace(node.name, nodeIdentifier);
+                    const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
+                        .replace(node.name, blockScopeNode);
                     const newIdentifierName: string = newIdentifier.name;
 
                     if (node.name !== newIdentifierName) {

+ 17 - 16
src/node-transformers/obfuscating-transformers/ImportDeclarationTransformer.ts

@@ -95,45 +95,47 @@ export class ImportDeclarationTransformer extends AbstractNodeTransformer {
      * @returns {Node}
      */
     public transformNode (importDeclarationNode: ESTree.ImportDeclaration, parentNode: ESTree.Node): ESTree.Node {
-        const nodeIdentifier: number = this.nodeIdentifier++;
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopesOfNode(importDeclarationNode)[0];
+        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopeOfNode(importDeclarationNode);
 
-        this.storeImportSpecifierNames(importDeclarationNode, nodeIdentifier);
+        this.storeImportSpecifierNames(importDeclarationNode, blockScopeNode);
 
         // check for cached identifiers for current scope node. If exist - loop through them.
         if (this.replaceableIdentifiers.has(blockScopeNode)) {
-            this.replaceScopeCachedIdentifiers(blockScopeNode, nodeIdentifier);
+            this.replaceScopeCachedIdentifiers(blockScopeNode);
         } else {
-            this.replaceScopeIdentifiers(blockScopeNode, nodeIdentifier);
+            this.replaceScopeIdentifiers(blockScopeNode);
         }
 
         return importDeclarationNode;
     }
 
     /**
-     * @param {ImportDefaultSpecifier | ImportNamespaceSpecifier} importDeclarationNode
-     * @param {number} nodeIdentifier
+     * @param {ImportDeclaration} importDeclarationNode
+     * @param {TNodeWithBlockScope} blockScopeNode
      */
-    private storeImportSpecifierNames (importDeclarationNode: ESTree.ImportDeclaration, nodeIdentifier: number): void {
+    private storeImportSpecifierNames (
+        importDeclarationNode: ESTree.ImportDeclaration,
+        blockScopeNode: TNodeWithBlockScope
+    ): void {
         importDeclarationNode.specifiers.forEach((importSpecifierNode: TImportSpecifier) => {
             if (ImportDeclarationTransformer.isProhibitedImportSpecifierNode(importSpecifierNode)) {
                 return;
             }
 
-            this.identifierObfuscatingReplacer.storeGlobalName(importSpecifierNode.local.name, nodeIdentifier);
+            this.identifierObfuscatingReplacer.storeGlobalName(importSpecifierNode.local.name, blockScopeNode);
         });
     }
 
     /**
      * @param {TNodeWithBlockScope} blockScopeNode
-     * @param {number} nodeIdentifier
      */
-    private replaceScopeCachedIdentifiers (blockScopeNode: TNodeWithBlockScope, nodeIdentifier: number): void {
-        const cachedReplaceableIdentifiers: ESTree.Identifier[] = <ESTree.Identifier[]>this.replaceableIdentifiers.get(blockScopeNode);
+    private replaceScopeCachedIdentifiers (blockScopeNode: TNodeWithBlockScope): void {
+        const cachedReplaceableIdentifiers: ESTree.Identifier[] =
+            <ESTree.Identifier[]>this.replaceableIdentifiers.get(blockScopeNode);
 
         cachedReplaceableIdentifiers.forEach((replaceableIdentifier: ESTree.Identifier) => {
             const newReplaceableIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                .replace(replaceableIdentifier.name, nodeIdentifier);
+                .replace(replaceableIdentifier.name, blockScopeNode);
 
             replaceableIdentifier.name = newReplaceableIdentifier.name;
             NodeMetadata.set(replaceableIdentifier, { renamedIdentifier: true });
@@ -142,9 +144,8 @@ export class ImportDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {TNodeWithBlockScope} blockScopeNode
-     * @param {number} nodeIdentifier
      */
-    private replaceScopeIdentifiers (blockScopeNode: TNodeWithBlockScope, nodeIdentifier: number): void {
+    private replaceScopeIdentifiers (blockScopeNode: TNodeWithBlockScope): void {
         const storedReplaceableIdentifiers: ESTree.Identifier[] = [];
 
         estraverse.replace(blockScopeNode, {
@@ -155,7 +156,7 @@ export class ImportDeclarationTransformer extends AbstractNodeTransformer {
                     && !NodeMetadata.isRenamedIdentifier(node)
                 ) {
                     const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                        .replace(node.name, nodeIdentifier);
+                        .replace(node.name, blockScopeNode);
                     const newIdentifierName: string = newIdentifier.name;
 
                     if (node.name !== newIdentifierName) {

+ 17 - 9
src/node-transformers/obfuscating-transformers/LabeledStatementTransformer.ts

@@ -16,6 +16,8 @@ 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';
 
 /**
  * replaces:
@@ -84,32 +86,38 @@ export class LabeledStatementTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (labeledStatementNode: ESTree.LabeledStatement, parentNode: ESTree.Node): ESTree.Node {
-        const nodeIdentifier: number = this.nodeIdentifier++;
+        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopeOfNode(labeledStatementNode);
 
-        this.storeLabeledStatementName(labeledStatementNode, nodeIdentifier);
-        this.replaceLabeledStatementName(labeledStatementNode, nodeIdentifier);
+        this.storeLabeledStatementName(labeledStatementNode, blockScopeNode);
+        this.replaceLabeledStatementName(labeledStatementNode, blockScopeNode);
 
         return labeledStatementNode;
     }
 
     /**
      * @param {LabeledStatement} labeledStatementNode
-     * @param {number} nodeIdentifier
+     * @param {TNodeWithBlockScope} blockScopeNode
      */
-    private storeLabeledStatementName (labeledStatementNode: ESTree.LabeledStatement, nodeIdentifier: number): void {
-        this.identifierObfuscatingReplacer.storeLocalName(labeledStatementNode.label.name, nodeIdentifier);
+    private storeLabeledStatementName (
+        labeledStatementNode: ESTree.LabeledStatement,
+        blockScopeNode: TNodeWithBlockScope
+    ): void {
+        this.identifierObfuscatingReplacer.storeLocalName(labeledStatementNode.label.name, blockScopeNode);
     }
 
     /**
      * @param {LabeledStatement} labeledStatementNode
-     * @param {number} nodeIdentifier
+     * @param {TNodeWithBlockScope} blockScopeNode
      */
-    private replaceLabeledStatementName (labeledStatementNode: ESTree.LabeledStatement, nodeIdentifier: number): void {
+    private replaceLabeledStatementName (
+        labeledStatementNode: ESTree.LabeledStatement,
+        blockScopeNode: TNodeWithBlockScope
+    ): 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, nodeIdentifier);
+                        .replace(node.name, blockScopeNode);
 
                     node.name = newIdentifier.name;
                 }

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

@@ -93,25 +93,24 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (variableDeclarationNode: ESTree.VariableDeclaration, parentNode: ESTree.Node): ESTree.Node {
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopesOfNode(variableDeclarationNode)[0];
+        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopeOfNode(variableDeclarationNode);
         const isGlobalDeclaration: boolean = blockScopeNode.type === NodeType.Program;
 
         if (!this.options.renameGlobals && isGlobalDeclaration) {
             return variableDeclarationNode;
         }
 
-        const nodeIdentifier: number = this.nodeIdentifier++;
         const scopeNode: ESTree.Node = variableDeclarationNode.kind === 'var'
             ? blockScopeNode
             : parentNode;
 
-        this.storeVariableNames(variableDeclarationNode, isGlobalDeclaration, nodeIdentifier);
+        this.storeVariableNames(variableDeclarationNode, blockScopeNode, isGlobalDeclaration);
 
         // check for cached identifiers for current scope node. If exist - loop through them.
         if (this.replaceableIdentifiers.has(scopeNode)) {
-            this.replaceScopeCachedIdentifiers(variableDeclarationNode, scopeNode, nodeIdentifier);
+            this.replaceScopeCachedIdentifiers(variableDeclarationNode, blockScopeNode, scopeNode);
         } else {
-            this.replaceScopeIdentifiers(scopeNode, nodeIdentifier);
+            this.replaceScopeIdentifiers(scopeNode, blockScopeNode);
         }
 
         return variableDeclarationNode;
@@ -119,34 +118,35 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {VariableDeclaration} variableDeclarationNode
+     * @param {TNodeWithBlockScope} blockScopeNode
      * @param {boolean} isGlobalDeclaration
-     * @param {number} nodeIdentifier
      */
     private storeVariableNames (
         variableDeclarationNode: ESTree.VariableDeclaration,
-        isGlobalDeclaration: boolean,
-        nodeIdentifier: number
+        blockScopeNode: TNodeWithBlockScope,
+        isGlobalDeclaration: boolean
     ): void {
         this.traverseDeclarationIdentifiers(variableDeclarationNode, (identifierNode: ESTree.Identifier) => {
             if (isGlobalDeclaration) {
-                this.identifierObfuscatingReplacer.storeGlobalName(identifierNode.name, nodeIdentifier);
+                this.identifierObfuscatingReplacer.storeGlobalName(identifierNode.name, blockScopeNode);
             } else {
-                this.identifierObfuscatingReplacer.storeLocalName(identifierNode.name, nodeIdentifier);
+                this.identifierObfuscatingReplacer.storeLocalName(identifierNode.name, blockScopeNode);
             }
         });
     }
 
     /**
      * @param {VariableDeclaration} variableDeclarationNode
+     * @param {TNodeWithBlockScope} blockScopeNode
      * @param {Node} scopeNode
-     * @param {number} nodeIdentifier
      */
     private replaceScopeCachedIdentifiers (
         variableDeclarationNode: ESTree.VariableDeclaration,
-        scopeNode: ESTree.Node,
-        nodeIdentifier: number
+        blockScopeNode: TNodeWithBlockScope,
+        scopeNode: ESTree.Node
     ): void {
-        const cachedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames | undefined = this.replaceableIdentifiers.get(scopeNode);
+        const cachedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames | undefined =
+            this.replaceableIdentifiers.get(scopeNode);
 
         if (!cachedReplaceableIdentifiersNamesMap) {
             return;
@@ -159,7 +159,8 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
         });
 
         identifierNames.forEach((identifierName: string) => {
-            const cachedReplaceableIdentifiers: ESTree.Identifier[] | undefined = cachedReplaceableIdentifiersNamesMap.get(identifierName);
+            const cachedReplaceableIdentifiers: ESTree.Identifier[] | undefined =
+                cachedReplaceableIdentifiersNamesMap.get(identifierName);
 
             if (!cachedReplaceableIdentifiers) {
                 return;
@@ -175,7 +176,7 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
                 }
 
                 const newReplaceableIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
-                    .replace(replaceableIdentifier.name, nodeIdentifier);
+                    .replace(replaceableIdentifier.name, blockScopeNode);
 
                 replaceableIdentifier.name = newReplaceableIdentifier.name;
                 NodeMetadata.set(replaceableIdentifier, { renamedIdentifier: true });
@@ -184,27 +185,29 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
     }
 
     /**
-     * @param {NodeGuards} blockScopeNode
-     * @param {number} nodeIdentifier
+     * @param {Node} scopeNode
+     * @param {TNodeWithBlockScope} blockScopeNode
      */
-    private replaceScopeIdentifiers (blockScopeNode: ESTree.Node, nodeIdentifier: number): void {
+    private replaceScopeIdentifiers (scopeNode: ESTree.Node, blockScopeNode: TNodeWithBlockScope): void {
         const storedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames = new Map();
 
-        estraverse.replace(blockScopeNode, {
+        estraverse.replace(scopeNode, {
             enter: (node: ESTree.Node, parentNode: ESTree.Node | null): void => {
                 if (
                     parentNode
                     && NodeGuards.isReplaceableIdentifierNode(node, parentNode)
                     && !NodeMetadata.isRenamedIdentifier(node)
                 ) {
-                    const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer.replace(node.name, nodeIdentifier);
+                    const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
+                        .replace(node.name, blockScopeNode);
                     const newIdentifierName: string = newIdentifier.name;
 
                     if (node.name !== newIdentifierName) {
                         node.name = newIdentifierName;
                         NodeMetadata.set(node, { renamedIdentifier: true });
                     } else {
-                        const storedReplaceableIdentifiers: ESTree.Identifier[] = storedReplaceableIdentifiersNamesMap.get(node.name) || [];
+                        const storedReplaceableIdentifiers: ESTree.Identifier[] =
+                            storedReplaceableIdentifiersNamesMap.get(node.name) || [];
 
                         storedReplaceableIdentifiers.push(node);
                         storedReplaceableIdentifiersNamesMap.set(node.name, storedReplaceableIdentifiers);
@@ -213,7 +216,7 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
             }
         });
 
-        this.replaceableIdentifiers.set(blockScopeNode, storedReplaceableIdentifiersNamesMap);
+        this.replaceableIdentifiers.set(scopeNode, storedReplaceableIdentifiersNamesMap);
     }
 
     /**

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

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

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

@@ -4,6 +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 { IIdentifierNamesGenerator } from '../../../../interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
 import { IIdentifierObfuscatingReplacer } from '../../../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer';
@@ -20,9 +21,9 @@ export class BaseIdentifierObfuscatingReplacer extends AbstractObfuscatingReplac
     private readonly identifierNamesGenerator: IIdentifierNamesGenerator;
 
     /**
-     * @type {Map<string, string>}
+     * @type {Map<TNodeWithBlockScope, Map<string, string>>}
      */
-    private readonly namesMap: Map<string, string> = new Map();
+    private readonly blockScopesMap: Map<TNodeWithBlockScope, Map<string, string>> = new Map();
 
     /**
      * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
@@ -40,14 +41,16 @@ export class BaseIdentifierObfuscatingReplacer extends AbstractObfuscatingReplac
 
     /**
      * @param {string} nodeValue
-     * @param {number} nodeIdentifier
+     * @param {TNodeWithBlockScope} blockScopeNode
      * @returns {Identifier}
      */
-    public replace (nodeValue: string, nodeIdentifier: number): ESTree.Identifier {
-        const mapKey: string = `${nodeValue}-${String(nodeIdentifier)}`;
+    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);
 
-        if (this.namesMap.has(mapKey)) {
-            nodeValue = <string>this.namesMap.get(mapKey);
+            if (namesMap.has(nodeValue)) {
+                nodeValue = <string>namesMap.get(nodeValue);
+            }
         }
 
         return NodeFactory.identifierNode(nodeValue);
@@ -58,16 +61,22 @@ export class BaseIdentifierObfuscatingReplacer extends AbstractObfuscatingReplac
      * Reserved name will be ignored.
      *
      * @param {string} nodeName
-     * @param {number} nodeIdentifier
+     * @param {TNodeWithBlockScope} blockScopeNode
      */
-    public storeGlobalName (nodeName: string, nodeIdentifier: number): void {
+    public storeGlobalName (nodeName: string, blockScopeNode: TNodeWithBlockScope): void {
         if (this.isReservedName(nodeName)) {
             return;
         }
 
         const identifierName: string = this.identifierNamesGenerator.generateWithPrefix();
 
-        this.namesMap.set(`${nodeName}-${String(nodeIdentifier)}`, identifierName);
+        if (!this.blockScopesMap.has(blockScopeNode)) {
+            this.blockScopesMap.set(blockScopeNode, new Map());
+        }
+
+        const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(blockScopeNode);
+
+        namesMap.set(nodeName, identifierName);
     }
 
     /**
@@ -75,16 +84,22 @@ export class BaseIdentifierObfuscatingReplacer extends AbstractObfuscatingReplac
      * Reserved name will be ignored.
      *
      * @param {string} nodeName
-     * @param {number} nodeIdentifier
+     * @param {TNodeWithBlockScope} blockScopeNode
      */
-    public storeLocalName (nodeName: string, nodeIdentifier: number): void {
+    public storeLocalName (nodeName: string, blockScopeNode: TNodeWithBlockScope): void {
         if (this.isReservedName(nodeName)) {
             return;
         }
 
         const identifierName: string = this.identifierNamesGenerator.generate();
 
-        this.namesMap.set(`${nodeName}-${String(nodeIdentifier)}`, identifierName);
+        if (!this.blockScopesMap.has(blockScopeNode)) {
+            this.blockScopesMap.set(blockScopeNode, new Map());
+        }
+
+        const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(blockScopeNode);
+
+        namesMap.set(nodeName, identifierName);
     }
 
     /**

+ 16 - 2
src/node/NodeUtils.ts

@@ -69,6 +69,14 @@ 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[]}
@@ -206,17 +214,23 @@ 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) {
@@ -248,7 +262,7 @@ export class NodeUtils {
         }
 
         if (node !== parentNode) {
-            return NodeUtils.getBlockScopesOfNodeRecursive(parentNode, blockScopes, ++depth);
+            return NodeUtils.getBlockScopesOfNodeRecursive(parentNode, maxSize, blockScopes, ++depth);
         }
 
         return blockScopes;

+ 96 - 1
test/unit-tests/node/node-utils/NodeUtils.spec.ts

@@ -181,6 +181,101 @@ 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,
@@ -239,7 +334,7 @@ describe('NodeUtils', () => {
             expressionStatementNode3.parentNode = ifStatementBlockStatementNode2;
         });
 
-        it('should return block-scope node for `program` node child', () => {
+        it('should return block-scope node for `program` node child node', () => {
             assert.deepEqual(NodeUtils.getBlockScopesOfNode(programNode)[0], programNode);
         });
 

Деякі файли не було показано, через те що забагато файлів було змінено