(chunks: CodeChunk[], graph: InternalFileGraph)
| 24 | } |
| 25 | |
| 26 | function collectFileMetrics(chunks: CodeChunk[], graph: InternalFileGraph): FileMetricsMap { |
| 27 | const metrics = new Map<string, FileMetrics>(); |
| 28 | const graphJson = graph.toJSON(); |
| 29 | const reverseImports = new Map<string, Set<string>>(); |
| 30 | |
| 31 | for (const [file, deps] of Object.entries(graphJson.imports)) { |
| 32 | const normalizedFile = normalizePathLike(file); |
| 33 | const fileMetrics = metrics.get(normalizedFile) ?? { |
| 34 | importCount: 0, |
| 35 | importerCount: 0, |
| 36 | cycleCount: 0, |
| 37 | maxCyclomaticComplexity: 0 |
| 38 | }; |
| 39 | fileMetrics.importCount = deps.length; |
| 40 | metrics.set(normalizedFile, fileMetrics); |
| 41 | |
| 42 | for (const dependency of deps) { |
| 43 | const normalizedDependency = normalizePathLike(dependency); |
| 44 | const importers = reverseImports.get(normalizedDependency) ?? new Set<string>(); |
| 45 | importers.add(normalizedFile); |
| 46 | reverseImports.set(normalizedDependency, importers); |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | for (const [file, importers] of reverseImports.entries()) { |
| 51 | const fileMetrics = metrics.get(file) ?? { |
| 52 | importCount: 0, |
| 53 | importerCount: 0, |
| 54 | cycleCount: 0, |
| 55 | maxCyclomaticComplexity: 0 |
| 56 | }; |
| 57 | fileMetrics.importerCount = importers.size; |
| 58 | metrics.set(file, fileMetrics); |
| 59 | } |
| 60 | |
| 61 | for (const chunk of chunks) { |
| 62 | const file = normalizePathLike(chunk.relativePath || chunk.filePath); |
| 63 | const fileMetrics = metrics.get(file) ?? { |
| 64 | importCount: 0, |
| 65 | importerCount: 0, |
| 66 | cycleCount: 0, |
| 67 | maxCyclomaticComplexity: 0 |
| 68 | }; |
| 69 | const chunkComplexity = |
| 70 | typeof chunk.metadata?.cyclomaticComplexity === 'number' |
| 71 | ? chunk.metadata.cyclomaticComplexity |
| 72 | : typeof chunk.metadata?.complexity === 'number' |
| 73 | ? chunk.metadata.complexity |
| 74 | : 0; |
| 75 | fileMetrics.maxCyclomaticComplexity = Math.max( |
| 76 | fileMetrics.maxCyclomaticComplexity, |
| 77 | chunkComplexity |
| 78 | ); |
| 79 | metrics.set(file, fileMetrics); |
| 80 | } |
| 81 | |
| 82 | const hotspotRanks = Array.from(metrics.entries()) |
| 83 | .map(([file, fileMetrics]) => ({ |
no test coverage detected