mprokopowicz/custom-error

View on GitHub
src/custom-error.js

Summary

Maintainability
A
25 mins
Test Coverage
'use strict';

const format = require('util').format;
const vm = require('vm');

class CustomError {
  constructor(...message) {
    if (this.constructor === CustomError) {
      throw new Error('new called on CustomError, create custom error type instead');
    }

    Error.captureStackTrace(this, this.constructor);

    Object.defineProperties(this, {
      message: {
        enumerable: false,
        writable: true,
        configurable: false,
        value: this.formatMessage(...message)
      },
      cause: {
        enumerable: false,
        writable: true,
        configurable: false,
        value: null
      }
    });
  }

  formatMessage(...message) {
    return message.length ? format(...message) : this.defaultMessage;
  }

  causedBy(causeError) {
    if ('message' in causeError && typeof causeError.message === 'string' && causeError.message.length) {
      if (!this.message) {
        this.message = causeError.message;
      } else {
        this.message = `${this.message} ${this.glue} ${causeError.message}`;
      }
    } else {
      //do not modify empty message if cause error does not have message too
    }

    this.cause = causeError;
    return this;
  }

  static create(type, ...defaultMessage) {
    const NewCustomError = class extends this {};
    NewCustomError.prototype.name = type;
    if (defaultMessage.length) {
      NewCustomError.prototype.defaultMessage = format(...defaultMessage);
    }

    return NewCustomError;
  }

  static global(type, ...defaultMessage) {
    if (vm.runInThisContext(`typeof ${type}`) !== 'undefined') {
      throw new Error(`can not create global error type "${type}"; there is already such global`);
    }
    global[type] = CustomError.create(type, ...defaultMessage);
  }

  toString() {
    return this.message ? `${this.name}: ${this.message}` : this.name;
  }

  inspect() {
    return this.stack;
  }
}
CustomError.prototype.name = 'CustomError';
CustomError.prototype.glue = '<<';
CustomError.prototype.defaultMessage = '';

module.exports = CustomError;