UNPKG

4.99 kBJavaScriptView Raw
1/*!
2 * Adapted from http-errors
3 * https://github.com/jshttp/http-errors/blob/master/index.js
4 * Copyright(c) 2014 Jonathan Ong
5 * Copyright(c) 2016 Douglas Christopher Wilson
6 * MIT Licensed
7 */
8
9'use strict'
10
11/**
12 * Module dependencies.
13 * @private
14 */
15
16var statuses = require('statuses')
17var inherits = require('inherits')
18var customErrors = require('./errors.json')
19
20/**
21 * Module exports.
22 * @public
23 */
24
25module.exports = createError
26module.exports.HttpError = createHttpErrorConstructor()
27
28// Populate exports for all constructors
29populateConstructorExports(module.exports, customErrors, module.exports.HttpError)
30
31/**
32 * Create a new HTTP Error.
33 *
34 * @returns {Error}
35 * @public
36 */
37
38function createError () {
39 // so much arity going on ~_~
40 var err
41 var msg
42 var status = 500
43 var props = {}
44 for (var i = 0; i < arguments.length; i++) {
45 var arg = arguments[i]
46 if (arg instanceof Error) {
47 err = arg
48 status = err.status || err.statusCode || status
49 continue
50 }
51 switch (typeof arg) {
52 case 'string':
53 msg = arg
54 break
55 case 'number':
56 status = arg
57 break
58 case 'object':
59 props = arg
60 break
61 }
62 }
63
64 if (typeof status !== 'number' || !statuses[status]) {
65 status = 500
66 }
67
68 // constructor
69 var HttpError = createError[status]
70
71 if (!err) {
72 // create error
73 err = HttpError
74 ? new HttpError(msg)
75 : new Error(msg || statuses[status])
76 Error.captureStackTrace(err, createError)
77 }
78
79 if (!HttpError || !(err instanceof HttpError)) {
80 // add properties to generic error
81 err.expose = status < 500
82 err.status = err.statusCode = status
83 }
84
85 for (var key in props) {
86 if (key !== 'status' && key !== 'statusCode') {
87 err[key] = props[key]
88 }
89 }
90
91 return err
92}
93
94/**
95 * Create HTTP error abstract base class.
96 * @private
97 */
98
99function createHttpErrorConstructor () {
100 function HttpError () {
101 throw new TypeError('cannot construct abstract class')
102 }
103
104 inherits(HttpError, Error)
105
106 return HttpError
107}
108
109/**
110 * Create a constructor for a client error.
111 * @private
112 */
113
114function createClientErrorConstructor (HttpError, name, template, code) {
115 var className = name.match(/Error$/) ? name : name + 'Error'
116
117 function ClientError () {
118 var args = Array.prototype.slice.call(arguments)
119 var err
120 if (args[0] instanceof Error) {
121 err = args[0]
122 } else {
123 err = new Error(sprintf(template, args))
124 }
125
126 // capture a stack trace to the construction point
127 Error.captureStackTrace(err, ClientError)
128
129 // adjust the [[Prototype]]
130 Object.setPrototypeOf(err, ClientError.prototype)
131
132 // redefine the error name
133 Object.defineProperty(err, 'name', {
134 enumerable: false,
135 configurable: true,
136 value: className,
137 writable: true
138 })
139
140 return err
141 }
142
143 inherits(ClientError, HttpError)
144
145 ClientError.prototype.status = code
146 ClientError.prototype.statusCode = code
147 ClientError.prototype.expose = true
148
149 return ClientError
150}
151
152/**
153 * Create a constructor for a server error.
154 * @private
155 */
156
157function createServerErrorConstructor (HttpError, name, template, code) {
158 var className = name.match(/Error$/) ? name : name + 'Error'
159
160 function ServerError () {
161 var args = Array.prototype.slice.call(arguments)
162 var err
163 if (args[0] instanceof Error) {
164 err = args[0]
165 } else {
166 err = new Error(sprintf(template, args))
167 }
168
169 // capture a stack trace to the construction point
170 Error.captureStackTrace(err, ServerError)
171
172 // adjust the [[Prototype]]
173 Object.setPrototypeOf(err, ServerError.prototype)
174
175 // redefine the error name
176 Object.defineProperty(err, 'name', {
177 enumerable: false,
178 configurable: true,
179 value: className,
180 writable: true
181 })
182
183 return err
184 }
185
186 inherits(ServerError, HttpError)
187
188 ServerError.prototype.status = code
189 ServerError.prototype.statusCode = code
190 ServerError.prototype.expose = false
191
192 return ServerError
193}
194
195/**
196 * Populate the exports object with constructors for osm-p2p custom errors.
197 * @private
198 */
199
200function populateConstructorExports (exports, errors, HttpError) {
201 Object.keys(errors).forEach(function (name) {
202 var CodeError
203 var code = errors[name].code
204 var message = errors[name].message
205
206 switch (String(code).charAt(0)) {
207 case '4':
208 CodeError = createClientErrorConstructor(HttpError, name, message, code)
209 break
210 case '5':
211 CodeError = createServerErrorConstructor(HttpError, name, message, code)
212 break
213 }
214
215 if (CodeError) {
216 // export the constructor
217 exports[name] = CodeError
218 }
219 })
220}
221
222/**
223 * @param {String} template
224 * @param {String[]} values
225 * @return {String}
226 */
227function sprintf (template, values) {
228 return template.replace(/%s/g, function () {
229 return values.shift() || ''
230 }).replace(/ {2}/g, ' ').trim() + (values.length ? '\n' + values.join('\n') : '')
231}