Source: sources/messages/AbstractError.js

/**
 * @module Messages/AbstractError
 * @desc Export the AbstractError abstract class.
 *
 * @requires {@link https://github.com/Itee/itee-validators itee-validators}
 * @requires {@link https://github.com/uuidjs/uuid uuid}
 *
 * @author [Tristan Valcke]{@link https://github.com/Itee}
 * @license [BSD-3-Clause]{@link https://opensource.org/licenses/BSD-3-Clause}
 */
import {
    isBlankString,
    isEmptyString,
    isNotDefined,
    isNotString
}                       from 'itee-validators'
import { v4 as uuidv4 } from 'uuid'

/**
 * @class
 * @classdesc The AbstractError is the base class for all derived errors.
 * It is composed by an uuid v4, the name which is based on the instance constructor name, and a message
 *
 * @extends Error
 */
class AbstractError extends Error {

    /**
     * @constructor
     * @param message {string} The error message to dispatch
     */
    constructor ( message ) {
        super()

        this._uuid    = uuidv4()
        this._name    = this.constructor.name
        this._message = ( () => {
            // Validate message before assign it as readonly property !
            const expect = 'Expect a non empty string.'
            if ( isNotDefined( message ) ) { throw new ReferenceError( `The error message cannot be null or undefined. ${ expect }` )}
            if ( isNotString( message ) ) { throw new TypeError( `The error message cannot be an instance of ${ message.constructor.name }. ${ expect }` )}
            if ( isEmptyString( message ) ) { throw new TypeError( `The error message cannot be an empty string. ${ expect }` )}
            if ( isBlankString( message ) ) { throw new TypeError( `The error message cannot be a blank string. ${ expect }` )}

            return message
        } )()

        // Override the default Error stack behavior and apply get/set to avoid mutation
        this._stack = this.stack

        /**
         * The stack trace of the error
         * @member module:Messages/AbstractError~AbstractError#stack
         * @readonly
         * @type {string}
         */
        Object.defineProperty( this, 'stack', {
            get: () => { return this._stack },
            set: () => { throw new SyntaxError( 'Try to assign a read only property.' ) }
        } )


    }
    /**
     * A boolean based on classname that allow fast type checking, will ever be true
     * @constant
     * @default true
     * @type {boolean}
     */
    get isAbstractError () { return true }
    /**
     * An auto-generated universally unique identifier, this allow to recognize any error by id
     * @readonly
     * @type {string}
     */
    get uuid () { return this._uuid }
    set uuid ( value ) { throw new SyntaxError( 'Try to assign a read only property.' ) }
    /**
     * The name of current instanced error (a.k.a the constructor name)
     * @readonly
     * @type {string}
     */
    get name () { return this._name }
    set name ( value ) { throw new SyntaxError( 'Try to assign a read only property.' ) }
    /**
     * The error message
     * @readonly
     * @type {string}
     */
    get message () { return this._message }
    set message ( value ) { throw new SyntaxError( 'Try to assign a read only property.' ) }

}

export { AbstractError }