Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/util/vs/base/common/errors.ts
13405 views
1
//!!! DO NOT modify, this file was COPIED from 'microsoft/vscode'
2
3
/*---------------------------------------------------------------------------------------------
4
* Copyright (c) Microsoft Corporation. All rights reserved.
5
* Licensed under the MIT License. See License.txt in the project root for license information.
6
*--------------------------------------------------------------------------------------------*/
7
8
export interface ErrorListenerCallback {
9
(error: any): void;
10
}
11
12
export interface ErrorListenerUnbind {
13
(): void;
14
}
15
16
// Avoid circular dependency on EventEmitter by implementing a subset of the interface.
17
export class ErrorHandler {
18
private unexpectedErrorHandler: (e: any) => void;
19
private listeners: ErrorListenerCallback[];
20
21
constructor() {
22
23
this.listeners = [];
24
25
this.unexpectedErrorHandler = function (e: any) {
26
setTimeout(() => {
27
if (e.stack) {
28
if (ErrorNoTelemetry.isErrorNoTelemetry(e)) {
29
throw new ErrorNoTelemetry(e.message + '\n\n' + e.stack);
30
}
31
32
throw new Error(e.message + '\n\n' + e.stack);
33
}
34
35
throw e;
36
}, 0);
37
};
38
}
39
40
addListener(listener: ErrorListenerCallback): ErrorListenerUnbind {
41
this.listeners.push(listener);
42
43
return () => {
44
this._removeListener(listener);
45
};
46
}
47
48
private emit(e: any): void {
49
this.listeners.forEach((listener) => {
50
listener(e);
51
});
52
}
53
54
private _removeListener(listener: ErrorListenerCallback): void {
55
this.listeners.splice(this.listeners.indexOf(listener), 1);
56
}
57
58
setUnexpectedErrorHandler(newUnexpectedErrorHandler: (e: any) => void): void {
59
this.unexpectedErrorHandler = newUnexpectedErrorHandler;
60
}
61
62
getUnexpectedErrorHandler(): (e: any) => void {
63
return this.unexpectedErrorHandler;
64
}
65
66
onUnexpectedError(e: any): void {
67
this.unexpectedErrorHandler(e);
68
this.emit(e);
69
}
70
71
// For external errors, we don't want the listeners to be called
72
onUnexpectedExternalError(e: any): void {
73
this.unexpectedErrorHandler(e);
74
}
75
}
76
77
export const errorHandler = new ErrorHandler();
78
79
/** @skipMangle */
80
export function setUnexpectedErrorHandler(newUnexpectedErrorHandler: (e: any) => void): void {
81
errorHandler.setUnexpectedErrorHandler(newUnexpectedErrorHandler);
82
}
83
84
/**
85
* Returns if the error is a SIGPIPE error. SIGPIPE errors should generally be
86
* logged at most once, to avoid a loop.
87
*
88
* @see https://github.com/microsoft/vscode-remote-release/issues/6481
89
*/
90
export function isSigPipeError(e: unknown): e is Error {
91
if (!e || typeof e !== 'object') {
92
return false;
93
}
94
95
const cast = e as Record<string, string | undefined>;
96
return cast.code === 'EPIPE' && cast.syscall?.toUpperCase() === 'WRITE';
97
}
98
99
/**
100
* This function should only be called with errors that indicate a bug in the product.
101
* E.g. buggy extensions/invalid user-input/network issues should not be able to trigger this code path.
102
* If they are, this indicates there is also a bug in the product.
103
*/
104
export function onBugIndicatingError(e: any): undefined {
105
errorHandler.onUnexpectedError(e);
106
return undefined;
107
}
108
109
export function onUnexpectedError(e: any): undefined {
110
// ignore errors from cancelled promises
111
if (!isCancellationError(e)) {
112
errorHandler.onUnexpectedError(e);
113
}
114
return undefined;
115
}
116
117
export function onUnexpectedExternalError(e: any): undefined {
118
// ignore errors from cancelled promises
119
if (!isCancellationError(e)) {
120
errorHandler.onUnexpectedExternalError(e);
121
}
122
return undefined;
123
}
124
125
export interface SerializedError {
126
readonly $isError: true;
127
readonly name: string;
128
readonly message: string;
129
readonly stack: string;
130
readonly noTelemetry: boolean;
131
readonly code?: string;
132
readonly cause?: SerializedError;
133
}
134
135
type ErrorWithCode = Error & {
136
code: string | undefined;
137
};
138
139
export function transformErrorForSerialization(error: Error): SerializedError;
140
export function transformErrorForSerialization(error: any): any;
141
export function transformErrorForSerialization(error: any): any {
142
if (error instanceof Error) {
143
const { name, message, cause } = error;
144
// eslint-disable-next-line local/code-no-any-casts
145
const stack: string = (<any>error).stacktrace || (<any>error).stack;
146
return {
147
$isError: true,
148
name,
149
message,
150
stack,
151
noTelemetry: ErrorNoTelemetry.isErrorNoTelemetry(error),
152
cause: cause ? transformErrorForSerialization(cause) : undefined,
153
code: (<ErrorWithCode>error).code
154
};
155
}
156
157
// return as is
158
return error;
159
}
160
161
export function transformErrorFromSerialization(data: SerializedError): Error {
162
let error: Error;
163
if (data.noTelemetry) {
164
error = new ErrorNoTelemetry();
165
} else {
166
error = new Error();
167
error.name = data.name;
168
}
169
error.message = data.message;
170
error.stack = data.stack;
171
if (data.code) {
172
(<ErrorWithCode>error).code = data.code;
173
}
174
if (data.cause) {
175
error.cause = transformErrorFromSerialization(data.cause);
176
}
177
return error;
178
}
179
180
// see https://github.com/v8/v8/wiki/Stack%20Trace%20API#basic-stack-traces
181
export interface V8CallSite {
182
getThis(): unknown;
183
getTypeName(): string | null;
184
getFunction(): Function | undefined;
185
getFunctionName(): string | null;
186
getMethodName(): string | null;
187
getFileName(): string | null;
188
getLineNumber(): number | null;
189
getColumnNumber(): number | null;
190
getEvalOrigin(): string | undefined;
191
isToplevel(): boolean;
192
isEval(): boolean;
193
isNative(): boolean;
194
isConstructor(): boolean;
195
toString(): string;
196
}
197
198
export const canceledName = 'Canceled';
199
200
/**
201
* Checks if the given error is a promise in canceled state
202
*/
203
export function isCancellationError(error: any): boolean {
204
if (error instanceof CancellationError) {
205
return true;
206
}
207
return error instanceof Error && error.name === canceledName && error.message === canceledName;
208
}
209
210
// !!!IMPORTANT!!!
211
// Do NOT change this class because it is also used as an API-type.
212
export class CancellationError extends Error {
213
constructor() {
214
super(canceledName);
215
this.name = this.message;
216
}
217
}
218
219
export class PendingMigrationError extends Error {
220
221
private static readonly _name = 'PendingMigrationError';
222
223
static is(error: unknown): error is PendingMigrationError {
224
return error instanceof PendingMigrationError || (error instanceof Error && error.name === PendingMigrationError._name);
225
}
226
227
constructor(message: string) {
228
super(message);
229
this.name = PendingMigrationError._name;
230
}
231
}
232
233
/**
234
* @deprecated use {@link CancellationError `new CancellationError()`} instead
235
*/
236
export function canceled(): Error {
237
const error = new Error(canceledName);
238
error.name = error.message;
239
return error;
240
}
241
242
export function illegalArgument(name?: string): Error {
243
if (name) {
244
return new Error(`Illegal argument: ${name}`);
245
} else {
246
return new Error('Illegal argument');
247
}
248
}
249
250
export function illegalState(name?: string): Error {
251
if (name) {
252
return new Error(`Illegal state: ${name}`);
253
} else {
254
return new Error('Illegal state');
255
}
256
}
257
258
export class ReadonlyError extends TypeError {
259
constructor(name?: string) {
260
super(name ? `${name} is read-only and cannot be changed` : 'Cannot change read-only property');
261
}
262
}
263
264
export function getErrorMessage(err: any): string {
265
if (!err) {
266
return 'Error';
267
}
268
269
if (err.message) {
270
return err.message;
271
}
272
273
if (err.stack) {
274
return err.stack.split('\n')[0];
275
}
276
277
return String(err);
278
}
279
280
export class NotImplementedError extends Error {
281
constructor(message?: string) {
282
super('NotImplemented');
283
if (message) {
284
this.message = message;
285
}
286
}
287
}
288
289
export class NotSupportedError extends Error {
290
constructor(message?: string) {
291
super('NotSupported');
292
if (message) {
293
this.message = message;
294
}
295
}
296
}
297
298
export class ExpectedError extends Error {
299
readonly isExpected = true;
300
}
301
302
/**
303
* Error that when thrown won't be logged in telemetry as an unhandled error.
304
*/
305
export class ErrorNoTelemetry extends Error {
306
override readonly name: string;
307
308
constructor(msg?: string) {
309
super(msg);
310
this.name = 'CodeExpectedError';
311
}
312
313
public static fromError(err: Error): ErrorNoTelemetry {
314
if (err instanceof ErrorNoTelemetry) {
315
return err;
316
}
317
318
const result = new ErrorNoTelemetry();
319
result.message = err.message;
320
result.stack = err.stack;
321
return result;
322
}
323
324
public static isErrorNoTelemetry(err: Error): err is ErrorNoTelemetry {
325
return err.name === 'CodeExpectedError';
326
}
327
}
328
329
/**
330
* This error indicates a bug.
331
* Do not throw this for invalid user input.
332
* Only catch this error to recover gracefully from bugs.
333
*/
334
export class BugIndicatingError extends Error {
335
constructor(message?: string) {
336
super(message || 'An unexpected bug occurred.');
337
Object.setPrototypeOf(this, BugIndicatingError.prototype);
338
339
// Because we know for sure only buggy code throws this,
340
// we definitely want to break here and fix the bug.
341
// debugger;
342
}
343
}
344
345