(matches: ApproachMatch[], k = 5)
| 97 | * skipped; capped at `k` (default 5, per the "last 5 approaches with dates" spec). PURE. |
| 98 | */ |
| 99 | export function renderTimeline(matches: ApproachMatch[], k = 5): string[] { |
| 100 | const dated = matches |
| 101 | .map(m => ({ m, t: m.at ? Date.parse(m.at) : NaN })) |
| 102 | .filter(x => Number.isFinite(x.t)) |
| 103 | .sort((a, b) => a.t - b.t) |
| 104 | .slice(-k); |
| 105 | if (dated.length < 2) return []; |
| 106 | const lines = ['', `Timeline (oldest → newest):`]; |
| 107 | dated.forEach(({ m }, i) => { |
| 108 | const date = m.at!.slice(0, 10); |
| 109 | const glyph = i === dated.length - 1 ? '●' : '○'; |
| 110 | const mark = m.verified === true ? ' ✓' : m.verified === false ? ' ⛔' : ''; |
| 111 | lines.push(` ${glyph} ${date}${mark} ${head(m.text, 76)}`); |
| 112 | }); |
| 113 | return lines; |
| 114 | } |
| 115 | |
| 116 | /** |
| 117 | * Render top-K matches as a visual comparison: the best approach in full, then each alternative |
no test coverage detected