(logPath: string)
| 179 | * Parse re-render logs from the CLI debug log file |
| 180 | */ |
| 181 | export function parseRerenderLogs(logPath: string): RerenderLogEntry[] { |
| 182 | const entries: RerenderLogEntry[] = [] |
| 183 | |
| 184 | try { |
| 185 | const content = fs.readFileSync(logPath, 'utf-8') |
| 186 | const lines = content.split('\n').filter((line) => line.trim()) |
| 187 | |
| 188 | for (const line of lines) { |
| 189 | try { |
| 190 | const parsed = JSON.parse(line) |
| 191 | |
| 192 | // Check if this is a re-render log entry |
| 193 | if ( |
| 194 | parsed.msg && |
| 195 | typeof parsed.msg === 'string' && |
| 196 | parsed.msg.includes('render #') |
| 197 | ) { |
| 198 | // Extract component name from msg like "MessageBlock render #2 [user-123]: 2 props changed" |
| 199 | const msgMatch = parsed.msg.match( |
| 200 | /^(\w+) render #(\d+) \[([^\]]+)\]/, |
| 201 | ) |
| 202 | if (msgMatch && parsed.data) { |
| 203 | entries.push({ |
| 204 | timestamp: parsed.timestamp, |
| 205 | componentName: msgMatch[1], |
| 206 | messageId: parsed.data.id || msgMatch[3], |
| 207 | renderCount: parseInt(msgMatch[2], 10), |
| 208 | changedProps: parsed.data.changedProps || [], |
| 209 | }) |
| 210 | } |
| 211 | } |
| 212 | } catch { |
| 213 | // Skip malformed lines |
| 214 | } |
| 215 | } |
| 216 | } catch { |
| 217 | // File doesn't exist or can't be read |
| 218 | } |
| 219 | |
| 220 | return entries |
| 221 | } |
| 222 | |
| 223 | /** |
| 224 | * Analyze re-render logs and return aggregated statistics |
no test coverage detected