diff --git a/README.md b/README.md index 20030a7..da07c55 100644 --- a/README.md +++ b/README.md @@ -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 \| 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` | @@ -110,7 +111,7 @@ type TableRow = { ## 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 = TableAnswer[] diff --git a/src/index.mts b/src/index.mts index 36269eb..2932a19 100644 --- a/src/index.mts +++ b/src/index.mts @@ -44,6 +44,7 @@ type TableConfig = { required?: boolean, loop?: boolean, allowUnset?: boolean, + ignoreEmptyAnswers?: boolean, validate?: (answers: TableAnswers) => boolean | string | Promise, sumUp?: (answers: TableAnswers) => string } @@ -202,6 +203,7 @@ export default createPrompt( loop = true, validate = () => true, sumUp = () => '', + ignoreEmptyAnswers = true, } = config const [status, setStatus] = useState('idle') @@ -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 @@ -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') @@ -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) diff --git a/test/normal.test.mts b/test/normal.test.mts index 55259d0..c523062 100644 --- a/test/normal.test.mts +++ b/test/normal.test.mts @@ -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, { + 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 to select, to move rows, 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 = [ { @@ -92,7 +156,7 @@ describe('table-multiple prompt [normal]', () => { }, ], rows: choices, - validate: (answers: TableAnswers) => answers.every(answer => answer.answers.length && answer.answers.every(value => value === 'A')) + validate: (answers: TableAnswers) => answers.length === 2 && answers.every(answer => answer.answers.length && answer.answers.every(value => value === 'A')) }) expect(getScreen()).toMatchInlineSnapshot([ @@ -177,7 +241,7 @@ describe('table-multiple prompt [normal]', () => { rows: choices, validate: (answers: TableAnswers): Promise => 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) }) })