UNPKG

keep-a-changelog

Version:

Parse and generate changelogs following the [keepachangelog](https://keepachangelog.com/) format.

198 lines (197 loc) 5.75 kB
import { compare, parse } from "./deps.js"; import Change from "./Change.js"; export default class Release { changelog; parsedVersion; date; yanked = false; description; changes; constructor(version, date, description = "") { this.setVersion(version); this.setDate(date); this.description = description; this.changes = new Map([ ["added", []], ["changed", []], ["deprecated", []], ["removed", []], ["fixed", []], ["security", []], ]); } get version() { return this.parsedVersion?.format(); } compare(release) { if (!this.parsedVersion && release.parsedVersion) { return -1; } if (!release.parsedVersion) { return 1; } if (!this.date && release.date) { return -1; } if (!release.date) { return 1; } if (this.parsedVersion && release.parsedVersion) { return -compare(this.parsedVersion, release.parsedVersion); } return 0; } combineChanges(changes) { changes.forEach((changes, type) => { if (!this.changes.has(type)) { this.changes.set(type, []); } this.changes.get(type).push(...changes); }); return this; } isEmpty() { if (this.description.trim()) { return false; } return Array.from(this.changes.values()).every((change) => !change.length); } setVersion(version) { const parsed = typeof version === "string" ? parse(version) : version; this.parsedVersion = parsed; //Re-sort the releases of the parent changelog if (this.changelog && this.changelog.autoSortReleases) { this.changelog.sortReleases(); } } setDate(date) { if (typeof date === "string") { date = new Date(date); } this.date = date; } setYanked(yanked = true) { this.yanked = yanked; return this; } addChange(type, change) { if (!(change instanceof Change)) { change = new Change(change); } if (!this.changes.has(type)) { throw new Error("Invalid change type"); } this.changes.get(type).push(change); return this; } added(change) { return this.addChange("added", change); } changed(change) { return this.addChange("changed", change); } deprecated(change) { return this.addChange("deprecated", change); } removed(change) { return this.addChange("removed", change); } fixed(change) { return this.addChange("fixed", change); } security(change) { return this.addChange("security", change); } toString(changelog) { let t = []; const hasCompareLink = this.getCompareLink(changelog) !== undefined; const yanked = this.yanked ? " [YANKED]" : ""; const { version } = this; if (version) { if (hasCompareLink) { t.push(`## [${version}] - ${formatDate(this.date)}${yanked}`); } else { t.push(`## ${version} - ${formatDate(this.date)}${yanked}`); } } else { if (hasCompareLink) { t.push(`## [Unreleased]${yanked}`); } else { t.push(`## Unreleased${yanked}`); } } if (changelog?.format === "markdownlint") { t.push(""); } if (this.description.trim()) { t.push(this.description.trim()); t.push(""); } this.changes.forEach((changes, type) => { if (changes.length) { t.push(`### ${type[0].toUpperCase()}${type.substring(1)}`); if (changelog?.format === "markdownlint") { t.push(""); } t = t.concat(changes.map((change) => change.toString(changelog?.bulletStyle))); t.push(""); } }); return t.join("\n").trim(); } getCompareLink(changelog) { if (!changelog?.url) { return; } const index = changelog.releases.indexOf(this); if (index === -1) { return; } let offset = 1; let previous = changelog.releases[index + offset]; while (previous && !previous.date) { ++offset; previous = changelog.releases[index + offset]; } if (!previous && (!this.version || !this.date)) { return; } const compareLink = changelog.compareLink(previous, this); if (!compareLink) { return; } return `[${this.version || "Unreleased"}]: ${compareLink}`; } getLinks(changelog) { const links = []; if (!changelog.url) { return links; } this.changes.forEach((changes) => changes.forEach((change) => { change.issues.forEach((issue) => { if (!links.includes(issue)) { links.push(`[#${issue}]: ${changelog.url}/issues/${issue}`); } }); })); return links; } } function formatDate(date) { if (!date) { return "Unreleased"; } const year = date.getUTCFullYear(); let month = date.getUTCMonth() + 1; let day = date.getUTCDate(); if (month < 10) { month = "0" + month; } if (day < 10) { day = "0" + day; } return `${year}-${month}-${day}`; }