( tasks: TaskInfo[], options: TimeSummaryOptions, isCompletedStatus: (status: string) => boolean )
| 169 | } |
| 170 | |
| 171 | export function computeTimeSummary( |
| 172 | tasks: TaskInfo[], |
| 173 | options: TimeSummaryOptions, |
| 174 | isCompletedStatus: (status: string) => boolean |
| 175 | ): TimeSummaryResult { |
| 176 | const { startDate, endDate } = computeDateRange(options); |
| 177 | |
| 178 | let totalMinutes = 0; |
| 179 | let completedTasks = 0; |
| 180 | let activeTasks = 0; |
| 181 | const taskStats: Array<{ task: string; title: string; minutes: number }> = []; |
| 182 | const projectStats = new Map<string, number>(); |
| 183 | const tagStats = options.includeTags ? new Map<string, number>() : null; |
| 184 | |
| 185 | for (const task of tasks) { |
| 186 | if (!task.timeEntries || task.timeEntries.length === 0) continue; |
| 187 | |
| 188 | let taskMinutes = 0; |
| 189 | let hasActiveSession = false; |
| 190 | |
| 191 | for (const entry of task.timeEntries) { |
| 192 | const entryStart = new Date(entry.startTime); |
| 193 | |
| 194 | if (entryStart >= startDate && entryStart <= endDate) { |
| 195 | if (!entry.endTime) { |
| 196 | taskMinutes += Math.floor( |
| 197 | (Date.now() - entryStart.getTime()) / (1000 * 60) |
| 198 | ); |
| 199 | hasActiveSession = true; |
| 200 | } else { |
| 201 | const entryEnd = new Date(entry.endTime); |
| 202 | taskMinutes += Math.floor( |
| 203 | (entryEnd.getTime() - entryStart.getTime()) / (1000 * 60) |
| 204 | ); |
| 205 | } |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | if (taskMinutes > 0) { |
| 210 | totalMinutes += taskMinutes; |
| 211 | taskStats.push({ |
| 212 | task: task.path, |
| 213 | title: task.title, |
| 214 | minutes: taskMinutes, |
| 215 | }); |
| 216 | |
| 217 | if (hasActiveSession) { |
| 218 | activeTasks++; |
| 219 | } else if (isCompletedStatus(task.status)) { |
| 220 | completedTasks++; |
| 221 | } |
| 222 | |
| 223 | if (task.projects) { |
| 224 | for (const project of task.projects) { |
| 225 | projectStats.set(project, (projectStats.get(project) || 0) + taskMinutes); |
| 226 | } |
| 227 | } |
| 228 |
no test coverage detected