id-scanner-lib 1.3.3 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +324 -410
- package/dist/id-scanner-lib.esm.js +4826 -0
- package/dist/id-scanner-lib.esm.js.map +1 -0
- package/dist/id-scanner-lib.js +4858 -0
- package/dist/id-scanner-lib.js.map +1 -0
- package/dist/types/browser-image-compression.d.ts +19 -0
- package/dist/types/tesseract.d.ts +280 -0
- package/package.json +89 -78
- package/src/core/base-module.ts +78 -0
- package/src/core/camera-manager.ts +813 -0
- package/src/core/config.ts +305 -0
- package/src/core/errors.ts +174 -0
- package/src/core/event-emitter.test.ts +42 -0
- package/src/core/event-emitter.ts +110 -0
- package/src/core/loading-state.test.ts +67 -0
- package/src/core/loading-state.ts +156 -0
- package/src/core/logger.test.ts +49 -0
- package/src/core/logger.ts +549 -0
- package/src/core/module-manager.ts +163 -0
- package/src/core/plugin-manager.ts +429 -0
- package/src/core/resource-manager.ts +762 -0
- package/src/core/result.ts +163 -0
- package/src/core/scanner-factory.ts +236 -0
- package/src/index.ts +117 -939
- package/src/interfaces/external-types.ts +200 -0
- package/src/interfaces/face-detection.ts +309 -0
- package/src/interfaces/scanner-module.ts +384 -0
- package/src/modules/face/face-detector.ts +988 -0
- package/src/modules/face/index.ts +208 -0
- package/src/modules/face/liveness-detector.ts +908 -0
- package/src/modules/face/types.ts +133 -0
- package/src/{id-recognition → modules/id-card}/anti-fake-detector.ts +274 -240
- package/src/modules/id-card/id-card-detector.ts +474 -0
- package/src/modules/id-card/index.ts +425 -0
- package/src/{id-recognition → modules/id-card}/ocr-processor.ts +149 -92
- package/src/modules/id-card/ocr-worker.ts +259 -0
- package/src/modules/id-card/types.ts +178 -0
- package/src/modules/qrcode/index.ts +175 -0
- package/src/modules/qrcode/qr-code-scanner.ts +231 -0
- package/src/modules/qrcode/types.ts +169 -0
- package/src/types/common.test.ts +99 -0
- package/src/types/common.ts +166 -0
- package/src/types/tesseract.d.ts +265 -22
- package/src/utils/camera.test.ts +30 -0
- package/src/utils/camera.ts +4 -1
- package/src/utils/error-handler.test.ts +137 -0
- package/src/utils/error-handler.ts +110 -0
- package/src/utils/image-processing.ts +68 -49
- package/src/utils/index.test.ts +186 -0
- package/src/utils/index.ts +429 -0
- package/src/utils/performance.ts +168 -131
- package/src/utils/resource-manager.ts +65 -146
- package/src/utils/retry.test.ts +142 -0
- package/src/utils/retry.ts +282 -0
- package/src/utils/types.ts +90 -2
- package/src/utils/utils.test.ts +171 -0
- package/src/utils/worker.ts +123 -84
- package/src/version.ts +11 -0
- package/tools/scaffold.js +543 -0
- package/dist/id-scanner-core.esm.js +0 -11349
- package/dist/id-scanner-core.js +0 -11361
- package/dist/id-scanner-core.min.js +0 -1
- package/dist/id-scanner-ocr.esm.js +0 -2319
- package/dist/id-scanner-ocr.js +0 -2328
- package/dist/id-scanner-ocr.min.js +0 -1
- package/dist/id-scanner-qr.esm.js +0 -1296
- package/dist/id-scanner-qr.js +0 -1305
- package/dist/id-scanner-qr.min.js +0 -1
- package/dist/id-scanner.js +0 -4561
- package/dist/id-scanner.min.js +0 -1
- package/src/core.ts +0 -138
- package/src/demo/demo.ts +0 -204
- package/src/id-recognition/data-extractor.ts +0 -262
- package/src/id-recognition/id-detector.ts +0 -510
- package/src/id-recognition/ocr-worker.ts +0 -156
- package/src/index-umd.ts +0 -477
- package/src/ocr-module.ts +0 -187
- package/src/qr-module.ts +0 -179
- package/src/scanner/barcode-scanner.ts +0 -251
- package/src/scanner/qr-scanner.ts +0 -167
package/src/types/tesseract.d.ts
CHANGED
|
@@ -2,36 +2,279 @@
|
|
|
2
2
|
* Type definitions for tesseract.js
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
declare module
|
|
5
|
+
declare module "tesseract.js" {
|
|
6
|
+
// Based on https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts
|
|
7
|
+
// and https://github.com/naptha/tesseract.js/blob/master/docs/api.md
|
|
8
|
+
|
|
9
|
+
export interface Point {
|
|
10
|
+
x: number
|
|
11
|
+
y: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface Bbox {
|
|
15
|
+
x0: number
|
|
16
|
+
y0: number
|
|
17
|
+
x1: number
|
|
18
|
+
y1: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface Baseline {
|
|
22
|
+
x0: number
|
|
23
|
+
y0: number
|
|
24
|
+
x1: number
|
|
25
|
+
y1: number
|
|
26
|
+
has_descenders: boolean
|
|
27
|
+
has_ascenders: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface Word {
|
|
31
|
+
symbols: Symbol[]
|
|
32
|
+
choices: Choice[]
|
|
33
|
+
text: string
|
|
34
|
+
confidence: number
|
|
35
|
+
baseline: Baseline
|
|
36
|
+
bbox: Bbox
|
|
37
|
+
is_numeric: boolean
|
|
38
|
+
in_dictionary: boolean
|
|
39
|
+
direction: string
|
|
40
|
+
language: string
|
|
41
|
+
is_from_dictionary: boolean
|
|
42
|
+
is_fuzzy: boolean
|
|
43
|
+
is_certain: boolean
|
|
44
|
+
is_bold: boolean
|
|
45
|
+
is_italic: boolean
|
|
46
|
+
is_underlined: boolean
|
|
47
|
+
is_monospace: boolean
|
|
48
|
+
is_serif: boolean
|
|
49
|
+
is_smallcaps: boolean
|
|
50
|
+
font_id: number
|
|
51
|
+
font_size: number
|
|
52
|
+
font_name: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface Symbol {
|
|
56
|
+
choices: Choice[]
|
|
57
|
+
image: null | HTMLImageElement // Or string if it's a path/URL
|
|
58
|
+
text: string
|
|
59
|
+
confidence: number
|
|
60
|
+
baseline: Baseline
|
|
61
|
+
bbox: Bbox
|
|
62
|
+
is_superscript: boolean
|
|
63
|
+
is_subscript: boolean
|
|
64
|
+
is_dropcap: boolean
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface Choice {
|
|
68
|
+
text: string
|
|
69
|
+
confidence: number
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface Line {
|
|
73
|
+
words: Word[]
|
|
74
|
+
text: string
|
|
75
|
+
confidence: number
|
|
76
|
+
baseline: Baseline
|
|
77
|
+
bbox: Bbox
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface Paragraph {
|
|
81
|
+
lines: Line[]
|
|
82
|
+
text: string
|
|
83
|
+
confidence: number
|
|
84
|
+
baseline: Baseline
|
|
85
|
+
bbox: Bbox
|
|
86
|
+
is_ltr: boolean
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface Block {
|
|
90
|
+
paragraphs: Paragraph[]
|
|
91
|
+
lines: Line[]
|
|
92
|
+
words: Word[]
|
|
93
|
+
text: string
|
|
94
|
+
confidence: number
|
|
95
|
+
baseline: Baseline
|
|
96
|
+
bbox: Bbox
|
|
97
|
+
blocktype: string
|
|
98
|
+
polygon: Point[]
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface Page {
|
|
102
|
+
blocks: Block[]
|
|
103
|
+
confidence: number
|
|
104
|
+
html: string // HTML representation of the page
|
|
105
|
+
jobId?: string
|
|
106
|
+
text: string
|
|
107
|
+
lines: Line[]
|
|
108
|
+
oem: string
|
|
109
|
+
operator: string
|
|
110
|
+
paragraphs: Paragraph[]
|
|
111
|
+
psm: string
|
|
112
|
+
symbols: Symbol[]
|
|
113
|
+
version: string
|
|
114
|
+
words: Word[]
|
|
115
|
+
hocr?: string // hOCR output
|
|
116
|
+
tsv?: string // TSV output
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface LoggerMessage {
|
|
120
|
+
jobId?: string
|
|
121
|
+
workerId?: string
|
|
122
|
+
status: string
|
|
123
|
+
progress: number
|
|
124
|
+
userfriendlyText?: string
|
|
125
|
+
}
|
|
126
|
+
|
|
6
127
|
export interface WorkerOptions {
|
|
7
|
-
langPath?: string
|
|
8
|
-
corePath?: string
|
|
9
|
-
workerPath?: string
|
|
10
|
-
logger?: (message:
|
|
11
|
-
errorHandler?: (error: Error) => void
|
|
128
|
+
langPath?: string
|
|
129
|
+
corePath?: string
|
|
130
|
+
workerPath?: string
|
|
131
|
+
logger?: (message: LoggerMessage) => void // More specific type for logger message <mcreference index="1" link="https://github.com/naptha/tesseract.js/blob/master/docs/api.md"></mcreference>
|
|
132
|
+
errorHandler?: (error: Error) => void
|
|
133
|
+
// Add other options based on documentation if needed
|
|
134
|
+
[key: string]: any // For other less common or dynamic options
|
|
12
135
|
}
|
|
13
136
|
|
|
14
137
|
export interface RecognizeResult {
|
|
138
|
+
data: Page // Use the detailed Page interface
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface DetectResult {
|
|
15
142
|
data: {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
143
|
+
tesseract_script_id: number | null
|
|
144
|
+
script: string | null
|
|
145
|
+
script_confidence: number | null
|
|
146
|
+
orientation_degrees: number | null
|
|
147
|
+
orientation_confidence: number | null
|
|
148
|
+
}
|
|
149
|
+
jobId?: string
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface ConfigResult {
|
|
153
|
+
data: null
|
|
154
|
+
jobId?: string
|
|
25
155
|
}
|
|
26
156
|
|
|
157
|
+
export type ImageLike =
|
|
158
|
+
| HTMLImageElement
|
|
159
|
+
| HTMLCanvasElement
|
|
160
|
+
| File
|
|
161
|
+
| string
|
|
162
|
+
| Buffer
|
|
163
|
+
| ImageData // Common image types
|
|
164
|
+
|
|
27
165
|
export interface Worker {
|
|
28
|
-
load(): Promise<
|
|
29
|
-
loadLanguage(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
166
|
+
load(jobId?: string): Promise<ConfigResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
|
|
167
|
+
loadLanguage(
|
|
168
|
+
langs?: string | string[],
|
|
169
|
+
jobId?: string
|
|
170
|
+
): Promise<ConfigResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
|
|
171
|
+
initialize(
|
|
172
|
+
langs?: string | string[],
|
|
173
|
+
oem?: OEM,
|
|
174
|
+
config?: string | Partial<InitOptions>,
|
|
175
|
+
jobId?: string
|
|
176
|
+
): Promise<ConfigResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
|
|
177
|
+
setParameters(
|
|
178
|
+
params: Partial<Parameters>,
|
|
179
|
+
jobId?: string
|
|
180
|
+
): Promise<ConfigResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
|
|
181
|
+
recognize(
|
|
182
|
+
image: ImageLike,
|
|
183
|
+
options?: Partial<RecognizeOptions>,
|
|
184
|
+
output?: Partial<OutputFormats>,
|
|
185
|
+
jobId?: string
|
|
186
|
+
): Promise<RecognizeResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
|
|
187
|
+
detect(
|
|
188
|
+
image: ImageLike,
|
|
189
|
+
options?: Partial<WorkerOptions>,
|
|
190
|
+
jobId?: string
|
|
191
|
+
): Promise<DetectResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
|
|
192
|
+
terminate(jobId?: string): Promise<ConfigResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
|
|
193
|
+
// Add other worker methods if present in the version you are targeting
|
|
194
|
+
// Example from docs for other methods like FS operations:
|
|
195
|
+
writeText?(
|
|
196
|
+
path: string,
|
|
197
|
+
text: string,
|
|
198
|
+
jobId?: string
|
|
199
|
+
): Promise<ConfigResult>
|
|
200
|
+
readText?(path: string, jobId?: string): Promise<ConfigResult>
|
|
201
|
+
removeFile?(path: string, jobId?: string): Promise<ConfigResult> // Assuming removeFile also returns ConfigResult or similar
|
|
202
|
+
FS?(method: string, args: any[], jobId?: string): Promise<any> // FS is more generic
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Based on Tesseract's OEM and PSM enums
|
|
206
|
+
export enum OEM {
|
|
207
|
+
TESSERACT_ONLY = 0,
|
|
208
|
+
LSTM_ONLY = 1,
|
|
209
|
+
TESSERACT_LSTM_COMBINED = 2,
|
|
210
|
+
DEFAULT = 3,
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export enum PSM {
|
|
214
|
+
OSD_ONLY = 0,
|
|
215
|
+
AUTO_OSD = 1,
|
|
216
|
+
AUTO_ONLY = 2,
|
|
217
|
+
AUTO = 3,
|
|
218
|
+
SINGLE_COLUMN = 4,
|
|
219
|
+
SINGLE_BLOCK_VERT_TEXT = 5,
|
|
220
|
+
SINGLE_BLOCK = 6,
|
|
221
|
+
SINGLE_LINE = 7,
|
|
222
|
+
SINGLE_WORD = 8,
|
|
223
|
+
CIRCLE_WORD = 9,
|
|
224
|
+
SINGLE_CHAR = 10,
|
|
225
|
+
SPARSE_TEXT = 11,
|
|
226
|
+
SPARSE_TEXT_OSD = 12,
|
|
227
|
+
RAW_LINE = 13,
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface Parameters {
|
|
231
|
+
tessedit_char_whitelist?: string
|
|
232
|
+
tessedit_pageseg_mode?: PSM
|
|
233
|
+
// Add other Tesseract parameters as needed
|
|
234
|
+
[key: string]: any // For flexibility with other parameters
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface RecognizeOptions {
|
|
238
|
+
rectangle?: Bbox // For recognizing a specific region
|
|
239
|
+
rectangles?: Bbox[] // For recognizing multiple regions
|
|
240
|
+
// Add other recognize specific options
|
|
241
|
+
[key: string]: any
|
|
34
242
|
}
|
|
35
243
|
|
|
36
|
-
export
|
|
244
|
+
export interface OutputFormats {
|
|
245
|
+
text?: boolean
|
|
246
|
+
blocks?: boolean
|
|
247
|
+
hocr?: boolean
|
|
248
|
+
tsv?: boolean
|
|
249
|
+
pdf?: boolean // If PDF output is supported
|
|
250
|
+
// Add other output formats
|
|
251
|
+
[key: string]: any
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export interface InitOptions {
|
|
255
|
+
load_system_dawg?: boolean
|
|
256
|
+
load_freq_dawg?: boolean
|
|
257
|
+
load_punc_dawg?: boolean
|
|
258
|
+
load_number_dawg?: boolean
|
|
259
|
+
load_unambig_dawg?: boolean
|
|
260
|
+
load_bigram_dawg?: boolean
|
|
261
|
+
load_fixed_length_dawgs?: boolean
|
|
262
|
+
// Add other init-only parameters
|
|
263
|
+
[key: string]: any
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export function createWorker(options?: Partial<WorkerOptions>): Worker // 修正返回类型为 Worker 而非 Promise<Worker>
|
|
267
|
+
export function setLogging(logging: boolean): void
|
|
268
|
+
export function recognize(
|
|
269
|
+
image: ImageLike,
|
|
270
|
+
langs?: string | string[],
|
|
271
|
+
options?: Partial<RecognizeOptions & WorkerOptions>
|
|
272
|
+
): Promise<RecognizeResult>
|
|
273
|
+
export function detect(
|
|
274
|
+
image: ImageLike,
|
|
275
|
+
options?: Partial<WorkerOptions>
|
|
276
|
+
): Promise<DetectResult>
|
|
277
|
+
|
|
278
|
+
// 正确导出 OEM 和 PSM 枚举
|
|
279
|
+
export { OEM, PSM }
|
|
37
280
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 摄像头工具测试
|
|
3
|
+
* @description 测试摄像头相关工具
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getMediaConstraints } from './index';
|
|
7
|
+
|
|
8
|
+
describe('Camera Utils', () => {
|
|
9
|
+
describe('getMediaConstraints', () => {
|
|
10
|
+
it('should return default constraints', () => {
|
|
11
|
+
const constraints = getMediaConstraints();
|
|
12
|
+
|
|
13
|
+
expect(constraints).toBeDefined();
|
|
14
|
+
expect(constraints.audio).toBe(false);
|
|
15
|
+
expect(constraints.video).toBeDefined();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should accept custom parameters', () => {
|
|
19
|
+
const constraints = getMediaConstraints(1920, 1080, 'user', 60);
|
|
20
|
+
|
|
21
|
+
expect(constraints.video).toBeDefined();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should handle partial parameters', () => {
|
|
25
|
+
const constraints = getMediaConstraints(640);
|
|
26
|
+
|
|
27
|
+
expect(constraints.video).toBeDefined();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
});
|
package/src/utils/camera.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* @module Camera
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { Logger } from '../core/logger';
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
10
|
* 相机配置选项接口
|
|
9
11
|
*
|
|
@@ -113,7 +115,8 @@ export class Camera {
|
|
|
113
115
|
});
|
|
114
116
|
}
|
|
115
117
|
} catch (error) {
|
|
116
|
-
|
|
118
|
+
const logger = Logger.getInstance();
|
|
119
|
+
logger.error('Camera', '无法访问摄像头', error instanceof Error ? error : undefined);
|
|
117
120
|
throw new Error('无法访问摄像头。请确保已授予摄像头访问权限,并且摄像头未被其他应用程序占用。');
|
|
118
121
|
}
|
|
119
122
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 错误处理工具测试
|
|
3
|
+
* @description 测试 ErrorHandler
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ErrorHandler, ErrorSeverity } from './error-handler';
|
|
7
|
+
|
|
8
|
+
describe('ErrorHandler', () => {
|
|
9
|
+
// Mock Logger
|
|
10
|
+
const mockLogger = {
|
|
11
|
+
debug: jest.fn(),
|
|
12
|
+
info: jest.fn(),
|
|
13
|
+
warn: jest.fn(),
|
|
14
|
+
error: jest.fn()
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
beforeAll(() => {
|
|
18
|
+
// Replace logger with mock
|
|
19
|
+
(ErrorHandler as any).logger = mockLogger;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
jest.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should handle error with ERROR severity', () => {
|
|
27
|
+
ErrorHandler.handle('TestModule', 'Test error', new Error('test error'));
|
|
28
|
+
|
|
29
|
+
expect(mockLogger.error).toHaveBeenCalledWith(
|
|
30
|
+
'TestModule',
|
|
31
|
+
'Test error',
|
|
32
|
+
expect.any(Error)
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should handle error with WARN severity', () => {
|
|
37
|
+
ErrorHandler.handle('TestModule', 'Warning message', null, ErrorSeverity.WARN);
|
|
38
|
+
|
|
39
|
+
expect(mockLogger.warn).toHaveBeenCalledWith(
|
|
40
|
+
'TestModule',
|
|
41
|
+
'Warning message',
|
|
42
|
+
undefined
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should handle error with INFO severity', () => {
|
|
47
|
+
ErrorHandler.handle('TestModule', 'Info message', null, ErrorSeverity.INFO);
|
|
48
|
+
|
|
49
|
+
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
50
|
+
'TestModule',
|
|
51
|
+
'Info message',
|
|
52
|
+
undefined
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should handle error with DEBUG severity', () => {
|
|
57
|
+
ErrorHandler.handle('TestModule', 'Debug message', null, ErrorSeverity.DEBUG);
|
|
58
|
+
|
|
59
|
+
expect(mockLogger.debug).toHaveBeenCalledWith(
|
|
60
|
+
'TestModule',
|
|
61
|
+
'Debug message',
|
|
62
|
+
undefined
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should convert string error to Error object', () => {
|
|
67
|
+
ErrorHandler.handle('TestModule', 'Test error', 'string error');
|
|
68
|
+
|
|
69
|
+
expect(mockLogger.error).toHaveBeenCalledWith(
|
|
70
|
+
'TestModule',
|
|
71
|
+
'Test error',
|
|
72
|
+
expect.any(Error)
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should convert unknown error to Error object', () => {
|
|
77
|
+
ErrorHandler.handle('TestModule', 'Test error', { code: 123 });
|
|
78
|
+
|
|
79
|
+
expect(mockLogger.error).toHaveBeenCalledWith(
|
|
80
|
+
'TestModule',
|
|
81
|
+
'Test error',
|
|
82
|
+
expect.any(Error)
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('asyncHandler', () => {
|
|
87
|
+
it('should create error handler function', () => {
|
|
88
|
+
const handler = ErrorHandler.asyncHandler('TestModule', 'Operation failed');
|
|
89
|
+
|
|
90
|
+
handler(new Error('test'));
|
|
91
|
+
|
|
92
|
+
expect(mockLogger.error).toHaveBeenCalledWith(
|
|
93
|
+
'TestModule',
|
|
94
|
+
'Operation failed',
|
|
95
|
+
expect.any(Error)
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('safeExecute', () => {
|
|
101
|
+
it('should return result on success', async () => {
|
|
102
|
+
const fn = async () => 'success';
|
|
103
|
+
const result = await ErrorHandler.safeExecute(fn, 'TestModule', 'fallback');
|
|
104
|
+
|
|
105
|
+
expect(result).toBe('success');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should return fallback on error', async () => {
|
|
109
|
+
const fn = async () => {
|
|
110
|
+
throw new Error('error');
|
|
111
|
+
};
|
|
112
|
+
const result = await ErrorHandler.safeExecute(fn, 'TestModule', 'fallback');
|
|
113
|
+
|
|
114
|
+
expect(result).toBe('fallback');
|
|
115
|
+
expect(mockLogger.error).toHaveBeenCalled();
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('safeExecuteSync', () => {
|
|
120
|
+
it('should return result on success', () => {
|
|
121
|
+
const fn = () => 'success';
|
|
122
|
+
const result = ErrorHandler.safeExecuteSync(fn, 'TestModule', 'fallback');
|
|
123
|
+
|
|
124
|
+
expect(result).toBe('success');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should return fallback on error', () => {
|
|
128
|
+
const fn = () => {
|
|
129
|
+
throw new Error('error');
|
|
130
|
+
};
|
|
131
|
+
const result = ErrorHandler.safeExecuteSync(fn, 'TestModule', 'fallback');
|
|
132
|
+
|
|
133
|
+
expect(result).toBe('fallback');
|
|
134
|
+
expect(mockLogger.error).toHaveBeenCalled();
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 统一错误处理工具
|
|
3
|
+
* @description 提供统一的错误处理和日志记录功能
|
|
4
|
+
* @module utils/error-handler
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Logger } from '../core/logger';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 错误严重级别
|
|
11
|
+
*/
|
|
12
|
+
export enum ErrorSeverity {
|
|
13
|
+
DEBUG = 'debug',
|
|
14
|
+
INFO = 'info',
|
|
15
|
+
WARN = 'warn',
|
|
16
|
+
ERROR = 'error'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 错误处理工具类
|
|
21
|
+
*/
|
|
22
|
+
export class ErrorHandler {
|
|
23
|
+
private static logger = Logger.getInstance();
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 处理错误并记录日志
|
|
27
|
+
* @param context 错误上下文(模块名)
|
|
28
|
+
* @param message 错误消息
|
|
29
|
+
* @param error 错误对象
|
|
30
|
+
* @param severity 错误级别
|
|
31
|
+
*/
|
|
32
|
+
static handle(
|
|
33
|
+
context: string,
|
|
34
|
+
message: string,
|
|
35
|
+
error?: unknown,
|
|
36
|
+
severity: ErrorSeverity = ErrorSeverity.ERROR
|
|
37
|
+
): void {
|
|
38
|
+
const errorObj = error instanceof Error ? error : error ? new Error(String(error)) : undefined;
|
|
39
|
+
|
|
40
|
+
switch (severity) {
|
|
41
|
+
case ErrorSeverity.DEBUG:
|
|
42
|
+
this.logger.debug(context, message, errorObj);
|
|
43
|
+
break;
|
|
44
|
+
case ErrorSeverity.INFO:
|
|
45
|
+
this.logger.info(context, message, errorObj);
|
|
46
|
+
break;
|
|
47
|
+
case ErrorSeverity.WARN:
|
|
48
|
+
this.logger.warn(context, message, errorObj);
|
|
49
|
+
break;
|
|
50
|
+
case ErrorSeverity.ERROR:
|
|
51
|
+
default:
|
|
52
|
+
this.logger.error(context, message, errorObj);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 处理异步错误
|
|
58
|
+
* @param context 错误上下文
|
|
59
|
+
* @param message 错误消息
|
|
60
|
+
* @returns 返回一个错误处理函数
|
|
61
|
+
*/
|
|
62
|
+
static asyncHandler(
|
|
63
|
+
context: string,
|
|
64
|
+
message: string
|
|
65
|
+
): (error: unknown) => void {
|
|
66
|
+
return (error: unknown) => {
|
|
67
|
+
this.handle(context, message, error);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 安全执行异步函数并处理错误
|
|
73
|
+
* @param fn 异步函数
|
|
74
|
+
* @param context 错误上下文
|
|
75
|
+
* @param fallbackValue 错误时的返回值
|
|
76
|
+
* @returns 函数结果或 fallbackValue
|
|
77
|
+
*/
|
|
78
|
+
static async safeExecute<T>(
|
|
79
|
+
fn: () => Promise<T>,
|
|
80
|
+
context: string,
|
|
81
|
+
fallbackValue: T
|
|
82
|
+
): Promise<T> {
|
|
83
|
+
try {
|
|
84
|
+
return await fn();
|
|
85
|
+
} catch (error) {
|
|
86
|
+
this.handle(context, 'Operation failed', error);
|
|
87
|
+
return fallbackValue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 安全执行函数并处理错误
|
|
93
|
+
* @param fn 函数
|
|
94
|
+
* @param context 错误上下文
|
|
95
|
+
* @param fallbackValue 错误时的返回值
|
|
96
|
+
* @returns 函数结果或 fallbackValue
|
|
97
|
+
*/
|
|
98
|
+
static safeExecuteSync<T>(
|
|
99
|
+
fn: () => T,
|
|
100
|
+
context: string,
|
|
101
|
+
fallbackValue: T
|
|
102
|
+
): T {
|
|
103
|
+
try {
|
|
104
|
+
return fn();
|
|
105
|
+
} catch (error) {
|
|
106
|
+
this.handle(context, 'Operation failed', error);
|
|
107
|
+
return fallbackValue;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|