From 97ed27f846f3e53dc127c577e6667f5faf6a814b Mon Sep 17 00:00:00 2001 From: Avahe Kellenberger Date: Mon, 9 Mar 2020 10:44:02 -0400 Subject: [PATCH] Add `leaves` option to show modules that do not have dependencies --- README.md | 16 ++++++++ bin/cli.js | 116 ++++++++++++++++++++++++++++++---------------------- lib/api.js | 10 +++++ test/api.js | 9 ++++ 4 files changed, 101 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 49e4ce14..5b0e95ea 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,18 @@ madge('path/to/app.js').then((res) => { }); ``` +#### .leaves() + +> Return an `Array` of all modules that have no dependencies. + +```javascript +const madge = require('madge'); + +madge('path/to/app.js').then((res) => { + console.log(res.leaves()); +}); +``` + #### .dot() > Returns a `Promise` resolved with a DOT representation of the module dependency graph. @@ -304,6 +316,10 @@ $ madge --depends wheels.js path/src/app.js $ madge --orphans path/src/ ``` +```sh +$ madge --leaves path/src/ +``` + > Excluding modules ```sh diff --git a/bin/cli.js b/bin/cli.js index e87d888f..ace5da8a 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -22,6 +22,7 @@ program .option('-i, --image ', 'write graph to file as an image') .option('-l, --layout ', 'layout engine to use for graph (dot/neato/fdp/sfdp/twopi/circo)') .option('--orphans', 'show modules that no one is depending on') + .option('--leaves', 'show modules that have no dependencies') .option('--dot', 'show graph using the DOT language') .option('--extensions ', 'comma separated string of valid file extensions') .option('--require-config ', 'path to RequireJS config') @@ -172,56 +173,9 @@ new Promise((resolve, reject) => { output.getResultSummary(res, startTime); } - if (program.summary) { - output.summary(res.obj(), { - json: program.json - }); - - return res; - } - - if (program.depends) { - output.modules(res.depends(program.depends), { - json: program.json - }); - - return res; - } - - if (program.orphans) { - output.modules(res.orphans(), { - json: program.json - }); - - return res; - } - - if (program.circular) { - const circular = res.circular(); - - output.circular(spinner, res, circular, { - json: program.json - }); - - if (circular.length) { - exitCode = 1; - } - - return res; - } - - if (program.image) { - return res.image(program.image).then((imagePath) => { - spinner.succeed(`${chalk.bold('Image created at')} ${chalk.cyan.bold(imagePath)}`); - return res; - }); - } - - if (program.dot) { - return res.dot().then((output) => { - process.stdout.write(output); - return res; - }); + const result = createOutputFromOptions(program, res); + if (result !== undefined) { + return result; } output.list(res.obj(), { @@ -246,3 +200,65 @@ new Promise((resolve, reject) => { console.log('\n%s %s\n', chalk.red('✖'), err.stack); process.exit(1); }); + +function createOutputFromOptions(program, res) { + if (program.summary) { + output.summary(res.obj(), { + json: program.json + }); + + return res; + } + + if (program.depends) { + output.modules(res.depends(program.depends), { + json: program.json + }); + + return res; + } + + if (program.orphans) { + output.modules(res.orphans(), { + json: program.json + }); + + return res; + } + + if (program.leaves) { + output.modules(res.leaves(), { + json: program.json + }); + + return res; + } + + if (program.circular) { + const circular = res.circular(); + + output.circular(spinner, res, circular, { + json: program.json + }); + + if (circular.length) { + exitCode = 1; + } + + return res; + } + + if (program.image) { + return res.image(program.image).then((imagePath) => { + spinner.succeed(`${chalk.bold('Image created at')} ${chalk.cyan.bold(imagePath)}`); + return res; + }); + } + + if (program.dot) { + return res.dot().then((output) => { + process.stdout.write(output); + return res; + }); + } +} diff --git a/lib/api.js b/lib/api.js index 60ed0393..2d1cc5b2 100644 --- a/lib/api.js +++ b/lib/api.js @@ -129,6 +129,16 @@ class Madge { .filter((dep) => !map[dep]); } + /** + * Return a list of modules that have no dependencies. + * @api public + * @return {Array} + */ + leaves() { + const tree = this.obj(); + return Object.keys(tree).filter((key) => !tree[key].length); + } + /** * Return the module dependency graph as DOT output. * @api public diff --git a/test/api.js b/test/api.js index 0a96edca..697486eb 100644 --- a/test/api.js +++ b/test/api.js @@ -235,6 +235,15 @@ describe('API', () => { }); }); + describe('leaves()', () => { + it('returns modules that have no dependencies', (done) => { + madge(__dirname + '/cjs/normal').then((res) => { + res.leaves().should.eql(['d.js']); + done(); + }).catch(done); + }); + }); + describe('svg()', () => { it('returns a promise resolved with XML SVG output in a Buffer', (done) => { madge(__dirname + '/cjs/b.js')