Skip to content

Commit

Permalink
feat: allow setting typeDefault on nopt and clean lib methods
Browse files Browse the repository at this point in the history
Setting this option allows bypassing the default handling of unknown
keys when cleaning data.
  • Loading branch information
lukekarrys committed May 29, 2023
1 parent 15befd2 commit 7ede6c7
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 16 deletions.
34 changes: 23 additions & 11 deletions lib/nopt-lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ var abbrev = require('abbrev')
const debug = require('./debug')
const defaultTypeDefs = require('./type-defs')

function nopt (args, { types, shorthands, typeDefs, invalidHandler }) {
function nopt (args, { types, shorthands, typeDefs, invalidHandler, typeDefault }) {
debug(types, shorthands, args, typeDefs)

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

// now data is full
clean(data, { types, typeDefs, invalidHandler })
clean(data, { types, typeDefs, invalidHandler, typeDefault })
data.argv = argv

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

function clean (data, { types, typeDefs, invalidHandler }) {
function clean (data, { types, typeDefs, invalidHandler, typeDefault }) {
const StringType = typeDefs.String.type
const NumberType = typeDefs.Number.type
const ArrayType = typeDefs.Array.type
const BooleanType = typeDefs.Boolean.type
const DateType = typeDefs.Date.type

const hasTypeDefault = typeof typeDefault !== 'undefined'
if (!hasTypeDefault) {
typeDefault = [false, true, null, StringType, ArrayType]
}

var remove = {}
var typeDefault = [false, true, null, StringType, ArrayType]

Object.keys(data).forEach(function (k) {
if (k === 'argv') {
return
}
var val = data[k]
var isArray = Array.isArray(val)
var type = types[k]
let rawType = types[k]
var type = rawType
if (!isArray) {
val = [val]
}
Expand Down Expand Up @@ -82,7 +87,14 @@ function clean (data, { types, typeDefs, invalidHandler }) {
}

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

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

var d = {}
d[k] = v
debug('prevalidated val', d, v, types[k])
if (!validate(d, k, v, types[k], { typeDefs })) {
debug('prevalidated val', d, v, rawType)
if (!validate(d, k, v, rawType, { typeDefs })) {
if (invalidHandler) {
invalidHandler(k, v, types[k], data)
invalidHandler(k, v, rawType, data)
} else if (invalidHandler !== false) {
debug('invalid: ' + k + '=' + v, types[k])
debug('invalid: ' + k + '=' + v, rawType)
}
return remove
}
debug('validated v', d, v, types[k])
debug('validated v', d, v, rawType)
return d[k]
}).filter(function (v) {
return v !== remove
Expand Down
3 changes: 1 addition & 2 deletions lib/nopt.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const lib = require('./nopt-lib')
const defaultTypeDefs = require('./type-defs')

// This is the version of nopt's API that requires setting typeDefs and invalidHandler
// on the required `nopt` object since it is a singleton. To not do a breaking change
Expand All @@ -9,7 +8,7 @@ const defaultTypeDefs = require('./type-defs')

module.exports = exports = nopt
exports.clean = clean
exports.typeDefs = defaultTypeDefs
exports.typeDefs = lib.typeDefs
exports.lib = lib

function nopt (types = {}, shorthands = {}, args = process.argv, slice = 2) {
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
"tap": "^16.3.0"
},
"tap": {
"lines": 91,
"branches": 87,
"statements": 91,
"lines": 92,
"branches": 86,
"statements": 92,
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
Expand Down
48 changes: 48 additions & 0 deletions test/type-default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const t = require('tap')
const nopt = require('../lib/nopt-lib.js')

t.test('use other type default', (t) => {
const NotAllowed = Symbol('NotAllowed')
const Invalid = Symbol('Invalid')

const clean = (data, opts) => {
const invalids = []
nopt.clean(data, {
types: {
str: nopt.typeDefs.String.type,
invalid: Invalid,
},
typeDefs: {
...nopt.typeDefs,
NotAllowed: { type: NotAllowed, validate: () => false },
Invalid: { type: Invalid, validate: () => false },
},
invalidHandler: (k, v, type) => invalids.push([k, v, type]),
...opts,
})
return {
keys: Object.keys(data),
invalids,
}
}

t.strictSame(clean({
str: 'aaa',
invalid: 'bad',
unknown: 'huh?',
}), {
keys: ['str', 'unknown'],
invalids: [['invalid', 'bad', Invalid]],
}, 'invalid data is removed with clean')

t.strictSame(clean({
str: 'aaa',
invalid: 'bad',
unknown: 'huh?',
}, { typeDefault: NotAllowed }), {
keys: ['str'],
invalids: [['invalid', 'bad', Invalid], ['unknown', 'huh?', NotAllowed]],
}, 'invalid and unknown data is removed with a custom typeDefault')

t.end()
})

0 comments on commit 7ede6c7

Please sign in to comment.