106 lines
3.1 KiB
JavaScript
106 lines
3.1 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
var extend = require('xtend/mutable');
|
||
|
var assert = require('assert');
|
||
|
|
||
|
var TypedError = require('./typed.js');
|
||
|
|
||
|
var objectToString = Object.prototype.toString;
|
||
|
var ERROR_TYPE = '[object Error]';
|
||
|
var causeMessageRegex = /\{causeMessage\}/g;
|
||
|
var origMessageRegex = /\{origMessage\}/g;
|
||
|
|
||
|
module.exports = WrappedError;
|
||
|
|
||
|
function WrappedError(options) {
|
||
|
assert(options, 'WrappedError: must specify options');
|
||
|
assert(options.type, 'WrappedError: must specify type');
|
||
|
assert(options.message, 'WrappedError: must specify message');
|
||
|
|
||
|
assert(!has(options, 'cause'),
|
||
|
'WrappedError: cause field is reserved');
|
||
|
assert(!has(options, 'fullType'),
|
||
|
'WrappedError: fullType field is reserved');
|
||
|
assert(!has(options, 'causeMessage'),
|
||
|
'WrappedError: causeMessage field is reserved');
|
||
|
assert(!has(options, 'origMessage'),
|
||
|
'WrappedError: origMessage field is reserved');
|
||
|
|
||
|
var createTypedError = TypedError(options);
|
||
|
extend(createError, options);
|
||
|
createError._name = options.name;
|
||
|
|
||
|
return createError;
|
||
|
|
||
|
function createError(cause, opts) {
|
||
|
/*eslint max-statements: [2, 25]*/
|
||
|
assert(cause, 'an error is required');
|
||
|
assert(isError(cause),
|
||
|
'WrappedError: first argument must be an error');
|
||
|
|
||
|
var causeMessage = cause.message;
|
||
|
if (causeMessage.indexOf('{causeMessage}') >= 0) {
|
||
|
// recover
|
||
|
causeMessage = causeMessage.replace(
|
||
|
causeMessageRegex,
|
||
|
'$INVALID_CAUSE_MESSAGE_LITERAL'
|
||
|
);
|
||
|
}
|
||
|
if (causeMessage.indexOf('{origMessage}') >= 0) {
|
||
|
causeMessage = causeMessage.replace(
|
||
|
origMessageRegex,
|
||
|
'$INVALID_ORIG_MESSAGE_LITERAL'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
var nodeCause = false;
|
||
|
var errOptions = extend({}, opts, {
|
||
|
causeMessage: causeMessage,
|
||
|
origMessage: causeMessage
|
||
|
});
|
||
|
|
||
|
if (has(cause, 'code') && !has(errOptions, 'code')) {
|
||
|
errOptions.code = cause.code;
|
||
|
}
|
||
|
|
||
|
if (has(cause, 'errno') && !has(errOptions, 'errno')) {
|
||
|
errOptions.errno = cause.errno;
|
||
|
nodeCause = true;
|
||
|
}
|
||
|
|
||
|
if (has(cause, 'syscall') && !has(errOptions, 'syscall')) {
|
||
|
errOptions.syscall = cause.syscall;
|
||
|
nodeCause = true;
|
||
|
}
|
||
|
|
||
|
var causeType = cause.type;
|
||
|
if (!causeType && nodeCause) {
|
||
|
causeType = 'error.wrapped-io.' +
|
||
|
(cause.syscall || 'unknown') + '.' +
|
||
|
(cause.errno || 'unknown');
|
||
|
} else {
|
||
|
causeType = 'error.wrapped-unknown';
|
||
|
}
|
||
|
|
||
|
errOptions.fullType = options.type + '~!~' +
|
||
|
(cause.fullType || cause.type || causeType);
|
||
|
|
||
|
var err = createTypedError(errOptions);
|
||
|
|
||
|
Object.defineProperty(err, 'cause', {
|
||
|
value: cause,
|
||
|
configurable: true,
|
||
|
enumerable: false
|
||
|
});
|
||
|
return err;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function has(obj, key) {
|
||
|
return Object.prototype.hasOwnProperty.call(obj, key);
|
||
|
}
|
||
|
|
||
|
function isError(err) {
|
||
|
return objectToString.call(err) === ERROR_TYPE;
|
||
|
}
|