Skip to content

Commit

Permalink
fix: Handle dependency cycles gracefully
Browse files Browse the repository at this point in the history
The toArchy-function now has a cycle-checker that adds a special
"cycle"-node to the tree, when one has been detected
  • Loading branch information
nknapp committed Apr 11, 2018
1 parent fb80e13 commit 414ada7
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 8 deletions.
28 changes: 20 additions & 8 deletions src/index.js
Expand Up @@ -23,7 +23,7 @@ function analyze (cwd, options = {}) {
.then(function (tree) {
return archy({
label: `size: ${tree.rootPackage.stats.totalBlockSize() / 1024}k... with-dependencies: ${tree.rootPackage.totalStats().totalBlockSize() / 1024}k`,
nodes: toArchy(tree.prod, options.depth)
nodes: toArchy(tree.prod, options.depth, [])
})
})
}
Expand All @@ -33,15 +33,27 @@ function analyze (cwd, options = {}) {
* @param pkgs
* @param {number=} depth
*/
function toArchy (pkgs, depth) {
function toArchy (pkgs, depth, cycleChecker) {
if (depth <= 0) return []
const result = pkgs.map(pkg => {
const blockSize = pkg.totalStats().totalBlockSize()
const dependencyCount = pkg.totalDependencies()
return {
label: `${pkg.packageJson._id}, ${chalk.red(blockSize / 1024 + 'k')}, ${dependencyCount} deps`,
size: blockSize,
nodes: toArchy(pkg.dependencies, depth && depth - 1)
if (cycleChecker.indexOf(pkg.packageJson._location) >= 0) {
return {
label: `${pkg.packageJson._id} (cycle detected)`,
size: undefined,
nodes: []
}
}
cycleChecker.push(pkg.packageJson._location)
try {
const blockSize = pkg.totalStats().totalBlockSize()
const dependencyCount = pkg.totalDependencies()
return {
label: `${pkg.packageJson._id}, ${chalk.red(blockSize / 1024 + 'k')}, ${dependencyCount} deps`,
size: blockSize,
nodes: toArchy(pkg.dependencies, depth && depth - 1, cycleChecker)
}
} finally {
cycleChecker.pop()
}
})
return sortby(result, (node) => {
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/moduleWithCyclicDeps.txt
@@ -0,0 +1,5 @@
size: 42k... with-dependencies: 42k
└─┬ dep1@1.0.0, 42k, 3 deps
└─┬ dep1a@1.0.0, 42k, 3 deps
└─┬ dep2@1.0.0, 42k, 3 deps
└── dep1@1.0.0 (cycle detected)
Empty file.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions test/fixtures/moduleWithCyclicDeps/package.json
@@ -0,0 +1,8 @@
{
"name": "moduleWithDeps",
"version": "1.0.0",
"dependencies": {
"dep1": "1.0.0",
"dep2": "1.0.0"
}
}
18 changes: 18 additions & 0 deletions test/index-spec.js
Expand Up @@ -28,4 +28,22 @@ describe('The index-function (module main function):', function () {
expect(result).to.equal(fs.readFileSync(`test/fixtures/moduleWithDeps-depth1-blk${blksize}-${process.platform}.txt`, 'utf-8'))
})
})

it('should handle cyclic dependencies gracefully', function () {
return analyze('test/fixtures/moduleWithCyclicDeps')
.then((result) => {
// The size numbers in this test are irrelevant. In order to keep the test compatible on multiple platforms,
// all sizes are set to 42k
expect(k24(result)).to.equal(k24(fs.readFileSync(`test/fixtures/moduleWithCyclicDeps.txt`, 'utf-8')))
})
})
})

/**
* Replace all kilobyte-numbers by 42k for comparibility if the numbers should not be part of the test
* @param string
* @return {*}
*/
function k24 (string) {
return string.replace(/\d+k/g, '42k')
}

0 comments on commit 414ada7

Please sign in to comment.