From 0becf21d7cf2426fe575dfee3dd2dcba8860156e Mon Sep 17 00:00:00 2001 From: Andreas Windt Date: Fri, 22 Apr 2016 19:59:06 +0200 Subject: [PATCH] feat(diff): detailed comparison via verbose output flag (#61) --- src/bin/diff.js | 50 ++++++++++++++++++++++++++----- src/lib/flatten-rules-diff.js | 38 +++++++++++++++++++++++ src/lib/stringify-rule-config.js | 11 +++++++ test/bin/diff.js | 20 ++++++++++++- test/lib/flatten-rules-diff.js | 38 +++++++++++++++++++++++ test/lib/stringify-rule-config.js | 25 ++++++++++++++++ 6 files changed, 173 insertions(+), 9 deletions(-) create mode 100644 src/lib/flatten-rules-diff.js create mode 100644 src/lib/stringify-rule-config.js create mode 100644 test/lib/flatten-rules-diff.js create mode 100644 test/lib/stringify-rule-config.js diff --git a/src/bin/diff.js b/src/bin/diff.js index 4696ca3..c94f8c6 100644 --- a/src/bin/diff.js +++ b/src/bin/diff.js @@ -3,14 +3,21 @@ 'use strict' var path = require('path') +var argv = require('yargs') + .boolean('verbose') + .alias('v', 'verbose') + .argv var cli = require('../lib/cli-util') var getRuleFinder = require('../lib/rule-finder') -var difference = require('../lib/array-diff') +var arrayDifference = require('../lib/array-diff') +var objectDifference = require('../lib/object-diff') var getSortedRules = require('../lib/sort-rules') +var flattenRulesDiff = require('../lib/flatten-rules-diff') +var stringifyRuleConfig = require('../lib/stringify-rule-config') -var files = [process.argv[2], process.argv[3]] +var files = [argv._[0], argv._[1]] var collectedRules = getFilesToCompare(files).map(compareConfigs) var rulesCount = collectedRules.reduce( @@ -18,18 +25,29 @@ var rulesCount = collectedRules.reduce( return prev + (curr && curr.rules ? curr.rules.length : /* istanbul ignore next */ 0) }, 0) -/* istanbul ignore next */ +/* istanbul ignore else */ +if (argv.verbose || rulesCount) { + cli.push('\ndiff rules\n' + rulesCount + ' rules differ\n') +} + +/* istanbul ignore else */ if (rulesCount) { - cli.push('\ndiff rules\n') collectedRules.forEach(function displayConfigs(diff) { var rules = diff.rules + /* istanbul ignore if */ if (!rules.length) { return } - cli.push('\nin ' + diff.config1 + ' but not in ' + diff.config2 + ':\n') - cli.push(rules) + if (argv.verbose) { + rules = flattenRulesDiff(rules).map(stringifyRuleConfig) + rules.unshift([], diff.config1, diff.config2) + } else { + cli.push('\nin ' + diff.config1 + ' but not in ' + diff.config2 + ':\n') + } + + cli.push(rules, argv.verbose ? 3 : 0) }) } @@ -37,7 +55,14 @@ cli.write() function getFilesToCompare(allFiles) { var filesToCompare = [allFiles] - filesToCompare.push([].concat(allFiles).reverse()) + + if (!argv.verbose) { + // in non-verbose output mode, compare a to b + // and b to a afterwards, to obtain ALL differences + // accross those files, but grouped + filesToCompare.push([].concat(allFiles).reverse()) + } + return filesToCompare } @@ -53,8 +78,17 @@ function compareConfigs(currentFiles) { } function rulesDifference(a, b) { + if (argv.verbose) { + return getSortedRules( + objectDifference( + a.getCurrentRulesDetailed(), + b.getCurrentRulesDetailed() + ) + ) + } + return getSortedRules( - difference( + arrayDifference( a.getCurrentRules(), b.getCurrentRules() ) diff --git a/src/lib/flatten-rules-diff.js b/src/lib/flatten-rules-diff.js new file mode 100644 index 0000000..86bab1c --- /dev/null +++ b/src/lib/flatten-rules-diff.js @@ -0,0 +1,38 @@ +function flattenRulesDiff(diff) { + if (Array.isArray(diff)) { + return flattenRulesDiffArray(diff) + } else if (typeof diff === 'object') { + return flattenRulesDiffObject(diff) + } + + return [] +} + +function flattenRulesDiffObject(diffObject) { + var flattened = [] + + Object.keys(diffObject).forEach(function flattenEachRuleDiff(ruleName) { + var ruleRow = [ruleName] + var diff = diffObject[ruleName] + + Object.keys(diff).forEach(function flattenEachChildProp(configName) { + ruleRow.push(diff[configName]) + }) + + flattened.push.apply(flattened, ruleRow) + }) + + return flattened +} + +function flattenRulesDiffArray(diffArray) { + var flattened = [] + + diffArray.forEach(function flattenEachDiff(diff) { + flattened.push.apply(flattened, flattenRulesDiff(diff)) + }) + + return flattened +} + +module.exports = flattenRulesDiff diff --git a/src/lib/stringify-rule-config.js b/src/lib/stringify-rule-config.js new file mode 100644 index 0000000..c3d9f17 --- /dev/null +++ b/src/lib/stringify-rule-config.js @@ -0,0 +1,11 @@ +function stringifyRuleConfig(rule) { + if (typeof rule === 'string') { + return rule + } else if (typeof rule === 'undefined') { + return '-' + } + + return JSON.stringify(rule) +} + +module.exports = stringifyRuleConfig diff --git a/test/bin/diff.js b/test/bin/diff.js index 636fc92..5b220ca 100644 --- a/test/bin/diff.js +++ b/test/bin/diff.js @@ -8,9 +8,11 @@ var stub = { '../lib/rule-finder': function() { return { getCurrentRules: function noop() {}, + getCurrentRulesDetailed: function noop() {}, } }, '../lib/array-diff': sinon.stub().returns(['diff']), + '../lib/object-diff': sinon.stub().returns([{'test-rule': {config1: 'foo-config', config2: 'bar-config'}}]), } describe('diff', function() { @@ -27,9 +29,11 @@ describe('diff', function() { afterEach(function() { console.log.restore() // eslint-disable-line no-console + // purge yargs cache + delete require.cache[require.resolve('yargs')] }) - it('log diff', function() { + it('logs diff', function() { process.argv[2] = './foo' process.argv[3] = './bar' proxyquire('../../src/bin/diff', stub) @@ -41,4 +45,18 @@ describe('diff', function() { ) ) }) + + it('logs diff verbosely', function() { + process.argv[2] = '--verbose' + process.argv[3] = './foo' + process.argv[4] = './bar' + proxyquire('../../src/bin/diff', stub) + assert.ok( + console.log.calledWith( // eslint-disable-line no-console + sinon.match( + /diff rules[^]*foo[^]*bar[^]*test-rule[^]*foo-config[^]*bar-config/ + ) + ) + ) + }) }) diff --git a/test/lib/flatten-rules-diff.js b/test/lib/flatten-rules-diff.js new file mode 100644 index 0000000..0f93f5e --- /dev/null +++ b/test/lib/flatten-rules-diff.js @@ -0,0 +1,38 @@ +var assert = require('assert') +var flattenRulesDiff = require('../../src/lib/flatten-rules-diff') + +describe('flatten rules diff', function() { + it('should return flat array from diff-object with single rule', function() { + assert.deepEqual( + flattenRulesDiff({'foo-rule': {config1: [2, 'foo'], config2: [2, 'bar']}}), + ['foo-rule', [2, 'foo'], [2, 'bar']] + ) + }) + + it('should return flat array from diff-object with multiple rules', function() { + assert.deepEqual( + flattenRulesDiff({ + 'foo-rule': {config1: [2, 'foo'], config2: [2, 'bar']}, + 'bar-rule': {config1: undefined, config2: [1, 'bar']}, + }), + ['foo-rule', [2, 'foo'], [2, 'bar'], 'bar-rule', undefined, [1, 'bar']] + ) + }) + + it('should return flat array from an array of diff-objects', function() { + assert.deepEqual( + flattenRulesDiff([ + {'foo-rule': {config1: [2, 'foo'], config2: [2, 'bar']}}, + {'bar-rule': {config1: undefined, config2: [1, 'bar']}}, + ]), + ['foo-rule', [2, 'foo'], [2, 'bar'], 'bar-rule', undefined, [1, 'bar']] + ) + }) + + it('should return empty array on anything else', function() { + assert.deepEqual( + flattenRulesDiff(undefined), + [] + ) + }) +}) diff --git a/test/lib/stringify-rule-config.js b/test/lib/stringify-rule-config.js new file mode 100644 index 0000000..f708d46 --- /dev/null +++ b/test/lib/stringify-rule-config.js @@ -0,0 +1,25 @@ +var assert = require('assert') +var stringifyRuleConfig = require('../../src/lib/stringify-rule-config') + +describe('stringify rule config', function() { + it('should return a string', function() { + assert.equal( + stringifyRuleConfig('A simple string'), + 'A simple string' + ) + }) + + it('should return \'-\' for "undefined"', function() { + assert.equal( + stringifyRuleConfig(undefined), + '-' + ) + }) + + it('should return a JSON.stringify\'ed result for any object', function() { + assert.deepEqual( + stringifyRuleConfig([2, 'foo', {bar: true}]), + JSON.stringify([2, 'foo', {bar: true}]) + ) + }) +})