index.js 4.6 KB

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