import { StringBuilder , IStringBuilder } from '@rushstack/node-core-library' ; remarks export class IndentedWriter { /**
     * The text characters used to create one level of indentation.
     * Two spaces by default.
     */ public defaultIndentPrefix : string = '  ' ; private readonly _builder : IStringBuilder ; private _latestChunk : string | undefined ; private _previousChunk : string | undefined ; private _atStartOfLine : boolean ; private readonly _indentStack : string [ ] ; private _indentText : string ; public constructor ( builder ? ) { this . _builder = builder === undefined ? new StringBuilder ( ) : builder ; this . _latestChunk = undefined ; this . _previousChunk = undefined ; this . _atStartOfLine = true ; this . _indentStack = [ ] ; this . _indentText = '' ; } /**
     * Retrieves the output that was built so far.
     */ public getText ( ) { return this . _builder . toString ( ) ; } public toString ( ) { return this . getText ( ) ; } /**
     * Increases the indentation.  Normally the indentation is two spaces,
     * however an arbitrary prefix can optional be specified.  (For example,
     * the prefix could be "// " to indent and comment simultaneously.)
     * Each call to IndentedWriter.increaseIndent() must be followed by a
     * corresponding call to IndentedWriter.decreaseIndent().
     */ public increaseIndent ( indentPrefix ? ) { this . _indentStack . push ( indentPrefix !== undefined ? indentPrefix : this . defaultIndentPrefix ) ; this . _updateIndentText ( ) ; } /**
     * Decreases the indentation, reverting the effect of the corresponding call
     * to IndentedWriter.increaseIndent().
     */ public decreaseIndent ( ) { this . _indentStack . pop ( ) ; this . _updateIndentText ( ) ; } /**
     * A shorthand for ensuring that increaseIndent()/decreaseIndent() occur
     * in pairs.
     */ public indentScope ( scope , indentPrefix ? ) { this . increaseIndent ( indentPrefix ) ; scope ( ) ; this . decreaseIndent ( ) ; } /**
     * Adds a newline if the file pointer is not already at the start of the line (or start of the stream).
     */ public ensureNewLine ( ) { const lastCharacter = this . peekLastCharacter ( ) ; if ( lastCharacter !== '\n' && lastCharacter !== '' ) { this . _writeNewLine ( ) ; } } /**
     * Adds up to two newlines to ensure that there is a blank line above the current line.
     */ public ensureSkippedLine ( ) { if ( this . peekLastCharacter ( ) !== '\n' ) { this . _writeNewLine ( ) ; } const secondLastCharacter = this . peekSecondLastCharacter ( ) ; if ( secondLastCharacter !== '\n' && secondLastCharacter !== '' ) { this . _writeNewLine ( ) ; } } /**
     * Returns the last character that was written, or an empty string if no characters have been written yet.
     */ public peekLastCharacter ( ) { if ( this . _latestChunk !== undefined ) { return this . _latestChunk . substr ( - 1 , 1 ) ; } return '' ; } /**
     * Returns the second to last character that was written, or an empty string if less than one characters
     * have been written yet.
     */ public peekSecondLastCharacter ( ) { if ( this . _latestChunk !== undefined ) { if ( this . _latestChunk . length > 1 ) { return this . _latestChunk . substr ( - 2 , 1 ) ; } if ( this . _previousChunk !== undefined ) { return this . _previousChunk . substr ( - 1 , 1 ) ; } } return '' ; } /**
     * Writes some text to the internal string buffer, applying indentation according
     * to the current indentation level.  If the string contains multiple newlines,
     * each line will be indented separately.
     */ public write ( message ) { if ( message . length === 0 ) { return ; } if ( ! /[\r\n]/ . test ( message ) ) { this . _writeLinePart ( message ) ; return ; } let first = true ; for ( const linePart of message . split ( '\n' ) ) { if ( ! first ) { this . _writeNewLine ( ) ; } else { first = false ; } if ( linePart ) { this . _writeLinePart ( linePart . replace ( /[\r]/g , '' ) ) ; } } } /**
     * A shorthand for writing an optional message, followed by a newline.
     * Indentation is applied following the semantics of IndentedWriter.write().
     */ public writeLine ( message = '' ) { if ( message . length > 0 ) { this . write ( message ) ; } this . _writeNewLine ( ) ; } /**
     * Writes a string that does not contain any newline characters.
     */ private _writeLinePart ( message ) { if ( message . length > 0 ) { if ( this . _atStartOfLine && this . _indentText . length > 0 ) { this . _write ( this . _indentText ) ; } this . _write ( message ) ; this . _atStartOfLine = false ; } } private _writeNewLine ( ) { if ( this . _atStartOfLine && this . _indentText . length > 0 ) { this . _write ( this . _indentText ) ; } this . _write ( '\n' ) ; this . _atStartOfLine = true ; } private _write ( s ) { this . _previousChunk = this . _latestChunk ; this . _latestChunk = s ; this . _builder . append ( s ) ; } private _updateIndentText ( ) { this . _indentText = this . _indentStack . join ( '' ) ; } }