Skip to content

Commit 082bad3

Browse files
committed
feat: allow setting typeDefault on nopt and clean lib methods
Setting this option allows bypassing the default handling of unknown keys when cleaning data.
1 parent 9122d7c commit 082bad3

File tree

2 files changed

+71
-11
lines changed

2 files changed

+71
-11
lines changed

lib/nopt-lib.js

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

5-
function nopt (args, { types, shorthands, typeDefs, invalidHandler }) {
5+
function nopt (args, { types, shorthands, typeDefs, invalidHandler, typeDefault }) {
66
debug(types, shorthands, args, typeDefs)
77

88
var data = {}
@@ -15,7 +15,7 @@ function nopt (args, { types, shorthands, typeDefs, invalidHandler }) {
1515
parse(args, data, argv.remain, { typeDefs, types, shorthands })
1616

1717
// now data is full
18-
clean(data, { types, typeDefs, invalidHandler })
18+
clean(data, { types, typeDefs, invalidHandler, typeDefault })
1919
data.argv = argv
2020

2121
Object.defineProperty(data.argv, 'toString', {
@@ -28,23 +28,28 @@ function nopt (args, { types, shorthands, typeDefs, invalidHandler }) {
2828
return data
2929
}
3030

31-
function clean (data, { types, typeDefs, invalidHandler }) {
31+
function clean (data, { types, typeDefs, invalidHandler, typeDefault }) {
3232
const StringType = typeDefs.String.type
3333
const NumberType = typeDefs.Number.type
3434
const ArrayType = typeDefs.Array.type
3535
const BooleanType = typeDefs.Boolean.type
3636
const DateType = typeDefs.Date.type
3737

38+
const hasTypeDefault = typeof typeDefault !== 'undefined'
39+
if (!hasTypeDefault) {
40+
typeDefault = [false, true, null, StringType, ArrayType]
41+
}
42+
3843
var remove = {}
39-
var typeDefault = [false, true, null, StringType, ArrayType]
4044

4145
Object.keys(data).forEach(function (k) {
4246
if (k === 'argv') {
4347
return
4448
}
4549
var val = data[k]
4650
var isArray = Array.isArray(val)
47-
var type = types[k]
51+
let rawType = types[k]
52+
var type = rawType
4853
if (!isArray) {
4954
val = [val]
5055
}
@@ -82,7 +87,14 @@ function clean (data, { types, typeDefs, invalidHandler }) {
8287
}
8388

8489
if (!Object.prototype.hasOwnProperty.call(types, k)) {
85-
return v
90+
if (!hasTypeDefault) {
91+
return v
92+
}
93+
// if the default type has been passed in then we want to validate the
94+
// unknown data key instead of bailing out earlier. we also set the raw
95+
// type which is passed to the invalid handler so that it can be
96+
// determined if during validation if it is unknown vs invalid
97+
rawType = typeDefault
8698
}
8799

88100
// allow `--no-blah` to set 'blah' to null if null is allowed
@@ -93,16 +105,16 @@ function clean (data, { types, typeDefs, invalidHandler }) {
93105

94106
var d = {}
95107
d[k] = v
96-
debug('prevalidated val', d, v, types[k])
97-
if (!validate(d, k, v, types[k], { typeDefs })) {
108+
debug('prevalidated val', d, v, rawType)
109+
if (!validate(d, k, v, rawType, { typeDefs })) {
98110
if (invalidHandler) {
99-
invalidHandler(k, v, types[k], data)
111+
invalidHandler(k, v, rawType, data)
100112
} else if (invalidHandler !== false) {
101-
debug('invalid: ' + k + '=' + v, types[k])
113+
debug('invalid: ' + k + '=' + v, rawType)
102114
}
103115
return remove
104116
}
105-
debug('validated v', d, v, types[k])
117+
debug('validated v', d, v, rawType)
106118
return d[k]
107119
}).filter(function (v) {
108120
return v !== remove

test/type-default.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
const t = require('tap')
2+
const nopt = require('../lib/nopt-lib.js')
3+
4+
t.test('use other type default', (t) => {
5+
const NotAllowed = Symbol('NotAllowed')
6+
const Invalid = Symbol('Invalid')
7+
8+
const clean = (data, opts) => {
9+
const invalids = []
10+
nopt.clean(data, {
11+
types: {
12+
str: nopt.typeDefs.String.type,
13+
invalid: Invalid,
14+
},
15+
typeDefs: {
16+
...nopt.typeDefs,
17+
NotAllowed: { type: NotAllowed, validate: () => false },
18+
Invalid: { type: Invalid, validate: () => false },
19+
},
20+
invalidHandler: (k, v, type) => invalids.push([k, v, type]),
21+
...opts,
22+
})
23+
return {
24+
keys: Object.keys(data),
25+
invalids,
26+
}
27+
}
28+
29+
t.strictSame(clean({
30+
str: 'aaa',
31+
invalid: 'bad',
32+
unknown: 'huh?',
33+
}), {
34+
keys: ['str', 'unknown'],
35+
invalids: [['invalid', 'bad', Invalid]],
36+
}, 'invalid data is removed with clean')
37+
38+
t.strictSame(clean({
39+
str: 'aaa',
40+
invalid: 'bad',
41+
unknown: 'huh?',
42+
}, { typeDefault: NotAllowed }), {
43+
keys: ['str'],
44+
invalids: [['invalid', 'bad', Invalid], ['unknown', 'huh?', NotAllowed]],
45+
}, 'invalid and unknown data is removed with a custom typeDefault')
46+
47+
t.end()
48+
})

0 commit comments

Comments
 (0)