Skip to content

Commit

Permalink
fix: flatten/duplicate regression (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
laggingreflex authored and bcoe committed Jan 2, 2017
1 parent 941d8f3 commit 68d68a0
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 31 deletions.
73 changes: 44 additions & 29 deletions index.js
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
185 changes: 183 additions & 2 deletions test/yargs-parser.js
Expand Up @@ -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'], {
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 68d68a0

Please sign in to comment.