Skip to content

Commit

Permalink
feat: add fallback option to use function when looking up types
Browse files Browse the repository at this point in the history
  • Loading branch information
lukekarrys committed Jun 14, 2023
1 parent 082bad3 commit 008c672
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 15 deletions.
37 changes: 25 additions & 12 deletions lib/nopt-lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,22 @@ var abbrev = require('abbrev')
const debug = require('./debug')
const defaultTypeDefs = require('./type-defs')

function nopt (args, { types, shorthands, typeDefs, invalidHandler, typeDefault }) {
const hasOwn = (o, k) => Object.prototype.hasOwnProperty.call(o, k)

const getType = (k, { types, dynamicTypes }) => {
let hasType = hasOwn(types, k)
let type = types[k]
if (!hasType && typeof dynamicTypes === 'function') {
const matchedType = dynamicTypes(k)
if (matchedType !== undefined) {
type = matchedType
hasType = true
}
}
return [hasType, type]
}

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

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

parse(args, data, argv.remain, { typeDefs, types, shorthands })
parse(args, data, argv.remain, { typeDefs, types, dynamicTypes, shorthands })

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

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

function clean (data, { types, typeDefs, invalidHandler, typeDefault }) {
function clean (data, { types, dynamicTypes, typeDefs, invalidHandler, typeDefault }) {
const StringType = typeDefs.String.type
const NumberType = typeDefs.Number.type
const ArrayType = typeDefs.Array.type
Expand All @@ -48,7 +63,7 @@ function clean (data, { types, typeDefs, invalidHandler, typeDefault }) {
}
var val = data[k]
var isArray = Array.isArray(val)
let rawType = types[k]
let [hasType, rawType] = getType(k, { types, dynamicTypes })
var type = rawType
if (!isArray) {
val = [val]
Expand Down Expand Up @@ -86,7 +101,7 @@ function clean (data, { types, typeDefs, invalidHandler, typeDefault }) {
}
}

if (!Object.prototype.hasOwnProperty.call(types, k)) {
if (!hasType) {
if (!hasTypeDefault) {
return v
}
Expand Down Expand Up @@ -205,7 +220,7 @@ function validate (data, k, val, type, { typeDefs }) {
return ok
}

function parse (args, data, remain, { typeDefs, types, shorthands }) {
function parse (args, data, remain, { typeDefs, types, dynamicTypes, shorthands }) {
const StringType = typeDefs.String.type
const NumberType = typeDefs.String.type
const ArrayType = typeDefs.Array.type
Expand All @@ -214,6 +229,7 @@ function parse (args, data, remain, { typeDefs, types, shorthands }) {
debug('parse', args, data, remain)

var abbrevs = abbrev(Object.keys(types))
debug('abbrevs=%j', abbrevs)
var shortAbbr = abbrev(Object.keys(shorthands))

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

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

// allow unknown things to be arrays if specified multiple times.
if (
!Object.prototype.hasOwnProperty.call(types, arg) &&
Object.prototype.hasOwnProperty.call(data, arg)
) {
if (!hasType && hasOwn(data, arg)) {
if (!Array.isArray(data[arg])) {
data[arg] = [data[arg]]
}
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,
"statements": 94,
"branches": 88,
"lines": 94,
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
Expand Down
72 changes: 72 additions & 0 deletions test/dynamic-types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const t = require('tap')
const nopt = require('../lib/nopt-lib.js')

t.test('fallback types', (t) => {
const n = (dynamicTypes) => {
const args = [
'--hello', '100',
'--goodbye', '50',
'--hat=blue',
'--mult', '200',
'--mult', '300',
'--multeq=111',
'--multeq=999',
]
const res = nopt.nopt(args, {
types: { hello: nopt.typeDefs.Number.type },
dynamicTypes,
typeDefs: nopt.typeDefs,
shorthands: {},
})
delete res.argv.cooked
delete res.argv.original
return res
}

t.strictSame(n(), {
hello: 100,
goodbye: true,
hat: 'blue',
mult: [
true,
true,
],
multeq: [
'111',
'999',
],
argv: {
remain: [
'50',
'200',
'300',
],
},
}, 'parse args with no fallback')

t.strictSame(n((k) => {
if (k.startsWith('goo')) {
return nopt.typeDefs.Number.type
}
if (k === 'mult') {
return [nopt.typeDefs.Number.type, nopt.typeDefs.Array.type]
}
}), {
hello: 100,
goodbye: 50,
hat: 'blue',
mult: [
200,
300,
],
multeq: [
'111',
'999',
],
argv: {
remain: [],
},
}, 'parse args with no fallback')

t.end()
})

0 comments on commit 008c672

Please # to comment.