Skip to content

Commit 008c672

Browse files
committed
feat: add fallback option to use function when looking up types
1 parent 082bad3 commit 008c672

File tree

3 files changed

+100
-15
lines changed

3 files changed

+100
-15
lines changed

lib/nopt-lib.js

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,22 @@ var abbrev = require('abbrev')
22
const debug = require('./debug')
33
const defaultTypeDefs = require('./type-defs')
44

5-
function nopt (args, { types, shorthands, typeDefs, invalidHandler, typeDefault }) {
5+
const hasOwn = (o, k) => Object.prototype.hasOwnProperty.call(o, k)
6+
7+
const getType = (k, { types, dynamicTypes }) => {
8+
let hasType = hasOwn(types, k)
9+
let type = types[k]
10+
if (!hasType && typeof dynamicTypes === 'function') {
11+
const matchedType = dynamicTypes(k)
12+
if (matchedType !== undefined) {
13+
type = matchedType
14+
hasType = true
15+
}
16+
}
17+
return [hasType, type]
18+
}
19+
20+
function nopt (args, { types, dynamicTypes, shorthands, typeDefs, invalidHandler, typeDefault }) {
621
debug(types, shorthands, args, typeDefs)
722

823
var data = {}
@@ -12,10 +27,10 @@ function nopt (args, { types, shorthands, typeDefs, invalidHandler, typeDefault
1227
original: args.slice(0),
1328
}
1429

15-
parse(args, data, argv.remain, { typeDefs, types, shorthands })
30+
parse(args, data, argv.remain, { typeDefs, types, dynamicTypes, shorthands })
1631

1732
// now data is full
18-
clean(data, { types, typeDefs, invalidHandler, typeDefault })
33+
clean(data, { types, dynamicTypes, typeDefs, invalidHandler, typeDefault })
1934
data.argv = argv
2035

2136
Object.defineProperty(data.argv, 'toString', {
@@ -28,7 +43,7 @@ function nopt (args, { types, shorthands, typeDefs, invalidHandler, typeDefault
2843
return data
2944
}
3045

31-
function clean (data, { types, typeDefs, invalidHandler, typeDefault }) {
46+
function clean (data, { types, dynamicTypes, typeDefs, invalidHandler, typeDefault }) {
3247
const StringType = typeDefs.String.type
3348
const NumberType = typeDefs.Number.type
3449
const ArrayType = typeDefs.Array.type
@@ -48,7 +63,7 @@ function clean (data, { types, typeDefs, invalidHandler, typeDefault }) {
4863
}
4964
var val = data[k]
5065
var isArray = Array.isArray(val)
51-
let rawType = types[k]
66+
let [hasType, rawType] = getType(k, { types, dynamicTypes })
5267
var type = rawType
5368
if (!isArray) {
5469
val = [val]
@@ -86,7 +101,7 @@ function clean (data, { types, typeDefs, invalidHandler, typeDefault }) {
86101
}
87102
}
88103

89-
if (!Object.prototype.hasOwnProperty.call(types, k)) {
104+
if (!hasType) {
90105
if (!hasTypeDefault) {
91106
return v
92107
}
@@ -205,7 +220,7 @@ function validate (data, k, val, type, { typeDefs }) {
205220
return ok
206221
}
207222

208-
function parse (args, data, remain, { typeDefs, types, shorthands }) {
223+
function parse (args, data, remain, { typeDefs, types, dynamicTypes, shorthands }) {
209224
const StringType = typeDefs.String.type
210225
const NumberType = typeDefs.String.type
211226
const ArrayType = typeDefs.Array.type
@@ -214,6 +229,7 @@ function parse (args, data, remain, { typeDefs, types, shorthands }) {
214229
debug('parse', args, data, remain)
215230

216231
var abbrevs = abbrev(Object.keys(types))
232+
debug('abbrevs=%j', abbrevs)
217233
var shortAbbr = abbrev(Object.keys(shorthands))
218234

219235
for (var i = 0; i < args.length; i++) {
@@ -260,7 +276,7 @@ function parse (args, data, remain, { typeDefs, types, shorthands }) {
260276
arg = abbrevs[arg]
261277
}
262278

263-
var argType = types[arg]
279+
var [hasType, argType] = getType(arg, { types, dynamicTypes })
264280
var isTypeArray = Array.isArray(argType)
265281
if (isTypeArray && argType.length === 1) {
266282
isTypeArray = false
@@ -271,10 +287,7 @@ function parse (args, data, remain, { typeDefs, types, shorthands }) {
271287
isTypeArray && argType.indexOf(ArrayType) !== -1
272288

273289
// allow unknown things to be arrays if specified multiple times.
274-
if (
275-
!Object.prototype.hasOwnProperty.call(types, arg) &&
276-
Object.prototype.hasOwnProperty.call(data, arg)
277-
) {
290+
if (!hasType && hasOwn(data, arg)) {
278291
if (!Array.isArray(data[arg])) {
279292
data[arg] = [data[arg]]
280293
}

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
"tap": "^16.3.0"
3131
},
3232
"tap": {
33-
"lines": 91,
34-
"branches": 87,
35-
"statements": 91,
33+
"statements": 94,
34+
"branches": 88,
35+
"lines": 94,
3636
"nyc-arg": [
3737
"--exclude",
3838
"tap-snapshots/**"

test/dynamic-types.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
const t = require('tap')
2+
const nopt = require('../lib/nopt-lib.js')
3+
4+
t.test('fallback types', (t) => {
5+
const n = (dynamicTypes) => {
6+
const args = [
7+
'--hello', '100',
8+
'--goodbye', '50',
9+
'--hat=blue',
10+
'--mult', '200',
11+
'--mult', '300',
12+
'--multeq=111',
13+
'--multeq=999',
14+
]
15+
const res = nopt.nopt(args, {
16+
types: { hello: nopt.typeDefs.Number.type },
17+
dynamicTypes,
18+
typeDefs: nopt.typeDefs,
19+
shorthands: {},
20+
})
21+
delete res.argv.cooked
22+
delete res.argv.original
23+
return res
24+
}
25+
26+
t.strictSame(n(), {
27+
hello: 100,
28+
goodbye: true,
29+
hat: 'blue',
30+
mult: [
31+
true,
32+
true,
33+
],
34+
multeq: [
35+
'111',
36+
'999',
37+
],
38+
argv: {
39+
remain: [
40+
'50',
41+
'200',
42+
'300',
43+
],
44+
},
45+
}, 'parse args with no fallback')
46+
47+
t.strictSame(n((k) => {
48+
if (k.startsWith('goo')) {
49+
return nopt.typeDefs.Number.type
50+
}
51+
if (k === 'mult') {
52+
return [nopt.typeDefs.Number.type, nopt.typeDefs.Array.type]
53+
}
54+
}), {
55+
hello: 100,
56+
goodbye: 50,
57+
hat: 'blue',
58+
mult: [
59+
200,
60+
300,
61+
],
62+
multeq: [
63+
'111',
64+
'999',
65+
],
66+
argv: {
67+
remain: [],
68+
},
69+
}, 'parse args with no fallback')
70+
71+
t.end()
72+
})

0 commit comments

Comments
 (0)