All files / src/semantic co-usage.ts

51.51% Statements 17/33
31.57% Branches 6/19
33.33% Functions 1/3
51.85% Lines 14/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86                      23x   23x 39x   39x 29x 29x   29x 45x 45x 45x   45x 45x 45x         23x                                                                                                          
import type { DependencyGraph, CoUsageData } from '../types';
 
/**
 * Build co-usage matrix: track which files are imported together frequently.
 *
 * @param graph - The dependency graph to analyze.
 * @returns Map of file path to nested map of related files and their co-occurrence counts.
 */
export function buildCoUsageMatrix(
  graph: DependencyGraph
): Map<string, Map<string, number>> {
  const coUsageMatrix = new Map<string, Map<string, number>>();
 
  for (const [, node] of graph.nodes) {
    const imports = node.imports;
 
    for (let i = 0; i < imports.length; i++) {
      const fileA = imports[i];
      if (!coUsageMatrix.has(fileA)) coUsageMatrix.set(fileA, new Map());
 
      for (let j = i + 1; j < imports.length; j++) {
        const fileB = imports[j];
        const fileAUsage = coUsageMatrix.get(fileA)!;
        fileAUsage.set(fileB, (fileAUsage.get(fileB) || 0) + 1);
 
        Iif (!coUsageMatrix.has(fileB)) coUsageMatrix.set(fileB, new Map());
        const fileBUsage = coUsageMatrix.get(fileB)!;
        fileBUsage.set(fileA, (fileBUsage.get(fileA) || 0) + 1);
      }
    }
  }
 
  return coUsageMatrix;
}
 
/**
 * Find semantic clusters using frequently occurring co-usage patterns.
 *
 * @param coUsageMatrix - The co-usage matrix from buildCoUsageMatrix.
 * @param minCoUsage - Minimum co-usage count to consider a strong relationship (default: 3).
 * @returns Map of cluster representative files to their associated cluster members.
 */
export function findSemanticClusters(
  coUsageMatrix: Map<string, Map<string, number>>,
  minCoUsage: number = 3
): Map<string, string[]> {
  const clusters = new Map<string, string[]>();
  const visited = new Set<string>();
 
  for (const [file, coUsages] of coUsageMatrix) {
    if (visited.has(file)) continue;
 
    const cluster: string[] = [file];
    visited.add(file);
 
    for (const [relatedFile, count] of coUsages) {
      if (count >= minCoUsage && !visited.has(relatedFile)) {
        cluster.push(relatedFile);
        visited.add(relatedFile);
      }
    }
 
    if (cluster.length > 1) clusters.set(file, cluster);
  }
 
  return clusters;
}
 
/**
 * Retrieve co-usage data for a specific file.
 *
 * @param file - The file path to look up.
 * @param coUsageMatrix - The global co-usage matrix.
 * @returns Formatted co-usage data object.
 */
export function getCoUsageData(
  file: string,
  coUsageMatrix: Map<string, Map<string, number>>
): CoUsageData {
  return {
    file,
    coImportedWith: coUsageMatrix.get(file) || new Map(),
    sharedImporters: [],
  };
}