Files
aragrp/lib/changelog-types.ts
alirez.brandCursor a47ec493c5 feat: add version history drawer with release notes
Introduce a footer-triggered Version History drawer with categorized release notes, hardcoded release data, and semver tracking at v0.3.0. Also ships blog blockquote/table styling, site-wide typography, home page image updates, header refinements, and related bug fixes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 02:46:20 +03:30

84 lines
2.0 KiB
TypeScript

const SECTION_HEADINGS = [
"Added",
"Changed",
"Fixed",
"Removed",
"Deprecated",
"Security",
] as const;
export type ChangelogSectionTitle = (typeof SECTION_HEADINGS)[number];
export type ChangelogSection = {
title: ChangelogSectionTitle;
items: string[];
};
export type ChangelogRelease = {
version: string;
date: string;
major: number;
minor: number;
patch: number;
/** Categorized release notes. */
sections: ChangelogSection[];
/** Optional paragraph summary for major or initial releases. */
summary?: string;
};
export const CHANGELOG_SECTION_LABELS: Record<ChangelogSectionTitle, string> = {
Added: "Added",
Changed: "Improved",
Fixed: "Fixed",
Removed: "Removed",
Deprecated: "Deprecated",
Security: "Security",
};
export function parseChangelog(markdown: string): ChangelogRelease[] {
const releases: ChangelogRelease[] = [];
const lines = markdown.split("\n");
let i = 0;
while (i < lines.length) {
const versionMatch = lines[i].match(/^## \[([\d.]+)\] - (.+)$/);
if (!versionMatch) {
i++;
continue;
}
const version = versionMatch[1];
const date = versionMatch[2];
const [major = 0, minor = 0, patch = 0] = version.split(".").map(Number);
i++;
const sections: ChangelogSection[] = [];
while (i < lines.length && !lines[i].match(/^## \[/)) {
const sectionMatch = lines[i].match(/^### (.+)$/);
if (
sectionMatch &&
SECTION_HEADINGS.includes(sectionMatch[1] as ChangelogSectionTitle)
) {
const title = sectionMatch[1] as ChangelogSectionTitle;
i++;
const items: string[] = [];
while (i < lines.length && lines[i].startsWith("- ")) {
items.push(lines[i].slice(2).trim());
i++;
}
if (items.length > 0) {
sections.push({ title, items });
}
continue;
}
i++;
}
releases.push({ version, date, major, minor, patch, sections });
}
return releases;
}