file copyright author Vivek M. Chawla <@VivekMChawla>
 *  summary description version license import { SfdxError } from '@salesforce/core' ; import { isEmpty } from 'lodash' ; import { findJson } from '../sfdx-falcon-util/index' ; const chalk = require ( 'chalk' ) ; const util = require ( 'util' ) ; interface description export interface CliErrorDetail { command : string ; status : number ; result : unknown ; name ? : string ; message ? : string ; actions ? : string [ ] ; stack ? : string ; warnings ? : unknown ; } interface description export interface SfdxFalconErrorRenderOptions { headerColor : string ; labelColor : string ; errorLabelColor : string ; valueColor : string ; childInspectDepth : number ; detailInspectDepth : number ; errorInspectDepth : number ; } interface description export interface ShellErrorDetail { code : number ; command : string ; message : string ; signal : string ; stderr : string ; stdout : string ; } class extends SfdxError description public export class SfdxFalconError extends SfdxError { method param { Error } errorToRender param { number } childInspectDepth param { number } detailInspectDepth param { number } errorInspectDepth returns { string } description public static public static renderError ( errorToRender , childInspectDepth = 2 , detailInspectDepth = 4 , errorInspectDepth = 1 ) { const renderOptions = { headerColor : `yellow` , labelColor : `blue` , errorLabelColor : `red` , valueColor : `reset` , childInspectDepth : childInspectDepth || 2 , detailInspectDepth : detailInspectDepth || 4 , errorInspectDepth : errorInspectDepth || 1 } ; if ( ( errorToRender instanceof Error ) !== true ) { return SfdxFalconError . renderUnknownDetail ( errorToRender , renderOptions ) ; } let renderOutput = SfdxFalconError . renderBaseDetail ( errorToRender as SfdxFalconError , renderOptions ) ; if ( errorToRender instanceof SfdxCliError ) { renderOutput += SfdxFalconError . renderSfdxCliErrorDetail ( errorToRender , renderOptions ) ; } if ( errorToRender instanceof ShellError ) { renderOutput += SfdxFalconError . renderShellErrorDetail ( errorToRender , renderOptions ) ; } return renderOutput ; } method param { Error | unknown } error param { string } source description public static public static wrap ( error , source ? ) { if ( error instanceof SfdxFalconError ) { return error ; } let sfdxFalconError ; if ( error instanceof Error ) { sfdxFalconError = new SfdxFalconError ( error . message , error . name , source ) ; if ( sfdxFalconError . stack ) { sfdxFalconError . stack = sfdxFalconError . stack . replace ( `${ error . name }: ${ error . message }` , `Outer stack:` ) ; sfdxFalconError . stack = `${ error . stack }\n${ sfdxFalconError . stack }` ; } } else { sfdxFalconError = new SfdxFalconError ( `Additional error detail saved to the SfdxFalconError.data Object.` , `UnknownError` ) ; sfdxFalconError . data = { unknownObj : error } ; } return sfdxFalconError ; } method param { SfdxFalconError } errorToRender param { SfdxFalconErrorRenderOptions } options returns { string } description private static private static renderBaseDetail ( errorToRender , options ) { let renderOutput = chalk `\n{${ options . errorLabelColor } Error Name:}    {${ options . valueColor } ${ errorToRender . name }}` + chalk `\n{${ options . errorLabelColor } Error Message:} {${ options . valueColor } ${ errorToRender . message }}` ; if ( errorToRender . actions && ( isEmpty ( errorToRender . actions ) === false ) ) { renderOutput += chalk `\n{${ options . errorLabelColor } SfdxError Actions (Depth ${ options . childInspectDepth }):}\n{reset ${ util . inspect ( errorToRender . actions , { depth : options . childInspectDepth , colors : true } ) }}` ; } renderOutput += chalk `\n{${ options . errorLabelColor } Error Source:}  {${ options . valueColor } ${ errorToRender . source }}` + chalk `\n{${ options . errorLabelColor } Error Stack:} \n{${ options . valueColor } ${ errorToRender . stack }}` ; if ( errorToRender . resultStack && ( isEmpty ( errorToRender . resultStack ) === false ) ) { renderOutput += chalk `\n{${ options . errorLabelColor } Result Stack:}\n${ errorToRender . resultStack }` ; } if ( errorToRender . detail && ( isEmpty ( errorToRender . detail ) === false ) ) { renderOutput += chalk `\n{${ options . errorLabelColor } Error Detail:}\n{reset ${ util . inspect ( errorToRender . detail , { depth : 10 , colors : true } ) }}` ; } if ( errorToRender . data && ( isEmpty ( errorToRender . data ) === false ) ) { renderOutput += chalk `\n{${ options . errorLabelColor } Error Data (Depth ${ options . errorInspectDepth }):}\n{reset ${ util . inspect ( errorToRender . data , { depth : options . errorInspectDepth , colors : true } ) }}` ; } return renderOutput ; } method param { SfdxCliError } errorToRender param { SfdxFalconErrorRenderOptions } options returns { string } description private static private static renderSfdxCliErrorDetail ( errorToRender , options ) { let renderOutput = '' ; if ( isEmpty ( errorToRender . cliError . command ) === false ) { renderOutput += chalk `\n{${ options . errorLabelColor } CLI Command:}       ${ errorToRender . cliError . command }` ; } if ( isEmpty ( errorToRender . cliError . name ) === false ) { renderOutput += chalk `\n{${ options . errorLabelColor } CLI Error Name:}    ${ errorToRender . cliError . name }` ; } if ( isEmpty ( errorToRender . cliError . message ) === false ) { renderOutput += chalk `\n{${ options . errorLabelColor } CLI Error Message:} ${ errorToRender . cliError . message }` ; } if ( isEmpty ( errorToRender . cliError . status ) === false ) { renderOutput += chalk `\n{${ options . errorLabelColor } CLI Error Status:}  ${ errorToRender . cliError . status }` ; } if ( Array . isArray ( errorToRender . cliError . actions ) ) { renderOutput += chalk `\n{${ options . errorLabelColor } CLI Error Actions:}` ; for ( const action of errorToRender . cliError . actions ) { renderOutput += chalk `\n{green ${ action }}` ; } } if ( isEmpty ( errorToRender . cliError . warnings ) === false ) { renderOutput += chalk `\n{${ options . errorLabelColor } CLI Error Warnings:}\n${ util . inspect ( errorToRender . cliError . warnings , { depth : options . childInspectDepth , colors : true } ) }` ; } if ( isEmpty ( errorToRender . cliError . stack ) === false && options . childInspectDepth >= 5 ) { renderOutput += chalk `\n{${ options . errorLabelColor } CLI Error Stack:}   \n${ errorToRender . cliError . stack }` ; } if ( isEmpty ( errorToRender . cliError . result ) === false && options . childInspectDepth >= 2 ) { const cliRawResultDepth = 10 ; renderOutput += chalk `\n{${ options . errorLabelColor } CLI Error Raw Result: (Depth ${ cliRawResultDepth })}\n${ util . inspect ( errorToRender . cliError . result , { depth : cliRawResultDepth , colors : true } ) }` ; } return renderOutput ; } method param { ShellError } errorToRender param { SfdxFalconErrorRenderOptions } options returns { string } description private static private static renderShellErrorDetail ( errorToRender , options ) { let renderOutput = '' ; if ( isEmpty ( errorToRender . shellError . command ) === false ) { renderOutput += chalk `\n{${ options . errorLabelColor } ShellError Command:} ${ errorToRender . shellError . command }` ; } if ( errorToRender . shellError . code ) { renderOutput += chalk `\n{${ options . errorLabelColor } ShellError Code:}    ${ errorToRender . shellError . code }` ; } if ( isEmpty ( errorToRender . shellError . signal ) === false ) { renderOutput += chalk `\n{${ options . errorLabelColor } ShellError Signal:}  ${ errorToRender . shellError . signal }` ; } if ( isEmpty ( errorToRender . shellError . message ) === false ) { renderOutput += chalk `\n{${ options . errorLabelColor } ShellError Message:} ${ errorToRender . shellError . message }` ; } if ( isEmpty ( errorToRender . shellError . stderr ) === false ) { renderOutput += chalk `\n{${ options . errorLabelColor } ShellError StdErr:}\n${ errorToRender . shellError . stderr }` ; } if ( isEmpty ( errorToRender . shellError . stdout ) === false ) { renderOutput += chalk `\n{${ options . errorLabelColor } ShellError StdOut:}\n${ errorToRender . shellError . stdout }` ; } return renderOutput ; } method param { unknown } unknownObject param { SfdxFalconErrorRenderOptions } options returns { string } description private static private static renderUnknownDetail ( unknownObject , options ) { const renderOutput = chalk `\n{${ options . errorLabelColor } Error Name:}    {${ options . valueColor } UNKNOWN}` + chalk `\n{${ options . errorLabelColor } Error Message:} {${ options . valueColor } The object provided is not of type 'Error'}` + chalk `\n{${ options . errorLabelColor } Error Stack:}   {${ options . valueColor } Not Available}` + chalk `\n{${ options . errorLabelColor } Raw Object: (Depth ${ options . childInspectDepth })}\n${ util . inspect ( unknownObject , { depth : options . childInspectDepth , colors : true } ) }` ; return renderOutput ; } public readonly source : string ; private _resultStack : string ; private _detail : unknown ; private _userInfo : SfdxFalconErrorInfo ; private _debugInfo : SfdxFalconErrorInfo ; private _devInfo : SfdxFalconErrorInfo ; constructs param { string } message param { string } name param { string } source param { Error } cause param { string [ ] } actions param { number } exitCode description public public constructor ( message , name ? , source = 'Unhandled Exception' , cause ? , actions ? , exitCode ? ) { const thisName = name || 'SfdxFalconError' ; super ( message , thisName , actions || [ ] , exitCode || 1 , cause ) ; this . data = { } ; this . source = source ; this . _detail = { } ; this . _userInfo = new SfdxFalconErrorInfo ( ) ; this . _debugInfo = new SfdxFalconErrorInfo ( ) ; this . _devInfo = new SfdxFalconErrorInfo ( ) ; if ( cause ) { const causeError = cause as SfdxFalconError ; this . _resultStack = causeError . resultStack || `` ; } else { this . _resultStack = `` ; } } method param { string } stackItem returns { void } description public public addToStack ( stackItem ) { const indent = `    ` ; if ( this . _resultStack ) { this . _resultStack = `${ indent }${ stackItem }\n${ this . _resultStack }` ; } else { this . _resultStack = `${ indent }${ stackItem }` ; } } property returns { unknown } description public public get detail ( ) : unknown { return this . _detail ; } property returns { SfdxFalconErrorInfo } description public public get debugInfo ( ) : SfdxFalconErrorInfo { return this . _debugInfo ; } property returns { SfdxFalconErrorInfo } description public public get devInfo ( ) : SfdxFalconErrorInfo { return this . _devInfo ; } property returns { string } description public public get resultStack ( ) : string { return this . _resultStack ; } property returns { SfdxFalconError } description public public get rootCause ( ) : SfdxFalconError { let rootCause = this as SfdxFalconError ; while ( rootCause . cause && ( isEmpty ( rootCause . cause ) === false ) ) { rootCause = rootCause . cause as SfdxFalconError ; } return rootCause ; } property returns { SfdxFalconErrorInfo } description public public get userInfo ( ) : SfdxFalconErrorInfo { return this . _userInfo ; } method param { unknown } detail returns { this } description public public setDetail ( detail ) { this . _detail = detail ; return this ; } } class description public export class SfdxFalconErrorInfo { public title : string ; public message : string ; public actions : string [ ] ; constructs description public public constructor ( ) { this . title = 'UNKNOWN ERROR' ; this . message = 'An unknown error has occured' ; this . actions = [ ] ; } method param { string } actionItem returns { void } description public public addAction ( actionItem = '' ) { this . actions . push ( actionItem ) ; } } class extends SfdxFalconError description public export class SfdxCliError extends SfdxFalconError { public cliError : CliErrorDetail ; constructs param { string } cliCommandString param { string } cliResponseBuffer param { string } message param { string } source description public public constructor ( sfdxCommandString , cliResponseBuffer , message = 'Unknown CLI Error' , source = '' ) { const cliError = { } as CliErrorDetail ; let actions = new Array < string > ( ) ; try { const parsedError = JSON . parse ( cliResponseBuffer ) ; cliError . command = sfdxCommandString || `Command String Not Provided` ; cliError . name = parsedError . name || `UnknownCliError` ; cliError . message = parsedError . message || `Unknown CLI Error (see 'cliError.result.rawResult' for original CLI response)` ; cliError . status = ( isNaN ( parsedError . status ) ) ? 1 : parsedError . status ; if ( Array . isArray ( parsedError . actions ) ) { actions = actions . concat ( parsedError . actions ) ; } if ( parsedError . action ) { actions . push ( parsedError . action ) ; } cliError . actions = actions ; cliError . warnings = parsedError . warnings || [ ] ; cliError . stack = parsedError . stack || '' ; if ( parsedError . result ) { cliError . result = parsedError . result ; } else { const parsedStack = findJson ( parsedError . stack ) ; if ( parsedStack ) { parsedError . stack = parsedStack ; } cliError . result = { rawResult : parsedError } ; } } catch ( parsingError ) { cliError . command = sfdxCommandString || `Command String Not Provided` ; cliError . name = `UnparseableCliError` ; cliError . message = `Unparseable CLI Error (see 'cliError.result.rawResult' for raw error)` ; cliError . status = 999 ; cliError . actions = [ ] ; cliError . warnings = [ ] ; cliError . stack = `Unparseable CLI Error (see 'cliError.result.rawResult' for raw error)` ; cliError . result = { rawResult : cliResponseBuffer } ; } super ( `${ message }. ${ cliError . message }` , 'SfdxCliError' , source ) ; this . cliError = cliError ; if ( isEmpty ( cliError . actions ) === false ) { this . actions = cliError . actions ; } return ; } } class extends SfdxFalconError description public export class ShellError extends SfdxFalconError { public shellError : ShellErrorDetail ; constructs param { string } command param { number } code param { string } signal param { string } stdErrBuffer param { string } stdOutBuffer param { string } source param { string } message description public public constructor ( command , code , signal , stdErrBuffer , stdOutBuffer = null , source = '' , message = '' ) { if ( ! message ) { if ( typeof stdErrBuffer === 'string' && stdErrBuffer ) { message = stdErrBuffer . substr ( 0 , stdErrBuffer . indexOf ( '\n' ) ) ; } else if ( typeof stdOutBuffer === 'string' && stdOutBuffer ) { message = stdOutBuffer . substr ( 0 , stdOutBuffer . indexOf ( '\n' ) ) ; } else { message = `Unknown Shell Error (code=${ code }, signal=${ signal })` ; } } super ( `${ message }` , 'ShellError' , source ) ; this . shellError = { } as ShellErrorDetail ; this . shellError . command = command ; this . shellError . code = code ; this . shellError . signal = signal ; this . shellError . stdout = stdOutBuffer ; this . shellError . stderr = stdErrBuffer ; this . shellError . message = message ; return ; } }