Files
lab-rv32i-asm-control-flow/scripts/export_lesson_report.mjs
T

108 lines
4.1 KiB
JavaScript

import { mkdir, writeFile } from 'node:fs/promises';
import { spawn } from 'node:child_process';
import path from 'node:path';
import {
catalogFromCard,
normaliseProgress,
readJson,
statusLabel,
teamsMarkdown
} from './lib/card_progress.mjs';
const root = path.resolve(process.cwd());
const card = await readJson(path.join(root, 'json/card_source.json'));
const progressFile = path.resolve(process.env.CARD_PROGRESS_FILE ?? path.join(root, 'json/lesson_progress.json'));
let savedProgress;
try {
savedProgress = await readJson(progressFile);
} catch (error) {
if (error.code !== 'ENOENT') throw error;
savedProgress = {};
}
const progress = normaliseProgress(card, savedProgress, {
repository: process.env.CARD_SOURCE_REPOSITORY,
revision: process.env.CARD_SOURCE_REVISION
});
const reportDir = path.join(root, 'doc/session-reports');
const basename = `${card.card.id}-${progress.session.id}`;
const markdownFile = path.join(reportDir, `${basename}.md`);
const texFile = path.join(reportDir, `${basename}.tex`);
const pdfFile = path.join(reportDir, `${basename}.pdf`);
function tex(value) {
return String(value ?? '')
.replaceAll('\\', '\\textbackslash{}')
.replaceAll('&', '\\&').replaceAll('%', '\\%').replaceAll('$', '\\$')
.replaceAll('#', '\\#').replaceAll('_', '\\_').replaceAll('{', '\\{')
.replaceAll('}', '\\}').replaceAll('~', '\\textasciitilde{}')
.replaceAll('^', '\\textasciicircum{}');
}
function reportTex() {
const catalog = catalogFromCard(card);
const rows = catalog.map(item => {
const current = progress.items[item.id];
return `${tex(item.id)} & ${tex(statusLabel[current.status])} & ${tex(current.updated_at || '—')} & ${tex(item.title)} \\\\ \\hline`;
}).join('\n');
const events = progress.events.length
? progress.events.map(event => `${tex(event.at)} & ${tex(event.item_id)} & ${tex(`${statusLabel[event.from]}${statusLabel[event.to]}`)} & ${tex(event.note || '—')} \\\\ \\hline`).join('\n')
: `— & — & Brak zmian & — \\\\ \\hline`;
return `\\documentclass[11pt,a4paper]{article}
\\usepackage[utf8]{inputenc}
\\usepackage[T1]{fontenc}
\\usepackage[polish]{babel}
\\usepackage[margin=18mm]{geometry}
\\usepackage{longtable}
\\usepackage{array}
\\usepackage{booktabs}
\\begin{document}
\\section*{${tex(card.card.title)} — zapis zajęć}
\\begin{tabular}{ll}
Karta & ${tex(card.card.id)} (${tex(card.card.version)}) \\\\
Materiały & ${tex(progress.card.repository || 'nieuzupełniono')} \\\\
Rewizja & ${tex(progress.card.revision || 'nieuzupełniono')} \\\\
Sesja & ${tex(progress.session.id)} \\\\
Prowadzący & ${tex(progress.session.teacher || 'nieuzupełniono')} \\\\
Rozpoczęcie & ${tex(progress.session.started_at || 'brak')} \\\\
\\end{tabular}
\\subsection*{Zakres i status}
\\begin{longtable}{p{0.13\\textwidth}p{0.18\\textwidth}p{0.22\\textwidth}p{0.38\\textwidth}}
\\toprule Element & Status & Ostatnia zmiana & Zakres \\\\ \\midrule
${rows}
\\bottomrule
\\end{longtable}
\\subsection*{Historia zatwierdzeń}
\\begin{longtable}{p{0.22\\textwidth}p{0.13\\textwidth}p{0.25\\textwidth}p{0.30\\textwidth}}
\\toprule Czas & Element & Zmiana & Notatka \\\\ \\midrule
${events}
\\bottomrule
\\end{longtable}
\\end{document}
`;
}
function run(command, args, options) {
return new Promise((resolve, reject) => {
const child = spawn(command, args, options);
child.on('error', reject);
child.on('exit', code => code === 0 ? resolve() : reject(new Error(`${command} zakończył się kodem ${code}`)));
});
}
await mkdir(reportDir, { recursive: true });
await writeFile(markdownFile, teamsMarkdown(card, progress), 'utf8');
await writeFile(texFile, reportTex(), 'utf8');
console.log(`Markdown: ${path.relative(root, markdownFile)}`);
console.log(`TeX: ${path.relative(root, texFile)}`);
if (!process.argv.includes('--no-pdf')) {
try {
await run('latexmk', ['-pdf', '-interaction=nonstopmode', '-outdir=' + reportDir, texFile], { cwd: root, stdio: 'inherit' });
console.log(`PDF: ${path.relative(root, pdfFile)}`);
} catch (error) {
console.warn(`Nie utworzono PDF (${error.message}). Pliki Markdown i TeX są gotowe.`);
}
}