makeerror.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. var tmpl = require('tmpl')
  2. module.exports = makeError
  3. function BaseError() {}
  4. BaseError.prototype = new Error()
  5. BaseError.prototype.toString = function() {
  6. return this.message
  7. }
  8. /**
  9. * Makes an Error function with the signature:
  10. *
  11. * function(message, data)
  12. *
  13. * You'll typically do something like:
  14. *
  15. * var UnknownFileTypeError = makeError(
  16. * 'UnknownFileTypeError',
  17. * 'The specified type is not known.'
  18. * )
  19. * var er = UnknownFileTypeError()
  20. *
  21. * `er` will have a prototype chain that ensures:
  22. *
  23. * er instanceof Error
  24. * er instanceof UnknownFileTypeError
  25. *
  26. * You can also do `var er = new UnknownFileTypeError()` if you really like the
  27. * `new` keyword.
  28. *
  29. * @param String The name of the error.
  30. * @param String The default message string.
  31. * @param Object The default data object, merged with per instance data.
  32. */
  33. function makeError(name, defaultMessage, defaultData) {
  34. defaultMessage = tmpl(defaultMessage || '')
  35. defaultData = defaultData || {}
  36. if (defaultData.proto && !(defaultData.proto instanceof BaseError))
  37. throw new Error('The custom "proto" must be an Error created via makeError')
  38. var CustomError = function(message, data) {
  39. if (!(this instanceof CustomError)) return new CustomError(message, data)
  40. if (typeof message !== 'string' && !data) {
  41. data = message
  42. message = null
  43. }
  44. this.name = name
  45. this.data = data || defaultData
  46. if (typeof message === 'string') {
  47. this.message = tmpl(message, this.data)
  48. } else {
  49. this.message = defaultMessage(this.data)
  50. }
  51. var er = new Error()
  52. this.stack = er.stack
  53. if (this.stack) {
  54. // remove TWO stack level:
  55. if (typeof Components !== 'undefined') {
  56. // Mozilla:
  57. this.stack = this.stack.substring(this.stack.indexOf('\n') + 2)
  58. } else if (typeof chrome !== 'undefined' || typeof process !== 'undefined') {
  59. // Google Chrome/Node.js:
  60. this.stack = this.stack.replace(/\n[^\n]*/, '')
  61. this.stack = this.stack.replace(/\n[^\n]*/, '')
  62. this.stack = (
  63. this.name +
  64. (this.message ? (': ' + this.message) : '') +
  65. this.stack.substring(5)
  66. )
  67. }
  68. }
  69. if ('fileName' in er) this.fileName = er.fileName
  70. if ('lineNumber' in er) this.lineNumber = er.lineNumber
  71. }
  72. CustomError.prototype = defaultData.proto || new BaseError()
  73. delete defaultData.proto
  74. return CustomError
  75. }