Skip to content

busbud/super-error

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

65 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Super Error

Easily subclass errors.

npm install super-error

Simple Subclassing

SuperError can easily be subclassed using the subclass method. Class hierarchies can be created by using the subclass method on other subclasses.

Error instances can be tested with the instanceof operator how you'd expect. They also have stack, name and message properties, as you'd expect.

var SuperError = require('super-error');

var MyError = SuperError.subclass('MyError');
var MySpecificError = MyError.subclass('MySpecificError');

var err = new MySpecificError('my message');

err instanceof MySpecificError; //=> true
err instanceof MyError;         //=> true
err instanceof SuperError;      //=> true
err instanceof Error;           //=> true

throw err;

The default SuperError constructor also accepts a plain object of properties to assign on the error.

var err = new MySpecificError('my message', {code: 404});
// Or, equivalently:
var err = new MySpecificError({message: 'my message', code: 404});

err.message; //=> 'my message'
err.code;    //=> 404

Custom Constructors

A custom constructor can be passed to subclass, which will hide all super constructors. If you want to propagate arguments to the parent constructor, call it explicitly.

var SuperError = require('super-error');

var ERROR_CODES = {
  1: 'Invalid foo',
  2: 'Invalid bar',
  3: 'Invalid baz'
};

var MyCodeError = SuperError.subclass('MyCodeError', function(code) {
  this.code = code;
  this.message = ERROR_CODES[code];
});

var err = new MyCodeError(2);

err.code;    //=> 2
err.message; //=> 'Invalid bar'

throw err;

var MyCustomError = SuperError.subclass('MyCustomError', function(message, properties) {
  SuperError.call(this, 'Decorated ' + message, properties);
});

Custom ES6 Classes

The custom constructor passed to subclass can be an ES6 class, which must extend (directly or indirectly) SuperError.

var SuperError = require('super-error');

var ERROR_CODES = {
  1: 'Invalid foo',
  2: 'Invalid bar',
  3: 'Invalid baz'
};

var MyES6CodeError = SuperError.subclass('MyES6CodeError', class extends SuperError {
  constructor(code) {
    super();
    this.code = code;
  }
  get message() {
    return ERROR_CODES[this.code];
  }
});

var err = new MyES6CodeError(2);

err.code;    //=> 2
err.message; //=> 'Invalid bar'

throw err;

Exporting Error Classes

An exports object can be passed to subclass in order to automatically export the error class. This prevents repeating the class name more than twice and simplifies a common pattern.

var SuperError = require('super-error');

var MyError = SuperError.subclass(exports, 'MyError');
var MySpecificError = MyError.subclass(exports, 'MySpecificError');

exports.MyError === MyError;                 //=> true
exports.MySpecificError === MySpecificError; //=> true

Error Causes

SuperError instances can wrap other Error or SuperError instances as their cause. This allows for higher-level error matching and handling at the top of a call stack without losing any information about the original specific cause.

Causes are set using causedBy on a SuperError instance. The instance is returned from the method for ease of use with throw or callbacks.

var SuperError = require('super-error');

var MyParseError = SuperError.subclass('MyParseError');

try {
  var obj = JSON.parse('"foo');
} catch (e) {
  throw new MyParseError('failed to parse').causedBy(e);
}

The cause is saved on the cause property of the SuperError instance, and the stack traces are concatenated. The original stack trace can be accessed through the ownStack property.

MyParseError: failed to parse
    at Object.<anonymous> (example.js:8:9)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3
Cause: SyntaxError: Unexpected end of input
    at Object.parse (native)
    at Object.<anonymous> (example.js:6:18)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3

In a chain of nested wrapped errors, the original unwrapped cause can be accessed through the rootCause property of each SuperError instance in the chain.

var SuperError = require('super-error');

var WrappedError = SuperError.subclass('WrappedError');
var TopError = SuperError.subclass('TopError');

var cause = new Error('cause');
var wrapped = new WrappedError('wrapped').causedBy(cause);
var top = new TopError('top').causedBy(wrapped);

top.cause.message;     //=> 'wrapped'
top.rootCause.message; //=> 'cause'