Skip to content

Commit 5e99300

Browse files
committed
Trying out proxies instead to wrap the error chain object, and either strip or configure the error chain...
1 parent e930b4d commit 5e99300

File tree

3 files changed

+58
-22
lines changed

3 files changed

+58
-22
lines changed

src/AbstractError.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { CustomError } from 'ts-custom-error';
66
* Abstract error
77
* Intended for further extension
88
*/
9-
class AbstractError<T extends Error | void = void> extends CustomError {
9+
class AbstractError<T = void> extends CustomError {
1010
/**
1111
* Static description of exception
1212
*/
@@ -56,6 +56,11 @@ class AbstractError<T extends Error | void = void> extends CustomError {
5656
* Not all causes can be stringified
5757
* You must use the replacer to encode the cause property
5858
*/
59+
60+
61+
// We should use a Proxy, to "proxy the object" or the exception chain
62+
// And then specialise the toJSON, rather than doing this?
63+
5964
public toJSON(
6065
_key: string = '',
6166
options: {
@@ -94,6 +99,7 @@ class AbstractError<T extends Error | void = void> extends CustomError {
9499
if (this.cause instanceof AbstractError) {
95100
data.cause = this.cause.toJSON('cause', options);
96101
} else {
102+
// Use `replacer` to further encode this object
97103
data.cause = this.cause;
98104
}
99105
}
@@ -104,7 +110,7 @@ class AbstractError<T extends Error | void = void> extends CustomError {
104110
};
105111
}
106112

107-
public static fromJSON(json: any): AbstractError<any> | undefined {
113+
public static fromJSON(json: any): AbstractError<unknown> | undefined {
108114
if (typeof json !== 'object' || json == null) {
109115
return;
110116
}
@@ -122,8 +128,9 @@ class AbstractError<T extends Error | void = void> extends CustomError {
122128
}
123129
let timestamp;
124130
if (json.data.timestamp != null) {
125-
if (!isNaN(Date.parse(json.data.timestamp))) {
126-
timestamp = new Date(timestamp);
131+
const timestampParsed = Date.parse(json.data.timestamp);
132+
if (!isNaN(timestampParsed)) {
133+
timestamp = new Date(timestampParsed);
127134
} else {
128135
return;
129136
}
@@ -134,24 +141,16 @@ class AbstractError<T extends Error | void = void> extends CustomError {
134141
if (json.data.stack != null && typeof json.data.stack !== 'string') {
135142
return;
136143
}
137-
let cause;
138-
if (json.data.cause != null) {
139-
// THIS is a problem
140-
// we don't know what the cause may be
141-
// We don't know how to reconstruct it
142-
// It is neither Error, nor AbstractError
143-
// Do we check up the chain?
144-
// The problem is that we can't really decode this if we don't know what the chain might be
145-
// If e as an instance can be encoded with arbitrary error objects
146-
// Then during decoding, how would we know how to reconstruct it?
147-
// super.name
148144

149-
cause = this.fromJSON(json.data.cause);
150-
}
145+
// The cause cannot be reconstructed, unless it's the same as this exception class
146+
// Even then, that would only be the case, if we use toError() again on it
147+
// and no it's not part of the chain of exceptions
148+
// An alternative is class decoration
149+
151150
const e = new this(json.data.message, {
152151
data: json.data.data ?? {},
153152
timestamp: timestamp,
154-
cause: cause,
153+
cause: json.data.cause,
155154
});
156155
e.stack = json.data.stack;
157156
return e;

src/utils.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ any key can be further processed
99
}
1010
*/
1111

12+
// the replacer is designed for the cause chain
13+
// not for other exceptions
14+
// in fact using this is completely optional
15+
// we may even in fact not bother with this at all
16+
1217
function replacer(options) {
1318
return (key: string, value: any): any => {
1419
if (value instanceof Error) {
@@ -25,6 +30,32 @@ function replacer(options) {
2530
};
2631
}
2732

33+
// filterError
34+
35+
function filterError (e, options) {
36+
const handler = {
37+
get(target, propKey, receiver) {
38+
const targetValue = Reflect.get(target, propKey, receiver);
39+
if (typeof targetValue === 'function') {
40+
return function (...args) {
41+
// Set certain options here
42+
if (propKey === 'toJSON') {
43+
args[1] = options;
44+
}
45+
46+
// Again how does this actually, pass down to the other objects?
47+
48+
return targetValue.apply(this, args);
49+
};
50+
} else {
51+
return targetValue;
52+
}
53+
}
54+
}
55+
return new Proxy(e, handler);
56+
}
57+
2858
export {
29-
replacer
59+
replacer,
60+
filterError
3061
};

test-json.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { AbstractError } from "./src";
2-
import { replacer } from './src/utils';
2+
import { replacer, filterError } from './src/utils';
33

44
async function main () {
55

@@ -30,11 +30,17 @@ async function main () {
3030
// if you want to prevent stack though, or message that's up to you
3131

3232
const j = JSON.stringify(
33-
e3.toJSON(undefined, { stack: false, data: false }),
34-
replacer,
33+
filterError(e3, { stack: false }),
34+
null,
3535
2
3636
);
3737

38+
// const j = JSON.stringify(
39+
// e3.toJSON(undefined, { stack: false, data: false }),
40+
// replacer,
41+
// 2
42+
// );
43+
3844
console.log(j)
3945

4046
}

0 commit comments

Comments
 (0)