@@ -838,7 +838,56 @@ export const log = {
838
838
} ,
839
839
} ;
840
840
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 = { } ) => {
842
891
const frames = unicode ? [ '◒' , '◐' , '◓' , '◑' ] : [ '•' , 'o' , 'O' , '0' ] ;
843
892
const delay = unicode ? 80 : 120 ;
844
893
const isCI = process . env . CI === 'true' ;
@@ -848,6 +897,7 @@ export const spinner = () => {
848
897
let isSpinnerActive = false ;
849
898
let _message = '' ;
850
899
let _prevMessage : string | undefined = undefined ;
900
+ let _origin : number = performance . now ( ) ;
851
901
852
902
const formatMessage = ( symbol : string , msg : string ) : string => {
853
903
return format ( msg , {
@@ -899,13 +949,21 @@ export const spinner = () => {
899
949
return msg . replace ( / \. + $ / , '' ) ;
900
950
} ;
901
951
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
+
902
959
const start = ( msg = '' ) : void => {
903
960
isSpinnerActive = true ;
904
961
unblock = block ( ) ;
905
962
_message = parseMessage ( msg ) ;
963
+ _origin = performance . now ( ) ;
906
964
process . stdout . write ( `${ color . gray ( S_BAR ) } \n` ) ;
907
965
let frameIndex = 0 ;
908
- let dotsTimer = 0 ;
966
+ let indicatorTimer = 0 ;
909
967
registerHooks ( ) ;
910
968
loop = setInterval ( ( ) => {
911
969
if ( isCI && _message === _prevMessage ) {
@@ -914,11 +972,18 @@ export const spinner = () => {
914
972
clearPrevMessage ( ) ;
915
973
_prevMessage = _message ;
916
974
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
+
920
985
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 ;
922
987
} , delay ) ;
923
988
} ;
924
989
@@ -933,7 +998,11 @@ export const spinner = () => {
933
998
? color . red ( S_STEP_CANCEL )
934
999
: color . red ( S_STEP_ERROR ) ;
935
1000
_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
+ }
937
1006
clearHooks ( ) ;
938
1007
unblock ( ) ;
939
1008
} ;
0 commit comments