From 68d68a0440510eabbd4d1aca22b6b091e454c19f Mon Sep 17 00:00:00 2001 From: laggingreflex Date: Tue, 3 Jan 2017 01:06:19 +0530 Subject: [PATCH] fix: flatten/duplicate regression (#75) --- index.js | 73 ++++++++++------- test/yargs-parser.js | 185 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 227 insertions(+), 31 deletions(-) diff --git a/index.js b/index.js index cdb5fc55..1a04d559 100644 --- a/index.js +++ b/index.js @@ -325,8 +325,10 @@ function parse (args, opts) { i = ii argsToSet.push(args[ii]) } - if (multipleArrayFlag && !configuration['flatten-duplicate-arrays']) { - setArg(key, argsToSet) + if (multipleArrayFlag) { + setArg(key, argsToSet.map(function (arg) { + return processValue(key, arg) + })) } else { argsToSet.forEach(function (arg) { setArg(key, arg) @@ -339,33 +341,13 @@ function parse (args, opts) { function setArg (key, val) { unsetDefaulted(key) - // handle parsing boolean arguments --foo=true --bar false. - if (checkAllAliases(key, flags.bools) || checkAllAliases(key, flags.counts)) { - if (typeof val === 'string') val = val === 'true' - } - if (/-/.test(key) && !(flags.aliases[key] && flags.aliases[key].length) && configuration['camel-case-expansion']) { var c = camelCase(key) flags.aliases[key] = [c] newAliases[c] = true } - var value = val - if (!checkAllAliases(key, flags.strings) && !checkAllAliases(key, flags.coercions)) { - if (isNumber(val)) value = Number(val) - if (!isUndefined(val) && !isNumber(val) && checkAllAliases(key, flags.numbers)) value = NaN - } - - // increment a count given as arg (either no value or value parsed as boolean) - if (checkAllAliases(key, flags.counts) && (isUndefined(value) || typeof value === 'boolean')) { - value = increment - } - - // Set normalized value when key is in 'normalize' and in 'arrays' - if (checkAllAliases(key, flags.normalize) && checkAllAliases(key, flags.arrays)) { - if (Array.isArray(val)) value = val.map(path.normalize) - else value = path.normalize(val) - } + var value = processValue(key, val) var splitKey = key.split('.') setKey(argv, splitKey, value) @@ -407,6 +389,31 @@ function parse (args, opts) { } } + function processValue (key, val) { + // handle parsing boolean arguments --foo=true --bar false. + if (checkAllAliases(key, flags.bools) || checkAllAliases(key, flags.counts)) { + if (typeof val === 'string') val = val === 'true' + } + + var value = val + if (!checkAllAliases(key, flags.strings) && !checkAllAliases(key, flags.coercions)) { + if (isNumber(val)) value = Number(val) + if (!isUndefined(val) && !isNumber(val) && checkAllAliases(key, flags.numbers)) value = NaN + } + + // increment a count given as arg (either no value or value parsed as boolean) + if (checkAllAliases(key, flags.counts) && (isUndefined(value) || typeof value === 'boolean')) { + value = increment + } + + // Set normalized value when key is in 'normalize' and in 'arrays' + if (checkAllAliases(key, flags.normalize) && checkAllAliases(key, flags.arrays)) { + if (Array.isArray(val)) value = val.map(path.normalize) + else value = path.normalize(val) + } + return value + } + // set args from config.json file, this should be // applied last so that defaults can be applied. function setConfig (argv) { @@ -551,15 +558,23 @@ function parse (args, opts) { var key = keys[keys.length - 1] + var isTypeArray = checkAllAliases(key, flags.arrays) + var isValueArray = Array.isArray(value) + var duplicate = configuration['duplicate-arguments-array'] + if (value === increment) { o[key] = increment(o[key]) - } else if (o[key] === undefined && checkAllAliases(key, flags.arrays)) { - o[key] = Array.isArray(value) && configuration['flatten-duplicate-arrays'] ? value : [value] - } else if (o[key] === undefined || checkAllAliases(key, flags.bools) || checkAllAliases(keys.join('.'), flags.bools) || checkAllAliases(key, flags.counts)) { - o[key] = value } else if (Array.isArray(o[key])) { - o[key].push(value) - } else if (configuration['duplicate-arguments-array']) { + if (duplicate && isTypeArray && isValueArray) { + o[key] = configuration['flatten-duplicate-arrays'] ? o[key].concat(value) : [o[key]].concat([value]) + } else if (!duplicate && Boolean(isTypeArray) === Boolean(isValueArray)) { + o[key] = value + } else { + o[key] = o[key].concat([value]) + } + } else if (o[key] === undefined && isTypeArray) { + o[key] = isValueArray ? value : [value] + } else if (duplicate && !(o[key] === undefined || checkAllAliases(key, flags.bools) || checkAllAliases(keys.join('.'), flags.bools) || checkAllAliases(key, flags.counts))) { o[key] = [ o[key], value ] } else { o[key] = value diff --git a/test/yargs-parser.js b/test/yargs-parser.js index 5d4243aa..c9c59993 100644 --- a/test/yargs-parser.js +++ b/test/yargs-parser.js @@ -1374,11 +1374,16 @@ describe('yargs-parser', function () { }) describe('array', function () { - it('should group values into an array if the same option is specified multiple times', function () { - var parse = parser(['-v', 'a', '-v', 'b', '-v', 'c']) + it('should group values into an array if the same option is specified multiple times (duplicate-arguments-array=true)', function () { + var parse = parser(['-v', 'a', '-v', 'b', '-v', 'c'], {configuration: {'duplicate-arguments-array': true}}) parse.should.have.property('v').and.deep.equal(['a', 'b', 'c']) parse.should.have.property('_').with.length(0) }) + it('should keep only the last value if the same option is specified multiple times (duplicate-arguments-false)', function () { + var parse = parser(['-v', 'a', '-v', 'b', '-v', 'c'], {configuration: {'duplicate-arguments-array': false}}) + parse.should.have.property('v').and.equal('c') + parse.should.have.property('_').with.length(0) + }) it('should default an array to an empty array if passed as first option followed by another', function () { var result = parser(['-a', '-b'], { @@ -2012,6 +2017,182 @@ describe('yargs-parser', function () { parsed['x'].should.deep.equal(['a', 'b']) }) }) + + describe('duplicate-arguments-array VS flatten-duplicate-arrays', function () { + /* + duplicate=false, flatten=false + type=array + [-x 1 2 3] => [1, 2, 3] + [-x 1 2 3 -x 2 3 4] => [2, 3, 4] + type=string/number/etc + [-x 1 -x 2 -x 3] => 3 + + duplicate=false, flatten=true + type=array + [-x 1 2 3] => [1, 2, 3] + [-x 1 2 3 -x 2 3 4] => [2, 3, 4] + type=string/number/etc + [-x 1 -x 2 -x 3] => 3 + + duplicate=true, flatten=true + type=array + [-x 1 2 3] => [1, 2, 3] + [-x 1 2 3 -x 2 3 4] => [1, 2, 3, 2, 3, 4] + type=string/number/etc + [-x 1 -x 2 -x 3] => [1, 2, 3] + + duplicate=true, flatten=false + type=array + [-x 1 2 3] => [1, 2, 3] + [-x 1 2 3 -x 2 3 4] => [[1, 2, 3], [2, 3, 4]] + type=string/number/etc + [-x 1 -x 2 -x 3] => [1, 2, 3] + */ + describe('duplicate=false, flatten=false,', function () { + describe('type=array', function () { + it('[-x 1 2 3] => [1, 2, 3]', function () { + var parsed = parser('-x 1 2 3', { + array: ['x'], + configuration: { + 'duplicate-arguments-array': false, + 'flatten-duplicate-arrays': false + } + }) + parsed['x'].should.deep.equal([1, 2, 3]) + }) + it('[-x 1 2 3 -x 2 3 4] => [2, 3, 4]', function () { + var parsed = parser('-x 1 2 3 -x 2 3 4', { + array: ['x'], + configuration: { + 'duplicate-arguments-array': false, + 'flatten-duplicate-arrays': false + } + }) + parsed['x'].should.deep.equal([2, 3, 4]) + }) + }) + describe('type=number', function () { + it('[-x 1 -x 2 -x 3] => 3', function () { + var parsed = parser('-x 1 -x 2 -x 3', { + number: 'x', + configuration: { + 'duplicate-arguments-array': false, + 'flatten-duplicate-arrays': false + } + }) + parsed['x'].should.deep.equal(3) + }) + }) + }) + describe('duplicate=false, flatten=true,', function () { + describe('type=array', function () { + it('[-x 1 2 3] => [1, 2, 3]', function () { + var parsed = parser('-x 1 2 3', { + array: ['x'], + configuration: { + 'duplicate-arguments-array': false, + 'flatten-duplicate-arrays': true + } + }) + parsed['x'].should.deep.equal([1, 2, 3]) + }) + it('[-x 1 2 3 -x 2 3 4] => [2, 3, 4]', function () { + var parsed = parser('-x 1 2 3 -x 2 3 4', { + array: ['x'], + configuration: { + 'duplicate-arguments-array': false, + 'flatten-duplicate-arrays': true + } + }) + parsed['x'].should.deep.equal([2, 3, 4]) + }) + }) + describe('type=number', function () { + it('[-x 1 -x 2 -x 3] => 3', function () { + var parsed = parser('-x 1 -x 2 -x 3', { + number: 'x', + configuration: { + 'duplicate-arguments-array': false, + 'flatten-duplicate-arrays': true + } + }) + parsed['x'].should.deep.equal(3) + }) + }) + }) + describe('duplicate=true, flatten=true,', function () { + describe('type=array', function () { + it('[-x 1 2 3] => [1, 2, 3]', function () { + var parsed = parser('-x 1 2 3', { + array: ['x'], + configuration: { + 'duplicate-arguments-array': true, + 'flatten-duplicate-arrays': true + } + }) + parsed['x'].should.deep.equal([1, 2, 3]) + }) + it('[-x 1 2 3 -x 2 3 4] => [1, 2, 3, 2, 3, 4]', function () { + var parsed = parser('-x 1 2 3 -x 2 3 4', { + array: ['x'], + configuration: { + 'duplicate-arguments-array': true, + 'flatten-duplicate-arrays': true + } + }) + parsed['x'].should.deep.equal([1, 2, 3, 2, 3, 4]) + }) + }) + describe('type=number', function () { + it('[-x 1 -x 2 -x 3] => [1, 2, 3]', function () { + var parsed = parser('-x 1 -x 2 -x 3', { + number: 'x', + configuration: { + 'duplicate-arguments-array': true, + 'flatten-duplicate-arrays': true + } + }) + parsed['x'].should.deep.equal([1, 2, 3]) + }) + }) + }) + describe('duplicate=true, flatten=false,', function () { + describe('type=array', function () { + it('[-x 1 -x 2 -x 3] => [1, 2, 3]', function () { + var parsed = parser('-x 1 -x 2 -x 3', { + array: ['x'], + configuration: { + 'duplicate-arguments-array': true, + 'flatten-duplicate-arrays': false + } + }) + parsed['x'].should.deep.equal([1, 2, 3]) + }) + it('[-x 1 2 3 -x 2 3 4] => [[1, 2, 3], [ 2, 3, 4]]', function () { + var parsed = parser('-x 1 2 3 -x 2 3 4', { + array: ['x'], + configuration: { + 'duplicate-arguments-array': true, + 'flatten-duplicate-arrays': false + } + }) + parsed['x'].should.deep.equal([[1, 2, 3], [2, 3, 4]]) + }) + }) + describe('type=number', function () { + it('[-x 1 -x 2 -x 3] => [1, 2, 3]', function () { + var parsed = parser('-x 1 -x 2 -x 3', { + number: 'x', + configuration: { + 'duplicate-arguments-array': true, + 'flatten-duplicate-arrays': false + } + }) + parsed['x'].should.deep.equal([1, 2, 3]) + }) + }) + }) + }) }) // addresses: https://github.com/yargs/yargs-parser/issues/41