import { execSync } from "node:child_process"; import { readFileSync, writeFileSync, mkdirSync } from "node:fs"; /** * ホームページの「更新情報」をビルド時に生成する。 * * git の履歴から「新しく公開したページ」だけを拾い(--diff-filter=A)、 * そのページのフロントマターの title と URL を組みにして src/data/updates.json に書き出す。 * 加筆や内部の修正は拾わないので、一覧が作業ログで埋まらない。 * * 生成結果はコミットしておく(git の履歴がない環境でもビルドできるように)。 */ export default function updatesIntegration() { return { name: "build-updates", hooks: { "astro:config:setup": () => { const items: { date: string; title: string; url: string; group: string }[] = []; try { const out = execSync( 'git log --diff-filter=A --name-only --date=short --format="%x01%ad" -- src/content/docs', { encoding: "utf-8", maxBuffer: 64 * 1024 * 1024 }, ); // 新しく追加されたファイル → そのコミットの日付(git log は新しい順なので最初の出現が追加時) const added = new Map(); let date = ""; for (const line of out.split("\n")) { if (line.startsWith("\u0001")) { date = line.slice(1).trim(); continue; } const file = line.trim(); if (!file.endsWith(".mdx") || file.endsWith("/index.mdx")) continue; if (!added.has(file)) added.set(file, date); } const reiwa = (dir: string) => { const n = Number(dir.replace(/^r(\d+)d$/, "$1")); return n === 1 ? "令和元年" : `令和${n}年`; }; for (const [file, d] of added) { try { const src = readFileSync(file, "utf-8"); // 下書き(draft: true)は本番に出ないので除外する const fm = src.match(/^---\r?\n([\s\S]*?)\r?\n---/); if (fm && /^draft:\s*true\s*$/m.test(fm[1])) continue; const m = src.match(/^title:\s*"?(.+?)"?\s*$/m); if (!m) continue; const slug = file .replace(/^src\/content\/docs\//, "") .replace(/\.mdx$/, ""); const url = `/${slug}/`; let group = ""; const mm = slug.match(/^ippan-situmon\/(r\d+d)\/(\d+)gatu\//); if (mm) group = `${reiwa(mm[1])}${mm[2]}月定例会`; items.push({ date: d, title: m[1], url, group }); } catch { // 追加後に改名・削除されたファイルは飛ばす } } items.sort((a, b) => b.date.localeCompare(a.date)); } catch (e) { console.warn("[updates] git から取得できませんでした:", (e as Error).message); } try { mkdirSync("src/data", { recursive: true }); writeFileSync( "src/data/updates.json", JSON.stringify(items.slice(0, 40), null, 2) + "\n", ); console.log(`[updates] ${items.length}件のうち直近${Math.min(items.length, 40)}件を書き出しました`); } catch (e) { console.warn("[updates] 書き出しに失敗しました:", (e as Error).message); } }, }, }; }