index.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. 'use strict'
  2. /** Only accept codes that are numbers, otherwise discard them */
  3. function parseCode(code) {
  4. const number = Number(code)
  5. if (isNaN(number)) return null
  6. return number
  7. }
  8. /** Fetch the code from the value */
  9. function fetchCode(value) {
  10. return (
  11. value &&
  12. (parseCode(value.exitCode) ||
  13. parseCode(value.errno) ||
  14. parseCode(value.code))
  15. )
  16. }
  17. /** Prevent [a weird error on node version 4](https://github.com/bevry/errlop/issues/1) and below. */
  18. function isValid(value) {
  19. /* eslint no-use-before-define:0 */
  20. return value instanceof Error || Errlop.isErrlop(value)
  21. }
  22. export default class Errlop extends Error {
  23. /**
  24. * Create an instance of an error, using a message, as well as an optional parent.
  25. * If the parent is provided, then the `fullStack` property will include its stack too
  26. */
  27. constructor(input, parent) {
  28. if (!input) throw new Error('Attempted to create an Errlop without a input')
  29. // Instantiate with the above
  30. super(input.message || input)
  31. // Apply
  32. this.klass = Errlop
  33. this.parent = parent || input.parent
  34. this.ancestors = []
  35. let ancestor = this.parent
  36. while (ancestor) {
  37. this.ancestors.push(ancestor)
  38. ancestor = ancestor.parent
  39. }
  40. // this code must support node 0.8, as well as prevent a weird bug in node v4
  41. // https://travis-ci.org/bevry/editions/jobs/408828147
  42. let exitCode = fetchCode(input)
  43. if (exitCode == null) exitCode = fetchCode(this)
  44. for (
  45. let index = 0;
  46. index < this.ancestors.length && exitCode == null;
  47. ++index
  48. ) {
  49. const error = this.ancestors[index]
  50. if (isValid(error)) exitCode = fetchCode(error)
  51. }
  52. // Apply
  53. if (exitCode != null) {
  54. this.exitCode = exitCode
  55. }
  56. this.orphanStack = (input.stack || this.stack).toString()
  57. this.stack = this.ancestors.reduce(
  58. (accumulator, error) =>
  59. `${accumulator}\n↳ ${error.orphanStack || error.stack || error}`,
  60. this.orphanStack
  61. )
  62. }
  63. /**
  64. * Syntatic sugar for Errlop class creation.
  65. * Enables `Errlop.create(...args)` to achieve `new Errlop(...args)`
  66. */
  67. static create(input, parent) {
  68. return new this(input, parent)
  69. }
  70. /** Check whether or not the value is an Errlop instance */
  71. static isErrlop(value) {
  72. return value && (value instanceof this || value.klass === this)
  73. }
  74. /** Ensure that the value is an Errlop instance */
  75. static ensure(value) {
  76. return this.isErrlop(value) ? value : this.create(value)
  77. }
  78. }