UNPKG

@r4lrgx/gitmoji

Version:

🧱 My customized Gitmoji Config - a fork of https://github.com/arvinxx/gitmoji-commit-workflow - just with several bug fixes and a cleaner look.

380 lines (372 loc) • 11.4 kB
import { readFileSync } from 'fs'; import { sep } from 'path'; import { fileURLToPath } from 'url'; import _ from 'lodash'; import pangu from 'pangu'; import fetch from 'sync-fetch'; // @r4lrgx/gitmoji v1.0.3 // MIT License // src/changelog-config/handlers/displayScopeMap.ts var displayScopeMap = (scope, customScopeMap) => { if (!scope || !customScopeMap) return scope; const custom = customScopeMap[scope]; if (custom) return custom; const all = customScopeMap["*"]; if (all) { return all.replace(/\*/g, scope); } return scope; }; var { merge } = _; var commitTypeMap = { feat: { emoji: "\u2728", title: "Features", subtitle: "New features and enhancements" }, fix: { emoji: "\u{1F41B}", title: "Bug Fixes", subtitle: "Resolved bugs and issues" }, perf: { emoji: "\u26A1", title: "Performance Improvements", subtitle: "Faster, leaner, better" }, refactor: { emoji: "\u267B", title: "Code Refactoring", subtitle: "Code structure improvements" }, chore: { emoji: "\u{1F527}", title: "Chores", subtitle: "Other tasks and maintenance" }, docs: { emoji: "\u{1F4DD}", title: "Documentation", subtitle: "Docs updates and improvements" }, build: { emoji: "\u{1F4E6}\uFE0F", title: "Build System", subtitle: "Changes to build tools and processes" }, ci: { emoji: "\u{1F477}", title: "Continuous Integration", subtitle: "CI config updates and automation" }, test: { emoji: "\u2705", title: "Tests", subtitle: "Added or updated tests" }, style: { emoji: "\u{1F3A8}", title: "Styles", subtitle: "Visual tweaks and formatting" }, wip: { emoji: "\u{1F691}\uFE0F", title: "Cleaning", subtitle: "Work in progress or cleanup" }, revert: { emoji: "\u23EA", title: "Reverts", subtitle: "Undone changes and rollbacks" } }; var defineCommitTypeMap = (customCommitTypeMap) => { if (!customCommitTypeMap) return commitTypeMap; return merge(customCommitTypeMap, commitTypeMap); }; var displayCommitType = (commitType, config) => { const { withEmoji = true, customCommitTypeMap = void 0 } = config; const diplayCommitTypeMap = defineCommitTypeMap(customCommitTypeMap); if (commitType in diplayCommitTypeMap) { const item = diplayCommitTypeMap[commitType]; const { emoji, title } = item; return `${withEmoji ? `${emoji} ` : ""}${title}`; } return commitType; }; function gitHubLookup(email) { const match = email.match(/^(\d*)\+?([a-zA-Z0-9\-]*)@users\.noreply\.github\.com$/); let info = null; if (match) { const [_3, id, username] = match; info = { id, username }; } else { try { const res = fetch(`https://api.github.com/search/commits?q=author-email:${encodeURIComponent(email)}`, { headers: { Accept: "application/vnd.github.cloak-preview+json" } }); if (!res.ok) return null; const data = res.json(); if (data.items && data.items.length > 0) { const username = data.items[0]?.author?.login; const id = data.items[0]?.author?.id; if (id && username) info = { id, username }; } } catch (_err) { return null; } } if (!info?.id || !info?.username) return null; try { const res = fetch(`https://api.github.com/users/${info.username}`, { headers: { Accept: "application/vnd.github.cloak-preview+json" } }); if (!res.ok) return null; const user = res.json(); return { authorName: info.username, authorAvatar: user.avatar_url, authorUrl: user.html_url, authorEmail: `${info.id}+${info.username}@users.noreply.github.com` }; } catch (_err) { return null; } } // src/commit-types/index.ts var commitTypes = [ // prettier "feat", "fix", "perf", "refactor", "chore", "docs", "build", "ci", "test", "style", "wip", "revert" ]; var commit_types_default = commitTypes; // src/changelog-config/handlers/transformer.ts var { cloneDeep } = _; var users = /* @__PURE__ */ new Map(); var capitalize = (str) => { if (!str?.length) return str; return str.replace(/([a-zA-Z])/u, (firs) => firs.toUpperCase()); }; var transformer = (config) => ( /** * Processes a single commit * @param {Commit} commit - The commit object to transform * @param {Context} context - The context object containing repository info * @returns {Commit | void} The transformed commit or undefined if excluded */ (commit, context) => { commit = cloneDeep(commit); const issues = []; let exclude = true; commit.notes.forEach((note) => { note.title = `${config.withEmoji === false ? "" : "\u{1F4A5}"} BREAKING CHANGES`; exclude = false; }); const { displayCommitTypes = commit_types_default } = config; if (!displayCommitTypes.includes(commit.type) && exclude || !commit.type) return; commit.type = displayCommitType(commit.type, config); if (commit.scope) { if (commit.scope === "*") { commit.scope = ""; } if (config.displayScopes) { if (!config.displayScopes.includes(commit.scope)) return; } if (config.customScopeMap) { commit.scope = displayScopeMap(commit.scope, config.customScopeMap); } commit.scope = capitalize(commit.scope); } if (commit.hash) { commit.hash = commit.hash.substring(0, 7); } if (commit.subject && typeof commit.subject === "string") { let repository = context.repository ? `${context.host}/${context.owner}/${context.repository}` : context.repoUrl; if (repository) { repository = `${repository}/issues/`; commit.subject = commit.subject.replace(/#([0-9]+)/g, (_3, issue) => { issues.push({ issue }); return `[#${issue}](${repository}${issue})`; }); } if (commit.host && typeof commit.host === "string") { commit.subject = commit.subject.replace(/\B@([a-z0-9](?:-?[a-z0-9/]){0,38})/g, (_3, username) => { if (username.includes("/")) { return `@${username}`; } return `[@${username}](${context.host}/${username})`; }); } } commit.references = commit.references.filter((reference) => { const values = new Set(issues.map((item) => item.issue)); return !values.has(reference.issue); }); if (commit.subject) { commit.rawSubject = commit.subject; commit.subject = pangu.spacing(capitalize(commit.subject)); } const authorEmail = commit.author.email; if (config.showAuthor || config.showAuthorAvatar) { if (!users.has(authorEmail)) { try { const author2 = gitHubLookup(authorEmail); users.set(authorEmail, author2); } catch (_e) { users.set(authorEmail, null); } } const author = users.get(authorEmail); Object.assign(commit, author); } return commit; } ); // src/changelog-config/context/index.ts var users2 = /* @__PURE__ */ new Map(); var finalizeContext = (config) => ( /** * Processes the changelog context * @param {Context} context - The changelog context to enhance * @returns {Context} The enhanced context or undefined if invalid */ (context) => { const subCommitScope = (config.customScopeMap && config.customScopeMap["*"]) ?? null; const commitTypeMap2 = defineCommitTypeMap(config.customCommitTypeMap); context.commitGroups = context.commitGroups?.map((item) => { const { subtitle } = Object.values(commitTypeMap2).find(({ emoji }) => item.title.includes(emoji)); let group; let commits = item.commits.sort((a, b) => { if (a.scope === subCommitScope && b.scope === subCommitScope) { return 0; } else if (a.scope === subCommitScope) { return 1; } else if (b.scope === subCommitScope) { return -1; } else { return 0; } }); commits = commits.map((commit, index) => { if (commit.scope) { if (group !== commit.scope) { group = commit.scope; commit.first = true; } else { commit.first = false; } } if (!commits[index + 1] || group !== commits[index + 1].scope) { commit.last = true; } else { commit.last = false; } const { email } = commit.author; if (config.showAuthor || config.showAuthorAvatar) { if (!users2.has(email)) { try { const author = gitHubLookup(email); users2.set(email, author); } catch (_e) { users2.set(email, null); } } } return commit; }); return { title: item.title, subtitle, commits }; }); context.authors = Array.from(users2.values()); return context; } ); // src/changelog-config/writer.ts var dirname = fileURLToPath(new URL(".", import.meta.url)); var reduceHeadingLevel = (skip, template) => { if (skip) return template; return template.replace(/(^|\n)(#{1,5})(?=\s)/g, (_match, prefix, hashes) => { return `${prefix}${hashes}#`; }); }; var readTemplate = (name) => { return readFileSync(`${dirname}${sep}templates${sep}${name}.hbs`, "utf-8"); }; function createGitmojiWriterOpts(config) { const [ // prettier authorAvatar, author, backToTop, commit, footer, headerNewlineTimestamp, header, summaryAvatar, summaryTemplate, template ] = [ // prettier readTemplate("author-avatar"), readTemplate("author"), readTemplate("back-to-top"), readTemplate("commit"), readTemplate("footer"), readTemplate("header-newline-timestamp"), readTemplate("header"), readTemplate("summary-avatar"), readTemplate("summary-template"), readTemplate("template") ]; const shouldReduce = !config.reduceHeadingLevel; const mainTemplate = () => { if (!config.showSummary) return template; if (config.showAuthor && config.showAuthorAvatar) return summaryTemplate.replace(/{{gitUserInfo}}/g, summaryAvatar); return summaryTemplate.replace(/{{gitUserInfo}}/g, ""); }; const headerPartial = () => { if (!config.newlineTimestamp) return header; return headerNewlineTimestamp; }; const commitPartial = () => { let gitUserInfo = ""; if (config.showAuthor) gitUserInfo = config.showAuthorAvatar ? authorAvatar : author; return commit.replace(/{{gitUserInfo}}/g, gitUserInfo); }; const footerPartial = () => { if (config.addBackToTop) return footer.replace(/{{backToTop}}/g, backToTop); return footer.replace(/{{backToTop}}/g, ""); }; return { transform: transformer(config), groupBy: "type", commitGroupsSort: "title", commitsSort: ["scope", "subject"], noteGroupsSort: "title", mainTemplate: reduceHeadingLevel(shouldReduce, mainTemplate()), headerPartial: reduceHeadingLevel(shouldReduce, headerPartial()), commitPartial: reduceHeadingLevel(shouldReduce, commitPartial()), footerPartial: reduceHeadingLevel(shouldReduce, footerPartial()), finalizeContext: finalizeContext(config) }; } export { createGitmojiWriterOpts as default }; //# sourceMappingURL=writer.js.map //# sourceMappingURL=writer.js.map