@@ -720,7 +720,11 @@ export const stream = {
720720 } ,
721721} ;
722722
723- export const spinner = ( ) => {
723+ export interface SpinnerOptions {
724+ indicator ?: 'dots' | 'timer' ;
725+ }
726+
727+ export const spinner = ( { indicator = 'dots' } : SpinnerOptions = { } ) => {
724728 const frames = unicode ? [ '◒' , '◐' , '◓' , '◑' ] : [ '•' , 'o' , 'O' , '0' ] ;
725729 const delay = unicode ? 80 : 120 ;
726730 const isCI = process . env . CI === 'true' ;
@@ -730,6 +734,7 @@ export const spinner = () => {
730734 let isSpinnerActive = false ;
731735 let _message = '' ;
732736 let _prevMessage : string | undefined = undefined ;
737+ let _origin : number = performance . now ( ) ;
733738
734739 const handleExit = ( code : number ) => {
735740 const msg = code > 1 ? 'Something went wrong' : 'Canceled' ;
@@ -770,13 +775,21 @@ export const spinner = () => {
770775 return msg . replace ( / \. + $ / , '' ) ;
771776 } ;
772777
778+ const formatTimer = ( origin : number ) : string => {
779+ const duration = ( performance . now ( ) - origin ) / 1000 ;
780+ const min = Math . floor ( duration / 60 ) ;
781+ const secs = Math . floor ( duration % 60 ) ;
782+ return min > 0 ? `[${ min } m ${ secs } s]` : `[${ secs } s]` ;
783+ } ;
784+
773785 const start = ( msg = '' ) : void => {
774786 isSpinnerActive = true ;
775787 unblock = block ( ) ;
776788 _message = parseMessage ( msg ) ;
789+ _origin = performance . now ( ) ;
777790 process . stdout . write ( `${ color . gray ( S_BAR ) } \n` ) ;
778791 let frameIndex = 0 ;
779- let dotsTimer = 0 ;
792+ let indicatorTimer = 0 ;
780793 registerHooks ( ) ;
781794 loop = setInterval ( ( ) => {
782795 if ( isCI && _message === _prevMessage ) {
@@ -785,10 +798,18 @@ export const spinner = () => {
785798 clearPrevMessage ( ) ;
786799 _prevMessage = _message ;
787800 const frame = color . magenta ( frames [ frameIndex ] ) ;
788- const loadingDots = isCI ? '...' : '.' . repeat ( Math . floor ( dotsTimer ) ) . slice ( 0 , 3 ) ;
789- process . stdout . write ( `${ frame } ${ _message } ${ loadingDots } ` ) ;
801+
802+ if ( isCI ) {
803+ process . stdout . write ( `${ frame } ${ _message } ...` ) ;
804+ } else if ( indicator === 'timer' ) {
805+ process . stdout . write ( `${ frame } ${ _message } ${ formatTimer ( _origin ) } ` ) ;
806+ } else {
807+ const loadingDots = '.' . repeat ( Math . floor ( indicatorTimer ) ) . slice ( 0 , 3 ) ;
808+ process . stdout . write ( `${ frame } ${ _message } ${ loadingDots } ` ) ;
809+ }
810+
790811 frameIndex = frameIndex + 1 < frames . length ? frameIndex + 1 : 0 ;
791- dotsTimer = dotsTimer < frames . length ? dotsTimer + 0.125 : 0 ;
812+ indicatorTimer = indicatorTimer < frames . length ? indicatorTimer + 0.125 : 0 ;
792813 } , delay ) ;
793814 } ;
794815
@@ -803,7 +824,11 @@ export const spinner = () => {
803824 ? color . red ( S_STEP_CANCEL )
804825 : color . red ( S_STEP_ERROR ) ;
805826 _message = parseMessage ( msg ?? _message ) ;
806- process . stdout . write ( `${ step } ${ _message } \n` ) ;
827+ if ( indicator === 'timer' ) {
828+ process . stdout . write ( `${ step } ${ _message } ${ formatTimer ( _origin ) } \n` ) ;
829+ } else {
830+ process . stdout . write ( `${ step } ${ _message } \n` ) ;
831+ }
807832 clearHooks ( ) ;
808833 unblock ( ) ;
809834 } ;
0 commit comments