New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

escomplex-plugin-metrics-module

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

escomplex-plugin-metrics-module - npm Package Compare versions

Comparing version 0.0.11 to 0.0.12

190

dist/ModuleMetricCalculate.js

@@ -29,5 +29,95 @@ 'use strict';

_createClass(ModuleMetricCalculate, null, [{
key: 'calculateCyclomaticDensity',
key: 'calculate',
/**
* Coordinates calculating all metrics. All module and class methods are traversed. If there are no module or class
* methods respectively the aggregate MethodReport is used for calculations.
*
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {object} settings - Settings for module processing.
*
* @private
*/
value: function calculate(moduleReport, settings) {
var moduleMethodCount = moduleReport.methods.length;
var moduleMethodAverages = moduleReport.methodAverage;
var moduleMethodAverageKeys = _ObjectUtil2.default.getAccessorList(moduleMethodAverages);
// Handle module methods.
moduleReport.methods.forEach(function (methodReport) {
moduleMethodAverageKeys.forEach(function (averageKey) {
ModuleMetricCalculate.calculateCyclomaticDensity(methodReport);
ModuleMetricCalculate.calculateHalsteadMetrics(methodReport.halstead);
var targetValue = _ObjectUtil2.default.safeAccess(methodReport, averageKey, 0);
_ObjectUtil2.default.safeSet(moduleMethodAverages, averageKey, targetValue, 'add');
});
});
// Handle module class reports.
moduleReport.classes.forEach(function (classReport) {
var classMethodAverages = classReport.methodAverage;
var classMethodCount = classReport.methods.length;
moduleMethodCount += classMethodCount;
// Process all class methods.
classReport.methods.forEach(function (methodReport) {
ModuleMetricCalculate.calculateCyclomaticDensity(methodReport);
ModuleMetricCalculate.calculateHalsteadMetrics(methodReport.halstead);
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');
});
});
ModuleMetricCalculate.calculateCyclomaticDensity(classReport.aggregateMethodReport);
ModuleMetricCalculate.calculateHalsteadMetrics(classReport.aggregateMethodReport.halstead);
// 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);
_ObjectUtil2.default.safeSet(classMethodAverages, averageKey, targetValue, 'add');
});
classMethodCount = 1;
}
moduleMethodAverageKeys.forEach(function (averageKey) {
_ObjectUtil2.default.safeSet(classMethodAverages, averageKey, classMethodCount, 'div');
});
ModuleMetricCalculate.calculateMaintainabilityIndex(classReport, settings, classMethodAverages.cyclomatic, classMethodAverages.halstead.effort, classMethodAverages.sloc.logical);
});
ModuleMetricCalculate.calculateCyclomaticDensity(moduleReport.aggregateMethodReport);
ModuleMetricCalculate.calculateHalsteadMetrics(moduleReport.aggregateMethodReport.halstead);
// 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);
_ObjectUtil2.default.safeSet(moduleMethodAverages, averageKey, targetValue, 'add');
});
// Sane handling of modules that contain no methods.
moduleMethodCount = 1;
}
moduleMethodAverageKeys.forEach(function (averageKey) {
_ObjectUtil2.default.safeSet(moduleMethodAverages, averageKey, moduleMethodCount, 'div');
});
ModuleMetricCalculate.calculateMaintainabilityIndex(moduleReport, settings, moduleMethodAverages.cyclomatic, moduleMethodAverages.halstead.effort, moduleMethodAverages.sloc.logical);
}
/**
* Calculates cyclomatic density - Proposed as a modification to cyclomatic complexity by Geoffrey K. Gill and

@@ -37,6 +127,9 @@ * Chris F. Kemerer in 1991, this metric simply re-expresses it as a percentage of the logical lines of code. Lower

*
* @param {MethodReport} report - A MethodReport to perform calculations on.
* @param {AggregateMethodReport} report - An AggregateMethodReport to perform calculations on.
*
* @private
*/
}, {
key: 'calculateCyclomaticDensity',
value: function calculateCyclomaticDensity(report) {

@@ -119,95 +212,2 @@ report.cyclomaticDensity = report.sloc.logical === 0 ? 0 : report.cyclomatic / report.sloc.logical * 100;

}
/**
* Coordinates calculating all metrics. All module and class methods are traversed. If there are no module or class
* methods respectively the aggregate MethodReport is used for calculations.
*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {object} settings - Settings for module processing.
*
* @private
*/
}, {
key: 'calculateMetrics',
value: function calculateMetrics(report, settings) {
var moduleMethodCount = report.methods.length;
var moduleMethodAverages = report.methodAverage;
var moduleMethodAverageKeys = _ObjectUtil2.default.getAccessorList(moduleMethodAverages);
// Handle module methods.
report.methods.forEach(function (methodReport) {
moduleMethodAverageKeys.forEach(function (averageKey) {
ModuleMetricCalculate.calculateCyclomaticDensity(methodReport);
ModuleMetricCalculate.calculateHalsteadMetrics(methodReport.halstead);
var targetValue = _ObjectUtil2.default.safeAccess(methodReport, averageKey, 0);
_ObjectUtil2.default.safeSet(moduleMethodAverages, averageKey, targetValue, 'add');
});
});
// Handle module class reports.
report.classes.forEach(function (classReport) {
var classMethodAverages = classReport.methodAverage;
var classMethodCount = classReport.methods.length;
moduleMethodCount += classMethodCount;
// Process all class methods.
classReport.methods.forEach(function (methodReport) {
ModuleMetricCalculate.calculateCyclomaticDensity(methodReport);
ModuleMetricCalculate.calculateHalsteadMetrics(methodReport.halstead);
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');
});
});
ModuleMetricCalculate.calculateCyclomaticDensity(classReport.aggregateMethodReport);
ModuleMetricCalculate.calculateHalsteadMetrics(classReport.aggregateMethodReport.halstead);
// 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);
_ObjectUtil2.default.safeSet(classMethodAverages, averageKey, targetValue, 'add');
});
classMethodCount = 1;
}
moduleMethodAverageKeys.forEach(function (averageKey) {
_ObjectUtil2.default.safeSet(classMethodAverages, averageKey, classMethodCount, 'div');
});
ModuleMetricCalculate.calculateMaintainabilityIndex(classReport, settings, classMethodAverages.cyclomatic, classMethodAverages.halstead.effort, classMethodAverages.sloc.logical);
});
ModuleMetricCalculate.calculateCyclomaticDensity(report.aggregateMethodReport);
ModuleMetricCalculate.calculateHalsteadMetrics(report.aggregateMethodReport.halstead);
// 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(report.aggregateMethodReport, averageKey, 0);
_ObjectUtil2.default.safeSet(moduleMethodAverages, averageKey, targetValue, 'add');
});
// Sane handling of modules that contain no methods.
moduleMethodCount = 1;
}
moduleMethodAverageKeys.forEach(function (averageKey) {
_ObjectUtil2.default.safeSet(moduleMethodAverages, averageKey, moduleMethodCount, 'div');
});
ModuleMetricCalculate.calculateMaintainabilityIndex(report, settings, moduleMethodAverages.cyclomatic, moduleMethodAverages.halstead.effort, moduleMethodAverages.sloc.logical);
}
}]);

@@ -214,0 +214,0 @@

@@ -30,8 +30,8 @@ 'use strict';

*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {object|Array<object>} dependencies - Dependencies to add.
*/
value: function addDependencies(report, dependencies) {
value: function addDependencies(moduleReport, dependencies) {
if ((typeof dependencies === 'undefined' ? 'undefined' : _typeof(dependencies)) === 'object' || Array.isArray(dependencies)) {
report.dependencies = report.dependencies.concat(dependencies);
moduleReport.dependencies = moduleReport.dependencies.concat(dependencies);
}

@@ -41,5 +41,5 @@ }

/**
* Creates a report scope when a class or method is entered.
* Creates a moduleReport scope when a class or method is entered.
*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {ModuleScopeControl} scopeControl - The associated module report scope control.

@@ -58,3 +58,3 @@ * @param {object} newScope - An object hash defining the new scope including:

key: 'createScope',
value: function createScope(report, scopeControl) {
value: function createScope(moduleReport, scopeControl) {
var newScope = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];

@@ -92,4 +92,4 @@

// Increments the associated aggregate report parameter count.
report.aggregateMethodReport.params += newScope.paramCount;
// Increments the associated aggregate moduleReport parameter count.
moduleReport.aggregateMethodReport.params += newScope.paramCount;

@@ -112,3 +112,3 @@ var classReport = scopeControl.getCurrentClassReport();

*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {ModuleScopeControl} scopeControl - The associated module report scope control.

@@ -121,14 +121,14 @@ * @param {string} metric - A Halstead metric name.

key: 'halsteadItemEncountered',
value: function halsteadItemEncountered(report, scopeControl, metric, identifier) {
value: function halsteadItemEncountered(moduleReport, scopeControl, metric, identifier) {
var currentClassReport = scopeControl.getCurrentClassReport();
var currentMethodReport = scopeControl.getCurrentMethodReport();
this.incrementHalsteadItems(report, metric, identifier);
ModuleMetricControl.incrementHalsteadItems(moduleReport, metric, identifier);
if (currentClassReport) {
this.incrementHalsteadItems(currentClassReport, metric, identifier);
ModuleMetricControl.incrementHalsteadItems(currentClassReport, metric, identifier);
}
if (currentMethodReport) {
this.incrementHalsteadItems(currentMethodReport, metric, identifier);
ModuleMetricControl.incrementHalsteadItems(currentMethodReport, metric, identifier);
}

@@ -140,3 +140,3 @@ }

*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {ModuleScopeControl} scopeControl - The associated module report scope control.

@@ -148,7 +148,7 @@ * @param {number} amount - Amount to increment.

key: 'incrementCyclomatic',
value: function incrementCyclomatic(report, scopeControl, amount) {
value: function incrementCyclomatic(moduleReport, scopeControl, amount) {
var currentClassReport = scopeControl.getCurrentClassReport();
var currentMethodReport = scopeControl.getCurrentMethodReport();
report.methodAggregate.cyclomatic += amount;
moduleReport.methodAggregate.cyclomatic += amount;

@@ -167,3 +167,3 @@ if (currentClassReport) {

*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {ModuleScopeControl} scopeControl - The associated module report scope control.

@@ -175,7 +175,7 @@ * @param {number} amount - Amount to increment.

key: 'incrementLogicalSloc',
value: function incrementLogicalSloc(report, scopeControl, amount) {
value: function incrementLogicalSloc(moduleReport, scopeControl, amount) {
var currentClassReport = scopeControl.getCurrentClassReport();
var currentMethodReport = scopeControl.getCurrentMethodReport();
report.methodAggregate.sloc.logical += amount;
moduleReport.methodAggregate.sloc.logical += amount;

@@ -193,3 +193,3 @@ if (currentClassReport) {

*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {string} metric - A Halstead metric name.

@@ -201,11 +201,11 @@ * @param {string} identifier - A Halstead identifier name.

key: 'incrementHalsteadItems',
value: function incrementHalsteadItems(report, metric, identifier) {
value: function incrementHalsteadItems(moduleReport, metric, identifier) {
// Increments the associated aggregate report HalsteadData for distinct identifiers.
if (report.aggregateMethodReport.halstead[metric].identifiers.indexOf(identifier) === -1) {
report.aggregateMethodReport.halstead[metric].identifiers.push(identifier);
report.aggregateMethodReport.halstead[metric]['distinct'] += 1;
if (moduleReport.aggregateMethodReport.halstead[metric].identifiers.indexOf(identifier) === -1) {
moduleReport.aggregateMethodReport.halstead[metric].identifiers.push(identifier);
moduleReport.aggregateMethodReport.halstead[metric]['distinct'] += 1;
}
// Increment total halstead items
report.aggregateMethodReport.halstead[metric]['total'] += 1;
moduleReport.aggregateMethodReport.halstead[metric]['total'] += 1;
}

@@ -216,3 +216,3 @@

*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {ModuleScopeControl} scopeControl - The associated module report scope control.

@@ -226,17 +226,15 @@ * @param {object} syntax - The associated syntax being processed for current node.

key: 'processSyntax',
value: function processSyntax(report, scopeControl, syntax, node, parent) {
var _this = this;
value: function processSyntax(moduleReport, scopeControl, syntax, node, parent) {
var _loop = function _loop(key) {
switch (syntax[key].metric) {
case 'cyclomatic':
_this.incrementCyclomatic(report, scopeControl, syntax[key].valueOf(node, parent));
ModuleMetricControl.incrementCyclomatic(moduleReport, scopeControl, syntax[key].valueOf(node, parent));
break;
case 'dependencies':
_this.addDependencies(report, syntax[key].valueOf(node, parent));
ModuleMetricControl.addDependencies(moduleReport, syntax[key].valueOf(node, parent));
break;
case 'lloc':
_this.incrementLogicalSloc(report, scopeControl, syntax[key].valueOf(node, parent));
ModuleMetricControl.incrementLogicalSloc(moduleReport, scopeControl, syntax[key].valueOf(node, parent));
break;

@@ -250,3 +248,3 @@ }

identifiers.forEach(function (identifier) {
_this.halsteadItemEncountered(report, scopeControl, syntax[key].metric, identifier);
ModuleMetricControl.halsteadItemEncountered(moduleReport, scopeControl, syntax[key].metric, identifier);
});

@@ -253,0 +251,0 @@ }

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
value: true
});

@@ -30,78 +30,76 @@

var PluginMetricsModule = function () {
function PluginMetricsModule() {
_classCallCheck(this, PluginMetricsModule);
}
function PluginMetricsModule() {
_classCallCheck(this, PluginMetricsModule);
}
_createClass(PluginMetricsModule, [{
key: 'onConfigure',
_createClass(PluginMetricsModule, [{
key: 'onConfigure',
// ESComplexModule plugin callbacks ------------------------------------------------------------------------------
/**
* 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.
*
* @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.
*
* @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 report = ev.data.report;
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') {
_ModuleMetricControl2.default.processSyntax(report, scopeControl, syntax, node, parent);
// Process node syntax.
if ((typeof syntax === 'undefined' ? 'undefined' : _typeof(syntax)) === 'object') {
_ModuleMetricControl2.default.processSyntax(moduleReport, scopeControl, syntax, node, parent);
}
}
}
/**
* Performs final calculations based on collected report data.
*
* @param {object} ev - escomplex plugin event data.
*/
/**
* Performs final calculations based on collected report data.
*
* @param {object} ev - escomplex plugin event data.
*/
}, {
key: 'onModuleEnd',
value: function onModuleEnd(ev) {
_ModuleMetricCalculate2.default.calculateMetrics(ev.data.report, ev.data.settings);
}
}, {
key: 'onModuleEnd',
value: function onModuleEnd(ev) {
_ModuleMetricCalculate2.default.calculate(ev.data.moduleReport, ev.data.settings);
}
/**
* A new module report scope has been created. Update any associated metrics regarding the new scope.
*
* @param {object} ev - escomplex plugin event data.
*/
/**
* A new module report scope has been created. Update any associated metrics regarding the new scope.
*
* @param {object} ev - escomplex plugin event data.
*/
}, {
key: 'onScopeCreated',
value: function onScopeCreated(ev) {
var report = ev.data.report;
var scopeControl = ev.data.scopeControl;
var newScope = ev.data.newScope;
}, {
key: 'onScopeCreated',
value: function onScopeCreated(ev) {
var moduleReport = ev.data.moduleReport;
var scopeControl = ev.data.scopeControl;
var newScope = ev.data.newScope;
_ModuleMetricControl2.default.createScope(report, scopeControl, newScope);
}
}]);
_ModuleMetricControl2.default.createScope(moduleReport, scopeControl, newScope);
}
}]);
return PluginMetricsModule;
return PluginMetricsModule;
}();

@@ -108,0 +106,0 @@

{
"name": "escomplex-plugin-metrics-module",
"version": "0.0.11",
"version": "0.0.12",
"homepage": "https://github.com/typhonjs-node-escomplex/escomplex-plugin-metrics-module/",

@@ -23,6 +23,6 @@ "description": "Provides the core module metric / report generation plugin for typhonjs-escomplex module processing.",

"dependencies": {
"typhonjs-escomplex-commons": "^0.0.15"
"typhonjs-escomplex-commons": "^0.0.16"
},
"devDependencies": {
"escomplex-plugin-syntax-babylon": "^0.0.11",
"escomplex-plugin-syntax-babylon": "^0.0.12",
"typhonjs-ast-walker": "^0.1.0",

@@ -29,0 +29,0 @@ "typhonjs-config-eslint": "^0.4.0",

@@ -1,2 +0,2 @@

import ObjectUtil from 'typhonjs-escomplex-commons/src/utils/ObjectUtil';
import ObjectUtil from 'typhonjs-escomplex-commons/src/utils/ObjectUtil';

@@ -12,92 +12,6 @@ /**

/**
* Calculates cyclomatic density - Proposed as a modification to cyclomatic complexity by Geoffrey K. Gill and
* Chris F. Kemerer in 1991, this metric simply re-expresses it as a percentage of the logical lines of code. Lower
* is better.
*
* @param {MethodReport} report - A MethodReport to perform calculations on.
*
* @private
*/
static calculateCyclomaticDensity(report)
{
report.cyclomaticDensity = report.sloc.logical === 0 ? 0 : (report.cyclomatic / report.sloc.logical) * 100;
}
/**
* Calculates Halstead metrics. In 1977, Maurice Halstead developed a set of metrics which are calculated based on
* the number of distinct operators, the number of distinct operands, the total number of operators and the total
* number of operands in each function. This site picks out three Halstead measures in particular: difficulty,
* volume and effort.
*
* @param {HalsteadData} halstead - A HalsteadData instance to perform calculations on.
*
* @see https://en.wikipedia.org/wiki/Halstead_complexity_measures
*
* @private
*/
static calculateHalsteadMetrics(halstead)
{
halstead.length = halstead.operators.total + halstead.operands.total;
/* istanbul ignore if */
if (halstead.length === 0)
{
halstead.reset();
}
else
{
halstead.vocabulary = halstead.operators.distinct + halstead.operands.distinct;
halstead.difficulty = (halstead.operators.distinct / 2)
* (halstead.operands.distinct === 0 ? 1 : halstead.operands.total / halstead.operands.distinct);
halstead.volume = halstead.length * (Math.log(halstead.vocabulary) / Math.log(2));
halstead.effort = halstead.difficulty * halstead.volume;
halstead.bugs = halstead.volume / 3000;
halstead.time = halstead.effort / 18;
}
}
/**
* Designed in 1991 by Paul Oman and Jack Hagemeister at the University of Idaho, this metric is calculated at the
* whole program or module level from averages of the other 3 metrics, using the following formula:
* ```
* 171 -
* (3.42 * ln(mean effort)) -
* (0.23 * ln(mean cyclomatic complexity)) -
* (16.2 * ln(mean logical LOC))
* ```
* Values are on a logarithmic scale ranging from negative infinity up to 171, with greater numbers indicating a
* higher level of maintainability. In their original paper, Oman and Hagemeister identified 65 as the threshold
* value below which a program should be considered difficult to maintain.
*
* @param {ClassReport|ModuleReport} report - A ClassReport or ModuleReport to perform calculations on.
* @param {object} settings - Settings for module processing.
* @param {number} averageCyclomatic - Average cyclomatic metric across a ClassReport / ModuleReport.
* @param {number} averageEffort - Average Halstead effort across a ClassReport / ModuleReport.
* @param {number} averageLoc - Average SLOC metric across a ClassReport / ModuleReport.
*
* @private
*/
static calculateMaintainabilityIndex(report, settings, averageCyclomatic, averageEffort, averageLoc)
{
/* istanbul ignore if */
if (averageCyclomatic === 0) { throw new Error('Encountered function with cyclomatic complexity zero!'); }
report.maintainability =
171
- (3.42 * Math.log(averageEffort))
- (0.23 * Math.log(averageCyclomatic))
- (16.2 * Math.log(averageLoc));
/* istanbul ignore if */
if (report.maintainability > 171) { report.maintainability = 171; }
/* istanbul ignore if */
if (settings.newmi) { report.maintainability = Math.max(0, (report.maintainability * 100) / 171); }
}
/**
* Coordinates calculating all metrics. All module and class methods are traversed. If there are no module or class
* methods respectively the aggregate MethodReport is used for calculations.
*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {object} settings - Settings for module processing.

@@ -107,10 +21,10 @@ *

*/
static calculateMetrics(report, settings)
static calculate(moduleReport, settings)
{
let moduleMethodCount = report.methods.length;
const moduleMethodAverages = report.methodAverage;
let moduleMethodCount = moduleReport.methods.length;
const moduleMethodAverages = moduleReport.methodAverage;
const moduleMethodAverageKeys = ObjectUtil.getAccessorList(moduleMethodAverages);
// Handle module methods.
report.methods.forEach((methodReport) =>
moduleReport.methods.forEach((methodReport) =>
{

@@ -128,3 +42,3 @@ moduleMethodAverageKeys.forEach((averageKey) =>

// Handle module class reports.
report.classes.forEach((classReport) =>
moduleReport.classes.forEach((classReport) =>
{

@@ -177,4 +91,4 @@ const classMethodAverages = classReport.methodAverage;

ModuleMetricCalculate.calculateCyclomaticDensity(report.aggregateMethodReport);
ModuleMetricCalculate.calculateHalsteadMetrics(report.aggregateMethodReport.halstead);
ModuleMetricCalculate.calculateCyclomaticDensity(moduleReport.aggregateMethodReport);
ModuleMetricCalculate.calculateHalsteadMetrics(moduleReport.aggregateMethodReport.halstead);

@@ -187,3 +101,3 @@ // If there are no module methods use the module aggregate MethodReport.

{
const targetValue = ObjectUtil.safeAccess(report.aggregateMethodReport, averageKey, 0);
const targetValue = ObjectUtil.safeAccess(moduleReport.aggregateMethodReport, averageKey, 0);

@@ -202,5 +116,91 @@ ObjectUtil.safeSet(moduleMethodAverages, averageKey, targetValue, 'add');

ModuleMetricCalculate.calculateMaintainabilityIndex(report, settings, moduleMethodAverages.cyclomatic,
ModuleMetricCalculate.calculateMaintainabilityIndex(moduleReport, settings, moduleMethodAverages.cyclomatic,
moduleMethodAverages.halstead.effort, moduleMethodAverages.sloc.logical);
}
/**
* Calculates cyclomatic density - Proposed as a modification to cyclomatic complexity by Geoffrey K. Gill and
* Chris F. Kemerer in 1991, this metric simply re-expresses it as a percentage of the logical lines of code. Lower
* is better.
*
* @param {AggregateMethodReport} report - An AggregateMethodReport to perform calculations on.
*
* @private
*/
static calculateCyclomaticDensity(report)
{
report.cyclomaticDensity = report.sloc.logical === 0 ? 0 : (report.cyclomatic / report.sloc.logical) * 100;
}
/**
* Calculates Halstead metrics. In 1977, Maurice Halstead developed a set of metrics which are calculated based on
* the number of distinct operators, the number of distinct operands, the total number of operators and the total
* number of operands in each function. This site picks out three Halstead measures in particular: difficulty,
* volume and effort.
*
* @param {HalsteadData} halstead - A HalsteadData instance to perform calculations on.
*
* @see https://en.wikipedia.org/wiki/Halstead_complexity_measures
*
* @private
*/
static calculateHalsteadMetrics(halstead)
{
halstead.length = halstead.operators.total + halstead.operands.total;
/* istanbul ignore if */
if (halstead.length === 0)
{
halstead.reset();
}
else
{
halstead.vocabulary = halstead.operators.distinct + halstead.operands.distinct;
halstead.difficulty = (halstead.operators.distinct / 2)
* (halstead.operands.distinct === 0 ? 1 : halstead.operands.total / halstead.operands.distinct);
halstead.volume = halstead.length * (Math.log(halstead.vocabulary) / Math.log(2));
halstead.effort = halstead.difficulty * halstead.volume;
halstead.bugs = halstead.volume / 3000;
halstead.time = halstead.effort / 18;
}
}
/**
* Designed in 1991 by Paul Oman and Jack Hagemeister at the University of Idaho, this metric is calculated at the
* whole program or module level from averages of the other 3 metrics, using the following formula:
* ```
* 171 -
* (3.42 * ln(mean effort)) -
* (0.23 * ln(mean cyclomatic complexity)) -
* (16.2 * ln(mean logical LOC))
* ```
* Values are on a logarithmic scale ranging from negative infinity up to 171, with greater numbers indicating a
* higher level of maintainability. In their original paper, Oman and Hagemeister identified 65 as the threshold
* value below which a program should be considered difficult to maintain.
*
* @param {ClassReport|ModuleReport} report - A ClassReport or ModuleReport to perform calculations on.
* @param {object} settings - Settings for module processing.
* @param {number} averageCyclomatic - Average cyclomatic metric across a ClassReport / ModuleReport.
* @param {number} averageEffort - Average Halstead effort across a ClassReport / ModuleReport.
* @param {number} averageLoc - Average SLOC metric across a ClassReport / ModuleReport.
*
* @private
*/
static calculateMaintainabilityIndex(report, settings, averageCyclomatic, averageEffort, averageLoc)
{
/* istanbul ignore if */
if (averageCyclomatic === 0) { throw new Error('Encountered function with cyclomatic complexity zero!'); }
report.maintainability =
171
- (3.42 * Math.log(averageEffort))
- (0.23 * Math.log(averageCyclomatic))
- (16.2 * Math.log(averageLoc));
/* istanbul ignore if */
if (report.maintainability > 171) { report.maintainability = 171; }
/* istanbul ignore if */
if (settings.newmi) { report.maintainability = Math.max(0, (report.maintainability * 100) / 171); }
}
}

@@ -8,10 +8,10 @@ import HalsteadArray from 'typhonjs-escomplex-commons/src/module/traits/HalsteadArray';

*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {object|Array<object>} dependencies - Dependencies to add.
*/
static addDependencies(report, dependencies)
static addDependencies(moduleReport, dependencies)
{
if (typeof dependencies === 'object' || Array.isArray(dependencies))
{
report.dependencies = report.dependencies.concat(dependencies);
moduleReport.dependencies = moduleReport.dependencies.concat(dependencies);
}

@@ -21,5 +21,5 @@ }

/**
* Creates a report scope when a class or method is entered.
* Creates a moduleReport scope when a class or method is entered.
*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {ModuleScopeControl} scopeControl - The associated module report scope control.

@@ -35,3 +35,3 @@ * @param {object} newScope - An object hash defining the new scope including:

*/
static createScope(report, scopeControl, newScope = {})
static createScope(moduleReport, scopeControl, newScope = {})
{

@@ -72,4 +72,4 @@ if (typeof newScope !== 'object') { throw new TypeError(`createScope error: 'newScope' is not an 'object'.`); }

// Increments the associated aggregate report parameter count.
report.aggregateMethodReport.params += newScope.paramCount;
// Increments the associated aggregate moduleReport parameter count.
moduleReport.aggregateMethodReport.params += newScope.paramCount;

@@ -90,3 +90,3 @@ const classReport = scopeControl.getCurrentClassReport();

*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {ModuleScopeControl} scopeControl - The associated module report scope control.

@@ -96,3 +96,3 @@ * @param {string} metric - A Halstead metric name.

*/
static halsteadItemEncountered(report, scopeControl, metric, identifier)
static halsteadItemEncountered(moduleReport, scopeControl, metric, identifier)
{

@@ -102,7 +102,7 @@ const currentClassReport = scopeControl.getCurrentClassReport();

this.incrementHalsteadItems(report, metric, identifier);
ModuleMetricControl.incrementHalsteadItems(moduleReport, metric, identifier);
if (currentClassReport) { this.incrementHalsteadItems(currentClassReport, metric, identifier); }
if (currentClassReport) { ModuleMetricControl.incrementHalsteadItems(currentClassReport, metric, identifier); }
if (currentMethodReport) { this.incrementHalsteadItems(currentMethodReport, metric, identifier); }
if (currentMethodReport) { ModuleMetricControl.incrementHalsteadItems(currentMethodReport, metric, identifier); }
}

@@ -114,7 +114,7 @@

*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {ModuleScopeControl} scopeControl - The associated module report scope control.
* @param {number} amount - Amount to increment.
*/
static incrementCyclomatic(report, scopeControl, amount)
static incrementCyclomatic(moduleReport, scopeControl, amount)
{

@@ -124,3 +124,3 @@ const currentClassReport = scopeControl.getCurrentClassReport();

report.methodAggregate.cyclomatic += amount;
moduleReport.methodAggregate.cyclomatic += amount;

@@ -135,7 +135,7 @@ if (currentClassReport) { currentClassReport.methodAggregate.cyclomatic += amount; }

*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {ModuleScopeControl} scopeControl - The associated module report scope control.
* @param {number} amount - Amount to increment.
*/
static incrementLogicalSloc(report, scopeControl, amount)
static incrementLogicalSloc(moduleReport, scopeControl, amount)
{

@@ -145,3 +145,3 @@ const currentClassReport = scopeControl.getCurrentClassReport();

report.methodAggregate.sloc.logical += amount;
moduleReport.methodAggregate.sloc.logical += amount;

@@ -155,17 +155,17 @@ if (currentClassReport) { currentClassReport.methodAggregate.sloc.logical += amount; }

*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {string} metric - A Halstead metric name.
* @param {string} identifier - A Halstead identifier name.
*/
static incrementHalsteadItems(report, metric, identifier)
static incrementHalsteadItems(moduleReport, metric, identifier)
{
// Increments the associated aggregate report HalsteadData for distinct identifiers.
if (report.aggregateMethodReport.halstead[metric].identifiers.indexOf(identifier) === -1)
if (moduleReport.aggregateMethodReport.halstead[metric].identifiers.indexOf(identifier) === -1)
{
report.aggregateMethodReport.halstead[metric].identifiers.push(identifier);
report.aggregateMethodReport.halstead[metric]['distinct'] += 1;
moduleReport.aggregateMethodReport.halstead[metric].identifiers.push(identifier);
moduleReport.aggregateMethodReport.halstead[metric]['distinct'] += 1;
}
// Increment total halstead items
report.aggregateMethodReport.halstead[metric]['total'] += 1;
moduleReport.aggregateMethodReport.halstead[metric]['total'] += 1;
}

@@ -176,3 +176,3 @@

*
* @param {ModuleReport} report - The ModuleReport being processed.
* @param {ModuleReport} moduleReport - The ModuleReport being processed.
* @param {ModuleScopeControl} scopeControl - The associated module report scope control.

@@ -183,3 +183,3 @@ * @param {object} syntax - The associated syntax being processed for current node.

*/
static processSyntax(report, scopeControl, syntax, node, parent)
static processSyntax(moduleReport, scopeControl, syntax, node, parent)
{

@@ -191,11 +191,11 @@ for (const key in syntax)

case 'cyclomatic':
this.incrementCyclomatic(report, scopeControl, syntax[key].valueOf(node, parent));
ModuleMetricControl.incrementCyclomatic(moduleReport, scopeControl, syntax[key].valueOf(node, parent));
break;
case 'dependencies':
this.addDependencies(report, syntax[key].valueOf(node, parent));
ModuleMetricControl.addDependencies(moduleReport, syntax[key].valueOf(node, parent));
break;
case 'lloc':
this.incrementLogicalSloc(report, scopeControl, syntax[key].valueOf(node, parent));
ModuleMetricControl.incrementLogicalSloc(moduleReport, scopeControl, syntax[key].valueOf(node, parent));
break;

@@ -211,3 +211,3 @@ }

{
this.halsteadItemEncountered(report, scopeControl, syntax[key].metric, identifier);
ModuleMetricControl.halsteadItemEncountered(moduleReport, scopeControl, syntax[key].metric, identifier);
});

@@ -214,0 +214,0 @@ }

@@ -12,4 +12,2 @@ import ModuleMetricCalculate from './ModuleMetricCalculate';

{
// ESComplexModule plugin callbacks ------------------------------------------------------------------------------
/**

@@ -39,3 +37,3 @@ * Loads any default settings that are not already provided by any user options.

{
const report = ev.data.report;
const moduleReport = ev.data.moduleReport;
const scopeControl = ev.data.scopeControl;

@@ -47,3 +45,6 @@ const node = ev.data.node;

// Process node syntax.
if (typeof syntax === 'object') { ModuleMetricControl.processSyntax(report, scopeControl, syntax, node, parent); }
if (typeof syntax === 'object')
{
ModuleMetricControl.processSyntax(moduleReport, scopeControl, syntax, node, parent);
}
}

@@ -58,3 +59,3 @@

{
ModuleMetricCalculate.calculateMetrics(ev.data.report, ev.data.settings);
ModuleMetricCalculate.calculate(ev.data.moduleReport, ev.data.settings);
}

@@ -69,8 +70,8 @@

{
const report = ev.data.report;
const moduleReport = ev.data.moduleReport;
const scopeControl = ev.data.scopeControl;
const newScope = ev.data.newScope;
ModuleMetricControl.createScope(report, scopeControl, newScope);
ModuleMetricControl.createScope(moduleReport, scopeControl, newScope);
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc