Files
psu-schedule/scripts/snapshot-lines.js
Zakhar Timoshenko e61fbf4404 Fix formatting and correct instructor names in schedule snapshots
- Updated "Ф и з и ч е с к а я к у л ь т у р а" to "Физическая культура" in fkne-daily.txt
- Corrected instructor name for "Лабораторный спецпрактикум: Объектно-ориентированное программирование" to "Солдатенко П.Н." in multiple entries in fkne-daily.txt
- Changed the format of room numbers in "Иностранный язык (англ.)" entry in fkne.txt to use commas for clarity
2026-10-26 22:42:32 +03:00

52 lines
2.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// One readable line per parsed lesson, the form both snapshots compare: what a student sees
// (day, time, weeks or dates, subject, kind, room, teacher, groups), not ids or source colours.
const DAYS = ["", "пн", "вт", "ср", "чт", "пт", "сб", "вс"];
const weeks = (ranges) =>
ranges?.map(([a, b]) => (b === null ? `с ${a}` : a === b ? `${a}` : `${a}-${b}`)).join(",") || "";
export const lessonLine = (l) =>
[
`${l.date || DAYS[l.day]} ${l.start}${l.end ? `–${l.end}` : ""}`,
(l.date ? "один раз" : l.dates?.length ? `даты ${l.dates.join(",")}` : l.weekRanges ? `нед. ${weeks(l.weekRanges)}` : "каждую неделю") +
(l.from ? ` с ${l.from}` : "") +
(l.variant === "upper" ? ", верхняя строка" : l.variant === "lower" ? ", нижняя строка" : ""),
l.subject,
l.type,
// The town only when the cell names one or the day's note puts the lesson there.
[l.room, l.place].filter(Boolean).join(", "),
l.teacher,
[...l.groups, ...l.subgroups.map((s) => `${s.group}/${s.label.replace("Подгруппа ", "п")}`)].join(",") +
// "Немецкий язык" or "Французский язык": a part of the group takes one of them.
(l.option ? " · на выбор" : "") +
// Russian for foreign students while the others have physical education.
(l.audience === "foreign" ? " · иностранцам" : l.audience === "local" ? " · кроме иностранцев" : ""),
]
.map((part) => String(part ?? "").replace(/\s+/g, " ").trim())
.join(" | ");
// "Занятия в Полоцке": a day of a group or subgroup in another town, not a lesson.
const placeLine = (p) =>
[
`@ ${p.date || DAYS[p.day]}${p.from ? ` с ${p.from}` : ""}`,
p.text,
[...p.groups, ...p.subgroups.map((s) => `${s.group}/${s.label.replace("Подгруппа ", "п")}`)].join(","),
].join(" | ");
/** Sorted lesson lines of a parsed document, with its groups and period on top. */
export const snapshotOf = (schedule) => [
`# ${schedule.period} · ${schedule.groups.join(", ")}`,
...(schedule.places || []).map(placeLine).sort(),
...schedule.lessons.map(lessonLine).sort(),
];
/** Lines only in `before` (removed) and only in `after` (added), duplicates counted. */
export function diffLines(before, after) {
const count = (lines) => lines.reduce((m, x) => m.set(x, (m.get(x) || 0) + 1), new Map());
const a = count(before), b = count(after);
const removed = [], added = [];
for (const [line, n] of a) for (let i = b.get(line) || 0; i < n; i++) removed.push(line);
for (const [line, n] of b) for (let i = a.get(line) || 0; i < n; i++) added.push(line);
return { removed, added };
}