import chalk from 'chalk' ; import { validateStringContainsBoolean } from './utils' ; function indentString ( indentLevel ) { let str = "" ; for ( let i = 0 ; i < indentLevel ; i ++ ) { str += chalk . blackBright ( "⎸ " ) ; } return str ; } function isEnabled ( name ) { const v = process . env . APOLLO_FEDERATION_DEBUG ; const bool = validateStringContainsBoolean ( v ) ; if ( bool !== undefined ) { return bool ; } const enabledNames = v ! . split ( ',' ) . map ( n => n . trim ( ) ) ; return enabledNames . includes ( name ) ; } let currentIndentLevel = 0 ; let currentIndentation = '' ; let maxLoggerNameLength = 0 ; const createdLoggers = [ ] ; export function newDebugLogger ( name ) { const enabled = isEnabled ( name ) ; const created = new DebugLogger ( name , enabled ) ; if ( enabled ) { global . console = require ( 'console' ) ; createdLoggers . push ( created ) ; maxLoggerNameLength = Math . max ( maxLoggerNameLength , name . length ) ; for ( const logger of createdLoggers ) { DebugLogger . prototype [ 'updateHeader' ] . call ( logger , maxLoggerNameLength ) ; } } return created ; } function increaseIndentation ( ) { currentIndentLevel ++ ; currentIndentation = indentString ( currentIndentLevel ) ; } function decreaseIndentation ( ) { if ( currentIndentLevel > 0 ) { currentIndentLevel -- ; currentIndentation = indentString ( currentIndentLevel ) ; } } /**
 * A facility to log messages for debugging.
 *
 * All `DebugLogger` share an indentation level that is used before logged messages. That indentation level gets
 * increased by calling `group()` and decreased by `groupEnd()`. This is meant to help representing the nestedness
 * of the code being debugged.
 */ export class DebugLogger { private header : string ; param enabled constructor ( readonly name , readonly enabled ) { this . header = chalk . blackBright ( `[${ name }] ` ) ; } private updateHeader ( maxLength ) { let padding = "" ; if ( maxLength > this . name . length ) { const toPad = maxLength - this . name . length ; for ( let i = 0 ; i < toPad ; i ++ ) { padding += " " ; } } this . header = chalk . blackBright ( '[' + padding + this . name + '] ' ) ; } private doLog ( str ) { const indent = this . header + currentIndentation ; const withIndentedNewlines = str . replace ( /\n/g , '\n' + indent + '  ' ) ; console . log ( indent + withIndentedNewlines ) ; } param message param prefix public log ( message , prefix = chalk . yellow ( '• ' ) ) { if ( ! this . enabled ) return this ; if ( typeof message !== 'string' ) { message = message ( ) ; } this . doLog ( prefix + message ) ; return this ; } param values param printFn param initialMessage public groupedValues < T > ( values , printFn , initialMessage ? ) { if ( ! this . enabled ) return this ; this . group ( initialMessage ) ; for ( const value of values ) { this . doLog ( '- ' + printFn ( value ) ) ; } return this . groupEnd ( ) ; } param map param keyPrintFn param valuePrintFn public groupedEntries < K , V > ( map , keyPrintFn , valuePrintFn ) { if ( ! this . enabled ) return this ; this . group ( ) ; for ( const [ k , v ] of map . entries ( ) ) { this . doLog ( '- ' + keyPrintFn ( k ) + ': ' + valuePrintFn ( v ) ) ; } return this . groupEnd ( ) ; } param openingMessage public group ( openingMessage ? ) { if ( this . enabled ) { if ( openingMessage ) { this . log ( openingMessage , chalk . blue ( '‣ ' ) ) ; } increaseIndentation ( ) ; } return this ; } param closingMessage public groupEnd ( closingMessage ? ) { if ( ! this . enabled ) { return this ; } decreaseIndentation ( ) ; if ( closingMessage ) { this . log ( closingMessage , chalk . green ( '⇒ ' ) ) ; } return this ; } }