@@ -838,7 +838,56 @@ export const log = {
838838 } ,
839839} ;
840840
841- export const spinner = ( ) => {
841+ const prefix = `${ color . gray ( S_BAR ) } ` ;
842+ export const stream = {
843+ message : async (
844+ iterable : Iterable < string > | AsyncIterable < string > ,
845+ { symbol = color . gray ( S_BAR ) } : LogMessageOptions = { }
846+ ) => {
847+ process . stdout . write ( `${ color . gray ( S_BAR ) } \n${ symbol } ` ) ;
848+ let lineWidth = 3 ;
849+ for await ( let chunk of iterable ) {
850+ chunk = chunk . replace ( / \n / g, `\n${ prefix } ` ) ;
851+ if ( chunk . includes ( '\n' ) ) {
852+ lineWidth = 3 + strip ( chunk . slice ( chunk . lastIndexOf ( '\n' ) ) ) . length ;
853+ }
854+ const chunkLen = strip ( chunk ) . length ;
855+ if ( lineWidth + chunkLen < process . stdout . columns ) {
856+ lineWidth += chunkLen ;
857+ process . stdout . write ( chunk ) ;
858+ } else {
859+ process . stdout . write ( `\n${ prefix } ${ chunk . trimStart ( ) } ` ) ;
860+ lineWidth = 3 + strip ( chunk . trimStart ( ) ) . length ;
861+ }
862+ }
863+ process . stdout . write ( '\n' ) ;
864+ } ,
865+ info : ( iterable : Iterable < string > | AsyncIterable < string > ) => {
866+ return stream . message ( iterable , { symbol : color . blue ( S_INFO ) } ) ;
867+ } ,
868+ success : ( iterable : Iterable < string > | AsyncIterable < string > ) => {
869+ return stream . message ( iterable , { symbol : color . green ( S_SUCCESS ) } ) ;
870+ } ,
871+ step : ( iterable : Iterable < string > | AsyncIterable < string > ) => {
872+ return stream . message ( iterable , { symbol : color . green ( S_STEP_SUBMIT ) } ) ;
873+ } ,
874+ warn : ( iterable : Iterable < string > | AsyncIterable < string > ) => {
875+ return stream . message ( iterable , { symbol : color . yellow ( S_WARN ) } ) ;
876+ } ,
877+ /** alias for `log.warn()`. */
878+ warning : ( iterable : Iterable < string > | AsyncIterable < string > ) => {
879+ return stream . warn ( iterable ) ;
880+ } ,
881+ error : ( iterable : Iterable < string > | AsyncIterable < string > ) => {
882+ return stream . message ( iterable , { symbol : color . red ( S_ERROR ) } ) ;
883+ } ,
884+ } ;
885+
886+ export interface SpinnerOptions {
887+ indicator ?: 'dots' | 'timer' ;
888+ }
889+
890+ export const spinner = ( { indicator = 'dots' } : SpinnerOptions = { } ) => {
842891 const frames = unicode ? [ '◒' , '◐' , '◓' , '◑' ] : [ '•' , 'o' , 'O' , '0' ] ;
843892 const delay = unicode ? 80 : 120 ;
844893 const isCI = process . env . CI === 'true' ;
@@ -848,6 +897,7 @@ export const spinner = () => {
848897 let isSpinnerActive = false ;
849898 let _message = '' ;
850899 let _prevMessage : string | undefined = undefined ;
900+ let _origin : number = performance . now ( ) ;
851901
852902 const formatMessage = ( symbol : string , msg : string ) : string => {
853903 return format ( msg , {
@@ -899,13 +949,21 @@ export const spinner = () => {
899949 return msg . replace ( / \. + $ / , '' ) ;
900950 } ;
901951
952+ const formatTimer = ( origin : number ) : string => {
953+ const duration = ( performance . now ( ) - origin ) / 1000 ;
954+ const min = Math . floor ( duration / 60 ) ;
955+ const secs = Math . floor ( duration % 60 ) ;
956+ return min > 0 ? `[${ min } m ${ secs } s]` : `[${ secs } s]` ;
957+ } ;
958+
902959 const start = ( msg = '' ) : void => {
903960 isSpinnerActive = true ;
904961 unblock = block ( ) ;
905962 _message = parseMessage ( msg ) ;
963+ _origin = performance . now ( ) ;
906964 process . stdout . write ( `${ color . gray ( S_BAR ) } \n` ) ;
907965 let frameIndex = 0 ;
908- let dotsTimer = 0 ;
966+ let indicatorTimer = 0 ;
909967 registerHooks ( ) ;
910968 loop = setInterval ( ( ) => {
911969 if ( isCI && _message === _prevMessage ) {
@@ -914,11 +972,18 @@ export const spinner = () => {
914972 clearPrevMessage ( ) ;
915973 _prevMessage = _message ;
916974 const frame = color . magenta ( frames [ frameIndex ] ) ;
917- const loadingDots = isCI ? '...' : '.' . repeat ( Math . floor ( dotsTimer ) ) . slice ( 0 , 3 ) ;
918- _prevMessage = _message ;
919- process . stdout . write ( formatMessage ( frame , _message + loadingDots ) ) ;
975+
976+ if ( isCI ) {
977+ process . stdout . write ( `${ frame } ${ _message } ...` ) ;
978+ } else if ( indicator === 'timer' ) {
979+ process . stdout . write ( `${ frame } ${ _message } ${ formatTimer ( _origin ) } ` ) ;
980+ } else {
981+ const loadingDots = '.' . repeat ( Math . floor ( indicatorTimer ) ) . slice ( 0 , 3 ) ;
982+ process . stdout . write ( `${ frame } ${ _message } ${ loadingDots } ` ) ;
983+ }
984+
920985 frameIndex = frameIndex + 1 < frames . length ? frameIndex + 1 : 0 ;
921- dotsTimer = dotsTimer < frames . length ? dotsTimer + 0.125 : 0 ;
986+ indicatorTimer = indicatorTimer < frames . length ? indicatorTimer + 0.125 : 0 ;
922987 } , delay ) ;
923988 } ;
924989
@@ -933,7 +998,11 @@ export const spinner = () => {
933998 ? color . red ( S_STEP_CANCEL )
934999 : color . red ( S_STEP_ERROR ) ;
9351000 _message = parseMessage ( msg ?? _message ) ;
936- process . stdout . write ( `${ step } ${ _message } \n` ) ;
1001+ if ( indicator === 'timer' ) {
1002+ process . stdout . write ( `${ step } ${ _message } ${ formatTimer ( _origin ) } \n` ) ;
1003+ } else {
1004+ process . stdout . write ( `${ step } ${ _message } \n` ) ;
1005+ }
9371006 clearHooks ( ) ;
9381007 unblock ( ) ;
9391008 } ;
0 commit comments