All files / ima/error ExtensibleError.js

41.67% Statements 15/36
23.08% Branches 3/13
50% Functions 1/2
41.67% Lines 15/36
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135    23x                                             134x     134x             134x             134x             134x                   134x 134x     134x                       134x                   134x     23x 23x                 23x                                                                     23x  
import ns from '../namespace';
 
ns.namespace('ima.error');
 
/**
 * Base class of custom error classes, extending the native {@linkcode Error}
 * class.
 *
 * This class has been introduced to fix the Babel-related issues with
 * extending the native JavaScript (Error) classes.
 *
 * @abstract
 * @class
 * @extends Error
 * @param {string} message The message describing the cause of the error.
 * @param {boolean=} dropInternalStackFrames Whether or not the call stack
 *        frames referring to the constructors of the custom errors should be
 *        excluded from the stack of this error (just like the native platform
 *        call stack frames are dropped by the JS engine).
 *        This flag is enabled by default.
 */
export default function ExtensibleError(
  message,
  dropInternalStackFrames = true
) {
  Iif (!(this instanceof ExtensibleError)) {
    throw new TypeError('Cannot call a class as a function');
  }
  Iif (this.constructor === ExtensibleError) {
    throw new TypeError(
      'The ExtensibleError is an abstract class and ' +
        'must be extended before it can be instantiated.'
    );
  }
 
  Error.call(this, message); // super-constructor call;
 
  /**
	 * The name of this error, used in the generated stack trace.
	 *
	 * @type {string}
	 */
  this.name = this.constructor.name;
 
  /**
	 * The message describing the cause of the error.
	 *
	 * @type {string}
	 */
  this.message = message;
 
  /**
	 * Native error instance we use to generate the call stack. For some reason
	 * some browsers do not generate call stacks for instances of classes
	 * extending the native {@codelink Error} class, so we bypass this
	 * shortcoming this way.
	 *
	 * @type {Error}
	 */
  this._nativeError = new Error(message);
  this._nativeError.name = this.name;
 
  // improve compatibility with Gecko
  Iif (this._nativeError.columnNumber) {
    this.lineNumber = this._nativeError.lineNumber;
    this.columnNumber = this._nativeError.columnNumber;
    this.fileName = this._nativeError.fileName;
  }
 
  /**
	 * The internal cache of the generated stack. The cache is filled upon
	 * first access to the {@codelink stack} property.
	 *
	 * @type {?string}
	 */
  this._stack = null;
 
  /**
	 * Whether or not the call stack frames referring to the constructors of
	 * the custom errors should be excluded from the stack of this error (just
	 * like the native platform call stack frames are dropped by the JS
	 * engine).
	 *
	 * @type {boolean}
	 */
  this._dropInternalStackFrames = dropInternalStackFrames;
}
 
ExtensibleError.prototype = Object.create(Error.prototype);
ExtensibleError.prototype.constructor = ExtensibleError;
 
/**
 * The call stack captured at the moment of creation of this error. The
 * formatting of the stack is browser-dependant.
 *
 * @return {string} The call stack captured at the moment of creation of this
 *         error.
 */
Object.defineProperty(ExtensibleError.prototype, 'stack', {
  configurable: true,
  enumerable: false,
  get: function() {
    if (this._stack) {
      return this._stack;
    }
 
    let stack = this._nativeError.stack;
    if (typeof stack !== 'string') {
      return undefined;
    }
 
    // drop the stack trace frames referring to the custom error
    // constructors
    if (this._dropInternalStackFrames) {
      let stackLines = stack.split('\n');
 
      let inheritanceDepth = 1;
      let currentPrototype = Object.getPrototypeOf(this);
      while (currentPrototype !== ExtensibleError.prototype) {
        currentPrototype = Object.getPrototypeOf(currentPrototype);
        inheritanceDepth++;
      }
      stackLines.splice(1, inheritanceDepth);
 
      this._stack = stackLines.join('\n');
    } else {
      this._stack = stack;
    }
 
    return this._stack;
  }
});
 
ns.ima.error.ExtensibleError = ExtensibleError;