#!/usr/bin/env node import { mkdir, readFile, writeFile } from 'node:fs/promises'; import { dirname } from 'node:path'; import { convertCourseSource } from './lib/previous-wiki.mjs'; const recoveryLines = (await readFile('docs/live-course-recovery.tsv', 'utf8')).trim().split(/\r?\n/); const recoveryHeader = recoveryLines.shift(); const records = recoveryLines.map((line) => { const [id, sourceUrl, status, destination, capturedSource, reason] = line.split('\t'); return { id, sourceUrl, status, destination, capturedSource, reason }; }); const pdfs = (await readFile('docs/pdf-inventory.tsv', 'utf8')).trim().split(/\r?\n/).slice(1) .map((line) => { const [mediaId, publicUrl] = line.split('\t'); return { mediaId, publicUrl }; }); const toPublish = records.filter(({ status }) => status === 'migrate'); if (toPublish.length !== 54) throw new Error(`expected 54 course pages to publish, found ${toPublish.length}`); for (const record of toPublish) { const source = await readFile(record.capturedSource, 'utf8'); const markdown = convertCourseSource({ pageId: record.id, sourceUrl: record.sourceUrl, source, pdfs, }); await mkdir(dirname(record.destination), { recursive: true }); await writeFile(record.destination, markdown); } const supplemental = JSON.parse(await readFile('docs/supplemental-content.json', 'utf8')) .filter(({ category }) => category !== 'live-course-recovery'); for (const record of toPublish) { supplemental.push({ destination: record.destination, source: record.sourceUrl, category: 'live-course-recovery', }); } supplemental.sort((a, b) => a.destination.localeCompare(b.destination)); await writeFile('docs/supplemental-content.json', `${JSON.stringify(supplemental, null, 2)}\n`); const groups = new Map(); for (const record of toPublish) { const slug = record.destination.replace(/^src\/content\/docs\//, '').replace(/\.md$/, ''); const [programme, year, block] = slug.split('/'); const key = `${programme}/${year}`; if (!groups.has(key)) groups.set(key, new Map()); if (!groups.get(key).has(block)) groups.get(key).set(block, []); groups.get(key).get(block).push(slug); } const sidebarLines = ['export const recoveredCourseSidebar = {']; for (const [key, blocks] of [...groups].sort(([a], [b]) => a.localeCompare(b))) { sidebarLines.push(` '${key}': [`); for (const [block, slugs] of [...blocks].sort(([a], [b]) => a.localeCompare(b))) { const blockNumber = block.replace('block-', ''); sidebarLines.push(` { label: 'Block ${blockNumber}', items: [`); for (const slug of slugs.sort()) sidebarLines.push(` { slug: '${slug}' },`); sidebarLines.push(' ] },'); } sidebarLines.push(' ],'); } sidebarLines.push('};', ''); await writeFile('src/config/recovered-course-sidebar.mjs', sidebarLines.join('\n')); for (const record of toPublish) record.status = 'migrated'; const updatedTsv = [recoveryHeader, ...records.map((record) => [ record.id, record.sourceUrl, record.status, record.destination, record.capturedSource, record.status === 'migrated' ? 'Substantive public course page migrated from the live DokuWiki.' : record.reason, ].join('\t'))].join('\n'); await writeFile('docs/live-course-recovery.tsv', `${updatedTsv}\n`); console.log(`Published ${toPublish.length} recovered course pages.`);