@@ -844,36 +844,49 @@ export const spinner = ({ indicator = 'dots' }: SpinnerOptions = {}) => {
844844 } ;
845845} ;
846846
847- export type PromptGroupAwaitedReturn < T > = {
848- [ P in keyof T ] : Exclude < Awaited < T [ P ] > , symbol > ;
847+ type Prettify < T > = {
848+ [ P in keyof T ] : T [ P ] ;
849+ } & { } ;
850+
851+ export type PromptAwaitedReturn < T > = Exclude < Awaited < T > , symbol > ;
852+
853+ export type PromptGroupAwaitedReturn < T > = Prettify < {
854+ [ P in keyof T ] : PromptAwaitedReturn < T [ P ] > ;
855+ } > ;
856+
857+ export type PromptWithOptions <
858+ TResults ,
859+ TResult ,
860+ // biome-ignore lint/complexity/noBannedTypes: {} is initializing a empty object
861+ TOptions extends Record < string , unknown > = { } ,
862+ > = (
863+ opts : Prettify <
864+ {
865+ results : PromptGroupAwaitedReturn < TResults > ;
866+ } & TOptions
867+ >
868+ ) => TResult ;
869+
870+ export type PromptGroup < T > = {
871+ [ P in keyof T ] : PromptWithOptions < Partial < Omit < T , P > > , undefined | Promise < T [ P ] | undefined > > ;
849872} ;
850873
851874export interface PromptGroupOptions < T > {
852875 /**
853876 * Control how the group can be canceled
854877 * if one of the prompts is canceled.
855878 */
856- onCancel ?: ( opts : { results : Prettify < Partial < PromptGroupAwaitedReturn < T > > > } ) => void ;
879+ onCancel ?: PromptWithOptions < Partial < T > , void > ;
857880}
858881
859- type Prettify < T > = {
860- [ P in keyof T ] : T [ P ] ;
861- } & { } ;
862-
863- export type PromptGroup < T > = {
864- [ P in keyof T ] : ( opts : {
865- results : Prettify < Partial < PromptGroupAwaitedReturn < Omit < T , P > > > > ;
866- } ) => undefined | Promise < T [ P ] | undefined > ;
867- } ;
868-
869882/**
870883 * Define a group of prompts to be displayed
871884 * and return a results of objects within the group
872885 */
873886export const group = async < T > (
874887 prompts : PromptGroup < T > ,
875888 opts ?: PromptGroupOptions < T >
876- ) : Promise < Prettify < PromptGroupAwaitedReturn < T > > > => {
889+ ) : Promise < PromptGroupAwaitedReturn < T > > => {
877890 const results = { } as any ;
878891 const promptNames = Object . keys ( prompts ) ;
879892
@@ -898,6 +911,121 @@ export const group = async <T>(
898911 return results ;
899912} ;
900913
914+ type NextWorkflowBuilder <
915+ TResults extends Record < string , unknown > ,
916+ TKey extends string ,
917+ TResult ,
918+ > = WorkflowBuilder <
919+ Prettify <
920+ {
921+ [ Key in keyof TResults ] : Key extends TKey ? TResult : TResults [ Key ] ;
922+ } & {
923+ [ Key in TKey as undefined extends TResult ? never : TKey ] : TResult ;
924+ } & {
925+ [ Key in TKey as undefined extends TResult ? TKey : never ] ?: TResult ;
926+ }
927+ >
928+ > ;
929+
930+ type WorkflowStep < TName extends string , TResults , TResult = unknown > = {
931+ name : TName ;
932+ prompt : PromptWithOptions < TResults , TResult > ;
933+ setResult : boolean ;
934+ condition ?: PromptWithOptions < TResults , boolean > ;
935+ } ;
936+
937+ // biome-ignore lint/complexity/noBannedTypes: <explanation>
938+ class WorkflowBuilder < TResults extends Record < string , unknown > = { } > {
939+ private results : TResults = { } as TResults ;
940+ private steps : WorkflowStep < string , TResults > [ ] = [ ] ;
941+ private cancelCallback : PromptWithOptions < Partial < TResults > , void > | undefined ;
942+
943+ public step < TName extends string , TResult > (
944+ name : TName extends keyof TResults ? never : TName ,
945+ prompt : PromptWithOptions < TResults , TResult >
946+ ) : NextWorkflowBuilder < TResults , TName , PromptAwaitedReturn < TResult > > {
947+ this . steps . push ( { name, prompt, setResult : true } ) ;
948+ return this as any ;
949+ }
950+
951+ public conditionalStep < TName extends string , TResult > (
952+ name : TName ,
953+ condition : PromptWithOptions < TResults , boolean > ,
954+ prompt : PromptWithOptions < TResults , TResult >
955+ ) : NextWorkflowBuilder <
956+ TResults ,
957+ TName ,
958+ | ( TName extends keyof TResults ? TResults [ TName ] : never )
959+ | PromptAwaitedReturn < TResult >
960+ | undefined
961+ > {
962+ this . steps . push ( { name, prompt, condition, setResult : true } ) ;
963+ return this as any ;
964+ }
965+
966+ public forkStep < TName extends string , TResult extends Record < string , unknown > > (
967+ name : TName ,
968+ condition : PromptWithOptions < TResults , boolean > ,
969+ subWorkflow : PromptWithOptions < TResults , WorkflowBuilder < TResult > >
970+ ) : NextWorkflowBuilder <
971+ TResults ,
972+ TName ,
973+ ( TName extends keyof TResults ? TResults [ TName ] : never ) | TResult | undefined
974+ > {
975+ this . steps . push ( {
976+ name,
977+ prompt : ( { results } ) => {
978+ return subWorkflow ( { results } ) . run ( ) ;
979+ } ,
980+ condition,
981+ setResult : true ,
982+ } ) ;
983+ return this as any ;
984+ }
985+
986+ public logStep (
987+ name : string ,
988+ prompt : PromptWithOptions < TResults , void >
989+ ) : WorkflowBuilder < TResults > {
990+ this . steps . push ( { name, prompt, setResult : false } ) ;
991+ return this ;
992+ }
993+
994+ public customStep < TName extends string , TResult > (
995+ step : WorkflowStep < TName , TResults , TResult >
996+ ) : NextWorkflowBuilder < TResults , TName , PromptAwaitedReturn < TResult > > {
997+ this . steps . push ( step ) ;
998+ return this as any ;
999+ }
1000+
1001+ public onCancel ( cb : PromptWithOptions < Partial < TResults > , void > ) : WorkflowBuilder < TResults > {
1002+ this . cancelCallback = cb ;
1003+ return this ;
1004+ }
1005+
1006+ public async run ( ) : Promise < TResults > {
1007+ for ( const step of this . steps ) {
1008+ if ( step . condition && ! step . condition ( { results : this . results as any } ) ) {
1009+ continue ;
1010+ }
1011+ const result = await step . prompt ( { results : this . results as any } ) ;
1012+ if ( isCancel ( result ) ) {
1013+ this . cancelCallback ?.( { results : this . results as any } ) ;
1014+ continue ;
1015+ }
1016+ if ( step . setResult ) {
1017+ //@ts -ignore
1018+ this . results [ step . name ] = result ;
1019+ }
1020+ }
1021+ return this . results ;
1022+ }
1023+ }
1024+
1025+ export const workflow = ( ) => {
1026+ return new WorkflowBuilder ( ) ;
1027+ } ;
1028+
9011029export type Task = {
9021030 /**
9031031 * Task title
0 commit comments