148 lines
3.6 KiB
JavaScript
148 lines
3.6 KiB
JavaScript
// ISC @ Julien Fontanet
|
|
|
|
'use strict'
|
|
|
|
// ===================================================================
|
|
|
|
var construct = typeof Reflect !== 'undefined' ? Reflect.construct : undefined
|
|
var defineProperty = Object.defineProperty
|
|
|
|
// -------------------------------------------------------------------
|
|
|
|
var captureStackTrace = Error.captureStackTrace
|
|
if (captureStackTrace === undefined) {
|
|
captureStackTrace = function captureStackTrace (error) {
|
|
var container = new Error()
|
|
|
|
defineProperty(error, 'stack', {
|
|
configurable: true,
|
|
get: function getStack () {
|
|
var stack = container.stack
|
|
|
|
// Replace property with value for faster future accesses.
|
|
defineProperty(this, 'stack', {
|
|
configurable: true,
|
|
value: stack,
|
|
writable: true
|
|
})
|
|
|
|
return stack
|
|
},
|
|
set: function setStack (stack) {
|
|
defineProperty(error, 'stack', {
|
|
configurable: true,
|
|
value: stack,
|
|
writable: true
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
|
|
function BaseError (message) {
|
|
if (message !== undefined) {
|
|
defineProperty(this, 'message', {
|
|
configurable: true,
|
|
value: message,
|
|
writable: true
|
|
})
|
|
}
|
|
|
|
var cname = this.constructor.name
|
|
if (
|
|
cname !== undefined &&
|
|
cname !== this.name
|
|
) {
|
|
defineProperty(this, 'name', {
|
|
configurable: true,
|
|
value: cname,
|
|
writable: true
|
|
})
|
|
}
|
|
|
|
captureStackTrace(this, this.constructor)
|
|
}
|
|
|
|
BaseError.prototype = Object.create(Error.prototype, {
|
|
// See: https://github.com/JsCommunity/make-error/issues/4
|
|
constructor: {
|
|
configurable: true,
|
|
value: BaseError,
|
|
writable: true
|
|
}
|
|
})
|
|
|
|
// -------------------------------------------------------------------
|
|
|
|
// Sets the name of a function if possible (depends of the JS engine).
|
|
var setFunctionName = (function () {
|
|
function setFunctionName (fn, name) {
|
|
return defineProperty(fn, 'name', {
|
|
configurable: true,
|
|
value: name
|
|
})
|
|
}
|
|
try {
|
|
var f = function () {}
|
|
setFunctionName(f, 'foo')
|
|
if (f.name === 'foo') {
|
|
return setFunctionName
|
|
}
|
|
} catch (_) {}
|
|
})()
|
|
|
|
// -------------------------------------------------------------------
|
|
|
|
function makeError (constructor, super_) {
|
|
if (super_ == null || super_ === Error) {
|
|
super_ = BaseError
|
|
} else if (typeof super_ !== 'function') {
|
|
throw new TypeError('super_ should be a function')
|
|
}
|
|
|
|
var name
|
|
if (typeof constructor === 'string') {
|
|
name = constructor
|
|
constructor = construct !== undefined
|
|
? function () { return construct(super_, arguments, this.constructor) }
|
|
: function () { super_.apply(this, arguments) }
|
|
|
|
// If the name can be set, do it once and for all.
|
|
if (setFunctionName !== undefined) {
|
|
setFunctionName(constructor, name)
|
|
name = undefined
|
|
}
|
|
} else if (typeof constructor !== 'function') {
|
|
throw new TypeError('constructor should be either a string or a function')
|
|
}
|
|
|
|
// Also register the super constructor also as `constructor.super_` just
|
|
// like Node's `util.inherits()`.
|
|
constructor.super_ = constructor['super'] = super_
|
|
|
|
var properties = {
|
|
constructor: {
|
|
configurable: true,
|
|
value: constructor,
|
|
writable: true
|
|
}
|
|
}
|
|
|
|
// If the name could not be set on the constructor, set it on the
|
|
// prototype.
|
|
if (name !== undefined) {
|
|
properties.name = {
|
|
configurable: true,
|
|
value: name,
|
|
writable: true
|
|
}
|
|
}
|
|
constructor.prototype = Object.create(super_.prototype, properties)
|
|
|
|
return constructor
|
|
}
|
|
exports = module.exports = makeError
|
|
exports.BaseError = BaseError
|