(path: string, analysis: AnalysisResult, blockMap: Map<string, BlockInfo>)
| 84 | } |
| 85 | |
| 86 | function buildAnalyzeResult(path: string, analysis: AnalysisResult, blockMap: Map<string, BlockInfo>): AnalyzeResult { |
| 87 | const { stats, lint, dag } = analysis |
| 88 | |
| 89 | // Helper to get block label |
| 90 | const getLabel = (blockId: string): string => { |
| 91 | const info = blockMap.get(blockId) |
| 92 | if (info) { |
| 93 | return `${info.notebookName}/${info.label}` |
| 94 | } |
| 95 | return blockId.slice(0, 8) |
| 96 | } |
| 97 | |
| 98 | // Find entry points (blocks with no incoming edges) |
| 99 | const blocksWithIncoming = new Set(dag.edges.map(e => e.to)) |
| 100 | const entryPoints = dag.nodes |
| 101 | .filter(n => !blocksWithIncoming.has(n.id)) |
| 102 | .map(n => ({ |
| 103 | id: n.id, |
| 104 | label: getLabel(n.id), |
| 105 | })) |
| 106 | |
| 107 | // Find exit points (blocks with no outgoing edges) |
| 108 | const blocksWithOutgoing = new Set(dag.edges.map(e => e.from)) |
| 109 | const exitPoints = dag.nodes |
| 110 | .filter(n => !blocksWithOutgoing.has(n.id)) |
| 111 | .map(n => ({ |
| 112 | id: n.id, |
| 113 | label: getLabel(n.id), |
| 114 | })) |
| 115 | |
| 116 | // Calculate longest dependency chain using BFS |
| 117 | const longestChain = calculateLongestChain(dag.nodes, dag.edges) |
| 118 | |
| 119 | // Calculate quality score (0-100) |
| 120 | // Start at 100, subtract for issues |
| 121 | let score = 100 |
| 122 | score -= lint.issueCount.errors * 10 // -10 per error |
| 123 | score -= lint.issueCount.warnings * 2 // -2 per warning |
| 124 | score = Math.max(0, Math.min(100, score)) // Clamp to 0-100 |
| 125 | |
| 126 | // Generate suggestions |
| 127 | const suggestions = generateSuggestions(analysis) |
| 128 | |
| 129 | return { |
| 130 | path, |
| 131 | project: { |
| 132 | name: stats.projectName, |
| 133 | id: stats.projectId, |
| 134 | notebooks: stats.notebookCount, |
| 135 | blocks: stats.totalBlocks, |
| 136 | linesOfCode: stats.totalLinesOfCode, |
| 137 | }, |
| 138 | quality: { |
| 139 | score, |
| 140 | errors: lint.issueCount.errors, |
| 141 | warnings: lint.issueCount.warnings, |
| 142 | issues: lint.issues.map(issue => ({ |
| 143 | severity: issue.severity, |
no test coverage detected