twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

index.js (5878B)


      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 }