@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.
@@ -75,6 +75,8 @@
75
75
  * - **流量控制**:可配置任务间延迟,避免资源竞争
76
76
  * - **状态追踪**:清晰的成功/失败状态管理
77
77
  * - **背压处理**:避免内存溢出的队列管理
78
+ * - **并发控制**:支持配置并发处理数量,默认为 1
79
+ * - **链式调用**:支持流畅的链式 API 调用
78
80
  */
79
81
  import { catchIt } from '../catch';
80
82
  function delay(arg0) {
@@ -94,7 +96,8 @@ function delay(arg0) {
94
96
  * const queue = new FlowQueue<InputType, OutputType>(
95
97
  * {
96
98
  * retry: { strategy: 'exponential', baseDelay: 1000, maxRetries: 3 },
97
- * delay: { base: 100, jitter: true }
99
+ * delay: { base: 100, jitter: true },
100
+ * concurrency: 3 // 支持 3 个并发处理
98
101
  * },
99
102
  * async (input) => {
100
103
  * // 处理逻辑
@@ -102,13 +105,25 @@ function delay(arg0) {
102
105
  * }
103
106
  * );
104
107
  *
105
- * // 添加输入并监听输出
108
+ * // 传统方式
106
109
  * queue.input(data1, data2, data3);
107
110
  * queue.onGenerate(result => console.log('处理完成:', result));
108
- *
109
- * // 等待所有处理完成
110
111
  * queue.closeInput();
111
112
  * await queue.awaitCompletion();
113
+ *
114
+ * // 链式调用方式
115
+ * await queue
116
+ * .input(data1, data2)
117
+ * .input(data3)
118
+ * .closeInput()
119
+ * .awaitCompletion();
120
+ *
121
+ * // 重置并重新开始
122
+ * await queue
123
+ * .reset()
124
+ * .input(newData1, newData2)
125
+ * .closeInput()
126
+ * .awaitCompletion();
112
127
  * ```
113
128
  */
114
129
  export class FlowQueue {
@@ -118,7 +133,7 @@ export class FlowQueue {
118
133
  processedInputs = []; // 已处理
119
134
  successOutputs = new Map();
120
135
  erroredOutputs = new Map();
121
- isProcessing = false; // 防止并发处理
136
+ processingCount = 0; // 当前正在处理的任务数量
122
137
  retryCount = new Map(); // 记录每个输入的重试次数
123
138
  onGenerates = new Map();
124
139
  isInputClosed = false; // 标记输入是否已关闭
@@ -134,14 +149,16 @@ export class FlowQueue {
134
149
  * - 可以在处理过程中通过 this.input() 动态添加新任务
135
150
  * - 支持异步处理,避免阻塞主线程
136
151
  * - 失败时会根据重试策略自动重试
152
+ * - 支持并发处理,默认并发数为 1
137
153
  *
138
154
  * @example
139
155
  * ```typescript
140
- * // 处理嵌套文件结构的示例
156
+ * // 处理嵌套文件结构的示例(单线程)
141
157
  * const fileQueue = new FlowQueue<FileNode, ProcessedFile>(
142
158
  * {
143
159
  * retry: { strategy: 'exponential', baseDelay: 1000, maxRetries: 3 },
144
- * delay: { base: 100, jitter: true }
160
+ * delay: { base: 100, jitter: true },
161
+ * concurrency: 1 // 默认值,可省略
145
162
  * },
146
163
  * async (node) => {
147
164
  * try {
@@ -158,6 +175,17 @@ export class FlowQueue {
158
175
  * }
159
176
  * }
160
177
  * );
178
+ *
179
+ * // 并发处理示例
180
+ * const concurrentQueue = new FlowQueue<Task, Result>(
181
+ * {
182
+ * concurrency: 5, // 同时处理 5 个任务
183
+ * retry: { strategy: 'exponential', baseDelay: 1000, maxRetries: 3 }
184
+ * },
185
+ * async (task) => {
186
+ * return await processTask(task);
187
+ * }
188
+ * );
161
189
  * ```
162
190
  */
163
191
  constructor(options, processor) {
@@ -172,6 +200,8 @@ export class FlowQueue {
172
200
  this.options.delay.base = this.options.delay.base ?? 0;
173
201
  this.options.delay.jitter = this.options.delay.jitter ?? false;
174
202
  this.options.delay.jitterRange = this.options.delay.jitterRange ?? 0.1;
203
+ // 设置并发配置默认值
204
+ this.options.concurrency = this.options.concurrency ?? 1;
175
205
  }
176
206
  /**
177
207
  * 计算重试延迟时间
@@ -242,7 +272,9 @@ export class FlowQueue {
242
272
  * 调度下一个处理任务
243
273
  */
244
274
  scheduleNextProcessing() {
245
- if (this.pendingInputs.length > 0) {
275
+ // 启动尽可能多的处理任务,直到达到并发限制
276
+ const tasksToStart = Math.min(this.pendingInputs.length, this.options.concurrency - this.processingCount);
277
+ for (let i = 0; i < tasksToStart; i++) {
246
278
  // 计算任务间延迟
247
279
  const taskDelay = this.calculateTaskDelay();
248
280
  if (taskDelay > 0) {
@@ -254,10 +286,8 @@ export class FlowQueue {
254
286
  setTimeout(() => this.processFlow(), 0);
255
287
  }
256
288
  }
257
- else {
258
- // 没有更多待处理的输入,检查是否已标记为完成
259
- this.checkAndTriggerCompletion();
260
- }
289
+ // 检查是否已标记为完成
290
+ this.checkAndTriggerCompletion();
261
291
  }
262
292
  /**
263
293
  * 延迟执行重试
@@ -265,12 +295,14 @@ export class FlowQueue {
265
295
  scheduleRetry(input, delayTime) {
266
296
  this.pendingInputs.unshift(input);
267
297
  if (delayTime <= 0) {
268
- // 立即重试
269
- setTimeout(() => this.processFlow(), 0);
298
+ // 立即重试,启动调度
299
+ this.scheduleNextProcessing();
270
300
  }
271
301
  else {
272
302
  // 延迟重试
273
- setTimeout(() => this.processFlow(), delayTime);
303
+ setTimeout(() => {
304
+ this.scheduleNextProcessing();
305
+ }, delayTime);
274
306
  }
275
307
  }
276
308
  /**
@@ -278,7 +310,7 @@ export class FlowQueue {
278
310
  */
279
311
  async checkAndTriggerCompletion() {
280
312
  await delay(0); // 确保在当前执行栈完成后再检查
281
- if (this.isInputClosed && this.pendingInputs.length === 0 && !this.isProcessing && this.completionResolve) {
313
+ if (this.isInputClosed && this.pendingInputs.length === 0 && this.processingCount === 0 && this.completionResolve) {
282
314
  this.completionResolve();
283
315
  this.completionResolve = null;
284
316
  }
@@ -290,19 +322,19 @@ export class FlowQueue {
290
322
  * 可以设置失败的重试次数,如果超过最大重试次数则不再重试
291
323
  */
292
324
  async processFlow() {
293
- // 如果正在处理或没有待处理的输入,直接返回
294
- if (this.isProcessing || this.pendingInputs.length === 0) {
295
- // 检查是否已标记为完成且没有待处理的输入
325
+ // 检查并发限制
326
+ if (this.processingCount >= this.options.concurrency) {
327
+ return;
328
+ }
329
+ // 取出第一个待处理的输入
330
+ const input = this.pendingInputs.shift();
331
+ if (!input) {
296
332
  this.checkAndTriggerCompletion();
297
333
  return;
298
334
  }
299
- this.isProcessing = true;
300
- const processResult = await catchIt(async () => {
301
- // 取出第一个待处理的输入
302
- const input = this.pendingInputs.shift();
303
- if (!input) {
304
- return;
305
- }
335
+ // 增加处理计数
336
+ this.processingCount++;
337
+ try {
306
338
  // 获取当前输入的重试次数
307
339
  const currentRetries = this.retryCount.get(input) || 0;
308
340
  // 使用 processor 处理输入
@@ -319,8 +351,6 @@ export class FlowQueue {
319
351
  this.erroredOutputs.set(input, result.error);
320
352
  this.processedInputs.push(input);
321
353
  this.retryCount.delete(input);
322
- // 处理完当前输入后,继续处理下一个(如果有的话)
323
- this.scheduleNextProcessing();
324
354
  }
325
355
  }
326
356
  else {
@@ -332,17 +362,17 @@ export class FlowQueue {
332
362
  this.erroredOutputs.delete(input);
333
363
  // 通知所有注册的回调
334
364
  await this.notifyOnGenerates(result.value);
335
- // 处理完当前输入后,继续处理下一个(如果有的话)
336
- this.scheduleNextProcessing();
337
365
  }
338
- });
339
- // 处理 processFlow 中的错误
340
- if (processResult.isError()) {
341
- console.error('Error in processFlow:', processResult.error);
342
366
  }
343
- // 确保在任何情况下都重置 isProcessing 状态
344
- this.isProcessing = false;
345
- this.checkAndTriggerCompletion();
367
+ catch (error) {
368
+ console.error('Error in processFlow:', error);
369
+ }
370
+ finally {
371
+ // 减少正在处理的任务计数
372
+ this.processingCount--;
373
+ // 处理完当前输入后,尝试启动更多处理任务
374
+ this.scheduleNextProcessing();
375
+ }
346
376
  }
347
377
  /**
348
378
  * 通知所有注册的回调函数
@@ -362,8 +392,10 @@ export class FlowQueue {
362
392
  * - 在 processor 函数内部可以动态添加新的输入
363
393
  * - 避免了深度递归调用栈
364
394
  * - 支持批量添加多个输入
395
+ * - 支持链式调用
365
396
  *
366
397
  * @param inputs 要处理的输入数据
398
+ * @returns 返回 FlowQueue 实例以支持链式调用
367
399
  *
368
400
  * @example
369
401
  * ```typescript
@@ -378,13 +410,20 @@ export class FlowQueue {
378
410
  *
379
411
  * return result;
380
412
  * };
413
+ *
414
+ * // 链式调用示例
415
+ * queue
416
+ * .input(data1, data2)
417
+ * .input(data3)
418
+ * .closeInput();
381
419
  * ```
382
420
  */
383
421
  input(...inputs) {
384
422
  if (this.isInputClosed)
385
- return;
423
+ return this;
386
424
  this.pendingInputs.push(...inputs);
387
425
  this.processFlow();
426
+ return this;
388
427
  }
389
428
  /**
390
429
  * 注册输出监听器
@@ -418,7 +457,7 @@ export class FlowQueue {
418
457
  * 只读标记,代表是否当前已经 closeInput 并且所有输入都已经处理完毕
419
458
  */
420
459
  get isCompleted() {
421
- return this.isInputClosed && this.pendingInputs.length === 0 && !this.isProcessing;
460
+ return this.isInputClosed && this.pendingInputs.length === 0 && this.processingCount === 0;
422
461
  }
423
462
  /**
424
463
  * 标记当前 FlowQueue 不会再有新的输入了
@@ -427,9 +466,12 @@ export class FlowQueue {
427
466
  * - 队列将不再接受新的输入
428
467
  * - 当所有现有输入处理完成后,队列将进入完成状态
429
468
  * - 可以通过 awaitCompletion() 等待所有处理完成
469
+ * - 支持链式调用
430
470
  *
431
471
  * 在深度循环解耦场景中,这是控制处理边界的重要方法。
432
472
  *
473
+ * @returns 返回 FlowQueue 实例以支持链式调用
474
+ *
433
475
  * @example
434
476
  * ```typescript
435
477
  * // 添加所有初始数据
@@ -441,12 +483,19 @@ export class FlowQueue {
441
483
  * // 等待所有处理完成
442
484
  * await queue.awaitCompletion();
443
485
  * console.log('所有数据处理完成');
486
+ *
487
+ * // 链式调用示例
488
+ * await queue
489
+ * .input(data1, data2)
490
+ * .closeInput()
491
+ * .awaitCompletion();
444
492
  * ```
445
493
  */
446
494
  closeInput() {
447
495
  this.isInputClosed = true;
448
496
  // 使用统一的完成检查方法
449
497
  this.checkAndTriggerCompletion();
498
+ return this;
450
499
  }
451
500
  /**
452
501
  * 返回一个 Promise,代表当前已经标记为输入关闭状态、所有输入都已经处理完毕
@@ -476,8 +525,8 @@ export class FlowQueue {
476
525
  if (this.completionPromise) {
477
526
  return this.completionPromise;
478
527
  }
479
- // 如果已经标记为输入关闭且没有待处理的输入,立即返回 resolved Promise
480
- if (this.isInputClosed && this.pendingInputs.length === 0 && !this.isProcessing) {
528
+ // 如果已经标记为输入关闭且没有待处理的输入和正在处理的任务,立即返回 resolved Promise
529
+ if (this.isInputClosed && this.pendingInputs.length === 0 && this.processingCount === 0) {
481
530
  console.log('所有输入已处理完毕');
482
531
  return Promise.resolve();
483
532
  }
@@ -492,6 +541,17 @@ export class FlowQueue {
492
541
  }
493
542
  /**
494
543
  * 移除尚未处理的输入并调用 closeInput
544
+ *
545
+ * @returns 返回 FlowQueue 实例以支持链式调用
546
+ *
547
+ * @example
548
+ * ```typescript
549
+ * // 链式调用示例
550
+ * queue
551
+ * .input(data1, data2)
552
+ * .cancel()
553
+ * .reset();
554
+ * ```
495
555
  */
496
556
  cancel() {
497
557
  // 清除所有待处理的输入
@@ -500,11 +560,23 @@ export class FlowQueue {
500
560
  this.retryCount.clear();
501
561
  // 标记输入已关闭
502
562
  this.closeInput();
563
+ return this;
503
564
  }
504
565
  /**
505
566
  * 重置 FlowQueue 到初始状态
506
567
  * 清空所有数据,包括待处理、已处理、输出、重试计数等
507
568
  * 重置后可以重新开始处理
569
+ *
570
+ * @returns 返回 FlowQueue 实例以支持链式调用
571
+ *
572
+ * @example
573
+ * ```typescript
574
+ * // 链式调用示例
575
+ * queue
576
+ * .reset()
577
+ * .input(newData1, newData2)
578
+ * .closeInput();
579
+ * ```
508
580
  */
509
581
  reset() {
510
582
  // 清空所有队列和状态
@@ -514,7 +586,7 @@ export class FlowQueue {
514
586
  this.pendingInputs.length = 0;
515
587
  this.processedInputs.length = 0;
516
588
  // 重置处理状态
517
- this.isProcessing = false;
589
+ this.processingCount = 0;
518
590
  this.isInputClosed = false;
519
591
  // 重置完成状态
520
592
  if (this.completionResolve) {
@@ -522,6 +594,7 @@ export class FlowQueue {
522
594
  this.completionResolve = null;
523
595
  }
524
596
  this.completionPromise = null;
597
+ return this;
525
598
  }
526
599
  /**
527
600
  * 重试所有失败的输入
@@ -183,24 +183,98 @@ describe('FlowQueue', () => {
183
183
  });
184
184
  });
185
185
  describe('并发处理', () => {
186
- it('应该防止并发处理', async () => {
186
+ it('应该支持配置的并发数量', async () => {
187
187
  const inputs = [
188
188
  { id: 1, data: 'test1' },
189
- { id: 2, data: 'test2' }
189
+ { id: 2, data: 'test2' },
190
+ { id: 3, data: 'test3' },
191
+ { id: 4, data: 'test4' }
190
192
  ];
191
- // 模拟较慢的处理器
193
+ let processingCount = 0;
194
+ let maxConcurrentProcessing = 0;
195
+ // 模拟较慢的处理器,用来测试并发
192
196
  mockProcessor = vi.fn().mockImplementation(async (input) => {
197
+ processingCount++;
198
+ maxConcurrentProcessing = Math.max(maxConcurrentProcessing, processingCount);
199
+ await new Promise(resolve => setTimeout(resolve, 50));
200
+ processingCount--;
201
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
202
+ });
203
+ // 创建支持 3 个并发的队列
204
+ flowQueue = new FlowQueue({
205
+ retry: { maxRetries: 3 },
206
+ concurrency: 3
207
+ }, mockProcessor);
208
+ // 添加所有输入
209
+ flowQueue.input(...inputs);
210
+ flowQueue.closeInput();
211
+ await flowQueue.awaitCompletion();
212
+ // 验证结果
213
+ expect(mockProcessor).toHaveBeenCalledTimes(4);
214
+ expect(flowQueue.successOutputs.size).toBe(4);
215
+ expect(maxConcurrentProcessing).toBe(3); // 应该达到配置的并发数
216
+ });
217
+ it('默认应该使用并发数 1(顺序处理)', async () => {
218
+ const inputs = [
219
+ { id: 1, data: 'test1' },
220
+ { id: 2, data: 'test2' },
221
+ { id: 3, data: 'test3' }
222
+ ];
223
+ let processingCount = 0;
224
+ let maxConcurrentProcessing = 0;
225
+ const processingOrder = [];
226
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
227
+ processingCount++;
228
+ maxConcurrentProcessing = Math.max(maxConcurrentProcessing, processingCount);
229
+ processingOrder.push(input.id);
193
230
  await new Promise(resolve => setTimeout(resolve, 30));
231
+ processingCount--;
194
232
  return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
195
233
  });
234
+ // 使用默认配置(并发数应该为 1)
196
235
  flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
197
- // 快速添加两个输入
198
- flowQueue.input(inputs[0]);
199
- flowQueue.input(inputs[1]);
200
- await new Promise(resolve => setTimeout(resolve, 100));
201
- // 应该按顺序处理
202
- expect(mockProcessor).toHaveBeenCalledTimes(2);
203
- expect(flowQueue['processedInputs'].length).toBe(2);
236
+ flowQueue.input(...inputs);
237
+ flowQueue.closeInput();
238
+ await flowQueue.awaitCompletion();
239
+ // 验证顺序处理
240
+ expect(maxConcurrentProcessing).toBe(1);
241
+ expect(processingOrder).toEqual([1, 2, 3]); // 应该按顺序处理
242
+ });
243
+ it('应该在达到并发限制时等待', async () => {
244
+ const inputs = [
245
+ { id: 1, data: 'test1' },
246
+ { id: 2, data: 'test2' },
247
+ { id: 3, data: 'test3' },
248
+ { id: 4, data: 'test4' },
249
+ { id: 5, data: 'test5' }
250
+ ];
251
+ let activeProcessing = 0;
252
+ let maxActiveProcessing = 0;
253
+ const processStartTimes = [];
254
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
255
+ processStartTimes.push(Date.now());
256
+ activeProcessing++;
257
+ maxActiveProcessing = Math.max(maxActiveProcessing, activeProcessing);
258
+ await new Promise(resolve => setTimeout(resolve, 80));
259
+ activeProcessing--;
260
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
261
+ });
262
+ // 创建并发数为 2 的队列
263
+ flowQueue = new FlowQueue({
264
+ retry: { maxRetries: 3 },
265
+ concurrency: 2
266
+ }, mockProcessor);
267
+ const startTime = Date.now();
268
+ flowQueue.input(...inputs);
269
+ flowQueue.closeInput();
270
+ await flowQueue.awaitCompletion();
271
+ // 验证并发限制生效
272
+ expect(maxActiveProcessing).toBe(2);
273
+ expect(flowQueue.successOutputs.size).toBe(5);
274
+ // 验证第3个任务等待了前面任务完成
275
+ // 由于并发数为2,第3个任务应该在第一批任务完成后才开始
276
+ const totalTime = Date.now() - startTime;
277
+ expect(totalTime).toBeGreaterThan(150); // 至少需要两轮处理
204
278
  });
205
279
  });
206
280
  describe('边界情况', () => {
@@ -676,7 +750,7 @@ describe('FlowQueue', () => {
676
750
  expect(flowQueue['processedInputs'].length).toBe(0);
677
751
  expect(flowQueue.successOutputs.size).toBe(0);
678
752
  expect(flowQueue['retryCount'].size).toBe(0);
679
- expect(flowQueue['isProcessing']).toBe(false);
753
+ expect(flowQueue['processingCount']).toBe(0);
680
754
  expect(flowQueue['isInputClosed']).toBe(false);
681
755
  expect(flowQueue['completionPromise']).toBe(null);
682
756
  expect(flowQueue['completionResolve']).toBe(null);
@@ -1030,4 +1104,101 @@ describe('FlowQueue', () => {
1030
1104
  });
1031
1105
  });
1032
1106
  });
1107
+ describe('链式调用', () => {
1108
+ it('应该支持 input 方法的链式调用', async () => {
1109
+ const inputs = [
1110
+ { id: 1, data: 'test1' },
1111
+ { id: 2, data: 'test2' },
1112
+ { id: 3, data: 'test3' }
1113
+ ];
1114
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
1115
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
1116
+ });
1117
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
1118
+ // 测试链式调用并验证返回值
1119
+ const returnValue = flowQueue
1120
+ .input(inputs[0])
1121
+ .input(inputs[1], inputs[2]);
1122
+ expect(returnValue).toBe(flowQueue); // 验证返回的是同一个实例
1123
+ flowQueue.closeInput();
1124
+ await flowQueue.awaitCompletion();
1125
+ expect(flowQueue.successOutputs.size).toBe(3);
1126
+ });
1127
+ it('应该支持 closeInput 方法的链式调用', async () => {
1128
+ const testInput = { id: 1, data: 'test' };
1129
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
1130
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
1131
+ });
1132
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
1133
+ // 测试链式调用
1134
+ const returnValue = flowQueue
1135
+ .input(testInput)
1136
+ .closeInput();
1137
+ expect(returnValue).toBe(flowQueue);
1138
+ await flowQueue.awaitCompletion();
1139
+ expect(flowQueue.successOutputs.size).toBe(1);
1140
+ });
1141
+ it('应该支持 reset 方法的链式调用', async () => {
1142
+ const firstInput = { id: 1, data: 'first' };
1143
+ const secondInput = { id: 2, data: 'second' };
1144
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
1145
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
1146
+ });
1147
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
1148
+ // 第一轮处理
1149
+ flowQueue.input(firstInput);
1150
+ flowQueue.closeInput();
1151
+ await flowQueue.awaitCompletion();
1152
+ expect(flowQueue.successOutputs.size).toBe(1);
1153
+ // 测试链式调用重置并开始新处理
1154
+ const returnValue = flowQueue
1155
+ .reset()
1156
+ .input(secondInput)
1157
+ .closeInput();
1158
+ expect(returnValue).toBe(flowQueue);
1159
+ await flowQueue.awaitCompletion();
1160
+ expect(flowQueue.successOutputs.size).toBe(1);
1161
+ expect(flowQueue.successOutputs.get(secondInput)?.result).toBe('processed_second');
1162
+ });
1163
+ it('应该支持 cancel 方法的链式调用', async () => {
1164
+ const testInputs = [
1165
+ { id: 1, data: 'test1' },
1166
+ { id: 2, data: 'test2' }
1167
+ ];
1168
+ flowQueue.input(...testInputs);
1169
+ // 测试链式调用
1170
+ const returnValue = flowQueue.cancel();
1171
+ expect(returnValue).toBe(flowQueue);
1172
+ expect(flowQueue['pendingInputs'].length).toBe(0);
1173
+ // 等待异步完成状态更新
1174
+ await new Promise(resolve => setTimeout(resolve, 10));
1175
+ expect(flowQueue.isCompleted).toBe(true);
1176
+ });
1177
+ it('应该支持完整的链式调用流程', async () => {
1178
+ const inputs = [
1179
+ { id: 1, data: 'test1' },
1180
+ { id: 2, data: 'test2' },
1181
+ { id: 3, data: 'test3' }
1182
+ ];
1183
+ mockProcessor = vi.fn().mockImplementation(async (input) => {
1184
+ return { id: input.id, result: `processed_${input.data}`, timestamp: Date.now() };
1185
+ });
1186
+ flowQueue = new FlowQueue({ retry: { maxRetries: 3 } }, mockProcessor);
1187
+ // 测试完整的链式调用流程
1188
+ await flowQueue
1189
+ .input(inputs[0], inputs[1])
1190
+ .input(inputs[2])
1191
+ .closeInput()
1192
+ .awaitCompletion();
1193
+ expect(flowQueue.successOutputs.size).toBe(3);
1194
+ expect(mockProcessor).toHaveBeenCalledTimes(3);
1195
+ // 测试重置后的链式调用
1196
+ await flowQueue
1197
+ .reset()
1198
+ .input(inputs[0])
1199
+ .closeInput()
1200
+ .awaitCompletion();
1201
+ expect(flowQueue.successOutputs.size).toBe(1);
1202
+ });
1203
+ });
1033
1204
  });
@@ -52,7 +52,6 @@ export declare class DefaultLogFormatter implements LogFormatter {
52
52
  private formatError;
53
53
  private formatUserError;
54
54
  private formatSystemError;
55
- private formatUnknownError;
56
55
  private formatGenericError;
57
56
  private formatUnknownValue;
58
57
  private formatContext;
@@ -1 +1 @@
1
- {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../source/logger/formatter.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,eAAe;IACf,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAA;IAClC,aAAa;IACb,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAA;IAC7B,aAAa;IACb,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAA;IAC7B,aAAa;IACb,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,MAAM,CAAA;IAC9B,aAAa;IACb,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,MAAM,CAAA;IACnC,eAAe;IACf,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,CAAA;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,cAAc;IACd,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAAA;IACxB,cAAc;IACd,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,EAAE,CAAA;CACvC;AAED,MAAM,WAAW,qBAAqB;IACpC,eAAe;IACf,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,gBAAgB;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,sBAAsB;IACtB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,YAAY;IACtD,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,MAAM,CAA0C;gBAE5C,MAAM,GAAE,eAAoB,EAAE,YAAY,GAAE,qBAA0B;IAgBlF;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM;IAwBxB;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,EAAE;IAItC;;OAEG;IACH,OAAO,CAAC,WAAW;IA0BnB,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,WAAW;CAWpB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,qBAA4B,CAAA"}
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../source/logger/formatter.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,eAAe;IACf,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAA;IAClC,aAAa;IACb,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAA;IAC7B,aAAa;IACb,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAA;IAC7B,aAAa;IACb,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,MAAM,CAAA;IAC9B,aAAa;IACb,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,MAAM,CAAA;IACnC,eAAe;IACf,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,CAAA;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,cAAc;IACd,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAAA;IACxB,cAAc;IACd,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,EAAE,CAAA;CACvC;AAED,MAAM,WAAW,qBAAqB;IACpC,eAAe;IACf,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,gBAAgB;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,sBAAsB;IACtB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,YAAY;IACtD,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,MAAM,CAA0C;gBAE5C,MAAM,GAAE,eAAoB,EAAE,YAAY,GAAE,qBAA0B;IAgBlF;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM;IAwBxB;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,EAAE;IAItC;;OAEG;IACH,OAAO,CAAC,WAAW;IAsBnB,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,WAAW;CAWpB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,qBAA4B,CAAA"}
@@ -2,7 +2,7 @@
2
2
  * 格式化器配置模块
3
3
  * 提供各种类型数据的格式化功能
4
4
  */
5
- import { UserError, SystemError, UnknownError } from '../error';
5
+ import { UserError, SystemError } from '../error';
6
6
  /**
7
7
  * 日志格式化器
8
8
  * 负责根据配置格式化各种类型的参数
@@ -66,9 +66,6 @@ export class DefaultLogFormatter {
66
66
  if (SystemError.is(error)) {
67
67
  return this.formatSystemError(error, opts);
68
68
  }
69
- if (UnknownError.is(error)) {
70
- return this.formatUnknownError(error, opts);
71
- }
72
69
  if (error instanceof Error) {
73
70
  return this.formatGenericError(error, opts);
74
71
  }
@@ -100,19 +97,6 @@ export class DefaultLogFormatter {
100
97
  }
101
98
  return lines.join('\n ');
102
99
  }
103
- formatUnknownError(error, opts) {
104
- const lines = [
105
- this.colorize('❓ Unknown Error', 'magenta', opts.useColors),
106
- `Message: ${error.message}`,
107
- ];
108
- if (opts.showContext && error.context) {
109
- lines.push(`Context: ${this.formatContext(error.context)}`);
110
- }
111
- if (opts.showStack && error.stack) {
112
- lines.push(`Stack: ${error.stack}`);
113
- }
114
- return lines.join('\n ');
115
- }
116
100
  formatGenericError(error, opts) {
117
101
  const lines = [
118
102
  this.colorize(`💥 ${error.name}`, 'red', opts.useColors),
@@ -1,26 +1,2 @@
1
- declare module '../error' {
2
- interface UserErrorTypes {
3
- 'validation-failed': {
4
- field?: string;
5
- value?: unknown;
6
- rule?: string;
7
- };
8
- 'test-error': {
9
- field?: string;
10
- };
11
- }
12
- interface SystemErrorTypes {
13
- 'database-error': {
14
- query?: string;
15
- table?: string;
16
- operation?: string;
17
- };
18
- 'network-error': {
19
- url?: string;
20
- method?: string;
21
- status?: number;
22
- };
23
- }
24
- }
25
1
  export {};
26
2
  //# sourceMappingURL=formatter.test.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"formatter.test.d.ts","sourceRoot":"","sources":["../../source/logger/formatter.test.ts"],"names":[],"mappings":"AAKA,OAAO,QAAQ,UAAU,CAAC;IACxB,UAAU,cAAc;QACtB,mBAAmB,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,OAAO,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QACvE,YAAY,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KACjC;IAED,UAAU,gBAAgB;QACxB,gBAAgB,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QACxE,eAAe,EAAE;YAAE,GAAG,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KACpE;CACF"}
1
+ {"version":3,"file":"formatter.test.d.ts","sourceRoot":"","sources":["../../source/logger/formatter.test.ts"],"names":[],"mappings":""}