1
0

refactor: Rewrite to typescript
All checks were successful
Remote Deploy / deploy (push) Successful in 14s

This commit is contained in:
2026-02-11 08:20:56 +01:00
parent 138fa17e54
commit ae17dc241a
14 changed files with 941 additions and 121 deletions

View File

@@ -17,10 +17,28 @@ const LAST_HOUR = 10;
// -------------------------------
// Helpers
// -------------------------------
export const cleanInput = (input) => (input ?? "").trim().replace(/\s+/g, " ");
export const isTeacherToken = (t) => /^[A-Za-z]+$/.test(t);
export const cleanInput = (input: string | null | undefined): string => (input ?? "").trim().replace(/\s+/g, " ");
export const isTeacherToken = (t: string): boolean => /^[A-Za-z]+$/.test(t);
export const parseSpec = (spec) => {
interface Spec {
kind: "range" | "single";
value: { from: number; to: number } | number;
}
interface TeacherMap {
[key: string]: string;
}
export interface AbsenceResult {
teacher: string | null;
teacherCode: string | null;
type: string;
hours: { from: number; to: number } | number | null;
zastupuje?: { teacher: string | null; teacherCode: string | null };
original?: string;
}
export const parseSpec = (spec: string | null): Spec | null => {
if (!spec) return null;
let m;
@@ -55,12 +73,12 @@ export const parseSpec = (spec) => {
return null;
};
export const resolveTeacher = (teacherCode, teacherMap = {}) => ({
export const resolveTeacher = (teacherCode: string, teacherMap: TeacherMap = {}): { code: string; name: string | null } => ({
code: teacherCode,
name: teacherMap?.[teacherCode.toLowerCase()] ?? null,
});
const makeResult = (teacherCode, spec, teacherMap) => {
const makeResult = (teacherCode: string, spec: Spec | null, teacherMap: TeacherMap): AbsenceResult => {
const { name } = resolveTeacher(teacherCode, teacherMap);
const type = spec ? (spec.kind === "range" ? "range" : "single") : "wholeDay";
const hours = spec ? spec.value : null;
@@ -70,8 +88,8 @@ const makeResult = (teacherCode, spec, teacherMap) => {
// -------------------------------
// Teacher list processing (modular)
// -------------------------------
const processTeacherList = (teacherListStr, spec, teacherMap) => {
let results = [];
const processTeacherList = (teacherListStr: string, spec: Spec | null, teacherMap: TeacherMap): AbsenceResult[] => {
let results: AbsenceResult[] = [];
const teachers = teacherListStr.split(/[,;]\s*/).filter(Boolean);
if (teacherListStr.includes(";")) {
@@ -89,14 +107,14 @@ const processTeacherList = (teacherListStr, spec, teacherMap) => {
// -------------------------------
// Main parser
// -------------------------------
export default function parseAbsence(input, teacherMap = {}) {
export default function parseAbsence(input: string, teacherMap: TeacherMap = {}): AbsenceResult[] {
const s = cleanInput(input);
if (!s) return [];
const results = [];
const consumed = [];
const markConsumed = (start, end) => consumed.push([start, end]);
const isConsumed = (i) => consumed.some(([a, b]) => i >= a && i < b);
const results: AbsenceResult[] = [];
const consumed: [number, number][] = [];
const markConsumed = (start: number, end: number) => consumed.push([start, end]);
const isConsumed = (i: number) => consumed.some(([a, b]) => i >= a && i < b);
// 1. Teachers with specific hours (e.g. "Ab 1-4")
const teacherListThenSpecRe =
@@ -175,6 +193,7 @@ export default function parseAbsence(input, teacherMap = {}) {
teacher: missingResolved.name,
teacherCode: missingResolved.code.toLowerCase(),
type: "zastoupen",
hours: null,
zastupuje: {
teacher: subResolved.name,
teacherCode: subResolved.code.toLowerCase()

View File

@@ -14,15 +14,16 @@
import * as cheerio from "cheerio";
// @ts-ignore
globalThis.File = class File {};
export default async function parseTeachers() {
export default async function parseTeachers(): Promise<Record<string, string>> {
const url = "https://spsejecna.cz/ucitel";
const response = await fetch(url);
const data = await response.text();
const $ = cheerio.load(data);
const map = {};
const map: Record<string, string> = {};
$("main .contentLeftColumn li, main .contentRightColumn li").each((_, el) => {
const link = $(el).find("a");
@@ -30,8 +31,10 @@ export default async function parseTeachers() {
const text = link.text().trim(); // e.g. "Ing. Bc. Šárka Páltiková"
if (href) {
const key = href.split("/").pop().toLowerCase(); // get "pa"
map[key] = text;
const key = href.split("/").pop()?.toLowerCase(); // get "pa"
if (key) {
map[key] = text;
}
}
});