a reactive (signals based) hypermedia web framework (wip) stormlightlabs.github.io/volt/
hypermedia frontend signals
at main 3.0 kB view raw
1import path from "node:path"; 2import { diffSections, extractHeadings, extractSections, hashMarkdown } from "./differ.js"; 3import type { DocMetadata } from "./storage.js"; 4import { getDocMetadata, updateDocMetadata } from "./storage.js"; 5 6/** 7 * Track version for a generated documentation file 8 * Compares with previous version, calculates diff, bumps version, adds frontmatter 9 * 10 * @param filePath Absolute path to the documentation file 11 * @param content Generated markdown content (without frontmatter) 12 * @returns Content with frontmatter prepended 13 */ 14export async function trackVersion(filePath: string, content: string): Promise<string> { 15 const docsDir = path.join(process.cwd(), "..", "docs"); 16 const relPath = path.relative(docsDir, filePath); 17 18 const prevMeta = await getDocMetadata(relPath); 19 20 const newSections = extractSections(content); 21 const newHash = hashMarkdown(content); 22 const today = new Date().toISOString().split("T")[0]; 23 24 if (!prevMeta) { 25 const initialMeta: DocMetadata = { 26 version: "1.0", 27 updated: today, 28 hash: newHash, 29 sections: extractHeadings(content), 30 history: [{ version: "1.0", date: today, hash: newHash, added: newSections.length, removed: 0, edited: 0 }], 31 }; 32 33 await updateDocMetadata(relPath, initialMeta); 34 return addFrontmatter(content, "1.0", today); 35 } 36 37 if (prevMeta.hash === newHash) { 38 return addFrontmatter(content, prevMeta.version, prevMeta.updated); 39 } 40 41 const oldSections = extractSections(prevMeta.sections.map((h) => `${h}\n\nContent`).join("\n\n")); 42 const diff = diffSections(oldSections, newSections); 43 44 const newVersion = calculateVersionBump(diff, prevMeta.version); 45 46 const newMeta: DocMetadata = { 47 version: newVersion, 48 updated: today, 49 hash: newHash, 50 sections: extractHeadings(content), 51 history: [...prevMeta.history, { 52 version: newVersion, 53 date: today, 54 hash: newHash, 55 added: diff.added, 56 removed: diff.removed, 57 edited: diff.edited, 58 }], 59 }; 60 61 await updateDocMetadata(relPath, newMeta); 62 return addFrontmatter(content, newVersion, today); 63} 64 65/** 66 * Calculate version bump based on diff 67 * 68 * Rules: 69 * - Any sections removed → Major bump 70 * - Any sections added → Major bump 71 * - ≥4 sections edited → Major bump 72 * - 1-3 sections edited → Minor bump 73 * - No changes → No bump 74 */ 75function calculateVersionBump(diff: { added: number; removed: number; edited: number }, current: string): string { 76 const [major, minor] = current.split(".").map(Number); 77 78 if (diff.removed > 0) { 79 return `${major + 1}.0`; 80 } 81 82 if (diff.added > 0) { 83 return `${major + 1}.0`; 84 } 85 86 if (diff.edited >= 4) { 87 return `${major + 1}.0`; 88 } 89 90 if (diff.edited > 0) { 91 return `${major}.${minor + 1}`; 92 } 93 94 return current; 95} 96 97/** 98 * Add frontmatter to markdown content 99 */ 100function addFrontmatter(content: string, version: string, date: string): string { 101 return `--- 102version: ${version} 103updated: ${date} 104--- 105 106${content}`; 107}