[READ-ONLY] Mirror of https://github.com/bombshell-dev/clack. Effortlessly build beautiful command-line apps bomb.sh/docs/clack/basics/getting-started/
cli command-line command-line-app node prompt prompts
5

Configure Feed

Select the types of activity you want to include in your feed.

fix: validate initial values (#316)

authored by

Paul Valladares and committed by
GitHub
(May 13, 2025, 8:17 AM -0600) 34f52fea 78be1ea6

+125
+5
.changeset/mean-mice-train.md
··· 1 + --- 2 + "@clack/core": patch 3 + --- 4 + 5 + Validates initial values immediately when using text prompts with initialValue and validate props.
+41
examples/basic/text-validation.ts
··· 1 + import { text, note, isCancel } from '@clack/prompts'; 2 + import { setTimeout } from 'node:timers/promises'; 3 + 4 + async function main() { 5 + console.clear(); 6 + 7 + // Example demonstrating the issue with initial value validation 8 + const name = await text({ 9 + message: 'Enter your name (letters and spaces only)', 10 + initialValue: 'John123', // Invalid initial value with numbers 11 + validate: (value) => { 12 + if (!/^[a-zA-Z\s]+$/.test(value)) return 'Name can only contain letters and spaces'; 13 + return undefined; 14 + }, 15 + }); 16 + 17 + if (!isCancel(name)) { 18 + note(`Valid name: ${name}`, 'Success'); 19 + } 20 + 21 + await setTimeout(1000); 22 + 23 + // Example with a valid initial value for comparison 24 + const validName = await text({ 25 + message: 'Enter another name (letters and spaces only)', 26 + initialValue: 'John Doe', // Valid initial value 27 + validate: (value) => { 28 + if (!/^[a-zA-Z\s]+$/.test(value)) return 'Name can only contain letters and spaces'; 29 + return undefined; 30 + }, 31 + }); 32 + 33 + if (!isCancel(validName)) { 34 + note(`Valid name: ${validName}`, 'Success'); 35 + } 36 + 37 + await setTimeout(1000); 38 + 39 + } 40 + 41 + main().catch(console.error);
+9
packages/core/src/prompts/prompt.ts
··· 147 147 this.rl.write(this.opts.initialValue); 148 148 } 149 149 this._setValue(this.opts.initialValue); 150 + 151 + // Validate initial value if validator exists 152 + if (this.opts.validate) { 153 + const problem = this.opts.validate(this.opts.initialValue); 154 + if (problem) { 155 + this.error = problem instanceof Error ? problem.message : problem; 156 + this.state = 'error'; 157 + } 158 + } 150 159 } 151 160 152 161 this.input.on('keypress', this.onKeypress);
+70
packages/core/test/prompts/prompt.test.ts
··· 263 263 264 264 expect(instance.state).to.equal('cancel'); 265 265 }); 266 + 267 + test('validates initial value on prompt start', () => { 268 + const instance = new Prompt({ 269 + input, 270 + output, 271 + render: () => 'foo', 272 + initialValue: 'invalid', 273 + validate: (value) => value === 'valid' ? undefined : 'must be valid', 274 + }); 275 + instance.prompt(); 276 + 277 + expect(instance.state).to.equal('error'); 278 + expect(instance.error).to.equal('must be valid'); 279 + }); 280 + 281 + test('accepts valid initial value', () => { 282 + const instance = new Prompt({ 283 + input, 284 + output, 285 + render: () => 'foo', 286 + initialValue: 'valid', 287 + validate: (value) => value === 'valid' ? undefined : 'must be valid', 288 + }); 289 + instance.prompt(); 290 + 291 + expect(instance.state).to.equal('active'); 292 + expect(instance.error).to.equal(''); 293 + }); 294 + 295 + test('validates initial value with Error object', () => { 296 + const instance = new Prompt({ 297 + input, 298 + output, 299 + render: () => 'foo', 300 + initialValue: 'invalid', 301 + validate: (value) => value === 'valid' ? undefined : new Error('must be valid'), 302 + }); 303 + instance.prompt(); 304 + 305 + expect(instance.state).to.equal('error'); 306 + expect(instance.error).to.equal('must be valid'); 307 + }); 308 + 309 + test('validates initial value with regex validation', () => { 310 + const instance = new Prompt({ 311 + input, 312 + output, 313 + render: () => 'foo', 314 + initialValue: 'Invalid Value $$$', 315 + validate: (value) => /^[A-Z]+$/.test(value) ? undefined : 'Invalid value', 316 + }); 317 + instance.prompt(); 318 + 319 + expect(instance.state).to.equal('error'); 320 + expect(instance.error).to.equal('Invalid value'); 321 + }); 322 + 323 + test('accepts valid initial value with regex validation', () => { 324 + const instance = new Prompt({ 325 + input, 326 + output, 327 + render: () => 'foo', 328 + initialValue: 'VALID', 329 + validate: (value) => /^[A-Z]+$/.test(value) ? undefined : 'Invalid value', 330 + }); 331 + instance.prompt(); 332 + 333 + expect(instance.state).to.equal('active'); 334 + expect(instance.error).to.equal(''); 335 + }); 266 336 });