sanex3339 8 rokov pred
rodič
commit
17eee8aa3f

+ 192 - 53
dist/index.js

@@ -360,9 +360,11 @@ module.exports = require("inversify");
 "use strict";
 
 exports.ServiceIdentifiers = {
+    'Factory<ICalleeDataExtractor>': Symbol('Factory<ICalleeDataExtractor>'),
     'Factory<IControlFlowReplacer>': Symbol('Factory<IControlFlowReplacer>'),
     'Factory<INodeTransformer[]>': Symbol('Factory<INodeTransformer[]>'),
     'Factory<IReplacer>': Symbol('Factory<IReplacer>'),
+    ICalleeDataExtractor: Symbol('ICalleeDataExtractor'),
     IControlFlowReplacer: Symbol('IControlFlowReplacer'),
     IJavaScriptObfuscator: Symbol('IJavaScriptObfuscator'),
     INodeTransformer: Symbol('INodeTransformer'),
@@ -2083,12 +2085,12 @@ var ServiceIdentifiers_1 = __webpack_require__(2);
 var NodeControlFlowTransformersModule_1 = __webpack_require__(37);
 var NodeObfuscatorsModule_1 = __webpack_require__(38);
 var NodeTransformersModule_1 = __webpack_require__(39);
+var StackTraceAnalyzerModule_1 = __webpack_require__(114);
 var CustomNodesStorage_1 = __webpack_require__(83);
 var JavaScriptObfuscatorInternal_1 = __webpack_require__(31);
 var ObfuscationEventEmitter_1 = __webpack_require__(59);
 var Obfuscator_1 = __webpack_require__(32);
 var Options_1 = __webpack_require__(74);
-var StackTraceAnalyzer_1 = __webpack_require__(77);
 
 var InversifyContainerFacade = function () {
     function InversifyContainerFacade(options) {
@@ -2101,8 +2103,8 @@ var InversifyContainerFacade = function () {
         }).inSingletonScope();
         this.container.bind(ServiceIdentifiers_1.ServiceIdentifiers.IObfuscator).to(Obfuscator_1.Obfuscator).inSingletonScope();
         this.container.bind(ServiceIdentifiers_1.ServiceIdentifiers.IObfuscationEventEmitter).to(ObfuscationEventEmitter_1.ObfuscationEventEmitter).inSingletonScope();
-        this.container.bind(ServiceIdentifiers_1.ServiceIdentifiers.IStackTraceAnalyzer).to(StackTraceAnalyzer_1.StackTraceAnalyzer).inSingletonScope();
         this.container.bind(ServiceIdentifiers_1.ServiceIdentifiers['IStorage<ICustomNode>']).to(CustomNodesStorage_1.CustomNodesStorage).inSingletonScope();
+        this.container.load(StackTraceAnalyzerModule_1.stackTraceAnalyzerModule);
         this.container.load(NodeTransformersModule_1.nodeTransformersModule);
         this.container.load(NodeControlFlowTransformersModule_1.nodeControlFlowTransformersModule);
         this.container.load(NodeObfuscatorsModule_1.nodeObfuscatorsModule);
@@ -4951,19 +4953,22 @@ var __decorate = undefined && undefined.__decorate || function (decorators, targ
 var __metadata = undefined && undefined.__metadata || function (k, v) {
     if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
 };
+var __param = undefined && undefined.__param || function (paramIndex, decorator) {
+    return function (target, key) {
+        decorator(target, key, paramIndex);
+    };
+};
 var inversify_1 = __webpack_require__(1);
+var ServiceIdentifiers_1 = __webpack_require__(2);
 var estraverse = __webpack_require__(6);
-var NodeType_1 = __webpack_require__(9);
-var FunctionDeclarationCalleeDataExtractor_1 = __webpack_require__(78);
-var FunctionExpressionCalleeDataExtractor_1 = __webpack_require__(79);
-var ObjectExpressionCalleeDataExtractor_1 = __webpack_require__(80);
+var CalleeDataExtractors_1 = __webpack_require__(115);
 var Node_1 = __webpack_require__(4);
 var NodeUtils_1 = __webpack_require__(10);
 var StackTraceAnalyzer_1 = function () {
-    function StackTraceAnalyzer() {
+    function StackTraceAnalyzer(calleeDataExtractorsFactory) {
         _classCallCheck(this, StackTraceAnalyzer);
 
-        this.calleeDataExtractors = new Map([[NodeType_1.NodeType.FunctionDeclaration, FunctionDeclarationCalleeDataExtractor_1.FunctionDeclarationCalleeDataExtractor], [NodeType_1.NodeType.FunctionExpression, FunctionExpressionCalleeDataExtractor_1.FunctionExpressionCalleeDataExtractor], [NodeType_1.NodeType.ObjectExpression, ObjectExpressionCalleeDataExtractor_1.ObjectExpressionCalleeDataExtractor]]);
+        this.calleeDataExtractorsFactory = calleeDataExtractorsFactory;
     }
 
     _createClass(StackTraceAnalyzer, [{
@@ -4989,8 +4994,8 @@ var StackTraceAnalyzer_1 = function () {
                         if (!Node_1.Node.isCallExpressionNode(node) || rootNode.parentNode !== NodeUtils_1.NodeUtils.getBlockScopeOfNode(node)) {
                             return;
                         }
-                        _this.calleeDataExtractors.forEach(function (calleeDataExtractor) {
-                            var calleeData = new calleeDataExtractor(blockScopeBody, node.callee).extract();
+                        StackTraceAnalyzer_1.calleeDataExtractorsList.forEach(function (calleeDataExtractorName) {
+                            var calleeData = _this.calleeDataExtractorsFactory(calleeDataExtractorName).extract(blockScopeBody, node.callee);
                             if (!calleeData) {
                                 return;
                             }
@@ -5028,9 +5033,10 @@ var StackTraceAnalyzer_1 = function () {
     return StackTraceAnalyzer;
 }();
 var StackTraceAnalyzer = StackTraceAnalyzer_1;
+StackTraceAnalyzer.calleeDataExtractorsList = [CalleeDataExtractors_1.CalleeDataExtractors.FunctionDeclarationCalleeDataExtractor, CalleeDataExtractors_1.CalleeDataExtractors.FunctionExpressionCalleeDataExtractor, CalleeDataExtractors_1.CalleeDataExtractors.ObjectExpressionCalleeDataExtractor];
 StackTraceAnalyzer.limitThresholdActivationLength = 25;
 StackTraceAnalyzer.limitThreshold = 0.002;
-StackTraceAnalyzer = StackTraceAnalyzer_1 = __decorate([inversify_1.injectable(), __metadata('design:paramtypes', [])], StackTraceAnalyzer);
+StackTraceAnalyzer = StackTraceAnalyzer_1 = __decorate([inversify_1.injectable(), __param(0, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers['Factory<ICalleeDataExtractor>'])), __metadata('design:paramtypes', [Function])], StackTraceAnalyzer);
 exports.StackTraceAnalyzer = StackTraceAnalyzer;
 
 /***/ },
@@ -5042,37 +5048,56 @@ exports.StackTraceAnalyzer = StackTraceAnalyzer;
 
 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; }; })();
 
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+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 __decorate = undefined && undefined.__decorate || function (decorators, target, key, desc) {
+    var c = arguments.length,
+        r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc,
+        d;
+    if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);else for (var i = decorators.length - 1; i >= 0; i--) {
+        if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    }return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var __metadata = undefined && undefined.__metadata || function (k, v) {
+    if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
+};
+var inversify_1 = __webpack_require__(1);
 var estraverse = __webpack_require__(6);
+var AbstractCalleeDataExtractor_1 = __webpack_require__(116);
 var Node_1 = __webpack_require__(4);
 var NodeUtils_1 = __webpack_require__(10);
+var FunctionDeclarationCalleeDataExtractor = function (_AbstractCalleeDataEx) {
+    _inherits(FunctionDeclarationCalleeDataExtractor, _AbstractCalleeDataEx);
 
-var FunctionDeclarationCalleeDataExtractor = function () {
-    function FunctionDeclarationCalleeDataExtractor(blockScopeBody, callee) {
+    function FunctionDeclarationCalleeDataExtractor() {
         _classCallCheck(this, FunctionDeclarationCalleeDataExtractor);
 
-        this.blockScopeBody = blockScopeBody;
-        this.callee = callee;
+        return _possibleConstructorReturn(this, (FunctionDeclarationCalleeDataExtractor.__proto__ || Object.getPrototypeOf(FunctionDeclarationCalleeDataExtractor)).apply(this, arguments));
     }
 
     _createClass(FunctionDeclarationCalleeDataExtractor, [{
-        key: 'extract',
-        value: function extract() {
+        key: "extract",
+        value: function extract(blockScopeBody, callee) {
             var calleeBlockStatement = null;
-            if (Node_1.Node.isIdentifierNode(this.callee)) {
-                calleeBlockStatement = this.getCalleeBlockStatement(NodeUtils_1.NodeUtils.getBlockScopeOfNode(this.blockScopeBody[0]), this.callee.name);
+            if (Node_1.Node.isIdentifierNode(callee)) {
+                calleeBlockStatement = this.getCalleeBlockStatement(NodeUtils_1.NodeUtils.getBlockScopeOfNode(blockScopeBody[0]), callee.name);
             }
             if (!calleeBlockStatement) {
                 return null;
             }
             return {
                 callee: calleeBlockStatement,
-                name: this.callee.name
+                name: callee.name
             };
         }
     }, {
-        key: 'getCalleeBlockStatement',
+        key: "getCalleeBlockStatement",
         value: function getCalleeBlockStatement(node, name) {
             var calleeBlockStatement = null;
             estraverse.traverse(node, {
@@ -5088,8 +5113,8 @@ var FunctionDeclarationCalleeDataExtractor = function () {
     }]);
 
     return FunctionDeclarationCalleeDataExtractor;
-}();
-
+}(AbstractCalleeDataExtractor_1.AbstractCalleeDataExtractor);
+FunctionDeclarationCalleeDataExtractor = __decorate([inversify_1.injectable(), __metadata('design:paramtypes', [])], FunctionDeclarationCalleeDataExtractor);
 exports.FunctionDeclarationCalleeDataExtractor = FunctionDeclarationCalleeDataExtractor;
 
 /***/ },
@@ -5101,40 +5126,59 @@ exports.FunctionDeclarationCalleeDataExtractor = FunctionDeclarationCalleeDataEx
 
 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; }; })();
 
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+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 __decorate = undefined && undefined.__decorate || function (decorators, target, key, desc) {
+    var c = arguments.length,
+        r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc,
+        d;
+    if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);else for (var i = decorators.length - 1; i >= 0; i--) {
+        if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    }return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var __metadata = undefined && undefined.__metadata || function (k, v) {
+    if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
+};
+var inversify_1 = __webpack_require__(1);
 var estraverse = __webpack_require__(6);
+var AbstractCalleeDataExtractor_1 = __webpack_require__(116);
 var Node_1 = __webpack_require__(4);
 var NodeUtils_1 = __webpack_require__(10);
+var FunctionExpressionCalleeDataExtractor = function (_AbstractCalleeDataEx) {
+    _inherits(FunctionExpressionCalleeDataExtractor, _AbstractCalleeDataEx);
 
-var FunctionExpressionCalleeDataExtractor = function () {
-    function FunctionExpressionCalleeDataExtractor(blockScopeBody, callee) {
+    function FunctionExpressionCalleeDataExtractor() {
         _classCallCheck(this, FunctionExpressionCalleeDataExtractor);
 
-        this.blockScopeBody = blockScopeBody;
-        this.callee = callee;
+        return _possibleConstructorReturn(this, (FunctionExpressionCalleeDataExtractor.__proto__ || Object.getPrototypeOf(FunctionExpressionCalleeDataExtractor)).apply(this, arguments));
     }
 
     _createClass(FunctionExpressionCalleeDataExtractor, [{
-        key: 'extract',
-        value: function extract() {
+        key: "extract",
+        value: function extract(blockScopeBody, callee) {
             var calleeBlockStatement = null;
-            if (Node_1.Node.isIdentifierNode(this.callee)) {
-                calleeBlockStatement = this.getCalleeBlockStatement(NodeUtils_1.NodeUtils.getBlockScopeOfNode(this.blockScopeBody[0]), this.callee.name);
+            if (Node_1.Node.isIdentifierNode(callee)) {
+                calleeBlockStatement = this.getCalleeBlockStatement(NodeUtils_1.NodeUtils.getBlockScopeOfNode(blockScopeBody[0]), callee.name);
             }
-            if (Node_1.Node.isFunctionExpressionNode(this.callee)) {
-                calleeBlockStatement = this.callee.body;
+            if (Node_1.Node.isFunctionExpressionNode(callee)) {
+                calleeBlockStatement = callee.body;
             }
             if (!calleeBlockStatement) {
                 return null;
             }
             return {
                 callee: calleeBlockStatement,
-                name: this.callee.name || null
+                name: callee.name || null
             };
         }
     }, {
-        key: 'getCalleeBlockStatement',
+        key: "getCalleeBlockStatement",
         value: function getCalleeBlockStatement(node, name) {
             var calleeBlockStatement = null;
             estraverse.traverse(node, {
@@ -5150,8 +5194,8 @@ var FunctionExpressionCalleeDataExtractor = function () {
     }]);
 
     return FunctionExpressionCalleeDataExtractor;
-}();
-
+}(AbstractCalleeDataExtractor_1.AbstractCalleeDataExtractor);
+FunctionExpressionCalleeDataExtractor = __decorate([inversify_1.injectable(), __metadata('design:paramtypes', [])], FunctionExpressionCalleeDataExtractor);
 exports.FunctionExpressionCalleeDataExtractor = FunctionExpressionCalleeDataExtractor;
 
 /***/ },
@@ -5163,32 +5207,51 @@ exports.FunctionExpressionCalleeDataExtractor = FunctionExpressionCalleeDataExtr
 
 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; }; })();
 
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+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 __decorate = undefined && undefined.__decorate || function (decorators, target, key, desc) {
+    var c = arguments.length,
+        r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc,
+        d;
+    if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);else for (var i = decorators.length - 1; i >= 0; i--) {
+        if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    }return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var __metadata = undefined && undefined.__metadata || function (k, v) {
+    if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
+};
+var inversify_1 = __webpack_require__(1);
 var estraverse = __webpack_require__(6);
 var Node_1 = __webpack_require__(4);
 var NodeUtils_1 = __webpack_require__(10);
+var AbstractCalleeDataExtractor_1 = __webpack_require__(116);
+var ObjectExpressionCalleeDataExtractor = function (_AbstractCalleeDataEx) {
+    _inherits(ObjectExpressionCalleeDataExtractor, _AbstractCalleeDataEx);
 
-var ObjectExpressionCalleeDataExtractor = function () {
-    function ObjectExpressionCalleeDataExtractor(blockScopeBody, callee) {
+    function ObjectExpressionCalleeDataExtractor() {
         _classCallCheck(this, ObjectExpressionCalleeDataExtractor);
 
-        this.blockScopeBody = blockScopeBody;
-        this.callee = callee;
+        return _possibleConstructorReturn(this, (ObjectExpressionCalleeDataExtractor.__proto__ || Object.getPrototypeOf(ObjectExpressionCalleeDataExtractor)).apply(this, arguments));
     }
 
     _createClass(ObjectExpressionCalleeDataExtractor, [{
-        key: 'extract',
-        value: function extract() {
+        key: "extract",
+        value: function extract(blockScopeBody, callee) {
             var calleeBlockStatement = null,
                 functionExpressionName = null;
-            if (Node_1.Node.isMemberExpressionNode(this.callee)) {
-                var objectMembersCallsChain = this.createObjectMembersCallsChain([], this.callee);
+            if (Node_1.Node.isMemberExpressionNode(callee)) {
+                var objectMembersCallsChain = this.createObjectMembersCallsChain([], callee);
                 if (!objectMembersCallsChain.length) {
                     return null;
                 }
                 functionExpressionName = objectMembersCallsChain[objectMembersCallsChain.length - 1];
-                calleeBlockStatement = this.getCalleeBlockStatement(NodeUtils_1.NodeUtils.getBlockScopeOfNode(this.blockScopeBody[0]), objectMembersCallsChain);
+                calleeBlockStatement = this.getCalleeBlockStatement(NodeUtils_1.NodeUtils.getBlockScopeOfNode(blockScopeBody[0]), objectMembersCallsChain);
             }
             if (!calleeBlockStatement) {
                 return null;
@@ -5199,7 +5262,7 @@ var ObjectExpressionCalleeDataExtractor = function () {
             };
         }
     }, {
-        key: 'createObjectMembersCallsChain',
+        key: "createObjectMembersCallsChain",
         value: function createObjectMembersCallsChain(currentChain, memberExpression) {
             if (Node_1.Node.isIdentifierNode(memberExpression.property) && memberExpression.computed === false) {
                 currentChain.unshift(memberExpression.property.name);
@@ -5216,9 +5279,9 @@ var ObjectExpressionCalleeDataExtractor = function () {
             return currentChain;
         }
     }, {
-        key: 'getCalleeBlockStatement',
+        key: "getCalleeBlockStatement",
         value: function getCalleeBlockStatement(node, objectMembersCallsChain) {
-            var _this = this;
+            var _this2 = this;
 
             var objectName = objectMembersCallsChain.shift();
             if (!objectName) {
@@ -5228,7 +5291,7 @@ var ObjectExpressionCalleeDataExtractor = function () {
             estraverse.traverse(node, {
                 enter: function enter(node, parentNode) {
                     if (Node_1.Node.isVariableDeclaratorNode(node) && Node_1.Node.isIdentifierNode(node.id) && node.init && Node_1.Node.isObjectExpressionNode(node.init) && node.id.name === objectName) {
-                        calleeBlockStatement = _this.findCalleeBlockStatement(node.init.properties, objectMembersCallsChain);
+                        calleeBlockStatement = _this2.findCalleeBlockStatement(node.init.properties, objectMembersCallsChain);
                         return estraverse.VisitorOption.Break;
                     }
                 }
@@ -5236,7 +5299,7 @@ var ObjectExpressionCalleeDataExtractor = function () {
             return calleeBlockStatement;
         }
     }, {
-        key: 'findCalleeBlockStatement',
+        key: "findCalleeBlockStatement",
         value: function findCalleeBlockStatement(objectExpressionProperties, objectMembersCallsChain) {
             var nextItemInCallsChain = objectMembersCallsChain.shift();
             if (!nextItemInCallsChain) {
@@ -5282,8 +5345,8 @@ var ObjectExpressionCalleeDataExtractor = function () {
     }]);
 
     return ObjectExpressionCalleeDataExtractor;
-}();
-
+}(AbstractCalleeDataExtractor_1.AbstractCalleeDataExtractor);
+ObjectExpressionCalleeDataExtractor = __decorate([inversify_1.injectable(), __metadata('design:paramtypes', [])], ObjectExpressionCalleeDataExtractor);
 exports.ObjectExpressionCalleeDataExtractor = ObjectExpressionCalleeDataExtractor;
 
 /***/ },
@@ -5805,6 +5868,82 @@ module.exports = require("reflect-metadata");
 var JavaScriptObfuscator_1 = __webpack_require__(13);
 module.exports = JavaScriptObfuscator_1.JavaScriptObfuscator;
 
+/***/ },
+/* 114 */
+/***/ function(module, exports, __webpack_require__) {
+
+"use strict";
+"use strict";
+
+var inversify_1 = __webpack_require__(1);
+var ServiceIdentifiers_1 = __webpack_require__(2);
+var FunctionDeclarationCalleeDataExtractor_1 = __webpack_require__(78);
+var FunctionExpressionCalleeDataExtractor_1 = __webpack_require__(79);
+var ObjectExpressionCalleeDataExtractor_1 = __webpack_require__(80);
+var StackTraceAnalyzer_1 = __webpack_require__(77);
+var CalleeDataExtractors_1 = __webpack_require__(115);
+exports.stackTraceAnalyzerModule = new inversify_1.ContainerModule(function (bind) {
+    var calleeDataExtractorsTag = 'calleeDataExtractors';
+    bind(ServiceIdentifiers_1.ServiceIdentifiers.IStackTraceAnalyzer).to(StackTraceAnalyzer_1.StackTraceAnalyzer).inSingletonScope();
+    bind(ServiceIdentifiers_1.ServiceIdentifiers.ICalleeDataExtractor).to(FunctionDeclarationCalleeDataExtractor_1.FunctionDeclarationCalleeDataExtractor).whenTargetTagged(calleeDataExtractorsTag, CalleeDataExtractors_1.CalleeDataExtractors.FunctionDeclarationCalleeDataExtractor);
+    bind(ServiceIdentifiers_1.ServiceIdentifiers.ICalleeDataExtractor).to(FunctionExpressionCalleeDataExtractor_1.FunctionExpressionCalleeDataExtractor).whenTargetTagged(calleeDataExtractorsTag, CalleeDataExtractors_1.CalleeDataExtractors.FunctionExpressionCalleeDataExtractor);
+    bind(ServiceIdentifiers_1.ServiceIdentifiers.ICalleeDataExtractor).to(ObjectExpressionCalleeDataExtractor_1.ObjectExpressionCalleeDataExtractor).whenTargetTagged(calleeDataExtractorsTag, CalleeDataExtractors_1.CalleeDataExtractors.ObjectExpressionCalleeDataExtractor);
+    bind(ServiceIdentifiers_1.ServiceIdentifiers['Factory<ICalleeDataExtractor>']).toFactory(function (context) {
+        var cache = new Map();
+        return function (calleeDataExtractorName) {
+            if (cache.has(calleeDataExtractorName)) {
+                return cache.get(calleeDataExtractorName);
+            }
+            var calleeDataExtractor = context.container.getTagged(ServiceIdentifiers_1.ServiceIdentifiers.ICalleeDataExtractor, calleeDataExtractorsTag, calleeDataExtractorName);
+            cache.set(calleeDataExtractorName, calleeDataExtractor);
+            return calleeDataExtractor;
+        };
+    });
+});
+
+/***/ },
+/* 115 */
+/***/ function(module, exports) {
+
+"use strict";
+"use strict";
+
+(function (CalleeDataExtractors) {
+    CalleeDataExtractors[CalleeDataExtractors["FunctionDeclarationCalleeDataExtractor"] = 0] = "FunctionDeclarationCalleeDataExtractor";
+    CalleeDataExtractors[CalleeDataExtractors["FunctionExpressionCalleeDataExtractor"] = 1] = "FunctionExpressionCalleeDataExtractor";
+    CalleeDataExtractors[CalleeDataExtractors["ObjectExpressionCalleeDataExtractor"] = 2] = "ObjectExpressionCalleeDataExtractor";
+})(exports.CalleeDataExtractors || (exports.CalleeDataExtractors = {}));
+var CalleeDataExtractors = exports.CalleeDataExtractors;
+
+/***/ },
+/* 116 */
+/***/ function(module, exports, __webpack_require__) {
+
+"use strict";
+"use strict";
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var __decorate = undefined && undefined.__decorate || function (decorators, target, key, desc) {
+    var c = arguments.length,
+        r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc,
+        d;
+    if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);else for (var i = decorators.length - 1; i >= 0; i--) {
+        if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    }return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var __metadata = undefined && undefined.__metadata || function (k, v) {
+    if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
+};
+var inversify_1 = __webpack_require__(1);
+var AbstractCalleeDataExtractor = function AbstractCalleeDataExtractor() {
+    _classCallCheck(this, AbstractCalleeDataExtractor);
+};
+AbstractCalleeDataExtractor = __decorate([inversify_1.injectable(), __metadata('design:paramtypes', [])], AbstractCalleeDataExtractor);
+exports.AbstractCalleeDataExtractor = AbstractCalleeDataExtractor;
+
 /***/ }
 /******/ ]);
 //# sourceMappingURL=index.js.map

+ 2 - 2
src/JavaScriptObfuscatorInternal.ts

@@ -37,12 +37,12 @@ export class JavaScriptObfuscatorInternal implements IJavaScriptObfuscator {
     };
 
     /**
-     * @types {IStorage<ICustomNode>}
+     * @type {IStorage<ICustomNode>}
      */
     private readonly customNodesStorage: IStorage<ICustomNode>;
 
     /**
-     * @types {IObfuscator}
+     * @type {IObfuscator}
      */
     private readonly obfuscator: IObfuscator;
 

+ 4 - 8
src/container/InversifyContainerFacade.ts

@@ -4,14 +4,15 @@ import { ServiceIdentifiers } from './ServiceIdentifiers';
 import { nodeControlFlowTransformersModule } from './modules/node-transformers/NodeControlFlowTransformersModule';
 import { nodeObfuscatorsModule } from './modules/node-transformers/NodeObfuscatorsModule';
 import { nodeTransformersModule } from './modules/node-transformers/NodeTransformersModule';
+import { stackTraceAnalyzerModule } from './modules/stack-trace-analyzer/StackTraceAnalyzerModule';
 
 import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
 import { IInputOptions } from '../interfaces/IInputOptions';
+import { IInversifyContainerFacade } from '../interfaces/container/IInversifyContainerFacade';
 import { IJavaScriptObfuscator } from '../interfaces/IJavaScriptObfsucator';
 import { IObfuscationEventEmitter } from '../interfaces/IObfuscationEventEmitter';
 import { IObfuscator } from '../interfaces/IObfuscator';
 import { IOptions } from '../interfaces/IOptions';
-import { IStackTraceAnalyzer } from '../interfaces/stack-trace-analyzer/IStackTraceAnalyzer';
 import { IStorage } from '../interfaces/IStorage';
 
 import { CustomNodesStorage } from '../storages/custom-nodes/CustomNodesStorage';
@@ -19,9 +20,8 @@ import { JavaScriptObfuscatorInternal } from '../JavaScriptObfuscatorInternal';
 import { ObfuscationEventEmitter } from '../event-emitters/ObfuscationEventEmitter';
 import { Obfuscator } from '../Obfuscator';
 import { Options } from "../options/Options";
-import { StackTraceAnalyzer } from '../stack-trace-analyzer/StackTraceAnalyzer';
 
-export class InversifyContainerFacade {
+export class InversifyContainerFacade implements IInversifyContainerFacade {
     /**
      * @type {interfaces.Container}
      */
@@ -55,17 +55,13 @@ export class InversifyContainerFacade {
             .to(ObfuscationEventEmitter)
             .inSingletonScope();
 
-        this.container
-            .bind<IStackTraceAnalyzer>(ServiceIdentifiers.IStackTraceAnalyzer)
-            .to(StackTraceAnalyzer)
-            .inSingletonScope();
-
         this.container
             .bind<IStorage<ICustomNode>>(ServiceIdentifiers['IStorage<ICustomNode>'])
             .to(CustomNodesStorage)
             .inSingletonScope();
 
         // modules
+        this.container.load(stackTraceAnalyzerModule);
         this.container.load(nodeTransformersModule);
         this.container.load(nodeControlFlowTransformersModule);
         this.container.load(nodeObfuscatorsModule);

+ 2 - 0
src/container/ServiceIdentifiers.ts

@@ -1,9 +1,11 @@
 import { IContainerServiceIdentifiers } from '../interfaces/container/IContainerServiceIdentifiers';
 
 export const ServiceIdentifiers: IContainerServiceIdentifiers = {
+    'Factory<ICalleeDataExtractor>': Symbol('Factory<ICalleeDataExtractor>'),
     'Factory<IControlFlowReplacer>': Symbol('Factory<IControlFlowReplacer>'),
     'Factory<INodeTransformer[]>': Symbol('Factory<INodeTransformer[]>'),
     'Factory<IReplacer>': Symbol('Factory<IReplacer>'),
+    ICalleeDataExtractor: Symbol('ICalleeDataExtractor'),
     IControlFlowReplacer: Symbol('IControlFlowReplacer'),
     IJavaScriptObfuscator: Symbol('IJavaScriptObfuscator'),
     INodeTransformer: Symbol('INodeTransformer'),

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

@@ -0,0 +1,55 @@
+import { ContainerModule, interfaces } from 'inversify';
+import { ServiceIdentifiers } from '../../ServiceIdentifiers';
+
+import { ICalleeDataExtractor } from '../../../interfaces/stack-trace-analyzer/ICalleeDataExtractor';
+import { IStackTraceAnalyzer } from '../../../interfaces/stack-trace-analyzer/IStackTraceAnalyzer';
+
+import { FunctionDeclarationCalleeDataExtractor } from '../../../stack-trace-analyzer/callee-data-extractors/FunctionDeclarationCalleeDataExtractor';
+import { FunctionExpressionCalleeDataExtractor } from '../../../stack-trace-analyzer/callee-data-extractors/FunctionExpressionCalleeDataExtractor';
+import { ObjectExpressionCalleeDataExtractor } from '../../../stack-trace-analyzer/callee-data-extractors/ObjectExpressionCalleeDataExtractor';
+import { StackTraceAnalyzer } from '../../../stack-trace-analyzer/StackTraceAnalyzer';
+import { CalleeDataExtractors } from '../../../enums/container/CalleeDataExtractors';
+
+export const stackTraceAnalyzerModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
+    const calleeDataExtractorsTag: string = 'calleeDataExtractors';
+
+    // stack trace analyzer
+    bind<IStackTraceAnalyzer>(ServiceIdentifiers.IStackTraceAnalyzer)
+        .to(StackTraceAnalyzer)
+        .inSingletonScope();
+
+    // callee data extractors
+    bind<ICalleeDataExtractor>(ServiceIdentifiers.ICalleeDataExtractor)
+        .to(FunctionDeclarationCalleeDataExtractor)
+        .whenTargetTagged(calleeDataExtractorsTag, CalleeDataExtractors.FunctionDeclarationCalleeDataExtractor);
+
+    bind<ICalleeDataExtractor>(ServiceIdentifiers.ICalleeDataExtractor)
+        .to(FunctionExpressionCalleeDataExtractor)
+        .whenTargetTagged(calleeDataExtractorsTag, CalleeDataExtractors.FunctionExpressionCalleeDataExtractor);
+
+    bind<ICalleeDataExtractor>(ServiceIdentifiers.ICalleeDataExtractor)
+        .to(ObjectExpressionCalleeDataExtractor)
+        .whenTargetTagged(calleeDataExtractorsTag, CalleeDataExtractors.ObjectExpressionCalleeDataExtractor);
+
+    // node transformers factory
+    bind<ICalleeDataExtractor>(ServiceIdentifiers['Factory<ICalleeDataExtractor>'])
+        .toFactory<ICalleeDataExtractor>((context: interfaces.Context) => {
+            const cache: Map <CalleeDataExtractors, ICalleeDataExtractor> = new Map <CalleeDataExtractors, ICalleeDataExtractor> ();
+
+            return (calleeDataExtractorName: CalleeDataExtractors) => {
+                if (cache.has(calleeDataExtractorName)) {
+                    return <ICalleeDataExtractor>cache.get(calleeDataExtractorName);
+                }
+
+                const calleeDataExtractor: ICalleeDataExtractor = context.container.getTagged<ICalleeDataExtractor>(
+                    ServiceIdentifiers.ICalleeDataExtractor,
+                    calleeDataExtractorsTag,
+                    calleeDataExtractorName
+                );
+
+                cache.set(calleeDataExtractorName, calleeDataExtractor);
+
+                return calleeDataExtractor;
+            };
+        });
+});

+ 5 - 0
src/enums/container/CalleeDataExtractors.ts

@@ -0,0 +1,5 @@
+export enum CalleeDataExtractors {
+    FunctionDeclarationCalleeDataExtractor,
+    FunctionExpressionCalleeDataExtractor,
+    ObjectExpressionCalleeDataExtractor,
+}

+ 2 - 0
src/interfaces/container/IContainerServiceIdentifiers.d.ts

@@ -1,9 +1,11 @@
 import { interfaces } from 'inversify';
 
 export interface IContainerServiceIdentifiers {
+    'Factory<ICalleeDataExtractor>': interfaces.ServiceIdentifier<any>;
     'Factory<IControlFlowReplacer>': interfaces.ServiceIdentifier<any>;
     'Factory<INodeTransformer[]>': interfaces.ServiceIdentifier<any>;
     'Factory<IReplacer>': interfaces.ServiceIdentifier<any>;
+    ICalleeDataExtractor: interfaces.ServiceIdentifier<any>;
     IControlFlowReplacer: interfaces.ServiceIdentifier<any>;
     IJavaScriptObfuscator: interfaces.ServiceIdentifier<any>;
     INodeTransformer: interfaces.ServiceIdentifier<any>;

+ 3 - 1
src/interfaces/stack-trace-analyzer/ICalleeDataExtractor.d.ts

@@ -1,5 +1,7 @@
+import * as ESTree from 'estree';
+
 import { ICalleeData } from './ICalleeData';
 
 export interface ICalleeDataExtractor {
-    extract (): ICalleeData|null;
+    extract (blockScopeBody: ESTree.Node[], callee: ESTree.Node): ICalleeData|null;
 }

+ 30 - 21
src/stack-trace-analyzer/StackTraceAnalyzer.ts

@@ -1,19 +1,17 @@
-import { injectable } from 'inversify';
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
 
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
-import { TCalleeDataExtractor } from '../types/TCalleeDataExtractor';
+import { TCalleeDataExtractorsFactory } from '../types/TCalleeDataExtractorsFactory';
 
 import { ICalleeData } from '../interfaces/stack-trace-analyzer/ICalleeData';
+import { ICalleeDataExtractor } from '../interfaces/stack-trace-analyzer/ICalleeDataExtractor';
 import { IStackTraceAnalyzer } from '../interfaces/stack-trace-analyzer/IStackTraceAnalyzer';
 import { IStackTraceData } from '../interfaces/stack-trace-analyzer/IStackTraceData';
 
-import { NodeType } from '../enums/NodeType';
-
-import { FunctionDeclarationCalleeDataExtractor } from './callee-data-extractors/FunctionDeclarationCalleeDataExtractor';
-import { FunctionExpressionCalleeDataExtractor } from './callee-data-extractors/FunctionExpressionCalleeDataExtractor';
-import { ObjectExpressionCalleeDataExtractor } from './callee-data-extractors/ObjectExpressionCalleeDataExtractor';
+import { CalleeDataExtractors } from '../enums/container/CalleeDataExtractors';
 
 import { Node } from '../node/Node';
 import { NodeUtils } from '../node/NodeUtils';
@@ -51,6 +49,15 @@ import { NodeUtils } from '../node/NodeUtils';
  */
 @injectable()
 export class StackTraceAnalyzer implements IStackTraceAnalyzer {
+    /**
+     * @type {CalleeDataExtractors[]}
+     */
+    private static readonly calleeDataExtractorsList: CalleeDataExtractors[] = [
+        CalleeDataExtractors.FunctionDeclarationCalleeDataExtractor,
+        CalleeDataExtractors.FunctionExpressionCalleeDataExtractor,
+        CalleeDataExtractors.ObjectExpressionCalleeDataExtractor
+    ];
+
     /**
      * @type {number}
      */
@@ -62,13 +69,15 @@ export class StackTraceAnalyzer implements IStackTraceAnalyzer {
     private static readonly limitThreshold: number = 0.002;
 
     /**
-     * @type {Map<string, TCalleeDataExtractor>}
+     * @type {(calleeDataExtractorName: CalleeDataExtractors) => ICalleeDataExtractor}
      */
-    private readonly calleeDataExtractors: Map <string, TCalleeDataExtractor> = new Map <string, TCalleeDataExtractor> ([
-        [NodeType.FunctionDeclaration, FunctionDeclarationCalleeDataExtractor],
-        [NodeType.FunctionExpression, FunctionExpressionCalleeDataExtractor],
-        [NodeType.ObjectExpression, ObjectExpressionCalleeDataExtractor]
-    ]);
+    private calleeDataExtractorsFactory: (calleeDataExtractorName: CalleeDataExtractors) => ICalleeDataExtractor;
+
+    constructor (
+        @inject(ServiceIdentifiers['Factory<ICalleeDataExtractor>']) calleeDataExtractorsFactory: TCalleeDataExtractorsFactory
+    ) {
+        this.calleeDataExtractorsFactory = calleeDataExtractorsFactory;
+    }
 
     /**
      * @param blockScopeBodyLength
@@ -126,19 +135,19 @@ export class StackTraceAnalyzer implements IStackTraceAnalyzer {
                         return;
                     }
 
-                    this.calleeDataExtractors.forEach((calleeDataExtractor: TCalleeDataExtractor) => {
-                        const calleeData: ICalleeData|null = new calleeDataExtractor(
-                            blockScopeBody,
-                            node.callee
-                        ).extract();
+                    StackTraceAnalyzer.calleeDataExtractorsList.forEach((calleeDataExtractorName: CalleeDataExtractors) => {
+                        const calleeData: ICalleeData | null = this.calleeDataExtractorsFactory(calleeDataExtractorName)
+                            .extract(blockScopeBody, node.callee);
 
                         if (!calleeData) {
                             return;
                         }
 
-                        stackTraceData.push(Object.assign({}, calleeData, {
-                            stackTrace: this.analyzeRecursive(calleeData.callee.body)
-                        }));
+                        stackTraceData.push(
+                            Object.assign({}, calleeData, {
+                                stackTrace: this.analyzeRecursive(calleeData.callee.body)
+                            })
+                        );
                     });
                 }
             });

+ 16 - 0
src/stack-trace-analyzer/callee-data-extractors/AbstractCalleeDataExtractor.ts

@@ -0,0 +1,16 @@
+import { injectable } from 'inversify';
+
+import * as ESTree from 'estree';
+
+import { ICalleeData } from '../../interfaces/stack-trace-analyzer/ICalleeData';
+import { ICalleeDataExtractor } from '../../interfaces/stack-trace-analyzer/ICalleeDataExtractor';
+
+@injectable()
+export abstract class AbstractCalleeDataExtractor implements ICalleeDataExtractor {
+    /**
+     * @param blockScopeBody
+     * @param callee
+     * @returns {ICalleeData|null}
+     */
+    public abstract extract (blockScopeBody: ESTree.Node[], callee: ESTree.Node): ICalleeData|null;
+}

+ 10 - 24
src/stack-trace-analyzer/callee-data-extractors/FunctionDeclarationCalleeDataExtractor.ts

@@ -1,42 +1,28 @@
+import { injectable } from 'inversify';
+
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
 import { ICalleeData } from '../../interfaces/stack-trace-analyzer/ICalleeData';
-import { ICalleeDataExtractor } from '../../interfaces/stack-trace-analyzer/ICalleeDataExtractor';
 
+import { AbstractCalleeDataExtractor } from './AbstractCalleeDataExtractor';
 import { Node } from '../../node/Node';
 import { NodeUtils } from '../../node/NodeUtils';
 
-export class FunctionDeclarationCalleeDataExtractor implements ICalleeDataExtractor {
-    /**
-     * @type {ESTree.Node[]}
-     */
-    private blockScopeBody: ESTree.Node[];
-
-    /**
-     * @type {ESTree.Identifier}
-     */
-    private callee: ESTree.Identifier;
-
+@injectable()
+export class FunctionDeclarationCalleeDataExtractor extends AbstractCalleeDataExtractor {
     /**
      * @param blockScopeBody
      * @param callee
-     */
-    constructor (blockScopeBody: ESTree.Node[], callee: ESTree.Identifier) {
-        this.blockScopeBody = blockScopeBody;
-        this.callee = callee;
-    }
-
-    /**
      * @returns {ICalleeData|null}
      */
-    public extract (): ICalleeData|null {
+    public extract (blockScopeBody: ESTree.Node[], callee: ESTree.Identifier): ICalleeData|null {
         let calleeBlockStatement: ESTree.BlockStatement|null = null;
 
-        if (Node.isIdentifierNode(this.callee)) {
+        if (Node.isIdentifierNode(callee)) {
             calleeBlockStatement = this.getCalleeBlockStatement(
-                NodeUtils.getBlockScopeOfNode(this.blockScopeBody[0]),
-                this.callee.name
+                NodeUtils.getBlockScopeOfNode(blockScopeBody[0]),
+                callee.name
             );
         }
 
@@ -46,7 +32,7 @@ export class FunctionDeclarationCalleeDataExtractor implements ICalleeDataExtrac
 
         return {
             callee: calleeBlockStatement,
-            name: this.callee.name
+            name: callee.name
         };
     }
 

+ 12 - 26
src/stack-trace-analyzer/callee-data-extractors/FunctionExpressionCalleeDataExtractor.ts

@@ -1,47 +1,33 @@
+import { injectable } from 'inversify';
+
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
 import { ICalleeData } from '../../interfaces/stack-trace-analyzer/ICalleeData';
-import { ICalleeDataExtractor } from '../../interfaces/stack-trace-analyzer/ICalleeDataExtractor';
 
+import { AbstractCalleeDataExtractor } from './AbstractCalleeDataExtractor';
 import { Node } from '../../node/Node';
 import { NodeUtils } from '../../node/NodeUtils';
 
-export class FunctionExpressionCalleeDataExtractor implements ICalleeDataExtractor {
-    /**
-     * @type {ESTree.Node[]}
-     */
-    private blockScopeBody: ESTree.Node[];
-
-    /**
-     * @type {ESTree.Identifier}
-     */
-    private callee: ESTree.Identifier;
-
+@injectable()
+export class FunctionExpressionCalleeDataExtractor extends AbstractCalleeDataExtractor {
     /**
      * @param blockScopeBody
      * @param callee
-     */
-    constructor (blockScopeBody: ESTree.Node[], callee: ESTree.Identifier) {
-        this.blockScopeBody = blockScopeBody;
-        this.callee = callee;
-    }
-
-    /**
      * @returns {ICalleeData|null}
      */
-    public extract (): ICalleeData|null {
+    public extract (blockScopeBody: ESTree.Node[], callee: ESTree.Identifier): ICalleeData|null {
         let calleeBlockStatement: ESTree.BlockStatement|null = null;
 
-        if (Node.isIdentifierNode(this.callee)) {
+        if (Node.isIdentifierNode(callee)) {
             calleeBlockStatement = this.getCalleeBlockStatement(
-                NodeUtils.getBlockScopeOfNode(this.blockScopeBody[0]),
-                this.callee.name
+                NodeUtils.getBlockScopeOfNode(blockScopeBody[0]),
+                callee.name
             );
         }
 
-        if (Node.isFunctionExpressionNode(this.callee)) {
-            calleeBlockStatement = this.callee.body;
+        if (Node.isFunctionExpressionNode(callee)) {
+            calleeBlockStatement = callee.body;
         }
 
         if (!calleeBlockStatement) {
@@ -50,7 +36,7 @@ export class FunctionExpressionCalleeDataExtractor implements ICalleeDataExtract
 
         return {
             callee: calleeBlockStatement,
-            name: this.callee.name || null
+            name: callee.name || null
         };
     }
 

+ 9 - 23
src/stack-trace-analyzer/callee-data-extractors/ObjectExpressionCalleeDataExtractor.ts

@@ -1,45 +1,31 @@
+import { injectable } from 'inversify';
+
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
 import { TObjectMembersCallsChain } from '../../types/TObjectMembersCallsChain';
 
 import { ICalleeData } from '../../interfaces/stack-trace-analyzer/ICalleeData';
-import { ICalleeDataExtractor } from '../../interfaces/stack-trace-analyzer/ICalleeDataExtractor';
 
 import { Node } from '../../node/Node';
 import { NodeUtils } from '../../node/NodeUtils';
+import { AbstractCalleeDataExtractor } from './AbstractCalleeDataExtractor';
 
-export class ObjectExpressionCalleeDataExtractor implements ICalleeDataExtractor {
-    /**
-     * @type {ESTree.Node[]}
-     */
-    private blockScopeBody: ESTree.Node[];
-
-    /**
-     * @type {ESTree.MemberExpression}
-     */
-    private callee: ESTree.MemberExpression;
-
+@injectable()
+export class ObjectExpressionCalleeDataExtractor extends AbstractCalleeDataExtractor {
     /**
      * @param blockScopeBody
      * @param callee
-     */
-    constructor (blockScopeBody: ESTree.Node[], callee: ESTree.MemberExpression) {
-        this.blockScopeBody = blockScopeBody;
-        this.callee = callee;
-    }
-
-    /**
      * @returns {ICalleeData|null}
      */
-    public extract (): ICalleeData|null {
+    public extract (blockScopeBody: ESTree.Node[], callee: ESTree.MemberExpression): ICalleeData|null {
         let calleeBlockStatement: ESTree.BlockStatement|null = null,
             functionExpressionName: string|number|null = null;
 
-        if (Node.isMemberExpressionNode(this.callee)) {
+        if (Node.isMemberExpressionNode(callee)) {
             const objectMembersCallsChain: TObjectMembersCallsChain = this.createObjectMembersCallsChain(
                 [],
-                this.callee
+                callee
             );
 
             if (!objectMembersCallsChain.length) {
@@ -48,7 +34,7 @@ export class ObjectExpressionCalleeDataExtractor implements ICalleeDataExtractor
 
             functionExpressionName = objectMembersCallsChain[objectMembersCallsChain.length - 1];
             calleeBlockStatement = this.getCalleeBlockStatement(
-                NodeUtils.getBlockScopeOfNode(this.blockScopeBody[0]),
+                NodeUtils.getBlockScopeOfNode(blockScopeBody[0]),
                 objectMembersCallsChain
             );
         }

+ 0 - 5
src/types/TCalleeDataExtractor.d.ts

@@ -1,5 +0,0 @@
-import * as ESTree from 'estree';
-
-import { ICalleeDataExtractor } from '../interfaces/stack-trace-analyzer/ICalleeDataExtractor';
-
-export type TCalleeDataExtractor = (new (blockScopeBody: ESTree.Node[], callee: any) => ICalleeDataExtractor);

+ 5 - 0
src/types/TCalleeDataExtractorsFactory.d.ts

@@ -0,0 +1,5 @@
+import { ICalleeDataExtractor } from '../interfaces/stack-trace-analyzer/ICalleeDataExtractor';
+
+import { CalleeDataExtractors } from '../enums/container/CalleeDataExtractors';
+
+export type TCalleeDataExtractorsFactory = (calleeDataExtractorName: CalleeDataExtractors) => ICalleeDataExtractor;

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

@@ -1,18 +1,21 @@
+import { ServiceIdentifiers } from '../../../src/container/ServiceIdentifiers';
+
 import * as chai from 'chai';
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
 import { TNodeWithBlockStatement } from '../../../src/types/TNodeWithBlockStatement';
 
+import { IInversifyContainerFacade } from '../../../src/interfaces/container/IInversifyContainerFacade';
 import { IStackTraceAnalyzer } from '../../../src/interfaces/stack-trace-analyzer/IStackTraceAnalyzer';
 import { IStackTraceData } from '../../../src/interfaces/stack-trace-analyzer/IStackTraceData';
 
 import { readFileAsString } from '../../helpers/readFileAsString';
 
+import { InversifyContainerFacade } from '../../../src/container/InversifyContainerFacade';
 import { Node } from '../../../src/node/Node';
 import { NodeMocks } from '../../mocks/NodeMocks';
 import { NodeUtils } from '../../../src/node/NodeUtils';
-import { StackTraceAnalyzer } from '../../../src/stack-trace-analyzer/StackTraceAnalyzer';
 
 const assert: any = chai.assert;
 
@@ -146,7 +149,9 @@ function getObjectFunctionExpressionByName (astTree: ESTree.Node, objectName: st
 
 describe('StackTraceAnalyzer', () => {
     describe('extract (): IStackTraceData[]', () => {
-        const stackTraceAnalyzer: IStackTraceAnalyzer = new StackTraceAnalyzer();
+        const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade({});
+        const stackTraceAnalyzer: IStackTraceAnalyzer = inversifyContainerFacade
+            .get<IStackTraceAnalyzer>(ServiceIdentifiers.IStackTraceAnalyzer);
 
         let astTree: TNodeWithBlockStatement,
             stackTraceData: IStackTraceData[],
@@ -199,7 +204,7 @@ describe('StackTraceAnalyzer', () => {
             assert.deepEqual(stackTraceData, expectedStackTraceData);
         });
 
-        it('should returns correct BlockScopeTraceData - variant #2: basic-2', () => {
+        it('should returns correct IStackTraceData - variant #2: basic-2', () => {
             astTree = NodeMocks.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/basic-2.js')
@@ -235,7 +240,7 @@ describe('StackTraceAnalyzer', () => {
             assert.deepEqual(stackTraceData, expectedStackTraceData);
         });
 
-        it('should returns correct BlockScopeTraceData - variant #3: deep conditions nesting', () => {
+        it('should returns correct IStackTraceData - variant #3: deep conditions nesting', () => {
             astTree = NodeMocks.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/deep-conditions-nesting.js')
@@ -271,7 +276,7 @@ describe('StackTraceAnalyzer', () => {
             assert.deepEqual(stackTraceData, expectedStackTraceData);
         });
 
-        it('should returns correct BlockScopeTraceData - variant #4: call before declaration', () => {
+        it('should returns correct IStackTraceData - variant #4: call before declaration', () => {
             astTree = NodeMocks.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/call-before-declaration.js')
@@ -291,7 +296,7 @@ describe('StackTraceAnalyzer', () => {
             assert.deepEqual(stackTraceData, expectedStackTraceData);
         });
 
-        it('should returns correct BlockScopeTraceData - variant #5: call expression of object member #1', () => {
+        it('should returns correct IStackTraceData - variant #5: call expression of object member #1', () => {
             astTree = NodeMocks.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/call-expression-of-object-member-1.js')
@@ -347,7 +352,7 @@ describe('StackTraceAnalyzer', () => {
             assert.deepEqual(stackTraceData, expectedStackTraceData);
         });
 
-        it('should returns correct BlockScopeTraceData - variant #5: call expression of object member #2', () => {
+        it('should returns correct IStackTraceData - variant #5: call expression of object member #2', () => {
             astTree = NodeMocks.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/call-expression-of-object-member-2.js')
@@ -372,7 +377,7 @@ describe('StackTraceAnalyzer', () => {
             assert.deepEqual(stackTraceData, expectedStackTraceData);
         });
 
-        it('should returns correct BlockScopeTraceData - variant #6: no call expressions', () => {
+        it('should returns correct IStackTraceData - variant #6: no call expressions', () => {
             astTree = NodeMocks.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/no-call-expressions.js')
@@ -386,7 +391,7 @@ describe('StackTraceAnalyzer', () => {
             assert.deepEqual(stackTraceData, expectedStackTraceData);
         });
 
-        it('should returns correct BlockScopeTraceData - variant #7: only call expression', () => {
+        it('should returns correct IStackTraceData - variant #7: only call expression', () => {
             astTree = NodeMocks.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/only-call-expression.js')
@@ -400,7 +405,7 @@ describe('StackTraceAnalyzer', () => {
             assert.deepEqual(stackTraceData, expectedStackTraceData);
         });
 
-        it('should returns correct BlockScopeTraceData - variant #8: self-invoking functions', () => {
+        it('should returns correct IStackTraceData - variant #8: self-invoking functions', () => {
             astTree = NodeMocks.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/self-invoking-functions.js')
@@ -432,7 +437,7 @@ describe('StackTraceAnalyzer', () => {
             assert.deepEqual(stackTraceData, expectedStackTraceData);
         });
 
-        it('should returns correct BlockScopeTraceData - variant #9: no recursion', () => {
+        it('should returns correct IStackTraceData - variant #9: no recursion', () => {
             astTree = NodeMocks.getProgramNode(
                 NodeUtils.convertCodeToStructure(
                     readFileAsString('./test/fixtures/stack-trace-analyzer/no-recursion.js')

+ 7 - 2
test/unit-tests/node/NodeAppender.spec.ts

@@ -1,17 +1,20 @@
+import { ServiceIdentifiers } from '../../../src/container/ServiceIdentifiers';
+
 import * as chai from 'chai';
 import * as ESTree from 'estree';
 
 import { TStatement } from '../../../src/types/TStatement';
 
+import { IInversifyContainerFacade } from '../../../src/interfaces/container/IInversifyContainerFacade';
 import { IStackTraceAnalyzer } from '../../../src/interfaces/stack-trace-analyzer/IStackTraceAnalyzer';
 import { IStackTraceData } from '../../../src/interfaces/stack-trace-analyzer/IStackTraceData';
 
 import { readFileAsString } from '../../helpers/readFileAsString';
 
+import { InversifyContainerFacade } from '../../../src/container/InversifyContainerFacade';
 import { NodeAppender } from '../../../src/node/NodeAppender';
 import { NodeMocks } from '../../mocks/NodeMocks';
 import { NodeUtils } from '../../../src/node/NodeUtils';
-import { StackTraceAnalyzer } from '../../../src/stack-trace-analyzer/StackTraceAnalyzer';
 
 const assert: any = chai.assert;
 
@@ -50,7 +53,9 @@ describe('NodeAppender', () => {
     });
 
     describe('appendNodeToOptimalBlockScope (blockScopeStackTraceData: IStackTraceData[], blockScopeNode: TNodeWithBlockStatement, nodeBodyStatements: TStatement[], index: number = 0): void', () => {
-        const stackTraceAnalyzer: IStackTraceAnalyzer = new StackTraceAnalyzer();
+        const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade({});
+        const stackTraceAnalyzer: IStackTraceAnalyzer = inversifyContainerFacade
+            .get<IStackTraceAnalyzer>(ServiceIdentifiers.IStackTraceAnalyzer);
 
         let astTree: ESTree.Program,
             expectedAstTree: ESTree.Program,