Skip to content

Commit

Permalink
[Feature] Add ignoreEmptyAnswers option
Browse files Browse the repository at this point in the history
  • Loading branch information
Bartheleway committed Oct 6, 2024
1 parent 5628a54 commit 8389aea
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 8 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ const answer = await tableMultiple({
| - | - | - | - | - |
| allowUnset | `boolean` | no | If `multiple` is set to false and this one to `true`, you can unselect the selected choice. | `false`
| columns | `(TableQuestionColumn<Value> \| TableColumn)[]` | yes | The list of columns to display. |
| loop | `boolean` | no | Indicate if you can loop over table rows. | `true`
| ignoreEmptyAnswers | `boolean` | no | Indicate if `validate`, `sumUp` and output contains rows with no answers or not. | `true`
| loop | `boolean` | no | Indicate if you can loop over table rows. | `true`
| message | `string` | yes | The question to ask. |
| multiple | `boolean` | no | Indicate if rows allows multiple choices or not. | `false`
| pageSize | `number` | no | The number of lines to display. | `7` |
Expand Down Expand Up @@ -110,7 +111,7 @@ type TableRow<Value> = {
## Returned value
This inquirer prompt will return an array. Each responded row will contains the row value (`choice`) along with selected answers.
This inquirer prompt will return an array. Each responded row will contains the row value (`choice`) along with selected answers. By default only rows with answers will be returned, you can change this with `ignoreEmptyAnswers: false`
```typescript
type TableAnswers<Value> = TableAnswer<Value>[]
Expand Down
13 changes: 9 additions & 4 deletions src/index.mts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type TableConfig<Value extends object | string | number> = {
required?: boolean,
loop?: boolean,
allowUnset?: boolean,
ignoreEmptyAnswers?: boolean,
validate?: (answers: TableAnswers<Value>) => boolean | string | Promise<string | boolean>,
sumUp?: (answers: TableAnswers<Value>) => string
}
Expand Down Expand Up @@ -202,6 +203,7 @@ export default createPrompt(
loop = true,
validate = () => true,
sumUp = () => '',
ignoreEmptyAnswers = true,
} = config

const [status, setStatus] = useState<Status>('idle')
Expand Down Expand Up @@ -241,6 +243,8 @@ export default createPrompt(
}, [config.rows, config.columns])

useKeypress(async (key) => {
const answers = ignoreEmptyAnswers ? values.filter(row => row.answers.length) : values

// Ignore keypress while our prompt is doing other processing.
if (status !== 'idle') {
return
Expand All @@ -251,18 +255,18 @@ export default createPrompt(

if (
config.required
&& !values.find(value => value.answers.length)
&& !answers.find(value => value.answers.length)
) {
setError('Please select at least one value.')
setStatus('idle')
}
else {
const isValid = await validate(values)
const isValid = await validate(answers)

if (isValid === true) {
setShowHelpTip(false)
setStatus('done')
done(values.filter(value => value.answers.length))
done(answers)
} else {
setError(isValid || 'You must provide a valid value')
setStatus('idle')
Expand Down Expand Up @@ -392,7 +396,8 @@ export default createPrompt(
if (status !== 'done') {
printToShell.push('', table.toString())
} else {
const summarized = sumUp(values)
const answers = ignoreEmptyAnswers ? values.filter(row => row.answers.length) : values
const summarized = sumUp(answers)

if (summarized) {
printToShell.push(summarized)
Expand Down
68 changes: 66 additions & 2 deletions test/normal.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,70 @@ describe('table-multiple prompt [normal]', () => {
])
})

it('return all rows', async () => {
const choices = [
{
value: '1',
title: 'Test 1',
},
{
value: '2',
title: 'Test 2',
}
]

const { answer, events, getScreen } = await render(tableMultiple<string>, {
message: 'What do you want?',
columns: [
{
title: 'A?',
value: 'A',
},
{
title: 'B?',
value: 'B',
},
],
rows: choices,
ignoreEmptyAnswers: false
})

expect(getScreen()).toMatchInlineSnapshot([
`"? What do you want? (Press <space> to select, <Up and Down> to move rows, <Left${EXTRA_SPACE}`,
'and Right> to move columns)',
'',
'┌──────────┬───────┬───────┐',
'│ 1-2 of 2 │ A? │ B? │',
'├──────────┼───────┼───────┤',
'│ Test 1 │ [ ◯ ] │ ◯ │',
'├──────────┼───────┼───────┤',
'│ Test 2 │ ◯ │ ◯ │',
'└──────────┴───────┴───────┘"'
].join('\n'))

events.keypress('space')
events.keypress('enter')

await Promise.resolve()

expect(getScreen()).toMatchInlineSnapshot([
'"✔ What do you want?"',
].join('\n'))

await expect(answer).resolves.toHaveLength(2)

await expect(answer).resolves.toEqual([
{
choice: choices[0],
answers: ['A'],
},
{
choice: choices[1],
answers: [],
}
])
})

it('handle synchronous validation', async () => {
const choices = [
{
Expand All @@ -92,7 +156,7 @@ describe('table-multiple prompt [normal]', () => {
},
],
rows: choices,
validate: (answers: TableAnswers<string>) => answers.every(answer => answer.answers.length && answer.answers.every(value => value === 'A'))
validate: (answers: TableAnswers<string>) => answers.length === 2 && answers.every(answer => answer.answers.length && answer.answers.every(value => value === 'A'))
})

expect(getScreen()).toMatchInlineSnapshot([
Expand Down Expand Up @@ -177,7 +241,7 @@ describe('table-multiple prompt [normal]', () => {
rows: choices,
validate: (answers: TableAnswers<string>): Promise<boolean | string> => new Promise(resolve => {
setTimeout(() => {
resolve(answers.every(answer => answer.answers.length && answer.answers.every(value => value === 'A')) || 'Select all "A"')
resolve(answers.length === 2 && answers.every(answer => answer.answers.length && answer.answers.every(value => value === 'A')) || 'Select all "A"')
}, 300)
})
})
Expand Down

0 comments on commit 8389aea

Please sign in to comment.