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

complexity-report

Package Overview
Dependencies
Maintainers
1
Versions
52
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

complexity-report - npm Package Compare versions

Comparing version 0.2.7 to 0.2.8

12

Jakefile.js

@@ -10,3 +10,2 @@ /*jshint nomen:false */

commands = {
minify: './node_modules/.bin/uglifyjs --no-copyright --lift-vars --output ./src/complexityReport.min.js ./src/complexityReport.js',
test: './node_modules/.bin/mocha --ui tdd --reporter spec --colors --slow 50 ./test/complexityReport.js',

@@ -17,9 +16,2 @@ lint: './node_modules/.bin/jshint ./src/complexityReport.js --config config/jshint.json',

desc('Minify the source code for deployment.');
task('minify', [ 'prepare', 'lint', 'test' ], function () {
runTask(minify, 'Minifying...');
}, {
async: true
});
desc('Run the unit tests.');

@@ -51,6 +43,2 @@ task('test', [ 'prepare' ], function () {

function minify () {
runCommand(commands.minify);
}
function test () {

@@ -57,0 +45,0 @@ runCommand(commands.test);

12

package.json
{
"name": "complexity-report",
"version": "0.2.7",
"version": "0.2.8",
"author": "Phil Booth <pmbooth@gmail.com>",

@@ -29,10 +29,10 @@ "description": "A tool for reporting code complexity metrics in JavaScript projects.",

"check-types": "0.2.x",
"esprima": "0.9.x",
"esprima": "1.0.x",
"commander": "1.0.x"
},
"devDependencies": {
"jake": "0.3.x",
"jshint": "0.7.x",
"mocha": "1.2.x",
"chai": "1.1.x"
"jake": "0.5.x",
"jshint": "0.9.x",
"mocha": "1.6.x",
"chai": "1.3.x"
},

@@ -39,0 +39,0 @@ "license": "MIT",

@@ -36,8 +36,8 @@ # complexityReport.js

defaults to `stdout`.
* `-f <format`: Specify an output format for the report,
* `-f <format>`: Specify an output format for the report,
defaults to `plain`.
* `-t <threshold>`: Specify the per-function complexity threshold
(beyond which, will cause the process to fail when exiting).
* `-l`: Disregads operator `||` as a source of cyclomatic complexity.
* `-s`: Disegards `switch` statements as a source of cyclomatic complexity.
(beyond which, the process will fail when exiting).
* `-l`: Disregards operator `||` as a source of cyclomatic complexity.
* `-s`: Disregards `switch` statements as a source of cyclomatic complexity.
* `-i`: Treats `for`...`in` loops as a source of cyclomatic complexity.

@@ -44,0 +44,0 @@ * `-c`: Treats `catch` clauses as a source of cyclomatic complexity.

@@ -10,3 +10,3 @@ /**

var check, esprima, syntaxHandlers, settings, report;
var check, esprima, syntaxDefinitions, report, operators, operands;

@@ -18,24 +18,2 @@ exports.run = run;

syntaxHandlers = {
IfStatement: processCondition,
ConditionalExpression: processCondition,
BlockStatement: processBlock,
LogicalExpression: processLogical,
SwitchStatement: processSwitch,
SwitchCase: processCase,
ForStatement: processLoop,
ForInStatement: processForIn,
WhileStatement: processLoop,
DoWhileStatement: processLoop,
TryStatement: processTry,
CatchClause: processCatch,
FunctionDeclaration: processFunction,
FunctionExpression: processFunction,
VariableDeclaration: processVariables,
VariableDeclarator: processVariable,
ReturnStatement: processReturn,
ExpressionStatement: processExpression,
CallExpression: processCall
};
/**

@@ -52,3 +30,3 @@ * Public function `run`.

function run (source, options) {
var ast;
var settings, ast;

@@ -63,3 +41,6 @@ check.verifyUnemptyString(source, 'Invalid source');

syntaxDefinitions = getSyntaxDefinitions(settings);
report = createReport();
operators = {};
operands = {};

@@ -70,3 +51,3 @@ ast = esprima.parse(source, {

processTree(ast.body);
processTree(ast.body, undefined, undefined, {}, {});

@@ -85,2 +66,163 @@ return report;

function getSyntaxDefinitions (settings) {
// TODO: Refactor to traits.
return {
Literal: {
operands: [ {
name: function (node) {
if (check.isString(node.value)) {
// Avoid conflicts between string literals and identifiers.
return '"' + node.value + '"';
}
return node.value;
}
} ]
},
Identifier: {
operands: [ { name: function (node) { return node.name; } } ]
},
BlockStatement: {
children: [ 'body' ]
},
ObjectExpression: {
operands: [ { name: safeName } ],
children: [ 'properties' ]
},
Property: {
operators: [ { name: ':' } ],
children: [ 'key', 'value' ],
getAssignedName: function (node) { return safeName(node.key); }
},
ThisExpression: {
operands: [ { name: 'this' } ]
},
MemberExpression: {
operators: [ { name: function (node) { return '.'; } } ],
children: [ 'object', 'property' ]
},
CallExpression: getFunctionCallSyntaxDefinition('()'),
NewExpression: getFunctionCallSyntaxDefinition('new'),
ExpressionStatement: {
children: [ 'expression' ]
},
VariableDeclaration: {
operators: [ { name: function (node) { return node.kind; } } ],
children: [ 'declarations' ]
},
VariableDeclarator: {
operators: [ { name: '=', optional: function (node) { return !!node.init; } } ],
children: [ 'id', 'init' ],
getAssignedName: function (node) { return safeName(node.id); }
},
AssignmentExpression: {
operators: [ { name: function (node) { return node.operator; } } ],
children: [ 'left', 'right' ],
getAssignedName: function (node) {
if (node.left.type === 'MemberExpression') {
return safeName(node.left.object) + '.' + node.left.property.name;
}
return safeName(node.left.id);
}
},
BinaryExpression: {
operators: [ { name: function (node) { return node.operator; } } ],
children: [ 'left', 'right' ]
},
LogicalExpression: {
complexity: function (node) { return settings.logicalor && node.operator === '||'; },
operators: [ { name: function (node) { return node.operator; } } ],
children: [ 'left', 'right' ]
},
IfStatement: {
complexity: true,
operators: [
{ name: 'if' },
{ name: 'else', optional: function (node) { return !!node.alternate; } }
],
children: [ 'test', 'consequent', 'alternate' ]
},
ConditionalExpression: {
complexity: true,
operators: [ { name: ':?' } ],
children: [ 'test', 'consequent', 'alternate' ]
},
SwitchStatement: {
operators: [ { name: 'switch' } ],
children: [ 'discriminant', 'cases' ]
},
SwitchCase: {
complexity: function (node) { return settings.switchcase && node.test; },
operators: [ { name: function (node) { return node.test ? 'case' : 'default'; } } ],
children: [ 'test', 'consequent' ]
},
BreakStatement: {
operators: [ { name: 'break' } ]
},
ForStatement: getLoopSyntaxDefinition('for'),
ForInStatement: {
complexity: function (node) { return settings.forin; },
operators: [ { name: 'forin' } ],
children: [ 'left', 'right', 'body' ]
},
WhileStatement: getLoopSyntaxDefinition('while'),
DoWhileStatement: getLoopSyntaxDefinition('dowhile'),
FunctionDeclaration: getFunctionSyntaxDefinition(),
FunctionExpression: getFunctionSyntaxDefinition(),
ReturnStatement: {
operators: [ { name: 'return' } ],
children: [ 'argument' ]
},
TryStatement: {
children: [ 'block', 'handlers' ]
},
CatchClause: {
complexity: function (node) { return settings.trycatch; },
operators: [ { name: 'catch' } ],
children: [ 'param', 'body' ]
},
ThrowStatement: {
operators: [ { name: 'throw' } ],
children: [ 'argument' ]
}
};
}
function safeName (object, defaultName) {
if (check.isObject(object) && check.isUnemptyString(object.name)) {
return object.name;
}
if (check.isUnemptyString(defaultName)) {
return defaultName;
}
return '<anonymous>';
}
function getFunctionCallSyntaxDefinition (type) {
return {
operators: [ { name: type } ],
children: [ 'arguments', 'callee' ]
};
}
function getLoopSyntaxDefinition (type) {
return {
complexity: function (node) { return !!node.test; },
operators: [ { name: type } ],
children: [ 'init', 'test', 'update', 'body' ]
};
}
function getFunctionSyntaxDefinition () {
return {
operators: [ { name: 'function' } ],
operands: [ { name: function (node) { return safeName(node.id); } } ],
children: [ 'params', 'body' ],
isFunction: true
};
}
function createReport () {

@@ -98,3 +240,4 @@ return {

complexity: {
cyclomatic: 1
cyclomatic: 1,
halstead: createInitialHalsteadState()
}

@@ -104,3 +247,17 @@ };

function processTree (tree, currentReport) {
function createInitialHalsteadState () {
return {
operators: createInitialHalsteadItemState(),
operands: createInitialHalsteadItemState()
};
}
function createInitialHalsteadItemState () {
return {
distinct: 0,
total: 0
};
}
function processTree (tree, assignedName, currentReport, currentOperators, currentOperands) {
var i;

@@ -111,17 +268,38 @@

for (i = 0; i < tree.length; i += 1) {
processNode(tree[i], currentReport);
processNode(tree[i], assignedName, currentReport, currentOperators, currentOperands);
}
}
function processNode (node, currentReport) {
if (check.isObject(node) && check.isFunction(syntaxHandlers[node.type])) {
syntaxHandlers[node.type](node, currentReport);
function processNode (node, assignedName, currentReport, currentOperators, currentOperands) {
var def;
if (check.isObject(node)) {
def = syntaxDefinitions[node.type];
if (check.isObject(syntaxDefinitions[node.type])) {
processComplexity(node, currentReport);
processOperators(node, currentOperators, currentReport);
processOperands(node, currentOperands, currentReport);
if (def.isFunction) {
processChildrenInNewScope(node, assignedName);
} else {
processChildren(node, currentReport, currentOperators, currentOperands);
}
}
}
}
function processCondition (condition, currentReport) {
incrementComplexity(currentReport);
function processComplexity (node, currentReport) {
var def = syntaxDefinitions[node.type];
processNode(condition.consequent, currentReport);
processNode(condition.alternate, currentReport);
if (
def.complexity === true ||
(
check.isFunction(def.complexity) &&
def.complexity(node)
)
) {
incrementComplexity(currentReport);
}
}

@@ -137,92 +315,81 @@

function processBlock (block, currentReport) {
processTree(block.body, currentReport);
function processOperators (node, currentOperators, currentReport) {
processHalsteadMetric(node, 'operators', operators, currentOperators, currentReport);
}
function processLogical (logical, currentReport) {
if (settings.logicalor && logical.operator === '||') {
processCondition({
consequent: logical.left,
alternate: logical.right
}, currentReport);
}
function processOperands (node, currentOperands, currentReport) {
processHalsteadMetric(node, 'operands', operands, currentOperands, currentReport);
}
function processSwitch (s, currentReport) {
processTree(s.cases, currentReport);
}
function processHalsteadMetric (node, metric, items, currentItems, currentReport) {
var def = syntaxDefinitions[node.type], i, name;
function processCase (c, currentReport) {
if (settings.switchcase && c.test) {
processCondition({
consequent: {
type: 'BlockStatement',
body: c.consequent
if (check.isArray(def[metric])) {
for (i = 0; i < def[metric].length; i += 1) {
if (check.isFunction(def[metric][i].name)) {
name = def[metric][i].name(node);
} else {
name = def[metric][i].name;
}
}, currentReport);
} else {
processTree(c.consequent, currentReport);
}
}
function processLoop (loop, currentReport) {
if (loop.test) {
processCondition({
consequent: loop.body
}, currentReport);
if (
check.isFunction(def[metric][i].optional) === false ||
def[metric][i].optional(node) === true
) {
halsteadItemEncountered(name, currentItems, items, currentReport, metric);
}
}
}
}
function processForIn (forIn, currentReport) {
if (settings.forin) {
incrementComplexity(currentReport);
}
processNode(forIn.body, currentReport);
function halsteadItemEncountered (name, currentItems, items, currentReport, metric) {
incrementHalsteadItems(name, currentItems, currentReport, metric);
incrementHalsteadItems(name, items, report.aggregate, metric);
}
function processTry (t, currentReport) {
processNode(t.block, currentReport);
processTree(t.handlers, currentReport);
function incrementHalsteadItems (name, currentItems, baseReport, metric) {
incrementDistinctHalsteadItems(name, currentItems, baseReport, metric);
incrementTotalHalsteadItems(baseReport, metric);
}
function processCatch (c, currentReport) {
if (settings.trycatch) {
incrementComplexity(currentReport);
function incrementDistinctHalsteadItems (name, currentItems, baseReport, metric) {
if (Object.prototype.hasOwnProperty(name)) {
// Avoid clashes with built-in property names.
incrementDistinctHalsteadItems('_' + name, currentItems, baseReport, metric);
} else if (!currentItems[name]) {
incrementHalsteadMetric(baseReport, metric, 'distinct');
currentItems[name] = true;
}
}
processNode(c.body, currentReport);
function incrementTotalHalsteadItems (baseReport, metric) {
incrementHalsteadMetric(baseReport, metric, 'total');
}
function processFunction (fn, currentReport) {
var name;
if (check.isObject(fn.id)) {
name = fn.id.name;
function incrementHalsteadMetric (baseReport, metric, type) {
if (baseReport) {
baseReport.complexity.halstead[metric][type] += 1;
}
processFunctionBody(name, fn.body);
}
function processFunctionBody (name, body) {
var currentReport = createFunctionReport(name, body.loc);
function processChildrenInNewScope (node, assignedName) {
var newReport = createFunctionReport(safeName(node.id, assignedName), node.loc);
report.functions.push(currentReport);
report.functions.push(newReport);
processNode(body, currentReport);
processChildren(node, newReport, {}, {});
}
function processVariables (variables, currentReport) {
processTree(variables.declarations, currentReport);
}
function processChildren (node, currentReport, currentOperators, currentOperands) {
var def = syntaxDefinitions[node.type], i;
function processVariable (variable, currentReport) {
if (variable.init) {
if (
variable.init.type === 'FunctionExpression' &&
check.isObject(variable.init.id) === false
) {
processFunctionBody(variable.id.name, variable.init.body);
} else {
processNode(variable.init, currentReport);
if (check.isArray(def.children)) {
for (i = 0; i < def.children.length; i += 1) {
processChild(
node[def.children[i]],
check.isFunction(def.getAssignedName) ? def.getAssignedName(node) : '',
currentReport,
currentOperators,
currentOperands
);
}

@@ -232,15 +399,7 @@ }

function processReturn (rtn, currentReport) {
processNode(rtn.argument, currentReport);
function processChild (child, assignedName, currentReport, currentOperators, currentOperands) {
var fn = check.isArray(child) ? processTree : processNode;
fn(child, assignedName, currentReport, currentOperators, currentOperands);
}
function processExpression (expression, currentReport) {
processNode(expression.expression, currentReport);
}
function processCall (call, currentReport) {
processTree(call['arguments'], currentReport);
processNode(call.callee, currentReport);
}
}());

Sorry, the diff of this file is too big to display

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