UNPKG

@withstudiocms/internal_helpers

Version:

Internal helper utilities for StudioCMS

110 lines (109 loc) 3.82 kB
import fs from "node:fs"; import { fromMarkdown } from "mdast-util-from-markdown"; import { toString as ToString } from "mdast-util-to-string"; import { visit } from "unist-util-visit"; const semverCategories = ["major", "minor", "patch"]; function loadChangelog(src) { let markdown; if ("path" in src) { markdown = fs.readFileSync(src.path, "utf8"); } else { markdown = src.raw; } markdown = markdown.replace( /(?<=Thank[^.!]*? )@([a-z0-9-]+)(?=[\s,.!])/gi, "[@$1](https://github.com/$1)" ); const ast = fromMarkdown(markdown); const changelog = { packageName: "", versions: [] }; let state = "packageName"; let version; let semverCategory; function handleNode(node) { if (node.type === "heading") { if (node.depth === 1) { if (state !== "packageName") throw new Error("Unexpected h1"); changelog.packageName = ToString(node); state = "version"; return; } if (node.depth === 2) { if (state === "packageName") throw new Error("Unexpected h2"); version = { version: ToString(node), changes: { major: { type: "list", children: [] }, minor: { type: "list", children: [] }, patch: { type: "list", children: [] } }, includes: /* @__PURE__ */ new Set() }; changelog.versions.push(version); state = "semverCategory"; return; } if (node.depth === 3) { if (state === "packageName" || state === "version") throw new Error("Unexpected h3"); semverCategory = (ToString(node).split(" ")[0] || "").toLowerCase(); if (!semverCategories.includes(semverCategory)) throw new Error(`Unexpected semver category: ${semverCategory}`); state = "changes"; return; } } if (node.type === "list") { if (state !== "changes" || !version || !semverCategory) throw new Error("Unexpected list"); for (let listItemIdx = 0; listItemIdx < node.children.length; listItemIdx++) { const listItem = node.children[listItemIdx]; if (!listItem) continue; const lastChild = listItem.children[listItem.children.length - 1]; if (lastChild?.type === "list") { const packageRefs = []; lastChild.children.forEach((subListItem) => { const text = ToString(subListItem); if (parsePackageReference(text)) packageRefs.push(text); }); if (packageRefs.length === lastChild.children.length) { for (const packageRef of packageRefs) { version.includes.add(packageRef); } listItem.children.pop(); } } const firstPara = listItem.children[0]?.type === "paragraph" ? listItem.children[0] : void 0; if (firstPara) { visit(firstPara, "text", (textNode) => { textNode.value = textNode.value.replace(/(^[0-9a-f]{7,}: | \[[0-9a-f]{7,}\]$)/, ""); }); const firstParaText = ToString(firstPara); if (firstParaText === "Updated dependencies") continue; const packageRef = parsePackageReference(firstParaText); if (packageRef) { version.includes.add(firstParaText); continue; } version.changes[semverCategory].children.push(listItem); } } return; } throw new Error(`Unexpected node: ${JSON.stringify(node)}`); } ast.children.forEach((node) => { handleNode(node); }); return changelog; } function parsePackageReference(str) { const matches = str.match(/^([@/a-z0-9-]+)@([0-9.]+)$/); if (!matches) return; const [, packageName, version] = matches; return { packageName, version }; } export { loadChangelog, semverCategories };