projax 3.3.55 → 3.3.57

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.
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">0% </span>
26
+ <span class="strong">94.93% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>0/79</span>
28
+ <span class='fraction'>75/79</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">0% </span>
33
+ <span class="strong">83.05% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>0/59</span>
35
+ <span class='fraction'>49/59</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">0% </span>
40
+ <span class="strong">100% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>0/8</span>
42
+ <span class='fraction'>8/8</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">0% </span>
47
+ <span class="strong">94.87% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>0/78</span>
49
+ <span class='fraction'>74/78</span>
50
50
  </div>
51
51
 
52
52
 
@@ -61,7 +61,7 @@
61
61
  </div>
62
62
  </template>
63
63
  </div>
64
- <div class='status-line low'></div>
64
+ <div class='status-line high'></div>
65
65
  <pre><table class="coverage">
66
66
  <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
67
  <a name='L2'></a><a href='#L2'>2</a>
@@ -316,8 +316,8 @@
316
316
  <span class="cline-any cline-neutral">&nbsp;</span>
317
317
  <span class="cline-any cline-neutral">&nbsp;</span>
318
318
  <span class="cline-any cline-neutral">&nbsp;</span>
319
- <span class="cline-any cline-no">&nbsp;</span>
320
- <span class="cline-any cline-no">&nbsp;</span>
319
+ <span class="cline-any cline-yes">1x</span>
320
+ <span class="cline-any cline-yes">21x</span>
321
321
  <span class="cline-any cline-neutral">&nbsp;</span>
322
322
  <span class="cline-any cline-neutral">&nbsp;</span>
323
323
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -328,29 +328,29 @@
328
328
  <span class="cline-any cline-neutral">&nbsp;</span>
329
329
  <span class="cline-any cline-neutral">&nbsp;</span>
330
330
  <span class="cline-any cline-neutral">&nbsp;</span>
331
- <span class="cline-any cline-no">&nbsp;</span>
331
+ <span class="cline-any cline-yes">21x</span>
332
332
  <span class="cline-any cline-neutral">&nbsp;</span>
333
- <span class="cline-any cline-no">&nbsp;</span>
334
- <span class="cline-any cline-no">&nbsp;</span>
333
+ <span class="cline-any cline-yes">7x</span>
334
+ <span class="cline-any cline-yes">14x</span>
335
335
  <span class="cline-any cline-neutral">&nbsp;</span>
336
- <span class="cline-any cline-no">&nbsp;</span>
337
- <span class="cline-any cline-no">&nbsp;</span>
336
+ <span class="cline-any cline-yes">3x</span>
337
+ <span class="cline-any cline-yes">11x</span>
338
338
  <span class="cline-any cline-neutral">&nbsp;</span>
339
- <span class="cline-any cline-no">&nbsp;</span>
340
- <span class="cline-any cline-no">&nbsp;</span>
339
+ <span class="cline-any cline-yes">4x</span>
340
+ <span class="cline-any cline-yes">7x</span>
341
341
  <span class="cline-any cline-neutral">&nbsp;</span>
342
- <span class="cline-any cline-no">&nbsp;</span>
342
+ <span class="cline-any cline-yes">2x</span>
343
343
  <span class="cline-any cline-neutral">&nbsp;</span>
344
344
  <span class="cline-any cline-neutral">&nbsp;</span>
345
- <span class="cline-any cline-no">&nbsp;</span>
345
+ <span class="cline-any cline-yes">5x</span>
346
346
  <span class="cline-any cline-neutral">&nbsp;</span>
347
347
  <span class="cline-any cline-neutral">&nbsp;</span>
348
348
  <span class="cline-any cline-neutral">&nbsp;</span>
349
- <span class="cline-any cline-no">&nbsp;</span>
350
- <span class="cline-any cline-no">&nbsp;</span>
349
+ <span class="cline-any cline-yes">16x</span>
350
+ <span class="cline-any cline-yes">8x</span>
351
351
  <span class="cline-any cline-neutral">&nbsp;</span>
352
352
  <span class="cline-any cline-neutral">&nbsp;</span>
353
- <span class="cline-any cline-no">&nbsp;</span>
353
+ <span class="cline-any cline-yes">16x</span>
354
354
  <span class="cline-any cline-neutral">&nbsp;</span>
355
355
  <span class="cline-any cline-neutral">&nbsp;</span>
356
356
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -362,32 +362,32 @@
362
362
  <span class="cline-any cline-neutral">&nbsp;</span>
363
363
  <span class="cline-any cline-neutral">&nbsp;</span>
364
364
  <span class="cline-any cline-neutral">&nbsp;</span>
365
- <span class="cline-any cline-no">&nbsp;</span>
366
- <span class="cline-any cline-no">&nbsp;</span>
367
- <span class="cline-any cline-no">&nbsp;</span>
368
- <span class="cline-any cline-no">&nbsp;</span>
369
- <span class="cline-any cline-no">&nbsp;</span>
365
+ <span class="cline-any cline-yes">7x</span>
366
+ <span class="cline-any cline-yes">7x</span>
367
+ <span class="cline-any cline-yes">7x</span>
368
+ <span class="cline-any cline-yes">7x</span>
369
+ <span class="cline-any cline-yes">7x</span>
370
370
  <span class="cline-any cline-neutral">&nbsp;</span>
371
- <span class="cline-any cline-no">&nbsp;</span>
372
- <span class="cline-any cline-no">&nbsp;</span>
373
- <span class="cline-any cline-no">&nbsp;</span>
374
- <span class="cline-any cline-no">&nbsp;</span>
371
+ <span class="cline-any cline-yes">7x</span>
372
+ <span class="cline-any cline-yes">7x</span>
373
+ <span class="cline-any cline-yes">7x</span>
374
+ <span class="cline-any cline-yes">7x</span>
375
375
  <span class="cline-any cline-neutral">&nbsp;</span>
376
376
  <span class="cline-any cline-neutral">&nbsp;</span>
377
- <span class="cline-any cline-no">&nbsp;</span>
378
- <span class="cline-any cline-no">&nbsp;</span>
377
+ <span class="cline-any cline-yes">7x</span>
378
+ <span class="cline-any cline-yes">6x</span>
379
379
  <span class="cline-any cline-neutral">&nbsp;</span>
380
380
  <span class="cline-any cline-neutral">&nbsp;</span>
381
- <span class="cline-any cline-no">&nbsp;</span>
382
- <span class="cline-any cline-no">&nbsp;</span>
381
+ <span class="cline-any cline-yes">7x</span>
382
+ <span class="cline-any cline-yes">5x</span>
383
383
  <span class="cline-any cline-neutral">&nbsp;</span>
384
384
  <span class="cline-any cline-neutral">&nbsp;</span>
385
- <span class="cline-any cline-no">&nbsp;</span>
386
- <span class="cline-any cline-no">&nbsp;</span>
385
+ <span class="cline-any cline-yes">7x</span>
386
+ <span class="cline-any cline-yes">1x</span>
387
387
  <span class="cline-any cline-neutral">&nbsp;</span>
388
388
  <span class="cline-any cline-neutral">&nbsp;</span>
389
389
  <span class="cline-any cline-neutral">&nbsp;</span>
390
- <span class="cline-any cline-no">&nbsp;</span>
390
+ <span class="cline-any cline-yes">7x</span>
391
391
  <span class="cline-any cline-neutral">&nbsp;</span>
392
392
  <span class="cline-any cline-neutral">&nbsp;</span>
393
393
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -399,28 +399,28 @@
399
399
  <span class="cline-any cline-neutral">&nbsp;</span>
400
400
  <span class="cline-any cline-neutral">&nbsp;</span>
401
401
  <span class="cline-any cline-neutral">&nbsp;</span>
402
- <span class="cline-any cline-no">&nbsp;</span>
403
- <span class="cline-any cline-no">&nbsp;</span>
404
- <span class="cline-any cline-no">&nbsp;</span>
405
- <span class="cline-any cline-no">&nbsp;</span>
402
+ <span class="cline-any cline-yes">3x</span>
403
+ <span class="cline-any cline-yes">3x</span>
404
+ <span class="cline-any cline-yes">3x</span>
405
+ <span class="cline-any cline-yes">3x</span>
406
406
  <span class="cline-any cline-neutral">&nbsp;</span>
407
- <span class="cline-any cline-no">&nbsp;</span>
408
- <span class="cline-any cline-no">&nbsp;</span>
407
+ <span class="cline-any cline-yes">3x</span>
408
+ <span class="cline-any cline-yes">3x</span>
409
409
  <span class="cline-any cline-neutral">&nbsp;</span>
410
410
  <span class="cline-any cline-neutral">&nbsp;</span>
411
- <span class="cline-any cline-no">&nbsp;</span>
412
- <span class="cline-any cline-no">&nbsp;</span>
411
+ <span class="cline-any cline-yes">3x</span>
412
+ <span class="cline-any cline-yes">3x</span>
413
413
  <span class="cline-any cline-neutral">&nbsp;</span>
414
414
  <span class="cline-any cline-neutral">&nbsp;</span>
415
- <span class="cline-any cline-no">&nbsp;</span>
416
- <span class="cline-any cline-no">&nbsp;</span>
415
+ <span class="cline-any cline-yes">3x</span>
416
+ <span class="cline-any cline-yes">1x</span>
417
417
  <span class="cline-any cline-neutral">&nbsp;</span>
418
418
  <span class="cline-any cline-neutral">&nbsp;</span>
419
- <span class="cline-any cline-no">&nbsp;</span>
420
- <span class="cline-any cline-no">&nbsp;</span>
419
+ <span class="cline-any cline-yes">3x</span>
420
+ <span class="cline-any cline-yes">3x</span>
421
421
  <span class="cline-any cline-neutral">&nbsp;</span>
422
422
  <span class="cline-any cline-neutral">&nbsp;</span>
423
- <span class="cline-any cline-no">&nbsp;</span>
423
+ <span class="cline-any cline-yes">3x</span>
424
424
  <span class="cline-any cline-neutral">&nbsp;</span>
425
425
  <span class="cline-any cline-neutral">&nbsp;</span>
426
426
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -430,25 +430,25 @@
430
430
  <span class="cline-any cline-neutral">&nbsp;</span>
431
431
  <span class="cline-any cline-neutral">&nbsp;</span>
432
432
  <span class="cline-any cline-neutral">&nbsp;</span>
433
- <span class="cline-any cline-no">&nbsp;</span>
433
+ <span class="cline-any cline-yes">4x</span>
434
434
  <span class="cline-any cline-neutral">&nbsp;</span>
435
- <span class="cline-any cline-no">&nbsp;</span>
436
- <span class="cline-any cline-no">&nbsp;</span>
437
- <span class="cline-any cline-no">&nbsp;</span>
438
- <span class="cline-any cline-no">&nbsp;</span>
435
+ <span class="cline-any cline-yes">4x</span>
436
+ <span class="cline-any cline-yes">4x</span>
437
+ <span class="cline-any cline-yes">4x</span>
438
+ <span class="cline-any cline-yes">4x</span>
439
439
  <span class="cline-any cline-neutral">&nbsp;</span>
440
- <span class="cline-any cline-no">&nbsp;</span>
441
- <span class="cline-any cline-no">&nbsp;</span>
440
+ <span class="cline-any cline-yes">4x</span>
441
+ <span class="cline-any cline-yes">4x</span>
442
442
  <span class="cline-any cline-neutral">&nbsp;</span>
443
443
  <span class="cline-any cline-neutral">&nbsp;</span>
444
444
  <span class="cline-any cline-neutral">&nbsp;</span>
445
445
  <span class="cline-any cline-neutral">&nbsp;</span>
446
- <span class="cline-any cline-no">&nbsp;</span>
447
- <span class="cline-any cline-no">&nbsp;</span>
448
- <span class="cline-any cline-no">&nbsp;</span>
446
+ <span class="cline-any cline-yes">4x</span>
447
+ <span class="cline-any cline-yes">4x</span>
448
+ <span class="cline-any cline-yes">1x</span>
449
449
  <span class="cline-any cline-neutral">&nbsp;</span>
450
450
  <span class="cline-any cline-neutral">&nbsp;</span>
451
- <span class="cline-any cline-no">&nbsp;</span>
451
+ <span class="cline-any cline-yes">4x</span>
452
452
  <span class="cline-any cline-neutral">&nbsp;</span>
453
453
  <span class="cline-any cline-neutral">&nbsp;</span>
454
454
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -460,31 +460,31 @@
460
460
  <span class="cline-any cline-neutral">&nbsp;</span>
461
461
  <span class="cline-any cline-neutral">&nbsp;</span>
462
462
  <span class="cline-any cline-neutral">&nbsp;</span>
463
- <span class="cline-any cline-no">&nbsp;</span>
464
- <span class="cline-any cline-no">&nbsp;</span>
463
+ <span class="cline-any cline-yes">2x</span>
464
+ <span class="cline-any cline-yes">2x</span>
465
465
  <span class="cline-any cline-neutral">&nbsp;</span>
466
- <span class="cline-any cline-no">&nbsp;</span>
467
- <span class="cline-any cline-no">&nbsp;</span>
468
- <span class="cline-any cline-no">&nbsp;</span>
466
+ <span class="cline-any cline-yes">2x</span>
467
+ <span class="cline-any cline-yes">2x</span>
468
+ <span class="cline-any cline-yes">2x</span>
469
469
  <span class="cline-any cline-neutral">&nbsp;</span>
470
470
  <span class="cline-any cline-neutral">&nbsp;</span>
471
+ <span class="cline-any cline-yes">2x</span>
471
472
  <span class="cline-any cline-no">&nbsp;</span>
472
473
  <span class="cline-any cline-no">&nbsp;</span>
473
474
  <span class="cline-any cline-no">&nbsp;</span>
474
475
  <span class="cline-any cline-no">&nbsp;</span>
475
- <span class="cline-any cline-no">&nbsp;</span>
476
- <span class="cline-any cline-no">&nbsp;</span>
477
- <span class="cline-any cline-no">&nbsp;</span>
476
+ <span class="cline-any cline-yes">2x</span>
477
+ <span class="cline-any cline-yes">2x</span>
478
478
  <span class="cline-any cline-neutral">&nbsp;</span>
479
479
  <span class="cline-any cline-neutral">&nbsp;</span>
480
- <span class="cline-any cline-no">&nbsp;</span>
480
+ <span class="cline-any cline-yes">2x</span>
481
481
  <span class="cline-any cline-neutral">&nbsp;</span>
482
482
  <span class="cline-any cline-neutral">&nbsp;</span>
483
483
  <span class="cline-any cline-neutral">&nbsp;</span>
484
484
  <span class="cline-any cline-neutral">&nbsp;</span>
485
485
  <span class="cline-any cline-neutral">&nbsp;</span>
486
486
  <span class="cline-any cline-neutral">&nbsp;</span>
487
- <span class="cline-any cline-no">&nbsp;</span>
487
+ <span class="cline-any cline-yes">5x</span>
488
488
  <span class="cline-any cline-neutral">&nbsp;</span>
489
489
  <span class="cline-any cline-neutral">&nbsp;</span>
490
490
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -495,7 +495,7 @@
495
495
  <span class="cline-any cline-neutral">&nbsp;</span>
496
496
  <span class="cline-any cline-neutral">&nbsp;</span>
497
497
  <span class="cline-any cline-neutral">&nbsp;</span>
498
- <span class="cline-any cline-no">&nbsp;</span>
498
+ <span class="cline-any cline-yes">5x</span>
499
499
  <span class="cline-any cline-neutral">&nbsp;</span>
500
500
  <span class="cline-any cline-neutral">&nbsp;</span>
501
501
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -503,23 +503,23 @@
503
503
  <span class="cline-any cline-neutral">&nbsp;</span>
504
504
  <span class="cline-any cline-neutral">&nbsp;</span>
505
505
  <span class="cline-any cline-neutral">&nbsp;</span>
506
- <span class="cline-any cline-no">&nbsp;</span>
507
- <span class="cline-any cline-no">&nbsp;</span>
508
- <span class="cline-any cline-no">&nbsp;</span>
509
- <span class="cline-any cline-no">&nbsp;</span>
506
+ <span class="cline-any cline-yes">5x</span>
507
+ <span class="cline-any cline-yes">25x</span>
508
+ <span class="cline-any cline-yes">25x</span>
509
+ <span class="cline-any cline-yes">4x</span>
510
510
  <span class="cline-any cline-neutral">&nbsp;</span>
511
511
  <span class="cline-any cline-neutral">&nbsp;</span>
512
512
  <span class="cline-any cline-neutral">&nbsp;</span>
513
- <span class="cline-any cline-no">&nbsp;</span>
513
+ <span class="cline-any cline-yes">5x</span>
514
514
  <span class="cline-any cline-neutral">&nbsp;</span>
515
- <span class="cline-any cline-no">&nbsp;</span>
515
+ <span class="cline-any cline-yes">5x</span>
516
516
  <span class="cline-any cline-neutral">&nbsp;</span>
517
517
  <span class="cline-any cline-neutral">&nbsp;</span>
518
518
  <span class="cline-any cline-neutral">&nbsp;</span>
519
519
  <span class="cline-any cline-neutral">&nbsp;</span>
520
520
  <span class="cline-any cline-neutral">&nbsp;</span>
521
- <span class="cline-any cline-no">&nbsp;</span>
522
- <span class="cline-any cline-no">&nbsp;</span>
521
+ <span class="cline-any cline-yes">1x</span>
522
+ <span class="cline-any cline-yes">16x</span>
523
523
  <span class="cline-any cline-neutral">&nbsp;</span>
524
524
  <span class="cline-any cline-neutral">&nbsp;</span>
525
525
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -535,7 +535,7 @@
535
535
  <span class="cline-any cline-neutral">&nbsp;</span>
536
536
  <span class="cline-any cline-neutral">&nbsp;</span>
537
537
  <span class="cline-any cline-neutral">&nbsp;</span>
538
- <span class="cline-any cline-no">&nbsp;</span>
538
+ <span class="cline-any cline-yes">119x</span>
539
539
  <span class="cline-any cline-neutral">&nbsp;</span>
540
540
  <span class="cline-any cline-neutral">&nbsp;</span>
541
541
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -554,8 +554,8 @@ export interface ParsedTestResult {
554
554
  /**
555
555
  * Parse test output from various frameworks and extract statistics
556
556
  */
557
- <span class="cstat-no" title="statement not covered" >export function <span class="fstat-no" title="function not covered" >p</span>arseTestOutput(</span>output: string): ParsedTestResult | null {
558
- const result: ParsedTestResult = <span class="cstat-no" title="statement not covered" >{</span>
557
+ export function parseTestOutput(output: string): ParsedTestResult | null {
558
+ const result: ParsedTestResult = {
559
559
  framework: null,
560
560
  passed: 0,
561
561
  failed: 0,
@@ -566,163 +566,163 @@ export interface ParsedTestResult {
566
566
  };
567
567
  &nbsp;
568
568
  // Detect framework and parse accordingly
569
- <span class="cstat-no" title="statement not covered" > if (output.includes('PASS') &amp;&amp; output.includes('FAIL') || output.includes('Test Suites:')) {</span>
569
+ if (output.includes('PASS') &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >output.includes('FAIL') </span>|| output.includes('Test Suites:')) {
570
570
  // Jest/Vitest
571
- <span class="cstat-no" title="statement not covered" > result.framework = parseJestVitestOutput(output, result);</span>
572
- } else <span class="cstat-no" title="statement not covered" >if (output.includes('passing') &amp;&amp; output.includes('failing')) {</span>
571
+ result.framework = parseJestVitestOutput(output, result);
572
+ } else if (output.includes('passing') &amp;&amp; output.includes('failing')) {
573
573
  // Mocha
574
- <span class="cstat-no" title="statement not covered" > result.framework = parseMochaOutput(output, result);</span>
575
- } else <span class="cstat-no" title="statement not covered" >if (output.includes('passed') &amp;&amp; output.includes('failed') &amp;&amp; output.includes('pytest')) {</span>
574
+ result.framework = parseMochaOutput(output, result);
575
+ } else if (output.includes('passed') &amp;&amp; output.includes('failed') &amp;&amp; output.includes('pytest')) {
576
576
  // pytest
577
- <span class="cstat-no" title="statement not covered" > result.framework = parsePytestOutput(output, result);</span>
578
- } else <span class="cstat-no" title="statement not covered" >if (output.includes('OK') &amp;&amp; output.includes('test')) {</span>
577
+ result.framework = parsePytestOutput(output, result);
578
+ } else if (output.includes('OK') &amp;&amp; output.includes('test')) {
579
579
  // Python unittest
580
- <span class="cstat-no" title="statement not covered" > result.framework = parseUnittestOutput(output, result);</span>
580
+ result.framework = parseUnittestOutput(output, result);
581
581
  } else {
582
582
  // Try generic parsing
583
- <span class="cstat-no" title="statement not covered" > return parseGenericOutput(output);</span>
583
+ return parseGenericOutput(output);
584
584
  }
585
585
  &nbsp;
586
586
  // Calculate total if not set
587
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (result.total === 0) {</span>
588
- <span class="cstat-no" title="statement not covered" > result.total = result.passed + result.failed + result.skipped;</span>
587
+ if (result.total === 0) {
588
+ result.total = result.passed + result.failed + result.skipped;
589
589
  }
590
590
  &nbsp;
591
- <span class="cstat-no" title="statement not covered" > return result.total &gt; 0 ? result : null;</span>
591
+ return result.total &gt; 0 ? result : <span class="branch-1 cbranch-no" title="branch not covered" >null;</span>
592
592
  }
593
593
  &nbsp;
594
594
  /**
595
595
  * Parse Jest/Vitest output
596
596
  */
597
- function <span class="fstat-no" title="function not covered" >parseJestVitestOutput(</span>output: string, result: ParsedTestResult): string {
597
+ function parseJestVitestOutput(output: string, result: ParsedTestResult): string {
598
598
  // Jest format:
599
599
  // Test Suites: 2 failed, 1 passed, 3 total
600
600
  // Tests: 5 failed, 10 passed, 15 total
601
601
  // Time: 2.345 s
602
602
 
603
- const testSuitesMatch = <span class="cstat-no" title="statement not covered" >output.match(/Test Suites:.*?(\d+)\s+passed/i);</span>
604
- const testsMatch = <span class="cstat-no" title="statement not covered" >output.match(/Tests:\s+(?:(\d+)\s+failed,?\s*)?(?:(\d+)\s+skipped,?\s*)?(?:(\d+)\s+passed)/i);</span>
605
- const totalMatch = <span class="cstat-no" title="statement not covered" >output.match(/Tests:.*?(\d+)\s+total/i);</span>
606
- const timeMatch = <span class="cstat-no" title="statement not covered" >output.match(/Time:\s+([\d.]+)\s*s/i);</span>
607
- const coverageMatch = <span class="cstat-no" title="statement not covered" >output.match(/All files\s*\|\s*([\d.]+)/);</span>
603
+ const testSuitesMatch = output.match(/Test Suites:.*?(\d+)\s+passed/i);
604
+ const testsMatch = output.match(/Tests:\s+(?:(\d+)\s+failed,?\s*)?(?:(\d+)\s+skipped,?\s*)?(?:(\d+)\s+passed)/i);
605
+ const totalMatch = output.match(/Tests:.*?(\d+)\s+total/i);
606
+ const timeMatch = output.match(/Time:\s+([\d.]+)\s*s/i);
607
+ const coverageMatch = output.match(/All files\s*\|\s*([\d.]+)/);
608
608
 
609
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (testsMatch) {</span>
610
- <span class="cstat-no" title="statement not covered" > result.failed = testsMatch[1] ? parseInt(testsMatch[1], 10) : 0;</span>
611
- <span class="cstat-no" title="statement not covered" > result.skipped = testsMatch[2] ? parseInt(testsMatch[2], 10) : 0;</span>
612
- <span class="cstat-no" title="statement not covered" > result.passed = testsMatch[3] ? parseInt(testsMatch[3], 10) : 0;</span>
609
+ if (testsMatch) {
610
+ result.failed = testsMatch[1] ? parseInt(testsMatch[1], 10) : 0;
611
+ result.skipped = testsMatch[2] ? parseInt(testsMatch[2], 10) : 0;
612
+ result.passed = testsMatch[3] ? parseInt(testsMatch[3], 10) : <span class="branch-1 cbranch-no" title="branch not covered" >0;</span>
613
613
  }
614
614
 
615
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (totalMatch) {</span>
616
- <span class="cstat-no" title="statement not covered" > result.total = parseInt(totalMatch[1], 10);</span>
615
+ if (totalMatch) {
616
+ result.total = parseInt(totalMatch[1], 10);
617
617
  }
618
618
 
619
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (timeMatch) {</span>
620
- <span class="cstat-no" title="statement not covered" > result.duration = Math.floor(parseFloat(timeMatch[1]) * 1000);</span>
619
+ if (timeMatch) {
620
+ result.duration = Math.floor(parseFloat(timeMatch[1]) * 1000);
621
621
  }
622
622
 
623
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (coverageMatch) {</span>
624
- <span class="cstat-no" title="statement not covered" > result.coverage = parseFloat(coverageMatch[1]);</span>
623
+ if (coverageMatch) {
624
+ result.coverage = parseFloat(coverageMatch[1]);
625
625
  }
626
626
 
627
627
  // Determine if Jest or Vitest
628
- <span class="cstat-no" title="statement not covered" > return output.includes('vitest') ? 'vitest' : 'jest';</span>
628
+ return output.includes('vitest') ? 'vitest' : 'jest';
629
629
  }
630
630
  &nbsp;
631
631
  /**
632
632
  * Parse Mocha output
633
633
  */
634
- function <span class="fstat-no" title="function not covered" >parseMochaOutput(</span>output: string, result: ParsedTestResult): string {
634
+ function parseMochaOutput(output: string, result: ParsedTestResult): string {
635
635
  // Mocha format:
636
636
  // 10 passing (234ms)
637
637
  // 2 failing
638
638
  // 1 pending
639
639
 
640
- const passingMatch = <span class="cstat-no" title="statement not covered" >output.match(/(\d+)\s+passing/i);</span>
641
- const failingMatch = <span class="cstat-no" title="statement not covered" >output.match(/(\d+)\s+failing/i);</span>
642
- const pendingMatch = <span class="cstat-no" title="statement not covered" >output.match(/(\d+)\s+pending/i);</span>
643
- const timeMatch = <span class="cstat-no" title="statement not covered" >output.match(/passing\s+\((\d+)ms\)/i);</span>
640
+ const passingMatch = output.match(/(\d+)\s+passing/i);
641
+ const failingMatch = output.match(/(\d+)\s+failing/i);
642
+ const pendingMatch = output.match(/(\d+)\s+pending/i);
643
+ const timeMatch = output.match(/passing\s+\((\d+)ms\)/i);
644
644
 
645
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (passingMatch) {</span>
646
- <span class="cstat-no" title="statement not covered" > result.passed = parseInt(passingMatch[1], 10);</span>
645
+ if (passingMatch) {
646
+ result.passed = parseInt(passingMatch[1], 10);
647
647
  }
648
648
 
649
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (failingMatch) {</span>
650
- <span class="cstat-no" title="statement not covered" > result.failed = parseInt(failingMatch[1], 10);</span>
649
+ if (failingMatch) {
650
+ result.failed = parseInt(failingMatch[1], 10);
651
651
  }
652
652
 
653
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (pendingMatch) {</span>
654
- <span class="cstat-no" title="statement not covered" > result.skipped = parseInt(pendingMatch[1], 10);</span>
653
+ if (pendingMatch) {
654
+ result.skipped = parseInt(pendingMatch[1], 10);
655
655
  }
656
656
 
657
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (timeMatch) {</span>
658
- <span class="cstat-no" title="statement not covered" > result.duration = parseInt(timeMatch[1], 10);</span>
657
+ if (timeMatch) {
658
+ result.duration = parseInt(timeMatch[1], 10);
659
659
  }
660
660
 
661
- <span class="cstat-no" title="statement not covered" > return 'mocha';</span>
661
+ return 'mocha';
662
662
  }
663
663
  &nbsp;
664
664
  /**
665
665
  * Parse pytest output
666
666
  */
667
- function <span class="fstat-no" title="function not covered" >parsePytestOutput(</span>output: string, result: ParsedTestResult): string {
667
+ function parsePytestOutput(output: string, result: ParsedTestResult): string {
668
668
  // pytest format:
669
669
  // ===== 10 passed, 2 failed, 1 skipped in 2.34s =====
670
670
 
671
- const statsMatch = <span class="cstat-no" title="statement not covered" >output.match(/=+\s*(?:(\d+)\s+passed)?(?:,\s*(\d+)\s+failed)?(?:,\s*(\d+)\s+skipped)?(?:\s+in\s+([\d.]+)s)?/i);</span>
671
+ const statsMatch = output.match(/=+\s*(?:(\d+)\s+passed)?(?:,\s*(\d+)\s+failed)?(?:,\s*(\d+)\s+skipped)?(?:\s+in\s+([\d.]+)s)?/i);
672
672
 
673
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (statsMatch) {</span>
674
- <span class="cstat-no" title="statement not covered" > result.passed = statsMatch[1] ? parseInt(statsMatch[1], 10) : 0;</span>
675
- <span class="cstat-no" title="statement not covered" > result.failed = statsMatch[2] ? parseInt(statsMatch[2], 10) : 0;</span>
676
- <span class="cstat-no" title="statement not covered" > result.skipped = statsMatch[3] ? parseInt(statsMatch[3], 10) : 0;</span>
673
+ if (statsMatch) {
674
+ result.passed = statsMatch[1] ? parseInt(statsMatch[1], 10) : <span class="branch-1 cbranch-no" title="branch not covered" >0;</span>
675
+ result.failed = statsMatch[2] ? parseInt(statsMatch[2], 10) : <span class="branch-1 cbranch-no" title="branch not covered" >0;</span>
676
+ result.skipped = statsMatch[3] ? parseInt(statsMatch[3], 10) : 0;
677
677
 
678
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (statsMatch[4]) {</span>
679
- <span class="cstat-no" title="statement not covered" > result.duration = Math.floor(parseFloat(statsMatch[4]) * 1000);</span>
678
+ if (statsMatch[4]) {
679
+ result.duration = Math.floor(parseFloat(statsMatch[4]) * 1000);
680
680
  }
681
681
  }
682
682
 
683
683
  // Coverage
684
- const coverageMatch = <span class="cstat-no" title="statement not covered" >output.match(/TOTAL\s+\d+\s+\d+\s+(\d+)%/);</span>
685
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (coverageMatch) {</span>
686
- <span class="cstat-no" title="statement not covered" > result.coverage = parseInt(coverageMatch[1], 10);</span>
684
+ const coverageMatch = output.match(/TOTAL\s+\d+\s+\d+\s+(\d+)%/);
685
+ if (coverageMatch) {
686
+ result.coverage = parseInt(coverageMatch[1], 10);
687
687
  }
688
688
 
689
- <span class="cstat-no" title="statement not covered" > return 'pytest';</span>
689
+ return 'pytest';
690
690
  }
691
691
  &nbsp;
692
692
  /**
693
693
  * Parse Python unittest output
694
694
  */
695
- function <span class="fstat-no" title="function not covered" >parseUnittestOutput(</span>output: string, result: ParsedTestResult): string {
695
+ function parseUnittestOutput(output: string, result: ParsedTestResult): string {
696
696
  // unittest format:
697
697
  // Ran 15 tests in 2.345s
698
698
  // OK
699
699
  // or FAILED (failures=2, errors=1)
700
700
 
701
- const ranMatch = <span class="cstat-no" title="statement not covered" >output.match(/Ran\s+(\d+)\s+tests?\s+in\s+([\d.]+)s/i);</span>
702
- const failedMatch = <span class="cstat-no" title="statement not covered" >output.match(/FAILED\s*\((?:failures=(\d+))?(?:,\s*errors=(\d+))?\)/i);</span>
701
+ const ranMatch = output.match(/Ran\s+(\d+)\s+tests?\s+in\s+([\d.]+)s/i);
702
+ const failedMatch = output.match(/FAILED\s*\((?:failures=(\d+))?(?:,\s*errors=(\d+))?\)/i);
703
703
 
704
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (ranMatch) {</span>
705
- <span class="cstat-no" title="statement not covered" > result.total = parseInt(ranMatch[1], 10);</span>
706
- <span class="cstat-no" title="statement not covered" > result.duration = Math.floor(parseFloat(ranMatch[2]) * 1000);</span>
704
+ if (ranMatch) {
705
+ result.total = parseInt(ranMatch[1], 10);
706
+ result.duration = Math.floor(parseFloat(ranMatch[2]) * 1000);
707
707
  }
708
708
 
709
- <span class="cstat-no" title="statement not covered" > if (failedMatch) {</span>
709
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (failedMatch) {
710
710
  const failures = <span class="cstat-no" title="statement not covered" >failedMatch[1] ? parseInt(failedMatch[1], 10) : 0;</span>
711
711
  const errors = <span class="cstat-no" title="statement not covered" >failedMatch[2] ? parseInt(failedMatch[2], 10) : 0;</span>
712
712
  <span class="cstat-no" title="statement not covered" > result.failed = failures + errors;</span>
713
713
  <span class="cstat-no" title="statement not covered" > result.passed = result.total - result.failed;</span>
714
- } else <span class="cstat-no" title="statement not covered" ><span class="missing-if-branch" title="if path not taken" >I</span>if (output.includes('OK')) {</span>
715
- <span class="cstat-no" title="statement not covered" > result.passed = result.total;</span>
714
+ } else if (output.includes('OK')) {
715
+ result.passed = result.total;
716
716
  }
717
717
 
718
- <span class="cstat-no" title="statement not covered" > return 'unittest';</span>
718
+ return 'unittest';
719
719
  }
720
720
  &nbsp;
721
721
  /**
722
722
  * Generic parser for unrecognized frameworks
723
723
  */
724
- function <span class="fstat-no" title="function not covered" >parseGenericOutput(</span>output: string): ParsedTestResult | null {
725
- const result: ParsedTestResult = <span class="cstat-no" title="statement not covered" >{</span>
724
+ function parseGenericOutput(output: string): ParsedTestResult | null {
725
+ const result: ParsedTestResult = {
726
726
  framework: 'unknown',
727
727
  passed: 0,
728
728
  failed: 0,
@@ -733,7 +733,7 @@ function <span class="fstat-no" title="function not covered" >parseGenericOutput
733
733
  };
734
734
 
735
735
  // Try to find common patterns
736
- const patterns = <span class="cstat-no" title="statement not covered" >[</span>
736
+ const patterns = [
737
737
  { regex: /(\d+)\s+(?:test(?:s)?|spec(?:s)?)\s+passed/i, key: 'passed' },
738
738
  { regex: /(\d+)\s+(?:test(?:s)?|spec(?:s)?)\s+failed/i, key: 'failed' },
739
739
  { regex: /(\d+)\s+(?:test(?:s)?|spec(?:s)?)\s+skipped/i, key: 'skipped' },
@@ -741,23 +741,23 @@ function <span class="fstat-no" title="function not covered" >parseGenericOutput
741
741
  { regex: /✗\s*(\d+)/i, key: 'failed' },
742
742
  ];
743
743
 
744
- <span class="cstat-no" title="statement not covered" > for (const pattern of patterns) {</span>
745
- const match = <span class="cstat-no" title="statement not covered" >output.match(pattern.regex);</span>
746
- <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (match &amp;&amp; pattern.key in result) {</span>
747
- <span class="cstat-no" title="statement not covered" > result[pattern.key as 'passed' | 'failed' | 'skipped'] = parseInt(match[1], 10);</span>
744
+ for (const pattern of patterns) {
745
+ const match = output.match(pattern.regex);
746
+ if (match &amp;&amp; pattern.key in result) {
747
+ result[pattern.key as 'passed' | 'failed' | 'skipped'] = parseInt(match[1], 10);
748
748
  }
749
749
  }
750
750
 
751
- <span class="cstat-no" title="statement not covered" > result.total = result.passed + result.failed + result.skipped;</span>
751
+ result.total = result.passed + result.failed + result.skipped;
752
752
 
753
- <span class="cstat-no" title="statement not covered" > return result.total &gt; 0 ? result : null;</span>
753
+ return result.total &gt; 0 ? result : null;
754
754
  }
755
755
  &nbsp;
756
756
  /**
757
757
  * Check if output appears to be from a test command
758
758
  */
759
- <span class="cstat-no" title="statement not covered" >export function <span class="fstat-no" title="function not covered" >i</span>sTestOutput(</span>output: string): boolean {
760
- const testIndicators = <span class="cstat-no" title="statement not covered" >[</span>
759
+ export function isTestOutput(output: string): boolean {
760
+ const testIndicators = [
761
761
  'Test Suites:',
762
762
  'Tests:',
763
763
  'passing',
@@ -773,7 +773,7 @@ function <span class="fstat-no" title="function not covered" >parseGenericOutput
773
773
  'FAIL',
774
774
  ];
775
775
 
776
- <span class="cstat-no" title="statement not covered" > return testIndicators.some(<span class="fstat-no" title="function not covered" >indicator </span>=&gt; <span class="cstat-no" title="statement not covered" >output.includes(indicator))</span>;</span>
776
+ return testIndicators.some(indicator =&gt; output.includes(indicator));
777
777
  }
778
778
  &nbsp;
779
779
  &nbsp;
@@ -784,7 +784,7 @@ function <span class="fstat-no" title="function not covered" >parseGenericOutput
784
784
  <div class='footer quiet pad2 space-top1 center small'>
785
785
  Code coverage generated by
786
786
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
787
- at 2026-01-08T01:22:23.516Z
787
+ at 2026-01-08T07:29:04.471Z
788
788
  </div>
789
789
  <script src="prettify.js"></script>
790
790
  <script>