escomplex-plugin-metrics-module
Advanced tools
Comparing version 0.0.13 to 0.1.0
@@ -7,4 +7,10 @@ 'use strict'; | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); | ||
var _createClass2 = require('babel-runtime/helpers/createClass'); | ||
var _createClass3 = _interopRequireDefault(_createClass2); | ||
var _ObjectUtil = require('typhonjs-escomplex-commons/dist/utils/ObjectUtil'); | ||
@@ -16,4 +22,2 @@ | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
/** | ||
@@ -27,6 +31,6 @@ * Provides a typhonjs-escomplex-module / ESComplexModule plugin which gathers and calculates all default metrics. | ||
function ModuleMetricAverage() { | ||
_classCallCheck(this, ModuleMetricAverage); | ||
(0, _classCallCheck3.default)(this, ModuleMetricAverage); | ||
} | ||
_createClass(ModuleMetricAverage, null, [{ | ||
(0, _createClass3.default)(ModuleMetricAverage, null, [{ | ||
key: 'calculate', | ||
@@ -40,16 +44,10 @@ | ||
* @param {object} settings - Settings for module processing. | ||
* | ||
* @private | ||
*/ | ||
value: function calculate(moduleReport) { | ||
var moduleMethodCount = moduleReport.methods.length; | ||
var moduleMethodAverages = moduleReport.methodAverage; | ||
var moduleMethodAverageKeys = _ObjectUtil2.default.getAccessorList(moduleMethodAverages); | ||
var moduleAggregateDivisor = moduleMethodCount + 1; // Include the module as a potential control path. | ||
// Handle module methods. | ||
moduleReport.methods.forEach(function (methodReport) { | ||
moduleMethodAverageKeys.forEach(function (averageKey) { | ||
var targetValue = _ObjectUtil2.default.safeAccess(methodReport, averageKey, 0); | ||
_ObjectUtil2.default.safeSet(moduleMethodAverages, averageKey, targetValue, 'add'); | ||
}); | ||
_ObjectUtil2.default.safeBatchSet(moduleReport.methodAverage, moduleReport.methodAverage.keys, methodReport, 'add'); | ||
}); | ||
@@ -59,53 +57,36 @@ | ||
moduleReport.classes.forEach(function (classReport) { | ||
var classMethodAverages = classReport.methodAverage; | ||
var classMethodCount = classReport.methods.length; | ||
var classAggregateDivisor = classMethodCount + 1; | ||
var classMethodCount = classReport.methods.length; | ||
moduleMethodCount += classMethodCount; | ||
moduleAggregateDivisor += classMethodCount; // Soon to add + 1 for the Class aggregate | ||
// Process all class methods. | ||
classReport.methods.forEach(function (methodReport) { | ||
moduleMethodAverageKeys.forEach(function (averageKey) { | ||
var targetValue = _ObjectUtil2.default.safeAccess(methodReport, averageKey, 0); | ||
_ObjectUtil2.default.safeSet(moduleMethodAverages, averageKey, targetValue, 'add'); | ||
_ObjectUtil2.default.safeSet(classMethodAverages, averageKey, targetValue, 'add'); | ||
}); | ||
_ObjectUtil2.default.safeBatchSet(moduleReport.methodAverage, classReport.methodAverage.keys, methodReport, 'add'); | ||
_ObjectUtil2.default.safeBatchSet(classReport.methodAverage, classReport.methodAverage.keys, methodReport, 'add'); | ||
}); | ||
// If there are no class methods use the class aggregate MethodReport. | ||
if (classMethodCount === 0) { | ||
// Sane handling of classes that contain no methods. | ||
moduleMethodAverageKeys.forEach(function (averageKey) { | ||
var targetValue = _ObjectUtil2.default.safeAccess(classReport.aggregateMethodReport, averageKey, 0); | ||
// Calculate the pure average method data only if there are class methods. | ||
if (classMethodCount !== 0) { | ||
_ObjectUtil2.default.safeBatchSet(classReport.methodAverage, classReport.methodAverage.keys, classMethodCount, 'div'); | ||
} | ||
_ObjectUtil2.default.safeSet(classMethodAverages, averageKey, targetValue, 'add'); | ||
}); | ||
// Calculate average class aggregate method data by adding the aggregate & dividing by the class divisor. | ||
_ObjectUtil2.default.safeBatchSet(classReport.aggregateAverage, classReport.aggregateAverage.keys, classReport.aggregate, 'add'); | ||
classMethodCount = 1; | ||
} | ||
moduleMethodAverageKeys.forEach(function (averageKey) { | ||
_ObjectUtil2.default.safeSet(classMethodAverages, averageKey, classMethodCount, 'div'); | ||
}); | ||
_ObjectUtil2.default.safeBatchSet(classReport.aggregateAverage, classReport.aggregateAverage.keys, classAggregateDivisor, 'div'); | ||
}); | ||
// If there are no module methods use the module aggregate MethodReport. | ||
if (moduleMethodCount === 0) { | ||
// Sane handling of classes that contain no methods. | ||
moduleMethodAverageKeys.forEach(function (averageKey) { | ||
var targetValue = _ObjectUtil2.default.safeAccess(moduleReport.aggregateMethodReport, averageKey, 0); | ||
// Calculate the pure average method data only if there are module methods. | ||
if (moduleMethodCount !== 0) { | ||
_ObjectUtil2.default.safeBatchSet(moduleReport.methodAverage, moduleReport.methodAverage.keys, moduleMethodCount, 'div'); | ||
} | ||
_ObjectUtil2.default.safeSet(moduleMethodAverages, averageKey, targetValue, 'add'); | ||
}); | ||
// Calculate average module aggregate method data by adding the aggregate & dividing by the module divisor. | ||
_ObjectUtil2.default.safeBatchSet(moduleReport.aggregateAverage, moduleReport.aggregateAverage.keys, moduleReport.aggregate, 'add'); | ||
// Sane handling of modules that contain no methods. | ||
moduleMethodCount = 1; | ||
} | ||
moduleMethodAverageKeys.forEach(function (averageKey) { | ||
_ObjectUtil2.default.safeSet(moduleMethodAverages, averageKey, moduleMethodCount, 'div'); | ||
}); | ||
_ObjectUtil2.default.safeBatchSet(moduleReport.aggregateAverage, moduleReport.aggregateAverage.keys, moduleAggregateDivisor, 'div'); | ||
} | ||
}]); | ||
return ModuleMetricAverage; | ||
@@ -112,0 +93,0 @@ }(); |
@@ -7,6 +7,12 @@ "use strict"; | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); | ||
var _createClass2 = require("babel-runtime/helpers/createClass"); | ||
var _createClass3 = _interopRequireDefault(_createClass2); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/** | ||
@@ -20,6 +26,6 @@ * Provides a typhonjs-escomplex-module / ESComplexModule plugin which gathers and calculates all default metrics. | ||
function ModuleMetricCalculate() { | ||
_classCallCheck(this, ModuleMetricCalculate); | ||
(0, _classCallCheck3.default)(this, ModuleMetricCalculate); | ||
} | ||
_createClass(ModuleMetricCalculate, null, [{ | ||
(0, _createClass3.default)(ModuleMetricCalculate, null, [{ | ||
key: "calculate", | ||
@@ -32,4 +38,2 @@ | ||
* @param {ModuleReport} moduleReport - The ModuleReport being processed. | ||
* | ||
* @private | ||
*/ | ||
@@ -51,8 +55,8 @@ value: function calculate(moduleReport) { | ||
ModuleMetricCalculate.calculateCyclomaticDensity(classReport.aggregateMethodReport); | ||
ModuleMetricCalculate.calculateHalsteadMetrics(classReport.aggregateMethodReport.halstead); | ||
ModuleMetricCalculate.calculateCyclomaticDensity(classReport.aggregateReport); | ||
ModuleMetricCalculate.calculateHalsteadMetrics(classReport.aggregateReport.halstead); | ||
}); | ||
ModuleMetricCalculate.calculateCyclomaticDensity(moduleReport.aggregateMethodReport); | ||
ModuleMetricCalculate.calculateHalsteadMetrics(moduleReport.aggregateMethodReport.halstead); | ||
ModuleMetricCalculate.calculateCyclomaticDensity(moduleReport.aggregateReport); | ||
ModuleMetricCalculate.calculateHalsteadMetrics(moduleReport.aggregateReport.halstead); | ||
} | ||
@@ -107,3 +111,2 @@ | ||
}]); | ||
return ModuleMetricCalculate; | ||
@@ -110,0 +113,0 @@ }(); |
@@ -1,2 +0,2 @@ | ||
'use strict'; | ||
"use strict"; | ||
@@ -7,6 +7,12 @@ Object.defineProperty(exports, "__esModule", { | ||
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 _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); | ||
var _createClass2 = require("babel-runtime/helpers/createClass"); | ||
var _createClass3 = _interopRequireDefault(_createClass2); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/** | ||
@@ -20,7 +26,7 @@ * Provides a typhonjs-escomplex-module / ESComplexModule plugin which gathers and calculates all default metrics. | ||
function ModuleMetricPostAverage() { | ||
_classCallCheck(this, ModuleMetricPostAverage); | ||
(0, _classCallCheck3.default)(this, ModuleMetricPostAverage); | ||
} | ||
_createClass(ModuleMetricPostAverage, null, [{ | ||
key: 'calculate', | ||
(0, _createClass3.default)(ModuleMetricPostAverage, null, [{ | ||
key: "calculate", | ||
@@ -38,8 +44,13 @@ /** | ||
// Handle module report. | ||
var moduleMethodAverages = moduleReport.methodAverage; | ||
var moduleAggregateAverage = moduleReport.aggregateAverage; | ||
ModuleMetricPostAverage.calculateMaintainabilityIndex(moduleReport, settings, moduleMethodAverages.cyclomatic, moduleMethodAverages.halstead.effort, moduleMethodAverages.sloc.logical); | ||
ModuleMetricPostAverage.calculateMaintainabilityIndex(moduleReport, settings, moduleAggregateAverage.cyclomatic, moduleAggregateAverage.halstead.effort, moduleAggregateAverage.sloc.logical); | ||
// Handle module class reports. | ||
moduleReport.classes.forEach(function (classReport) { | ||
// const classAggregateAverage = classReport.aggregateAverage; | ||
// | ||
// ModuleMetricPostAverage.calculateMaintainabilityIndex(classReport, settings, classAggregateAverage.cyclomatic, | ||
// classAggregateAverage.halstead.effort, classAggregateAverage.sloc.logical); | ||
var classMethodAverages = classReport.methodAverage; | ||
@@ -64,2 +75,6 @@ | ||
* | ||
* Note: Bare module reports with no branching control flow or module methods and class reports with no class | ||
* methods start with a base cyclomatic complexity of 0. It is necessary to handle this case as | ||
* Math.log(0) === -Infinity. | ||
* | ||
* @param {ClassReport|ModuleReport} report - A ClassReport or ModuleReport to perform calculations on. | ||
@@ -69,3 +84,3 @@ * @param {object} settings - Settings for module processing. | ||
* @param {number} averageEffort - Average Halstead effort across a ClassReport / ModuleReport. | ||
* @param {number} averageLoc - Average SLOC metric across a ClassReport / ModuleReport. | ||
* @param {number} averageLoc - Average logical SLOC across a ClassReport / ModuleReport. | ||
* | ||
@@ -76,11 +91,6 @@ * @private | ||
}, { | ||
key: 'calculateMaintainabilityIndex', | ||
key: "calculateMaintainabilityIndex", | ||
value: function calculateMaintainabilityIndex(report, settings, averageCyclomatic, averageEffort, averageLoc) { | ||
/* istanbul ignore if */ | ||
if (averageCyclomatic === 0) { | ||
throw new Error('Encountered report with cyclomatic complexity zero!'); | ||
} | ||
report.maintainability = 171 - 3.42 * Math.log(averageEffort) - (0.23 * averageCyclomatic === 0 ? 0 : Math.log(averageCyclomatic)) - 16.2 * Math.log(averageLoc); | ||
report.maintainability = 171 - 3.42 * Math.log(averageEffort) - 0.23 * Math.log(averageCyclomatic) - 16.2 * Math.log(averageLoc); | ||
/* istanbul ignore if */ | ||
@@ -97,3 +107,2 @@ if (report.maintainability > 171) { | ||
}]); | ||
return ModuleMetricPostAverage; | ||
@@ -103,2 +112,2 @@ }(); | ||
exports.default = ModuleMetricPostAverage; | ||
module.exports = exports['default']; | ||
module.exports = exports["default"]; |
@@ -7,6 +7,18 @@ '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 ? "symbol" : typeof obj; }; | ||
var _isInteger = require('babel-runtime/core-js/number/is-integer'); | ||
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 _isInteger2 = _interopRequireDefault(_isInteger); | ||
var _typeof2 = require('babel-runtime/helpers/typeof'); | ||
var _typeof3 = _interopRequireDefault(_typeof2); | ||
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); | ||
var _createClass2 = require('babel-runtime/helpers/createClass'); | ||
var _createClass3 = _interopRequireDefault(_createClass2); | ||
var _HalsteadArray = require('typhonjs-escomplex-commons/dist/module/traits/HalsteadArray'); | ||
@@ -18,4 +30,2 @@ | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
/** | ||
@@ -26,6 +36,6 @@ * Provides the main processing of syntax data for all default metrics gathered. | ||
function ModuleMetricProcess() { | ||
_classCallCheck(this, ModuleMetricProcess); | ||
(0, _classCallCheck3.default)(this, ModuleMetricProcess); | ||
} | ||
_createClass(ModuleMetricProcess, null, [{ | ||
(0, _createClass3.default)(ModuleMetricProcess, null, [{ | ||
key: 'addDependencies', | ||
@@ -40,3 +50,3 @@ | ||
value: function addDependencies(moduleReport, dependencies) { | ||
if ((typeof dependencies === 'undefined' ? 'undefined' : _typeof(dependencies)) === 'object' || Array.isArray(dependencies)) { | ||
if ((typeof dependencies === 'undefined' ? 'undefined' : (0, _typeof3.default)(dependencies)) === 'object' || Array.isArray(dependencies)) { | ||
moduleReport.dependencies = moduleReport.dependencies.concat(dependencies); | ||
@@ -52,8 +62,6 @@ } | ||
* @param {object} newScope - An object hash defining the new scope including: | ||
* @param {object} node - Current AST node. | ||
* @param {object} parent - Parent AST node. | ||
* ``` | ||
* (string) type - Type of report to create. | ||
* (string) name - Name of the class or method. | ||
* (number) lineStart - Start line of method. | ||
* (number) lineEnd - End line of method. | ||
* (number) paramCount - (For method scopes) Number of parameters for method. | ||
* (string) type - Type of report scope being created. | ||
* ``` | ||
@@ -63,24 +71,81 @@ */ | ||
}, { | ||
key: 'createScope', | ||
value: function createScope(moduleReport, scopeControl) { | ||
var newScope = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; | ||
key: 'preScopeCreated', | ||
value: function preScopeCreated(moduleReport, scopeControl) { | ||
var newScope = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
var node = arguments[3]; | ||
var parent = arguments[4]; | ||
if ((typeof newScope === 'undefined' ? 'undefined' : _typeof(newScope)) !== 'object') { | ||
throw new TypeError('createScope error: \'newScope\' is not an \'object\'.'); | ||
if ((typeof newScope === 'undefined' ? 'undefined' : (0, _typeof3.default)(newScope)) !== 'object') { | ||
throw new TypeError('preScopeCreated error: \'newScope\' is not an \'object\'.'); | ||
} | ||
if (typeof newScope.type !== 'string') { | ||
throw new TypeError('createScope error: \'newScope.type\' is not a \'string\'.'); | ||
throw new TypeError('preScopeCreated error: \'newScope.type\' is not a \'string\'.'); | ||
} | ||
if (typeof newScope.name !== 'string') { | ||
throw new TypeError('createScope error: \'newScope.name\' is not a \'string\'.'); | ||
switch (newScope.type) { | ||
case 'class': | ||
case 'method': | ||
// Increments logical SLOC for previous report scopes. | ||
if ((0, _isInteger2.default)(newScope.lloc)) { | ||
// Increments current module report associated aggregate report parameter count. | ||
moduleReport.aggregateReport.sloc.logical += newScope.lloc; | ||
var classReport = scopeControl.getCurrentClassReport(); | ||
var methodReport = scopeControl.getCurrentMethodReport(); | ||
if (classReport) { | ||
classReport.aggregateReport.sloc.logical += newScope.lloc; | ||
} | ||
if (methodReport) { | ||
methodReport.sloc.logical += newScope.lloc; | ||
} | ||
} | ||
if (newScope.operands instanceof _HalsteadArray2.default) { | ||
var identifiers = newScope.operands.valueOf(node, parent); | ||
identifiers.forEach(function (identifier) { | ||
ModuleMetricProcess.halsteadItemEncountered(moduleReport, scopeControl, 'operands', identifier); | ||
}); | ||
} | ||
if (newScope.operators instanceof _HalsteadArray2.default) { | ||
var _identifiers = newScope.operators.valueOf(node, parent); | ||
_identifiers.forEach(function (identifier) { | ||
ModuleMetricProcess.halsteadItemEncountered(moduleReport, scopeControl, 'operators', identifier); | ||
}); | ||
} | ||
break; | ||
} | ||
} | ||
if (!Number.isInteger(newScope.lineStart)) { | ||
throw new TypeError('createScope error: \'newScope.lineStart\' is not an \'integer\'.'); | ||
/** | ||
* Creates a moduleReport scope when a class or method is entered. | ||
* | ||
* @param {ModuleReport} moduleReport - The ModuleReport being processed. | ||
* @param {ModuleScopeControl} scopeControl - The associated module report scope control. | ||
* @param {object} newScope - An object hash defining the new scope including: | ||
* ``` | ||
* (string) type - Type of report scope being created. | ||
* (string) name - Name of the class or method. | ||
* (number) lineStart - Start line of method. | ||
* (number) lineEnd - End line of method. | ||
* (Array<string>) paramNames - (For method scopes) An array of parameters names for method. | ||
* ``` | ||
*/ | ||
}, { | ||
key: 'postScopeCreated', | ||
value: function postScopeCreated(moduleReport, scopeControl) { | ||
var newScope = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
if ((typeof newScope === 'undefined' ? 'undefined' : (0, _typeof3.default)(newScope)) !== 'object') { | ||
throw new TypeError('postScopeCreated error: \'newScope\' is not an \'object\'.'); | ||
} | ||
if (!Number.isInteger(newScope.lineEnd)) { | ||
throw new TypeError('createScope error: \'newScope.lineEnd\' is not an \'integer\'.'); | ||
if (typeof newScope.type !== 'string') { | ||
throw new TypeError('postScopeCreated error: \'newScope.type\' is not a \'string\'.'); | ||
} | ||
@@ -94,16 +159,36 @@ | ||
{ | ||
if (!Number.isInteger(newScope.paramCount)) { | ||
throw new TypeError('createScope error: \'newScope.paramCount\' is not an \'integer\'.'); | ||
if (!(0, _isInteger2.default)(newScope.cyclomatic)) { | ||
throw new TypeError('postScopeCreated error: \'newScope.cyclomatic\' is not an \'integer\'.'); | ||
} | ||
// Increments the associated aggregate moduleReport parameter count. | ||
moduleReport.aggregateMethodReport.params += newScope.paramCount; | ||
if (!Array.isArray(newScope.paramNames)) { | ||
throw new TypeError('postScopeCreated error: \'newScope.paramNames\' is not an \'array\'.'); | ||
} | ||
var classReport = scopeControl.getCurrentClassReport(); | ||
var methodReport = scopeControl.getCurrentMethodReport(); | ||
// Increments current class report associated aggregate report parameter count. | ||
// Increments current module report associated aggregate report cyclomatic count. | ||
moduleReport.aggregateReport.cyclomatic += newScope.cyclomatic; | ||
// Increments current module report associated aggregate report parameter count. | ||
moduleReport.aggregateReport.paramCount += newScope.paramNames.length; | ||
if (classReport) { | ||
classReport.aggregateMethodReport.params += newScope.paramCount; | ||
// Increments current class report associated aggregate report cyclomatic count. | ||
classReport.aggregateReport.cyclomatic += newScope.cyclomatic; | ||
// Increments current class report associated aggregate report parameter count. | ||
classReport.aggregateReport.paramCount += newScope.paramNames.length; | ||
} | ||
if ((0, _isInteger2.default)(newScope.postLloc)) { | ||
moduleReport.aggregateReport.sloc.logical += newScope.postLloc; | ||
if (classReport) { | ||
classReport.aggregateReport.sloc.logical += newScope.postLloc; | ||
} | ||
if (methodReport) { | ||
methodReport.sloc.logical += newScope.postLloc; | ||
} | ||
} | ||
break; | ||
@@ -155,6 +240,6 @@ } | ||
moduleReport.methodAggregate.cyclomatic += amount; | ||
moduleReport.aggregate.cyclomatic += amount; | ||
if (currentClassReport) { | ||
currentClassReport.methodAggregate.cyclomatic += amount; | ||
currentClassReport.aggregate.cyclomatic += amount; | ||
} | ||
@@ -181,8 +266,13 @@ if (currentMethodReport) { | ||
moduleReport.methodAggregate.sloc.logical += amount; | ||
moduleReport.aggregate.sloc.logical += amount; | ||
if (currentClassReport) { | ||
currentClassReport.methodAggregate.sloc.logical += amount; | ||
currentClassReport.aggregate.sloc.logical += amount; | ||
} | ||
if (currentMethodReport) { | ||
// if (amount > 0) | ||
// { | ||
// console.log('!! MMP - incrementLogicalSloc (method) - node type: ' + nodeType + '; amount: ' + amount); | ||
// } | ||
currentMethodReport.sloc.logical += amount; | ||
@@ -195,5 +285,5 @@ } | ||
* | ||
* @param {ModuleReport} moduleReport - The ModuleReport being processed. | ||
* @param {string} metric - A Halstead metric name. | ||
* @param {string} identifier - A Halstead identifier name. | ||
* @param {ModuleReport|ClassReport|MethodReport} report - The report being processed. | ||
* @param {string} metric - A Halstead metric name. | ||
* @param {string} identifier - A Halstead identifier name. | ||
*/ | ||
@@ -203,11 +293,11 @@ | ||
key: 'incrementHalsteadItems', | ||
value: function incrementHalsteadItems(moduleReport, metric, identifier) { | ||
value: function incrementHalsteadItems(report, metric, identifier) { | ||
// Increments the associated aggregate report HalsteadData for distinct identifiers. | ||
if (moduleReport.aggregateMethodReport.halstead[metric].identifiers.indexOf(identifier) === -1) { | ||
moduleReport.aggregateMethodReport.halstead[metric].identifiers.push(identifier); | ||
moduleReport.aggregateMethodReport.halstead[metric]['distinct'] += 1; | ||
if (report.aggregateReport.halstead[metric].identifiers.indexOf(identifier) === -1) { | ||
report.aggregateReport.halstead[metric].identifiers.push(identifier); | ||
report.aggregateReport.halstead[metric]['distinct'] += 1; | ||
} | ||
// Increment total halstead items | ||
moduleReport.aggregateMethodReport.halstead[metric]['total'] += 1; | ||
report.aggregateReport.halstead[metric]['total'] += 1; | ||
} | ||
@@ -229,13 +319,19 @@ | ||
var _loop = function _loop(key) { | ||
switch (syntax[key].metric) { | ||
var trait = syntax[key]; | ||
switch (trait.metric) { | ||
case 'cyclomatic': | ||
ModuleMetricProcess.incrementCyclomatic(moduleReport, scopeControl, syntax[key].valueOf(node, parent)); | ||
ModuleMetricProcess.incrementCyclomatic(moduleReport, scopeControl, trait.valueOf(node, parent)); | ||
break; | ||
case 'dependencies': | ||
ModuleMetricProcess.addDependencies(moduleReport, syntax[key].valueOf(node, parent)); | ||
ModuleMetricProcess.addDependencies(moduleReport, trait.valueOf(node, parent)); | ||
break; | ||
case 'lloc': | ||
ModuleMetricProcess.incrementLogicalSloc(moduleReport, scopeControl, syntax[key].valueOf(node, parent)); | ||
// if (trait.valueOf(node, parent) > 0) | ||
// { | ||
// console.log('!! MMP - increment sloc - node type: ' + node.type + '; value: ' + trait.valueOf(node, parent)); | ||
// } | ||
ModuleMetricProcess.incrementLogicalSloc(moduleReport, scopeControl, trait.valueOf(node, parent)); | ||
break; | ||
@@ -245,7 +341,7 @@ } | ||
// Process operands / operators HalsteadArray entries. | ||
if (syntax[key] instanceof _HalsteadArray2.default) { | ||
var identifiers = syntax[key].valueOf(node, parent); | ||
if (trait instanceof _HalsteadArray2.default) { | ||
var identifiers = trait.valueOf(node, parent); | ||
identifiers.forEach(function (identifier) { | ||
ModuleMetricProcess.halsteadItemEncountered(moduleReport, scopeControl, syntax[key].metric, identifier); | ||
ModuleMetricProcess.halsteadItemEncountered(moduleReport, scopeControl, trait.metric, identifier); | ||
}); | ||
@@ -260,3 +356,2 @@ } | ||
}]); | ||
return ModuleMetricProcess; | ||
@@ -263,0 +358,0 @@ }(); |
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; | ||
var _typeof2 = require('babel-runtime/helpers/typeof'); | ||
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 _typeof3 = _interopRequireDefault(_typeof2); | ||
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); | ||
var _createClass2 = require('babel-runtime/helpers/createClass'); | ||
var _createClass3 = _interopRequireDefault(_createClass2); | ||
var _ModuleMetricAverage = require('./ModuleMetricAverage'); | ||
@@ -29,4 +37,2 @@ | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
/** | ||
@@ -39,96 +45,107 @@ * Provides a typhonjs-escomplex-module / ESComplexModule plugin which gathers and calculates all default metrics. | ||
var PluginMetricsModule = function () { | ||
function PluginMetricsModule() { | ||
_classCallCheck(this, PluginMetricsModule); | ||
} | ||
function PluginMetricsModule() { | ||
(0, _classCallCheck3.default)(this, PluginMetricsModule); | ||
} | ||
_createClass(PluginMetricsModule, [{ | ||
key: 'onConfigure', | ||
(0, _createClass3.default)(PluginMetricsModule, [{ | ||
key: 'onConfigure', | ||
/** | ||
* Loads any default settings that are not already provided by any user options. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
* | ||
* The following options are: | ||
* ``` | ||
* (boolean) newmi - Boolean indicating whether the maintainability index should be rebased on a scale from | ||
* 0 to 100; defaults to false. | ||
* ``` | ||
*/ | ||
value: function onConfigure(ev) { | ||
ev.data.settings.newmi = typeof ev.data.options.newmi === 'boolean' ? ev.data.options.newmi : false; | ||
} | ||
/** | ||
* Loads any default settings that are not already provided by any user options. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
* | ||
* The following options are: | ||
* ``` | ||
* (boolean) newmi - Boolean indicating whether the maintainability index should be rebased on a scale from | ||
* 0 to 100; defaults to false. | ||
* ``` | ||
*/ | ||
value: function onConfigure(ev) { | ||
ev.data.settings.newmi = typeof ev.data.options.newmi === 'boolean' ? ev.data.options.newmi : false; | ||
} | ||
/** | ||
* During AST traversal when a node is entered it is processed immediately if the node type corresponds to a | ||
* loaded trait syntax. This is the main metric capture and processing location. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
*/ | ||
/** | ||
* During AST traversal when a node is entered it is processed immediately if the node type corresponds to a | ||
* loaded trait syntax. This is the main metric capture and processing location. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
*/ | ||
}, { | ||
key: 'onEnterNode', | ||
value: function onEnterNode(ev) { | ||
var moduleReport = ev.data.moduleReport; | ||
var scopeControl = ev.data.scopeControl; | ||
var node = ev.data.node; | ||
var parent = ev.data.parent; | ||
var syntax = ev.data.syntaxes[node.type]; | ||
}, { | ||
key: 'onEnterNode', | ||
value: function onEnterNode(ev) { | ||
var moduleReport = ev.data.moduleReport; | ||
var scopeControl = ev.data.scopeControl; | ||
var node = ev.data.node; | ||
var parent = ev.data.parent; | ||
var syntax = ev.data.syntaxes[node.type]; | ||
// Process node syntax. | ||
if ((typeof syntax === 'undefined' ? 'undefined' : _typeof(syntax)) === 'object') { | ||
_ModuleMetricProcess2.default.processSyntax(moduleReport, scopeControl, syntax, node, parent); | ||
} | ||
// Process node syntax. | ||
if ((typeof syntax === 'undefined' ? 'undefined' : (0, _typeof3.default)(syntax)) === 'object') { | ||
_ModuleMetricProcess2.default.processSyntax(moduleReport, scopeControl, syntax, node, parent); | ||
} | ||
} | ||
/** | ||
* Performs average calculations based on collected report data. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
*/ | ||
/** | ||
* Performs average calculations based on collected report data. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
*/ | ||
}, { | ||
key: 'onModuleAverage', | ||
value: function onModuleAverage(ev) { | ||
_ModuleMetricAverage2.default.calculate(ev.data.moduleReport); | ||
} | ||
}, { | ||
key: 'onModuleAverage', | ||
value: function onModuleAverage(ev) { | ||
_ModuleMetricAverage2.default.calculate(ev.data.moduleReport); | ||
} | ||
/** | ||
* Performs initial calculations based on collected report data. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
*/ | ||
/** | ||
* Performs initial calculations based on collected report data. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
*/ | ||
}, { | ||
key: 'onModuleCalculate', | ||
value: function onModuleCalculate(ev) { | ||
_ModuleMetricCalculate2.default.calculate(ev.data.moduleReport); | ||
} | ||
}, { | ||
key: 'onModuleCalculate', | ||
value: function onModuleCalculate(ev) { | ||
_ModuleMetricCalculate2.default.calculate(ev.data.moduleReport); | ||
} | ||
/** | ||
* Performs any calculations that depend on averaged data. This is where the maintainability index is calculated. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
*/ | ||
/** | ||
* Performs any calculations that depend on averaged data. This is where the maintainability index is calculated. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
*/ | ||
}, { | ||
key: 'onModulePostAverage', | ||
value: function onModulePostAverage(ev) { | ||
_ModuleMetricPostAverage2.default.calculate(ev.data.moduleReport, ev.data.settings); | ||
} | ||
}, { | ||
key: 'onModulePostAverage', | ||
value: function onModulePostAverage(ev) { | ||
_ModuleMetricPostAverage2.default.calculate(ev.data.moduleReport, ev.data.settings); | ||
} | ||
/** | ||
* A new module report scope has been created. Update any associated metrics processing regarding the new scope. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
*/ | ||
/** | ||
* A new module report scope has been created. Update any associated metrics processing regarding the new scope. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
*/ | ||
}, { | ||
key: 'onModuleScopeCreated', | ||
value: function onModuleScopeCreated(ev) { | ||
_ModuleMetricProcess2.default.createScope(ev.data.moduleReport, ev.data.scopeControl, ev.data.newScope); | ||
} | ||
}]); | ||
}, { | ||
key: 'onModulePostScopeCreated', | ||
value: function onModulePostScopeCreated(ev) { | ||
_ModuleMetricProcess2.default.postScopeCreated(ev.data.moduleReport, ev.data.scopeControl, ev.data.newScope); | ||
} | ||
return PluginMetricsModule; | ||
/** | ||
* A new module report scope has been created. Update any associated metrics processing regarding the new scope. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
*/ | ||
}, { | ||
key: 'onModulePreScopeCreated', | ||
value: function onModulePreScopeCreated(ev) { | ||
_ModuleMetricProcess2.default.preScopeCreated(ev.data.moduleReport, ev.data.scopeControl, ev.data.newScope, ev.data.node, ev.data.parent); | ||
} | ||
}]); | ||
return PluginMetricsModule; | ||
}(); | ||
@@ -135,0 +152,0 @@ |
{ | ||
"name": "escomplex-plugin-metrics-module", | ||
"version": "0.0.13", | ||
"version": "0.1.0", | ||
"homepage": "https://github.com/typhonjs-node-escomplex/escomplex-plugin-metrics-module/", | ||
@@ -9,3 +9,3 @@ "description": "Provides the core module metric / report generation plugin for typhonjs-escomplex module processing.", | ||
"author": { | ||
"name": "Mike Leahy" | ||
"name": "Michael Leahy" | ||
}, | ||
@@ -18,3 +18,3 @@ "repository": { | ||
{ | ||
"name": "Mike Leahy", | ||
"name": "Michael Leahy", | ||
"email": "support@typhonjs.io", | ||
@@ -25,9 +25,9 @@ "url": "https://github.com/typhonrt" | ||
"dependencies": { | ||
"typhonjs-escomplex-commons": "^0.0.16" | ||
"typhonjs-escomplex-commons": "^0.1.0" | ||
}, | ||
"devDependencies": { | ||
"escomplex-plugin-syntax-babylon": "^0.0.13", | ||
"typhonjs-ast-walker": "^0.1.0", | ||
"typhonjs-config-eslint": "^0.4.0", | ||
"typhonjs-npm-build-test": "^0.3.0" | ||
"escomplex-plugin-syntax-babylon": "^0.1.0", | ||
"typhonjs-ast-walker": "^0.2.0", | ||
"typhonjs-config-eslint": "^0.5.0", | ||
"typhonjs-npm-build-test": "^0.7.0" | ||
}, | ||
@@ -40,3 +40,5 @@ "scripts": { | ||
"test": "babel-node ./node_modules/typhonjs-npm-scripts-test-mocha/scripts/mocha.js", | ||
"test-coverage": "babel-node ./node_modules/typhonjs-npm-scripts-test-mocha/scripts/mocha-istanbul.js" | ||
"test-coverage": "babel-node ./node_modules/typhonjs-npm-scripts-test-mocha/scripts/mocha-istanbul.js", | ||
"dev-test": "BABEL_ENV=escomplex-dev babel-node ./node_modules/typhonjs-npm-scripts-test-mocha/scripts/mocha.js dev_test", | ||
"dev-test-coverage": "BABEL_ENV=escomplex-dev babel-node ./node_modules/typhonjs-npm-scripts-test-mocha/scripts/mocha-istanbul.js dev_test" | ||
}, | ||
@@ -43,0 +45,0 @@ "keywords": [ |
@@ -11,4 +11,4 @@ ![escomplex-plugin-metrics-module](https://i.imgur.com/VUdkEAq.png) | ||
[![Coverage](https://img.shields.io/codecov/c/github/typhonjs-node-escomplex/escomplex-plugin-metrics-module.svg)](https://codecov.io/github/typhonjs-node-escomplex/escomplex-plugin-metrics-module) | ||
[![Dependency Status](https://www.versioneye.com/user/projects/575e41b87757a0003bd4c2d4/badge.svg?style=flat)](https://www.versioneye.com/user/projects/575e41b87757a0003bd4c2d4) | ||
[![Dependency Status](https://david-dm.org/typhonjs-node-escomplex/escomplex-plugin-metrics-module/status.svg)](https://david-dm.org/typhonjs-node-escomplex/escomplex-plugin-metrics-module) | ||
Provides the core module metric / report generation plugin for typhonjs-escomplex module processing. |
@@ -1,2 +0,2 @@ | ||
import ObjectUtil from 'typhonjs-escomplex-commons/src/utils/ObjectUtil'; | ||
import ObjectUtil from 'typhonjs-escomplex-commons/src/utils/ObjectUtil'; | ||
@@ -17,4 +17,2 @@ /** | ||
* @param {object} settings - Settings for module processing. | ||
* | ||
* @private | ||
*/ | ||
@@ -24,4 +22,3 @@ static calculate(moduleReport) | ||
let moduleMethodCount = moduleReport.methods.length; | ||
const moduleMethodAverages = moduleReport.methodAverage; | ||
const moduleMethodAverageKeys = ObjectUtil.getAccessorList(moduleMethodAverages); | ||
let moduleAggregateDivisor = moduleMethodCount + 1; // Include the module as a potential control path. | ||
@@ -31,7 +28,3 @@ // Handle module methods. | ||
{ | ||
moduleMethodAverageKeys.forEach((averageKey) => | ||
{ | ||
const targetValue = ObjectUtil.safeAccess(methodReport, averageKey, 0); | ||
ObjectUtil.safeSet(moduleMethodAverages, averageKey, targetValue, 'add'); | ||
}); | ||
ObjectUtil.safeBatchSet(moduleReport.methodAverage, moduleReport.methodAverage.keys, methodReport, 'add'); | ||
}); | ||
@@ -42,6 +35,7 @@ | ||
{ | ||
const classMethodAverages = classReport.methodAverage; | ||
const classMethodCount = classReport.methods.length; | ||
const classAggregateDivisor = classMethodCount + 1; | ||
let classMethodCount = classReport.methods.length; | ||
moduleMethodCount += classMethodCount; | ||
moduleAggregateDivisor += classMethodCount; // Soon to add + 1 for the Class aggregate | ||
@@ -51,51 +45,34 @@ // Process all class methods. | ||
{ | ||
moduleMethodAverageKeys.forEach((averageKey) => | ||
{ | ||
const targetValue = ObjectUtil.safeAccess(methodReport, averageKey, 0); | ||
ObjectUtil.safeSet(moduleMethodAverages, averageKey, targetValue, 'add'); | ||
ObjectUtil.safeSet(classMethodAverages, averageKey, targetValue, 'add'); | ||
}); | ||
ObjectUtil.safeBatchSet(moduleReport.methodAverage, classReport.methodAverage.keys, methodReport, 'add'); | ||
ObjectUtil.safeBatchSet(classReport.methodAverage, classReport.methodAverage.keys, methodReport, 'add'); | ||
}); | ||
// If there are no class methods use the class aggregate MethodReport. | ||
if (classMethodCount === 0) | ||
// Calculate the pure average method data only if there are class methods. | ||
if (classMethodCount !== 0) | ||
{ | ||
// Sane handling of classes that contain no methods. | ||
moduleMethodAverageKeys.forEach((averageKey) => | ||
{ | ||
const targetValue = ObjectUtil.safeAccess(classReport.aggregateMethodReport, averageKey, 0); | ||
ObjectUtil.safeBatchSet(classReport.methodAverage, classReport.methodAverage.keys, | ||
classMethodCount, 'div'); | ||
} | ||
ObjectUtil.safeSet(classMethodAverages, averageKey, targetValue, 'add'); | ||
}); | ||
// Calculate average class aggregate method data by adding the aggregate & dividing by the class divisor. | ||
ObjectUtil.safeBatchSet(classReport.aggregateAverage, classReport.aggregateAverage.keys, | ||
classReport.aggregate, 'add'); | ||
classMethodCount = 1; | ||
} | ||
moduleMethodAverageKeys.forEach((averageKey) => | ||
{ | ||
ObjectUtil.safeSet(classMethodAverages, averageKey, classMethodCount, 'div'); | ||
}); | ||
ObjectUtil.safeBatchSet(classReport.aggregateAverage, classReport.aggregateAverage.keys, | ||
classAggregateDivisor, 'div'); | ||
}); | ||
// If there are no module methods use the module aggregate MethodReport. | ||
if (moduleMethodCount === 0) | ||
// Calculate the pure average method data only if there are module methods. | ||
if (moduleMethodCount !== 0) | ||
{ | ||
// Sane handling of classes that contain no methods. | ||
moduleMethodAverageKeys.forEach((averageKey) => | ||
{ | ||
const targetValue = ObjectUtil.safeAccess(moduleReport.aggregateMethodReport, averageKey, 0); | ||
ObjectUtil.safeBatchSet(moduleReport.methodAverage, moduleReport.methodAverage.keys, moduleMethodCount, 'div'); | ||
} | ||
ObjectUtil.safeSet(moduleMethodAverages, averageKey, targetValue, 'add'); | ||
}); | ||
// Calculate average module aggregate method data by adding the aggregate & dividing by the module divisor. | ||
ObjectUtil.safeBatchSet(moduleReport.aggregateAverage, moduleReport.aggregateAverage.keys, | ||
moduleReport.aggregate, 'add'); | ||
// Sane handling of modules that contain no methods. | ||
moduleMethodCount = 1; | ||
} | ||
moduleMethodAverageKeys.forEach((averageKey) => | ||
{ | ||
ObjectUtil.safeSet(moduleMethodAverages, averageKey, moduleMethodCount, 'div'); | ||
}); | ||
ObjectUtil.safeBatchSet(moduleReport.aggregateAverage, moduleReport.aggregateAverage.keys, | ||
moduleAggregateDivisor, 'div'); | ||
} | ||
} |
@@ -14,4 +14,2 @@ /** | ||
* @param {ModuleReport} moduleReport - The ModuleReport being processed. | ||
* | ||
* @private | ||
*/ | ||
@@ -37,8 +35,8 @@ static calculate(moduleReport) | ||
ModuleMetricCalculate.calculateCyclomaticDensity(classReport.aggregateMethodReport); | ||
ModuleMetricCalculate.calculateHalsteadMetrics(classReport.aggregateMethodReport.halstead); | ||
ModuleMetricCalculate.calculateCyclomaticDensity(classReport.aggregateReport); | ||
ModuleMetricCalculate.calculateHalsteadMetrics(classReport.aggregateReport.halstead); | ||
}); | ||
ModuleMetricCalculate.calculateCyclomaticDensity(moduleReport.aggregateMethodReport); | ||
ModuleMetricCalculate.calculateHalsteadMetrics(moduleReport.aggregateMethodReport.halstead); | ||
ModuleMetricCalculate.calculateCyclomaticDensity(moduleReport.aggregateReport); | ||
ModuleMetricCalculate.calculateHalsteadMetrics(moduleReport.aggregateReport.halstead); | ||
} | ||
@@ -45,0 +43,0 @@ |
@@ -21,6 +21,6 @@ /** | ||
// Handle module report. | ||
const moduleMethodAverages = moduleReport.methodAverage; | ||
const moduleAggregateAverage = moduleReport.aggregateAverage; | ||
ModuleMetricPostAverage.calculateMaintainabilityIndex(moduleReport, settings, moduleMethodAverages.cyclomatic, | ||
moduleMethodAverages.halstead.effort, moduleMethodAverages.sloc.logical); | ||
ModuleMetricPostAverage.calculateMaintainabilityIndex(moduleReport, settings, moduleAggregateAverage.cyclomatic, | ||
moduleAggregateAverage.halstead.effort, moduleAggregateAverage.sloc.logical); | ||
@@ -30,2 +30,7 @@ // Handle module class reports. | ||
{ | ||
// const classAggregateAverage = classReport.aggregateAverage; | ||
// | ||
// ModuleMetricPostAverage.calculateMaintainabilityIndex(classReport, settings, classAggregateAverage.cyclomatic, | ||
// classAggregateAverage.halstead.effort, classAggregateAverage.sloc.logical); | ||
const classMethodAverages = classReport.methodAverage; | ||
@@ -51,2 +56,6 @@ | ||
* | ||
* Note: Bare module reports with no branching control flow or module methods and class reports with no class | ||
* methods start with a base cyclomatic complexity of 0. It is necessary to handle this case as | ||
* Math.log(0) === -Infinity. | ||
* | ||
* @param {ClassReport|ModuleReport} report - A ClassReport or ModuleReport to perform calculations on. | ||
@@ -56,3 +65,3 @@ * @param {object} settings - Settings for module processing. | ||
* @param {number} averageEffort - Average Halstead effort across a ClassReport / ModuleReport. | ||
* @param {number} averageLoc - Average SLOC metric across a ClassReport / ModuleReport. | ||
* @param {number} averageLoc - Average logical SLOC across a ClassReport / ModuleReport. | ||
* | ||
@@ -63,9 +72,6 @@ * @private | ||
{ | ||
/* istanbul ignore if */ | ||
if (averageCyclomatic === 0) { throw new Error('Encountered report with cyclomatic complexity zero!'); } | ||
report.maintainability = | ||
171 | ||
- (3.42 * Math.log(averageEffort)) | ||
- (0.23 * Math.log(averageCyclomatic)) | ||
- (0.23 * averageCyclomatic === 0 ? 0 : Math.log(averageCyclomatic)) | ||
- (16.2 * Math.log(averageLoc)); | ||
@@ -72,0 +78,0 @@ |
@@ -28,32 +28,85 @@ import HalsteadArray from 'typhonjs-escomplex-commons/src/module/traits/HalsteadArray'; | ||
* @param {object} newScope - An object hash defining the new scope including: | ||
* @param {object} node - Current AST node. | ||
* @param {object} parent - Parent AST node. | ||
* ``` | ||
* (string) type - Type of report to create. | ||
* (string) name - Name of the class or method. | ||
* (number) lineStart - Start line of method. | ||
* (number) lineEnd - End line of method. | ||
* (number) paramCount - (For method scopes) Number of parameters for method. | ||
* (string) type - Type of report scope being created. | ||
* ``` | ||
*/ | ||
static createScope(moduleReport, scopeControl, newScope = {}) | ||
static preScopeCreated(moduleReport, scopeControl, newScope = {}, node, parent) | ||
{ | ||
if (typeof newScope !== 'object') { throw new TypeError(`createScope error: 'newScope' is not an 'object'.`); } | ||
if (typeof newScope !== 'object') | ||
{ | ||
throw new TypeError(`preScopeCreated error: 'newScope' is not an 'object'.`); | ||
} | ||
if (typeof newScope.type !== 'string') | ||
{ | ||
throw new TypeError(`createScope error: 'newScope.type' is not a 'string'.`); | ||
throw new TypeError(`preScopeCreated error: 'newScope.type' is not a 'string'.`); | ||
} | ||
if (typeof newScope.name !== 'string') | ||
switch (newScope.type) | ||
{ | ||
throw new TypeError(`createScope error: 'newScope.name' is not a 'string'.`); | ||
case 'class': | ||
case 'method': | ||
// Increments logical SLOC for previous report scopes. | ||
if (Number.isInteger(newScope.lloc)) | ||
{ | ||
// Increments current module report associated aggregate report parameter count. | ||
moduleReport.aggregateReport.sloc.logical += newScope.lloc; | ||
const classReport = scopeControl.getCurrentClassReport(); | ||
const methodReport = scopeControl.getCurrentMethodReport(); | ||
if (classReport) { classReport.aggregateReport.sloc.logical += newScope.lloc; } | ||
if (methodReport) { methodReport.sloc.logical += newScope.lloc; } | ||
} | ||
if (newScope.operands instanceof HalsteadArray) | ||
{ | ||
const identifiers = newScope.operands.valueOf(node, parent); | ||
identifiers.forEach((identifier) => | ||
{ | ||
ModuleMetricProcess.halsteadItemEncountered(moduleReport, scopeControl, 'operands', identifier); | ||
}); | ||
} | ||
if (newScope.operators instanceof HalsteadArray) | ||
{ | ||
const identifiers = newScope.operators.valueOf(node, parent); | ||
identifiers.forEach((identifier) => | ||
{ | ||
ModuleMetricProcess.halsteadItemEncountered(moduleReport, scopeControl, 'operators', identifier); | ||
}); | ||
} | ||
break; | ||
} | ||
} | ||
if (!Number.isInteger(newScope.lineStart)) | ||
/** | ||
* Creates a moduleReport scope when a class or method is entered. | ||
* | ||
* @param {ModuleReport} moduleReport - The ModuleReport being processed. | ||
* @param {ModuleScopeControl} scopeControl - The associated module report scope control. | ||
* @param {object} newScope - An object hash defining the new scope including: | ||
* ``` | ||
* (string) type - Type of report scope being created. | ||
* (string) name - Name of the class or method. | ||
* (number) lineStart - Start line of method. | ||
* (number) lineEnd - End line of method. | ||
* (Array<string>) paramNames - (For method scopes) An array of parameters names for method. | ||
* ``` | ||
*/ | ||
static postScopeCreated(moduleReport, scopeControl, newScope = {}) | ||
{ | ||
if (typeof newScope !== 'object') | ||
{ | ||
throw new TypeError(`createScope error: 'newScope.lineStart' is not an 'integer'.`); | ||
throw new TypeError(`postScopeCreated error: 'newScope' is not an 'object'.`); | ||
} | ||
if (!Number.isInteger(newScope.lineEnd)) | ||
if (typeof newScope.type !== 'string') | ||
{ | ||
throw new TypeError(`createScope error: 'newScope.lineEnd' is not an 'integer'.`); | ||
throw new TypeError(`postScopeCreated error: 'newScope.type' is not a 'string'.`); | ||
} | ||
@@ -68,15 +121,36 @@ | ||
{ | ||
if (!Number.isInteger(newScope.paramCount)) | ||
if (!Number.isInteger(newScope.cyclomatic)) | ||
{ | ||
throw new TypeError(`createScope error: 'newScope.paramCount' is not an 'integer'.`); | ||
throw new TypeError(`postScopeCreated error: 'newScope.cyclomatic' is not an 'integer'.`); | ||
} | ||
// Increments the associated aggregate moduleReport parameter count. | ||
moduleReport.aggregateMethodReport.params += newScope.paramCount; | ||
if (!Array.isArray(newScope.paramNames)) | ||
{ | ||
throw new TypeError(`postScopeCreated error: 'newScope.paramNames' is not an 'array'.`); | ||
} | ||
const classReport = scopeControl.getCurrentClassReport(); | ||
const methodReport = scopeControl.getCurrentMethodReport(); | ||
// Increments current class report associated aggregate report parameter count. | ||
if (classReport) { classReport.aggregateMethodReport.params += newScope.paramCount; } | ||
// Increments current module report associated aggregate report cyclomatic count. | ||
moduleReport.aggregateReport.cyclomatic += newScope.cyclomatic; | ||
// Increments current module report associated aggregate report parameter count. | ||
moduleReport.aggregateReport.paramCount += newScope.paramNames.length; | ||
if (classReport) | ||
{ | ||
// Increments current class report associated aggregate report cyclomatic count. | ||
classReport.aggregateReport.cyclomatic += newScope.cyclomatic; | ||
// Increments current class report associated aggregate report parameter count. | ||
classReport.aggregateReport.paramCount += newScope.paramNames.length; | ||
} | ||
if (Number.isInteger(newScope.postLloc)) | ||
{ | ||
moduleReport.aggregateReport.sloc.logical += newScope.postLloc; | ||
if (classReport) { classReport.aggregateReport.sloc.logical += newScope.postLloc; } | ||
if (methodReport) { methodReport.sloc.logical += newScope.postLloc; } | ||
} | ||
break; | ||
@@ -108,3 +182,2 @@ } | ||
/** | ||
@@ -122,5 +195,5 @@ * Increments the cyclomatic metric for the ModuleReport and any current class or method report being tracked. | ||
moduleReport.methodAggregate.cyclomatic += amount; | ||
moduleReport.aggregate.cyclomatic += amount; | ||
if (currentClassReport) { currentClassReport.methodAggregate.cyclomatic += amount; } | ||
if (currentClassReport) { currentClassReport.aggregate.cyclomatic += amount; } | ||
if (currentMethodReport) { currentMethodReport.cyclomatic += amount; } | ||
@@ -142,6 +215,14 @@ } | ||
moduleReport.methodAggregate.sloc.logical += amount; | ||
moduleReport.aggregate.sloc.logical += amount; | ||
if (currentClassReport) { currentClassReport.methodAggregate.sloc.logical += amount; } | ||
if (currentMethodReport) { currentMethodReport.sloc.logical += amount; } | ||
if (currentClassReport) { currentClassReport.aggregate.sloc.logical += amount; } | ||
if (currentMethodReport) | ||
{ | ||
// if (amount > 0) | ||
// { | ||
// console.log('!! MMP - incrementLogicalSloc (method) - node type: ' + nodeType + '; amount: ' + amount); | ||
// } | ||
currentMethodReport.sloc.logical += amount; | ||
} | ||
} | ||
@@ -152,17 +233,17 @@ | ||
* | ||
* @param {ModuleReport} moduleReport - The ModuleReport being processed. | ||
* @param {string} metric - A Halstead metric name. | ||
* @param {string} identifier - A Halstead identifier name. | ||
* @param {ModuleReport|ClassReport|MethodReport} report - The report being processed. | ||
* @param {string} metric - A Halstead metric name. | ||
* @param {string} identifier - A Halstead identifier name. | ||
*/ | ||
static incrementHalsteadItems(moduleReport, metric, identifier) | ||
static incrementHalsteadItems(report, metric, identifier) | ||
{ | ||
// Increments the associated aggregate report HalsteadData for distinct identifiers. | ||
if (moduleReport.aggregateMethodReport.halstead[metric].identifiers.indexOf(identifier) === -1) | ||
if (report.aggregateReport.halstead[metric].identifiers.indexOf(identifier) === -1) | ||
{ | ||
moduleReport.aggregateMethodReport.halstead[metric].identifiers.push(identifier); | ||
moduleReport.aggregateMethodReport.halstead[metric]['distinct'] += 1; | ||
report.aggregateReport.halstead[metric].identifiers.push(identifier); | ||
report.aggregateReport.halstead[metric]['distinct'] += 1; | ||
} | ||
// Increment total halstead items | ||
moduleReport.aggregateMethodReport.halstead[metric]['total'] += 1; | ||
report.aggregateReport.halstead[metric]['total'] += 1; | ||
} | ||
@@ -183,14 +264,20 @@ | ||
{ | ||
switch (syntax[key].metric) | ||
const trait = syntax[key]; | ||
switch (trait.metric) | ||
{ | ||
case 'cyclomatic': | ||
ModuleMetricProcess.incrementCyclomatic(moduleReport, scopeControl, syntax[key].valueOf(node, parent)); | ||
ModuleMetricProcess.incrementCyclomatic(moduleReport, scopeControl, trait.valueOf(node, parent)); | ||
break; | ||
case 'dependencies': | ||
ModuleMetricProcess.addDependencies(moduleReport, syntax[key].valueOf(node, parent)); | ||
ModuleMetricProcess.addDependencies(moduleReport, trait.valueOf(node, parent)); | ||
break; | ||
case 'lloc': | ||
ModuleMetricProcess.incrementLogicalSloc(moduleReport, scopeControl, syntax[key].valueOf(node, parent)); | ||
// if (trait.valueOf(node, parent) > 0) | ||
// { | ||
// console.log('!! MMP - increment sloc - node type: ' + node.type + '; value: ' + trait.valueOf(node, parent)); | ||
// } | ||
ModuleMetricProcess.incrementLogicalSloc(moduleReport, scopeControl, trait.valueOf(node, parent)); | ||
break; | ||
@@ -200,9 +287,9 @@ } | ||
// Process operands / operators HalsteadArray entries. | ||
if (syntax[key] instanceof HalsteadArray) | ||
if (trait instanceof HalsteadArray) | ||
{ | ||
const identifiers = syntax[key].valueOf(node, parent); | ||
const identifiers = trait.valueOf(node, parent); | ||
identifiers.forEach((identifier) => | ||
{ | ||
ModuleMetricProcess.halsteadItemEncountered(moduleReport, scopeControl, syntax[key].metric, identifier); | ||
ModuleMetricProcess.halsteadItemEncountered(moduleReport, scopeControl, trait.metric, identifier); | ||
}); | ||
@@ -209,0 +296,0 @@ } |
@@ -86,6 +86,17 @@ import ModuleMetricAverage from './ModuleMetricAverage'; | ||
*/ | ||
onModuleScopeCreated(ev) | ||
onModulePostScopeCreated(ev) | ||
{ | ||
ModuleMetricProcess.createScope(ev.data.moduleReport, ev.data.scopeControl, ev.data.newScope); | ||
ModuleMetricProcess.postScopeCreated(ev.data.moduleReport, ev.data.scopeControl, ev.data.newScope); | ||
} | ||
/** | ||
* A new module report scope has been created. Update any associated metrics processing regarding the new scope. | ||
* | ||
* @param {object} ev - escomplex plugin event data. | ||
*/ | ||
onModulePreScopeCreated(ev) | ||
{ | ||
ModuleMetricProcess.preScopeCreated(ev.data.moduleReport, ev.data.scopeControl, ev.data.newScope, ev.data.node, | ||
ev.data.parent); | ||
} | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
86368
17
1204
0
+ Addedtyphonjs-escomplex-commons@0.1.1(transitive)
- Removedtyphonjs-escomplex-commons@0.0.16(transitive)