-
-
Notifications
You must be signed in to change notification settings - Fork 212
feat: add async validation #583
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| "@clack/prompts": minor | ||
| "@clack/core": minor | ||
| --- | ||
|
|
||
| Add async validation support to prompts, and validation state rendering to text prompts. |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -209,7 +209,11 @@ export default class Prompt<TValue> { | |||||||||
| this._setUserInput(''); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| private onKeypress(char: string | undefined, key: Key) { | ||||||||||
| private async onKeypress(char: string | undefined, key: Key) { | ||||||||||
| if (this.state === 'validating') { | ||||||||||
| return; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (this._track && key.name !== 'return') { | ||||||||||
| if (key.name && this._isActionKey(char, key)) { | ||||||||||
| this.rl?.write(null, { ctrl: true, name: 'h' }); | ||||||||||
|
|
@@ -238,7 +242,21 @@ export default class Prompt<TValue> { | |||||||||
|
|
||||||||||
| if (key?.name === 'return' && this._shouldSubmit(char, key)) { | ||||||||||
| if (this.opts.validate) { | ||||||||||
| const problem = runValidation(this.opts.validate, this.value); | ||||||||||
| const problemResult = runValidation(this.opts.validate, this.value); | ||||||||||
| let problem: string | Error | undefined; | ||||||||||
| // Only if it is not a string or an Error, we assume | ||||||||||
| // it is a Promise and await it. | ||||||||||
| if ( | ||||||||||
| problemResult !== undefined && | ||||||||||
| typeof problemResult !== 'string' && | ||||||||||
| !(problemResult instanceof Error) | ||||||||||
|
Comment on lines
+250
to
+252
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
wouldn't be a more clean approach for the check to be set this way? |
||||||||||
| ) { | ||||||||||
| this.state = 'validating'; | ||||||||||
| this.render(); | ||||||||||
| problem = await problemResult; | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if the async validator throws (network error, w/e), this will throw inside an un-awaited async handler. that's an unhandled promise rejection, which kills the process in node. probably it might be better to do a try/catch? so that routes the thrown error into |
||||||||||
| } else { | ||||||||||
| problem = problemResult; | ||||||||||
| } | ||||||||||
| if (problem) { | ||||||||||
| this.error = problem instanceof Error ? problem.message : problem; | ||||||||||
| this.state = 'error'; | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is now async but the emitter doesn't await it, so input keeps flowing while a validation is in flight. so i feel like there are 2 problems maybe i'm overthinking u tell me:
submit, close the prompt and then second resolves and tries to render/emit on a finalizad prompt. state gets tangled.valuemid-flight. then the error or submit applies to a stale value, and the rendered dimmed input won't match what was validated.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch!
we may be able to just return early when we're validating, i.e. ignore all key presses during validation