UNPKG

keep-a-changelog

Version:

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

131 lines (129 loc) 4.13 kB
import { equals, parse } from "./deps.js"; export default class Changelog { flag; title; description; head = "HEAD"; footer; url; releases = []; tagNameBuilder; /** @deprecated: Use tagLinkBuilder() instead */ compareLinkBuilder; tagLinkBuilder; format = "compact"; bulletStyle = "-"; autoSortReleases = true; constructor(title, description = "") { this.title = title; this.description = description; } addRelease(release) { this.releases.push(release); if (this.autoSortReleases) { this.sortReleases(); } release.changelog = this; return this; } findRelease(version) { if (!version) { return this.releases.find((release) => !release.version); } const parsed = typeof version === "string" ? parse(version) : version; return this.releases.find((release) => release.parsedVersion && equals(release.parsedVersion, parsed)); } sortReleases() { this.releases.sort((a, b) => a.compare(b)); } compareLink(previous, release) { if (this.compareLinkBuilder) { return this.compareLinkBuilder(previous, release); } if (this.tagLinkBuilder) { const url = this.url; if (!previous) { return this.tagLinkBuilder(this.url, this.tagName(release), undefined, this.head); } if (!release.date || !release.version) { return this.tagLinkBuilder(url, this.head, this.tagName(previous), this.head); } return this.tagLinkBuilder(url, this.tagName(release), this.tagName(previous), this.head); } if (!previous) { return `${this.url}/releases/tag/${this.tagName(release)}`; } if (!release.date || !release.version) { return `${this.url}/compare/${this.tagName(previous)}...${this.head}`; } return `${this.url}/compare/${this.tagName(previous)}...${this.tagName(release)}`; } tagName(release) { if (this.tagNameBuilder) { return this.tagNameBuilder(release); } return `v${release.version}`; } toString() { const t = []; if (this.flag) { t.push(`<!-- ${this.flag} -->`); t.push(""); } t.push(`# ${this.title}`); if (this.format === "markdownlint") { t.push(""); } const links = []; const compareLinks = []; const description = this.description.trim() || `All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/) and this project adheres to [Semantic Versioning](https://semver.org/).`; if (description) { t.push(description); } this.releases.forEach((release) => { t.push(""); t.push(release.toString(this)); release.getLinks(this).forEach((link) => { if (!links.includes(link)) { links.push(link); } }); const compareLink = release.getCompareLink(this); if (compareLink) { compareLinks.push(compareLink); } }); if (links.length) { t.push(""); links.sort(compare); links.forEach((link) => t.push(link)); } if (compareLinks.length) { t.push(""); compareLinks.forEach((link) => t.push(link)); } t.push(""); if (this.footer) { t.push("---"); t.push(""); t.push(this.footer); t.push(""); } return t.join("\n"); } } function compare(a, b) { if (a === b) { return 0; } const reg = /^\[#(\d+)\]:/; const aNumber = a.match(reg); const bNumber = b.match(reg); if (aNumber && bNumber) { return parseInt(aNumber[1]) - parseInt(bNumber[1]); } return a < b ? -1 : 1; }