stack.js 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. const newline = /\r?\n/;
  2. const onoCall = /\bono[ @]/;
  3. /**
  4. * Is the property lazily computed?
  5. */
  6. export function isLazyStack(stackProp) {
  7. return Boolean(stackProp &&
  8. stackProp.configurable &&
  9. typeof stackProp.get === "function");
  10. }
  11. /**
  12. * Is the stack property writable?
  13. */
  14. export function isWritableStack(stackProp) {
  15. return Boolean(
  16. // If there is no stack property, then it's writable, since assigning it will create it
  17. !stackProp ||
  18. stackProp.writable ||
  19. typeof stackProp.set === "function");
  20. }
  21. /**
  22. * Appends the original `Error.stack` property to the new Error's stack.
  23. */
  24. export function joinStacks(newError, originalError) {
  25. let newStack = popStack(newError.stack);
  26. let originalStack = originalError ? originalError.stack : undefined;
  27. if (newStack && originalStack) {
  28. return newStack + "\n\n" + originalStack;
  29. }
  30. else {
  31. return newStack || originalStack;
  32. }
  33. }
  34. /**
  35. * Calls `joinStacks` lazily, when the `Error.stack` property is accessed.
  36. */
  37. export function lazyJoinStacks(lazyStack, newError, originalError) {
  38. if (originalError) {
  39. Object.defineProperty(newError, "stack", {
  40. get: () => {
  41. let newStack = lazyStack.get.apply(newError);
  42. return joinStacks({ stack: newStack }, originalError);
  43. },
  44. enumerable: false,
  45. configurable: true
  46. });
  47. }
  48. else {
  49. lazyPopStack(newError, lazyStack);
  50. }
  51. }
  52. /**
  53. * Removes Ono from the stack, so that the stack starts at the original error location
  54. */
  55. function popStack(stack) {
  56. if (stack) {
  57. let lines = stack.split(newline);
  58. // Find the Ono call(s) in the stack, and remove them
  59. let onoStart;
  60. for (let i = 0; i < lines.length; i++) {
  61. let line = lines[i];
  62. if (onoCall.test(line)) {
  63. if (onoStart === undefined) {
  64. // We found the first Ono call in the stack trace.
  65. // There may be other subsequent Ono calls as well.
  66. onoStart = i;
  67. }
  68. }
  69. else if (onoStart !== undefined) {
  70. // We found the first non-Ono call after one or more Ono calls.
  71. // So remove the Ono call lines from the stack trace
  72. lines.splice(onoStart, i - onoStart);
  73. break;
  74. }
  75. }
  76. if (lines.length > 0) {
  77. return lines.join("\n");
  78. }
  79. }
  80. // If we get here, then the stack doesn't contain a call to `ono`.
  81. // This may be due to minification or some optimization of the JS engine.
  82. // So just return the stack as-is.
  83. return stack;
  84. }
  85. /**
  86. * Calls `popStack` lazily, when the `Error.stack` property is accessed.
  87. */
  88. function lazyPopStack(error, lazyStack) {
  89. Object.defineProperty(error, "stack", {
  90. get: () => popStack(lazyStack.get.apply(error)),
  91. enumerable: false,
  92. configurable: true
  93. });
  94. }
  95. //# sourceMappingURL=stack.js.map