@@ -98,14 +98,17 @@ const limitOptions = <TOption>(params: LimitOptionsParams<TOption>): string[] =>
9898 } ) ;
9999} ;
100100
101- export interface TextOptions {
101+ export interface CommonOptions {
102+ input ?: Readable ;
103+ output ?: Writable ;
104+ }
105+
106+ export interface TextOptions extends CommonOptions {
102107 message : string ;
103108 placeholder ?: string ;
104109 defaultValue ?: string ;
105110 initialValue ?: string ;
106111 validate ?: ( value : string ) => string | Error | undefined ;
107- input ?: Readable ;
108- output ?: Writable ;
109112}
110113export const text = ( opts : TextOptions ) => {
111114 return new TextPrompt ( {
@@ -140,7 +143,7 @@ export const text = (opts: TextOptions) => {
140143 } ) . prompt ( ) as Promise < string | symbol > ;
141144} ;
142145
143- export interface PasswordOptions {
146+ export interface PasswordOptions extends CommonOptions {
144147 message : string ;
145148 mask ?: string ;
146149 validate ?: ( value : string ) => string | Error | undefined ;
@@ -149,6 +152,8 @@ export const password = (opts: PasswordOptions) => {
149152 return new PasswordPrompt ( {
150153 validate : opts . validate ,
151154 mask : opts . mask ?? S_PASSWORD_MASK ,
155+ input : opts . input ,
156+ output : opts . output ,
152157 render ( ) {
153158 const title = `${ color . gray ( S_BAR ) } \n${ symbol ( this . state ) } ${ opts . message } \n` ;
154159 const value = this . valueWithCursor ;
@@ -172,7 +177,7 @@ export const password = (opts: PasswordOptions) => {
172177 } ) . prompt ( ) as Promise < string | symbol > ;
173178} ;
174179
175- export interface ConfirmOptions {
180+ export interface ConfirmOptions extends CommonOptions {
176181 message : string ;
177182 active ?: string ;
178183 inactive ?: string ;
@@ -184,6 +189,8 @@ export const confirm = (opts: ConfirmOptions) => {
184189 return new ConfirmPrompt ( {
185190 active,
186191 inactive,
192+ input : opts . input ,
193+ output : opts . output ,
187194 initialValue : opts . initialValue ?? true ,
188195 render ( ) {
189196 const title = `${ color . gray ( S_BAR ) } \n${ symbol ( this . state ) } ${ opts . message } \n` ;
@@ -252,7 +259,7 @@ export type Option<Value> = Value extends Primitive
252259 hint ?: string ;
253260 } ;
254261
255- export interface SelectOptions < Value > {
262+ export interface SelectOptions < Value > extends CommonOptions {
256263 message : string ;
257264 options : Option < Value > [ ] ;
258265 initialValue ?: Value ;
@@ -278,6 +285,8 @@ export const select = <Value>(opts: SelectOptions<Value>) => {
278285
279286 return new SelectPrompt ( {
280287 options : opts . options ,
288+ input : opts . input ,
289+ output : opts . output ,
281290 initialValue : opts . initialValue ,
282291 render ( ) {
283292 const title = `${ color . gray ( S_BAR ) } \n${ symbol ( this . state ) } ${ opts . message } \n` ;
@@ -327,6 +336,8 @@ export const selectKey = <Value extends string>(opts: SelectOptions<Value>) => {
327336
328337 return new SelectKeyPrompt ( {
329338 options : opts . options ,
339+ input : opts . input ,
340+ output : opts . output ,
330341 initialValue : opts . initialValue ,
331342 render ( ) {
332343 const title = `${ color . gray ( S_BAR ) } \n${ symbol ( this . state ) } ${ opts . message } \n` ;
@@ -351,7 +362,7 @@ export const selectKey = <Value extends string>(opts: SelectOptions<Value>) => {
351362 } ) . prompt ( ) as Promise < Value | symbol > ;
352363} ;
353364
354- export interface MultiSelectOptions < Value > {
365+ export interface MultiSelectOptions < Value > extends CommonOptions {
355366 message : string ;
356367 options : Option < Value > [ ] ;
357368 initialValues ?: Value [ ] ;
@@ -389,6 +400,8 @@ export const multiselect = <Value>(opts: MultiSelectOptions<Value>) => {
389400
390401 return new MultiSelectPrompt ( {
391402 options : opts . options ,
403+ input : opts . input ,
404+ output : opts . output ,
392405 initialValues : opts . initialValues ,
393406 required : opts . required ?? true ,
394407 cursorAt : opts . cursorAt ,
@@ -461,7 +474,7 @@ export const multiselect = <Value>(opts: MultiSelectOptions<Value>) => {
461474 } ) . prompt ( ) as Promise < Value [ ] | symbol > ;
462475} ;
463476
464- export interface GroupMultiSelectOptions < Value > {
477+ export interface GroupMultiSelectOptions < Value > extends CommonOptions {
465478 message : string ;
466479 options : Record < string , Option < Value > [ ] > ;
467480 initialValues ?: Value [ ] ;
@@ -522,6 +535,8 @@ export const groupMultiselect = <Value>(opts: GroupMultiSelectOptions<Value>) =>
522535
523536 return new GroupMultiSelectPrompt ( {
524537 options : opts . options ,
538+ input : opts . input ,
539+ output : opts . output ,
525540 initialValues : opts . initialValues ,
526541 required : opts . required ?? true ,
527542 cursorAt : opts . cursorAt ,
@@ -614,9 +629,10 @@ export const groupMultiselect = <Value>(opts: GroupMultiSelectOptions<Value>) =>
614629 } ) . prompt ( ) as Promise < Value [ ] | symbol > ;
615630} ;
616631
617- export const note = ( message = '' , title = '' ) => {
632+ export const note = ( message = '' , title = '' , opts ?: CommonOptions ) => {
618633 const lines = `\n${ message } \n` . split ( '\n' ) ;
619634 const titleLen = strip ( title ) . length ;
635+ const output : Writable = opts ?. output ?? process . stdout ;
620636 const len =
621637 Math . max (
622638 lines . reduce ( ( sum , ln ) => {
@@ -633,59 +649,71 @@ export const note = (message = '', title = '') => {
633649 ) } `
634650 )
635651 . join ( '\n' ) ;
636- process . stdout . write (
652+ output . write (
637653 `${ color . gray ( S_BAR ) } \n${ color . green ( S_STEP_SUBMIT ) } ${ color . reset ( title ) } ${ color . gray (
638654 S_BAR_H . repeat ( Math . max ( len - titleLen - 1 , 1 ) ) + S_CORNER_TOP_RIGHT
639655 ) } \n${ msg } \n${ color . gray ( S_CONNECT_LEFT + S_BAR_H . repeat ( len + 2 ) + S_CORNER_BOTTOM_RIGHT ) } \n`
640656 ) ;
641657} ;
642658
643- export const cancel = ( message = '' ) => {
644- process . stdout . write ( `${ color . gray ( S_BAR_END ) } ${ color . red ( message ) } \n\n` ) ;
659+ export const cancel = ( message = '' , opts ?: CommonOptions ) => {
660+ const output : Writable = opts ?. output ?? process . stdout ;
661+ output . write ( `${ color . gray ( S_BAR_END ) } ${ color . red ( message ) } \n\n` ) ;
645662} ;
646663
647- export const intro = ( title = '' ) => {
648- process . stdout . write ( `${ color . gray ( S_BAR_START ) } ${ title } \n` ) ;
664+ export const intro = ( title = '' , opts ?: CommonOptions ) => {
665+ const output : Writable = opts ?. output ?? process . stdout ;
666+ output . write ( `${ color . gray ( S_BAR_START ) } ${ title } \n` ) ;
649667} ;
650668
651- export const outro = ( message = '' ) => {
652- process . stdout . write ( `${ color . gray ( S_BAR ) } \n${ color . gray ( S_BAR_END ) } ${ message } \n\n` ) ;
669+ export const outro = ( message = '' , opts ?: CommonOptions ) => {
670+ const output : Writable = opts ?. output ?? process . stdout ;
671+ output . write ( `${ color . gray ( S_BAR ) } \n${ color . gray ( S_BAR_END ) } ${ message } \n\n` ) ;
653672} ;
654673
655- export type LogMessageOptions = {
674+ export interface LogMessageOptions extends CommonOptions {
656675 symbol ?: string ;
657- } ;
676+ }
658677export const log = {
659- message : ( message = '' , { symbol = color . gray ( S_BAR ) } : LogMessageOptions = { } ) => {
678+ message : (
679+ message = '' ,
680+ { symbol = color . gray ( S_BAR ) , output = process . stdout } : LogMessageOptions = { }
681+ ) => {
660682 const parts = [ `${ color . gray ( S_BAR ) } ` ] ;
661683 if ( message ) {
662684 const [ firstLine , ...lines ] = message . split ( '\n' ) ;
663685 parts . push ( `${ symbol } ${ firstLine } ` , ...lines . map ( ( ln ) => `${ color . gray ( S_BAR ) } ${ ln } ` ) ) ;
664686 }
665- process . stdout . write ( `${ parts . join ( '\n' ) } \n` ) ;
687+ output . write ( `${ parts . join ( '\n' ) } \n` ) ;
666688 } ,
667- info : ( message : string ) => {
668- log . message ( message , { symbol : color . blue ( S_INFO ) } ) ;
689+ info : ( message : string , opts ?: LogMessageOptions ) => {
690+ log . message ( message , { ... opts , symbol : color . blue ( S_INFO ) } ) ;
669691 } ,
670- success : ( message : string ) => {
671- log . message ( message , { symbol : color . green ( S_SUCCESS ) } ) ;
692+ success : ( message : string , opts ?: LogMessageOptions ) => {
693+ log . message ( message , { ... opts , symbol : color . green ( S_SUCCESS ) } ) ;
672694 } ,
673- step : ( message : string ) => {
674- log . message ( message , { symbol : color . green ( S_STEP_SUBMIT ) } ) ;
695+ step : ( message : string , opts ?: LogMessageOptions ) => {
696+ log . message ( message , { ... opts , symbol : color . green ( S_STEP_SUBMIT ) } ) ;
675697 } ,
676- warn : ( message : string ) => {
677- log . message ( message , { symbol : color . yellow ( S_WARN ) } ) ;
698+ warn : ( message : string , opts ?: LogMessageOptions ) => {
699+ log . message ( message , { ... opts , symbol : color . yellow ( S_WARN ) } ) ;
678700 } ,
679701 /** alias for `log.warn()`. */
680- warning : ( message : string ) => {
681- log . warn ( message ) ;
702+ warning : ( message : string , opts ?: LogMessageOptions ) => {
703+ log . warn ( message , opts ) ;
682704 } ,
683- error : ( message : string ) => {
684- log . message ( message , { symbol : color . red ( S_ERROR ) } ) ;
705+ error : ( message : string , opts ?: LogMessageOptions ) => {
706+ log . message ( message , { ... opts , symbol : color . red ( S_ERROR ) } ) ;
685707 } ,
686708} ;
687709
688710const prefix = `${ color . gray ( S_BAR ) } ` ;
711+
712+ // TODO (43081j): this currently doesn't support custom `output` writables
713+ // because we rely on `columns` existing (i.e. `process.stdout.columns).
714+ //
715+ // If we want to support `output` being passed in, we will need to use
716+ // a condition like `if (output insance Writable)` to check if it has columns
689717export const stream = {
690718 message : async (
691719 iterable : Iterable < string > | AsyncIterable < string > ,
@@ -730,10 +758,9 @@ export const stream = {
730758 } ,
731759} ;
732760
733- export interface SpinnerOptions {
761+ export interface SpinnerOptions extends CommonOptions {
734762 indicator ?: 'dots' | 'timer' ;
735763 onCancel ?: ( ) => void ;
736- output ?: Writable ;
737764}
738765
739766export interface SpinnerResult {
@@ -952,11 +979,11 @@ export type Task = {
952979/**
953980 * Define a group of tasks to be executed
954981 */
955- export const tasks = async ( tasks : Task [ ] ) => {
982+ export const tasks = async ( tasks : Task [ ] , opts ?: CommonOptions ) => {
956983 for ( const task of tasks ) {
957984 if ( task . enabled === false ) continue ;
958985
959- const s = spinner ( ) ;
986+ const s = spinner ( opts ) ;
960987 s . start ( task . title ) ;
961988 const result = await task . task ( s . message ) ;
962989 s . stop ( result || task . title ) ;
0 commit comments