osm-p2p-server
Version:
Peer-to-peer OpenStreetMap API v0.6 Server
232 lines (188 loc) • 4.99 kB
JavaScript
/*!
* Adapted from http-errors
* https://github.com/jshttp/http-errors/blob/master/index.js
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2016 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module dependencies.
* @private
*/
var statuses = require('statuses')
var inherits = require('inherits')
var customErrors = require('./errors.json')
/**
* Module exports.
* @public
*/
module.exports = createError
module.exports.HttpError = createHttpErrorConstructor()
// Populate exports for all constructors
populateConstructorExports(module.exports, customErrors, module.exports.HttpError)
/**
* Create a new HTTP Error.
*
* @returns {Error}
* @public
*/
function createError () {
// so much arity going on ~_~
var err
var msg
var status = 500
var props = {}
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i]
if (arg instanceof Error) {
err = arg
status = err.status || err.statusCode || status
continue
}
switch (typeof arg) {
case 'string':
msg = arg
break
case 'number':
status = arg
break
case 'object':
props = arg
break
}
}
if (typeof status !== 'number' || !statuses[status]) {
status = 500
}
// constructor
var HttpError = createError[status]
if (!err) {
// create error
err = HttpError
? new HttpError(msg)
: new Error(msg || statuses[status])
Error.captureStackTrace(err, createError)
}
if (!HttpError || !(err instanceof HttpError)) {
// add properties to generic error
err.expose = status < 500
err.status = err.statusCode = status
}
for (var key in props) {
if (key !== 'status' && key !== 'statusCode') {
err[key] = props[key]
}
}
return err
}
/**
* Create HTTP error abstract base class.
* @private
*/
function createHttpErrorConstructor () {
function HttpError () {
throw new TypeError('cannot construct abstract class')
}
inherits(HttpError, Error)
return HttpError
}
/**
* Create a constructor for a client error.
* @private
*/
function createClientErrorConstructor (HttpError, name, template, code) {
var className = name.match(/Error$/) ? name : name + 'Error'
function ClientError () {
var args = Array.prototype.slice.call(arguments)
var err
if (args[0] instanceof Error) {
err = args[0]
} else {
err = new Error(sprintf(template, args))
}
// capture a stack trace to the construction point
Error.captureStackTrace(err, ClientError)
// adjust the [[Prototype]]
Object.setPrototypeOf(err, ClientError.prototype)
// redefine the error name
Object.defineProperty(err, 'name', {
enumerable: false,
configurable: true,
value: className,
writable: true
})
return err
}
inherits(ClientError, HttpError)
ClientError.prototype.status = code
ClientError.prototype.statusCode = code
ClientError.prototype.expose = true
return ClientError
}
/**
* Create a constructor for a server error.
* @private
*/
function createServerErrorConstructor (HttpError, name, template, code) {
var className = name.match(/Error$/) ? name : name + 'Error'
function ServerError () {
var args = Array.prototype.slice.call(arguments)
var err
if (args[0] instanceof Error) {
err = args[0]
} else {
err = new Error(sprintf(template, args))
}
// capture a stack trace to the construction point
Error.captureStackTrace(err, ServerError)
// adjust the [[Prototype]]
Object.setPrototypeOf(err, ServerError.prototype)
// redefine the error name
Object.defineProperty(err, 'name', {
enumerable: false,
configurable: true,
value: className,
writable: true
})
return err
}
inherits(ServerError, HttpError)
ServerError.prototype.status = code
ServerError.prototype.statusCode = code
ServerError.prototype.expose = false
return ServerError
}
/**
* Populate the exports object with constructors for osm-p2p custom errors.
* @private
*/
function populateConstructorExports (exports, errors, HttpError) {
Object.keys(errors).forEach(function (name) {
var CodeError
var code = errors[name].code
var message = errors[name].message
switch (String(code).charAt(0)) {
case '4':
CodeError = createClientErrorConstructor(HttpError, name, message, code)
break
case '5':
CodeError = createServerErrorConstructor(HttpError, name, message, code)
break
}
if (CodeError) {
// export the constructor
exports[name] = CodeError
}
})
}
/**
* @param {String} template
* @param {String[]} values
* @return {String}
*/
function sprintf (template, values) {
return template.replace(/%s/g, function () {
return values.shift() || ''
}).replace(/ {2}/g, ' ').trim() + (values.length ? '\n' + values.join('\n') : '')
}