Skip to content

Commit 4486551

Browse files
Jessica NahulanJessNah
authored andcommitted
feat(parseArgs): set positionals and handle withValue with multiples 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
1 parent 0f40fa0 commit 4486551

2 files changed

Lines changed: 80 additions & 10 deletions

File tree

index.js

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ const parseArgs = (
77
if (typeof options !== 'object' || options === null) {
88
throw new Error('Whoops!')
99
}
10+
if(options.withValue && !Array.isArray(options.withValue)) {
11+
throw new Error('Whoops! options.withValue should be an array.')
12+
}
1013

1114
let result = {
1215
args: {},
@@ -23,7 +26,6 @@ const parseArgs = (
2326
// and is returned verbatim
2427
if (arg === '--') {
2528
result.positionals.push(...argv.slice(++pos))
26-
2729
return result
2830
}
2931
// look for shortcodes: -fXzy
@@ -39,14 +41,28 @@ const parseArgs = (
3941
const argParts = arg.split('=')
4042

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

52+
result.args[arg] = true
53+
//If withValue option isn't specified, set value as undefined
54+
const val = options.withValue && options.withValue.includes(arg) ? argv[++pos] : undefined
55+
//Append value to previous arg values array for case of multiples option, else add to empty array
56+
result.values[arg] = [...(options.multiples && options.multiples.includes(arg) && result.values[arg] ? result.values[arg] : []), val]
57+
} else {
58+
result.args[arg] = true
59+
//Append undefined to previous arg values array for case of multiples option, else add to empty array
60+
result.values[arg] = [...(options.multiples && options.multiples.includes(arg) && result.values[arg] ? result.values[arg] : []), undefined]
4961
}
62+
63+
} else {
64+
//Arguements without a dash prefix are considered "positional"
65+
result.positionals.push(arg)
5066
}
5167

5268
pos++

test/index.js

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
const test = require('tape')
44
const {parseArgs} = require('../index.js')
55

6+
//Test results are as we expect
7+
68
test('Everything after a bare `--` is considered a positional argument', function (t) {
79
const passedArgs = ['--', 'barepositionals', 'mopositionals']
810
const expected = { args: {}, values: {}, positionals: ['barepositionals', 'mopositionals'] }
@@ -15,22 +17,74 @@ test('Everything after a bare `--` is considered a positional argument', functio
1517

1618
test('args are true', function (t) {
1719
const passedArgs = ['--foo', '--bar']
18-
const expected = { args: { foo: true, bar: true}, values: {}, positionals: [] }
20+
const expected = { args: { foo: true, bar: true}, values: {foo: [undefined], bar: [undefined]}, positionals: [] }
1921
const args = parseArgs(passedArgs)
2022

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

2325
t.end()
2426
})
2527

28+
test('arg is true and positional is identified', function (t) {
29+
const passedArgs = ['--foo=a', '--foo', 'b']
30+
const expected = { args: { foo: true}, values: { foo: [undefined]}, positionals: ['b'] }
31+
const args = parseArgs(passedArgs)
32+
33+
t.deepEqual(args, expected, 'arg is true and positional is identified')
34+
35+
t.end()
36+
})
37+
2638
test('args equals are passed "withValue"', function (t) {
2739
const passedArgs = ['--so=wat']
28-
const passedOptions = { withValue: true }
29-
const expected = { args: { so: true}, values: { so: "wat"}, positionals: [] }
40+
const passedOptions = { withValue: ['so'] }
41+
const expected = { args: { so: true}, values: { so: ["wat"]}, positionals: [] }
3042
const args = parseArgs(passedArgs, passedOptions)
3143

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

3446
t.end()
3547
})
3648

49+
test('same arg is passed twice "withValue" and last value is recorded', function (t) {
50+
const passedArgs = ['--foo=a', '--foo', 'b']
51+
const passedOptions = { withValue: ['foo'] }
52+
const expected = { args: { foo: true}, values: { foo: ['b']}, positionals: [] }
53+
const args = parseArgs(passedArgs, passedOptions)
54+
55+
t.deepEqual(args, expected, 'last arg value is passed')
56+
57+
t.end()
58+
})
59+
60+
test('args are passed "withValue" and "multiples"', function (t) {
61+
const passedArgs = ['--foo=a', '--foo', 'b']
62+
const passedOptions = { withValue: ['foo'], multiples: ['foo'] }
63+
const expected = { args: { foo: true}, values: { foo: ['a', 'b']}, positionals: [] }
64+
const args = parseArgs(passedArgs, passedOptions)
65+
66+
t.deepEqual(args, expected, 'both arg values are passed')
67+
68+
t.end()
69+
})
70+
71+
72+
//Test bad inputs
73+
74+
test('boolean passed to "withValue" option', function (t) {
75+
const passedArgs = ['--so=wat']
76+
const passedOptions = { withValue: true }
77+
78+
t.throws(function() { parseArgs(passedArgs, passedOptions) });
79+
80+
t.end()
81+
})
82+
83+
test('string passed to "withValue" option', function (t) {
84+
const passedArgs = ['--so=wat']
85+
const passedOptions = { withValue: 'so' }
86+
87+
t.throws(function() { parseArgs(passedArgs, passedOptions) });
88+
89+
t.end()
90+
})

0 commit comments

Comments
 (0)