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

escomplex

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

escomplex - npm Package Compare versions

Comparing version 0.1.3 to 0.2.0

13

package.json
{
"name": "escomplex",
"version": "0.1.3",
"description": "Software complexity analysis of Mozilla-format abstract syntax trees.",
"version": "0.2.0",
"description": "Software complexity analysis of JavaScript-family abstract syntax trees.",
"homepage": "https://github.com/philbooth/escomplex",

@@ -30,3 +30,4 @@ "bugs": "https://github.com/philbooth/escomplex/issues",

"dependencies": {
"check-types": "0.7.x"
"check-types": "0.7.x",
"matrix-utilities": "1.2.x"
},

@@ -37,3 +38,3 @@ "devDependencies": {

"chai": "1.8.x",
"escomplex-ast-moz": "0.1.0",
"escomplex-ast-moz": "0.1.x",
"esprima": "1.0.x",

@@ -44,5 +45,7 @@ "coffee-script-redux": "2.0.x"

"lint": "./node_modules/jshint/bin/jshint src --config config/jshint.json",
"test": "./node_modules/mocha/bin/mocha --ui tdd --reporter spec --colors test"
"test": "npm run test-module && npm run test-project",
"test-module": "./node_modules/mocha/bin/mocha --ui tdd --reporter spec --colors test/module",
"test-project": "./node_modules/mocha/bin/mocha --ui tdd --reporter spec --colors test/project"
}
}
# escomplex
THIS PROJECT IS (kind of) BRAND NEW AND NOT SAFE TO USE YET! :)
[![Build status][ci-image]][ci-status]

@@ -9,11 +7,38 @@

of JavaScript-family abstract syntax trees.
The back-end for [complexity-report].
* [Metrics][#metrics]
* [Abstract syntax trees][#abstract-syntax-trees]
* [Installation][#installation]
* [Usage][#usage]
* [Related projects][#related-projects]
* [Development][#development]
* [License][#license]
* [Abstract syntax trees](#abstract-syntax-trees)
* [Syntax tree walkers](#syntax-tree-walkers)
* [Metrics](#metrics)
* [Links to research](#links-to-research)
* [Installation](#installation)
* [Usage](#usage)
* [Related projects](#related-projects)
* [Development](#development)
* [License](#license)
## Abstract syntax trees
This library deliberately excludes
logic for parsing source code
and for navigating parse trees.
Both the syntax tree
and a matching [syntax tree walker](#syntax-tree-walkers)
are inputs to escomplex,
meaning it is not tied
to any particular language,
parser
or data format.
## Syntax tree walkers
* [escomplex-ast-moz]:
Walks syntax trees
that conform to the format
defined in Mozilla's [Parser API][api].
This format is returned
by [Esprima]
and [Acorn],
two popular JavaScript parsers.
## Metrics

@@ -23,18 +48,90 @@

* lines of code;
* number of parameters;
* cyclomatic complexity;
* Halstead metrics;
* maintainability index;
* dependencies (CommonJS and AMD);
* first-order density.
* Lines of code:
Both physical (the number of lines in a module or function)
and logical (a count of the imperative statements).
A crude measure.
* Number of parameters:
Analysed statically
from the function signature,
so no accounting is made
for functions that rely on the `arguments` object.
Lower is better.
* Cyclomatic complexity:
Defined by Thomas J. McCabe in 1976,
this is a count of the number of cycles
in the program flow control graph.
Effectively the number of distinct paths
through a block of code.
Lower is better.
* Cyclomatic complexity 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.
* Halstead metrics:
Defined by Maurice Halstead in 1977,
these metrics are calculated
from the numbers of operators
and operands in each function.
Lower is better.
* Maintainability index:
Defined by Paul Oman & Jack Hagemeister in 1991,
this is a logarithmic scale
from negative infinity to 171,
calculated from
the logical lines of code,
the cyclomatix complexity
and the Halstead effort.
Higher is better.
* Dependencies:
A count of the calls
to CommonJS and AMD `require`.
Analysed statically
from the function signature,
so no accounting is made
for dynamic calls
where a variable or function is
obscuring the nature of the dependency.
Lower is better.
* First-order density:
The percentage of all possible internal dependencies
that are actually realised in the project.
Lower is better.
* Change cost:
The percentage of modules affected,
on average,
when one module in the project
is changed.
Lower is better.
* Core size:
the percentage of modules
that are both widely depended on
and themselves depend on other modules.
Lower is better.
## Abstract syntax trees
It is important to note
that none of these metrics
can compete with the insight
of a competent developer.
At best,
they are an automatable warning system,
which can help to identify areas of code
that warrant closer inspection.
* [Esprima][esprima];
* [Acorn][acorn];
* [CoffeeScriptRedux][coffee];
* [LiveScript][live];
## Links to research
## Abstract syntax tree walkers
* [A Complexity Measure][mccabe],
by Thomas J McCabe.
* [Cyclomatic Complexity Density and Software Maintenance Productivity][gillkemerer],
by Geoffrey K. Gill and Chris F. Kemerer.
* [Resolving the Mysteries of the Halstead Measures][horstzuse],
by Horst Zuse.
* [Exploring the Structure of Complex Software Designs: An Empirical Study of Open Source and Proprietary Code][dsm],
by Alan MacCormack, John Rusnak and Carliss Baldwin.
* [The Impact of Software Design Structure on Product Maintenance Costs and Measurement of Economic Benefits of Product Redesign][akaikine],
by Andrei Akaikine.
* [A Systematic Review of Software Maintainability Prediction and Metrics][review],
by Mehwish Riaz, Emilia Mendes and Ewan Tempero.

@@ -68,3 +165,3 @@ ## Installation

```javascript
var result = escomplex.analyse(ast, options);
var result = escomplex.analyse(ast, walker, options);
```

@@ -75,8 +172,21 @@

an abstract syntax tree
as defined by Mozilla's Parser API
or an array of said syntax trees.
or an array of syntax trees.
If it is an array,
each tree should include
an extra property, `path`,
that is either a relative
or full path to equivalent module
on disk.
As well as identifying
each of the result objects,
that path is also used
during dependency analysis.
The second argument, `options`,
The second argument, `walker`,
must be a [syntax tree walker](#syntax-tree-walkers).
The third argument, `options`,
is an optional object
containing properties that modify some of the complexity calculations:
containing properties that modify
some of the complexity calculations:

@@ -107,17 +217,127 @@ * `options.logicalor`:

the result will be a report object
detailing the complexity of that syntax tree.
If `ast` is an array,
the result will be an array of complexity reports.
containing the following properties:
TODO: Properties on the returned object
* `report.maintainability`:
The maintainability index for the module.
* `report.dependencies`:
The array of CommonJS/AMD dependencies for the module.
* `report.aggregate.sloc.physical`:
Physical lines of code for the module.
Will be `undefined`
if the syntax tree
is not annotated
with line number data.
* `report.aggregate.sloc.logical`:
Logical lines of code for the module.
* `report.aggregate.params`:
Parameter count for the module.
* `report.aggregate.cyclomatic`:
Cyclomatic complexity for the module.
* `report.aggregate.cyclomaticDensity`:
Cyclomatic complexity density for the module.
* `report.aggregate.halstead.vocabulary`:
Halstead vocabulary size for the module.
* `report.aggregate.halstead.difficulty`:
Halstead difficulty for the module.
* `report.aggregate.halstead.volume`:
Halstead volume for the module.
* `report.aggregate.halstead.effort`:
Halstead effort for the module.
* `report.aggregate.halstead.bugs`:
Halstead bugs for the module.
* `report.aggregate.halstead.time`:
Halstead time for the module.
* `report.functions[n].name`:
Function name.
* `report.functions[n].line`:
Line number that the function starts on.
Will be `undefined`
if the syntax tree
is not annotated
with line number data.
* `report.functions[n].sloc.physical`:
Physical lines of code for the function.
Will be `undefined`
if the syntax tree
is not annotated
with line number data.
* `report.functions[n].sloc.logical`:
Logical lines of code for the function.
* `report.functions[n].params`:
Parameter count for the function.
* `report.functions[n].cyclomatic`:
Cyclomatic complexity for the function.
* `report.functions[n].cyclomaticDensity`:
Cyclomatic complexity density for the function.
* `report.functions[n].halstead.vocabulary`:
Halstead vocabulary size for the function.
* `report.functions[n].halstead.difficulty`:
Halstead difficulty for the function.
* `report.functions[n].halstead.volume`:
Halstead volume for the function.
* `report.functions[n].halstead.effort`:
Halstead effort for the function.
* `report.functions[n].halstead.bugs`:
Halstead bugs for the function.
* `report.functions[n].halstead.time`:
Halstead time for the function.
## Related projects
If an array of syntax trees
is passed in the `ast` argument,
the result will be an object
containing the following properties:
TODO
* `result.reports`:
An array of report objects,
each one in the same format described above
but with an extra property `path`
that matches the `path` property
from its corresponding syntax tree.
This `path` property is required
because the reports array gets sorted
during dependency analysis.
* `result.adjacencyMatrix`:
The adjacency
design structure matrix (DSM)
for the project.
This is a two-dimensional array,
each dimension with the same order and length
as the `reports` array.
Each row and column
represents its equivalent
indexed module
from the `reports` array,
with values along the horizontal
being `1`
when that module
directly depends on another
and values along the vertical
being `1`
when that module
is directly depended on by another.
All other values are `0`.
* `result.firstOrderDensity`:
The first-order density for the project.
* `result.visibilityMatrix`:
The visibility DSM for the project.
Like the adjacency matrix,
but expanded to incorporate
indirect dependencies.
* `result.changeCost`:
The change cost for the project.
* `result.coreSize`:
The core size for the project.
## Development
TODO
Source code is in `/src`.
Unit tests are in `/test`.
You can run them with `npm test`.
You can run the linter with `npm run lint`.
Make sure you've installed
all the dependencies
with `npm install`
first.
## What license is it released under?
## License

@@ -128,15 +348,16 @@ [MIT][license]

[ci-status]: http://travis-ci.org/#!/philbooth/escomplex
[complexity-report]: https://github.com/philbooth/complexity-report
[escomplex-ast-moz]: https://github.com/philbooth/escomplex-ast-moz
[api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
[esprima]: http://esprima.org/
[acorn]: http://marijnhaverbeke.nl/acorn
[coffee]: https://github.com/michaelficarra/CoffeeScriptRedux
[live]: https://github.com/gkz/LiveScript
[escomplex-ast-csr]: https://github.com/philbooth/escomplex-ast-csr
[coffeescriptredux]: https://github.com/michaelficarra/CoffeeScriptRedux
[mccabe]: http://www.literateprogramming.com/mccabe.pdf
[gillkemerer]: http://www.pitt.edu/~ckemerer/CK%20research%20papers/CyclomaticComplexityDensity_GillKemerer91.pdf
[horstzuse]: http://horst-zuse.homepage.t-online.de/z-halstead-final-05-1.pdf
[dsm]: http://www.people.hbs.edu/cbaldwin/DR2/MRBDesignStructure17thSep1.pdf
[akaikine]: http://sdm.mit.edu/docs/akaikine_thesis.pdf
[review]: http://www.rose-hulman.edu/Users/faculty/young/CS-Classes/csse575/Resources/maintainabilityMeas05314233.pdf
[license]: https://github.com/philbooth/escomplex/blob/master/COPYING
[msvariant]: http://blogs.msdn.com/b/codeanalysis/archive/2007/11/20/maintainability-index-range-and-meaning.aspx
[jarrod]: http://jarrodoverson.com/blog/about
[plato]: https://github.com/jsoverson/plato
[grunt-complexity]: https://github.com/vigetlabs/grunt-complexity
[bob]: https://github.com/cliffano/bob
[cardio]: https://github.com/auchenberg/cardio
[brackets-crjs]: https://github.com/sahlas/brackets-crjs
[node]: http://nodejs.org/

@@ -143,0 +364,0 @@ [npm]: https://npmjs.org/

@@ -39,3 +39,3 @@ /*globals exports, require */

processLloc(node, syntax, currentReport);
processComplexity(node, syntax, currentReport);
processCyclomatic(node, syntax, currentReport);
processOperators(node, syntax, currentReport);

@@ -55,3 +55,3 @@ processOperands(node, syntax, currentReport);

report.functions.push(currentReport);
report.aggregate.complexity.params += parameterCount;
report.aggregate.params += parameterCount;

@@ -65,3 +65,3 @@ scopeStack.push(currentReport);

if (scopeStack.length > 0) {
currentReport = scopeStack[scopeStack.length - 1]
currentReport = scopeStack[scopeStack.length - 1];
} else {

@@ -94,10 +94,8 @@ currentReport = undefined;

name: name,
complexity: {
sloc: {
logical: 0
},
cyclomatic: 1,
halstead: createInitialHalsteadState(),
params: params
}
sloc: {
logical: 0
},
cyclomatic: 1,
halstead: createInitialHalsteadState(),
params: params
};

@@ -107,3 +105,3 @@

result.line = lines.start.line;
result.complexity.sloc.physical = lines.end.line - lines.start.line + 1;
result.sloc.physical = lines.end.line - lines.start.line + 1;
}

@@ -144,18 +142,18 @@

function incrementLogicalSloc (currentReport, amount) {
report.aggregate.complexity.sloc.logical += amount;
report.aggregate.sloc.logical += amount;
if (currentReport) {
currentReport.complexity.sloc.logical += amount;
currentReport.sloc.logical += amount;
}
}
function processComplexity (node, syntax, currentReport) {
incrementCounter(node, syntax, 'complexity', incrementComplexity, currentReport);
function processCyclomatic (node, syntax, currentReport) {
incrementCounter(node, syntax, 'cyclomatic', incrementCyclomatic, currentReport);
}
function incrementComplexity (currentReport, amount) {
report.aggregate.complexity.cyclomatic += amount;
function incrementCyclomatic (currentReport, amount) {
report.aggregate.cyclomatic += amount;
if (currentReport) {
currentReport.complexity.cyclomatic += amount;
currentReport.cyclomatic += amount;
}

@@ -214,7 +212,7 @@ }

function isHalsteadMetricDistinct (baseReport, metric, identifier) {
return baseReport.complexity.halstead[metric].identifiers.indexOf(identifier) === -1;
return baseReport.halstead[metric].identifiers.indexOf(identifier) === -1;
}
function recordDistinctHalsteadMetric (baseReport, metric, identifier) {
baseReport.complexity.halstead[metric].identifiers.push(identifier);
baseReport.halstead[metric].identifiers.push(identifier);
}

@@ -224,3 +222,3 @@

if (baseReport) {
baseReport.complexity.halstead[metric][type] += 1;
baseReport.halstead[metric][type] += 1;
}

@@ -255,3 +253,3 @@ }

loc: 0,
complexity: 1,
cyclomatic: 1,
effort: 2,

@@ -262,4 +260,5 @@ params: 3

for (i = 0; i < report.functions.length; i += 1) {
data = report.functions[i].complexity;
data = report.functions[i];
calculateCyclomaticDensity(data);
calculateHalsteadMetrics(data.halstead);

@@ -269,6 +268,7 @@ sumMaintainabilityMetrics(sums, indices, data);

calculateHalsteadMetrics(report.aggregate.complexity.halstead);
calculateCyclomaticDensity(report.aggregate);
calculateHalsteadMetrics(report.aggregate.halstead);
if (i === 0) {
// Sane handling of modules that contain no functions.
sumMaintainabilityMetrics(sums, indices, report.aggregate.complexity);
sumMaintainabilityMetrics(sums, indices, report.aggregate);
i = 1;

@@ -281,3 +281,3 @@ }

averages[indices.effort],
averages[indices.complexity],
averages[indices.cyclomatic],
averages[indices.loc],

@@ -290,2 +290,6 @@ settings

function calculateCyclomaticDensity (data) {
data.cyclomaticDensity = (data.cyclomatic / data.sloc.logical) * 100;
}
function calculateHalsteadMetrics (data) {

@@ -319,3 +323,3 @@ data.length = data.operators.total + data.operands.total;

sums[indices.loc] += data.sloc.logical;
sums[indices.complexity] += data.cyclomatic;
sums[indices.cyclomatic] += data.cyclomatic;
sums[indices.effort] += data.halstead.effort;

@@ -325,4 +329,4 @@ sums[indices.params] += data.params;

function calculateMaintainabilityIndex (averageEffort, averageComplexity, averageLoc, settings) {
if (averageComplexity === 0) {
function calculateMaintainabilityIndex (averageEffort, averageCyclomatic, averageLoc, settings) {
if (averageCyclomatic === 0) {
throw new Error('Encountered function with cyclomatic complexity zero!');

@@ -337,3 +341,3 @@ }

(3.42 * Math.log(averageEffort)) -
(0.23 * Math.log(averageComplexity)) -
(0.23 * Math.log(averageCyclomatic)) -
(16.2 * Math.log(averageLoc));

@@ -343,5 +347,5 @@ }

if (settings.newmi) {
report.maintainability = Math.max(0, (report.maintainability*100)/171);
report.maintainability = Math.max(0, (report.maintainability * 100) / 171);
}
}

@@ -5,3 +5,3 @@ /*globals exports, require */

var path, check, moduleAnalyser;
var path, check, matrix, moduleAnalyser;

@@ -12,2 +12,3 @@ exports.analyse = analyse;

check = require('check-types');
matrix = require('matrix-utilities');
moduleAnalyser = require('./module');

@@ -18,3 +19,3 @@

var reports;
var reports, result;

@@ -34,19 +35,23 @@ check.verifyArray(modules, 'Invalid modules');

return {
result = {
reports: reports,
matrices: [ createAdjacencyMatrix(reports) ]
};
createAdjacencyMatrix(result);
createVisibilityMatrix(result);
setCoreSize(result);
return result;
}
// TODO: Move this dependency stuff into a separate module
function createAdjacencyMatrix (reports) {
var matrix = new Array(reports.length), density = 0;
function createAdjacencyMatrix (result) {
var adjacencyMatrix = new Array(result.reports.length), density = 0;
reports.sort(function (lhs, rhs) {
result.reports.sort(function (lhs, rhs) {
return comparePaths(lhs.path, rhs.path);
}).forEach(function (ignore, x) {
matrix[x] = new Array(reports.length);
reports.forEach(function (ignore, y) {
matrix[x][y] = getAdjacencyMatrixValue(reports, x, y);
if (matrix[x][y] === 1) {
adjacencyMatrix[x] = new Array(result.reports.length);
result.reports.forEach(function (ignore, y) {
adjacencyMatrix[x][y] = getAdjacencyMatrixValue(result.reports, x, y);
if (adjacencyMatrix[x][y] === 1) {
density += 1;

@@ -57,6 +62,4 @@ }

return {
matrix: matrix,
density: density
};
result.adjacencyMatrix = adjacencyMatrix;
result.firstOrderDensity = percentifyDensity(density, adjacencyMatrix);
}

@@ -80,3 +83,3 @@

if (x === y) {
return null;
return 0;
}

@@ -138,1 +141,104 @@

function percentifyDensity (density, matrix) {
return percentify(density, matrix.length * matrix.length);
}
function percentify (value, limit) {
if (limit === 0) {
return 0;
}
return (value / limit) * 100;
}
function createVisibilityMatrix (result) {
var product = result.adjacencyMatrix, sum = result.adjacencyMatrix, changeCost = 0, visibilityMatrix;
result.adjacencyMatrix.forEach(function () {
product = matrix.multiply(product, result.adjacencyMatrix);
sum = matrix.add(product, sum);
});
result.adjacencyMatrix.forEach(function (ignore, index) {
sum[index][index] = 1;
});
visibilityMatrix = sum.map(function (row, rowIndex) {
return row.map(function (value, columnIndex) {
if (value > 0) {
changeCost += 1;
if (columnIndex !== rowIndex) {
return 1;
}
}
return 0;
});
});
result.visibilityMatrix = visibilityMatrix;
result.changeCost = percentifyDensity(changeCost, visibilityMatrix);
}
function setCoreSize (result) {
var fanIn, fanOut, boundaries, coreSize;
if (result.firstOrderDensity === 0) {
result.coreSize = 0;
return;
}
fanIn = new Array(result.visibilityMatrix.length);
fanOut = new Array(result.visibilityMatrix.length);
boundaries = {};
coreSize = 0;
result.visibilityMatrix.forEach(function (row, rowIndex) {
fanIn[rowIndex] = row.reduce(function (sum, value, valueIndex) {
if (rowIndex === 0) {
fanOut[valueIndex] = value;
} else {
fanOut[valueIndex] += value;
}
return sum + value;
}, 0);
});
// Boundary values can also be chosen by looking for discontinuity in the
// distribution of values, but I've chosen the median to keep it simple.
boundaries.fanIn = getMedian(fanIn.slice());
boundaries.fanOut = getMedian(fanOut.slice());
result.visibilityMatrix.forEach(function (ignore, index) {
if (fanIn[index] >= boundaries.fanIn && fanOut[index] >= boundaries.fanOut) {
coreSize += 1;
}
});
result.coreSize = percentify(coreSize, result.visibilityMatrix.length);
}
function getMedian (values) {
values.sort(compareNumbers);
if (check.isOddNumber(values.length)) {
return values[(values.length - 1) / 2];
}
return (values[(values.length - 2) / 2] + values[values.length / 2]) / 2;
}
function compareNumbers (lhs, rhs) {
if (lhs < rhs) {
return -1;
}
if (lhs > rhs) {
return 1;
}
return 0;
}

@@ -84,20 +84,20 @@ /*globals require, suite, test, setup, teardown */

test('matrices array exists', function () {
assert.isArray(result.matrices);
test('adjacency matrix exists', function () {
assert.isArray(result.adjacencyMatrix);
});
test('matrices array has one item', function () {
assert.lengthOf(result.matrices, 1);
test('adjacency matrix has zero length', function () {
assert.lengthOf(result.adjacencyMatrix, 0);
});
test('adjacency matrix exists', function () {
assert.isArray(result.matrices[0].matrix);
test('first-order density is correct', function () {
assert.strictEqual(result.firstOrderDensity, 0);
});
test('adjacency matrix has zero length', function () {
assert.lengthOf(result.matrices[0].matrix, 0);
test('change cost is correct', function () {
assert.strictEqual(result.changeCost, 0);
});
test('first-order density is correct', function () {
assert.strictEqual(result.matrices[0].density, 0);
test('core size is correct', function () {
assert.strictEqual(result.coreSize, 0);
});

@@ -125,13 +125,17 @@ });

test('first report aggregate has correct physical lines of code', function () {
assert.strictEqual(result.reports[0].aggregate.complexity.sloc.physical, 1);
assert.strictEqual(result.reports[0].aggregate.sloc.physical, 1);
});
test('first report aggregate has correct logical lines of code', function () {
assert.strictEqual(result.reports[0].aggregate.complexity.sloc.logical, 4);
assert.strictEqual(result.reports[0].aggregate.sloc.logical, 4);
});
test('first report aggregate has correct cyclomatic complexity', function () {
assert.strictEqual(result.reports[0].aggregate.complexity.cyclomatic, 2);
assert.strictEqual(result.reports[0].aggregate.cyclomatic, 2);
});
test('first report aggregate has correct cyclomatic complexity density', function () {
assert.strictEqual(result.reports[0].aggregate.cyclomaticDensity, 50);
});
test('first report functions is empty', function () {

@@ -142,15 +146,15 @@ assert.lengthOf(result.reports[0].functions, 0);

test('first report aggregate has correct Halstead total operators', function () {
assert.strictEqual(result.reports[0].aggregate.complexity.halstead.operators.total, 2);
assert.strictEqual(result.reports[0].aggregate.halstead.operators.total, 2);
});
test('first report aggregate has correct Halstead distinct operators', function () {
assert.strictEqual(result.reports[0].aggregate.complexity.halstead.operators.distinct, 2);
assert.strictEqual(result.reports[0].aggregate.halstead.operators.distinct, 2);
});
test('first report aggregate has correct Halstead total operands', function () {
assert.strictEqual(result.reports[0].aggregate.complexity.halstead.operands.total, 3);
assert.strictEqual(result.reports[0].aggregate.halstead.operands.total, 3);
});
test('first report aggregate has correct Halstead distinct operands', function () {
assert.strictEqual(result.reports[0].aggregate.complexity.halstead.operands.distinct, 3);
assert.strictEqual(result.reports[0].aggregate.halstead.operands.distinct, 3);
});

@@ -160,4 +164,4 @@

assert.lengthOf(
result.reports[0].aggregate.complexity.halstead.operators.identifiers,
result.reports[0].aggregate.complexity.halstead.operators.distinct
result.reports[0].aggregate.halstead.operators.identifiers,
result.reports[0].aggregate.halstead.operators.distinct
);

@@ -168,4 +172,4 @@ });

assert.lengthOf(
result.reports[0].aggregate.complexity.halstead.operands.identifiers,
result.reports[0].aggregate.complexity.halstead.operands.distinct
result.reports[0].aggregate.halstead.operands.identifiers,
result.reports[0].aggregate.halstead.operands.distinct
);

@@ -175,27 +179,27 @@ });

test('first report aggregate has correct Halstead length', function () {
assert.strictEqual(result.reports[0].aggregate.complexity.halstead.length, 5);
assert.strictEqual(result.reports[0].aggregate.halstead.length, 5);
});
test('first report aggregate has correct Halstead vocabulary', function () {
assert.strictEqual(result.reports[0].aggregate.complexity.halstead.vocabulary, 5);
assert.strictEqual(result.reports[0].aggregate.halstead.vocabulary, 5);
});
test('first report aggregate has correct Halstead difficulty', function () {
assert.strictEqual(result.reports[0].aggregate.complexity.halstead.difficulty, 1);
assert.strictEqual(result.reports[0].aggregate.halstead.difficulty, 1);
});
test('first report aggregate has correct Halstead volume', function () {
assert.strictEqual(Math.round(result.reports[0].aggregate.complexity.halstead.volume), 12);
assert.strictEqual(Math.round(result.reports[0].aggregate.halstead.volume), 12);
});
test('first report aggregate has correct Halstead effort', function () {
assert.strictEqual(Math.round(result.reports[0].aggregate.complexity.halstead.effort), 12);
assert.strictEqual(Math.round(result.reports[0].aggregate.halstead.effort), 12);
});
test('first report aggregate has correct Halstead bugs', function () {
assert.strictEqual(Math.round(result.reports[0].aggregate.complexity.halstead.bugs), 0);
assert.strictEqual(Math.round(result.reports[0].aggregate.halstead.bugs), 0);
});
test('first report aggregate has correct Halstead time', function () {
assert.strictEqual(Math.round(result.reports[0].aggregate.complexity.halstead.time), 1);
assert.strictEqual(Math.round(result.reports[0].aggregate.halstead.time), 1);
});

@@ -212,11 +216,11 @@

test('second report first function has correct parameter count', function () {
assert.strictEqual(result.reports[1].functions[0].complexity.params, 2);
assert.strictEqual(result.reports[1].functions[0].params, 2);
});
test('second report second function has correct parameter count', function () {
assert.strictEqual(result.reports[1].functions[1].complexity.params, 2);
assert.strictEqual(result.reports[1].functions[1].params, 2);
});
test('second report aggregate has correct parameter count', function () {
assert.strictEqual(result.reports[1].aggregate.complexity.params, 4);
assert.strictEqual(result.reports[1].aggregate.params, 4);
});

@@ -231,2 +235,14 @@

});
test('first-order density is correct', function () {
assert.strictEqual(result.firstOrderDensity, 0);
});
test('change cost is correct', function () {
assert.strictEqual(result.changeCost, 50);
});
test('core size is correct', function () {
assert.strictEqual(result.coreSize, 0);
});
});

@@ -258,35 +274,138 @@

test('adjacency matrix is correct', function () {
assert.lengthOf(result.matrices[0].matrix, 4);
assert.lengthOf(result.adjacencyMatrix, 4);
assert.lengthOf(result.matrices[0].matrix[0], 4);
assert.isNull(result.matrices[0].matrix[0][0]);
assert.strictEqual(result.matrices[0].matrix[0][1], 0);
assert.strictEqual(result.matrices[0].matrix[0][2], 1);
assert.strictEqual(result.matrices[0].matrix[0][3], 1);
assert.lengthOf(result.adjacencyMatrix[0], 4);
assert.strictEqual(result.adjacencyMatrix[0][0], 0);
assert.strictEqual(result.adjacencyMatrix[0][1], 0);
assert.strictEqual(result.adjacencyMatrix[0][2], 1);
assert.strictEqual(result.adjacencyMatrix[0][3], 1);
assert.lengthOf(result.matrices[0].matrix[1], 4);
assert.strictEqual(result.matrices[0].matrix[1][0], 1);
assert.isNull(result.matrices[0].matrix[1][1]);
assert.strictEqual(result.matrices[0].matrix[1][2], 0);
assert.strictEqual(result.matrices[0].matrix[1][3], 0);
assert.lengthOf(result.adjacencyMatrix[1], 4);
assert.strictEqual(result.adjacencyMatrix[1][0], 1);
assert.strictEqual(result.adjacencyMatrix[1][1], 0);
assert.strictEqual(result.adjacencyMatrix[1][2], 0);
assert.strictEqual(result.adjacencyMatrix[1][3], 0);
assert.lengthOf(result.matrices[0].matrix[2], 4);
assert.strictEqual(result.matrices[0].matrix[2][0], 0);
assert.strictEqual(result.matrices[0].matrix[2][1], 0);
assert.isNull(result.matrices[0].matrix[2][2]);
assert.strictEqual(result.matrices[0].matrix[2][3], 1);
assert.lengthOf(result.adjacencyMatrix[2], 4);
assert.strictEqual(result.adjacencyMatrix[2][0], 0);
assert.strictEqual(result.adjacencyMatrix[2][1], 0);
assert.strictEqual(result.adjacencyMatrix[2][2], 0);
assert.strictEqual(result.adjacencyMatrix[2][3], 1);
assert.lengthOf(result.matrices[0].matrix[3], 4);
assert.strictEqual(result.matrices[0].matrix[3][0], 0);
assert.strictEqual(result.matrices[0].matrix[3][1], 0);
assert.strictEqual(result.matrices[0].matrix[3][2], 1);
assert.isNull(result.matrices[0].matrix[3][3]);
assert.lengthOf(result.adjacencyMatrix[3], 4);
assert.strictEqual(result.adjacencyMatrix[3][0], 0);
assert.strictEqual(result.adjacencyMatrix[3][1], 0);
assert.strictEqual(result.adjacencyMatrix[3][2], 1);
assert.strictEqual(result.adjacencyMatrix[3][3], 0);
});
test('first order density is correct', function () {
assert.strictEqual(result.matrices[0].density, 5);
assert.strictEqual(result.firstOrderDensity, 31.25);
});
test('change cost is correct', function () {
assert.strictEqual(result.changeCost, 68.75);
});
test('core size is correct', function () {
assert.strictEqual(result.coreSize, 0);
});
});
suite('MacCormack, Rusnak & Baldwin example:', function () {
var result;
setup(function () {
result = cr.analyse([
{ ast: esprima.parse('"f";', { loc: true }), path: '/a/c/f.js' },
{ ast: esprima.parse('require("./f");"e";', { loc: true }), path: '/a/c/e.js' },
{ ast: esprima.parse('"d";', { loc: true }), path: '/a/b/d.js' },
{ ast: esprima.parse('require("./c/e");"c";', { loc: true }), path: '/a/c.js' },
{ ast: esprima.parse('require("./b/d");"b";', { loc: true }), path: '/a/b.js' },
{ ast: esprima.parse('require("./a/b");require("./a/c");"a";', { loc: true }), path: '/a.js' }
], mozWalker);
});
teardown(function () {
result = undefined;
});
test('reports are in correct order', function () {
assert.strictEqual(result.reports[0].path, '/a.js');
assert.strictEqual(result.reports[1].path, '/a/b.js');
assert.strictEqual(result.reports[2].path, '/a/c.js');
assert.strictEqual(result.reports[3].path, '/a/b/d.js');
assert.strictEqual(result.reports[4].path, '/a/c/e.js');
assert.strictEqual(result.reports[5].path, '/a/c/f.js');
});
test('adjacency matrix is correct', function () {
assert.lengthOf(result.adjacencyMatrix, 6);
assert.lengthOf(result.adjacencyMatrix[0], 6);
assert.strictEqual(result.adjacencyMatrix[0][0], 0);
assert.strictEqual(result.adjacencyMatrix[0][1], 1);
assert.strictEqual(result.adjacencyMatrix[0][2], 1);
assert.strictEqual(result.adjacencyMatrix[0][3], 0);
assert.strictEqual(result.adjacencyMatrix[0][4], 0);
assert.strictEqual(result.adjacencyMatrix[0][5], 0);
assert.lengthOf(result.adjacencyMatrix[1], 6);
assert.strictEqual(result.adjacencyMatrix[1][0], 0);
assert.strictEqual(result.adjacencyMatrix[1][1], 0);
assert.strictEqual(result.adjacencyMatrix[1][2], 0);
assert.strictEqual(result.adjacencyMatrix[1][3], 1);
assert.strictEqual(result.adjacencyMatrix[1][4], 0);
assert.strictEqual(result.adjacencyMatrix[1][5], 0);
assert.lengthOf(result.adjacencyMatrix[2], 6);
assert.strictEqual(result.adjacencyMatrix[2][0], 0);
assert.strictEqual(result.adjacencyMatrix[2][1], 0);
assert.strictEqual(result.adjacencyMatrix[2][2], 0);
assert.strictEqual(result.adjacencyMatrix[2][3], 0);
assert.strictEqual(result.adjacencyMatrix[2][4], 1);
assert.strictEqual(result.adjacencyMatrix[2][5], 0);
assert.lengthOf(result.adjacencyMatrix[3], 6);
assert.strictEqual(result.adjacencyMatrix[3][0], 0);
assert.strictEqual(result.adjacencyMatrix[3][1], 0);
assert.strictEqual(result.adjacencyMatrix[3][2], 0);
assert.strictEqual(result.adjacencyMatrix[3][3], 0);
assert.strictEqual(result.adjacencyMatrix[3][4], 0);
assert.strictEqual(result.adjacencyMatrix[3][5], 0);
assert.lengthOf(result.adjacencyMatrix[4], 6);
assert.strictEqual(result.adjacencyMatrix[4][0], 0);
assert.strictEqual(result.adjacencyMatrix[4][1], 0);
assert.strictEqual(result.adjacencyMatrix[4][2], 0);
assert.strictEqual(result.adjacencyMatrix[4][3], 0);
assert.strictEqual(result.adjacencyMatrix[4][4], 0);
assert.strictEqual(result.adjacencyMatrix[4][5], 1);
assert.lengthOf(result.adjacencyMatrix[5], 6);
assert.strictEqual(result.adjacencyMatrix[5][0], 0);
assert.strictEqual(result.adjacencyMatrix[5][1], 0);
assert.strictEqual(result.adjacencyMatrix[5][2], 0);
assert.strictEqual(result.adjacencyMatrix[5][3], 0);
assert.strictEqual(result.adjacencyMatrix[5][4], 0);
assert.strictEqual(result.adjacencyMatrix[5][5], 0);
});
test('first order density is correct', function () {
assert.isTrue(result.firstOrderDensity > 13.88);
assert.isTrue(result.firstOrderDensity < 13.89);
});
test('change cost is correct', function () {
assert.isTrue(result.changeCost > 41.66);
assert.isTrue(result.changeCost < 41.67);
});
test('core size is correct', function () {
assert.isTrue(result.coreSize > 16.66);
assert.isTrue(result.coreSize < 16.67);
});
});
});
});

Sorry, the diff of this file is not supported yet

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