chuvsu-js 4.1.0 → 4.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -133,13 +133,12 @@ function parseSessionSchedule(doc, educationType) {
|
|
|
133
133
|
const cellHtml = dateCell.innerHTML ?? "";
|
|
134
134
|
const brMatch = cellHtml.match(/<br\s*\/?>\s*(.+)/i);
|
|
135
135
|
const weekday = brMatch ? brMatch[1].trim() : "";
|
|
136
|
-
//
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const dataCell = row.querySelector("td.trdata:not(.trfd)");
|
|
141
|
-
if (!dataCell)
|
|
136
|
+
// Live session tables repeat the date cell after the data cell. Only the
|
|
137
|
+
// leading date cell has the schedule data as its next sibling.
|
|
138
|
+
const dataCell = dateCell.nextElementSibling;
|
|
139
|
+
if (!dataCell?.matches("td.trdata:not(.trfd)")) {
|
|
142
140
|
continue;
|
|
141
|
+
}
|
|
143
142
|
const slots = [];
|
|
144
143
|
for (const entryRow of dataCell.querySelectorAll("table tr")) {
|
|
145
144
|
const td = entryRow.querySelector("td") ?? entryRow;
|
|
@@ -3,26 +3,33 @@ import { parseGroupsString } from "./groups.js";
|
|
|
3
3
|
import { LESSON_TYPE_PATTERN, LESSON_TYPE_RE, LESSON_TYPE_RE_I, SUBGROUP_RE, } from "./patterns.js";
|
|
4
4
|
const GROUP_CODE_RE = /[A-ZА-ЯЁ]{1,}(?:-[A-ZА-ЯЁa-zа-яё0-9]+)+/u;
|
|
5
5
|
const DISTANCE_RE = /дистанционно|ДОТ/i;
|
|
6
|
+
const BLUE_SPAN_RE = /<span\b(?=[^>]*(?:style=["'][^"']*color:\s*blue|class=["'][^"']*\bblue\b))[^>]*>([^<]+)<\/span>/i;
|
|
6
7
|
export function parseDate(dd, mm, yyyy) {
|
|
7
8
|
return new Date(parseInt(yyyy), parseInt(mm) - 1, parseInt(dd));
|
|
8
9
|
}
|
|
9
10
|
export function parseTransferDiv(div) {
|
|
10
11
|
const divText = text(div);
|
|
11
12
|
const divHtml = div.innerHTML ?? "";
|
|
12
|
-
const m = divText.match(/(\d{2})\.(\d{2})\.(\d{4})\s*перенос\s*c\s*(\d{2})\.(\d{2})\.(\d{4})\s*\((\d+)\s*пара\)/);
|
|
13
|
+
const m = divText.match(/(\d{2})\.(\d{2})\.(\d{4})\s*перенос\s*[cс]\s*(\d{2})\.(\d{2})\.(\d{4})\s*\((\d+)\s*пара\)/iu);
|
|
13
14
|
if (!m)
|
|
14
15
|
return null;
|
|
15
16
|
const targetDate = parseDate(m[1], m[2], m[3]);
|
|
16
17
|
const fromDate = parseDate(m[4], m[5], m[6]);
|
|
17
18
|
const fromSlot = parseInt(m[7]);
|
|
19
|
+
const lineHtmls = divHtml.split(/<br\s*\/?>/i);
|
|
20
|
+
const lessonLineHtml = lineHtmls.find((line) => {
|
|
21
|
+
const lineText = line.replace(/<[^>]*>/g, "").trim();
|
|
22
|
+
return BLUE_SPAN_RE.test(line) && LESSON_TYPE_RE_I.test(lineText);
|
|
23
|
+
}) ?? "";
|
|
24
|
+
const subjectMatch = lessonLineHtml.match(BLUE_SPAN_RE);
|
|
18
25
|
const subjectEl = div.querySelector('span[style*="color: blue"]');
|
|
19
|
-
const subject = subjectEl ? text(subjectEl) : "";
|
|
26
|
+
const subject = subjectMatch?.[1]?.trim() ?? (subjectEl ? text(subjectEl) : "");
|
|
20
27
|
if (!subject)
|
|
21
28
|
return null;
|
|
22
|
-
const roomMatch =
|
|
29
|
+
const roomMatch = lessonLineHtml.match(/([А-Яа-яA-Za-z]-\d+)/) ??
|
|
30
|
+
divHtml.match(/([А-Яа-яA-Za-z]-\d+)/);
|
|
23
31
|
const typeMatch = divText.match(LESSON_TYPE_RE);
|
|
24
|
-
const parts =
|
|
25
|
-
.split(/<br\s*\/?>/i)
|
|
32
|
+
const parts = lineHtmls
|
|
26
33
|
.map((part) => part.replace(/<[^>]*>/g, "").trim())
|
|
27
34
|
.filter((part) => part.length > 0);
|
|
28
35
|
let teacherPart = "";
|
|
@@ -31,13 +38,15 @@ export function parseTransferDiv(div) {
|
|
|
31
38
|
const cleaned = part.trim();
|
|
32
39
|
if (!cleaned)
|
|
33
40
|
continue;
|
|
41
|
+
const isLessonMeta = cleaned.includes(subject) ||
|
|
42
|
+
(roomMatch?.[1] != null && cleaned.includes(roomMatch[1])) ||
|
|
43
|
+
LESSON_TYPE_RE_I.test(cleaned);
|
|
44
|
+
if (isLessonMeta)
|
|
45
|
+
continue;
|
|
34
46
|
if (GROUP_CODE_RE.test(cleaned)) {
|
|
35
47
|
groupsPart = cleaned;
|
|
36
48
|
continue;
|
|
37
49
|
}
|
|
38
|
-
const isLessonMeta = cleaned.includes(subject) ||
|
|
39
|
-
(roomMatch?.[1] != null && cleaned.includes(roomMatch[1])) ||
|
|
40
|
-
LESSON_TYPE_RE_I.test(cleaned);
|
|
41
50
|
if (!isLessonMeta && !teacherPart) {
|
|
42
51
|
teacherPart = cleaned;
|
|
43
52
|
}
|
package/dist/tt/parse/teacher.js
CHANGED
|
@@ -3,7 +3,7 @@ import { getLessonNumber } from "../utils/index.js";
|
|
|
3
3
|
import { parseSemesterScheduleWith } from "./full-schedule.js";
|
|
4
4
|
import { parseGroupsString } from "./groups.js";
|
|
5
5
|
import { parseSubstituteForDiv, parseSubstitutionDiv, parseTransferDiv, } from "./overlays.js";
|
|
6
|
-
import {
|
|
6
|
+
import { FLEXIBLE_LESSON_TYPE_RE_I, LESSON_TYPE_RE, SUBGROUP_RE, WEEKS_RE, } from "./patterns.js";
|
|
7
7
|
const DISTANCE_RE = /дистанционно|ДОТ/i;
|
|
8
8
|
export function parseTeacherFullSchedule(html, educationType) {
|
|
9
9
|
const doc = parseHtml(html);
|
|
@@ -88,12 +88,10 @@ function parseTeacherSessionSchedule(doc, educationType) {
|
|
|
88
88
|
const cellHtml = dateCell.innerHTML ?? "";
|
|
89
89
|
const brMatch = cellHtml.match(/<br\s*\/?>\s*(.+)/i);
|
|
90
90
|
const weekday = brMatch ? brMatch[1].trim() : "";
|
|
91
|
-
const
|
|
92
|
-
if (!
|
|
93
|
-
continue;
|
|
94
|
-
const dataCell = row.querySelector("td.trdata:not(.trfd)");
|
|
95
|
-
if (!dataCell)
|
|
91
|
+
const dataCell = dateCell.nextElementSibling;
|
|
92
|
+
if (!dataCell?.matches("td.trdata:not(.trfd)")) {
|
|
96
93
|
continue;
|
|
94
|
+
}
|
|
97
95
|
const slots = [];
|
|
98
96
|
for (const entryRow of dataCell.querySelectorAll("table tr")) {
|
|
99
97
|
const td = entryRow.querySelector("td") ?? entryRow;
|
|
@@ -128,11 +126,15 @@ function parseTeacherSessionEntry(td) {
|
|
|
128
126
|
const typeMatch = plainText.match(FLEXIBLE_LESSON_TYPE_RE_I);
|
|
129
127
|
const type = typeMatch ? typeMatch[1].replace(/\.$/, "").toLowerCase() : "";
|
|
130
128
|
const subgroupMatch = plainText.match(SUBGROUP_RE);
|
|
131
|
-
// Groups: text between </span> type and <br>time
|
|
132
|
-
const groupsMatch = fullHtml.match(new RegExp(`\\((?:${FLEXIBLE_LESSON_TYPE_PATTERN})\\)\\s*([^<]+?)\\s*<br`, "i"));
|
|
133
129
|
const timeMatch = fullHtml.match(/<br\s*\/?>\s*(\d{2}:\d{2})\s*-\s*(\d{2}:\d{2})/);
|
|
134
130
|
if (!timeMatch)
|
|
135
131
|
return null;
|
|
132
|
+
const parts = fullHtml
|
|
133
|
+
.split(/<br\s*\/?>/i)
|
|
134
|
+
.map((part) => part.replace(/<[^>]*>/g, "").trim())
|
|
135
|
+
.filter((part) => part.length > 0);
|
|
136
|
+
const groupsPart = parts.find((part) => !part.includes(subject) &&
|
|
137
|
+
!/^\d{2}:\d{2}\s*-\s*\d{2}:\d{2}$/.test(part)) ?? "";
|
|
136
138
|
return {
|
|
137
139
|
entry: {
|
|
138
140
|
room,
|
|
@@ -140,7 +142,7 @@ function parseTeacherSessionEntry(td) {
|
|
|
140
142
|
type,
|
|
141
143
|
weeks: { from: 0, to: 0 },
|
|
142
144
|
teacher: { name: "" },
|
|
143
|
-
groups: parseGroupsString(
|
|
145
|
+
groups: parseGroupsString(groupsPart),
|
|
144
146
|
subgroup: subgroupMatch ? parseInt(subgroupMatch[1]) : undefined,
|
|
145
147
|
isDistance: DISTANCE_RE.test(plainText) || DISTANCE_RE.test(room),
|
|
146
148
|
possibleChanges,
|