import { type ParsedCommitData, prCategories } from "../commit";
import { entitiesConfig } from "../intershell-config/intershell-config";
import { ChangelogTemplate } from "./template";
const DEFAULT_BADGE_COLOR = "6B7280";
const validTypes = entitiesConfig.getConfig().commit.conventional.type?.list ?? [];
export class DefaultChangelogTemplate extends ChangelogTemplate {
protected generateChangelogHeader(): string {
return [
`## Changelog (${this.packageName})`,
"",
"[](https://keepachangelog.com)",
"[](https://semver.org)",
"",
"All notable changes to this project will be documented in this file.",
"The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),",
"and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).",
"",
].join("\n");
}
protected generateChangelogVersionHeader(version: string): string {
return ["", `## ${version === "[Unreleased]" ? "" : this.prefix}${version}`, ""].join("\n");
}
protected generateCommitSection(commit: ParsedCommitData, repoUrl: string): string {
if (commit.pr?.prNumber) {
return this.generatePrSection(commit, commit.pr.prCommits || [commit], repoUrl);
}
return `###### ${this.generateCommitLine(commit, repoUrl)}`;
}
private generatePrSection(
mainCommit: ParsedCommitData,
allCommits: ParsedCommitData[],
repoUrl: string,
): string {
const { pr: { prNumber, prCategory = "other", prBranchName } = {} } = mainCommit;
const commitCount = allCommits.length;
const categoryEmoji = prCategories[prCategory]?.emoji;
const categoryTitle = prCategories[prCategory]?.label;
const prCategoryBadge = `
`;
const prNumberBadge =
!!prNumber &&
`
`;
const commitCountBadge = `
`;
const prNumberLink =
!!prNumberBadge && `${prNumberBadge}`;
const prMessages = mainCommit.message.isMerge
? [
// mainCommit.message.bodyLines[0], // We don't want the first line: "Merge pull request #154 from feature/custom-version-management"
// "", // Empty line for separation, if you added the first line above, uncomment this line as well
...mainCommit.message.bodyLines.slice(1), // Rest of the lines: "Refactors the version management system..."
]
: [mainCommit.message.description, "", ...mainCommit.message.bodyLines];
return [
// Format: emoji branch-name category-title #PR-number commit-count
// Example: 🔄 refactor/test-versioning Code Quality & Refactoring #144 9 commits
"",
`### ${categoryEmoji} ${typeof prBranchName === "object" && prBranchName?.name ? prBranchName.name : typeof prBranchName === "string" ? prBranchName : "unknown-branch"} ${prCategoryBadge} ${prNumberLink} ${commitCountBadge}`,
"",
...prMessages,
"",
"📝 Commits (Click to expand)
",
"",
...allCommits.map((commit) => `- ${this.generateCommitLine(commit, repoUrl)}`),
"",
" ",
"",
].join("\n");
}
private generateCommitLine(commit: ParsedCommitData, repoUrl: string): string {
const {
info: { hash, author = "Unknown" } = {},
message: { type, description, scopes = [] },
} = commit;
const hashKey = hash?.substring(0, 7) || "unknown";
const hashUrl = hash ? `${repoUrl}/commit/${hash}` : undefined;
const scopeSection =
scopes && scopes.length > 0
? scopes.map((s: string) => s.toLowerCase().replace("-", "%20")).join(",")
: "";
const badgeText = `${type}-(${scopeSection || "noscope"})`;
const badgeColor = validTypes.find((t) => t.type === type)?.badgeColor || DEFAULT_BADGE_COLOR;
const badge = `
`;
const badgeUrl = hashUrl ? `${badge}` : badge;
const hashLink = hashUrl ? `([${hashKey}](${hashUrl}))` : `[${hashKey}]`;
return [
badgeUrl,
description,
hashLink,
author && (author.includes("@") ? `by [${author}](mailto:${author})` : `by **${author}**`),
]
.filter(Boolean)
.join(" ")
.trim();
}
}