Просмотр исходного кода

TS 2.0 Strict Null Checks refactoring

sanex3339 8 лет назад
Родитель
Сommit
7e2f891aab
43 измененных файлов с 339 добавлено и 311 удалено
  1. 125 115
      dist/index.js
  2. 7 4
      src/JavaScriptObfuscator.ts
  3. 7 4
      src/JavaScriptObfuscatorInternal.ts
  4. 6 2
      src/NodeUtils.ts
  5. 1 3
      src/Nodes.ts
  6. 5 3
      src/Obfuscator.ts
  7. 6 6
      src/Options.ts
  8. 26 21
      src/OptionsNormalizer.ts
  9. 8 10
      src/Utils.ts
  10. 9 9
      src/cli/JavaScriptObfuscatorCLI.ts
  11. 5 4
      src/custom-nodes/Node.ts
  12. 0 2
      src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts
  13. 4 4
      src/custom-nodes/unicode-array-nodes/UnicodeArrayCallsWrapper.ts
  14. 4 4
      src/custom-nodes/unicode-array-nodes/UnicodeArrayDecodeNode.ts
  15. 4 4
      src/custom-nodes/unicode-array-nodes/UnicodeArrayNode.ts
  16. 4 4
      src/custom-nodes/unicode-array-nodes/UnicodeArrayRotateFunctionNode.ts
  17. 0 35
      src/interfaces/ICustomNode.d.ts
  18. 1 1
      src/interfaces/INodesGroup.d.ts
  19. 1 1
      src/interfaces/IObfuscatorOptions.d.ts
  20. 20 0
      src/interfaces/custom-nodes/ICustomNode.d.ts
  21. 13 0
      src/interfaces/custom-nodes/ICustomNodeWithData.d.ts
  22. 8 0
      src/interfaces/custom-nodes/ICustomNodeWithIdentifier.d.ts
  23. 1 1
      src/interfaces/nodes/IIfStatementNode.ts
  24. 1 1
      src/node-groups/NodesGroup.ts
  25. 1 1
      src/node-obfuscators/MemberExpressionObfuscator.ts
  26. 32 27
      src/node-obfuscators/NodeObfuscator.ts
  27. 1 1
      src/node-obfuscators/ObjectExpressionObfuscator.ts
  28. 2 2
      src/preset-options/DefaultPreset.ts
  29. 2 2
      src/preset-options/NoCustomNodesPreset.ts
  30. 1 1
      src/types/TNodeObfuscator.d.ts
  31. 2 2
      src/types/TOptionsNormalizerRule.ts
  32. 3 0
      src/types/custom-nodes/TUnicodeArrayCallsWrapper.ts
  33. 4 0
      src/types/custom-nodes/TUnicodeArrayNode.d.ts
  34. 2 1
      test/dev/test.ts
  35. 1 1
      test/functional-tests/JavaScriptObfuscator.spec.ts
  36. 0 18
      test/unit-tests/NodeUtils.spec.ts
  37. 4 4
      test/unit-tests/OptionsNormalizer.spec.ts
  38. 7 6
      test/unit-tests/Utils.spec.ts
  39. 1 1
      test/unit-tests/node-obfuscators/CatchClauseObfuscator.spec.ts
  40. 3 3
      test/unit-tests/node-obfuscators/FunctionDeclarationObfuscator.spec.ts
  41. 1 1
      test/unit-tests/node-obfuscators/FunctionObfuscator.spec.ts
  42. 3 1
      tsconfig-test.json
  43. 3 1
      tsconfig.json

+ 125 - 115
dist/index.js

@@ -109,21 +109,17 @@ var Utils = function () {
     }, {
         key: 'arrayRotate',
         value: function arrayRotate(array, times) {
-            var reverse = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
-
+            if (!array.length) {
+                throw new ReferenceError('Cannot rotate empty array.');
+            }
             if (times <= 0) {
                 return array;
             }
             var newArray = array,
                 temp = void 0;
             while (times--) {
-                if (!reverse) {
-                    temp = newArray.pop();
-                    newArray.unshift(temp);
-                } else {
-                    temp = newArray.shift();
-                    newArray.push(temp);
-                }
+                temp = newArray.pop();
+                newArray.unshift(temp);
             }
             return newArray;
         }
@@ -217,7 +213,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
 
 var escodegen = __webpack_require__(10);
 var esprima = __webpack_require__(17);
-var estraverse = __webpack_require__(3);
+var estraverse = __webpack_require__(4);
 var NodeType_1 = __webpack_require__(6);
 var Nodes_1 = __webpack_require__(7);
 var Utils_1 = __webpack_require__(0);
@@ -280,7 +276,10 @@ var NodeUtils = function () {
                 throw new ReferenceError('`parentNode` property of given node is `undefined`');
             }
             if (Nodes_1.Nodes.isBlockStatementNode(parentNode)) {
-                if (!Utils_1.Utils.arrayContains(NodeUtils.nodesWithBlockScope, parentNode['parentNode'].type)) {
+                if (!parentNode.parentNode) {
+                    throw new ReferenceError('`parentNode` property of `parentNode` of given node is `undefined`');
+                }
+                if (!Utils_1.Utils.arrayContains(NodeUtils.nodesWithBlockScope, parentNode.parentNode.type)) {
                     return NodeUtils.getBlockScopeOfNode(parentNode, depth);
                 } else if (depth > 0) {
                     return NodeUtils.getBlockScopeOfNode(parentNode, --depth);
@@ -360,12 +359,6 @@ var AppendState = exports.AppendState;
 /* 3 */
 /***/ function(module, exports) {
 
-module.exports = require("estraverse");
-
-/***/ },
-/* 4 */
-/***/ function(module, exports) {
-
 "use strict";
 "use strict";
 
@@ -397,6 +390,12 @@ var Node = function () {
 
 exports.Node = Node;
 
+/***/ },
+/* 4 */
+/***/ function(module, exports) {
+
+module.exports = require("estraverse");
+
 /***/ },
 /* 5 */
 /***/ function(module, exports, __webpack_require__) {
@@ -408,7 +407,6 @@ var _createClass = function () { function defineProperties(target, props) { for
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var estraverse = __webpack_require__(3);
 var JSFuck_1 = __webpack_require__(9);
 var Nodes_1 = __webpack_require__(7);
 var Utils_1 = __webpack_require__(0);
@@ -433,9 +431,7 @@ var NodeObfuscator = function () {
         value: function storeIdentifiersNames(node, namesMap) {
             if (Nodes_1.Nodes.isIdentifierNode(node) && !this.isReservedName(node.name)) {
                 namesMap.set(node.name, Utils_1.Utils.getRandomVariableName());
-                return;
             }
-            return estraverse.VisitorOption.Skip;
         }
     }, {
         key: "replaceIdentifiersWithRandomNames",
@@ -466,34 +462,40 @@ var NodeObfuscator = function () {
     }, {
         key: "replaceLiteralValueWithUnicodeValue",
         value: function replaceLiteralValueWithUnicodeValue(nodeValue) {
-            var value = nodeValue,
-                replaceWithUnicodeArrayFlag = Math.random() <= this.options.get('unicodeArrayThreshold');
+            var replaceWithUnicodeArrayFlag = Math.random() <= this.options.get('unicodeArrayThreshold');
             if (this.options.get('encodeUnicodeLiterals') && replaceWithUnicodeArrayFlag) {
-                value = Utils_1.Utils.btoa(value);
+                nodeValue = Utils_1.Utils.btoa(nodeValue);
             }
-            value = Utils_1.Utils.stringToUnicode(value);
-            if (!this.options.get('unicodeArray') || !replaceWithUnicodeArrayFlag) {
-                return value;
+            nodeValue = Utils_1.Utils.stringToUnicode(nodeValue);
+            if (this.options.get('unicodeArray') && replaceWithUnicodeArrayFlag) {
+                return this.replaceLiteralValueWithUnicodeArrayCall(nodeValue);
             }
-            return this.replaceLiteralValueWithUnicodeArrayCall(value);
+            return nodeValue;
         }
     }, {
         key: "replaceLiteralValueWithUnicodeArrayCall",
         value: function replaceLiteralValueWithUnicodeArrayCall(value) {
-            var unicodeArrayNode = this.nodes.get('unicodeArrayNode'),
-                unicodeArray = unicodeArrayNode.getNodeData(),
-                sameIndex = unicodeArray.indexOf(value),
-                index = void 0,
+            var unicodeArrayNode = this.nodes.get('unicodeArrayNode');
+            if (!unicodeArrayNode) {
+                throw new ReferenceError('`unicodeArrayNode` node is not found in Map with custom nodes.');
+            }
+            var unicodeArray = unicodeArrayNode.getNodeData(),
+                valueIndex = unicodeArray.indexOf(value),
+                literalValueCallIndex = void 0,
                 hexadecimalIndex = void 0;
-            if (sameIndex >= 0) {
-                index = sameIndex;
+            if (valueIndex >= 0) {
+                literalValueCallIndex = valueIndex;
             } else {
-                index = unicodeArray.length;
+                literalValueCallIndex = unicodeArray.length;
                 unicodeArrayNode.updateNodeData(value);
             }
-            hexadecimalIndex = this.replaceLiteralNumberWithHexadecimalValue(index);
+            hexadecimalIndex = this.replaceLiteralNumberWithHexadecimalValue(literalValueCallIndex);
             if (this.options.get('wrapUnicodeArrayCalls')) {
-                return this.nodes.get('unicodeArrayCallsWrapper').getNodeIdentifier() + "('" + hexadecimalIndex + "')";
+                var unicodeArrayCallsWrapper = this.nodes.get('unicodeArrayCallsWrapper');
+                if (!unicodeArrayCallsWrapper) {
+                    throw new ReferenceError('`unicodeArrayCallsWrapper` node is not found in Map with custom nodes.');
+                }
+                return unicodeArrayCallsWrapper.getNodeIdentifier() + "('" + hexadecimalIndex + "')";
             }
             return unicodeArrayNode.getNodeIdentifier() + "[" + hexadecimalIndex + "]";
         }
@@ -563,12 +565,11 @@ var Nodes = function () {
     _createClass(Nodes, null, [{
         key: "getProgramNode",
         value: function getProgramNode(bodyNode) {
-            var programNode = {
+            return {
                 'type': NodeType_1.NodeType.Program,
                 'body': bodyNode,
                 'sourceType': 'script'
             };
-            return programNode;
         }
     }, {
         key: "isBlockStatementNode",
@@ -629,7 +630,7 @@ var _createClass = function () { function defineProperties(target, props) { for
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 var JavaScriptObfuscatorCLI_1 = __webpack_require__(26);
-var JavaScriptObfuscatorInternal_1 = __webpack_require__(14);
+var JavaScriptObfuscatorInternal_1 = __webpack_require__(15);
 
 var JavaScriptObfuscator = function () {
     function JavaScriptObfuscator() {
@@ -639,9 +640,9 @@ var JavaScriptObfuscator = function () {
     _createClass(JavaScriptObfuscator, null, [{
         key: "obfuscate",
         value: function obfuscate(sourceCode) {
-            var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
+            var obfuscatorOptions = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
 
-            var javaScriptObfuscator = new JavaScriptObfuscatorInternal_1.JavaScriptObfuscatorInternal(sourceCode, options);
+            var javaScriptObfuscator = new JavaScriptObfuscatorInternal_1.JavaScriptObfuscatorInternal(sourceCode, obfuscatorOptions);
             javaScriptObfuscator.obfuscate();
             return javaScriptObfuscator.getObfuscationResult();
         }
@@ -778,6 +779,30 @@ exports.NodesGroup = NodesGroup;
 "use strict";
 "use strict";
 
+var SourceMapMode_1 = __webpack_require__(11);
+exports.DEFAULT_PRESET = Object.freeze({
+    compact: true,
+    debugProtection: false,
+    debugProtectionInterval: false,
+    disableConsoleOutput: true,
+    encodeUnicodeLiterals: false,
+    reservedNames: [],
+    rotateUnicodeArray: true,
+    selfDefending: true,
+    sourceMap: false,
+    sourceMapMode: SourceMapMode_1.SourceMapMode.Separate,
+    unicodeArray: true,
+    unicodeArrayThreshold: 0.8,
+    wrapUnicodeArrayCalls: true
+});
+
+/***/ },
+/* 14 */
+/***/ function(module, exports, __webpack_require__) {
+
+"use strict";
+"use strict";
+
 var SourceMapMode_1 = __webpack_require__(11);
 exports.NO_CUSTOM_NODES_PRESET = Object.freeze({
     compact: true,
@@ -796,7 +821,7 @@ exports.NO_CUSTOM_NODES_PRESET = Object.freeze({
 });
 
 /***/ },
-/* 14 */
+/* 15 */
 /***/ function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -808,18 +833,20 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
 
 var esprima = __webpack_require__(17);
 var escodegen = __webpack_require__(10);
-var ObfuscationResult_1 = __webpack_require__(15);
+var ObfuscationResult_1 = __webpack_require__(16);
 var Obfuscator_1 = __webpack_require__(21);
 var Options_1 = __webpack_require__(22);
 var SourceMapCorrector_1 = __webpack_require__(24);
 
 var JavaScriptObfuscatorInternal = function () {
-    function JavaScriptObfuscatorInternal(sourceCode, customOptions) {
+    function JavaScriptObfuscatorInternal(sourceCode, obfuscatorOptions) {
         _classCallCheck(this, JavaScriptObfuscatorInternal);
 
         this.sourceMapUrl = '';
         this.sourceCode = sourceCode;
-        this.options = new Options_1.Options(customOptions);
+        if (obfuscatorOptions) {
+            this.options = new Options_1.Options(obfuscatorOptions);
+        }
     }
 
     _createClass(JavaScriptObfuscatorInternal, [{
@@ -869,7 +896,7 @@ JavaScriptObfuscatorInternal.escodegenParams = {
 exports.JavaScriptObfuscatorInternal = JavaScriptObfuscatorInternal;
 
 /***/ },
-/* 15 */
+/* 16 */
 /***/ function(module, exports) {
 
 "use strict";
@@ -909,30 +936,6 @@ var ObfuscationResult = function () {
 
 exports.ObfuscationResult = ObfuscationResult;
 
-/***/ },
-/* 16 */
-/***/ function(module, exports, __webpack_require__) {
-
-"use strict";
-"use strict";
-
-var SourceMapMode_1 = __webpack_require__(11);
-exports.DEFAULT_PRESET = Object.freeze({
-    compact: true,
-    debugProtection: false,
-    debugProtectionInterval: false,
-    disableConsoleOutput: true,
-    encodeUnicodeLiterals: false,
-    reservedNames: [],
-    rotateUnicodeArray: true,
-    selfDefending: true,
-    sourceMap: false,
-    sourceMapMode: SourceMapMode_1.SourceMapMode.Separate,
-    unicodeArray: true,
-    unicodeArrayThreshold: 0.8,
-    wrapUnicodeArrayCalls: true
-});
-
 /***/ },
 /* 17 */
 /***/ function(module, exports) {
@@ -977,7 +980,7 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var estraverse = __webpack_require__(3);
+var estraverse = __webpack_require__(4);
 var AppendState_1 = __webpack_require__(2);
 var NodeType_1 = __webpack_require__(6);
 var CatchClauseObfuscator_1 = __webpack_require__(40);
@@ -1035,10 +1038,11 @@ var Obfuscator = function () {
         value: function initializeNodeObfuscators(node, parentNode) {
             var _this = this;
 
-            if (!this.nodeObfuscators.has(node.type)) {
+            var nodeObfuscators = this.nodeObfuscators.get(node.type);
+            if (!nodeObfuscators) {
                 return;
             }
-            this.nodeObfuscators.get(node.type).forEach(function (obfuscator) {
+            nodeObfuscators.forEach(function (obfuscator) {
                 new obfuscator(_this.nodes, _this.options).obfuscateNode(node, parentNode);
             });
         }
@@ -1072,13 +1076,13 @@ var _createClass = function () { function defineProperties(target, props) { for
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 var OptionsNormalizer_1 = __webpack_require__(23);
-var DefaultPreset_1 = __webpack_require__(16);
+var DefaultPreset_1 = __webpack_require__(13);
 
 var Options = function () {
-    function Options(options) {
+    function Options(obfuscatorOptions) {
         _classCallCheck(this, Options);
 
-        this.options = Object.freeze(OptionsNormalizer_1.OptionsNormalizer.normalizeOptionsPreset(Object.assign({}, DefaultPreset_1.DEFAULT_PRESET, options)));
+        this.options = Object.freeze(OptionsNormalizer_1.OptionsNormalizer.normalizeOptionsPreset(Object.assign({}, DefaultPreset_1.DEFAULT_PRESET, obfuscatorOptions)));
     }
 
     _createClass(Options, [{
@@ -1095,7 +1099,7 @@ exports.Options = Options;
 
 /***/ },
 /* 23 */
-/***/ function(module, exports) {
+/***/ function(module, exports, __webpack_require__) {
 
 "use strict";
 "use strict";
@@ -1104,6 +1108,8 @@ var _createClass = function () { function defineProperties(target, props) { for
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
+var DefaultPreset_1 = __webpack_require__(13);
+
 var OptionsNormalizer = function () {
     function OptionsNormalizer() {
         _classCallCheck(this, OptionsNormalizer);
@@ -1161,7 +1167,11 @@ var OptionsNormalizer = function () {
         value: function unicodeArrayThresholdRule(options) {
             var minValue = 0,
                 maxValue = 1;
-            options.unicodeArrayThreshold = Math.min(Math.max(options.unicodeArrayThreshold, minValue), maxValue);
+            if (typeof options.unicodeArrayThreshold !== 'number') {
+                options.unicodeArrayThreshold = DefaultPreset_1.DEFAULT_PRESET.unicodeArrayThreshold;
+            } else {
+                options.unicodeArrayThreshold = Math.min(Math.max(options.unicodeArrayThreshold, minValue), maxValue);
+            }
             return options;
         }
     }]);
@@ -1195,7 +1205,7 @@ var _createClass = function () { function defineProperties(target, props) { for
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 var SourceMapMode_1 = __webpack_require__(11);
-var ObfuscationResult_1 = __webpack_require__(15);
+var ObfuscationResult_1 = __webpack_require__(16);
 var Utils_1 = __webpack_require__(0);
 
 var SourceMapCorrector = function () {
@@ -1350,10 +1360,10 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
 var path = __webpack_require__(18);
 var commander_1 = __webpack_require__(49);
 var SourceMapMode_1 = __webpack_require__(11);
-var DefaultPreset_1 = __webpack_require__(16);
+var DefaultPreset_1 = __webpack_require__(13);
 var CLIUtils_1 = __webpack_require__(25);
 var JavaScriptObfuscator_1 = __webpack_require__(8);
-var JavaScriptObfuscatorInternal_1 = __webpack_require__(14);
+var JavaScriptObfuscatorInternal_1 = __webpack_require__(15);
 var Utils_1 = __webpack_require__(0);
 
 var JavaScriptObfuscatorCLI = function () {
@@ -1380,7 +1390,7 @@ var JavaScriptObfuscatorCLI = function () {
     }, {
         key: 'buildOptions',
         value: function buildOptions() {
-            var options = {},
+            var obfuscatorOptions = {},
                 availableOptions = Object.keys(DefaultPreset_1.DEFAULT_PRESET);
             for (var option in this.commands) {
                 if (!this.commands.hasOwnProperty(option)) {
@@ -1389,9 +1399,9 @@ var JavaScriptObfuscatorCLI = function () {
                 if (!Utils_1.Utils.arrayContains(availableOptions, option)) {
                     continue;
                 }
-                options[option] = this.commands[option];
+                obfuscatorOptions[option] = this.commands[option];
             }
-            return Object.assign({}, DefaultPreset_1.DEFAULT_PRESET, options);
+            return Object.assign({}, DefaultPreset_1.DEFAULT_PRESET, obfuscatorOptions);
         }
     }, {
         key: 'configureCommands',
@@ -1488,7 +1498,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 AppendState_1 = __webpack_require__(2);
-var Node_1 = __webpack_require__(4);
+var Node_1 = __webpack_require__(3);
 var NodeUtils_1 = __webpack_require__(1);
 
 var ConsoleOutputDisableExpressionNode = function (_Node_1$Node) {
@@ -1542,7 +1552,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 AppendState_1 = __webpack_require__(2);
-var Node_1 = __webpack_require__(4);
+var Node_1 = __webpack_require__(3);
 var NodeUtils_1 = __webpack_require__(1);
 
 var DebugProtectionFunctionCallNode = function (_Node_1$Node) {
@@ -1591,7 +1601,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 AppendState_1 = __webpack_require__(2);
-var Node_1 = __webpack_require__(4);
+var Node_1 = __webpack_require__(3);
 var NodeUtils_1 = __webpack_require__(1);
 
 var DebugProtectionFunctionIntervalNode = function (_Node_1$Node) {
@@ -1640,7 +1650,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 AppendState_1 = __webpack_require__(2);
-var Node_1 = __webpack_require__(4);
+var Node_1 = __webpack_require__(3);
 var NodeUtils_1 = __webpack_require__(1);
 var Utils_1 = __webpack_require__(0);
 
@@ -1701,9 +1711,9 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function"
 
 var AppendState_1 = __webpack_require__(2);
 var JSFuck_1 = __webpack_require__(9);
-var NoCustomNodesPreset_1 = __webpack_require__(13);
+var NoCustomNodesPreset_1 = __webpack_require__(14);
 var JavaScriptObfuscator_1 = __webpack_require__(8);
-var Node_1 = __webpack_require__(4);
+var Node_1 = __webpack_require__(3);
 var NodeUtils_1 = __webpack_require__(1);
 var Utils_1 = __webpack_require__(0);
 
@@ -1768,7 +1778,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 AppendState_1 = __webpack_require__(2);
-var Node_1 = __webpack_require__(4);
+var Node_1 = __webpack_require__(3);
 var NodeUtils_1 = __webpack_require__(1);
 var Utils_1 = __webpack_require__(0);
 
@@ -1790,6 +1800,9 @@ var UnicodeArrayCallsWrapper = function (_Node_1$Node) {
     _createClass(UnicodeArrayCallsWrapper, [{
         key: "appendNode",
         value: function appendNode(blockScopeNode) {
+            if (!this.unicodeArray.length) {
+                return;
+            }
             NodeUtils_1.NodeUtils.insertNodeAtIndex(blockScopeNode.body, this.getNode(), 1);
         }
     }, {
@@ -1800,9 +1813,6 @@ var UnicodeArrayCallsWrapper = function (_Node_1$Node) {
     }, {
         key: "getNode",
         value: function getNode() {
-            if (!this.unicodeArray.length) {
-                return;
-            }
             return _get(Object.getPrototypeOf(UnicodeArrayCallsWrapper.prototype), "getNode", this).call(this);
         }
     }, {
@@ -1837,9 +1847,9 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function"
 
 var AppendState_1 = __webpack_require__(2);
 var JSFuck_1 = __webpack_require__(9);
-var NoCustomNodesPreset_1 = __webpack_require__(13);
+var NoCustomNodesPreset_1 = __webpack_require__(14);
 var JavaScriptObfuscator_1 = __webpack_require__(8);
-var Node_1 = __webpack_require__(4);
+var Node_1 = __webpack_require__(3);
 var NodeUtils_1 = __webpack_require__(1);
 var Utils_1 = __webpack_require__(0);
 
@@ -1860,14 +1870,14 @@ var UnicodeArrayDecodeNode = function (_Node_1$Node) {
     _createClass(UnicodeArrayDecodeNode, [{
         key: "appendNode",
         value: function appendNode(blockScopeNode) {
+            if (!this.unicodeArray.length) {
+                return;
+            }
             NodeUtils_1.NodeUtils.insertNodeAtIndex(blockScopeNode.body, this.getNode(), 1);
         }
     }, {
         key: "getNode",
         value: function getNode() {
-            if (!this.unicodeArray.length) {
-                return;
-            }
             return _get(Object.getPrototypeOf(UnicodeArrayDecodeNode.prototype), "getNode", this).call(this);
         }
     }, {
@@ -1910,7 +1920,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 AppendState_1 = __webpack_require__(2);
-var Node_1 = __webpack_require__(4);
+var Node_1 = __webpack_require__(3);
 var NodeUtils_1 = __webpack_require__(1);
 var Utils_1 = __webpack_require__(0);
 
@@ -1935,6 +1945,9 @@ var UnicodeArrayNode = function (_Node_1$Node) {
     _createClass(UnicodeArrayNode, [{
         key: 'appendNode',
         value: function appendNode(blockScopeNode) {
+            if (!this.unicodeArray.length) {
+                return;
+            }
             NodeUtils_1.NodeUtils.prependNode(blockScopeNode.body, this.getNode());
         }
     }, {
@@ -1950,9 +1963,6 @@ var UnicodeArrayNode = function (_Node_1$Node) {
     }, {
         key: 'getNode',
         value: function getNode() {
-            if (!this.unicodeArray.length) {
-                return;
-            }
             Utils_1.Utils.arrayRotate(this.unicodeArray, this.unicodeArrayRotateValue);
             return _get(Object.getPrototypeOf(UnicodeArrayNode.prototype), 'getNode', this).call(this);
         }
@@ -1993,9 +2003,9 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function"
 
 var AppendState_1 = __webpack_require__(2);
 var JSFuck_1 = __webpack_require__(9);
-var NoCustomNodesPreset_1 = __webpack_require__(13);
+var NoCustomNodesPreset_1 = __webpack_require__(14);
 var JavaScriptObfuscator_1 = __webpack_require__(8);
-var Node_1 = __webpack_require__(4);
+var Node_1 = __webpack_require__(3);
 var NodeUtils_1 = __webpack_require__(1);
 var Utils_1 = __webpack_require__(0);
 
@@ -2017,14 +2027,14 @@ var UnicodeArrayRotateFunctionNode = function (_Node_1$Node) {
     _createClass(UnicodeArrayRotateFunctionNode, [{
         key: "appendNode",
         value: function appendNode(blockScopeNode) {
+            if (!this.unicodeArray.length) {
+                return;
+            }
             NodeUtils_1.NodeUtils.insertNodeAtIndex(blockScopeNode.body, this.getNode(), 1);
         }
     }, {
         key: "getNode",
         value: function getNode() {
-            if (!this.unicodeArray.length) {
-                return;
-            }
             return _get(Object.getPrototypeOf(UnicodeArrayRotateFunctionNode.prototype), "getNode", this).call(this);
         }
     }, {
@@ -2241,7 +2251,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 estraverse = __webpack_require__(3);
+var estraverse = __webpack_require__(4);
 var NodeObfuscator_1 = __webpack_require__(5);
 
 var CatchClauseObfuscator = function (_NodeObfuscator_1$Nod) {
@@ -2312,7 +2322,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 estraverse = __webpack_require__(3);
+var estraverse = __webpack_require__(4);
 var NodeType_1 = __webpack_require__(6);
 var NodeObfuscator_1 = __webpack_require__(5);
 var NodeUtils_1 = __webpack_require__(1);
@@ -2389,7 +2399,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 estraverse = __webpack_require__(3);
+var estraverse = __webpack_require__(4);
 var NodeObfuscator_1 = __webpack_require__(5);
 
 var FunctionObfuscator = function (_NodeObfuscator_1$Nod) {
@@ -2532,7 +2542,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 escodegen = __webpack_require__(10);
-var estraverse = __webpack_require__(3);
+var estraverse = __webpack_require__(4);
 var NodeType_1 = __webpack_require__(6);
 var NodeObfuscator_1 = __webpack_require__(5);
 var Nodes_1 = __webpack_require__(7);
@@ -2615,7 +2625,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 estraverse = __webpack_require__(3);
+var estraverse = __webpack_require__(4);
 var NodeObfuscator_1 = __webpack_require__(5);
 var Nodes_1 = __webpack_require__(7);
 var Utils_1 = __webpack_require__(0);
@@ -2682,7 +2692,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 escodegen = __webpack_require__(10);
-var estraverse = __webpack_require__(3);
+var estraverse = __webpack_require__(4);
 var NodeType_1 = __webpack_require__(6);
 var NodeObfuscator_1 = __webpack_require__(5);
 var Nodes_1 = __webpack_require__(7);
@@ -2764,7 +2774,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 estraverse = __webpack_require__(3);
+var estraverse = __webpack_require__(4);
 var NodeType_1 = __webpack_require__(6);
 var NodeObfuscator_1 = __webpack_require__(5);
 var NodeUtils_1 = __webpack_require__(1);

+ 7 - 4
src/JavaScriptObfuscator.ts

@@ -1,5 +1,5 @@
 import { IObfuscationResult } from "./interfaces/IObfuscationResult";
-import { IOptionsPreset } from "./interfaces/IOptionsPreset";
+import { IObfuscatorOptions } from "./interfaces/IObfuscatorOptions";
 
 import { JavaScriptObfuscatorCLI } from "./cli/JavaScriptObfuscatorCLI";
 import { JavaScriptObfuscatorInternal } from "./JavaScriptObfuscatorInternal";
@@ -7,11 +7,14 @@ import { JavaScriptObfuscatorInternal } from "./JavaScriptObfuscatorInternal";
 export class JavaScriptObfuscator {
     /**
      * @param sourceCode
-     * @param options
+     * @param obfuscatorOptions
      * @returns {string}
      */
-    public static obfuscate (sourceCode: string, options: IOptionsPreset = {}): IObfuscationResult {
-        let javaScriptObfuscator: JavaScriptObfuscatorInternal = new JavaScriptObfuscatorInternal(sourceCode, options);
+    public static obfuscate (sourceCode: string, obfuscatorOptions: IObfuscatorOptions = {}): IObfuscationResult {
+        let javaScriptObfuscator: JavaScriptObfuscatorInternal = new JavaScriptObfuscatorInternal(
+            sourceCode,
+            obfuscatorOptions
+        );
 
         javaScriptObfuscator.obfuscate();
 

+ 7 - 4
src/JavaScriptObfuscatorInternal.ts

@@ -1,11 +1,11 @@
 import * as esprima from 'esprima';
 import * as escodegen from 'escodegen';
 
+import { IObfuscatorOptions } from "./interfaces/IObfuscatorOptions";
 import { IGeneratorOutput } from "./interfaces/IGeneratorOutput";
 import { INode } from './interfaces/nodes/INode';
 import { IObfuscationResult } from "./interfaces/IObfuscationResult";
 import { IOptions } from './interfaces/IOptions';
-import { IOptionsPreset } from "./interfaces/IOptionsPreset";
 
 import { TSourceMapMode } from "./types/TSourceMapMode";
 
@@ -45,11 +45,14 @@ export class JavaScriptObfuscatorInternal {
 
     /**
      * @param sourceCode
-     * @param customOptions
+     * @param obfuscatorOptions
      */
-    constructor (sourceCode: string, customOptions?: IOptionsPreset) {
+    constructor (sourceCode: string, obfuscatorOptions?: IObfuscatorOptions) {
         this.sourceCode = sourceCode;
-        this.options = new Options(customOptions);
+
+        if (obfuscatorOptions) {
+            this.options = new Options(obfuscatorOptions);
+        }
     }
 
     /**

+ 6 - 2
src/NodeUtils.ts

@@ -88,14 +88,18 @@ export class NodeUtils {
      * @returns {INode}
      */
     public static getBlockScopeOfNode (node: INode, depth: number = 0): TNodeWithBlockStatement {
-        let parentNode: INode = node.parentNode;
+        let parentNode: INode | undefined = node.parentNode;
 
         if (!parentNode) {
             throw new ReferenceError('`parentNode` property of given node is `undefined`');
         }
 
         if (Nodes.isBlockStatementNode(parentNode)) {
-            if (!Utils.arrayContains(NodeUtils.nodesWithBlockScope, parentNode['parentNode'].type)) {
+            if (!parentNode.parentNode) {
+                throw new ReferenceError('`parentNode` property of `parentNode` of given node is `undefined`');
+            }
+
+            if (!Utils.arrayContains(NodeUtils.nodesWithBlockScope, parentNode.parentNode.type)) {
                 return NodeUtils.getBlockScopeOfNode(parentNode, depth);
             } else if (depth > 0) {
                 return NodeUtils.getBlockScopeOfNode(parentNode, --depth);

+ 1 - 3
src/Nodes.ts

@@ -19,13 +19,11 @@ export class Nodes {
      * @returns IProgramNode
      */
     public static getProgramNode (bodyNode: TStatement[]): IProgramNode {
-        let programNode: IProgramNode = {
+        return {
             'type': NodeType.Program,
             'body': bodyNode,
             'sourceType': 'script'
         };
-
-        return programNode;
     }
 
     /**

+ 5 - 3
src/Obfuscator.ts

@@ -1,6 +1,6 @@
 import * as estraverse from 'estraverse';
 
-import { ICustomNode } from './interfaces/ICustomNode';
+import { ICustomNode } from './interfaces/custom-nodes/ICustomNode';
 import { INode } from './interfaces/nodes/INode';
 import { IObfuscator } from "./interfaces/IObfuscator";
 import { IOptions } from "./interfaces/IOptions";
@@ -110,11 +110,13 @@ export class Obfuscator implements IObfuscator {
      * @param parentNode
      */
     private initializeNodeObfuscators (node: INode, parentNode: INode): void {
-        if (!this.nodeObfuscators.has(node.type)) {
+        let nodeObfuscators: TNodeObfuscator[] | undefined = this.nodeObfuscators.get(node.type);
+
+        if (!nodeObfuscators) {
             return;
         }
 
-        this.nodeObfuscators.get(node.type).forEach((obfuscator: TNodeObfuscator) => {
+        nodeObfuscators.forEach((obfuscator: TNodeObfuscator) => {
             new obfuscator(this.nodes, this.options).obfuscateNode(node, parentNode);
         });
     }

+ 6 - 6
src/Options.ts

@@ -1,5 +1,5 @@
+import { IObfuscatorOptions } from "./interfaces/IObfuscatorOptions";
 import { IOptions } from "./interfaces/IOptions";
-import { IOptionsPreset } from "./interfaces/IOptionsPreset";
 
 import { OptionsNormalizer } from "./OptionsNormalizer";
 
@@ -7,17 +7,17 @@ import { DEFAULT_PRESET } from "./preset-options/DefaultPreset";
 
 export class Options implements IOptions {
     /**
-     * @type {IOptionsPreset}
+     * @type {IObfuscatorOptions}
      */
-    private options: IOptionsPreset;
+    private options: IObfuscatorOptions;
 
     /**
-     * @param options
+     * @param obfuscatorOptions
      */
-    constructor (options: IOptionsPreset) {
+    constructor (obfuscatorOptions: IObfuscatorOptions) {
         this.options = Object.freeze(
             OptionsNormalizer.normalizeOptionsPreset(
-                Object.assign({}, DEFAULT_PRESET, options)
+                Object.assign({}, DEFAULT_PRESET, obfuscatorOptions)
             )
         );
     }

+ 26 - 21
src/OptionsNormalizer.ts

@@ -1,12 +1,13 @@
-import { IOptionsPreset } from "./interfaces/IOptionsPreset";
+import { IObfuscatorOptions } from "./interfaces/IObfuscatorOptions";
 
 import { TOptionsNormalizerRule } from "./types/TOptionsNormalizerRule";
+import {DEFAULT_PRESET} from "./preset-options/DefaultPreset";
 
 export class OptionsNormalizer {
     /**
-     * @type {IOptionsPreset}
+     * @type {IObfuscatorOptions}
      */
-    private static DISABLED_UNICODE_ARRAY_OPTIONS: IOptionsPreset = {
+    private static DISABLED_UNICODE_ARRAY_OPTIONS: IObfuscatorOptions = {
         encodeUnicodeLiterals: false,
         rotateUnicodeArray: false,
         unicodeArray: false,
@@ -15,9 +16,9 @@ export class OptionsNormalizer {
     };
 
     /**
-     * @type {IOptionsPreset}
+     * @type {IObfuscatorOptions}
      */
-    private static SELF_DEFENDING_OPTIONS: IOptionsPreset = {
+    private static SELF_DEFENDING_OPTIONS: IObfuscatorOptions = {
         compact: true,
         selfDefending: true
     };
@@ -33,10 +34,10 @@ export class OptionsNormalizer {
 
     /**
      * @param options
-     * @returns {IOptionsPreset}
+     * @returns {IObfuscatorOptions}
      */
-    public static normalizeOptionsPreset (options: IOptionsPreset): IOptionsPreset {
-        let normalizedOptions: IOptionsPreset = Object.assign({}, options);
+    public static normalizeOptionsPreset (options: IObfuscatorOptions): IObfuscatorOptions {
+        let normalizedOptions: IObfuscatorOptions = Object.assign({}, options);
 
         for (let normalizerRule of OptionsNormalizer.normalizerRules) {
             normalizedOptions = normalizerRule(normalizedOptions);
@@ -47,9 +48,9 @@ export class OptionsNormalizer {
 
     /**
      * @param options
-     * @returns {IOptionsPreset}
+     * @returns {IObfuscatorOptions}
      */
-    private static selfDefendingRule (options: IOptionsPreset): IOptionsPreset {
+    private static selfDefendingRule (options: IObfuscatorOptions): IObfuscatorOptions {
         if (options.selfDefending) {
             Object.assign(options, OptionsNormalizer.SELF_DEFENDING_OPTIONS);
         }
@@ -59,9 +60,9 @@ export class OptionsNormalizer {
 
     /**
      * @param options
-     * @returns {IOptionsPreset}
+     * @returns {IObfuscatorOptions}
      */
-    private static unicodeArrayRule (options: IOptionsPreset): IOptionsPreset {
+    private static unicodeArrayRule (options: IObfuscatorOptions): IObfuscatorOptions {
         if (!options.unicodeArray) {
             Object.assign(options, OptionsNormalizer.DISABLED_UNICODE_ARRAY_OPTIONS);
         }
@@ -71,19 +72,23 @@ export class OptionsNormalizer {
 
     /**
      * @param options
-     * @returns {IOptionsPreset}
+     * @returns {IObfuscatorOptions}
      */
-    private static unicodeArrayThresholdRule (options: IOptionsPreset): IOptionsPreset {
+    private static unicodeArrayThresholdRule (options: IObfuscatorOptions): IObfuscatorOptions {
         const minValue: number = 0,
             maxValue: number = 1;
 
-        options.unicodeArrayThreshold = Math.min(
-            Math.max(
-                options.unicodeArrayThreshold,
-                minValue
-            ),
-            maxValue
-        );
+        if (typeof options.unicodeArrayThreshold !== 'number') {
+            options.unicodeArrayThreshold = DEFAULT_PRESET.unicodeArrayThreshold;
+        } else {
+            options.unicodeArrayThreshold = Math.min(
+                Math.max(
+                    options.unicodeArrayThreshold,
+                    minValue
+                ),
+                maxValue
+            );
+        }
 
         return options;
     }

+ 8 - 10
src/Utils.ts

@@ -25,25 +25,23 @@ export class Utils {
     /**
      * @param array
      * @param times
-     * @param reverse
      * @returns {T[]}
      */
-    public static arrayRotate <T> (array: T[], times: number, reverse: boolean = false): T[] {
+    public static arrayRotate <T> (array: T[], times: number): T[] {
+        if (!array.length) {
+            throw new ReferenceError(`Cannot rotate empty array.`);
+        }
+
         if (times <= 0) {
             return array;
         }
 
         let newArray: T[] = array,
-            temp: T;
+            temp: T | undefined;
 
         while (times--) {
-            if (!reverse) {
-                temp = newArray.pop();
-                newArray.unshift(temp);
-            } else {
-                temp = newArray.shift();
-                newArray.push(temp);
-            }
+            temp = newArray.pop()!;
+            newArray.unshift(temp);
         }
 
         return newArray;

+ 9 - 9
src/cli/JavaScriptObfuscatorCLI.ts

@@ -3,7 +3,7 @@ import * as path from 'path';
 import { Command } from 'commander';
 
 import { IObfuscationResult } from "../interfaces/IObfuscationResult";
-import { IOptionsPreset } from "../interfaces/IOptionsPreset";
+import { IObfuscatorOptions } from "../interfaces/IObfuscatorOptions";
 
 import { SourceMapMode } from "../enums/SourceMapMode";
 
@@ -97,10 +97,10 @@ export class JavaScriptObfuscatorCLI {
     }
 
     /**
-     * @returns {IOptionsPreset}
+     * @returns {IObfuscatorOptions}
      */
-    private buildOptions (): IOptionsPreset {
-        let options: IOptionsPreset = {},
+    private buildOptions (): IObfuscatorOptions {
+        let obfuscatorOptions: IObfuscatorOptions = {},
             availableOptions: string[] = Object.keys(DEFAULT_PRESET);
 
         for (let option in this.commands) {
@@ -112,10 +112,10 @@ export class JavaScriptObfuscatorCLI {
                 continue;
             }
 
-            options[option] = (<any>this.commands)[option];
+            obfuscatorOptions[option] = (<any>this.commands)[option];
         }
 
-        return Object.assign({}, DEFAULT_PRESET, options);
+        return Object.assign({}, DEFAULT_PRESET, obfuscatorOptions);
     }
 
     private configureCommands (): void {
@@ -155,7 +155,7 @@ export class JavaScriptObfuscatorCLI {
     }
 
     private processData (): void {
-        let options: IOptionsPreset = this.buildOptions(),
+        let options: IObfuscatorOptions = this.buildOptions(),
             outputCodePath: string = CLIUtils.getOutputCodePath(this.commands, this.inputPath);
 
         if (options.sourceMap) {
@@ -169,7 +169,7 @@ export class JavaScriptObfuscatorCLI {
      * @param outputCodePath
      * @param options
      */
-    private processDataWithoutSourceMap (outputCodePath: string, options: IOptionsPreset): void {
+    private processDataWithoutSourceMap (outputCodePath: string, options: IObfuscatorOptions): void {
         let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(this.data, options).getObfuscatedCode();
 
         CLIUtils.writeFile(outputCodePath, obfuscatedCode);
@@ -179,7 +179,7 @@ export class JavaScriptObfuscatorCLI {
      * @param outputCodePath
      * @param options
      */
-    private processDataWithSourceMap (outputCodePath: string, options: IOptionsPreset): void {
+    private processDataWithSourceMap (outputCodePath: string, options: IObfuscatorOptions): void {
         let javaScriptObfuscator: JavaScriptObfuscatorInternal = new JavaScriptObfuscatorInternal(this.data, options),
             obfuscationResult: IObfuscationResult,
             outputSourceMapPath: string = CLIUtils.getOutputSourceMapPath(outputCodePath);

+ 5 - 4
src/custom-nodes/Node.ts

@@ -1,4 +1,4 @@
-import { ICustomNode } from '../interfaces/ICustomNode';
+import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
 import { INode } from '../interfaces/nodes/INode';
 import { IOptions } from "../interfaces/IOptions";
 
@@ -6,11 +6,9 @@ import { AppendState } from '../enums/AppendState';
 
 export abstract class Node implements ICustomNode {
     /**
-     * TODO: add `abstract` modifier
-     *
      * @type {AppendState}
      */
-    protected appendState: AppendState;
+    protected abstract appendState: AppendState;
 
     /**
      * @type {IOptions}
@@ -24,6 +22,9 @@ export abstract class Node implements ICustomNode {
         this.options = options;
     }
 
+    /**
+     * @param astTree
+     */
     public abstract appendNode (astTree: INode): void;
 
     /**

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

@@ -1,5 +1,3 @@
-import * as esprima from 'esprima';
-
 import { INode } from "../../interfaces/nodes/INode";
 
 import { TNodeWithBlockStatement } from "../../types/TNodeWithBlockStatement";

+ 4 - 4
src/custom-nodes/unicode-array-nodes/UnicodeArrayCallsWrapper.ts

@@ -53,6 +53,10 @@ export class UnicodeArrayCallsWrapper extends Node {
      * @param blockScopeNode
      */
     public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+        if (!this.unicodeArray.length) {
+            return;
+        }
+
         NodeUtils.insertNodeAtIndex(blockScopeNode.body, this.getNode(), 1);
     }
 
@@ -67,10 +71,6 @@ export class UnicodeArrayCallsWrapper extends Node {
      * @returns {INode}
      */
     public getNode (): INode {
-        if (!this.unicodeArray.length) {
-            return;
-        }
-
         return super.getNode();
     }
 

+ 4 - 4
src/custom-nodes/unicode-array-nodes/UnicodeArrayDecodeNode.ts

@@ -50,6 +50,10 @@ export class UnicodeArrayDecodeNode extends Node {
      * @param blockScopeNode
      */
     public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+        if (!this.unicodeArray.length) {
+            return;
+        }
+
         NodeUtils.insertNodeAtIndex(blockScopeNode.body, this.getNode(), 1);
     }
 
@@ -57,10 +61,6 @@ export class UnicodeArrayDecodeNode extends Node {
      * @returns {INode}
      */
     public getNode (): INode {
-        if (!this.unicodeArray.length) {
-            return;
-        }
-
         return super.getNode();
     }
 

+ 4 - 4
src/custom-nodes/unicode-array-nodes/UnicodeArrayNode.ts

@@ -55,6 +55,10 @@ export class UnicodeArrayNode extends Node {
      * @param blockScopeNode
      */
     public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+        if (!this.unicodeArray.length) {
+            return;
+        }
+
         NodeUtils.prependNode(blockScopeNode.body, this.getNode());
     }
 
@@ -76,10 +80,6 @@ export class UnicodeArrayNode extends Node {
      * @returns {INode}
      */
     public getNode (): INode {
-        if (!this.unicodeArray.length) {
-            return;
-        }
-
         Utils.arrayRotate <string> (this.unicodeArray, this.unicodeArrayRotateValue);
 
         return super.getNode();

+ 4 - 4
src/custom-nodes/unicode-array-nodes/UnicodeArrayRotateFunctionNode.ts

@@ -57,6 +57,10 @@ export class UnicodeArrayRotateFunctionNode extends Node {
      * @param blockScopeNode
      */
     public appendNode (blockScopeNode: TNodeWithBlockStatement): void {
+        if (!this.unicodeArray.length) {
+            return;
+        }
+
         NodeUtils.insertNodeAtIndex(blockScopeNode.body, this.getNode(), 1);
     }
 
@@ -64,10 +68,6 @@ export class UnicodeArrayRotateFunctionNode extends Node {
      * @returns {INode}
      */
     public getNode (): INode {
-        if (!this.unicodeArray.length) {
-            return;
-        }
-
         return super.getNode();
     }
 

+ 0 - 35
src/interfaces/ICustomNode.d.ts

@@ -1,35 +0,0 @@
-import { INode } from '../interfaces/nodes/INode';
-
-import { AppendState } from '../enums/AppendState';
-
-export interface ICustomNode {
-    /**
-     * @param astTree
-     */
-    appendNode (astTree: INode): void;
-
-    /**
-     * @returns {AppendState}
-     */
-    getAppendState (): AppendState;
-
-    /**
-     * @returns INode
-     */
-    getNode (): INode;
-
-    /**
-     * @returns {string}
-     */
-    getNodeIdentifier ? (): string;
-
-    /**
-     * @returns any
-     */
-    getNodeData ? (): any;
-
-    /**
-     * @param data
-     */
-    updateNodeData ? (data: any): void;
-}

+ 1 - 1
src/interfaces/INodesGroup.d.ts

@@ -1,4 +1,4 @@
-import { ICustomNode } from './ICustomNode';
+import { ICustomNode } from './custom-nodes/ICustomNode';
 
 export interface INodesGroup {
     /**

+ 1 - 1
src/interfaces/IOptionsPreset.d.ts → src/interfaces/IObfuscatorOptions.d.ts

@@ -1,6 +1,6 @@
 import { TSourceMapMode } from "../types/TSourceMapMode";
 
-export interface IOptionsPreset {
+export interface IObfuscatorOptions {
     compact?: boolean;
     debugProtection?: boolean;
     debugProtectionInterval?: boolean;

+ 20 - 0
src/interfaces/custom-nodes/ICustomNode.d.ts

@@ -0,0 +1,20 @@
+import { INode } from '../nodes/INode';
+
+import { AppendState } from '../../enums/AppendState';
+
+export interface ICustomNode {
+    /**
+     * @param astTree
+     */
+    appendNode (astTree: INode): void;
+
+    /**
+     * @returns {AppendState}
+     */
+    getAppendState (): AppendState;
+
+    /**
+     * @returns INode
+     */
+    getNode (): INode;
+}

+ 13 - 0
src/interfaces/custom-nodes/ICustomNodeWithData.d.ts

@@ -0,0 +1,13 @@
+import { ICustomNode } from "./ICustomNode";
+
+export interface ICustomNodeWithData extends ICustomNode {
+    /**
+     * @returns any
+     */
+    getNodeData (): any;
+
+    /**
+     * @param data
+     */
+    updateNodeData (data: any): void;
+}

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

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

+ 1 - 1
src/interfaces/nodes/IIfStatementNode.ts

@@ -4,5 +4,5 @@ import { INode } from "./INode";
 export interface IIfStatementNode extends INode {
     test: any;
     consequent: IBlockStatementNode;
-    alternate: IBlockStatementNode;
+    alternate: IBlockStatementNode | null;
 }

+ 1 - 1
src/node-groups/NodesGroup.ts

@@ -1,4 +1,4 @@
-import { ICustomNode } from '../interfaces/ICustomNode';
+import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
 
 import { INodesGroup } from '../interfaces/INodesGroup';
 import { IOptions } from "../interfaces/IOptions";

+ 1 - 1
src/node-obfuscators/MemberExpressionObfuscator.ts

@@ -77,7 +77,7 @@ export class MemberExpressionObfuscator extends NodeObfuscator {
     private obfuscateLiteralProperty (node: ILiteralNode): void {
         if (typeof node.value === 'string' && !node['x-verbatim-property']) {
             node['x-verbatim-property'] = {
-                content : this.replaceLiteralValueWithUnicodeValue(<string>node.value),
+                content : this.replaceLiteralValueWithUnicodeValue(node.value),
                 precedence: escodegen.Precedence.Primary
             };
         }

+ 32 - 27
src/node-obfuscators/NodeObfuscator.ts

@@ -1,14 +1,14 @@
-import * as estraverse from 'estraverse';
-
-import { ICustomNode } from '../interfaces/ICustomNode';
+import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
 import { INodeObfuscator } from '../interfaces/INodeObfuscator';
 import { INode } from "../interfaces/nodes/INode";
 import { IOptions } from "../interfaces/IOptions";
 
+import { TUnicodeArrayCallsWrapper } from "../types/custom-nodes/TUnicodeArrayCallsWrapper";
+import { TUnicodeArrayNode } from "../types/custom-nodes/TUnicodeArrayNode";
+
 import { JSFuck } from "../enums/JSFuck";
 
 import { Nodes } from "../Nodes";
-import { UnicodeArrayNode } from "../custom-nodes/unicode-array-nodes/UnicodeArrayNode";
 import { Utils } from '../Utils';
 
 export abstract class NodeObfuscator implements INodeObfuscator {
@@ -54,19 +54,14 @@ export abstract class NodeObfuscator implements INodeObfuscator {
      *
      * @param node
      * @param namesMap
-     * @returns {estraverse.VisitorOption}
      */
     protected storeIdentifiersNames (
         node: INode,
         namesMap: Map <string, string>
-    ): estraverse.VisitorOption {
+    ): void {
         if (Nodes.isIdentifierNode(node) && !this.isReservedName(node.name)) {
             namesMap.set(node.name, Utils.getRandomVariableName());
-
-            return;
         }
-
-        return estraverse.VisitorOption.Skip;
     }
 
     /**
@@ -94,7 +89,7 @@ export abstract class NodeObfuscator implements INodeObfuscator {
                 return;
             }
 
-            node.name = namesMap.get(node.name);
+            node.name = <string>namesMap.get(node.name);
         }
     }
 
@@ -125,20 +120,19 @@ export abstract class NodeObfuscator implements INodeObfuscator {
      * @returns {string}
      */
     protected replaceLiteralValueWithUnicodeValue (nodeValue: string): string {
-        let value: string = nodeValue,
-            replaceWithUnicodeArrayFlag: boolean = Math.random() <= this.options.get('unicodeArrayThreshold');
+        let replaceWithUnicodeArrayFlag: boolean = Math.random() <= this.options.get('unicodeArrayThreshold');
 
         if (this.options.get('encodeUnicodeLiterals') && replaceWithUnicodeArrayFlag) {
-            value = Utils.btoa(value);
+            nodeValue = Utils.btoa(nodeValue);
         }
 
-        value = Utils.stringToUnicode(value);
+        nodeValue = Utils.stringToUnicode(nodeValue);
 
-        if (!this.options.get('unicodeArray') || !replaceWithUnicodeArrayFlag) {
-            return value;
+        if (this.options.get('unicodeArray') && replaceWithUnicodeArrayFlag) {
+            return this.replaceLiteralValueWithUnicodeArrayCall(nodeValue);
         }
 
-        return this.replaceLiteralValueWithUnicodeArrayCall(value);
+        return nodeValue;
     }
 
     /**
@@ -146,23 +140,34 @@ export abstract class NodeObfuscator implements INodeObfuscator {
      * @returns {string}
      */
     protected replaceLiteralValueWithUnicodeArrayCall (value: string): string {
-        let unicodeArrayNode: UnicodeArrayNode = <UnicodeArrayNode> this.nodes.get('unicodeArrayNode'),
-            unicodeArray: string[] = unicodeArrayNode.getNodeData(),
-            sameIndex: number = unicodeArray.indexOf(value),
-            index: number,
+        let unicodeArrayNode: TUnicodeArrayNode = <TUnicodeArrayNode>this.nodes.get('unicodeArrayNode');
+
+        if (!unicodeArrayNode) {
+            throw new ReferenceError('`unicodeArrayNode` node is not found in Map with custom nodes.');
+        }
+
+        let unicodeArray: string[] = unicodeArrayNode.getNodeData(),
+            valueIndex: number = unicodeArray.indexOf(value),
+            literalValueCallIndex: number,
             hexadecimalIndex: string;
 
-        if (sameIndex >= 0) {
-            index = sameIndex;
+        if (valueIndex >= 0) {
+            literalValueCallIndex = valueIndex;
         } else {
-            index = unicodeArray.length;
+            literalValueCallIndex = unicodeArray.length;
             unicodeArrayNode.updateNodeData(value);
         }
 
-        hexadecimalIndex = this.replaceLiteralNumberWithHexadecimalValue(index);
+        hexadecimalIndex = this.replaceLiteralNumberWithHexadecimalValue(literalValueCallIndex);
 
         if (this.options.get('wrapUnicodeArrayCalls')) {
-            return `${this.nodes.get('unicodeArrayCallsWrapper').getNodeIdentifier()}('${hexadecimalIndex}')`;
+            let unicodeArrayCallsWrapper: TUnicodeArrayCallsWrapper = <TUnicodeArrayCallsWrapper>this.nodes.get('unicodeArrayCallsWrapper');
+
+            if (!unicodeArrayCallsWrapper) {
+                throw new ReferenceError('`unicodeArrayCallsWrapper` node is not found in Map with custom nodes.');
+            }
+
+            return `${unicodeArrayCallsWrapper.getNodeIdentifier()}('${hexadecimalIndex}')`;
         }
 
         return `${unicodeArrayNode.getNodeIdentifier()}[${hexadecimalIndex}]`;

+ 1 - 1
src/node-obfuscators/ObjectExpressionObfuscator.ts

@@ -52,7 +52,7 @@ export class ObjectExpressionObfuscator extends NodeObfuscator {
     private obfuscateLiteralPropertyKey (node: ILiteralNode): void {
         if (typeof node.value === 'string' && !node['x-verbatim-property']) {
             node['x-verbatim-property'] = {
-                content : Utils.stringToUnicode(<string>node.value),
+                content : Utils.stringToUnicode(node.value),
                 precedence: escodegen.Precedence.Primary
             };
         }

+ 2 - 2
src/preset-options/DefaultPreset.ts

@@ -1,8 +1,8 @@
-import { IOptionsPreset } from "../interfaces/IOptionsPreset";
+import { IObfuscatorOptions } from "../interfaces/IObfuscatorOptions";
 
 import { SourceMapMode } from "../enums/SourceMapMode";
 
-export const DEFAULT_PRESET: IOptionsPreset = Object.freeze({
+export const DEFAULT_PRESET: IObfuscatorOptions = Object.freeze({
     compact: true,
     debugProtection: false,
     debugProtectionInterval: false,

+ 2 - 2
src/preset-options/NoCustomNodesPreset.ts

@@ -1,8 +1,8 @@
-import { IOptionsPreset } from "../interfaces/IOptionsPreset";
+import { IObfuscatorOptions } from "../interfaces/IObfuscatorOptions";
 
 import { SourceMapMode } from "../enums/SourceMapMode";
 
-export const NO_CUSTOM_NODES_PRESET: IOptionsPreset = Object.freeze({
+export const NO_CUSTOM_NODES_PRESET: IObfuscatorOptions = Object.freeze({
     compact: true,
     debugProtection: false,
     debugProtectionInterval: false,

+ 1 - 1
src/types/TNodeObfuscator.d.ts

@@ -1,4 +1,4 @@
-import { ICustomNode } from "../interfaces/ICustomNode";
+import { ICustomNode } from "../interfaces/custom-nodes/ICustomNode";
 import { INodeObfuscator } from "../interfaces/INodeObfuscator";
 import { IOptions } from "../interfaces/IOptions";
 

+ 2 - 2
src/types/TOptionsNormalizerRule.ts

@@ -1,3 +1,3 @@
-import { IOptionsPreset } from "../interfaces/IOptionsPreset";
+import { IObfuscatorOptions } from "../interfaces/IObfuscatorOptions";
 
-export type TOptionsNormalizerRule = (options: IOptionsPreset) => IOptionsPreset;
+export type TOptionsNormalizerRule = (options: IObfuscatorOptions) => IObfuscatorOptions;

+ 3 - 0
src/types/custom-nodes/TUnicodeArrayCallsWrapper.ts

@@ -0,0 +1,3 @@
+import { ICustomNodeWithIdentifier } from "../../interfaces/custom-nodes/ICustomNodeWithIdentifier";
+
+export type TUnicodeArrayCallsWrapper = ICustomNodeWithIdentifier;

+ 4 - 0
src/types/custom-nodes/TUnicodeArrayNode.d.ts

@@ -0,0 +1,4 @@
+import { ICustomNodeWithData } from "../../interfaces/custom-nodes/ICustomNodeWithData";
+import { ICustomNodeWithIdentifier } from "../../interfaces/custom-nodes/ICustomNodeWithIdentifier";
+
+export type TUnicodeArrayNode = ICustomNodeWithData & ICustomNodeWithIdentifier;

+ 2 - 1
test/dev/test.ts

@@ -60,7 +60,8 @@ let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
     `,
     {
         disableConsoleOutput: false,
-        encodeUnicodeLiterals: true
+        encodeUnicodeLiterals: true,
+        unicodeArrayThreshold: 0
     }
 ).getObfuscatedCode();
 

+ 1 - 1
test/functional-tests/JavaScriptObfuscator.spec.ts

@@ -7,7 +7,7 @@ import { NO_CUSTOM_NODES_PRESET } from "../../src/preset-options/NoCustomNodesPr
 const assert: Chai.AssertStatic = require('chai').assert;
 
 describe('JavaScriptObfuscator', () => {
-    describe('obfuscate (sourceCode: string, customOptions?: IOptionsPreset): IObfuscationResult', () => {
+    describe('obfuscate (sourceCode: string, customOptions?: IObfuscatorOptions): IObfuscationResult', () => {
         describe('if `sourceMap` option is `false`', () => {
             it('should returns object with obfuscated code and empty source map', () => {
                 let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(

+ 0 - 18
test/unit-tests/NodeUtils.spec.ts

@@ -59,12 +59,6 @@ describe('NodeUtils', () => {
         });
 
         it('should does not change `BlockStatement` node body if given node is not a valid Node', () => {
-            assert.doesNotChange(
-                () => NodeUtils.appendNode(blockStatementNode.body, <INode>null),
-                blockStatementNode,
-                'body'
-            );
-
             assert.doesNotChange(
                 () => NodeUtils.appendNode(blockStatementNode.body, <INode>{}),
                 blockStatementNode,
@@ -234,12 +228,6 @@ describe('NodeUtils', () => {
         });
 
         it('should does not change `BlockStatement` node body if given node is not a valid Node', () => {
-            assert.doesNotChange(
-                () => NodeUtils.insertNodeAtIndex(blockStatementNode.body, <INode>null, 1),
-                blockStatementNode,
-                'body'
-            );
-
             assert.doesNotChange(
                 () => NodeUtils.insertNodeAtIndex(blockStatementNode.body, <INode>{}, 1),
                 blockStatementNode,
@@ -323,12 +311,6 @@ describe('NodeUtils', () => {
         });
 
         it('should does not change `BlockStatement` node body if given node is not a valid Node', () => {
-            assert.doesNotChange(
-                () => NodeUtils.prependNode(blockStatementNode.body, <INode>null),
-                blockStatementNode,
-                'body'
-            );
-
             assert.doesNotChange(
                 () => NodeUtils.prependNode(blockStatementNode.body, <INode>{}),
                 blockStatementNode,

+ 4 - 4
test/unit-tests/OptionsNormalizer.spec.ts

@@ -1,4 +1,4 @@
-import { IOptionsPreset } from "../../src/interfaces/IOptionsPreset";
+import { IObfuscatorOptions } from "../../src/interfaces/IObfuscatorOptions";
 
 import { OptionsNormalizer } from '../../src/OptionsNormalizer';
 
@@ -7,9 +7,9 @@ import { DEFAULT_PRESET } from '../../src/preset-options/DefaultPreset';
 const assert: Chai.AssertStatic = require('chai').assert;
 
 describe('OptionsNormalizer', () => {
-    describe('normalizeOptionsPreset (options: IOptionsPreset): IOptionsPreset', () => {
-        let optionsPreset1: IOptionsPreset,
-            optionsPreset2: IOptionsPreset;
+    describe('normalizeOptionsPreset (options: IObfuscatorOptions): IObfuscatorOptions', () => {
+        let optionsPreset1: IObfuscatorOptions,
+            optionsPreset2: IObfuscatorOptions;
 
         beforeEach(() => {
             optionsPreset1 = Object.assign({}, DEFAULT_PRESET, {

+ 7 - 6
test/unit-tests/Utils.spec.ts

@@ -13,7 +13,7 @@ describe('Utils', () => {
         });
     });
 
-    describe('arrayRotate <T> (array: T[], times: number, reverse: boolean = false): T[]', () => {
+    describe('arrayRotate <T> (array: T[], times: number): T[]', () => {
         let array: number[];
 
         beforeEach(() => {
@@ -24,13 +24,14 @@ describe('Utils', () => {
             assert.deepEqual(Utils.arrayRotate(array, 2), [5, 6, 1, 2, 3, 4]);
         });
 
-        it('should rotate (shift) array by a given value in reverse directions', () => {
-            assert.deepEqual(Utils.arrayRotate(array, 2, true), [3, 4, 5, 6, 1, 2]);
-        });
 
         it('should do nothing if value <= 0', () => {
-            assert.deepEqual(Utils.arrayRotate(array, 0, true), [1, 2, 3, 4, 5, 6]);
-            assert.deepEqual(Utils.arrayRotate(array, -1, true), [1, 2, 3, 4, 5, 6]);
+            assert.deepEqual(Utils.arrayRotate(array, 0), [1, 2, 3, 4, 5, 6]);
+            assert.deepEqual(Utils.arrayRotate(array, -1), [1, 2, 3, 4, 5, 6]);
+        });
+
+        it('should throw exception if array is empty', () => {
+            assert.throws(() => Utils.arrayRotate([], 5), ReferenceError);
         });
     });
 

+ 1 - 1
test/unit-tests/node-obfuscators/CatchClauseObfuscator.spec.ts

@@ -1,5 +1,5 @@
 import { ICatchClauseNode } from "../../../src/interfaces/nodes/ICatchClauseNode";
-import { ICustomNode } from "../../../src/interfaces/ICustomNode";
+import { ICustomNode } from "../../../src/interfaces/custom-nodes/ICustomNode";
 import { IExpressionStatementNode } from "../../../src/interfaces/nodes/IExpressionStatementNode";
 
 import { DEFAULT_PRESET } from "../../../src/preset-options/DefaultPreset";

+ 3 - 3
test/unit-tests/node-obfuscators/FunctionDeclarationObfuscator.spec.ts

@@ -1,5 +1,5 @@
 import { IBlockStatementNode } from "../../../src/interfaces/nodes/IBlockStatementNode";
-import { ICustomNode } from "../../../src/interfaces/ICustomNode";
+import { ICustomNode } from "../../../src/interfaces/custom-nodes/ICustomNode";
 import { IExpressionStatementNode } from "../../../src/interfaces/nodes/IExpressionStatementNode";
 import { IFunctionDeclarationNode } from "../../../src/interfaces/nodes/IFunctionDeclarationNode";
 import { IProgramNode } from "../../../src/interfaces/nodes/IProgramNode";
@@ -63,7 +63,7 @@ describe('FunctionDeclarationObfuscator', () => {
 
                 functionDeclarationObfuscator.obfuscateNode(
                     functionDeclarationNode,
-                    functionDeclarationNode['parentNode']
+                    blockStatementNode
                 );
             });
 
@@ -87,7 +87,7 @@ describe('FunctionDeclarationObfuscator', () => {
 
                 functionDeclarationObfuscator.obfuscateNode(
                     functionDeclarationNode,
-                    functionDeclarationNode['parentNode']
+                    programNode
                 );
             });
 

+ 1 - 1
test/unit-tests/node-obfuscators/FunctionObfuscator.spec.ts

@@ -1,5 +1,5 @@
 import { IBlockStatementNode } from "../../../src/interfaces/nodes/IBlockStatementNode";
-import { ICustomNode } from "../../../src/interfaces/ICustomNode";
+import { ICustomNode } from "../../../src/interfaces/custom-nodes/ICustomNode";
 import { IExpressionStatementNode } from "../../../src/interfaces/nodes/IExpressionStatementNode";
 import { IFunctionDeclarationNode } from "../../../src/interfaces/nodes/IFunctionDeclarationNode";
 import { IIdentifierNode } from "../../../src/interfaces/nodes/IIdentifierNode";

+ 3 - 1
tsconfig-test.json

@@ -8,7 +8,9 @@
     "emitDecoratorMetadata": true,
     "experimentalDecorators": true,
     "removeComments": true,
-    "noImplicitAny": true
+    "noImplicitAny": true,
+    "strictNullChecks": true,
+    "noUnusedLocals": true
   },
   "exclude": [
     "node_modules"

+ 3 - 1
tsconfig.json

@@ -6,6 +6,8 @@
     "emitDecoratorMetadata": true,
     "experimentalDecorators": true,
     "removeComments": true,
-    "noImplicitAny": true
+    "noImplicitAny": true,
+    "strictNullChecks": true,
+    "noUnusedLocals": true
   }
 }