diff --git a/bin/cli.js b/bin/cli.js index ca3aaba7..0802ab94 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -1,10 +1,14 @@ #!/usr/bin/env node 'use strict'; +const path = require('path'); const process = require('process'); const program = require('commander'); const rc = require('rc')('madge'); const version = require('../package.json').version; +const ora = require('ora'); +const chalk = require('chalk'); +const startTime = Date.now(); program .version(version) @@ -46,6 +50,12 @@ const log = require('../lib/log'); const output = require('../lib/output'); const madge = require('../lib/api'); const config = Object.assign({}, rc); +const spinner = ora({ + text: 'Finding files', + color: 'white', + interval: 100000 +}); + let exitCode = 0; delete config._; @@ -92,6 +102,22 @@ if (!program.color) { config.edgeColor = '#757575'; } +function dependencyFilter() { + let prevFile; + + return (dependencyFilePath, traversedFilePath, baseDir) => { + if (prevFile !== traversedFilePath) { + const relPath = path.relative(baseDir, traversedFilePath); + const dir = path.dirname(relPath) + '/'; + const file = path.basename(relPath); + + spinner.text = chalk.grey(dir) + chalk.cyan(file); + spinner.render(); + prevFile = traversedFilePath; + } + }; +} + new Promise((resolve, reject) => { if (program.stdin) { let buffer = ''; @@ -114,9 +140,19 @@ new Promise((resolve, reject) => { } }) .then((src) => { + if (!program.json && !program.dot) { + spinner.start(); + config.dependencyFilter = dependencyFilter(); + } + return madge(src, config); }) .then((res) => { + if (!program.json && !program.dot) { + spinner.stop(); + output.getResultSummary(res, startTime); + } + if (program.summary) { output.summary(res.obj(), { json: program.json @@ -136,7 +172,7 @@ new Promise((resolve, reject) => { if (program.circular) { const circular = res.circular(); - output.circular(res, circular, { + output.circular(spinner, res, circular, { json: program.json }); @@ -149,7 +185,7 @@ new Promise((resolve, reject) => { if (program.image) { return res.image(program.image).then((imagePath) => { - console.log('Image created at %s', imagePath); + spinner.succeed(`${chalk.bold('Image created at')} ${chalk.cyan.bold(imagePath)}`); return res; }); } @@ -172,10 +208,14 @@ new Promise((resolve, reject) => { output.warnings(res); } + if (!program.json && !program.dot) { + console.log(''); + } + process.exit(exitCode); }) .catch((err) => { - output.error(err); - + spinner.stop(); + console.log('\n%s %s\n', chalk.red('✖'), err.stack); process.exit(1); }); diff --git a/lib/output.js b/lib/output.js index f683f492..40f9e439 100644 --- a/lib/output.js +++ b/lib/output.js @@ -2,12 +2,7 @@ const chalk = require('chalk'); const pluralize = require('pluralize'); - -const red = chalk.red; -const cyan = chalk.cyan; -const grey = chalk.grey; -const green = chalk.green; -const yellow = chalk.yellow; +const prettyMs = require('pretty-ms'); /** * Print given object as JSON. @@ -32,9 +27,9 @@ module.exports.list = function (modules, opts) { } Object.keys(modules).forEach((id) => { - console.log(cyan.bold(id)); + console.log(chalk.cyan.bold(id)); modules[id].forEach((depId) => { - console.log(grey(` ${depId}`)); + console.log(chalk.grey(` ${depId}`)); }); }); }; @@ -56,7 +51,7 @@ module.exports.summary = function (modules, opts) { if (opts.json) { o[id] = modules[id].length; } else { - console.log(cyan.bold(`${id}: `) + yellow.bold(modules[id].length)); + console.log('%s %s', chalk.cyan.bold(modules[id].length), chalk.grey(id)); } }); @@ -67,35 +62,33 @@ module.exports.summary = function (modules, opts) { /** * Print the result from Madge.circular(). + * @param {Object} spinner * @param {Object} res * @param {Array} circular * @param {Object} opts * @return {undefined} */ -module.exports.circular = function (res, circular, opts) { +module.exports.circular = function (spinner, res, circular, opts) { if (opts.json) { return printJSON(circular); } - const warningCount = res.warnings().skipped.length; - const fileCount = Object.keys(res.obj()).length; const cyclicCount = Object.keys(circular).length; - const statusMsg = `(${pluralize('file', fileCount, true)}, ${pluralize('warning', warningCount, true)})`; if (!circular.length) { - console.log(green.bold(`✔ No circular dependency ${statusMsg}`)); + spinner.succeed(chalk.bold('No circular dependency found!')); } else { - console.log(red.bold(`✖ ${pluralize('circular dependency', cyclicCount, true)} ${statusMsg}\n`)); + spinner.fail(chalk.red.bold(`Found ${pluralize('circular dependency', cyclicCount, true)}!\n`)); circular.forEach((path, idx) => { + process.stdout.write(chalk.dim(idx + 1 + ') ')); path.forEach((module, idx) => { if (idx) { - process.stdout.write(grey(' > ')); + process.stdout.write(chalk.dim(' > ')); } - process.stdout.write(cyan.bold(module)); + process.stdout.write(chalk.cyan.bold(module)); }); process.stdout.write('\n'); }); - process.stdout.write('\n'); } }; @@ -111,7 +104,7 @@ module.exports.depends = function (depends, opts) { } depends.forEach((id) => { - console.log(cyan.bold(id)); + console.log(chalk.cyan.bold(id)); }); }; @@ -124,22 +117,28 @@ module.exports.warnings = function (res) { const skipped = res.warnings().skipped; if (skipped.length) { - console.log(red.bold(`✖ Skipped ${pluralize('file', skipped.length, true)}\n`)); + console.log(chalk.yellow.bold(`\n✖ Skipped ${pluralize('file', skipped.length, true)}\n`)); skipped.forEach((file) => { - console.log(red(file)); + console.log(chalk.yellow(file)); }); - - process.stdout.write('\n'); } }; /** - * Print error to the console. - * @param {Object} err - * @param {Object} opts + * Get a summary from the result. + * @param {Object} res + * @param {Number} startTime * @return {undefined} */ -module.exports.error = function (err) { - console.log(red.bold(err.stack ? err.stack : err)); +module.exports.getResultSummary = function (res, startTime) { + const warningCount = res.warnings().skipped.length; + const fileCount = Object.keys(res.obj()).length; + + console.log('Processed %s %s %s %s\n', + chalk.bold(fileCount), + pluralize('file', fileCount), + chalk.dim(`(${prettyMs(Date.now() - startTime)})`), + warningCount ? '(' + chalk.yellow.bold(pluralize('warning', warningCount, true)) + ')' : '' + ); };