sanex3339 8 gadi atpakaļ
vecāks
revīzija
e0c46e091b

+ 86 - 91
dist/index.js

@@ -232,14 +232,12 @@ var NodeUtils = function () {
     _createClass(NodeUtils, null, [{
         key: 'addXVerbatimPropertyToLiterals',
         value: function addXVerbatimPropertyToLiterals(node) {
-            estraverse.replace(node, {
-                enter: function enter(node, parentNode) {
-                    if (Nodes_1.Nodes.isLiteralNode(node)) {
-                        node['x-verbatim-property'] = {
-                            content: node.raw,
-                            precedence: escodegen.Precedence.Primary
-                        };
-                    }
+            NodeUtils.typedReplace(node, NodeType_1.NodeType.Literal, {
+                leave: function leave(node) {
+                    node['x-verbatim-property'] = {
+                        content: node.raw,
+                        precedence: escodegen.Precedence.Primary
+                    };
                 }
             });
         }
@@ -335,6 +333,29 @@ var NodeUtils = function () {
             }
             blockScopeBody.unshift(node);
         }
+    }, {
+        key: 'typedReplace',
+        value: function typedReplace(node, nodeType, visitor) {
+            NodeUtils.typedTraverse(node, nodeType, visitor, 'replace');
+        }
+    }, {
+        key: 'typedTraverse',
+        value: function typedTraverse(node, nodeType, visitor) {
+            var traverseType = arguments.length <= 3 || arguments[3] === undefined ? 'traverse' : arguments[3];
+
+            estraverse[traverseType](node, {
+                enter: function enter(node) {
+                    if (node.type === nodeType && visitor.enter) {
+                        visitor.enter(node);
+                    }
+                },
+                leave: function leave(node) {
+                    if (node.type === nodeType && visitor.leave) {
+                        visitor.leave(node);
+                    }
+                }
+            });
+        }
     }, {
         key: 'validateNode',
         value: function validateNode(node) {
@@ -508,44 +529,19 @@ module.exports = require("estraverse");
 
 /***/ },
 /* 6 */
-/***/ function(module, exports, __webpack_require__) {
+/***/ function(module, exports) {
 
 "use strict";
 "use strict";
 
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var Nodes_1 = __webpack_require__(2);
-var Utils_1 = __webpack_require__(0);
+var AbstractNodeObfuscator = function AbstractNodeObfuscator(nodes, options) {
+    _classCallCheck(this, AbstractNodeObfuscator);
 
-var AbstractNodeObfuscator = function () {
-    function AbstractNodeObfuscator(nodes, options) {
-        _classCallCheck(this, AbstractNodeObfuscator);
-
-        this.nodes = nodes;
-        this.options = options;
-    }
-
-    _createClass(AbstractNodeObfuscator, [{
-        key: "isReservedName",
-        value: function isReservedName(name) {
-            return this.options.reservedNames.some(function (reservedName) {
-                return new RegExp(reservedName, 'g').test(name);
-            });
-        }
-    }, {
-        key: "storeIdentifiersNames",
-        value: function storeIdentifiersNames(node, namesMap) {
-            if (Nodes_1.Nodes.isIdentifierNode(node) && !this.isReservedName(node.name)) {
-                namesMap.set(node.name, Utils_1.Utils.getRandomVariableName());
-            }
-        }
-    }]);
-
-    return AbstractNodeObfuscator;
-}();
+    this.nodes = nodes;
+    this.options = options;
+};
 
 exports.AbstractNodeObfuscator = AbstractNodeObfuscator;
 
@@ -716,6 +712,7 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
 
 var AbstractReplacer_1 = __webpack_require__(13);
+var Utils_1 = __webpack_require__(0);
 
 var IdentifierReplacer = function (_AbstractReplacer_1$A) {
     _inherits(IdentifierReplacer, _AbstractReplacer_1$A);
@@ -735,6 +732,20 @@ var IdentifierReplacer = function (_AbstractReplacer_1$A) {
             }
             return obfuscatedIdentifierName;
         }
+    }, {
+        key: "storeNames",
+        value: function storeNames(nodeName, namesMap) {
+            if (!this.isReservedName(nodeName)) {
+                namesMap.set(nodeName, Utils_1.Utils.getRandomVariableName());
+            }
+        }
+    }, {
+        key: "isReservedName",
+        value: function isReservedName(name) {
+            return this.options.reservedNames.some(function (reservedName) {
+                return new RegExp(reservedName, 'g').test(name);
+            });
+        }
     }]);
 
     return IdentifierReplacer;
@@ -2362,54 +2373,51 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
 
 var estraverse = __webpack_require__(5);
+var NodeType_1 = __webpack_require__(7);
 var AbstractNodeObfuscator_1 = __webpack_require__(6);
 var IdentifierReplacer_1 = __webpack_require__(14);
 var Nodes_1 = __webpack_require__(2);
+var NodeUtils_1 = __webpack_require__(1);
 
 var CatchClauseObfuscator = function (_AbstractNodeObfuscat) {
     _inherits(CatchClauseObfuscator, _AbstractNodeObfuscat);
 
-    function CatchClauseObfuscator() {
-        var _Object$getPrototypeO;
-
+    function CatchClauseObfuscator(nodes, options) {
         _classCallCheck(this, CatchClauseObfuscator);
 
-        for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
-            args[_key] = arguments[_key];
-        }
-
-        var _this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(CatchClauseObfuscator)).call.apply(_Object$getPrototypeO, [this].concat(args)));
+        var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(CatchClauseObfuscator).call(this, nodes, options));
 
         _this.catchClauseParam = new Map();
+        _this.identifierReplacer = new IdentifierReplacer_1.IdentifierReplacer(_this.nodes, _this.options);
         return _this;
     }
 
     _createClass(CatchClauseObfuscator, [{
-        key: 'obfuscateNode',
+        key: "obfuscateNode",
         value: function obfuscateNode(catchClauseNode) {
             this.storeCatchClauseParam(catchClauseNode);
             this.replaceCatchClauseParam(catchClauseNode);
         }
     }, {
-        key: 'storeCatchClauseParam',
+        key: "storeCatchClauseParam",
         value: function storeCatchClauseParam(catchClauseNode) {
             var _this2 = this;
 
-            estraverse.traverse(catchClauseNode.param, {
+            NodeUtils_1.NodeUtils.typedReplace(catchClauseNode.param, NodeType_1.NodeType.Identifier, {
                 leave: function leave(node) {
-                    return _this2.storeIdentifiersNames(node, _this2.catchClauseParam);
+                    _this2.identifierReplacer.storeNames(node.name, _this2.catchClauseParam);
                 }
             });
         }
     }, {
-        key: 'replaceCatchClauseParam',
+        key: "replaceCatchClauseParam",
         value: function replaceCatchClauseParam(catchClauseNode) {
             var _this3 = this;
 
             estraverse.replace(catchClauseNode, {
                 leave: function leave(node, parentNode) {
                     if (Nodes_1.Nodes.isReplaceableIdentifierNode(node, parentNode)) {
-                        node.name = new IdentifierReplacer_1.IdentifierReplacer(_this3.nodes, _this3.options).replace(node.name, _this3.catchClauseParam);
+                        node.name = _this3.identifierReplacer.replace(node.name, _this3.catchClauseParam);
                     }
                 }
             });
@@ -2446,18 +2454,13 @@ var NodeUtils_1 = __webpack_require__(1);
 var FunctionDeclarationObfuscator = function (_AbstractNodeObfuscat) {
     _inherits(FunctionDeclarationObfuscator, _AbstractNodeObfuscat);
 
-    function FunctionDeclarationObfuscator() {
-        var _Object$getPrototypeO;
-
+    function FunctionDeclarationObfuscator(nodes, options) {
         _classCallCheck(this, FunctionDeclarationObfuscator);
 
-        for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
-            args[_key] = arguments[_key];
-        }
-
-        var _this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(FunctionDeclarationObfuscator)).call.apply(_Object$getPrototypeO, [this].concat(args)));
+        var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(FunctionDeclarationObfuscator).call(this, nodes, options));
 
         _this.functionName = new Map();
+        _this.identifierReplacer = new IdentifierReplacer_1.IdentifierReplacer(_this.nodes, _this.options);
         return _this;
     }
 
@@ -2475,9 +2478,9 @@ var FunctionDeclarationObfuscator = function (_AbstractNodeObfuscat) {
         value: function storeFunctionName(functionDeclarationNode) {
             var _this2 = this;
 
-            estraverse.traverse(functionDeclarationNode.id, {
+            NodeUtils_1.NodeUtils.typedReplace(functionDeclarationNode.id, NodeType_1.NodeType.Identifier, {
                 leave: function leave(node) {
-                    return _this2.storeIdentifiersNames(node, _this2.functionName);
+                    _this2.identifierReplacer.storeNames(node.name, _this2.functionName);
                 }
             });
         }
@@ -2490,7 +2493,7 @@ var FunctionDeclarationObfuscator = function (_AbstractNodeObfuscat) {
             estraverse.replace(scopeNode, {
                 enter: function enter(node, parentNode) {
                     if (Nodes_1.Nodes.isReplaceableIdentifierNode(node, parentNode)) {
-                        node.name = new IdentifierReplacer_1.IdentifierReplacer(_this3.nodes, _this3.options).replace(node.name, _this3.functionName);
+                        node.name = _this3.identifierReplacer.replace(node.name, _this3.functionName);
                     }
                 }
             });
@@ -2518,56 +2521,53 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
 
 var estraverse = __webpack_require__(5);
+var NodeType_1 = __webpack_require__(7);
 var AbstractNodeObfuscator_1 = __webpack_require__(6);
 var IdentifierReplacer_1 = __webpack_require__(14);
 var Nodes_1 = __webpack_require__(2);
+var NodeUtils_1 = __webpack_require__(1);
 
 var FunctionObfuscator = function (_AbstractNodeObfuscat) {
     _inherits(FunctionObfuscator, _AbstractNodeObfuscat);
 
-    function FunctionObfuscator() {
-        var _Object$getPrototypeO;
-
+    function FunctionObfuscator(nodes, options) {
         _classCallCheck(this, FunctionObfuscator);
 
-        for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
-            args[_key] = arguments[_key];
-        }
-
-        var _this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(FunctionObfuscator)).call.apply(_Object$getPrototypeO, [this].concat(args)));
+        var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(FunctionObfuscator).call(this, nodes, options));
 
         _this.functionParams = new Map();
+        _this.identifierReplacer = new IdentifierReplacer_1.IdentifierReplacer(_this.nodes, _this.options);
         return _this;
     }
 
     _createClass(FunctionObfuscator, [{
-        key: 'obfuscateNode',
+        key: "obfuscateNode",
         value: function obfuscateNode(functionNode) {
             this.storeFunctionParams(functionNode);
             this.replaceFunctionParams(functionNode);
         }
     }, {
-        key: 'storeFunctionParams',
+        key: "storeFunctionParams",
         value: function storeFunctionParams(functionNode) {
             var _this2 = this;
 
             functionNode.params.forEach(function (paramsNode) {
-                estraverse.traverse(paramsNode, {
+                NodeUtils_1.NodeUtils.typedReplace(paramsNode, NodeType_1.NodeType.Identifier, {
                     leave: function leave(node) {
-                        return _this2.storeIdentifiersNames(node, _this2.functionParams);
+                        _this2.identifierReplacer.storeNames(node.name, _this2.functionParams);
                     }
                 });
             });
         }
     }, {
-        key: 'replaceFunctionParams',
+        key: "replaceFunctionParams",
         value: function replaceFunctionParams(functionNode) {
             var _this3 = this;
 
             var replaceVisitor = {
                 leave: function leave(node, parentNode) {
                     if (Nodes_1.Nodes.isReplaceableIdentifierNode(node, parentNode)) {
-                        node.name = new IdentifierReplacer_1.IdentifierReplacer(_this3.nodes, _this3.options).replace(node.name, _this3.functionParams);
+                        node.name = _this3.identifierReplacer.replace(node.name, _this3.functionParams);
                     }
                 }
             };
@@ -2911,18 +2911,13 @@ var NodeUtils_1 = __webpack_require__(1);
 var VariableDeclarationObfuscator = function (_AbstractNodeObfuscat) {
     _inherits(VariableDeclarationObfuscator, _AbstractNodeObfuscat);
 
-    function VariableDeclarationObfuscator() {
-        var _Object$getPrototypeO;
-
+    function VariableDeclarationObfuscator(nodes, options) {
         _classCallCheck(this, VariableDeclarationObfuscator);
 
-        for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
-            args[_key] = arguments[_key];
-        }
-
-        var _this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(VariableDeclarationObfuscator)).call.apply(_Object$getPrototypeO, [this].concat(args)));
+        var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(VariableDeclarationObfuscator).call(this, nodes, options));
 
         _this.variableNames = new Map();
+        _this.identifierReplacer = new IdentifierReplacer_1.IdentifierReplacer(_this.nodes, _this.options);
         return _this;
     }
 
@@ -2941,9 +2936,9 @@ var VariableDeclarationObfuscator = function (_AbstractNodeObfuscat) {
             var _this2 = this;
 
             variableDeclarationNode.declarations.forEach(function (declarationNode) {
-                estraverse.traverse(declarationNode.id, {
-                    enter: function enter(node) {
-                        return _this2.storeIdentifiersNames(node, _this2.variableNames);
+                NodeUtils_1.NodeUtils.typedReplace(declarationNode.id, NodeType_1.NodeType.Identifier, {
+                    leave: function leave(node) {
+                        _this2.identifierReplacer.storeNames(node.name, _this2.variableNames);
                     }
                 });
             });
@@ -2961,7 +2956,7 @@ var VariableDeclarationObfuscator = function (_AbstractNodeObfuscat) {
                         estraverse.replace(node, {
                             enter: function enter(node, parentNode) {
                                 if (Nodes_1.Nodes.isReplaceableIdentifierNode(node, parentNode)) {
-                                    node.name = new IdentifierReplacer_1.IdentifierReplacer(_this3.nodes, _this3.options).replace(node.name, _this3.variableNames);
+                                    node.name = _this3.identifierReplacer.replace(node.name, _this3.variableNames);
                                 }
                             }
                         });
@@ -2970,7 +2965,7 @@ var VariableDeclarationObfuscator = function (_AbstractNodeObfuscat) {
                         isNodeAfterVariableDeclaratorFlag = true;
                     }
                     if (Nodes_1.Nodes.isReplaceableIdentifierNode(node, parentNode) && isNodeAfterVariableDeclaratorFlag) {
-                        node.name = new IdentifierReplacer_1.IdentifierReplacer(_this3.nodes, _this3.options).replace(node.name, _this3.variableNames);
+                        node.name = _this3.identifierReplacer.replace(node.name, _this3.variableNames);
                     }
                 }
             });

+ 46 - 8
src/NodeUtils.ts

@@ -2,6 +2,7 @@ import * as escodegen from 'escodegen';
 import * as esprima from 'esprima';
 import * as estraverse from 'estraverse';
 
+import { ILiteralNode } from "./interfaces/nodes/ILiteralNode";
 import { INode } from './interfaces/nodes/INode';
 
 import { TNodeWithBlockStatement } from "./types/TNodeWithBlockStatement";
@@ -28,14 +29,12 @@ export class NodeUtils {
      * @param node
      */
     public static addXVerbatimPropertyToLiterals (node: INode): void {
-        estraverse.replace(node, {
-            enter: (node: INode, parentNode: INode): any => {
-                if (Nodes.isLiteralNode(node)) {
-                   node['x-verbatim-property'] = {
-                        content : node.raw,
-                        precedence: escodegen.Precedence.Primary
-                    };
-                }
+        NodeUtils.typedReplace(node, NodeType.Literal, {
+            leave: (node: ILiteralNode) => {
+                node['x-verbatim-property'] = {
+                    content : node.raw,
+                    precedence: escodegen.Precedence.Primary
+                };
             }
         });
     }
@@ -168,6 +167,45 @@ export class NodeUtils {
         blockScopeBody.unshift(node);
     }
 
+    /**
+     * @param node
+     * @param nodeType
+     * @param visitor
+     */
+    public static typedReplace (
+        node: INode,
+        nodeType: string,
+        visitor: {enter?: (node: INode) => void, leave?: (node: INode) => void},
+    ): void {
+        NodeUtils.typedTraverse(node, nodeType, visitor, 'replace');
+    }
+
+    /**
+     * @param node
+     * @param nodeType
+     * @param visitor
+     * @param traverseType
+     */
+    public static typedTraverse (
+        node: INode,
+        nodeType: string,
+        visitor: {enter?: (node: INode) => void, leave?: (node: INode) => void},
+        traverseType: string = 'traverse'
+    ): void {
+        (<any>estraverse)[traverseType](node, {
+            enter: (node: INode): any => {
+                if (node.type === nodeType && visitor.enter) {
+                    visitor.enter(node)
+                }
+            },
+            leave: (node: INode): any => {
+                if (node.type === nodeType && visitor.leave) {
+                    visitor.leave(node)
+                }
+            }
+        });
+    }
+
     /**
      * @param node
      * @returns {boolean}

+ 0 - 30
src/node-obfuscators/AbstractNodeObfuscator.ts

@@ -3,9 +3,6 @@ import { INodeObfuscator } from '../interfaces/INodeObfuscator';
 import { INode } from "../interfaces/nodes/INode";
 import { IOptions } from "../interfaces/IOptions";
 
-import { Nodes } from "../Nodes";
-import { Utils } from '../Utils';
-
 export abstract class AbstractNodeObfuscator implements INodeObfuscator {
     /**
      * @type Map <string, AbstractCustomNode>
@@ -31,31 +28,4 @@ export abstract class AbstractNodeObfuscator implements INodeObfuscator {
      * @param parentNode
      */
     public abstract obfuscateNode (node: INode, parentNode?: INode): void;
-
-    /**
-     * @param name
-     * @returns {boolean}
-     */
-    protected isReservedName (name: string): boolean {
-        return this.options.reservedNames
-            .some((reservedName: string) => {
-                return new RegExp(reservedName, 'g').test(name);
-            });
-    }
-
-    /**
-     * Store all identifiers names as keys in given `namesMap` with random names as value.
-     * Reserved names will be ignored.
-     *
-     * @param node
-     * @param namesMap
-     */
-    protected storeIdentifiersNames (
-        node: INode,
-        namesMap: Map <string, string>
-    ): void {
-        if (Nodes.isIdentifierNode(node) && !this.isReservedName(node.name)) {
-            namesMap.set(node.name, Utils.getRandomVariableName());
-        }
-    }
 }

+ 27 - 4
src/node-obfuscators/CatchClauseObfuscator.ts

@@ -1,11 +1,18 @@
 import * as estraverse from 'estraverse';
 
 import { ICatchClauseNode } from "../interfaces/nodes/ICatchClauseNode";
+import { ICustomNode } from "../interfaces/custom-nodes/ICustomNode";
+import { IIdentifierNode } from "../interfaces/nodes/IIdentifierNode";
 import { INode } from '../interfaces/nodes/INode';
+import { IOptions } from "../interfaces/IOptions";
+import { IReplacer } from "../interfaces/IReplacer";
+
+import { NodeType } from "../enums/NodeType";
 
 import { AbstractNodeObfuscator } from './AbstractNodeObfuscator';
 import { IdentifierReplacer } from "./replacers/IdentifierReplacer";
 import { Nodes } from "../Nodes";
+import { NodeUtils } from "../NodeUtils";
 
 /**
  * replaces:
@@ -21,6 +28,21 @@ export class CatchClauseObfuscator extends AbstractNodeObfuscator {
      */
     private catchClauseParam: Map <string, string> = new Map <string, string> ();
 
+    /**
+     * @type {IReplacer&IdentifierReplacer}
+     */
+    private identifierReplacer: IReplacer&IdentifierReplacer;
+
+    /**
+     * @param nodes
+     * @param options
+     */
+    constructor(nodes: Map <string, ICustomNode>, options: IOptions) {
+        super(nodes, options);
+
+        this.identifierReplacer = new IdentifierReplacer(this.nodes, this.options);
+    }
+
     /**
      * @param catchClauseNode
      */
@@ -33,8 +55,10 @@ export class CatchClauseObfuscator extends AbstractNodeObfuscator {
      * @param catchClauseNode
      */
     private storeCatchClauseParam (catchClauseNode: ICatchClauseNode): void {
-        estraverse.traverse(catchClauseNode.param, {
-            leave: (node: INode): any => this.storeIdentifiersNames(node, this.catchClauseParam)
+        NodeUtils.typedReplace(catchClauseNode.param, NodeType.Identifier, {
+            leave: (node: IIdentifierNode) => {
+                this.identifierReplacer.storeNames(node.name, this.catchClauseParam)
+            }
         });
     }
 
@@ -45,8 +69,7 @@ export class CatchClauseObfuscator extends AbstractNodeObfuscator {
         estraverse.replace(catchClauseNode, {
             leave: (node: INode, parentNode: INode): any => {
                 if (Nodes.isReplaceableIdentifierNode(node, parentNode)) {
-                    node.name = new IdentifierReplacer(this.nodes, this.options)
-                        .replace(node.name, this.catchClauseParam);
+                    node.name = this.identifierReplacer.replace(node.name, this.catchClauseParam);
                 }
             }
         });

+ 24 - 4
src/node-obfuscators/FunctionDeclarationObfuscator.ts

@@ -1,7 +1,11 @@
 import * as estraverse from 'estraverse';
 
+import { ICustomNode } from "../interfaces/custom-nodes/ICustomNode";
 import { IFunctionDeclarationNode } from "../interfaces/nodes/IFunctionDeclarationNode";
+import { IIdentifierNode } from "../interfaces/nodes/IIdentifierNode";
 import { INode } from "../interfaces/nodes/INode";
+import { IOptions } from "../interfaces/IOptions";
+import { IReplacer } from "../interfaces/IReplacer";
 
 import { NodeType } from "../enums/NodeType";
 
@@ -25,6 +29,21 @@ export class FunctionDeclarationObfuscator extends AbstractNodeObfuscator {
      */
     private functionName: Map <string, string> = new Map <string, string> ();
 
+    /**
+     * @type {IReplacer&IdentifierReplacer}
+     */
+    private identifierReplacer: IReplacer&IdentifierReplacer;
+
+    /**
+     * @param nodes
+     * @param options
+     */
+    constructor(nodes: Map <string, ICustomNode>, options: IOptions) {
+        super(nodes, options);
+
+        this.identifierReplacer = new IdentifierReplacer(this.nodes, this.options);
+    }
+
     /**
      * @param functionDeclarationNode
      * @param parentNode
@@ -42,8 +61,10 @@ export class FunctionDeclarationObfuscator extends AbstractNodeObfuscator {
      * @param functionDeclarationNode
      */
     private storeFunctionName (functionDeclarationNode: IFunctionDeclarationNode): void {
-        estraverse.traverse(functionDeclarationNode.id, {
-            leave: (node: INode): any => this.storeIdentifiersNames(node, this.functionName)
+        NodeUtils.typedReplace(functionDeclarationNode.id, NodeType.Identifier, {
+            leave: (node: IIdentifierNode) => {
+                this.identifierReplacer.storeNames(node.name, this.functionName)
+            }
         });
     }
 
@@ -58,8 +79,7 @@ export class FunctionDeclarationObfuscator extends AbstractNodeObfuscator {
         estraverse.replace(scopeNode, {
             enter: (node: INode, parentNode: INode): any => {
                 if (Nodes.isReplaceableIdentifierNode(node, parentNode)) {
-                    node.name = new IdentifierReplacer(this.nodes, this.options)
-                        .replace(node.name, this.functionName);
+                    node.name = this.identifierReplacer.replace(node.name, this.functionName);
                 }
             }
         });

+ 27 - 4
src/node-obfuscators/FunctionObfuscator.ts

@@ -1,11 +1,18 @@
 import * as estraverse from 'estraverse';
 
+import { ICustomNode } from "../interfaces/custom-nodes/ICustomNode";
 import { IFunctionNode } from "../interfaces/nodes/IFunctionNode";
+import { IIdentifierNode } from "../interfaces/nodes/IIdentifierNode";
 import { INode } from "../interfaces/nodes/INode";
+import { IOptions } from "../interfaces/IOptions";
+import { IReplacer } from "../interfaces/IReplacer";
+
+import { NodeType } from "../enums/NodeType";
 
 import { AbstractNodeObfuscator } from './AbstractNodeObfuscator';
 import { IdentifierReplacer } from "./replacers/IdentifierReplacer";
 import { Nodes } from "../Nodes";
+import { NodeUtils } from "../NodeUtils";
 
 /**
  * replaces:
@@ -21,6 +28,21 @@ export class FunctionObfuscator extends AbstractNodeObfuscator {
      */
     private functionParams: Map <string, string> = new Map <string, string> ();
 
+    /**
+     * @type {IReplacer&IdentifierReplacer}
+     */
+    private identifierReplacer: IReplacer&IdentifierReplacer;
+
+    /**
+     * @param nodes
+     * @param options
+     */
+    constructor(nodes: Map <string, ICustomNode>, options: IOptions) {
+        super(nodes, options);
+
+        this.identifierReplacer = new IdentifierReplacer(this.nodes, this.options);
+    }
+
     /**
      * @param functionNode
      */
@@ -35,8 +57,10 @@ export class FunctionObfuscator extends AbstractNodeObfuscator {
     private storeFunctionParams (functionNode: IFunctionNode): void {
         functionNode.params
             .forEach((paramsNode: INode) => {
-                estraverse.traverse(paramsNode, {
-                    leave: (node: INode): any => this.storeIdentifiersNames(node, this.functionParams)
+                NodeUtils.typedReplace(paramsNode, NodeType.Identifier, {
+                    leave: (node: IIdentifierNode) => {
+                        this.identifierReplacer.storeNames(node.name, this.functionParams)
+                    }
                 });
             });
     }
@@ -48,8 +72,7 @@ export class FunctionObfuscator extends AbstractNodeObfuscator {
         let replaceVisitor: estraverse.Visitor = {
             leave: (node: INode, parentNode: INode): any => {
                 if (Nodes.isReplaceableIdentifierNode(node, parentNode)) {
-                    node.name = new IdentifierReplacer(this.nodes, this.options)
-                        .replace(node.name, this.functionParams);
+                    node.name = this.identifierReplacer.replace(node.name, this.functionParams);
                 }
             }
         };

+ 25 - 6
src/node-obfuscators/VariableDeclarationObfuscator.ts

@@ -1,6 +1,10 @@
 import * as estraverse from 'estraverse';
 
+import { ICustomNode } from "../interfaces/custom-nodes/ICustomNode";
+import { IIdentifierNode } from "../interfaces/nodes/IIdentifierNode";
 import { INode } from "../interfaces/nodes/INode";
+import { IOptions } from "../interfaces/IOptions";
+import { IReplacer } from "../interfaces/IReplacer";
 import { IVariableDeclarationNode } from "../interfaces/nodes/IVariableDeclarationNode";
 import { IVariableDeclaratorNode } from "../interfaces/nodes/IVariableDeclaratorNode";
 
@@ -22,11 +26,26 @@ import { NodeUtils } from "../NodeUtils";
  *
  */
 export class VariableDeclarationObfuscator extends AbstractNodeObfuscator {
+    /**
+     * @type {IReplacer&IdentifierReplacer}
+     */
+    private identifierReplacer: IReplacer&IdentifierReplacer;
+
     /**
      * @type {Map<string, string>}
      */
     private variableNames: Map <string, string> = new Map <string, string> ();
 
+    /**
+     * @param nodes
+     * @param options
+     */
+    constructor(nodes: Map <string, ICustomNode>, options: IOptions) {
+        super(nodes, options);
+
+        this.identifierReplacer = new IdentifierReplacer(this.nodes, this.options);
+    }
+
     /**
      * @param variableDeclarationNode
      * @param parentNode
@@ -46,8 +65,10 @@ export class VariableDeclarationObfuscator extends AbstractNodeObfuscator {
     private storeVariableNames (variableDeclarationNode: IVariableDeclarationNode): void {
         variableDeclarationNode.declarations
             .forEach((declarationNode: IVariableDeclaratorNode) => {
-                estraverse.traverse(declarationNode.id, {
-                    enter: (node: INode): any => this.storeIdentifiersNames(node, this.variableNames)
+                NodeUtils.typedReplace(declarationNode.id, NodeType.Identifier, {
+                    leave: (node: IIdentifierNode) => {
+                        this.identifierReplacer.storeNames(node.name, this.variableNames)
+                    }
                 });
             });
     }
@@ -72,8 +93,7 @@ export class VariableDeclarationObfuscator extends AbstractNodeObfuscator {
                     estraverse.replace(node, {
                         enter: (node: INode, parentNode: INode): any => {
                             if (Nodes.isReplaceableIdentifierNode(node, parentNode)) {
-                                node.name = new IdentifierReplacer(this.nodes, this.options)
-                                    .replace(node.name, this.variableNames);
+                                node.name = this.identifierReplacer.replace(node.name, this.variableNames);
                             }
                         }
                     });
@@ -84,8 +104,7 @@ export class VariableDeclarationObfuscator extends AbstractNodeObfuscator {
                 }
 
                 if (Nodes.isReplaceableIdentifierNode(node, parentNode) && isNodeAfterVariableDeclaratorFlag) {
-                    node.name = new IdentifierReplacer(this.nodes, this.options)
-                        .replace(node.name, this.variableNames);
+                    node.name = this.identifierReplacer.replace(node.name, this.variableNames);
                 }
             }
         });

+ 25 - 0
src/node-obfuscators/replacers/IdentifierReplacer.ts

@@ -1,4 +1,5 @@
 import { AbstractReplacer } from "./AbstractReplacer";
+import { Utils } from "../../Utils";
 
 export class IdentifierReplacer extends AbstractReplacer {
     /**
@@ -15,4 +16,28 @@ export class IdentifierReplacer extends AbstractReplacer {
 
         return obfuscatedIdentifierName;
     }
+
+    /**
+     * Store all identifiers names as keys in given `namesMap` with random names as value.
+     * Reserved names will be ignored.
+     *
+     * @param nodeName
+     * @param namesMap
+     */
+    public storeNames (nodeName: string, namesMap: Map <string, string>): void {
+        if (!this.isReservedName(nodeName)) {
+            namesMap.set(nodeName, Utils.getRandomVariableName());
+        }
+    }
+
+    /**
+     * @param name
+     * @returns {boolean}
+     */
+    private isReservedName (name: string): boolean {
+        return this.options.reservedNames
+            .some((reservedName: string) => {
+                return new RegExp(reservedName, 'g').test(name);
+            });
+    }
 }