2021-12-03 17:58:48 +01:00

136 lines
3.8 KiB
JavaScript

'use strict';
// core modules
var http = require('http');
// external modules
var _ = require('lodash');
var assert = require('assert-plus');
// local globals
var INTERNAL_OPTS_KEYS = {
'code': true,
'restCode': true,
'statusCode': true,
'toJSON': true,
'toString': true
};
//------------------------------------------------------------------------------
// constructor arg parsers
//------------------------------------------------------------------------------
/**
* helper function for parsing all of the Error constructor variadic sigs.
* these signatures are all derived from VError.
* 1) new HttpError(sprintf_args...);
* 2) new HttpError(anotherErr, sprintf_args);
* 3) new HttpError({...}, sprintf_args);
* restify-errors' value is to add support for additional options using the
* signature #3. this function parses out the arguments specific to
* restify-errors so that they don't get passed on to VError.
* @public
* @param {Object} ctorArgs an 'arguments' object
* @function parseVErrorArgs
* @returns {Object}
*/
function parseVErrorArgs(ctorArgs) {
// to array the inner arguments so it's easier to determine which cases
// we are looking at
var args = _.toArray(ctorArgs);
var internalOpts = {};
var verrorOpts = {};
var verrorArgs;
if (_.isPlainObject(args[0])) {
// split restify-errors options from verror options
_.forOwn(args[0], function(val, key) {
if (INTERNAL_OPTS_KEYS.hasOwnProperty(key)) {
internalOpts[key] = val;
} else {
verrorOpts[key] = val;
}
});
// reconstruct verror ctor options from the cleaned up options
verrorArgs = [ verrorOpts ].concat(_.tail(args));
} else {
verrorArgs = args;
}
return {
// raw arguments to pass to VError constructor
verrorArgs: verrorArgs,
// restify-errors specific options
internalOpts: internalOpts
};
}
//------------------------------------------------------------------------------
// helpers
//------------------------------------------------------------------------------
/**
* create an error name from a status code. looks up the description via
* http.STATUS_CODES, then calls createErrNameFromDesc().
* @private
* @function errNameFromCode
* @param {Number} code an http status code
* @returns {String}
*/
function errNameFromCode(code) {
assert.number(code, 'code');
// attempt to retrieve status code description, if not available,
// fallback on 500.
var errorDesc = http.STATUS_CODES[code] || http.STATUS_CODES[500];
return errNameFromDesc(errorDesc);
}
/**
* used to programatically create http error code names, using the underlying
* status codes names exposed via the http module.
* @private
* @function errNameFromDesc
* @param {String} desc a description of the error, e.g., 'Not Found'
* @returns {String}
*/
function errNameFromDesc(desc) {
assert.string(desc, 'desc');
// takes an error description, split on spaces, camel case it correctly,
// then append 'Error' at the end of it.
// e.g., the passed in description is 'Internal Server Error'
// the output is 'InternalServerError'
var pieces = desc.split(/\s+/);
var name = _.reduce(pieces, function(acc, piece) {
// lowercase all, then capitalize it.
var normalizedPiece = _.capitalize(piece.toLowerCase());
return acc + normalizedPiece;
}, '');
// strip all non word characters
name = name.replace(/\W+/g, '');
// append 'Error' at the end of it only if it doesn't already end with it.
if (!_.endsWith(name, 'Error')) {
name += 'Error';
}
return name;
}
module.exports = {
errNameFromCode: errNameFromCode,
errNameFromDesc: errNameFromDesc,
parseVErrorArgs: parseVErrorArgs
};