Skip to content

Commit

Permalink
fix(command): fix interactive prompts for repeating numbers
Browse files Browse the repository at this point in the history
reconstruct arrays of numeric inputs into individual flag inputs for
nopt. this was working for strings because the values were technically
strings ('foo,bar,baz'). but for numeric flags, it was also being
constructed as a string ('1,2,3'), and nopt would fail validation.
This updates the interactive handler to reconstruct the value as
individual flags for nopt to validate
  • Loading branch information
esatterwhite committed Mar 19, 2021
1 parent 5817b34 commit c810602
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 7 deletions.
1 change: 1 addition & 0 deletions lib/command/flag-to-prompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ function flagToPrompt(name, opt) {
, 'when': opt.when
, 'validate': opt.validate
, 'filter': opt.filter
, 'transformer': opt.transformer
}
}
39 changes: 33 additions & 6 deletions lib/command/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

/**
* Base command class for creating interactive cli programs
* @module module:lib/command
* @module module:seeli/lib/command
* @author Eric Satterwhite
* @requires options
* @requires events
Expand Down Expand Up @@ -31,6 +31,7 @@ const ora = require('ora')
const toArray = require('mout/lang/toArray')
const isFunction = require('mout/lang/isFunction')
const hasOwn = require('mout/object/hasOwn')
const typecast = require('mout/string/typecast')
const toPrompt = require('./flag-to-prompt')
const Registry = require('../registry')
const conf = require('../conf')
Expand Down Expand Up @@ -346,7 +347,7 @@ class Command extends Registry {
const current = this.options.flags[flag]
if (current.interactive === false) continue
if (Array.isArray(current.type)) {
answers[flag] = await ask(flag, cmd, current, this[kPrompt])
answers[flag] = await ask(flag, current, this[kPrompt])
continue
}
const arg = toQuestion(flag, current, answers)
Expand All @@ -357,7 +358,13 @@ class Command extends Registry {
this.parsed = {...this.parsed, ...answers}

for (const [flag, answer] of Object.entries(answers)) {
args.push(`--${flag}=${answer}`)
if (Array.isArray(answer)) {
for (const value of answer) {
args.push(`--${flag}=${value}`)
}
} else {
args.push(`--${flag}=${answer}`)
}
object.set(this.parsed, flag, answer)
}

Expand Down Expand Up @@ -507,10 +514,22 @@ class Command extends Registry {
return this.register(...args)
}

/**
* @typedef {Object} Prompt
* @property {String} type
* @property {String} name
* @property {String} message
* @property {?String[]} choices
* @property {?String|Number|Boolean} default
* @property {?Function} when
* @property {?Function} validate
* @property {?Function} filter
**/

/**
* Convert all registered flags to inquierer compatible prompt objects
* @method module:seeli/lib/command#toPrompt
* @returns {Object[]} array of inquirer prompt objects
* @returns {Prompt[]} array of inquirer prompt objects
**/
toPrompt() {
const prompts = []
Expand Down Expand Up @@ -538,12 +557,19 @@ async function ask(name, opts, inquirer) {
const question = toQuestion(name, opts)
while (true) {
const answer = await inquirer(question)
if (answer[name] === '') break
results.push(answer[name])
const value = typecast(answer[name])
if (value === '') break
if (question.type === 'number' && isNaN(value)) break
results.push(value)
}
return results
}

function transform(input, answers, status) {
if (!status.isFinal) return input
if (this.type === 'number' && isNaN(input)) return ''
return chalk.cyan(input)
}
function toQuestion(flag, opts, answers) {
const arg = toPrompt(flag, opts)

Expand All @@ -553,6 +579,7 @@ function toQuestion(flag, opts, answers) {
arg.when = opts.when ? opts.when.bind(null, answers) : undefined
arg.validate = opts.validate ? opts.validate.bind(null, answers) : undefined
arg.filter = opts.filter ? opts.filter.bind(null, answers) : undefined
arg.transformer = opts.transformer ? opts.transformer : transform.bind(arg)
return arg
}

Expand Down
14 changes: 13 additions & 1 deletion lib/seeli.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
'use strict'

/**
* @module module:seeli/lib/seeli
* @requires mout/lang/toArray
* @requires mout/lang/kindOf
* @requires seeli/lib/command
* @requires seeli/lib/conf
**/
const chalk = require('chalk')
const toArray = require('mout/lang/toArray')
const kindOf = require('mout/lang/kindOf')
const Command = require('./command')
const config = require('./conf.js')
const {PluginException} = require('./exceptions.js')

/**
* Seeli Entrypoint used for registring and managing commands
* @constructor
* @alias module:seeli/lib/seeli
* @extends module:seeli/lib/command
**/
class Seeli extends Command {
constructor(...args) {
super({
Expand Down
3 changes: 3 additions & 0 deletions test/flag-to-prompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ test('flagToPrompt', async (t) => {
, when: undefined
, validate: undefined
, filter: undefined
, transformer: undefined
})
})

Expand All @@ -29,6 +30,7 @@ test('flagToPrompt', async (t) => {
, when: () => {}
, validate: () => {}
, filter: () => {}
, transformer: () => {}
})

t.match(out, {
Expand All @@ -39,6 +41,7 @@ test('flagToPrompt', async (t) => {
, when: Function
, validate: Function
, filter: Function
, transformer: Function
})
})
}).catch(threw)

0 comments on commit c810602

Please sign in to comment.