fix: coerce completedAt to String in visualizer changelog sort

YAML frontmatter parsers can return Date objects for ISO date strings
instead of plain strings. This caused a TypeError when calling
.localeCompare() on a Date object in the changelog sort.

Wrap completedAt with String() at both assignment and sort to handle
both native and JS parser paths safely.
This commit is contained in:
Jeremy McSpadden 2026-03-16 14:52:17 -05:00
parent 72223d0a7a
commit a01df1f110
2 changed files with 13 additions and 2 deletions

View file

@ -165,6 +165,17 @@ assertTrue(
"VisualizerData has changelog field",
);
// completedAt must be coerced to String() to handle YAML Date objects (issue #644)
assertTrue(
dataSrc.includes("String(summary.frontmatter.completed_at"),
"completedAt assignment coerces to String() for YAML Date safety",
);
assertTrue(
dataSrc.includes("String(b.completedAt") && dataSrc.includes("String(a.completedAt"),
"changelog sort coerces completedAt to String() for YAML Date safety",
);
// Verify overlay source exists and imports data module
const overlayPath = join(__dirname, "..", "visualizer-overlay.ts");
const overlaySrc = readFileSync(overlayPath, "utf-8");

View file

@ -379,7 +379,7 @@ async function loadChangelog(basePath: string, milestones: VisualizerMilestone[]
path: f.path,
description: f.description,
})),
completedAt: summary.frontmatter.completed_at ?? '',
completedAt: String(summary.frontmatter.completed_at ?? ''),
};
changelogCache.set(cacheKey, { mtime, entry });
@ -388,7 +388,7 @@ async function loadChangelog(basePath: string, milestones: VisualizerMilestone[]
}
// Sort by completedAt descending
entries.sort((a, b) => (b.completedAt || '').localeCompare(a.completedAt || ''));
entries.sort((a, b) => String(b.completedAt || '').localeCompare(String(a.completedAt || '')));
return { entries };
}