-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherrors.ts
More file actions
114 lines (102 loc) · 2.75 KB
/
errors.ts
File metadata and controls
114 lines (102 loc) · 2.75 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
export enum ErrorCategory {
VALIDATION = "validation",
RUNTIME = "runtime",
NETWORK = "network",
SECURITY = "security",
FILESYSTEM = "filesystem",
TIMEOUT = "timeout",
PERMISSION = "permission",
UNKNOWN = "unknown",
}
export enum ErrorCode {
INVALID_INPUT = "INVALID_INPUT",
COMMAND_NOT_FOUND = "COMMAND_NOT_FOUND",
PERMISSION_DENIED = "PERMISSION_DENIED",
TIMEOUT_EXCEEDED = "TIMEOUT_EXCEEDED",
FILE_NOT_FOUND = "FILE_NOT_FOUND",
NETWORK_ERROR = "NETWORK_ERROR",
REGEX_ERROR = "REGEX_ERROR",
CONCURRENT_MODIFICATION = "CONCURRENT_MODIFICATION",
QUOTA_EXCEEDED = "QUOTA_EXCEEDED",
INTERNAL_ERROR = "INTERNAL_ERROR",
}
export interface TypedError extends Error {
category: ErrorCategory;
code: ErrorCode;
recoverable: boolean;
suggestions?: string[];
}
export function categorizeError(error: unknown): ErrorCategory {
if (error instanceof Error) {
const message = error.message.toLowerCase();
const name = error.name.toLowerCase();
if (
name.includes("validation") ||
message.includes("invalid") ||
message.includes("validation")
) {
return ErrorCategory.VALIDATION;
}
if (
name.includes("permission") ||
message.includes("permission denied") ||
message.includes("eacces")
) {
return ErrorCategory.PERMISSION;
}
if (
name.includes("timeout") ||
message.includes("timed out") ||
message.includes("etimedout")
) {
return ErrorCategory.TIMEOUT;
}
if (
name.includes("enoent") ||
message.includes("not found") ||
message.includes("file not found")
) {
return ErrorCategory.FILESYSTEM;
}
if (
name.includes("network") ||
message.includes("connection") ||
message.includes("econn")
) {
return ErrorCategory.NETWORK;
}
if (
name.includes("security") ||
message.includes("forbidden") ||
message.includes("access denied")
) {
return ErrorCategory.SECURITY;
}
}
return ErrorCategory.UNKNOWN;
}
export function createTypedError(
message: string,
category: ErrorCategory,
code: ErrorCode,
options?: {
recoverable?: boolean;
suggestions?: string[];
cause?: Error;
}
): TypedError {
const error = new Error(message) as TypedError;
error.category = category;
error.code = code;
error.recoverable = options?.recoverable ?? false;
error.suggestions = options?.suggestions;
error.cause = options?.cause;
return error;
}
export function isRecoverable(error: unknown): boolean {
if (error instanceof Error && "recoverable" in error) {
return (error as TypedError).recoverable;
}
const category = categorizeError(error);
return category === ErrorCategory.NETWORK || category === ErrorCategory.TIMEOUT;
}