diff --git a/terminal.js b/terminal.js index 1a191a2f..77debcc8 100644 --- a/terminal.js +++ b/terminal.js @@ -108,7 +108,7 @@ class Interact { output: opts.masked ? new Writable({ write: mask }) : stdio.out }) - this._rl.input?.setMode(tty.constants.MODE_RAW) + if ('setMode' in this._rl.input) this._rl.input.setMode(tty.constants.MODE_RAW) this._rl.on('close', () => { console.log() // new line Bare.exit() @@ -147,12 +147,20 @@ class Interact { return fields } - #autosubmit () { + async #autosubmit () { const fields = {} const defaults = this._defaults while (this._params.length) { const param = this._params.shift() - fields[param.name] = defaults[param.name] ?? param.default + let answer = defaults[param.name] ?? param.default + const valid = !param.validation || await param.validation(answer) + if (valid) { + if (typeof answer === 'string') answer = answer.replace(this.constructor.rx, '') + fields[param.name] = answer + } else if (param.validation) { + stdio.err.write(`Validating '${param.name}' parameter default failed: ${param.msg}\n`) + throw Error(`Validating '${param.name}' parameter default failed: ${param.msg}\n`) + } } return fields } diff --git a/test/terminal.test.js b/test/terminal.test.js index 7e721b2d..d2fb4c91 100644 --- a/test/terminal.test.js +++ b/test/terminal.test.js @@ -287,3 +287,75 @@ test('permit function with encrypted key', async function (t) { const exitedRes = await exited t.is(exitedRes, true, 'Pear.exit ok') }) + +test('interact - run - autosubmit validation fails', async function (t) { + t.plan(1) + + const { teardown } = rig() + t.teardown(teardown) + + const { Interact, stdio } = require('../terminal') + + let output = '' + const originalWrite = stdio.err.write + stdio.err.write = (str) => { output += str } + t.teardown(() => { stdio.err.write = originalWrite }) + + const prompt = new Interact('', [{ + name: 'foo', + validation: () => false, // always fail + default: 'biz', + msg: 'must be a square circle' + }]) + + try { + await prompt.run({ autosubmit: true }) + } catch (e) { + t.is(output, "Validating 'foo' parameter default failed: must be a square circle\n", 'got error for param') + } + + t.end() +}) + +test('interact - run - autosubmit validation passes', async function (t) { + t.plan(2) + + const { teardown } = rig() + t.teardown(teardown) + + const { Interact, stdio } = require('../terminal') + + let output = '' + const originalWrite = stdio.err.write + stdio.err.write = (str) => { output += str } + t.teardown(() => { stdio.err.write = originalWrite }) + + const prompt = new Interact('', [ + { + name: 'foo', + validation: () => true, // always passes + default: 'bar', + msg: 'anything or nothing is good' + }, + { + name: 'biz', + default: 'baz', + msg: 'vibing' + } + ]) + + let locals + try { + locals = await prompt.run({ autosubmit: true }) + } catch (e) { + t.fail('Shouldnt fail validation') + } + + t.is(output, '', 'output stdio is silent') + t.alike(locals, { + foo: 'bar', + biz: 'baz' + }, 'has defaults as output') + + t.end() +})