refactor: Rewrite to typescript
All checks were successful
Remote Deploy / deploy (push) Successful in 14s
All checks were successful
Remote Deploy / deploy (push) Successful in 14s
This commit is contained in:
@@ -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()
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user