@@ -730,36 +730,44 @@ function ansiRegex() {
730
730
return new RegExp ( pattern , 'g' ) ;
731
731
}
732
732
733
- export type PromptGroupAwaitedReturn < T > = {
734
- [ P in keyof T ] : Exclude < Awaited < T [ P ] > , symbol > ;
733
+ type Prettify < T > = {
734
+ [ P in keyof T ] : T [ P ] ;
735
+ } & { } ;
736
+
737
+ export type PromptAwaitedReturn < T > = Exclude < Awaited < T > , symbol > ;
738
+
739
+ export type PromptGroupAwaitedReturn < T > = Prettify < {
740
+ [ P in keyof T ] : PromptAwaitedReturn < T [ P ] > ;
741
+ } > ;
742
+
743
+ export type PromptWithOptions < TResults , TResult , TOptions extends Record < string , unknown > = { } > = (
744
+ opts : Prettify <
745
+ {
746
+ results : PromptGroupAwaitedReturn < TResults > ;
747
+ } & TOptions
748
+ >
749
+ ) => TResult ;
750
+
751
+ export type PromptGroup < T > = {
752
+ [ P in keyof T ] : PromptWithOptions < Partial < Omit < T , P > > , void | Promise < T [ P ] | void > > ;
735
753
} ;
736
754
737
755
export interface PromptGroupOptions < T > {
738
756
/**
739
757
* Control how the group can be canceled
740
758
* if one of the prompts is canceled.
741
759
*/
742
- onCancel ?: ( opts : { results : Prettify < Partial < PromptGroupAwaitedReturn < T > > > } ) => void ;
760
+ onCancel ?: PromptWithOptions < Partial < T > , void > ;
743
761
}
744
762
745
- type Prettify < T > = {
746
- [ P in keyof T ] : T [ P ] ;
747
- } & { } ;
748
-
749
- export type PromptGroup < T > = {
750
- [ P in keyof T ] : ( opts : {
751
- results : Prettify < Partial < PromptGroupAwaitedReturn < Omit < T , P > > > > ;
752
- } ) => void | Promise < T [ P ] | void > ;
753
- } ;
754
-
755
763
/**
756
764
* Define a group of prompts to be displayed
757
765
* and return a results of objects within the group
758
766
*/
759
767
export const group = async < T > (
760
768
prompts : PromptGroup < T > ,
761
769
opts ?: PromptGroupOptions < T >
762
- ) : Promise < Prettify < PromptGroupAwaitedReturn < T > > > => {
770
+ ) : Promise < PromptGroupAwaitedReturn < T > > => {
763
771
const results = { } as any ;
764
772
const promptNames = Object . keys ( prompts ) ;
765
773
@@ -784,6 +792,120 @@ export const group = async <T>(
784
792
return results ;
785
793
} ;
786
794
795
+ type NextWorkflowBuilder <
796
+ TResults extends Record < string , unknown > ,
797
+ TKey extends string ,
798
+ TResult ,
799
+ > = WorkflowBuilder <
800
+ Prettify <
801
+ {
802
+ [ Key in keyof TResults ] : Key extends TKey ? TResult : TResults [ Key ] ;
803
+ } & {
804
+ [ Key in TKey as undefined extends TResult ? never : TKey ] : TResult ;
805
+ } & {
806
+ [ Key in TKey as undefined extends TResult ? TKey : never ] ?: TResult ;
807
+ }
808
+ >
809
+ > ;
810
+
811
+ type WorkflowStep < TName extends string , TResults , TResult = unknown > = {
812
+ name : TName ;
813
+ prompt : PromptWithOptions < TResults , TResult > ;
814
+ setResult : boolean ;
815
+ condition ?: PromptWithOptions < TResults , boolean > ;
816
+ } ;
817
+
818
+ class WorkflowBuilder < TResults extends Record < string , unknown > = { } > {
819
+ private results : TResults = { } as TResults ;
820
+ private steps : WorkflowStep < string , TResults > [ ] = [ ] ;
821
+ private cancelCallback : PromptWithOptions < Partial < TResults > , void > | undefined ;
822
+
823
+ public step < TName extends string , TResult > (
824
+ name : TName extends keyof TResults ? never : TName ,
825
+ prompt : PromptWithOptions < TResults , TResult >
826
+ ) : NextWorkflowBuilder < TResults , TName , PromptAwaitedReturn < TResult > > {
827
+ this . steps . push ( { name, prompt, setResult : true } ) ;
828
+ return this as any ;
829
+ }
830
+
831
+ public conditionalStep < TName extends string , TResult > (
832
+ name : TName ,
833
+ condition : PromptWithOptions < TResults , boolean > ,
834
+ prompt : PromptWithOptions < TResults , TResult >
835
+ ) : NextWorkflowBuilder <
836
+ TResults ,
837
+ TName ,
838
+ | ( TName extends keyof TResults ? TResults [ TName ] : never )
839
+ | PromptAwaitedReturn < TResult >
840
+ | undefined
841
+ > {
842
+ this . steps . push ( { name, prompt, condition, setResult : true } ) ;
843
+ return this as any ;
844
+ }
845
+
846
+ public forkStep < TName extends string , TResult extends Record < string , unknown > > (
847
+ name : TName ,
848
+ condition : PromptWithOptions < TResults , boolean > ,
849
+ subWorkflow : PromptWithOptions < TResults , WorkflowBuilder < TResult > >
850
+ ) : NextWorkflowBuilder <
851
+ TResults ,
852
+ TName ,
853
+ ( TName extends keyof TResults ? TResults [ TName ] : never ) | TResult | undefined
854
+ > {
855
+ this . steps . push ( {
856
+ name,
857
+ prompt : ( { results } ) => {
858
+ return subWorkflow ( { results } ) . run ( ) ;
859
+ } ,
860
+ condition,
861
+ setResult : true ,
862
+ } ) ;
863
+ return this as any ;
864
+ }
865
+
866
+ public logStep (
867
+ name : string ,
868
+ prompt : PromptWithOptions < TResults , void >
869
+ ) : WorkflowBuilder < TResults > {
870
+ this . steps . push ( { name, prompt, setResult : false } ) ;
871
+ return this ;
872
+ }
873
+
874
+ public customStep < TName extends string , TResult > (
875
+ step : WorkflowStep < TName , TResults , TResult >
876
+ ) : NextWorkflowBuilder < TResults , TName , PromptAwaitedReturn < TResult > > {
877
+ this . steps . push ( step ) ;
878
+ return this as any ;
879
+ }
880
+
881
+ public onCancel ( cb : PromptWithOptions < Partial < TResults > , void > ) : WorkflowBuilder < TResults > {
882
+ this . cancelCallback = cb ;
883
+ return this ;
884
+ }
885
+
886
+ public async run ( ) : Promise < TResults > {
887
+ for ( const step of this . steps ) {
888
+ if ( step . condition && ! step . condition ( { results : this . results as any } ) ) {
889
+ continue ;
890
+ }
891
+ const result = await step . prompt ( { results : this . results as any } ) ;
892
+ if ( isCancel ( result ) ) {
893
+ this . cancelCallback ?.( { results : this . results as any } ) ;
894
+ continue ;
895
+ }
896
+ if ( step . setResult ) {
897
+ //@ts -ignore
898
+ this . results [ step . name ] = result ;
899
+ }
900
+ }
901
+ return this . results ;
902
+ }
903
+ }
904
+
905
+ export const workflow = ( ) => {
906
+ return new WorkflowBuilder ( ) ;
907
+ } ;
908
+
787
909
export type Task = {
788
910
/**
789
911
* Task title
0 commit comments