import { InternalError } from '@rushstack/node-core-library' ; import { TerminalWritable , ITerminalChunk } from '@rushstack/terminal' ; import { CollatedWriter } from './CollatedWriter' ; import { CollatedTerminal } from './CollatedTerminal' ; /**
 * Constructor options for  StreamCollator .
 *
 *  beta export interface IStreamCollatorOptions { /**
     * The target  {@link @rushstack/terminal#TerminalWritable} object that the
     *  StreamCollator will write its output to.
      destination : TerminalWritable ; /**
     * An event handler that is called when a  CollatedWriter becomes output,
     * before any of its chunks have been written to the destination.
     *
     *  remarks onWriterActive ? : ( writer : CollatedWriter ) => void ; } beta export class StreamCollator { private _taskNames : Set < string > = new Set ( ) ; private _writers : Set < CollatedWriter > = new Set ( ) ; private _activeWriter : CollatedWriter | undefined = undefined ; private _openInactiveWriters : Set < CollatedWriter > = new Set ( ) ; private _closedInactiveWriters : Set < CollatedWriter > = new Set ( ) ; private _onWriterActive : ( ( writer : CollatedWriter ) => void ) | undefined ; private _preventReentrantCall : boolean = false ; public readonly destination : TerminalWritable ; public readonly terminal : CollatedTerminal ; public constructor ( options ) { this . destination = options . destination ; this . terminal = new CollatedTerminal ( this . destination ) ; this . _onWriterActive = options . onWriterActive ; } /**
     * Returns the currently active `CollatedWriter`, or `undefined` if no writer
     * is active yet.
     */ public get activeWriter ( ) : CollatedWriter | undefined { return this . _activeWriter ; } /**
     * For diagnostic purposes, returns the  CollatedWriter . taskName for the
     * currently active writer, or an empty string if no writer is active.
      public get activeTaskName ( ) : string { if ( this . _activeWriter ) { return this . _activeWriter . taskName ; } return '' ; } /**
     * The list of writers that have been registered by calling  StreamCollator . registerTask ,
     * in the order that they were registered.
      public get writers ( ) : ReadonlySet < CollatedWriter > { return this . _writers ; } /**
     * Registers a new task to be collated, and constructs a  CollatedWriter object
     * to receive its input.
      public registerTask ( taskName ) { if ( this . _taskNames . has ( taskName ) ) { throw new Error ( 'A task with that name has already been registered' ) ; } const writer = new CollatedWriter ( taskName , this ) ; this . _writers . add ( writer ) ; this . _taskNames . add ( writer . taskName ) ; this . _openInactiveWriters . add ( writer ) ; if ( this . _activeWriter === undefined ) { this . _assignActiveWriter ( writer ) ; } return writer ; } internal public _writerWriteChunk ( writer , chunk , bufferedChunks ) { this . _checkForReentrantCall ( ) ; if ( this . _activeWriter === undefined ) { this . _assignActiveWriter ( writer ) ; } if ( writer . isActive ) { this . destination . writeChunk ( chunk ) ; } else { bufferedChunks . push ( chunk ) ; } } internal public _writerClose ( writer , bufferedChunks ) { this . _checkForReentrantCall ( ) ; if ( writer . isActive ) { writer . _flushBufferedChunks ( ) ; this . _activeWriter = undefined ; for ( const closedInactiveWriter of [ ... this . _closedInactiveWriters ] ) { try { this . _assignActiveWriter ( closedInactiveWriter ) ; } finally { this . _activeWriter = undefined ; } } let writerToActivate = undefined ; for ( const openInactiveWriter of this . _openInactiveWriters ) { if ( openInactiveWriter . bufferedChunks . length > 0 ) { writerToActivate = openInactiveWriter ; break ; } } if ( ! writerToActivate ) { for ( const openInactiveWriter of this . _openInactiveWriters ) { writerToActivate = openInactiveWriter ; break ; } } if ( writerToActivate ) { this . _assignActiveWriter ( writerToActivate ) ; } } else { this . _openInactiveWriters . delete ( writer ) ; this . _closedInactiveWriters . add ( writer ) ; } } private _assignActiveWriter ( writer ) { this . _activeWriter = writer ; this . _closedInactiveWriters . delete ( writer ) ; this . _openInactiveWriters . delete ( writer ) ; if ( this . _onWriterActive ) { this . _preventReentrantCall = true ; try { this . _onWriterActive ( writer ) ; } finally { this . _preventReentrantCall = false ; } } writer . _flushBufferedChunks ( ) ; } private _checkForReentrantCall ( ) { if ( this . _preventReentrantCall ) { throw new InternalError ( 'Reentrant call to StreamCollator' ) ; } } }