-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
135 lines (111 loc) · 2.97 KB
/
index.js
File metadata and controls
135 lines (111 loc) · 2.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
const isNonErrorSymbol = Symbol('isNonError');
function defineProperty(object, key, value) {
Object.defineProperty(object, key, {
value,
writable: false,
enumerable: false,
configurable: false,
});
}
function stringify(value) {
if (value === undefined) {
return 'undefined';
}
if (value === null) {
return 'null';
}
if (typeof value === 'string') {
return value;
}
if (typeof value === 'number' || typeof value === 'boolean') {
return String(value);
}
if (typeof value === 'bigint') {
return `${value}n`;
}
if (typeof value === 'symbol') {
return value.toString();
}
if (typeof value === 'function') {
return `[Function${value.name ? ` ${value.name}` : ' (anonymous)'}]`;
}
// TODO: Use `Error.isError` when targeting Node.js 24
if (value instanceof Error) {
try {
return String(value);
} catch {
return '<Unserializable error>';
}
}
try {
return JSON.stringify(value);
} catch {
try {
return String(value);
} catch {
return '<Unserializable value>';
}
}
}
export default class NonError extends Error {
constructor(value, {superclass: Superclass = Error} = {}) {
// If already a NonError, return it as-is
if (NonError.isNonError(value)) {
return value; // eslint-disable-line no-constructor-return
}
if (value instanceof Error) {
throw new TypeError('Do not pass Error instances to NonError. Throw the error directly instead.');
}
super(`Non-error value: ${stringify(value)}`);
if (Superclass !== Error) {
// Change this instance's prototype to Superclass.prototype
// This makes instanceof Superclass work
Object.setPrototypeOf(this, Superclass.prototype);
}
defineProperty(this, 'name', 'NonError');
defineProperty(this, isNonErrorSymbol, true);
defineProperty(this, 'isNonError', true);
defineProperty(this, 'value', value);
}
static isNonError(value) {
return value?.[isNonErrorSymbol] === true;
}
static #handleCallback(callback, arguments_) {
try {
const result = callback(...arguments_);
// If the result is thenable (Promise-like), handle async rejections
if (result && typeof result.then === 'function') {
return (async () => {
try {
return await result;
} catch (error) {
// TODO: Use `Error.isError` when targeting Node.js 24
if (error instanceof Error) {
throw error;
}
throw new NonError(error);
}
})();
}
return result;
} catch (error) {
// TODO: Use `Error.isError` when targeting Node.js 24
// If it's already an Error, re-throw as-is
if (error instanceof Error) {
throw error;
}
// Otherwise, wrap it in NonError
throw new NonError(error);
}
}
static try(callback) {
return NonError.#handleCallback(callback, []);
}
static wrap(callback) {
return (...arguments_) => NonError.#handleCallback(callback, arguments_);
}
// This makes instanceof work even when using the `superclass` option
static [Symbol.hasInstance](instance) {
return NonError.isNonError(instance);
}
}