-
-
Notifications
You must be signed in to change notification settings - Fork 185
Expand file tree
/
Copy pathError.ts
More file actions
86 lines (76 loc) · 2.69 KB
/
Error.ts
File metadata and controls
86 lines (76 loc) · 2.69 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
interface ErrorType {
name: string;
new (...args: any[]): Error;
}
function getErrorStack(constructor: () => any): string | undefined {
// If debug module is not available in this environment, don't bother trying to get stack trace
if (debug === undefined) return undefined;
let level = 1;
while (true) {
const info = debug.getinfo(level, "f");
level += 1;
if (!info) {
// constructor is not in call stack
level = 1;
break;
} else if (info.func === constructor) {
break;
}
}
if (_VERSION.includes("Lua 5.0")) {
return debug.traceback(`[Level ${level}]`);
} else {
// @ts-ignore Fails when compiled with Lua 5.0 types
return debug.traceback(undefined, level);
}
}
function wrapErrorToString<T extends Error>(getDescription: (this: T) => string): (this: T) => string {
return function (this: Error): string {
const description = getDescription.call(this as T);
const caller = debug.getinfo(3, "f");
// @ts-ignore Fails when compiled with Lua 5.0 types
const isClassicLua = _VERSION.includes("Lua 5.0") || _VERSION === "Lua 5.1";
if (isClassicLua || (caller && caller.func !== error)) {
return description;
} else {
return `${description}\n${this.stack}`;
}
};
}
function initErrorClass(Type: ErrorType, name: string): any {
Type.name = name;
return setmetatable(Type, {
__call: (_self: any, message: string) => new Type(message),
});
}
export const Error: ErrorConstructor = initErrorClass(
class implements Error {
public name = "Error";
public stack?: string;
constructor(public message = "") {
this.stack = getErrorStack((this.constructor as any).new);
const metatable = getmetatable(this);
if (metatable && !metatable.__errorToStringPatched) {
metatable.__errorToStringPatched = true;
metatable.__tostring = wrapErrorToString(metatable.__tostring);
}
}
public toString(): string {
return this.message !== "" ? `${this.name}: ${this.message}` : this.name;
}
},
"Error"
);
function createErrorClass(name: string) {
return initErrorClass(
class extends Error {
public name = name;
},
name
);
}
export const RangeError = createErrorClass("RangeError");
export const ReferenceError = createErrorClass("ReferenceError");
export const SyntaxError = createErrorClass("SyntaxError");
export const TypeError = createErrorClass("TypeError");
export const URIError = createErrorClass("URIError");