108 lines
4.1 KiB
JavaScript
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.`);
|
|
}
|
|
}
|