@taicode/common-base 1.7.3 → 1.7.5
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/output/error/error.d.ts +104 -67
- package/output/error/error.d.ts.map +1 -1
- package/output/error/error.js +85 -59
- package/output/error/error.test.d.ts +0 -17
- package/output/error/error.test.d.ts.map +1 -1
- package/output/error/error.test.js +172 -99
- package/output/error/index.d.ts +2 -1
- package/output/error/index.d.ts.map +1 -1
- package/output/error/index.js +1 -1
- package/output/flow-queue/flow-queue.d.ts +79 -11
- package/output/flow-queue/flow-queue.d.ts.map +1 -1
- package/output/flow-queue/flow-queue.js +115 -42
- package/output/flow-queue/flow-queue.test.js +182 -11
- package/output/logger/formatter.d.ts +0 -1
- package/output/logger/formatter.d.ts.map +1 -1
- package/output/logger/formatter.js +1 -17
- package/output/logger/formatter.test.d.ts +0 -24
- package/output/logger/formatter.test.d.ts.map +1 -1
- package/output/logger/formatter.test.js +11 -30
- package/output/logger/logger.test.d.ts +0 -19
- package/output/logger/logger.test.d.ts.map +1 -1
- package/output/logger/logger.test.js +6 -16
- package/package.json +3 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { UserError, SystemError
|
|
2
|
+
import { UserError, SystemError } from './error';
|
|
3
3
|
describe('UserError', () => {
|
|
4
4
|
describe('constructor', () => {
|
|
5
5
|
it('应该正确创建UserError实例', () => {
|
|
6
6
|
const type = 'VALIDATION_ERROR';
|
|
7
7
|
const message = '输入验证失败';
|
|
8
|
-
const error = new UserError(type, message);
|
|
8
|
+
const error = new UserError(type, undefined, message);
|
|
9
9
|
expect(error).toBeInstanceOf(Error);
|
|
10
10
|
expect(error).toBeInstanceOf(UserError);
|
|
11
11
|
expect(error.name).toBe('UserError');
|
|
@@ -32,7 +32,7 @@ describe('UserError', () => {
|
|
|
32
32
|
});
|
|
33
33
|
it('应该在提供空字符串message时保持空字符串', () => {
|
|
34
34
|
const type = 'VALIDATION_ERROR';
|
|
35
|
-
const error = new UserError(type, '');
|
|
35
|
+
const error = new UserError(type, {}, '');
|
|
36
36
|
expect(error).toBeInstanceOf(Error);
|
|
37
37
|
expect(error).toBeInstanceOf(UserError);
|
|
38
38
|
expect(error.name).toBe('UserError');
|
|
@@ -43,34 +43,32 @@ describe('UserError', () => {
|
|
|
43
43
|
const type = 'VALIDATION_ERROR';
|
|
44
44
|
const message = '输入验证失败';
|
|
45
45
|
const cause = new Error('原始错误');
|
|
46
|
-
const error = new UserError(type,
|
|
46
|
+
const error = new UserError(type, { cause }, message);
|
|
47
47
|
expect(error.cause).toBe(cause);
|
|
48
48
|
});
|
|
49
49
|
it('应该支持ErrorOptions参数且message为可选', () => {
|
|
50
50
|
const type = 'VALIDATION_ERROR';
|
|
51
51
|
const cause = new Error('原始错误');
|
|
52
|
-
const error = new UserError(type,
|
|
52
|
+
const error = new UserError(type, { cause });
|
|
53
53
|
expect(error.cause).toBe(cause);
|
|
54
54
|
expect(error.message).toBe('');
|
|
55
55
|
});
|
|
56
56
|
it('应该正确设置错误堆栈信息', () => {
|
|
57
|
-
const error = new UserError('TEST_ERROR', '测试错误');
|
|
57
|
+
const error = new UserError('TEST_ERROR', undefined, '测试错误');
|
|
58
58
|
expect(error.stack).toBeDefined();
|
|
59
59
|
expect(error.stack).toContain('UserError');
|
|
60
60
|
});
|
|
61
61
|
});
|
|
62
62
|
describe('is', () => {
|
|
63
63
|
it('应该正确识别UserError实例', () => {
|
|
64
|
-
const error = new UserError('TEST_ERROR', '测试错误');
|
|
64
|
+
const error = new UserError('TEST_ERROR', undefined, '测试错误');
|
|
65
65
|
expect(UserError.is(error)).toBe(true);
|
|
66
66
|
});
|
|
67
67
|
it('应该正确识别非UserError实例', () => {
|
|
68
68
|
const regularError = new Error('普通错误');
|
|
69
|
-
const systemError = new SystemError('SYSTEM_ERROR', '系统错误');
|
|
70
|
-
const unknownError = new UnknownError('未知错误');
|
|
69
|
+
const systemError = new SystemError('SYSTEM_ERROR', undefined, '系统错误');
|
|
71
70
|
expect(UserError.is(regularError)).toBe(false);
|
|
72
71
|
expect(UserError.is(systemError)).toBe(false);
|
|
73
|
-
expect(UserError.is(unknownError)).toBe(false);
|
|
74
72
|
expect(UserError.is(null)).toBe(false);
|
|
75
73
|
expect(UserError.is(undefined)).toBe(false);
|
|
76
74
|
expect(UserError.is('字符串')).toBe(false);
|
|
@@ -78,7 +76,7 @@ describe('UserError', () => {
|
|
|
78
76
|
expect(UserError.is({})).toBe(false);
|
|
79
77
|
});
|
|
80
78
|
it('应该支持类型守卫功能', () => {
|
|
81
|
-
const error = new UserError('TEST_ERROR', '测试错误');
|
|
79
|
+
const error = new UserError('TEST_ERROR', undefined, '测试错误');
|
|
82
80
|
if (UserError.is(error)) {
|
|
83
81
|
// 在类型守卫内部,error的类型应该被正确推断
|
|
84
82
|
expect(error.type).toBe('TEST_ERROR');
|
|
@@ -89,13 +87,13 @@ describe('UserError', () => {
|
|
|
89
87
|
});
|
|
90
88
|
describe('继承行为', () => {
|
|
91
89
|
it('应该正确继承Error的所有属性和方法', () => {
|
|
92
|
-
const error = new UserError('TEST_ERROR', '测试错误');
|
|
90
|
+
const error = new UserError('TEST_ERROR', undefined, '测试错误');
|
|
93
91
|
expect(error.toString()).toContain('测试错误');
|
|
94
92
|
expect(error.toString()).toContain('UserError');
|
|
95
93
|
expect(error instanceof Error).toBe(true);
|
|
96
94
|
});
|
|
97
95
|
it('应该支持Error的标准用法', () => {
|
|
98
|
-
const error = new UserError('TEST_ERROR', '测试错误');
|
|
96
|
+
const error = new UserError('TEST_ERROR', undefined, '测试错误');
|
|
99
97
|
try {
|
|
100
98
|
throw error;
|
|
101
99
|
}
|
|
@@ -111,7 +109,7 @@ describe('SystemError', () => {
|
|
|
111
109
|
it('应该正确创建SystemError实例', () => {
|
|
112
110
|
const type = 'DATABASE_ERROR';
|
|
113
111
|
const message = '数据库连接失败';
|
|
114
|
-
const error = new SystemError(type, message);
|
|
112
|
+
const error = new SystemError(type, undefined, message);
|
|
115
113
|
expect(error).toBeInstanceOf(Error);
|
|
116
114
|
expect(error).toBeInstanceOf(SystemError);
|
|
117
115
|
expect(error.name).toBe('SystemError');
|
|
@@ -138,7 +136,7 @@ describe('SystemError', () => {
|
|
|
138
136
|
});
|
|
139
137
|
it('应该在提供空字符串message时保持空字符串', () => {
|
|
140
138
|
const type = 'DATABASE_ERROR';
|
|
141
|
-
const error = new SystemError(type, '');
|
|
139
|
+
const error = new SystemError(type, {}, '');
|
|
142
140
|
expect(error).toBeInstanceOf(Error);
|
|
143
141
|
expect(error).toBeInstanceOf(SystemError);
|
|
144
142
|
expect(error.name).toBe('SystemError');
|
|
@@ -149,34 +147,32 @@ describe('SystemError', () => {
|
|
|
149
147
|
const type = 'NETWORK_ERROR';
|
|
150
148
|
const message = '网络请求失败';
|
|
151
149
|
const cause = new Error('连接超时');
|
|
152
|
-
const error = new SystemError(type,
|
|
150
|
+
const error = new SystemError(type, { cause }, message);
|
|
153
151
|
expect(error.cause).toBe(cause);
|
|
154
152
|
});
|
|
155
153
|
it('应该支持ErrorOptions参数且message为可选', () => {
|
|
156
154
|
const type = 'NETWORK_ERROR';
|
|
157
155
|
const cause = new Error('连接超时');
|
|
158
|
-
const error = new SystemError(type,
|
|
156
|
+
const error = new SystemError(type, { cause });
|
|
159
157
|
expect(error.cause).toBe(cause);
|
|
160
158
|
expect(error.message).toBe('');
|
|
161
159
|
});
|
|
162
160
|
it('应该正确设置错误堆栈信息', () => {
|
|
163
|
-
const error = new SystemError('FILE_ERROR', '文件读取失败');
|
|
161
|
+
const error = new SystemError('FILE_ERROR', undefined, '文件读取失败');
|
|
164
162
|
expect(error.stack).toBeDefined();
|
|
165
163
|
expect(error.stack).toContain('SystemError');
|
|
166
164
|
});
|
|
167
165
|
});
|
|
168
166
|
describe('is', () => {
|
|
169
167
|
it('应该正确识别SystemError实例', () => {
|
|
170
|
-
const error = new SystemError('TEST_ERROR', '测试错误');
|
|
168
|
+
const error = new SystemError('TEST_ERROR', undefined, '测试错误');
|
|
171
169
|
expect(SystemError.is(error)).toBe(true);
|
|
172
170
|
});
|
|
173
171
|
it('应该正确识别非SystemError实例', () => {
|
|
174
172
|
const regularError = new Error('普通错误');
|
|
175
|
-
const userError = new UserError('USER_ERROR', '用户错误');
|
|
176
|
-
const unknownError = new UnknownError('未知错误');
|
|
173
|
+
const userError = new UserError('USER_ERROR', undefined, '用户错误');
|
|
177
174
|
expect(SystemError.is(regularError)).toBe(false);
|
|
178
175
|
expect(SystemError.is(userError)).toBe(false);
|
|
179
|
-
expect(SystemError.is(unknownError)).toBe(false);
|
|
180
176
|
expect(SystemError.is(null)).toBe(false);
|
|
181
177
|
expect(SystemError.is(undefined)).toBe(false);
|
|
182
178
|
expect(SystemError.is('字符串')).toBe(false);
|
|
@@ -184,7 +180,7 @@ describe('SystemError', () => {
|
|
|
184
180
|
expect(SystemError.is({})).toBe(false);
|
|
185
181
|
});
|
|
186
182
|
it('应该支持类型守卫功能', () => {
|
|
187
|
-
const error = new SystemError('DATABASE_ERROR', '数据库错误');
|
|
183
|
+
const error = new SystemError('DATABASE_ERROR', undefined, '数据库错误');
|
|
188
184
|
if (SystemError.is(error)) {
|
|
189
185
|
// 在类型守卫内部,error的类型应该被正确推断
|
|
190
186
|
expect(error.type).toBe('DATABASE_ERROR');
|
|
@@ -195,13 +191,13 @@ describe('SystemError', () => {
|
|
|
195
191
|
});
|
|
196
192
|
describe('继承行为', () => {
|
|
197
193
|
it('应该正确继承Error的所有属性和方法', () => {
|
|
198
|
-
const error = new SystemError('TEST_ERROR', '测试错误');
|
|
194
|
+
const error = new SystemError('TEST_ERROR', undefined, '测试错误');
|
|
199
195
|
expect(error.toString()).toContain('测试错误');
|
|
200
196
|
expect(error.toString()).toContain('SystemError');
|
|
201
197
|
expect(error instanceof Error).toBe(true);
|
|
202
198
|
});
|
|
203
199
|
it('应该支持Error的标准用法', () => {
|
|
204
|
-
const error = new SystemError('TEST_ERROR', '测试错误');
|
|
200
|
+
const error = new SystemError('TEST_ERROR', undefined, '测试错误');
|
|
205
201
|
try {
|
|
206
202
|
throw error;
|
|
207
203
|
}
|
|
@@ -212,99 +208,176 @@ describe('SystemError', () => {
|
|
|
212
208
|
});
|
|
213
209
|
});
|
|
214
210
|
});
|
|
215
|
-
describe('UnknownError', () => {
|
|
216
|
-
describe('constructor', () => {
|
|
217
|
-
it('应该正确创建UnknownError实例', () => {
|
|
218
|
-
const message = '发生了未知错误';
|
|
219
|
-
const error = new UnknownError(message);
|
|
220
|
-
expect(error).toBeInstanceOf(Error);
|
|
221
|
-
expect(error).toBeInstanceOf(UnknownError);
|
|
222
|
-
expect(error.name).toBe('UnknownError');
|
|
223
|
-
expect(error.message).toBe(message);
|
|
224
|
-
});
|
|
225
|
-
it('应该支持ErrorOptions参数', () => {
|
|
226
|
-
const message = '未知错误';
|
|
227
|
-
const cause = new Error('原始未知错误');
|
|
228
|
-
const error = new UnknownError(message, { cause });
|
|
229
|
-
expect(error.cause).toBe(cause);
|
|
230
|
-
});
|
|
231
|
-
it('应该正确设置错误堆栈信息', () => {
|
|
232
|
-
const error = new UnknownError('测试未知错误');
|
|
233
|
-
expect(error.stack).toBeDefined();
|
|
234
|
-
expect(error.stack).toContain('UnknownError');
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
describe('is', () => {
|
|
238
|
-
it('应该正确识别UnknownError实例', () => {
|
|
239
|
-
const error = new UnknownError('测试错误');
|
|
240
|
-
expect(UnknownError.is(error)).toBe(true);
|
|
241
|
-
});
|
|
242
|
-
it('应该正确识别非UnknownError实例', () => {
|
|
243
|
-
const regularError = new Error('普通错误');
|
|
244
|
-
const userError = new UserError('USER_ERROR', '用户错误');
|
|
245
|
-
const systemError = new SystemError('SYSTEM_ERROR', '系统错误');
|
|
246
|
-
expect(UnknownError.is(regularError)).toBe(false);
|
|
247
|
-
expect(UnknownError.is(userError)).toBe(false);
|
|
248
|
-
expect(UnknownError.is(systemError)).toBe(false);
|
|
249
|
-
expect(UnknownError.is(null)).toBe(false);
|
|
250
|
-
expect(UnknownError.is(undefined)).toBe(false);
|
|
251
|
-
expect(UnknownError.is('字符串')).toBe(false);
|
|
252
|
-
expect(UnknownError.is(123)).toBe(false);
|
|
253
|
-
expect(UnknownError.is({})).toBe(false);
|
|
254
|
-
});
|
|
255
|
-
});
|
|
256
|
-
describe('继承行为', () => {
|
|
257
|
-
it('应该正确继承Error的所有属性和方法', () => {
|
|
258
|
-
const error = new UnknownError('测试错误');
|
|
259
|
-
expect(error.toString()).toContain('测试错误');
|
|
260
|
-
expect(error instanceof Error).toBe(true);
|
|
261
|
-
});
|
|
262
|
-
it('应该支持Error的标准用法', () => {
|
|
263
|
-
const error = new UnknownError('测试错误');
|
|
264
|
-
try {
|
|
265
|
-
throw error;
|
|
266
|
-
}
|
|
267
|
-
catch (caught) {
|
|
268
|
-
expect(caught).toBe(error);
|
|
269
|
-
expect(caught).toBeInstanceOf(UnknownError);
|
|
270
|
-
}
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
211
|
describe('错误类型区分', () => {
|
|
275
|
-
it('
|
|
276
|
-
const userError = new UserError('USER_ERROR', '用户错误');
|
|
277
|
-
const systemError = new SystemError('SYSTEM_ERROR', '系统错误');
|
|
278
|
-
const unknownError = new UnknownError('未知错误');
|
|
212
|
+
it('两种错误类型应该是不同的类', () => {
|
|
213
|
+
const userError = new UserError('USER_ERROR', undefined, '用户错误');
|
|
214
|
+
const systemError = new SystemError('SYSTEM_ERROR', undefined, '系统错误');
|
|
279
215
|
// 每种错误只能被自己的类型检查函数识别
|
|
280
216
|
expect(UserError.is(userError)).toBe(true);
|
|
281
217
|
expect(SystemError.is(userError)).toBe(false);
|
|
282
|
-
expect(UnknownError.is(userError)).toBe(false);
|
|
283
218
|
expect(UserError.is(systemError)).toBe(false);
|
|
284
219
|
expect(SystemError.is(systemError)).toBe(true);
|
|
285
|
-
expect(UnknownError.is(systemError)).toBe(false);
|
|
286
|
-
expect(UserError.is(unknownError)).toBe(false);
|
|
287
|
-
expect(SystemError.is(unknownError)).toBe(false);
|
|
288
|
-
expect(UnknownError.is(unknownError)).toBe(true);
|
|
289
220
|
});
|
|
290
221
|
it('所有错误类型都应该是Error的实例', () => {
|
|
291
|
-
const userError = new UserError('USER_ERROR', '用户错误');
|
|
292
|
-
const systemError = new SystemError('SYSTEM_ERROR', '系统错误');
|
|
293
|
-
const unknownError = new UnknownError('未知错误');
|
|
222
|
+
const userError = new UserError('USER_ERROR', undefined, '用户错误');
|
|
223
|
+
const systemError = new SystemError('SYSTEM_ERROR', undefined, '系统错误');
|
|
294
224
|
expect(userError instanceof Error).toBe(true);
|
|
295
225
|
expect(systemError instanceof Error).toBe(true);
|
|
296
|
-
expect(unknownError instanceof Error).toBe(true);
|
|
297
226
|
});
|
|
298
227
|
});
|
|
299
228
|
describe('泛型类型支持', () => {
|
|
300
229
|
it('UserError应该支持字符串字面量类型', () => {
|
|
301
|
-
const error = new UserError('REQUIRED_FIELD', '字段必填');
|
|
230
|
+
const error = new UserError('REQUIRED_FIELD', {}, '字段必填');
|
|
302
231
|
expect(error.type).toBe('REQUIRED_FIELD');
|
|
303
232
|
expect(UserError.is(error)).toBe(true);
|
|
304
233
|
});
|
|
305
234
|
it('SystemError应该支持字符串字面量类型', () => {
|
|
306
|
-
const error = new SystemError('DATABASE_ERROR', '数据库连接失败');
|
|
235
|
+
const error = new SystemError('DATABASE_ERROR', {}, '数据库连接失败');
|
|
307
236
|
expect(error.type).toBe('DATABASE_ERROR');
|
|
308
237
|
expect(SystemError.is(error)).toBe(true);
|
|
309
238
|
});
|
|
310
239
|
});
|
|
240
|
+
describe('define 工厂方法', () => {
|
|
241
|
+
describe('UserError.define', () => {
|
|
242
|
+
it('应该定义一个绑定了特定错误类型的 UserError 类', () => {
|
|
243
|
+
const MyUserError = UserError.define({
|
|
244
|
+
'validation-failed': {},
|
|
245
|
+
'permission-denied': {},
|
|
246
|
+
'not-found': {}
|
|
247
|
+
});
|
|
248
|
+
const error = new MyUserError('validation-failed', {
|
|
249
|
+
field: 'email',
|
|
250
|
+
value: 'invalid@'
|
|
251
|
+
}, '验证失败');
|
|
252
|
+
expect(error).toBeInstanceOf(Error);
|
|
253
|
+
expect(error.name).toBe('UserError');
|
|
254
|
+
expect(error.type).toBe('validation-failed');
|
|
255
|
+
expect(error.message).toBe('验证失败');
|
|
256
|
+
expect(error.context).toEqual({ field: 'email', value: 'invalid@' });
|
|
257
|
+
});
|
|
258
|
+
it('应该支持 is 类型守卫', () => {
|
|
259
|
+
const MyUserError = UserError.define({
|
|
260
|
+
'test-error': {}
|
|
261
|
+
});
|
|
262
|
+
const error = new MyUserError('test-error', { code: 123 }, '测试错误');
|
|
263
|
+
expect(MyUserError.is(error)).toBe(true);
|
|
264
|
+
expect(MyUserError.is(new Error('普通错误'))).toBe(false);
|
|
265
|
+
expect(MyUserError.is(null)).toBe(false);
|
|
266
|
+
});
|
|
267
|
+
it('应该支持多次调用 define 定义不同的错误类', () => {
|
|
268
|
+
const ValidationError = UserError.define({
|
|
269
|
+
'required': {},
|
|
270
|
+
'invalid': {}
|
|
271
|
+
});
|
|
272
|
+
const AuthError = UserError.define({
|
|
273
|
+
'unauthorized': {},
|
|
274
|
+
'forbidden': {}
|
|
275
|
+
});
|
|
276
|
+
const validationError = new ValidationError('required', { field: 'username' }, '必填字段');
|
|
277
|
+
const authError = new AuthError('unauthorized', { reason: 'token expired' }, '未授权');
|
|
278
|
+
expect(validationError.type).toBe('required');
|
|
279
|
+
expect(authError.type).toBe('unauthorized');
|
|
280
|
+
expect(ValidationError.is(validationError)).toBe(true);
|
|
281
|
+
expect(ValidationError.is(authError)).toBe(false); // 不同的类不会互相识别
|
|
282
|
+
expect(AuthError.is(authError)).toBe(true);
|
|
283
|
+
expect(AuthError.is(validationError)).toBe(false); // 不同的类不会互相识别
|
|
284
|
+
});
|
|
285
|
+
it('应该支持不传 context 参数', () => {
|
|
286
|
+
const MyUserError = UserError.define({
|
|
287
|
+
'simple-error': {}
|
|
288
|
+
});
|
|
289
|
+
const error = new MyUserError('simple-error', undefined, '简单错误');
|
|
290
|
+
expect(error.type).toBe('simple-error');
|
|
291
|
+
expect(error.message).toBe('简单错误');
|
|
292
|
+
expect(error.context).toBeUndefined();
|
|
293
|
+
});
|
|
294
|
+
it('应该支持不传 message 参数', () => {
|
|
295
|
+
const MyUserError = UserError.define({
|
|
296
|
+
'no-message': {}
|
|
297
|
+
});
|
|
298
|
+
const error = new MyUserError('no-message');
|
|
299
|
+
expect(error.type).toBe('no-message');
|
|
300
|
+
expect(error.message).toBe('');
|
|
301
|
+
});
|
|
302
|
+
it('应该暴露所有定义的错误类型', () => {
|
|
303
|
+
const MyUserError = UserError.define({
|
|
304
|
+
'validation-failed': {},
|
|
305
|
+
'permission-denied': {},
|
|
306
|
+
'not-found': {}
|
|
307
|
+
});
|
|
308
|
+
expect(MyUserError.types).toEqual(['validation-failed', 'permission-denied', 'not-found']);
|
|
309
|
+
expect(MyUserError.types).toHaveLength(3);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
describe('SystemError.define', () => {
|
|
313
|
+
it('应该定义一个绑定了特定错误类型的 SystemError 类', () => {
|
|
314
|
+
const MySystemError = SystemError.define({
|
|
315
|
+
'database-error': {},
|
|
316
|
+
'network-error': {},
|
|
317
|
+
'service-unavailable': {}
|
|
318
|
+
});
|
|
319
|
+
const error = new MySystemError('database-error', {
|
|
320
|
+
query: 'SELECT * FROM users',
|
|
321
|
+
table: 'users'
|
|
322
|
+
}, '数据库错误');
|
|
323
|
+
expect(error).toBeInstanceOf(Error);
|
|
324
|
+
expect(error.name).toBe('SystemError');
|
|
325
|
+
expect(error.type).toBe('database-error');
|
|
326
|
+
expect(error.message).toBe('数据库错误');
|
|
327
|
+
expect(error.context).toEqual({ query: 'SELECT * FROM users', table: 'users' });
|
|
328
|
+
});
|
|
329
|
+
it('应该支持 is 类型守卫', () => {
|
|
330
|
+
const MySystemError = SystemError.define({
|
|
331
|
+
'test-error': {}
|
|
332
|
+
});
|
|
333
|
+
const error = new MySystemError('test-error', { code: 500 }, '测试错误');
|
|
334
|
+
expect(MySystemError.is(error)).toBe(true);
|
|
335
|
+
expect(MySystemError.is(new Error('普通错误'))).toBe(false);
|
|
336
|
+
expect(MySystemError.is(null)).toBe(false);
|
|
337
|
+
});
|
|
338
|
+
it('应该支持多次调用 define 定义不同的错误类', () => {
|
|
339
|
+
const DatabaseError = SystemError.define({
|
|
340
|
+
'connection-failed': {},
|
|
341
|
+
'query-timeout': {}
|
|
342
|
+
});
|
|
343
|
+
const NetworkError = SystemError.define({
|
|
344
|
+
'request-failed': {},
|
|
345
|
+
'timeout': {}
|
|
346
|
+
});
|
|
347
|
+
const dbError = new DatabaseError('connection-failed', { host: 'localhost', port: 5432 }, '连接失败');
|
|
348
|
+
const netError = new NetworkError('request-failed', { url: '/api/data', method: 'GET' }, '请求失败');
|
|
349
|
+
expect(dbError.type).toBe('connection-failed');
|
|
350
|
+
expect(netError.type).toBe('request-failed');
|
|
351
|
+
expect(DatabaseError.is(dbError)).toBe(true);
|
|
352
|
+
expect(DatabaseError.is(netError)).toBe(false); // 不同的类不会互相识别
|
|
353
|
+
expect(NetworkError.is(netError)).toBe(true);
|
|
354
|
+
expect(NetworkError.is(dbError)).toBe(false); // 不同的类不会互相识别
|
|
355
|
+
});
|
|
356
|
+
it('应该支持不传 context 参数', () => {
|
|
357
|
+
const MySystemError = SystemError.define({
|
|
358
|
+
'simple-error': {}
|
|
359
|
+
});
|
|
360
|
+
const error = new MySystemError('simple-error', undefined, '简单错误');
|
|
361
|
+
expect(error.type).toBe('simple-error');
|
|
362
|
+
expect(error.message).toBe('简单错误');
|
|
363
|
+
expect(error.context).toBeUndefined();
|
|
364
|
+
});
|
|
365
|
+
it('应该支持不传 message 参数', () => {
|
|
366
|
+
const MySystemError = SystemError.define({
|
|
367
|
+
'no-message': {}
|
|
368
|
+
});
|
|
369
|
+
const error = new MySystemError('no-message');
|
|
370
|
+
expect(error.type).toBe('no-message');
|
|
371
|
+
expect(error.message).toBe('');
|
|
372
|
+
});
|
|
373
|
+
it('应该暴露所有定义的错误类型', () => {
|
|
374
|
+
const MySystemError = SystemError.define({
|
|
375
|
+
'database-error': {},
|
|
376
|
+
'network-error': {},
|
|
377
|
+
'service-unavailable': {}
|
|
378
|
+
});
|
|
379
|
+
expect(MySystemError.types).toEqual(['database-error', 'network-error', 'service-unavailable']);
|
|
380
|
+
expect(MySystemError.types).toHaveLength(3);
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
});
|
package/output/error/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export { UserError, SystemError
|
|
1
|
+
export { UserError, SystemError } from './error';
|
|
2
|
+
export type { ErrorContext } from './error';
|
|
2
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/error/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/error/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,WAAW,EACZ,MAAM,SAAS,CAAA;AAEhB,YAAY,EACV,YAAY,EACb,MAAM,SAAS,CAAA"}
|
package/output/error/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { UserError, SystemError
|
|
1
|
+
export { UserError, SystemError } from './error';
|
|
@@ -75,6 +75,8 @@
|
|
|
75
75
|
* - **流量控制**:可配置任务间延迟,避免资源竞争
|
|
76
76
|
* - **状态追踪**:清晰的成功/失败状态管理
|
|
77
77
|
* - **背压处理**:避免内存溢出的队列管理
|
|
78
|
+
* - **并发控制**:支持配置并发处理数量,默认为 1
|
|
79
|
+
* - **链式调用**:支持流畅的链式 API 调用
|
|
78
80
|
*/
|
|
79
81
|
type FlowQueueInput = {};
|
|
80
82
|
type FlowQueueOutput = {};
|
|
@@ -157,6 +159,7 @@ export type FlowQueueDelayConfig = {
|
|
|
157
159
|
export type FlowQueueOptions = {
|
|
158
160
|
retry?: FlowQueueRetryConfig;
|
|
159
161
|
delay?: FlowQueueDelayConfig;
|
|
162
|
+
concurrency?: number;
|
|
160
163
|
};
|
|
161
164
|
/**
|
|
162
165
|
* FlowQueue 流式队列处理器类
|
|
@@ -172,7 +175,8 @@ export type FlowQueueOptions = {
|
|
|
172
175
|
* const queue = new FlowQueue<InputType, OutputType>(
|
|
173
176
|
* {
|
|
174
177
|
* retry: { strategy: 'exponential', baseDelay: 1000, maxRetries: 3 },
|
|
175
|
-
* delay: { base: 100, jitter: true }
|
|
178
|
+
* delay: { base: 100, jitter: true },
|
|
179
|
+
* concurrency: 3 // 支持 3 个并发处理
|
|
176
180
|
* },
|
|
177
181
|
* async (input) => {
|
|
178
182
|
* // 处理逻辑
|
|
@@ -180,13 +184,25 @@ export type FlowQueueOptions = {
|
|
|
180
184
|
* }
|
|
181
185
|
* );
|
|
182
186
|
*
|
|
183
|
-
* //
|
|
187
|
+
* // 传统方式
|
|
184
188
|
* queue.input(data1, data2, data3);
|
|
185
189
|
* queue.onGenerate(result => console.log('处理完成:', result));
|
|
186
|
-
*
|
|
187
|
-
* // 等待所有处理完成
|
|
188
190
|
* queue.closeInput();
|
|
189
191
|
* await queue.awaitCompletion();
|
|
192
|
+
*
|
|
193
|
+
* // 链式调用方式
|
|
194
|
+
* await queue
|
|
195
|
+
* .input(data1, data2)
|
|
196
|
+
* .input(data3)
|
|
197
|
+
* .closeInput()
|
|
198
|
+
* .awaitCompletion();
|
|
199
|
+
*
|
|
200
|
+
* // 重置并重新开始
|
|
201
|
+
* await queue
|
|
202
|
+
* .reset()
|
|
203
|
+
* .input(newData1, newData2)
|
|
204
|
+
* .closeInput()
|
|
205
|
+
* .awaitCompletion();
|
|
190
206
|
* ```
|
|
191
207
|
*/
|
|
192
208
|
export declare class FlowQueue<I extends FlowQueueInput, O extends FlowQueueOutput> {
|
|
@@ -196,7 +212,7 @@ export declare class FlowQueue<I extends FlowQueueInput, O extends FlowQueueOutp
|
|
|
196
212
|
private processedInputs;
|
|
197
213
|
successOutputs: Map<I, O>;
|
|
198
214
|
erroredOutputs: Map<I, unknown>;
|
|
199
|
-
private
|
|
215
|
+
private processingCount;
|
|
200
216
|
private retryCount;
|
|
201
217
|
private onGenerates;
|
|
202
218
|
private isInputClosed;
|
|
@@ -212,14 +228,16 @@ export declare class FlowQueue<I extends FlowQueueInput, O extends FlowQueueOutp
|
|
|
212
228
|
* - 可以在处理过程中通过 this.input() 动态添加新任务
|
|
213
229
|
* - 支持异步处理,避免阻塞主线程
|
|
214
230
|
* - 失败时会根据重试策略自动重试
|
|
231
|
+
* - 支持并发处理,默认并发数为 1
|
|
215
232
|
*
|
|
216
233
|
* @example
|
|
217
234
|
* ```typescript
|
|
218
|
-
* //
|
|
235
|
+
* // 处理嵌套文件结构的示例(单线程)
|
|
219
236
|
* const fileQueue = new FlowQueue<FileNode, ProcessedFile>(
|
|
220
237
|
* {
|
|
221
238
|
* retry: { strategy: 'exponential', baseDelay: 1000, maxRetries: 3 },
|
|
222
|
-
* delay: { base: 100, jitter: true }
|
|
239
|
+
* delay: { base: 100, jitter: true },
|
|
240
|
+
* concurrency: 1 // 默认值,可省略
|
|
223
241
|
* },
|
|
224
242
|
* async (node) => {
|
|
225
243
|
* try {
|
|
@@ -236,6 +254,17 @@ export declare class FlowQueue<I extends FlowQueueInput, O extends FlowQueueOutp
|
|
|
236
254
|
* }
|
|
237
255
|
* }
|
|
238
256
|
* );
|
|
257
|
+
*
|
|
258
|
+
* // 并发处理示例
|
|
259
|
+
* const concurrentQueue = new FlowQueue<Task, Result>(
|
|
260
|
+
* {
|
|
261
|
+
* concurrency: 5, // 同时处理 5 个任务
|
|
262
|
+
* retry: { strategy: 'exponential', baseDelay: 1000, maxRetries: 3 }
|
|
263
|
+
* },
|
|
264
|
+
* async (task) => {
|
|
265
|
+
* return await processTask(task);
|
|
266
|
+
* }
|
|
267
|
+
* );
|
|
239
268
|
* ```
|
|
240
269
|
*/
|
|
241
270
|
constructor(options: FlowQueueOptions, processor: FlowQueueProcessor<I, O>);
|
|
@@ -277,8 +306,10 @@ export declare class FlowQueue<I extends FlowQueueInput, O extends FlowQueueOutp
|
|
|
277
306
|
* - 在 processor 函数内部可以动态添加新的输入
|
|
278
307
|
* - 避免了深度递归调用栈
|
|
279
308
|
* - 支持批量添加多个输入
|
|
309
|
+
* - 支持链式调用
|
|
280
310
|
*
|
|
281
311
|
* @param inputs 要处理的输入数据
|
|
312
|
+
* @returns 返回 FlowQueue 实例以支持链式调用
|
|
282
313
|
*
|
|
283
314
|
* @example
|
|
284
315
|
* ```typescript
|
|
@@ -293,9 +324,15 @@ export declare class FlowQueue<I extends FlowQueueInput, O extends FlowQueueOutp
|
|
|
293
324
|
*
|
|
294
325
|
* return result;
|
|
295
326
|
* };
|
|
327
|
+
*
|
|
328
|
+
* // 链式调用示例
|
|
329
|
+
* queue
|
|
330
|
+
* .input(data1, data2)
|
|
331
|
+
* .input(data3)
|
|
332
|
+
* .closeInput();
|
|
296
333
|
* ```
|
|
297
334
|
*/
|
|
298
|
-
input(...inputs: I[]):
|
|
335
|
+
input(...inputs: I[]): FlowQueue<I, O>;
|
|
299
336
|
/**
|
|
300
337
|
* 注册输出监听器
|
|
301
338
|
*
|
|
@@ -331,9 +368,12 @@ export declare class FlowQueue<I extends FlowQueueInput, O extends FlowQueueOutp
|
|
|
331
368
|
* - 队列将不再接受新的输入
|
|
332
369
|
* - 当所有现有输入处理完成后,队列将进入完成状态
|
|
333
370
|
* - 可以通过 awaitCompletion() 等待所有处理完成
|
|
371
|
+
* - 支持链式调用
|
|
334
372
|
*
|
|
335
373
|
* 在深度循环解耦场景中,这是控制处理边界的重要方法。
|
|
336
374
|
*
|
|
375
|
+
* @returns 返回 FlowQueue 实例以支持链式调用
|
|
376
|
+
*
|
|
337
377
|
* @example
|
|
338
378
|
* ```typescript
|
|
339
379
|
* // 添加所有初始数据
|
|
@@ -345,9 +385,15 @@ export declare class FlowQueue<I extends FlowQueueInput, O extends FlowQueueOutp
|
|
|
345
385
|
* // 等待所有处理完成
|
|
346
386
|
* await queue.awaitCompletion();
|
|
347
387
|
* console.log('所有数据处理完成');
|
|
388
|
+
*
|
|
389
|
+
* // 链式调用示例
|
|
390
|
+
* await queue
|
|
391
|
+
* .input(data1, data2)
|
|
392
|
+
* .closeInput()
|
|
393
|
+
* .awaitCompletion();
|
|
348
394
|
* ```
|
|
349
395
|
*/
|
|
350
|
-
closeInput():
|
|
396
|
+
closeInput(): FlowQueue<I, O>;
|
|
351
397
|
/**
|
|
352
398
|
* 返回一个 Promise,代表当前已经标记为输入关闭状态、所有输入都已经处理完毕
|
|
353
399
|
*
|
|
@@ -375,14 +421,36 @@ export declare class FlowQueue<I extends FlowQueueInput, O extends FlowQueueOutp
|
|
|
375
421
|
awaitCompletion(): Promise<void>;
|
|
376
422
|
/**
|
|
377
423
|
* 移除尚未处理的输入并调用 closeInput
|
|
424
|
+
*
|
|
425
|
+
* @returns 返回 FlowQueue 实例以支持链式调用
|
|
426
|
+
*
|
|
427
|
+
* @example
|
|
428
|
+
* ```typescript
|
|
429
|
+
* // 链式调用示例
|
|
430
|
+
* queue
|
|
431
|
+
* .input(data1, data2)
|
|
432
|
+
* .cancel()
|
|
433
|
+
* .reset();
|
|
434
|
+
* ```
|
|
378
435
|
*/
|
|
379
|
-
cancel():
|
|
436
|
+
cancel(): FlowQueue<I, O>;
|
|
380
437
|
/**
|
|
381
438
|
* 重置 FlowQueue 到初始状态
|
|
382
439
|
* 清空所有数据,包括待处理、已处理、输出、重试计数等
|
|
383
440
|
* 重置后可以重新开始处理
|
|
441
|
+
*
|
|
442
|
+
* @returns 返回 FlowQueue 实例以支持链式调用
|
|
443
|
+
*
|
|
444
|
+
* @example
|
|
445
|
+
* ```typescript
|
|
446
|
+
* // 链式调用示例
|
|
447
|
+
* queue
|
|
448
|
+
* .reset()
|
|
449
|
+
* .input(newData1, newData2)
|
|
450
|
+
* .closeInput();
|
|
451
|
+
* ```
|
|
384
452
|
*/
|
|
385
|
-
reset():
|
|
453
|
+
reset(): FlowQueue<I, O>;
|
|
386
454
|
/**
|
|
387
455
|
* 重试所有失败的输入
|
|
388
456
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-queue.d.ts","sourceRoot":"","sources":["../../source/flow-queue/flow-queue.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"flow-queue.d.ts","sourceRoot":"","sources":["../../source/flow-queue/flow-queue.ts"],"names":[],"mappings":"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"}
|