extend-error.js 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import { addInspectMethod } from "./isomorphic.node";
  2. import { isLazyStack, isWritableStack, joinStacks, lazyJoinStacks } from "./stack";
  3. import { getDeepKeys, toJSON } from "./to-json";
  4. const protectedProps = ["name", "message", "stack"];
  5. /**
  6. * Extends the new error with the properties of the original error and the `props` object.
  7. *
  8. * @param newError - The error object to extend
  9. * @param originalError - The original error object, if any
  10. * @param props - Additional properties to add, if any
  11. */
  12. export function extendError(error, originalError, props) {
  13. let onoError = error;
  14. extendStack(onoError, originalError);
  15. // Copy properties from the original error
  16. if (originalError && typeof originalError === "object") {
  17. mergeErrors(onoError, originalError);
  18. }
  19. // The default `toJSON` method doesn't output props like `name`, `message`, `stack`, etc.
  20. // So replace it with one that outputs every property of the error.
  21. onoError.toJSON = toJSON;
  22. // On Node.js, add support for the `util.inspect()` method
  23. // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
  24. if (addInspectMethod) {
  25. addInspectMethod(onoError);
  26. }
  27. // Finally, copy custom properties that were specified by the user.
  28. // These props OVERWRITE any previous props
  29. if (props && typeof props === "object") {
  30. Object.assign(onoError, props);
  31. }
  32. return onoError;
  33. }
  34. /**
  35. * Extend the error stack to include its cause
  36. */
  37. function extendStack(newError, originalError) {
  38. let stackProp = Object.getOwnPropertyDescriptor(newError, "stack");
  39. if (isLazyStack(stackProp)) {
  40. lazyJoinStacks(stackProp, newError, originalError);
  41. }
  42. else if (isWritableStack(stackProp)) {
  43. newError.stack = joinStacks(newError, originalError);
  44. }
  45. }
  46. /**
  47. * Merges properties of the original error with the new error.
  48. *
  49. * @param newError - The error object to extend
  50. * @param originalError - The original error object, if any
  51. */
  52. function mergeErrors(newError, originalError) {
  53. // Get the original error's keys
  54. // NOTE: We specifically exclude properties that we have already set on the new error.
  55. // This is _especially_ important for the `stack` property, because this property has
  56. // a lazy getter in some environments
  57. let keys = getDeepKeys(originalError, protectedProps);
  58. // HACK: We have to cast the errors to `any` so we can use symbol indexers.
  59. // see https://github.com/Microsoft/TypeScript/issues/1863
  60. let _newError = newError;
  61. let _originalError = originalError;
  62. for (let key of keys) {
  63. if (_newError[key] === undefined) {
  64. try {
  65. _newError[key] = _originalError[key];
  66. }
  67. catch (e) {
  68. // This property is read-only, so it can't be copied
  69. }
  70. }
  71. }
  72. }
  73. //# sourceMappingURL=extend-error.js.map