import { Category, Commit, FixUpInfo, Ignored, Parser, SubCategory, } from "#types/changelogTypes.ts"; import { categories, combineKey, defaultIndentation, detailsKey, expandKey, ignoreKey, modInfoKey, noCategoryKey, priorityKey, } from "./definitions.ts"; import { parseCombine, parseDetails, parseExpand, parseIgnore, parseModInfo, parsePriority, } from "./specialParser.ts"; import { getChangelog } from "#utils/util.ts"; import ChangelogData from "./changelogData.ts"; export default async function parseParser( data: ChangelogData, parser: Parser, ): Promise { const commits = await getChangelog(data.since, data.to, parser.dirs); for (const commit of commits) { if (data.shaList.has(commit.hash)) continue; let savedFix: FixUpInfo | undefined = undefined; if (data.commitFixes.has(commit.hash)) { const fixUpInfo = data.commitFixes.get(commit.hash); if (fixUpInfo) { if (!parser.applyFixCalback || parser.applyFixCalback(fixUpInfo)) { applyFix(commit, fixUpInfo); } else { savedFix = fixUpInfo; } } } if (parser.skipCallback(commit, commit.message, commit.body)) { if (!parser.addSHACallback || parser.addSHACallback(commit, true)) data.shaList.add(commit.hash); continue; } const parsed = await parser.itemCallback( parser, commit, commit.message, commit.body, savedFix, ); if (parsed instanceof Ignored) { if (parsed.getCommitList() && parser.addCommitListCallback) { if (parser.addCommitListCallback(commit, true)) data.commitList.push(commit); } continue; } if (!parsed && parser.leftOverCallback) parser.leftOverCallback(commit, commit.message, commit.body, []); if (!parser.addSHACallback || parser.addSHACallback(commit, parsed)) data.shaList.add(commit.hash); if (parser.addCommitListCallback(commit, parsed)) data.commitList.push(commit); } } function applyFix(commit: Commit, fix: FixUpInfo) { if (fix.newTitle) commit.message = fix.newTitle; if (fix.newBody) { switch (fix.mode) { case "REPLACE": commit.body = fix.newBody; break; case "ADDITION": commit.body = commit.body.concat(`\n\n${fix.newBody}`); break; } } } /** * Parses a commit body. * @param commitMessage The commit message to put into the changelog. * @param commitBody The commit body to parse with. * @param commitObject The commit object. * @param parser The parser object to use for parse expand/details. * @return parsed Returns true if contains parsing keys, false if not. */ export async function parseCommitBody( commitMessage: string, commitBody: string, commitObject: Commit, parser: Parser, ): Promise { if (commitBody.includes(expandKey)) { await parseExpand(commitBody, commitObject, parser); return true; } if (commitBody.includes(ignoreKey)) { const ignore = await parseIgnore(commitBody, commitObject); // Only return if ignore is not undefined if (ignore) return ignore; } let newPriority = 0; if (commitBody.includes(priorityKey)) { const priority = await parsePriority(commitBody, commitObject); // Only set if priority is not undefined or 0 if (priority) newPriority = priority; } // Copy commit if new priority (don't mess it up for other changelog messages when using expand) if (commitObject.priority !== newPriority) { commitObject = { ...commitObject }; commitObject.priority = newPriority; } if (commitBody.includes(modInfoKey)) await parseModInfo(commitBody, commitObject); if (commitBody.includes(detailsKey)) { await parseDetails(commitMessage, commitBody, commitObject, parser); return true; } if (commitBody.includes(noCategoryKey)) { return true; } if (commitBody.includes(combineKey)) { await parseCombine(commitBody, commitObject); return true; } return sortCommit(commitMessage, commitBody, commitObject); } /** * Adds the (commit) message to its correct category. Does not parse special effect tags. * @param message The message to add * @param commitBody The body to use to sort * @param commit The commit object to grab date, author and SHA from * @param indentation The indentation of the message, if needed. Defaults to "". * @return added If the commit message was added to a category */ function sortCommit( message: string, commitBody: string, commit: Commit, indentation = defaultIndentation, ): boolean { const sortedCategories: Category[] = findCategories(commitBody); if (sortedCategories.length === 0) return false; sortedCategories.forEach((category) => { const subCategory = findSubCategory(commitBody, category); category.changelogSection?.get(subCategory)?.push({ commitMessage: message, commitObject: commit, indentation: indentation, }); }); return true; } /** * Finds the categories that a commit fits in. * @param commitBody The commit body to sort with * @return categoryList The categories that the commit belongs in. Return undefined if no category specified via keys. */ export function findCategories(commitBody: string): Category[] { const sortedCategories: Category[] = []; for (const category of categories) { if (category.commitKey !== undefined) { if (commitBody.includes(category.commitKey)) { sortedCategories.push(category); } } } return sortedCategories; } /** * Finds the correct Sub Category a commit should go in. Must be given the Category first! */ export function findSubCategory( commitBody: string, category: Category, ): SubCategory { for (const subCategory of category.subCategories) { if (subCategory.commitKey !== undefined) { if (commitBody.includes(subCategory.commitKey)) { return subCategory; } } } return category.defaultSubCategory; }