/**
 * Create a custom error class with the ability to define the error
 * code, status, and the help text.
 *
 * ```js
 * export class FileNotFoundException extends Exception {
 *   static status = 500
 *   static code = 'E_FILE_NOT_FOUND'
 * }
 *
 * throw new FileNotFoundException(
 *  `Unable to find file from ${filePath} location`
 * )
 * ```
 */
export class Exception extends Error {
    /**
     * Name of the class that raised the exception.
     */
    name;
    /**
     * A status code for the error. Usually helpful when converting errors
     * to HTTP responses.
     */
    status;
    /**
     * Create a new exception instance.
     * It tries to extract the error code and status from the
     * `init` object. If not found, it uses the default message.
     * @param init - An object containing error details
     * @param defaultMessage - A default message to use if `init.message` is not provided
     * @returns An instance of the Exception class
     * @example
     * ```js
     * const error = Exception.fromApiError({
     *   code: 'E_FILE_NOT_FOUND',
     *   status: 404,
     *   message: 'File not found',
     *   help: 'Please check the file path and try again'
     * }, 'An error occurred while processing your request')
     * ```
     */
    static fromRawException(init, defaultMessage) {
        const typed = init;
        const options = {};
        if (typed.code) {
            options.code = typed.code;
        }
        if (typed.status) {
            options.status = Number(typed.status);
        }
        const message = typed.message ?? defaultMessage;
        const result = new this(message, options);
        if (typed.help) {
            result.setHelp(typed.help);
        }
        if (typed.name) {
            result.name = typed.name;
        }
        return result;
    }
    constructor(message, options) {
        super(message, options);
        const ErrorConstructor = this.constructor;
        this.name = ErrorConstructor.name;
        this.message = message || ErrorConstructor.message || '';
        this.status = options?.status || ErrorConstructor.status || 500;
        const code = options?.code || ErrorConstructor.code;
        if (code !== undefined) {
            this.code = code;
        }
        const help = options?.help || ErrorConstructor.help;
        if (help !== undefined) {
            this.help = help;
        }
        Error.captureStackTrace(this, ErrorConstructor);
    }
    setHelp(help) {
        this.help = help;
        return this;
    }
    setCode(code) {
        this.code = code;
        return this;
    }
    setStatus(status) {
        this.status = status;
        return this;
    }
    get [Symbol.toStringTag]() {
        return this.constructor.name;
    }
    toString() {
        if (this.code) {
            return `${this.name} [${this.code}]: ${this.message}`;
        }
        return `${this.name}: ${this.message}`;
    }
    toJSON() {
        const result = {
            name: this.name,
            message: this.message,
        };
        if (this.status) {
            result.status = this.status;
        }
        if (this.code) {
            result.code = this.code;
        }
        if (this.help) {
            result.help = this.help;
        }
        return result;
    }
}
//# sourceMappingURL=exception.js.map