From d6485549db3781da391d8804215e47a4e9c13d2e Mon Sep 17 00:00:00 2001 From: Iskren Slavov Date: Sun, 7 Jan 2024 19:54:53 +0200 Subject: [PATCH] Simplify stack track merging to fix source maps. --- src/__tests__/errors.test.ts | 57 ++++++++++++++++++++---------------- src/errors.ts | 36 +++++++++++++---------- 2 files changed, 52 insertions(+), 41 deletions(-) diff --git a/src/__tests__/errors.test.ts b/src/__tests__/errors.test.ts index 5489fa5..4443edd 100644 --- a/src/__tests__/errors.test.ts +++ b/src/__tests__/errors.test.ts @@ -1,32 +1,32 @@ import { PersistError, RehydrateError } from '../errors'; describe('errors.ts', () => { - const extractParentErrorStack = (errorInstance: Error): string => { - const stackLines = errorInstance.stack!.split('\n'); - return stackLines - .slice(2, stackLines.length) - .join('\n'); - }; - describe('PersistError', () => { it('extends Error', () => { - const instance = new PersistError(new Error()); + const error = new Error('ERROR 1-0'); + const instance = new PersistError(error); expect(instance).toBeInstanceOf(Error); expect(instance).toBeInstanceOf(PersistError); - expect(instance.message).toEqual('redux-remember: persist error'); + expect(instance.originalError).toEqual(error); + expect(instance.message).toEqual(`${error.name}: ${error.message}`); }); it('copies the stack trace of wrapped Error', () => { - const error = new Error('ERROR 1'); + const error = new Error('ERROR 1-1'); + const errorStackLines = error.stack!.split('\n'); + const errorStackOnly = errorStackLines + .slice(1, errorStackLines.length) + .join('\n'); + const instance = new PersistError(error); - const instanceMessage = instance.stack!.slice( - 0, - instance.stack!.indexOf('\n') - ); + const instanceStackLine1 = instance.stack!.split('\n')[1]; - expect(instanceMessage).toEqual(`PersistError: ${instance.message}`); - expect(extractParentErrorStack(instance)).toEqual(error.stack); + expect(instance.stack).toEqual( + `PersistError: Error: ${error.message}\n` + + `${instanceStackLine1}\n` + + `${errorStackOnly}` + ); }); it('does not break when an invalid error is wrapped', () => { @@ -36,23 +36,30 @@ describe('errors.ts', () => { describe('RehydrateError', () => { it('extends Error', () => { - const instance = new RehydrateError(new Error()); + const error = new Error('ERROR 2-0'); + const instance = new RehydrateError(error); expect(instance).toBeInstanceOf(Error); expect(instance).toBeInstanceOf(RehydrateError); - expect(instance.message).toEqual('redux-remember: rehydrate error'); + expect(instance.originalError).toEqual(error); + expect(instance.message).toEqual(`${error.name}: ${error.message}`); }); it('copies the stack trace of wrapped Error', () => { - const error = new Error('ERROR 2'); + const error = new Error('ERROR 1-1'); + const errorStackLines = error.stack!.split('\n'); + const errorStackOnly = errorStackLines + .slice(1, errorStackLines.length) + .join('\n'); + const instance = new RehydrateError(error); - const instanceMessage = instance.stack!.slice( - 0, - instance.stack!.indexOf('\n') - ); + const instanceStackLine1 = instance.stack!.split('\n')[1]; - expect(instanceMessage).toEqual(`RehydrateError: ${instance.message}`); - expect(extractParentErrorStack(instance)).toEqual(error.stack); + expect(instance.stack).toEqual( + `RehydrateError: Error: ${error.message}\n` + + `${instanceStackLine1}\n` + + `${errorStackOnly}` + ); }); it('does not break when an invalid error is wrapped', () => { diff --git a/src/errors.ts b/src/errors.ts index d3f4bfa..dbe9453 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -1,28 +1,32 @@ class CustomError extends Error { - constructor(message: string, previousError: unknown) { - const prevStack = (previousError as Error)?.stack || ''; + originalError?: Error; + + constructor(originalError: unknown) { + const isOrigErrorValid = originalError instanceof Error; + const prevStackLines = isOrigErrorValid + ? originalError.stack?.split('\n') + : []; + + super(isOrigErrorValid + ? `${originalError.name}: ${originalError.message}` + : ''); - super(message); this.name = this.constructor.name; + if (isOrigErrorValid) { + this.originalError = originalError; + } - if (prevStack && this.stack) { + if (prevStackLines?.length && this.stack) { this.stack = this.stack .split('\n') .slice(0, 2) - .concat(prevStack) + .concat( + prevStackLines.slice(1, prevStackLines.length) + ) .join('\n'); } } } -export class PersistError extends CustomError { - constructor(previousError: unknown) { - super('redux-remember: persist error', previousError); - } -} - -export class RehydrateError extends CustomError { - constructor(previousError: unknown) { - super('redux-remember: rehydrate error', previousError); - } -} +export class PersistError extends CustomError {} +export class RehydrateError extends CustomError {}