From 9343dec76685a242c4c2b963168ae69c676b2d13 Mon Sep 17 00:00:00 2001 From: Sean Zellmer Date: Fri, 2 May 2025 13:13:15 -0500 Subject: [PATCH 1/3] Throw Error when autosubmitting params defaults which dont validate In the case that a default for a param is invalid by its own validation function, an Error will be thrown reporting the param's `name` and the `msg. --- terminal.js | 12 ++++++-- test/terminal.test.js | 72 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/terminal.js b/terminal.js index 1a191a2f..32ef26f1 100644 --- a/terminal.js +++ b/terminal.js @@ -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..c60b3583 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('interace - 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('interace - 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() +}) From 96942249a295dc426a09fc9ecd252035aafbc431 Mon Sep 17 00:00:00 2001 From: Sean Zellmer Date: Fri, 2 May 2025 15:10:38 -0500 Subject: [PATCH 2/3] Correct spelling in interact tests --- test/terminal.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/terminal.test.js b/test/terminal.test.js index c60b3583..d2fb4c91 100644 --- a/test/terminal.test.js +++ b/test/terminal.test.js @@ -288,7 +288,7 @@ test('permit function with encrypted key', async function (t) { t.is(exitedRes, true, 'Pear.exit ok') }) -test('interace - run - autosubmit validation fails', async function (t) { +test('interact - run - autosubmit validation fails', async function (t) { t.plan(1) const { teardown } = rig() @@ -317,7 +317,7 @@ test('interace - run - autosubmit validation fails', async function (t) { t.end() }) -test('interace - run - autosubmit validation passes', async function (t) { +test('interact - run - autosubmit validation passes', async function (t) { t.plan(2) const { teardown } = rig() From e77b47809d9e80bdef1b84325a0f5e876e1a4d80 Mon Sep 17 00:00:00 2001 From: Sean Zellmer Date: Fri, 2 May 2025 15:50:56 -0500 Subject: [PATCH 3/3] Check if readline input has `setMode()` to check Pipe stdin in Interact --- terminal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terminal.js b/terminal.js index 32ef26f1..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()