commit inicial
[VSoRC/.git] / node_modules / http-errors / index.js
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 deprecate = require('depd')('http-errors')
16 var setPrototypeOf = require('setprototypeof')
17 var statuses = require('statuses')
18 var inherits = require('inherits')
19 var toIdentifier = require('toidentifier')
20
21 /**
22  * Module exports.
23  * @public
24  */
25
26 module.exports = createError
27 module.exports.HttpError = createHttpErrorConstructor()
28
29 // Populate exports for all constructors
30 populateConstructorExports(module.exports, statuses.codes, module.exports.HttpError)
31
32 /**
33  * Get the code class of a status code.
34  * @private
35  */
36
37 function codeClass (status) {
38   return Number(String(status).charAt(0) + '00')
39 }
40
41 /**
42  * Create a new HTTP Error.
43  *
44  * @returns {Error}
45  * @public
46  */
47
48 function createError () {
49   // so much arity going on ~_~
50   var err
51   var msg
52   var status = 500
53   var props = {}
54   for (var i = 0; i < arguments.length; i++) {
55     var arg = arguments[i]
56     if (arg instanceof Error) {
57       err = arg
58       status = err.status || err.statusCode || status
59       continue
60     }
61     switch (typeof arg) {
62       case 'string':
63         msg = arg
64         break
65       case 'number':
66         status = arg
67         if (i !== 0) {
68           deprecate('non-first-argument status code; replace with createError(' + arg + ', ...)')
69         }
70         break
71       case 'object':
72         props = arg
73         break
74     }
75   }
76
77   if (typeof status === 'number' && (status < 400 || status >= 600)) {
78     deprecate('non-error status code; use only 4xx or 5xx status codes')
79   }
80
81   if (typeof status !== 'number' ||
82     (!statuses[status] && (status < 400 || status >= 600))) {
83     status = 500
84   }
85
86   // constructor
87   var HttpError = createError[status] || createError[codeClass(status)]
88
89   if (!err) {
90     // create error
91     err = HttpError
92       ? new HttpError(msg)
93       : new Error(msg || statuses[status])
94     Error.captureStackTrace(err, createError)
95   }
96
97   if (!HttpError || !(err instanceof HttpError) || err.status !== status) {
98     // add properties to generic error
99     err.expose = status < 500
100     err.status = err.statusCode = status
101   }
102
103   for (var key in props) {
104     if (key !== 'status' && key !== 'statusCode') {
105       err[key] = props[key]
106     }
107   }
108
109   return err
110 }
111
112 /**
113  * Create HTTP error abstract base class.
114  * @private
115  */
116
117 function createHttpErrorConstructor () {
118   function HttpError () {
119     throw new TypeError('cannot construct abstract class')
120   }
121
122   inherits(HttpError, Error)
123
124   return HttpError
125 }
126
127 /**
128  * Create a constructor for a client error.
129  * @private
130  */
131
132 function createClientErrorConstructor (HttpError, name, code) {
133   var className = name.match(/Error$/) ? name : name + 'Error'
134
135   function ClientError (message) {
136     // create the error object
137     var msg = message != null ? message : statuses[code]
138     var err = new Error(msg)
139
140     // capture a stack trace to the construction point
141     Error.captureStackTrace(err, ClientError)
142
143     // adjust the [[Prototype]]
144     setPrototypeOf(err, ClientError.prototype)
145
146     // redefine the error message
147     Object.defineProperty(err, 'message', {
148       enumerable: true,
149       configurable: true,
150       value: msg,
151       writable: true
152     })
153
154     // redefine the error name
155     Object.defineProperty(err, 'name', {
156       enumerable: false,
157       configurable: true,
158       value: className,
159       writable: true
160     })
161
162     return err
163   }
164
165   inherits(ClientError, HttpError)
166   nameFunc(ClientError, className)
167
168   ClientError.prototype.status = code
169   ClientError.prototype.statusCode = code
170   ClientError.prototype.expose = true
171
172   return ClientError
173 }
174
175 /**
176  * Create a constructor for a server error.
177  * @private
178  */
179
180 function createServerErrorConstructor (HttpError, name, code) {
181   var className = name.match(/Error$/) ? name : name + 'Error'
182
183   function ServerError (message) {
184     // create the error object
185     var msg = message != null ? message : statuses[code]
186     var err = new Error(msg)
187
188     // capture a stack trace to the construction point
189     Error.captureStackTrace(err, ServerError)
190
191     // adjust the [[Prototype]]
192     setPrototypeOf(err, ServerError.prototype)
193
194     // redefine the error message
195     Object.defineProperty(err, 'message', {
196       enumerable: true,
197       configurable: true,
198       value: msg,
199       writable: true
200     })
201
202     // redefine the error name
203     Object.defineProperty(err, 'name', {
204       enumerable: false,
205       configurable: true,
206       value: className,
207       writable: true
208     })
209
210     return err
211   }
212
213   inherits(ServerError, HttpError)
214   nameFunc(ServerError, className)
215
216   ServerError.prototype.status = code
217   ServerError.prototype.statusCode = code
218   ServerError.prototype.expose = false
219
220   return ServerError
221 }
222
223 /**
224  * Set the name of a function, if possible.
225  * @private
226  */
227
228 function nameFunc (func, name) {
229   var desc = Object.getOwnPropertyDescriptor(func, 'name')
230
231   if (desc && desc.configurable) {
232     desc.value = name
233     Object.defineProperty(func, 'name', desc)
234   }
235 }
236
237 /**
238  * Populate the exports object with constructors for every error class.
239  * @private
240  */
241
242 function populateConstructorExports (exports, codes, HttpError) {
243   codes.forEach(function forEachCode (code) {
244     var CodeError
245     var name = toIdentifier(statuses[code])
246
247     switch (codeClass(code)) {
248       case 400:
249         CodeError = createClientErrorConstructor(HttpError, name, code)
250         break
251       case 500:
252         CodeError = createServerErrorConstructor(HttpError, name, code)
253         break
254     }
255
256     if (CodeError) {
257       // export the constructor
258       exports[code] = CodeError
259       exports[name] = CodeError
260     }
261   })
262
263   // backwards-compatibility
264   exports["I'mateapot"] = deprecate.function(exports.ImATeapot,
265     '"I\'mateapot"; use "ImATeapot" instead')
266 }