@aiready/context-analyzer 0.21.25 → 0.21.27

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.
Files changed (78) hide show
  1. package/.turbo/turbo-build.log +32 -25
  2. package/.turbo/turbo-test.log +51 -87
  3. package/coverage/clover.xml +392 -1878
  4. package/coverage/coverage-final.json +15 -19
  5. package/coverage/index.html +48 -63
  6. package/coverage/src/analyzers/index.html +21 -21
  7. package/coverage/src/analyzers/python-context.ts.html +96 -96
  8. package/coverage/src/ast-utils.ts.html +34 -109
  9. package/coverage/src/classifier.ts.html +104 -104
  10. package/coverage/src/classify/classification-patterns.ts.html +1 -1
  11. package/coverage/src/classify/file-classifiers.ts.html +1 -1
  12. package/coverage/src/classify/index.html +1 -1
  13. package/coverage/src/cluster-detector.ts.html +72 -72
  14. package/coverage/src/defaults.ts.html +1 -1
  15. package/coverage/src/graph-builder.ts.html +131 -131
  16. package/coverage/src/index.html +101 -116
  17. package/coverage/src/index.ts.html +2 -2
  18. package/coverage/src/issue-analyzer.ts.html +32 -83
  19. package/coverage/src/mapper.ts.html +20 -2
  20. package/coverage/src/metrics.ts.html +127 -130
  21. package/coverage/src/orchestrator.ts.html +13 -13
  22. package/coverage/src/provider.ts.html +19 -19
  23. package/coverage/src/remediation.ts.html +59 -59
  24. package/coverage/src/report/console-report.ts.html +2 -2
  25. package/coverage/src/report/html-report.ts.html +60 -84
  26. package/coverage/src/report/index.html +7 -7
  27. package/coverage/src/report/interactive-setup.ts.html +1 -1
  28. package/coverage/src/scoring.ts.html +62 -62
  29. package/coverage/src/semantic/co-usage.ts.html +1 -1
  30. package/coverage/src/semantic/consolidation.ts.html +1 -1
  31. package/coverage/src/semantic/domain-inference.ts.html +1 -1
  32. package/coverage/src/semantic/index.html +1 -1
  33. package/coverage/src/semantic/type-graph.ts.html +1 -1
  34. package/coverage/src/summary.ts.html +67 -67
  35. package/coverage/src/types.ts.html +1 -1
  36. package/coverage/src/utils/dependency-graph-utils.ts.html +41 -41
  37. package/coverage/src/utils/index.html +21 -21
  38. package/coverage/src/utils/string-utils.ts.html +1 -1
  39. package/dist/chunk-22ZO4EKZ.mjs +1297 -0
  40. package/dist/chunk-4U4LDWGF.mjs +360 -0
  41. package/dist/chunk-BA7QGUHN.mjs +1722 -0
  42. package/dist/chunk-BCEZGRXI.mjs +1297 -0
  43. package/dist/chunk-BQCISA2F.mjs +91 -0
  44. package/dist/chunk-EMYD7NS6.mjs +137 -0
  45. package/dist/chunk-EWFR366Y.mjs +1740 -0
  46. package/dist/chunk-FO6YT6RG.mjs +1751 -0
  47. package/dist/chunk-J3SZQZNU.mjs +221 -0
  48. package/dist/chunk-OZE3FVZT.mjs +1089 -0
  49. package/dist/chunk-WHB7QI7N.mjs +91 -0
  50. package/dist/cli-action-CXIHOVAC.mjs +95 -0
  51. package/dist/cli-action-SA7SCYNV.mjs +95 -0
  52. package/dist/cli-action-YAJOJCXJ.mjs +95 -0
  53. package/dist/cli.js +688 -566
  54. package/dist/cli.mjs +4 -88
  55. package/dist/index.js +889 -773
  56. package/dist/index.mjs +21 -14
  57. package/dist/orchestrator-3L3NAZYP.mjs +10 -0
  58. package/dist/orchestrator-MONOZHVW.mjs +10 -0
  59. package/dist/orchestrator-ZR7JSKWI.mjs +10 -0
  60. package/dist/summary-7PZVW72O.mjs +7 -0
  61. package/dist/summary-LKUCJAIS.mjs +7 -0
  62. package/package.json +2 -2
  63. package/src/__tests__/analyzer.test.ts +1 -1
  64. package/src/__tests__/enhanced-cohesion.test.ts +4 -1
  65. package/src/__tests__/orchestrator.test.ts +19 -4
  66. package/src/__tests__/python-context.test.ts +6 -0
  67. package/src/__tests__/report/html-report.test.ts +8 -2
  68. package/src/ast-utils.ts +1 -26
  69. package/src/cli-definition.ts +4 -2
  70. package/src/issue-analyzer.ts +4 -19
  71. package/src/metrics.ts +1 -2
  72. package/src/provider.ts +4 -4
  73. package/src/report/html-report.ts +43 -59
  74. package/coverage/dist/chunk-64U3PNO3.mjs.html +0 -367
  75. package/coverage/dist/chunk-J3MUOWHC.mjs.html +0 -5326
  76. package/coverage/dist/index.html +0 -146
  77. package/coverage/dist/index.mjs.html +0 -1396
  78. package/coverage/src/analyzer.ts.html +0 -88
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">26.74% </span>
26
+ <span class="strong">75.58% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>23/86</span>
28
+ <span class='fraction'>65/86</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">11.53% </span>
33
+ <span class="strong">38.46% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>3/26</span>
35
+ <span class='fraction'>10/26</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">33.33% </span>
40
+ <span class="strong">88.88% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>3/9</span>
42
+ <span class='fraction'>8/9</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">27.5% </span>
47
+ <span class="strong">75% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>22/80</span>
49
+ <span class='fraction'>60/80</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 medium'></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>
@@ -413,39 +413,39 @@
413
413
  <span class="cline-any cline-yes">4x</span>
414
414
  <span class="cline-any cline-yes">4x</span>
415
415
  <span class="cline-any cline-yes">4x</span>
416
- <span class="cline-any cline-no">&nbsp;</span>
416
+ <span class="cline-any cline-yes">4x</span>
417
417
  <span class="cline-any cline-neutral">&nbsp;</span>
418
- <span class="cline-any cline-no">&nbsp;</span>
418
+ <span class="cline-any cline-yes">6x</span>
419
419
  <span class="cline-any cline-neutral">&nbsp;</span>
420
420
  <span class="cline-any cline-neutral">&nbsp;</span>
421
421
  <span class="cline-any cline-neutral">&nbsp;</span>
422
422
  <span class="cline-any cline-neutral">&nbsp;</span>
423
423
  <span class="cline-any cline-neutral">&nbsp;</span>
424
424
  <span class="cline-any cline-neutral">&nbsp;</span>
425
- <span class="cline-any cline-no">&nbsp;</span>
425
+ <span class="cline-any cline-yes">6x</span>
426
426
  <span class="cline-any cline-neutral">&nbsp;</span>
427
427
  <span class="cline-any cline-neutral">&nbsp;</span>
428
428
  <span class="cline-any cline-neutral">&nbsp;</span>
429
429
  <span class="cline-any cline-neutral">&nbsp;</span>
430
430
  <span class="cline-any cline-neutral">&nbsp;</span>
431
- <span class="cline-any cline-no">&nbsp;</span>
432
- <span class="cline-any cline-no">&nbsp;</span>
431
+ <span class="cline-any cline-yes">4x</span>
432
+ <span class="cline-any cline-yes">4x</span>
433
433
  <span class="cline-any cline-neutral">&nbsp;</span>
434
434
  <span class="cline-any cline-neutral">&nbsp;</span>
435
435
  <span class="cline-any cline-neutral">&nbsp;</span>
436
436
  <span class="cline-any cline-neutral">&nbsp;</span>
437
- <span class="cline-any cline-no">&nbsp;</span>
437
+ <span class="cline-any cline-yes">4x</span>
438
438
  <span class="cline-any cline-neutral">&nbsp;</span>
439
439
  <span class="cline-any cline-neutral">&nbsp;</span>
440
440
  <span class="cline-any cline-neutral">&nbsp;</span>
441
441
  <span class="cline-any cline-neutral">&nbsp;</span>
442
- <span class="cline-any cline-no">&nbsp;</span>
443
- <span class="cline-any cline-no">&nbsp;</span>
442
+ <span class="cline-any cline-yes">4x</span>
443
+ <span class="cline-any cline-yes">4x</span>
444
444
  <span class="cline-any cline-neutral">&nbsp;</span>
445
445
  <span class="cline-any cline-neutral">&nbsp;</span>
446
446
  <span class="cline-any cline-no">&nbsp;</span>
447
447
  <span class="cline-any cline-neutral">&nbsp;</span>
448
- <span class="cline-any cline-no">&nbsp;</span>
448
+ <span class="cline-any cline-yes">4x</span>
449
449
  <span class="cline-any cline-neutral">&nbsp;</span>
450
450
  <span class="cline-any cline-neutral">&nbsp;</span>
451
451
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -460,7 +460,7 @@
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-yes">4x</span>
463
+ <span class="cline-any cline-yes">3x</span>
464
464
  <span class="cline-any cline-neutral">&nbsp;</span>
465
465
  <span class="cline-any cline-neutral">&nbsp;</span>
466
466
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -482,21 +482,21 @@
482
482
  <span class="cline-any cline-yes">4x</span>
483
483
  <span class="cline-any cline-yes">4x</span>
484
484
  <span class="cline-any cline-yes">4x</span>
485
- <span class="cline-any cline-no">&nbsp;</span>
485
+ <span class="cline-any cline-yes">4x</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">4x</span>
488
488
  <span class="cline-any cline-neutral">&nbsp;</span>
489
- <span class="cline-any cline-no">&nbsp;</span>
490
- <span class="cline-any cline-no">&nbsp;</span>
491
- <span class="cline-any cline-no">&nbsp;</span>
489
+ <span class="cline-any cline-yes">4x</span>
490
+ <span class="cline-any cline-yes">6x</span>
491
+ <span class="cline-any cline-yes">6x</span>
492
492
  <span class="cline-any cline-no">&nbsp;</span>
493
493
  <span class="cline-any cline-neutral">&nbsp;</span>
494
494
  <span class="cline-any cline-neutral">&nbsp;</span>
495
495
  <span class="cline-any cline-neutral">&nbsp;</span>
496
- <span class="cline-any cline-no">&nbsp;</span>
497
- <span class="cline-any cline-neutral">&nbsp;</span>
498
496
  <span class="cline-any cline-yes">4x</span>
499
497
  <span class="cline-any cline-neutral">&nbsp;</span>
498
+ <span class="cline-any cline-no">&nbsp;</span>
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>
502
502
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -511,49 +511,49 @@
511
511
  <span class="cline-any cline-neutral">&nbsp;</span>
512
512
  <span class="cline-any cline-neutral">&nbsp;</span>
513
513
  <span class="cline-any cline-neutral">&nbsp;</span>
514
- <span class="cline-any cline-no">&nbsp;</span>
514
+ <span class="cline-any cline-yes">12x</span>
515
515
  <span class="cline-any cline-neutral">&nbsp;</span>
516
516
  <span class="cline-any cline-neutral">&nbsp;</span>
517
- <span class="cline-any cline-no">&nbsp;</span>
518
- <span class="cline-any cline-no">&nbsp;</span>
519
- <span class="cline-any cline-no">&nbsp;</span>
520
- <span class="cline-any cline-no">&nbsp;</span>
521
- <span class="cline-any cline-no">&nbsp;</span>
522
- <span class="cline-any cline-no">&nbsp;</span>
517
+ <span class="cline-any cline-yes">12x</span>
518
+ <span class="cline-any cline-yes">6x</span>
519
+ <span class="cline-any cline-yes">6x</span>
520
+ <span class="cline-any cline-yes">6x</span>
521
+ <span class="cline-any cline-yes">6x</span>
522
+ <span class="cline-any cline-yes">6x</span>
523
523
  <span class="cline-any cline-neutral">&nbsp;</span>
524
524
  <span class="cline-any cline-neutral">&nbsp;</span>
525
- <span class="cline-any cline-no">&nbsp;</span>
526
- <span class="cline-any cline-no">&nbsp;</span>
525
+ <span class="cline-any cline-yes">6x</span>
526
+ <span class="cline-any cline-yes">6x</span>
527
527
  <span class="cline-any cline-no">&nbsp;</span>
528
528
  <span class="cline-any cline-neutral">&nbsp;</span>
529
529
  <span class="cline-any cline-neutral">&nbsp;</span>
530
- <span class="cline-any cline-no">&nbsp;</span>
531
- <span class="cline-any cline-no">&nbsp;</span>
530
+ <span class="cline-any cline-yes">6x</span>
531
+ <span class="cline-any cline-yes">6x</span>
532
532
  <span class="cline-any cline-neutral">&nbsp;</span>
533
533
  <span class="cline-any cline-neutral">&nbsp;</span>
534
534
  <span class="cline-any cline-neutral">&nbsp;</span>
535
535
  <span class="cline-any cline-neutral">&nbsp;</span>
536
- <span class="cline-any cline-no">&nbsp;</span>
537
- <span class="cline-any cline-no">&nbsp;</span>
536
+ <span class="cline-any cline-yes">6x</span>
537
+ <span class="cline-any cline-yes">12x</span>
538
538
  <span class="cline-any cline-no">&nbsp;</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>
542
542
  <span class="cline-any cline-neutral">&nbsp;</span>
543
- <span class="cline-any cline-no">&nbsp;</span>
544
- <span class="cline-any cline-no">&nbsp;</span>
543
+ <span class="cline-any cline-yes">6x</span>
544
+ <span class="cline-any cline-yes">6x</span>
545
545
  <span class="cline-any cline-neutral">&nbsp;</span>
546
546
  <span class="cline-any cline-neutral">&nbsp;</span>
547
547
  <span class="cline-any cline-neutral">&nbsp;</span>
548
548
  <span class="cline-any cline-neutral">&nbsp;</span>
549
- <span class="cline-any cline-no">&nbsp;</span>
550
- <span class="cline-any cline-no">&nbsp;</span>
549
+ <span class="cline-any cline-yes">6x</span>
550
+ <span class="cline-any cline-yes">12x</span>
551
551
  <span class="cline-any cline-no">&nbsp;</span>
552
552
  <span class="cline-any cline-neutral">&nbsp;</span>
553
553
  <span class="cline-any cline-neutral">&nbsp;</span>
554
554
  <span class="cline-any cline-neutral">&nbsp;</span>
555
555
  <span class="cline-any cline-neutral">&nbsp;</span>
556
- <span class="cline-any cline-no">&nbsp;</span>
556
+ <span class="cline-any cline-yes">12x</span>
557
557
  <span class="cline-any cline-neutral">&nbsp;</span>
558
558
  <span class="cline-any cline-neutral">&nbsp;</span>
559
559
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -565,15 +565,15 @@
565
565
  <span class="cline-any cline-neutral">&nbsp;</span>
566
566
  <span class="cline-any cline-neutral">&nbsp;</span>
567
567
  <span class="cline-any cline-neutral">&nbsp;</span>
568
- <span class="cline-any cline-no">&nbsp;</span>
569
- <span class="cline-any cline-no">&nbsp;</span>
568
+ <span class="cline-any cline-yes">1x</span>
569
+ <span class="cline-any cline-yes">1x</span>
570
570
  <span class="cline-any cline-neutral">&nbsp;</span>
571
571
  <span class="cline-any cline-neutral">&nbsp;</span>
572
572
  <span class="cline-any cline-neutral">&nbsp;</span>
573
- <span class="cline-any cline-no">&nbsp;</span>
574
- <span class="cline-any cline-no">&nbsp;</span>
573
+ <span class="cline-any cline-yes">1x</span>
574
+ <span class="cline-any cline-yes">1x</span>
575
575
  <span class="cline-any cline-neutral">&nbsp;</span>
576
- <span class="cline-any cline-no">&nbsp;</span>
576
+ <span class="cline-any cline-yes">1x</span>
577
577
  <span class="cline-any cline-neutral">&nbsp;</span>
578
578
  <span class="cline-any cline-neutral">&nbsp;</span>
579
579
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -586,7 +586,7 @@
586
586
  <span class="cline-any cline-neutral">&nbsp;</span>
587
587
  <span class="cline-any cline-neutral">&nbsp;</span>
588
588
  <span class="cline-any cline-neutral">&nbsp;</span>
589
- <span class="cline-any cline-no">&nbsp;</span>
589
+ <span class="cline-any cline-yes">1x</span>
590
590
  <span class="cline-any cline-neutral">&nbsp;</span>
591
591
  <span class="cline-any cline-neutral">&nbsp;</span>
592
592
  <span class="cline-any cline-no">&nbsp;</span>
@@ -666,7 +666,7 @@ export async function analyzePythonContext(
666
666
  rootDir: string
667
667
  ): Promise&lt;PythonContextMetrics[]&gt; {
668
668
  const results: PythonContextMetrics[] = [];
669
- const parser = getParser('dummy.py');
669
+ const parser = await getParser('dummy.py');
670
670
  &nbsp;
671
671
  if (!parser) {
672
672
  console.warn('Python parser not available');
@@ -688,39 +688,39 @@ export async function analyzePythonContext(
688
688
  for (const file of pythonFiles) {
689
689
  try {
690
690
  const code = await fs.promises.readFile(file, 'utf-8');
691
- const result = <span class="cstat-no" title="statement not covered" >parser.parse(code, file);</span>
691
+ const result = parser.parse(code, file);
692
692
  &nbsp;
693
- const imports: PythonImportInfo[] = <span class="cstat-no" title="statement not covered" >result.imports.map(<span class="fstat-no" title="function not covered" >(i</span>mp) =&gt; (<span class="cstat-no" title="statement not covered" >{</span></span>
693
+ const imports: PythonImportInfo[] = result.imports.map((imp) =&gt; ({
694
694
  source: imp.source,
695
695
  specifiers: imp.specifiers,
696
696
  isRelative: imp.source.startsWith('.'),
697
697
  resolvedPath: resolvePythonImport(file, imp.source, rootDir),
698
698
  }));
699
699
  &nbsp;
700
- const exports: PythonExportInfo[] = <span class="cstat-no" title="statement not covered" >result.exports.map(<span class="fstat-no" title="function not covered" >(e</span>xp) =&gt; (<span class="cstat-no" title="statement not covered" >{</span></span>
700
+ const exports: PythonExportInfo[] = result.exports.map((exp) =&gt; ({
701
701
  name: exp.name,
702
702
  type: exp.type,
703
703
  }));
704
704
  &nbsp;
705
705
  // Calculate metrics
706
- const linesOfCode = <span class="cstat-no" title="statement not covered" >code.split('\n').length;</span>
707
- const <span class="cstat-no" title="statement not covered" >importDepth = calculateImportDepthFromEdges(</span>
706
+ const linesOfCode = code.split('\n').length;
707
+ const importDepth = calculateImportDepthFromEdges(
708
708
  file,
709
709
  dependencyGraph,
710
710
  new Set()
711
711
  );
712
- const contextBudget = <span class="cstat-no" title="statement not covered" >estimateContextBudget(</span>
712
+ const contextBudget = estimateContextBudget(
713
713
  code,
714
714
  imports,
715
715
  dependencyGraph
716
716
  );
717
- const cohesion = <span class="cstat-no" title="statement not covered" >calculatePythonCohesion(exports, imports);</span>
718
- const <span class="cstat-no" title="statement not covered" >circularDependencies = detectGraphCyclesFromFile(</span>
717
+ const cohesion = calculatePythonCohesion(exports, imports);
718
+ const circularDependencies = detectGraphCyclesFromFile(
719
719
  file,
720
720
  dependencyGraph
721
721
  ).map(<span class="fstat-no" title="function not covered" >(c</span>ycle) =&gt; <span class="cstat-no" title="statement not covered" >cycle.join(' -&gt; '))</span>;
722
722
  &nbsp;
723
- <span class="cstat-no" title="statement not covered" > results.push({</span>
723
+ results.push({
724
724
  file,
725
725
  importDepth,
726
726
  contextBudget,
@@ -750,27 +750,27 @@ async function buildPythonDependencyGraph(
750
750
  rootDir: string
751
751
  ): Promise&lt;Map&lt;string, Set&lt;string&gt;&gt;&gt; {
752
752
  const graph = new Map&lt;string, Set&lt;string&gt;&gt;();
753
- const parser = getParser('dummy.py');
753
+ const parser = await getParser('dummy.py');
754
754
  &nbsp;
755
755
  <span class="missing-if-branch" title="if path not taken" >I</span>if (!parser) <span class="cstat-no" title="statement not covered" >return graph;</span>
756
756
  &nbsp;
757
757
  for (const file of files) {
758
758
  try {
759
759
  const code = await fs.promises.readFile(file, 'utf-8');
760
- const result = <span class="cstat-no" title="statement not covered" >parser.parse(code, file);</span>
760
+ const result = parser.parse(code, file);
761
761
  &nbsp;
762
- const dependencies = <span class="cstat-no" title="statement not covered" >new Set&lt;string&gt;();</span>
762
+ const dependencies = new Set&lt;string&gt;();
763
763
  &nbsp;
764
- <span class="cstat-no" title="statement not covered" > for (const imp of result.imports) {</span>
765
- const resolved = <span class="cstat-no" title="statement not covered" >resolvePythonImport(file, imp.source, rootDir);</span>
766
- <span class="cstat-no" title="statement not covered" > if (resolved &amp;&amp; files.includes(resolved)) {</span>
764
+ for (const imp of result.imports) {
765
+ const resolved = resolvePythonImport(file, imp.source, rootDir);
766
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (resolved &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >files.includes(resolved)) {</span>
767
767
  <span class="cstat-no" title="statement not covered" > dependencies.add(resolved);</span>
768
768
  }
769
769
  }
770
770
  &nbsp;
771
- <span class="cstat-no" title="statement not covered" > graph.set(file, dependencies);</span>
771
+ graph.set(file, dependencies);
772
772
  } catch (error) {
773
- void error;
773
+ <span class="cstat-no" title="statement not covered" > void error;</span>
774
774
  // Skip files with errors
775
775
  }
776
776
  }
@@ -781,74 +781,74 @@ async function buildPythonDependencyGraph(
781
781
  /**
782
782
  * Resolve Python import to file path
783
783
  */
784
- function <span class="fstat-no" title="function not covered" >resolvePythonImport(</span>
784
+ function resolvePythonImport(
785
785
  fromFile: string,
786
786
  importPath: string,
787
787
  rootDir: string
788
788
  ): string | undefined {
789
- const <span class="cstat-no" title="statement not covered" >dir = dirname(fromFile);</span>
789
+ const dir = dirname(fromFile);
790
790
  &nbsp;
791
791
  // Handle relative imports
792
- <span class="cstat-no" title="statement not covered" > if (importPath.startsWith('.')) {</span>
793
- const parts = <span class="cstat-no" title="statement not covered" >importPath.split('.');</span>
794
- let upCount = <span class="cstat-no" title="statement not covered" >0;</span>
795
- <span class="cstat-no" title="statement not covered" > while (parts[0] === '') {</span>
796
- <span class="cstat-no" title="statement not covered" > upCount++;</span>
797
- <span class="cstat-no" title="statement not covered" > parts.shift();</span>
792
+ if (importPath.startsWith('.')) {
793
+ const parts = importPath.split('.');
794
+ let upCount = 0;
795
+ while (parts[0] === '') {
796
+ upCount++;
797
+ parts.shift();
798
798
  }
799
799
  &nbsp;
800
- let targetDir = <span class="cstat-no" title="statement not covered" >dir;</span>
801
- <span class="cstat-no" title="statement not covered" > for (let i = <span class="cstat-no" title="statement not covered" >0; i</span> &lt; upCount - 1; i++) {</span>
800
+ let targetDir = dir;
801
+ for (let i = 0; i &lt; upCount - 1; i++) {
802
802
  <span class="cstat-no" title="statement not covered" > targetDir = dirname(targetDir);</span>
803
803
  }
804
804
  &nbsp;
805
- const modulePath = <span class="cstat-no" title="statement not covered" >parts.join('/');</span>
806
- const possiblePaths = <span class="cstat-no" title="statement not covered" >[</span>
805
+ const modulePath = parts.join('/');
806
+ const possiblePaths = [
807
807
  resolve(targetDir, `${modulePath}.py`),
808
808
  resolve(targetDir, modulePath, '__init__.py'),
809
809
  ];
810
810
  &nbsp;
811
- <span class="cstat-no" title="statement not covered" > for (const path of possiblePaths) {</span>
812
- <span class="cstat-no" title="statement not covered" > if (fs.existsSync(path)) {</span>
811
+ for (const path of possiblePaths) {
812
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (fs.existsSync(path)) {
813
813
  <span class="cstat-no" title="statement not covered" > return path;</span>
814
814
  }
815
815
  }
816
816
  } else {
817
817
  // Handle absolute imports (from project root)
818
- const modulePath = <span class="cstat-no" title="statement not covered" >importPath.replace(/\./g, '/');</span>
819
- const possiblePaths = <span class="cstat-no" title="statement not covered" >[</span>
818
+ const modulePath = importPath.replace(/\./g, '/');
819
+ const possiblePaths = [
820
820
  resolve(rootDir, `${modulePath}.py`),
821
821
  resolve(rootDir, modulePath, '__init__.py'),
822
822
  ];
823
823
  &nbsp;
824
- <span class="cstat-no" title="statement not covered" > for (const path of possiblePaths) {</span>
825
- <span class="cstat-no" title="statement not covered" > if (fs.existsSync(path)) {</span>
824
+ for (const path of possiblePaths) {
825
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (fs.existsSync(path)) {
826
826
  <span class="cstat-no" title="statement not covered" > return path;</span>
827
827
  }
828
828
  }
829
829
  }
830
830
  &nbsp;
831
- <span class="cstat-no" title="statement not covered" > return undefined;</span>
831
+ return undefined;
832
832
  }
833
833
  &nbsp;
834
834
  /**
835
835
  * Estimate context budget (tokens needed for file + direct deps)
836
836
  */
837
- function <span class="fstat-no" title="function not covered" >estimateContextBudget(</span>
837
+ function estimateContextBudget(
838
838
  code: string,
839
839
  imports: PythonImportInfo[],
840
840
  dependencyGraph: Map&lt;string, Set&lt;string&gt;&gt;
841
841
  ): number {
842
842
  // File tokens
843
- <span class="cstat-no" title="statement not covered" > void dependencyGraph;</span>
844
- let <span class="cstat-no" title="statement not covered" >budget = estimateTokens(code);</span>
843
+ void dependencyGraph;
844
+ let budget = estimateTokens(code);
845
845
  &nbsp;
846
846
  // Add tokens for direct dependencies (simplified)
847
847
  // In a full implementation, we'd load each dependency file
848
- const avgTokensPerDep = <span class="cstat-no" title="statement not covered" >500; // Conservative estimate</span>
849
- <span class="cstat-no" title="statement not covered" > budget += imports.length * avgTokensPerDep;</span>
848
+ const avgTokensPerDep = 500; // Conservative estimate
849
+ budget += imports.length * avgTokensPerDep;
850
850
  &nbsp;
851
- <span class="cstat-no" title="statement not covered" > return budget;</span>
851
+ return budget;
852
852
  }
853
853
  &nbsp;
854
854
  /**
@@ -857,11 +857,11 @@ function <span class="fstat-no" title="function not covered" >estimateContextBud
857
857
  * Cohesion = How related are the exports to each other?
858
858
  * Higher cohesion = better (single responsibility)
859
859
  */
860
- function <span class="fstat-no" title="function not covered" >calculatePythonCohesion(</span>
860
+ function calculatePythonCohesion(
861
861
  exports: PythonExportInfo[],
862
862
  imports: PythonImportInfo[]
863
863
  ): number {
864
- <span class="cstat-no" title="statement not covered" > if (exports.length === 0) <span class="cstat-no" title="statement not covered" >return 1;</span></span>
864
+ <span class="missing-if-branch" title="else path not taken" >E</span>if (exports.length === 0) return 1;
865
865
  &nbsp;
866
866
  // Simple heuristic: files with many exports but few imports are less cohesive
867
867
  const exportCount = <span class="cstat-no" title="statement not covered" >exports.length;</span>
@@ -895,7 +895,7 @@ function <span class="fstat-no" title="function not covered" >calculatePythonCoh
895
895
  <div class='footer quiet pad2 space-top1 center small'>
896
896
  Code coverage generated by
897
897
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
898
- at 2026-03-21T12:52:37.698Z
898
+ at 2026-03-24T11:20:59.666Z
899
899
  </div>
900
900
  <script src="../../prettify.js"></script>
901
901
  <script>