index.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. 'use strict'
  2. /**
  3. * Make custom error types that pass `instanceof` checks, have stack traces,
  4. * support custom messages and properties, and support wrapping errors (causes).
  5. *
  6. * @module
  7. */
  8. /**
  9. * A base class for custom errors that handles:
  10. *
  11. * 1. Wrapping an optional 'cause'.
  12. * 2. Storing an 'info' object with additional data.
  13. * 3. Setting the name to the subclass name.
  14. *
  15. * @extends Error
  16. */
  17. class OError extends Error {
  18. /**
  19. * @param {string} message as for built-in Error
  20. * @param {?object} info extra data to attach to the error
  21. */
  22. constructor ({ message, info }) {
  23. super(message)
  24. this.name = this.constructor.name
  25. if (info) {
  26. this.info = info
  27. }
  28. }
  29. /**
  30. * Wrap the given error, which caused this error.
  31. *
  32. * @param {Error} cause
  33. * @return {this}
  34. */
  35. withCause (cause) {
  36. this.cause = cause
  37. if (this.message && cause.message) {
  38. this.message += ': ' + cause.message
  39. }
  40. return this
  41. }
  42. }
  43. /**
  44. * Return the `info` property from `error` and recursively merge the `info`
  45. * properties from the error's causes, if any.
  46. *
  47. * If a property is repeated, the first one in the cause chain wins.
  48. *
  49. * @param {?Error} error assumed not to have circular causes
  50. * @return {Object}
  51. */
  52. function getFullInfo (error) {
  53. if (!error) return {}
  54. const info = getFullInfo(error.cause)
  55. if (typeof error.info === 'object') Object.assign(info, error.info)
  56. return info
  57. }
  58. /**
  59. * Return the `stack` property from `error` and recursively append the `stack`
  60. * properties from the error's causes, if any.
  61. *
  62. * @param {?Error} error assumed not to have circular causes
  63. * @return {string}
  64. */
  65. function getFullStack (error) {
  66. if (!error) return ''
  67. const causeStack = getFullStack(error.cause)
  68. if (causeStack) return (error.stack + '\ncaused by: ' + causeStack)
  69. return error.stack
  70. }
  71. /**
  72. * Is `error` or one of its causes an instance of `klass`?
  73. *
  74. * @param {?Error} error assumed not to have circular causes
  75. * @param {function} klass
  76. * @return {Boolean}
  77. */
  78. function hasCauseInstanceOf (error, klass) {
  79. if (!error) return false
  80. return error instanceof klass || hasCauseInstanceOf(error.cause, klass)
  81. }
  82. OError.getFullInfo = getFullInfo
  83. OError.getFullStack = getFullStack
  84. OError.hasCauseInstanceOf = hasCauseInstanceOf
  85. module.exports = OError