fix: исправить ошибки типов в parser/schedule.ts
- Заменён несуществующий тип LessonObject на Partial<Lesson> - Исправлена инициализация dayInfo (Partial<Day> вместо Day) - Удалены @ts-ignore и @ts-expect-error комментарии - Добавлены приведения типов as Day и ! для корректной работы TypeScript - Исправлены проверки на null/undefined для RegExpMatchArray Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -281,9 +281,7 @@ function parseGroupSchedule(
|
|||||||
const allRows = Array.from(table.querySelectorAll('tr'))
|
const allRows = Array.from(table.querySelectorAll('tr'))
|
||||||
|
|
||||||
const days: Day[] = []
|
const days: Day[] = []
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
let dayInfo: Partial<Day> = {}
|
||||||
// @ts-ignore
|
|
||||||
let dayInfo: Day = {}
|
|
||||||
let dayLessons: Lesson[] = []
|
let dayLessons: Lesson[] = []
|
||||||
let currentWeekNumber: number | undefined
|
let currentWeekNumber: number | undefined
|
||||||
|
|
||||||
@@ -306,10 +304,8 @@ function parseGroupSchedule(
|
|||||||
// Сохраняем предыдущий день только если в нем есть пары,
|
// Сохраняем предыдущий день только если в нем есть пары,
|
||||||
// иначе получаются дубликаты заголовков без занятий.
|
// иначе получаются дубликаты заголовков без занятий.
|
||||||
if ('date' in dayInfo && dayLessons.length > 0) {
|
if ('date' in dayInfo && dayLessons.length > 0) {
|
||||||
days.push({ ...dayInfo, lessons: dayLessons })
|
days.push({ ...dayInfo, lessons: dayLessons } as Day)
|
||||||
dayLessons = []
|
dayLessons = []
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
dayInfo = {}
|
dayInfo = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,7 +357,7 @@ function parseGroupSchedule(
|
|||||||
|
|
||||||
// Добавляем последний день
|
// Добавляем последний день
|
||||||
if ('date' in dayInfo && dayLessons.length > 0) {
|
if ('date' in dayInfo && dayLessons.length > 0) {
|
||||||
days.push({ ...dayInfo, lessons: dayLessons })
|
days.push({ ...dayInfo, lessons: dayLessons } as Day)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Извлекаем wk из URL
|
// Извлекаем wk из URL
|
||||||
@@ -529,8 +525,6 @@ function parseTeacherSchedule(
|
|||||||
if (!subject && !groupShort && !group) continue
|
if (!subject && !groupShort && !group) continue
|
||||||
|
|
||||||
if (location || roomText) {
|
if (location || roomText) {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-expect-error — расширяем union тип за счет наличия place
|
|
||||||
lesson.place = {
|
lesson.place = {
|
||||||
address: location || '',
|
address: location || '',
|
||||||
classroom: roomText || '',
|
classroom: roomText || '',
|
||||||
@@ -583,9 +577,12 @@ function parseTeacherSchedule(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const parseLesson = (row: Element, isTeacherSchedule: boolean = false): Lesson | null => {
|
const parseLesson = (row: Element, isTeacherSchedule: boolean = false): Lesson | null => {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
const lesson: Partial<Lesson> & { fallbackDiscipline?: string, teacher?: string, place?: { address: string, classroom: string }, subject?: string } = {
|
||||||
// @ts-expect-error
|
resources: [],
|
||||||
const lesson: LessonObject = {}
|
homework: '',
|
||||||
|
type: '',
|
||||||
|
time: { start: '', end: '' }
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const cells = Array.from(row.querySelectorAll(':scope > td'))
|
const cells = Array.from(row.querySelectorAll(':scope > td'))
|
||||||
@@ -998,13 +995,12 @@ const parseLesson = (row: Element, isTeacherSchedule: boolean = false): Lesson |
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Колонка "Ресурс"
|
// Колонка "Ресурс"
|
||||||
lesson.resources = []
|
|
||||||
if (cells[5]) {
|
if (cells[5]) {
|
||||||
Array.from(cells[5].querySelectorAll('a')).forEach(a => {
|
Array.from(cells[5].querySelectorAll('a')).forEach(a => {
|
||||||
const title = a.textContent?.trim()
|
const title = a.textContent?.trim()
|
||||||
const url = a.getAttribute('href')
|
const url = a.getAttribute('href')
|
||||||
if (title && url) {
|
if (title && url) {
|
||||||
lesson.resources.push({
|
lesson.resources!.push({
|
||||||
type: 'link',
|
type: 'link',
|
||||||
title,
|
title,
|
||||||
url,
|
url,
|
||||||
@@ -1014,7 +1010,6 @@ const parseLesson = (row: Element, isTeacherSchedule: boolean = false): Lesson |
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Колонка "Задание для выполнения"
|
// Колонка "Задание для выполнения"
|
||||||
lesson.homework = ''
|
|
||||||
if (cells[6]) {
|
if (cells[6]) {
|
||||||
const hwCell = cells[6]
|
const hwCell = cells[6]
|
||||||
const rawText = hwCell.textContent?.replace(/\s+/g, ' ').trim() || ''
|
const rawText = hwCell.textContent?.replace(/\s+/g, ' ').trim() || ''
|
||||||
@@ -1027,7 +1022,7 @@ const parseLesson = (row: Element, isTeacherSchedule: boolean = false): Lesson |
|
|||||||
const title = a.textContent?.trim()
|
const title = a.textContent?.trim()
|
||||||
const url = a.getAttribute('href')
|
const url = a.getAttribute('href')
|
||||||
if (title && url) {
|
if (title && url) {
|
||||||
lesson.resources.push({
|
lesson.resources!.push({
|
||||||
type: 'link',
|
type: 'link',
|
||||||
title,
|
title,
|
||||||
url,
|
url,
|
||||||
@@ -1036,7 +1031,7 @@ const parseLesson = (row: Element, isTeacherSchedule: boolean = false): Lesson |
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return lesson
|
return lesson as Lesson
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error('Error while parsing lesson in table', e, row.textContent?.trim())
|
console.error('Error while parsing lesson in table', e, row.textContent?.trim())
|
||||||
return null
|
return null
|
||||||
@@ -1151,21 +1146,22 @@ export function parsePage(
|
|||||||
throw new Error(`Table not found for ${groupName}. Found ${tables.length} tables on the page.`)
|
throw new Error(`Table not found for ${groupName}. Found ${tables.length} tables on the page.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
logDebug('parsePage: selected table', { groupName, rows: table.querySelectorAll('tr').length })
|
// К этому моменту table определен (иначе была бы ошибка выше)
|
||||||
|
const selectedTable = table!
|
||||||
|
|
||||||
|
logDebug('parsePage: selected table', { groupName, rows: selectedTable.querySelectorAll('tr').length })
|
||||||
|
|
||||||
// Пытаемся найти tbody или использовать прямые children таблицы
|
// Пытаемся найти tbody или использовать прямые children таблицы
|
||||||
let tbody: HTMLTableSectionElement | null = null
|
let tbody: HTMLTableSectionElement | null = null
|
||||||
if (table) {
|
const tbodyElement = selectedTable.querySelector('tbody')
|
||||||
const tbodyElement = table.querySelector('tbody')
|
if (tbodyElement) {
|
||||||
if (tbodyElement) {
|
tbody = tbodyElement as HTMLTableSectionElement
|
||||||
tbody = tbodyElement as HTMLTableSectionElement
|
} else if (selectedTable.children.length > 0 && selectedTable.children[0].tagName === 'TBODY') {
|
||||||
} else if (table.children.length > 0 && table.children[0].tagName === 'TBODY') {
|
tbody = selectedTable.children[0] as HTMLTableSectionElement
|
||||||
tbody = table.children[0] as HTMLTableSectionElement
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!tbody && table.children.length === 0) {
|
if (!tbody && selectedTable.children.length === 0) {
|
||||||
throw new Error(`Table structure is invalid for ${groupName}`)
|
throw new Error(`Table structure is invalid for ${groupName}`)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Структура таблицы расписания с lk.ks.psuti.ru (mn=2&obj=ID группы):
|
// Структура таблицы расписания с lk.ks.psuti.ru (mn=2&obj=ID группы):
|
||||||
@@ -1176,24 +1172,23 @@ export function parsePage(
|
|||||||
// Заголовок колонок: <tr> с 7 <td> — «№ пары», «Время занятий», «Способ», «Дисциплина, преподаватель», «Тема занятия», «Ресурс», «Задание для выполнения».
|
// Заголовок колонок: <tr> с 7 <td> — «№ пары», «Время занятий», «Способ», «Дисциплина, преподаватель», «Тема занятия», «Ресурс», «Задание для выполнения».
|
||||||
// Строка пары: 7 <td> — номер, время (08:00 – 09:30), способ, ячейка с предметом/преподавателем/местом (subject + <br> + teacher + <font> адрес, Кабинет), тема, ресурсы, задание.
|
// Строка пары: 7 <td> — номер, время (08:00 – 09:30), способ, ячейка с предметом/преподавателем/местом (subject + <br> + teacher + <font> адрес, Кабинет), тема, ресурсы, задание.
|
||||||
const allRows = tbody
|
const allRows = tbody
|
||||||
? Array.from(tbody.querySelectorAll('tr'))
|
? Array.from(tbody!.querySelectorAll('tr'))
|
||||||
: Array.from(table.querySelectorAll('tr'))
|
: Array.from(selectedTable.querySelectorAll('tr'))
|
||||||
|
|
||||||
const rows = allRows.slice(2)
|
const rows = allRows.slice(2)
|
||||||
logDebug('parsePage: rows to parse', { groupName, rowsCount: rows.length, firstRows: rows.slice(0, 5).map(r => r.textContent?.trim().substring(0, 50)) })
|
logDebug('parsePage: rows to parse', { groupName, rowsCount: rows.length, firstRows: rows.slice(0, 5).map(r => r.textContent?.trim().substring(0, 50)) })
|
||||||
|
|
||||||
const days = []
|
const days: Day[] = []
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
let dayInfo: Partial<Day> = {}
|
||||||
// @ts-ignore
|
|
||||||
let dayInfo: Day = {}
|
|
||||||
let dayLessons: Lesson[] = []
|
let dayLessons: Lesson[] = []
|
||||||
let previousRowIsDayTitle = false
|
let previousRowIsDayTitle = false
|
||||||
let currentWeekNumber: number | undefined
|
let currentWeekNumber: number | undefined
|
||||||
|
|
||||||
// Пытаемся извлечь текущий wk из URL
|
// Пытаемся извлечь текущий wk из URL
|
||||||
const currentUrl = url || document.location?.href || ''
|
const currentUrl = url || document.location?.href || ''
|
||||||
const wkMatch = currentUrl.match(/[?&]wk=(\d+)/)
|
const wkMatchResult = currentUrl.match(/[?&]wk=(\d+)/)
|
||||||
const currentWk = wkMatch ? Number(wkMatch[1]) : undefined
|
const wkMatchValue = wkMatchResult?.[1]
|
||||||
|
const currentWk = wkMatchValue ? Number(wkMatchValue) : undefined
|
||||||
|
|
||||||
for (let i = 0; i < rows.length; i++) {
|
for (let i = 0; i < rows.length; i++) {
|
||||||
const row = rows[i]
|
const row = rows[i]
|
||||||
@@ -1211,10 +1206,8 @@ export function parsePage(
|
|||||||
|
|
||||||
// Если встречаем новый день, сохраняем предыдущий
|
// Если встречаем новый день, сохраняем предыдущий
|
||||||
if (isNewDayTitle && 'date' in dayInfo) {
|
if (isNewDayTitle && 'date' in dayInfo) {
|
||||||
days.push({ ...dayInfo, lessons: dayLessons })
|
days.push({ ...dayInfo, lessons: dayLessons } as Day)
|
||||||
dayLessons = []
|
dayLessons = []
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
dayInfo = {}
|
dayInfo = {}
|
||||||
previousRowIsDayTitle = false
|
previousRowIsDayTitle = false
|
||||||
}
|
}
|
||||||
@@ -1223,10 +1216,8 @@ export function parsePage(
|
|||||||
// Сохраняем день при разделителе только если есть уроки — иначе пустая строка
|
// Сохраняем день при разделителе только если есть уроки — иначе пустая строка
|
||||||
// между заголовком дня и строкой «№ пары / Время» сбрасывала контекст и все пары пропускались
|
// между заголовком дня и строкой «№ пары / Время» сбрасывала контекст и все пары пропускались
|
||||||
if ('date' in dayInfo && dayLessons.length > 0) {
|
if ('date' in dayInfo && dayLessons.length > 0) {
|
||||||
days.push({ ...dayInfo, lessons: dayLessons })
|
days.push({ ...dayInfo, lessons: dayLessons } as Day)
|
||||||
dayLessons = []
|
dayLessons = []
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
dayInfo = {}
|
dayInfo = {}
|
||||||
}
|
}
|
||||||
previousRowIsDayTitle = false
|
previousRowIsDayTitle = false
|
||||||
@@ -1242,9 +1233,10 @@ export function parsePage(
|
|||||||
|
|
||||||
// Извлекаем только часть до переноса строки или до начала следующего контента
|
// Извлекаем только часть до переноса строки или до начала следующего контента
|
||||||
// Заголовок дня может быть в начале строки, а дальше идет другой контент
|
// Заголовок дня может быть в начале строки, а дальше идет другой контент
|
||||||
const dayTitleMatch = dayTitleText.match(/((Понедельник|Вторник|Среда|Четверг|Пятница|Суббота|Воскресенье)\s+\d{1,2}\.\d{1,2}\.\d{4}\s*\/\s*\d+\s+неделя)/i)
|
const dayTitleMatchResult = dayTitleText.match(/((Понедельник|Вторник|Среда|Четверг|Пятница|Суббота|Воскресенье)\s+\d{1,2}\.\d{1,2}\.\d{4}\s*\/\s*\d+\s+неделя)/i)
|
||||||
if (dayTitleMatch) {
|
const dayTitleMatchValue = dayTitleMatchResult?.[1]!
|
||||||
dayTitleText = dayTitleMatch[1]
|
if (dayTitleMatchValue) {
|
||||||
|
dayTitleText = dayTitleMatchValue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dayTitleText) {
|
if (!dayTitleText) {
|
||||||
@@ -1300,15 +1292,16 @@ export function parsePage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const lesson = parseLesson(row, isTeacherSchedule)
|
const lesson = parseLesson(row, isTeacherSchedule)
|
||||||
if(lesson !== null) {
|
if (lesson) {
|
||||||
let lessonName = 'unknown'
|
let lessonName = 'unknown'
|
||||||
if ('subject' in lesson && lesson.subject) {
|
const lessonAny = lesson as any
|
||||||
lessonName = lesson.subject
|
if ('subject' in lessonAny && lessonAny.subject) {
|
||||||
} else if ('fallbackDiscipline' in lesson && lesson.fallbackDiscipline) {
|
lessonName = lessonAny.subject
|
||||||
lessonName = lesson.fallbackDiscipline
|
} else if ('fallbackDiscipline' in lessonAny && lessonAny.fallbackDiscipline) {
|
||||||
|
lessonName = lessonAny.fallbackDiscipline
|
||||||
}
|
}
|
||||||
logDebug('parsePage: parsed lesson', { lessonName })
|
logDebug('parsePage: parsed lesson', { lessonName })
|
||||||
dayLessons.push(lesson)
|
dayLessons.push(lesson as Lesson)
|
||||||
} else {
|
} else {
|
||||||
// Логируем строки, которые не распарсились как уроки
|
// Логируем строки, которые не распарсились как уроки
|
||||||
logDebug('parsePage: failed to parse lesson from row', { rowPreview: rowText.substring(0, 100) })
|
logDebug('parsePage: failed to parse lesson from row', { rowPreview: rowText.substring(0, 100) })
|
||||||
@@ -1329,29 +1322,29 @@ export function parsePage(
|
|||||||
// Добавляем последний день, если он не был добавлен
|
// Добавляем последний день, если он не был добавлен
|
||||||
if ('date' in dayInfo) {
|
if ('date' in dayInfo) {
|
||||||
logDebug('parsePage: adding final day', { lessonsCount: dayLessons.length })
|
logDebug('parsePage: adding final day', { lessonsCount: dayLessons.length })
|
||||||
days.push({ ...dayInfo, lessons: dayLessons })
|
days.push({ ...dayInfo, lessons: dayLessons } as Day)
|
||||||
}
|
}
|
||||||
|
|
||||||
logDebug('parsePage: total days parsed', { daysCount: days.length })
|
logDebug('parsePage: total days parsed', { daysCount: days.length })
|
||||||
|
|
||||||
// Парсим навигацию по неделям только если включена навигация
|
// Парсим навигацию по неделям только если включена навигация
|
||||||
let availableWeeks: WeekInfo[] | undefined
|
let availableWeeks: WeekInfo[] = []
|
||||||
let finalCurrentWk = currentWk
|
let finalCurrentWk = currentWk
|
||||||
|
|
||||||
if (shouldParseWeekNavigation && currentWeekNumber) {
|
if (shouldParseWeekNavigation && currentWeekNumber != null) {
|
||||||
availableWeeks = parseWeekNavigation(document, currentWeekNumber, currentWk)
|
availableWeeks = parseWeekNavigation(document, currentWeekNumber!, currentWk)
|
||||||
|
|
||||||
// Если не нашли ссылки, но есть текущий wk, добавляем текущую неделю
|
// Если не нашли ссылки, но есть текущий wk, добавляем текущую неделю
|
||||||
if (availableWeeks.length === 0 && currentWk) {
|
if (availableWeeks.length === 0 && currentWk != null) {
|
||||||
availableWeeks.push({ wk: currentWk, weekNumber: currentWeekNumber })
|
availableWeeks.push({ wk: currentWk!, weekNumber: currentWeekNumber! })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если currentWk не определен, но нашли недели, пытаемся определить текущую
|
// Если currentWk не определен, но нашли недели, пытаемся определить текущую
|
||||||
if (!currentWk && availableWeeks.length > 0) {
|
if (currentWk == null && availableWeeks.length > 0) {
|
||||||
// Ищем неделю с weekNumber равным currentWeekNumber
|
// Ищем неделю с weekNumber равным currentWeekNumber
|
||||||
const currentWeekInList = availableWeeks.find(w => w.weekNumber === currentWeekNumber)
|
const currentWeekInList = availableWeeks.find(w => w.weekNumber === currentWeekNumber!)
|
||||||
if (currentWeekInList) {
|
if (currentWeekInList) {
|
||||||
finalCurrentWk = currentWeekInList.wk
|
finalCurrentWk = currentWeekInList!.wk
|
||||||
} else {
|
} else {
|
||||||
// Если не нашли точное совпадение, берем первую неделю как текущую
|
// Если не нашли точное совпадение, берем первую неделю как текущую
|
||||||
finalCurrentWk = availableWeeks[0].wk
|
finalCurrentWk = availableWeeks[0].wk
|
||||||
|
|||||||
Reference in New Issue
Block a user