123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. 'use strict';
  2. var util = require('util');
  3. var isArrayish = require('is-arrayish');
  4. var errorEx = function errorEx(name, properties) {
  5. if (!name || name.constructor !== String) {
  6. properties = name || {};
  7. name = Error.name;
  8. }
  9. var errorExError = function ErrorEXError(message) {
  10. if (!this) {
  11. return new ErrorEXError(message);
  12. }
  13. message = message instanceof Error
  14. ? message.message
  15. : (message || this.message);
  16. Error.call(this, message);
  17. Error.captureStackTrace(this, errorExError);
  18. this.name = name;
  19. Object.defineProperty(this, 'message', {
  20. configurable: true,
  21. enumerable: false,
  22. get: function () {
  23. var newMessage = message.split(/\r?\n/g);
  24. for (var key in properties) {
  25. if (!properties.hasOwnProperty(key)) {
  26. continue;
  27. }
  28. var modifier = properties[key];
  29. if ('message' in modifier) {
  30. newMessage = modifier.message(this[key], newMessage) || newMessage;
  31. if (!isArrayish(newMessage)) {
  32. newMessage = [newMessage];
  33. }
  34. }
  35. }
  36. return newMessage.join('\n');
  37. },
  38. set: function (v) {
  39. message = v;
  40. }
  41. });
  42. var overwrittenStack = null;
  43. var stackDescriptor = Object.getOwnPropertyDescriptor(this, 'stack');
  44. var stackGetter = stackDescriptor.get;
  45. var stackValue = stackDescriptor.value;
  46. delete stackDescriptor.value;
  47. delete stackDescriptor.writable;
  48. stackDescriptor.set = function (newstack) {
  49. overwrittenStack = newstack;
  50. };
  51. stackDescriptor.get = function () {
  52. var stack = (overwrittenStack || ((stackGetter)
  53. ? stackGetter.call(this)
  54. : stackValue)).split(/\r?\n+/g);
  55. // starting in Node 7, the stack builder caches the message.
  56. // just replace it.
  57. if (!overwrittenStack) {
  58. stack[0] = this.name + ': ' + this.message;
  59. }
  60. var lineCount = 1;
  61. for (var key in properties) {
  62. if (!properties.hasOwnProperty(key)) {
  63. continue;
  64. }
  65. var modifier = properties[key];
  66. if ('line' in modifier) {
  67. var line = modifier.line(this[key]);
  68. if (line) {
  69. stack.splice(lineCount++, 0, ' ' + line);
  70. }
  71. }
  72. if ('stack' in modifier) {
  73. modifier.stack(this[key], stack);
  74. }
  75. }
  76. return stack.join('\n');
  77. };
  78. Object.defineProperty(this, 'stack', stackDescriptor);
  79. };
  80. if (Object.setPrototypeOf) {
  81. Object.setPrototypeOf(errorExError.prototype, Error.prototype);
  82. Object.setPrototypeOf(errorExError, Error);
  83. } else {
  84. util.inherits(errorExError, Error);
  85. }
  86. return errorExError;
  87. };
  88. errorEx.append = function (str, def) {
  89. return {
  90. message: function (v, message) {
  91. v = v || def;
  92. if (v) {
  93. message[0] += ' ' + str.replace('%s', v.toString());
  94. }
  95. return message;
  96. }
  97. };
  98. };
  99. errorEx.line = function (str, def) {
  100. return {
  101. line: function (v) {
  102. v = v || def;
  103. if (v) {
  104. return str.replace('%s', v.toString());
  105. }
  106. return null;
  107. }
  108. };
  109. };
  110. module.exports = errorEx;