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