#!/usr/bin/env node import { readFile, writeFile } from 'node:fs/promises'; function label(value) { return value .replace(/\.pdf$/i, '') .replaceAll('_', ' ') .replace(/\b\w/g, (character) => character.toUpperCase()); } export function renderPdfArchive(tsv) { const rows = tsv.trim().split(/\r?\n/).slice(1).map((line) => { const [mediaId, publicUrl] = line.split('\t'); const parts = mediaId.split(':'); return { publicUrl, directories: parts.slice(1, -1), filename: parts.at(-1) }; }); const lines = [ '---', 'title: Previous exams and documents', 'description: Permission-cleared exams, summaries, notes, and other course documents recovered from the previous Incognito wiki.', '---', '', 'This archive contains 332 documents recovered from the previous Incognito wiki. The original folders and filenames are preserved so their course context remains visible.', '', ':::caution[Historical documents]', 'These files originated in the previous wiki and may refer to older course structures, learning objectives, or examination formats. Check current course information before relying on them.', ':::', '', ]; let previous = []; for (const row of rows) { const shared = row.directories.findIndex((part, index) => previous[index] !== part); const start = shared === -1 ? Math.min(previous.length, row.directories.length) : shared; for (let index = start; index < row.directories.length; index += 1) { lines.push(`${'#'.repeat(Math.min(index + 2, 6))} ${label(row.directories[index])}`, ''); } lines.push(`- [${label(row.filename)}](${row.publicUrl})`, ''); previous = row.directories; } return `${lines.join('\n').trim()}\n`; } if (process.argv[1]?.endsWith('generate-pdf-archive.mjs')) { const output = renderPdfArchive(await readFile('docs/pdf-inventory.tsv', 'utf8')); await writeFile('src/content/docs/previous-exams-and-documents.md', output); }