(file: DeepnoteFile, options: AnalysisOptions = {})
| 114 | * Pure function - no I/O, no console output. |
| 115 | */ |
| 116 | export function computeProjectStats(file: DeepnoteFile, options: AnalysisOptions = {}): ProjectStats { |
| 117 | const notebooks: NotebookStats[] = [] |
| 118 | const allBlockTypes = new Map<string, { count: number; loc: number }>() |
| 119 | |
| 120 | let totalBlocks = 0 |
| 121 | let totalLoc = 0 |
| 122 | |
| 123 | for (const notebook of file.project.notebooks) { |
| 124 | if (options.notebook && notebook.name !== options.notebook) { |
| 125 | continue |
| 126 | } |
| 127 | |
| 128 | const notebookStats = analyzeNotebook(notebook) |
| 129 | notebooks.push(notebookStats) |
| 130 | |
| 131 | totalBlocks += notebookStats.blockCount |
| 132 | totalLoc += notebookStats.linesOfCode |
| 133 | |
| 134 | // Aggregate block types |
| 135 | for (const bt of notebookStats.blockTypes) { |
| 136 | const existing = allBlockTypes.get(bt.type) ?? { count: 0, loc: 0 } |
| 137 | allBlockTypes.set(bt.type, { |
| 138 | count: existing.count + bt.count, |
| 139 | loc: existing.loc + bt.linesOfCode, |
| 140 | }) |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | // Validate notebook exists if filter was specified |
| 145 | if (options.notebook && notebooks.length === 0) { |
| 146 | const availableNotebooks = file.project.notebooks.map(n => `"${n.name}"`).join(', ') |
| 147 | throw new NotFoundInProjectError( |
| 148 | `Notebook "${options.notebook}" not found in project. Available notebooks: ${availableNotebooks}` |
| 149 | ) |
| 150 | } |
| 151 | |
| 152 | // Convert block types map to sorted array |
| 153 | const blockTypesSummary: BlockTypeStats[] = Array.from(allBlockTypes.entries()) |
| 154 | .map(([type, stats]) => ({ |
| 155 | type, |
| 156 | count: stats.count, |
| 157 | linesOfCode: stats.loc, |
| 158 | })) |
| 159 | .sort((a, b) => b.count - a.count) |
| 160 | |
| 161 | return { |
| 162 | projectName: file.project.name, |
| 163 | projectId: file.project.id, |
| 164 | notebookCount: notebooks.length, |
| 165 | totalBlocks, |
| 166 | totalLinesOfCode: totalLoc, |
| 167 | blockTypesSummary, |
| 168 | notebooks, |
| 169 | // Imports are populated by analyzeProject using DAG analysis for accuracy |
| 170 | imports: [], |
| 171 | } |
| 172 | } |
| 173 |
no test coverage detected