Skip to content

Commit

Permalink
fix: 100 test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
lukekarrys committed Jun 13, 2023
1 parent 8da1a5e commit 8eecb32
Show file tree
Hide file tree
Showing 9 changed files with 376 additions and 137 deletions.
6 changes: 2 additions & 4 deletions lib/debug.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/* istanbul ignore next */
module.exports = process.env.DEBUG_NOPT || process.env.NOPT_DEBUG
? function () {
console.error.apply(console, arguments)
}
: function () {}
? (...a) => console.error(...a)
: () => {}
145 changes: 85 additions & 60 deletions lib/nopt-lib.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var abbrev = require('abbrev')
const abbrev = require('abbrev')
const debug = require('./debug')
const defaultTypeDefs = require('./type-defs')

Expand All @@ -17,11 +17,39 @@ const getType = (k, { types, fallbackTypes }) => {
return [hasType, type]
}

function nopt (args, { types, fallbackTypes, shorthands, typeDefs, invalidHandler, typeDefault }) {
const assertTypeDefs = (typeDefs) => {
if (!typeDefs) {
throw new Error('`typeDefs` are required')
}
const required = ['String', 'Number', 'Array', 'Boolean', 'Date']
const missing = []
const typeDefTypes = {}
for (const key of required) {
const type = typeDefs[key]?.type
if (type) {
typeDefTypes[`${key}Type`] = type
} else {
missing.push(key)
}
}
if (missing.length) {
throw new Error(`The following required \`typeDefs\` are missing: ${missing.join(', ')}`)
}
return typeDefTypes
}

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

var data = {}
var argv = {
const data = {}
const argv = {
remain: [],
cooked: args,
original: args.slice(0),
Expand All @@ -43,28 +71,25 @@ function nopt (args, { types, fallbackTypes, shorthands, typeDefs, invalidHandle
return data
}

function clean (data, { types, fallbackTypes, 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
function clean (data, { types = {}, fallbackTypes, typeDefs, invalidHandler, typeDefault } = {}) {
const { StringType, NumberType, ArrayType, BooleanType, DateType } = assertTypeDefs(typeDefs)

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

var remove = {}
const remove = {}

Object.keys(data).forEach(function (k) {
Object.keys(data).forEach((k) => {
if (k === 'argv') {
return
}
var val = data[k]
var isArray = Array.isArray(val)
let val = data[k]
debug('val=%j typeof=%s', val, typeof val)
const isArray = Array.isArray(val)
let [hasType, rawType] = getType(k, { types, fallbackTypes })
var type = rawType
let type = rawType
if (!isArray) {
val = [val]
}
Expand All @@ -80,7 +105,7 @@ function clean (data, { types, fallbackTypes, typeDefs, invalidHandler, typeDefa

debug('val=%j', val)
debug('types=', type)
val = val.map(function (v) {
val = val.map((v) => {
// if it's an unknown value, then parse false/true/null/numbers/dates
if (typeof v === 'string') {
debug('string %j', v)
Expand Down Expand Up @@ -118,7 +143,7 @@ function clean (data, { types, fallbackTypes, typeDefs, invalidHandler, typeDefa
v = null
}

var d = {}
const d = {}
d[k] = v
debug('prevalidated val', d, v, rawType)
if (!validate(d, k, v, rawType, { typeDefs })) {
Expand All @@ -131,9 +156,7 @@ function clean (data, { types, fallbackTypes, typeDefs, invalidHandler, typeDefa
}
debug('validated v', d, v, rawType)
return d[k]
}).filter(function (v) {
return v !== remove
})
}).filter((v) => v !== remove)

// if we allow Array specifically, then an empty array is how we
// express 'no value here', not null. Allow it.
Expand All @@ -151,8 +174,8 @@ function clean (data, { types, fallbackTypes, typeDefs, invalidHandler, typeDefa
})
}

function validate (data, k, val, type, { typeDefs }) {
const ArrayType = typeDefs.Array.type
function validate (data, k, val, type, { typeDefs } = {}) {
const { ArrayType } = assertTypeDefs(typeDefs)
// arrays are lists of types.
if (Array.isArray(type)) {
for (let i = 0, l = type.length; i < l; i++) {
Expand Down Expand Up @@ -193,17 +216,17 @@ function validate (data, k, val, type, { typeDefs }) {
}

// now go through the list of typeDefs, validate against each one.
var ok = false
var types = Object.keys(typeDefs)
let ok = false
const types = Object.keys(typeDefs)
for (let i = 0, l = types.length; i < l; i++) {
debug('test type %j %j %j', k, val, types[i])
var t = typeDefs[types[i]]
const t = typeDefs[types[i]]
if (t && (
(type && type.name && t.type && t.type.name) ?
(type.name === t.type.name) :
(type === t.type)
)) {
var d = {}
const d = {}
ok = t.validate(d, k, val) !== false
val = d[k]
if (ok) {
Expand All @@ -220,20 +243,17 @@ function validate (data, k, val, type, { typeDefs }) {
return ok
}

function parse (args, data, remain, { typeDefs, types, fallbackTypes, shorthands }) {
const StringType = typeDefs.String.type
const NumberType = typeDefs.String.type
const ArrayType = typeDefs.Array.type
const BooleanType = typeDefs.Boolean.type
function parse (args, data, remain, { types = {}, shorthands = {}, typeDefs, fallbackTypes } = {}) {
const { StringType, NumberType, ArrayType, BooleanType } = assertTypeDefs(typeDefs)

debug('parse', args, data, remain)

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

for (var i = 0; i < args.length; i++) {
var arg = args[i]
for (let i = 0; i < args.length; i++) {
let arg = args[i]
debug('arg', arg)

if (arg.match(/^-{2,}$/)) {
Expand All @@ -243,30 +263,29 @@ function parse (args, data, remain, { typeDefs, types, fallbackTypes, shorthands
args[i] = '--'
break
}
var hadEq = false
let hadEq = false
if (arg.charAt(0) === '-' && arg.length > 1) {
var at = arg.indexOf('=')
const at = arg.indexOf('=')
if (at > -1) {
hadEq = true
var v = arg.slice(at + 1)
const v = arg.slice(at + 1)
arg = arg.slice(0, at)
args.splice(i, 1, arg, v)
}

// see if it's a shorthand
// if so, splice and back up to re-parse it.
var shRes = resolveShort(arg, shortAbbr, abbrevs, { shorthands })
const shRes = resolveShort(arg, shortAbbr, abbrevs, { shorthands })
debug('arg=%j shRes=%j', arg, shRes)
if (shRes) {
debug(arg, shRes)
args.splice.apply(args, [i, 1].concat(shRes))
if (arg !== shRes[0]) {
i--
continue
}
}
arg = arg.replace(/^-+/, '')
var no = null
let no = null
while (arg.toLowerCase().indexOf('no-') === 0) {
no = !no
arg = arg.slice(3)
Expand All @@ -276,14 +295,14 @@ function parse (args, data, remain, { typeDefs, types, fallbackTypes, shorthands
arg = abbrevs[arg]
}

var [hasType, argType] = getType(arg, { types, fallbackTypes })
var isTypeArray = Array.isArray(argType)
let [hasType, argType] = getType(arg, { types, fallbackTypes })
let isTypeArray = Array.isArray(argType)
if (isTypeArray && argType.length === 1) {
isTypeArray = false
argType = argType[0]
}

var isArray = argType === ArrayType ||
let isArray = argType === ArrayType ||
isTypeArray && argType.indexOf(ArrayType) !== -1

// allow unknown things to be arrays if specified multiple times.
Expand All @@ -294,10 +313,10 @@ function parse (args, data, remain, { typeDefs, types, fallbackTypes, shorthands
isArray = true
}

var val
var la = args[i + 1]
let val
let la = args[i + 1]

var isBool = typeof no === 'boolean' ||
const isBool = typeof no === 'boolean' ||
argType === BooleanType ||
isTypeArray && argType.indexOf(BooleanType) !== -1 ||
(typeof argType === 'undefined' && !hadEq) ||
Expand Down Expand Up @@ -378,7 +397,21 @@ function parse (args, data, remain, { typeDefs, types, fallbackTypes, shorthands
}
}

function resolveShort (arg, shortAbbr, abbrevs, { shorthands }) {
function resolveShort (arg, ...rest) {
let shortAbbr
let abbrevs
let shorthands

if (rest.length === 3) {
shortAbbr = rest[0]
abbrevs = rest[1]
shorthands = rest[2].shorthands || {}
} else {
shorthands = rest[0]?.shorthands || {}
abbrevs = abbrev(Object.keys(rest[0]?.types || {}))
shortAbbr = abbrev(Object.keys(shorthands))
}

// handle single-char shorthands glommed together, like
// npm ls -glp, but only if there is one dash, and only if
// all of the chars are single-char shorthands, and it's
Expand All @@ -401,28 +434,20 @@ function resolveShort (arg, shortAbbr, abbrevs, { shorthands }) {
}

// first check to see if this arg is a set of single-char shorthands
var singles = shorthands.___singles
let singles = shorthands.___singles
if (!singles) {
singles = Object.keys(shorthands).filter(function (s) {
return s.length === 1
}).reduce(function (l, r) {
singles = Object.keys(shorthands).filter((s) => s.length === 1).reduce((l, r) => {
l[r] = true
return l
}, {})
shorthands.___singles = singles
debug('shorthand singles', singles)
}

var chrs = arg.split('').filter(function (c) {
return singles[c]
})
const chrs = arg.split('').filter((c) => singles[c])

if (chrs.join('') === arg) {
return chrs.map(function (c) {
return shorthands[c]
}).reduce(function (l, r) {
return l.concat(r)
}, [])
return chrs.map((c) => shorthands[c]).reduce((l, r) => l.concat(r), [])
}

// if it's an arg abbrev, and not a literal shorthand, then prefer the arg
Expand Down
4 changes: 2 additions & 2 deletions lib/nopt.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ exports.clean = clean
exports.typeDefs = defaultTypeDefs
exports.lib = lib

function nopt (types = {}, shorthands = {}, args = process.argv, slice = 2) {
function nopt (types, shorthands, args = process.argv, slice = 2) {
return lib.nopt(args.slice(slice), {
types,
shorthands: shorthands || {},
shorthands,
typeDefs: exports.typeDefs,
invalidHandler: exports.invalidHandler,
})
Expand Down
16 changes: 8 additions & 8 deletions lib/type-defs.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var url = require('url')
var path = require('path')
var Stream = require('stream').Stream
var os = require('os')
const url = require('url')
const path = require('path')
const Stream = require('stream').Stream
const os = require('os')
const debug = require('./debug')

function validateString (data, k, val) {
Expand All @@ -18,9 +18,9 @@ function validatePath (data, k, val) {

val = String(val)

var isWin = process.platform === 'win32'
var homePattern = isWin ? /^~(\/|\\)/ : /^~\//
var home = os.homedir()
const isWin = process.platform === 'win32'
const homePattern = isWin ? /^~(\/|\\)/ : /^~\//
const home = os.homedir()

if (home && val.match(homePattern)) {
data[k] = path.resolve(home, val.slice(2))
Expand All @@ -39,7 +39,7 @@ function validateNumber (data, k, val) {
}

function validateDate (data, k, val) {
var s = Date.parse(val)
const s = Date.parse(val)
debug('validate Date %j %j %j', k, val, s)
if (isNaN(s)) {
return false
Expand Down
3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@
"tap": "^16.3.0"
},
"tap": {
"statements": 94,
"branches": 88,
"lines": 94,
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
Expand Down
Loading

0 comments on commit 8eecb32

Please sign in to comment.