Skip to content

Commit

Permalink
feat(parseArgs): set positionals and handle withValue with multiples …
Browse files Browse the repository at this point in the history
…options

This PR handles:
1. setting values for args only if the arg is specified in the options.withValue array
2. set arg value to undefined if withValue isn't specified
3. add args without a dashprefix to the positionals array
4. handle only recording the last value for the arg, in the case of multiple values set for same arg
5. in the case of multiple values set for the same arg, and 'multiples' options having been set, handle recording all values for the arg in the returned array
6. Introduces new test cases covering readme examples, withValue, multiples, and error throwing bad input cases
  • Loading branch information
Jessica Nahulan authored and JessNah committed Sep 24, 2021
1 parent 0f40fa0 commit 4486551
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 10 deletions.
30 changes: 23 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const parseArgs = (
if (typeof options !== 'object' || options === null) {
throw new Error('Whoops!')
}
if(options.withValue && !Array.isArray(options.withValue)) {
throw new Error('Whoops! options.withValue should be an array.')
}

let result = {
args: {},
Expand All @@ -23,7 +26,6 @@ const parseArgs = (
// and is returned verbatim
if (arg === '--') {
result.positionals.push(...argv.slice(++pos))

return result
}
// look for shortcodes: -fXzy
Expand All @@ -39,14 +41,28 @@ const parseArgs = (
const argParts = arg.split('=')

result.args[argParts[0]] = true
if (options.withValue) {
result.values[argParts[0]] = argParts[1]
}
}
else {
result.args[arg] = true
//If withValue option isn't specified, set value as undefined
const val = options.withValue && options.withValue.includes(argParts[0]) ? argParts[1] : undefined
//Append value to previous arg values array for case of multiples option, else add to empty array
result.values[argParts[0]] = [...(options.multiples && options.multiples.includes(argParts[0]) && result.values[argParts[0]] ? result.values[argParts[0]] : []), val]
} else if (pos + 1 < argv.length) {
//withValue option should also support setting values when '=' isn't used
//ie. both --foo=bar and --foo bar should work

result.args[arg] = true
//If withValue option isn't specified, set value as undefined
const val = options.withValue && options.withValue.includes(arg) ? argv[++pos] : undefined
//Append value to previous arg values array for case of multiples option, else add to empty array
result.values[arg] = [...(options.multiples && options.multiples.includes(arg) && result.values[arg] ? result.values[arg] : []), val]
} else {
result.args[arg] = true
//Append undefined to previous arg values array for case of multiples option, else add to empty array
result.values[arg] = [...(options.multiples && options.multiples.includes(arg) && result.values[arg] ? result.values[arg] : []), undefined]
}

} else {
//Arguements without a dash prefix are considered "positional"
result.positionals.push(arg)
}

pos++
Expand Down
60 changes: 57 additions & 3 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
const test = require('tape')
const {parseArgs} = require('../index.js')

//Test results are as we expect

test('Everything after a bare `--` is considered a positional argument', function (t) {
const passedArgs = ['--', 'barepositionals', 'mopositionals']
const expected = { args: {}, values: {}, positionals: ['barepositionals', 'mopositionals'] }
Expand All @@ -15,22 +17,74 @@ test('Everything after a bare `--` is considered a positional argument', functio

test('args are true', function (t) {
const passedArgs = ['--foo', '--bar']
const expected = { args: { foo: true, bar: true}, values: {}, positionals: [] }
const expected = { args: { foo: true, bar: true}, values: {foo: [undefined], bar: [undefined]}, positionals: [] }
const args = parseArgs(passedArgs)

t.deepEqual(args, expected, 'args are true')

t.end()
})

test('arg is true and positional is identified', function (t) {
const passedArgs = ['--foo=a', '--foo', 'b']
const expected = { args: { foo: true}, values: { foo: [undefined]}, positionals: ['b'] }
const args = parseArgs(passedArgs)

t.deepEqual(args, expected, 'arg is true and positional is identified')

t.end()
})

test('args equals are passed "withValue"', function (t) {
const passedArgs = ['--so=wat']
const passedOptions = { withValue: true }
const expected = { args: { so: true}, values: { so: "wat"}, positionals: [] }
const passedOptions = { withValue: ['so'] }
const expected = { args: { so: true}, values: { so: ["wat"]}, positionals: [] }
const args = parseArgs(passedArgs, passedOptions)

t.deepEqual(args, expected, 'arg value is passed')

t.end()
})

test('same arg is passed twice "withValue" and last value is recorded', function (t) {
const passedArgs = ['--foo=a', '--foo', 'b']
const passedOptions = { withValue: ['foo'] }
const expected = { args: { foo: true}, values: { foo: ['b']}, positionals: [] }
const args = parseArgs(passedArgs, passedOptions)

t.deepEqual(args, expected, 'last arg value is passed')

t.end()
})

test('args are passed "withValue" and "multiples"', function (t) {
const passedArgs = ['--foo=a', '--foo', 'b']
const passedOptions = { withValue: ['foo'], multiples: ['foo'] }
const expected = { args: { foo: true}, values: { foo: ['a', 'b']}, positionals: [] }
const args = parseArgs(passedArgs, passedOptions)

t.deepEqual(args, expected, 'both arg values are passed')

t.end()
})


//Test bad inputs

test('boolean passed to "withValue" option', function (t) {
const passedArgs = ['--so=wat']
const passedOptions = { withValue: true }

t.throws(function() { parseArgs(passedArgs, passedOptions) });

t.end()
})

test('string passed to "withValue" option', function (t) {
const passedArgs = ['--so=wat']
const passedOptions = { withValue: 'so' }

t.throws(function() { parseArgs(passedArgs, passedOptions) });

t.end()
})

0 comments on commit 4486551

Please sign in to comment.