import { getClosestCallerPackage } from '../util/caller-package' ; import { replaceAll } from '../util/strings' ; import { ErrorDescriptor , ERRORS , getErrorCode } from './errors-list' ; const inspect = Symbol . for ( 'nodejs.util.inspect.custom' ) ; export class CustomError extends Error { constructor ( message , public readonly parent ? ) { super ( message ) ; this . name = this . constructor . name ; if ( ( Error as any ) . captureStackTrace !== undefined ) { ( Error as any ) . captureStackTrace ( this , this . constructor ) ; } } public [ inspect ] ( ) { let str = this . stack ; if ( this . parent !== undefined ) { const parentAsAny = this . parent as any ; const causeString = parentAsAny [ inspect ] ?. ( ) ?? parentAsAny . inspect ?. ( ) ?? parentAsAny . stack ?? parentAsAny . toString ( ) ; const nestedCauseStr = causeString . split ( '\n' ) . map ( ( line ) => `    ${ line }` ) . join ( '\n' ) . trim ( ) ; str += `

    Caused by: ${ nestedCauseStr }` ; } return str ; } } export class RedspotError extends CustomError { public static isRedspotError ( other ) { return ( other !== undefined && other !== null && other . _isRedspotError === true ) ; } public static isRedspotErrorType ( other , descriptor ) { return ( RedspotError . isRedspotError ( other ) && other . errorDescriptor . number === descriptor . number ) ; } public readonly errorDescriptor : ErrorDescriptor ; public readonly number : number ; public readonly messageArguments : Record < string , any > ; private readonly _isRedspotError : boolean ; constructor ( errorDescriptor , messageArguments = { } , parentError ? ) { const prefix = `${ getErrorCode ( errorDescriptor ) }: ` ; const formattedMessage = applyErrorMessageTemplate ( errorDescriptor . message , messageArguments ) ; super ( prefix + formattedMessage , parentError ) ; this . errorDescriptor = errorDescriptor ; this . number = errorDescriptor . number ; this . messageArguments = messageArguments ; this . _isRedspotError = true ; Object . setPrototypeOf ( this , RedspotError . prototype ) ; } } /**
 * This class is used to throw errors from redspot plugins made by third parties.
 */ export class RedspotPluginError extends CustomError { public static isRedspotPluginError ( other ) { return ( other !== undefined && other !== null && other . _isRedspotPluginError === true ) ; } public readonly pluginName : string ; private readonly _isRedspotPluginError : boolean ; param pluginName param message param parent public constructor ( pluginName , message , parent ? ) ; deprecated param message param parent public constructor ( message , parent ? ) ; public constructor ( pluginNameOrMessage , messageOrParent ? , parent ? ) { if ( typeof messageOrParent === 'string' ) { super ( messageOrParent , parent ) ; this . pluginName = pluginNameOrMessage ; } else { super ( pluginNameOrMessage , messageOrParent ) ; this . pluginName = getClosestCallerPackage ( ) ! ; } this . _isRedspotPluginError = true ; Object . setPrototypeOf ( this , RedspotPluginError . prototype ) ; } } export class NomicLabsRedspotPluginError extends RedspotPluginError { public static isNomicLabsRedspotPluginError ( other ) { return ( other !== undefined && other !== null && other . _isNomicLabsRedspotPluginError === true ) ; } private readonly _isNomicLabsRedspotPluginError : boolean ; /**
     * This class is used to throw errors from *core* redspot plugins. If you are
     * developing a third-party plugin, use RedspotPluginError instead.
     */ public constructor ( pluginName , message , parent ? , public shouldBeReported = false ) { super ( pluginName , message , parent ) ; this . _isNomicLabsRedspotPluginError = true ; Object . setPrototypeOf ( this , NomicLabsRedspotPluginError . prototype ) ; } } param template param values export function applyErrorMessageTemplate ( template , values ) { return _applyErrorMessageTemplate ( template , values , false ) ; } function _applyErrorMessageTemplate ( template , values , isRecursiveCall ) { if ( ! isRecursiveCall ) { for ( const variableName of Object . keys ( values ) ) { if ( variableName . match ( /^[a-zA-Z][a-zA-Z0-9]*$/ ) === null ) { throw new RedspotError ( ERRORS . INTERNAL . TEMPLATE_INVALID_VARIABLE_NAME , { variable : variableName } ) ; } const variableTag = `%${ variableName }%` ; if ( ! template . includes ( variableTag ) ) { throw new RedspotError ( ERRORS . INTERNAL . TEMPLATE_VARIABLE_TAG_MISSING , { variable : variableName } ) ; } } } if ( template . includes ( '%%' ) ) { return template . split ( '%%' ) . map ( ( part ) => _applyErrorMessageTemplate ( part , values , true ) ) . join ( '%' ) ; } for ( const variableName of Object . keys ( values ) ) { let value ; if ( values [ variableName ] === undefined ) { value = 'undefined' ; } else if ( values [ variableName ] === null ) { value = 'null' ; } else { value = values [ variableName ] . toString ( ) ; } if ( value === undefined ) { value = 'undefined' ; } const variableTag = `%${ variableName }%` ; if ( value . match ( /%([a-zA-Z][a-zA-Z0-9]*)?%/ ) !== null ) { throw new RedspotError ( ERRORS . INTERNAL . TEMPLATE_VALUE_CONTAINS_VARIABLE_TAG , { variable : variableName } ) ; } template = replaceAll ( template , variableTag , value ) ; } return template ; } export function assertRedspotInvariant ( invariant , message ) { if ( ! invariant ) { throw new RedspotError ( ERRORS . GENERAL . ASSERTION_ERROR , { message } ) ; } }