import { stderr as logUpdate } from 'log-update' ; import { EOL } from 'os' ; import { ListrEventType } from '@constants/event.constants' ; import { ListrEventFromType } from '@interfaces/listr.interface' ; import { ListrRenderer } from '@interfaces/renderer.interface' ; import { Task } from '@root/lib/task' ; import colorette from '@utils/colorette' ; import { figures } from '@utils/figures' ; /**
 * This is the default renderer which is neither verbose or updating.
 * It provides short output like update renderer, but does not disturb
 * stdin during execution of listr tasks
 */ export class SimpleRenderer implements ListrRenderer { public static nonTTY = true ; public static rendererOptions : { example default prefixWithTimestamp ? : boolean ; default output ? : 'stdout' | 'stderr' ; } = { prefixWithTimestamp : false , output : 'stdout' } ; public static rendererTaskOptions : never ; /**
     * Event type renderer map contains functions to process different task events
     */ public eventTypeRendererMap : Partial < { [ P in ListrEventType ] : ( t : Task < any , typeof SimpleRenderer > , event : ListrEventFromType < P > ) => void ; } > = { [ ListrEventType . SUBTASK ] : ( task ) => { if ( task . hasTitle ( ) ) { this . log ( `${ colorette . blue ( figures . pointer ) } ${ task . title }` ) ; } if ( task . hasSubtasks ( ) ) { this . render ( task . subtasks ) ; } } , [ ListrEventType . STATE ] : ( task ) => { if ( task . isCompleted ( ) && task . hasTitle ( ) ) { this . log ( `${ colorette . green ( figures . tick ) } ${ task . title }` ) ; } } , [ ListrEventType . DATA ] : ( task , event ) => { if ( task . isPrompt ( ) && ! String ( event . data ) . match ( /^\n$/ ) ) { logUpdate ( `${ event . data }` ) ; } else { this . log ( `${ figures . pointerSmall } ${ event . data }` ) ; } } , [ ListrEventType . MESSAGE ] : ( task , event ) => { if ( event . data . error ) { const title = SimpleRenderer . formatTitle ( task ) ; this . log ( `${ colorette . red ( figures . cross ) }${ title }: ${ event . data . error }` ) ; } else if ( event . data . skip ) { const title = SimpleRenderer . formatTitle ( task ) ; const skip = task . title !== event . data . skip ? `: ${ event . data . skip }` : '' ; this . log ( `${ colorette . yellow ( figures . arrowDown ) }${ title } [${ colorette . yellow ( `skipped${ skip }` ) }]` ) ; } else if ( event . data . rollback ) { const title = SimpleRenderer . formatTitle ( task ) ; this . log ( `${ colorette . red ( figures . arrowLeft ) }${ title }: ${ event . data . rollback }` ) ; } else if ( event . data . retry ) { const title = SimpleRenderer . formatTitle ( task ) ; this . log ( `[${ colorette . yellow ( `${ event . data . retry . count }` ) }]${ title }` ) ; } } } ; constructor ( public readonly tasks , public options ) { this . options = { ... SimpleRenderer . rendererOptions , ... options } ; } public static now ( ) { return new Date ( ) ; } public static formatTitle ( task ? ) { return task ?. title ? ` ${ task . title }` : '' ; } public log ( output ? ) { const logOut = ( msg ) : void => { process [ this . options . output ] . write ( msg . endsWith ( EOL ) ? msg : `${ msg }${ EOL }` ) ; } ; if ( ! this . options . prefixWithTimestamp ) { logOut ( `${ output }` ) ; return ; } const now = SimpleRenderer . now ( ) ; const timestamp = String ( now . getHours ( ) ) . padStart ( 2 , '0' ) + ':' + String ( now . getMinutes ( ) ) . padStart ( 2 , '0' ) + ':' + String ( now . getSeconds ( ) ) . padStart ( 2 , '0' ) ; logOut ( `${ colorette . dim ( `[${ timestamp }]` ) } ${ output }` ) ; } public end ( ) { } public render ( tasks ? ) { if ( tasks ?. length ) { tasks . forEach ( ( task ) => { task . subscribe ( ( event ) => { this . eventTypeRendererMap [ event . type ] ?. ( task , event as any ) ; } , this . log ) ; } ) ; } else { this . render ( this . tasks ) ; } } }