UNPKG

3.37 kBPlain TextView Raw
1/* eslint-disable no-continue */
2/* eslint-disable no-unused-vars */
3/* eslint-disable no-param-reassign */
4/* eslint-disable no-prototype-builtins */
5
6const errorClasses = {};
7const deserializers = {};
8
9export const addCustomErrorDeserializer = (
10 name: string,
11 deserializer: (obj: any) => any
12): void => {
13 deserializers[name] = deserializer;
14};
15
16type CustomErrorFunc = (
17 message?: string,
18 fields?: { [key: string]: any }
19) => void;
20
21export const createCustomErrorClass = (name: string): CustomErrorFunc => {
22 const C: CustomErrorFunc = function CustomError(message, fields): void {
23 Object.assign(this, fields);
24 this.name = name;
25 this.message = message || name;
26 this.stack = new Error().stack;
27 };
28 C.prototype = new Error();
29 errorClasses[name] = C;
30 return C;
31};
32
33// inspired from https://github.com/programble/errio/blob/master/index.js
34export const deserializeError = (object: any): Error => {
35 if (typeof object === "object" && object) {
36 try {
37 // $FlowFixMe FIXME HACK
38 const msg = JSON.parse(object.message);
39 if (msg.message && msg.name) {
40 object = msg;
41 }
42 } catch (e) {
43 // nothing
44 }
45
46 let error;
47 if (typeof object.name === "string") {
48 const { name } = object;
49 const des = deserializers[name];
50 if (des) {
51 error = des(object);
52 } else {
53 let constructor = name === "Error" ? Error : errorClasses[name];
54
55 if (!constructor) {
56 console.warn("deserializing an unknown class '" + name + "'");
57 constructor = createCustomErrorClass(name);
58 }
59
60 error = Object.create(constructor.prototype);
61 try {
62 for (const prop in object) {
63 if (object.hasOwnProperty(prop)) {
64 error[prop] = object[prop];
65 }
66 }
67 } catch (e) {
68 // sometimes setting a property can fail (e.g. .name)
69 }
70 }
71 } else {
72 error = new Error(object.message);
73 }
74
75 if (!error.stack && Error.captureStackTrace) {
76 Error.captureStackTrace(error, deserializeError);
77 }
78 return error;
79 }
80 return new Error(String(object));
81};
82
83// inspired from https://github.com/sindresorhus/serialize-error/blob/master/index.js
84export const serializeError = (value: any): undefined | To | string => {
85 if (!value) return value;
86 if (typeof value === "object") {
87 return destroyCircular(value, []);
88 }
89 if (typeof value === "function") {
90 return `[Function: ${value.name || "anonymous"}]`;
91 }
92 return value;
93};
94
95interface To {
96 name?: string;
97 message?: string;
98 stack?: string;
99}
100
101// https://www.npmjs.com/package/destroy-circular
102function destroyCircular(from: any, seen: any[]): To {
103 const to: To = {};
104 seen.push(from);
105 for (const key of Object.keys(from)) {
106 const value = from[key];
107 if (typeof value === "function") {
108 continue;
109 }
110 if (!value || typeof value !== "object") {
111 to[key] = value;
112 continue;
113 }
114 if (seen.indexOf(from[key]) === -1) {
115 to[key] = destroyCircular(from[key], seen.slice(0));
116 continue;
117 }
118 to[key] = "[Circular]";
119 }
120 if (typeof from.name === "string") {
121 to.name = from.name;
122 }
123 if (typeof from.message === "string") {
124 to.message = from.message;
125 }
126 if (typeof from.stack === "string") {
127 to.stack = from.stack;
128 }
129 return to;
130}