59 lines
2.7 KiB
TypeScript
59 lines
2.7 KiB
TypeScript
import type { ResultsSnapshot } from '../src/types/screen.js'
|
|
|
|
function object(value: unknown): Record<string, unknown> {
|
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
throw new Error('Некорректный снимок результатов')
|
|
return value as Record<string, unknown>
|
|
}
|
|
function list(value: unknown): unknown[] {
|
|
if (!Array.isArray(value)) throw new Error('Некорректный список результатов')
|
|
return value
|
|
}
|
|
function text(value: unknown): string {
|
|
if (typeof value !== 'string') throw new Error('Некорректный текст результатов')
|
|
return value
|
|
}
|
|
function integer(value: unknown, minimum = -2147483648): number {
|
|
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < minimum)
|
|
throw new Error('Некорректное число результатов')
|
|
return value
|
|
}
|
|
// Сохраняем только поля публичной таблицы, без участников, паролей и токенов.
|
|
export function parseResults(value: unknown, packageKey: string): ResultsSnapshot {
|
|
const data = object(value)
|
|
if (data.packageKey !== packageKey || !/^[a-f0-9]{64}$/.test(packageKey))
|
|
throw new Error('Результаты относятся к другой игре')
|
|
const captured = Date.parse(text(data.capturedAt))
|
|
if (!Number.isFinite(captured)) throw new Error('Некорректное время снимка результатов')
|
|
const questions = list(data.questions).map((value) => {
|
|
const q = object(value)
|
|
return { code: text(q.code), text: text(q.text) }
|
|
})
|
|
const codes = new Set(questions.map((q) => q.code))
|
|
if (codes.size !== questions.length || codes.has(''))
|
|
throw new Error('Повтор или отсутствие кода вопроса')
|
|
const teams = list(data.teams).map((value) => {
|
|
const team = object(value)
|
|
const answers = list(team.answers).map((value) => {
|
|
const a = object(value)
|
|
return { questionCode: text(a.questionCode), score: integer(a.score) }
|
|
})
|
|
if (
|
|
new Set(answers.map((a) => a.questionCode)).size !== answers.length ||
|
|
answers.some((a) => !codes.has(a.questionCode))
|
|
)
|
|
throw new Error('Некорректные ответы результатов')
|
|
return {
|
|
id: text(team.id),
|
|
name: text(team.name),
|
|
place: integer(team.place, 1),
|
|
totalScore: integer(team.totalScore),
|
|
actionsCount: integer(team.actionsCount, 0),
|
|
answers,
|
|
}
|
|
})
|
|
if (teams.some((team) => !team.id) || new Set(teams.map((t) => t.id)).size !== teams.length)
|
|
throw new Error('Повтор или отсутствие команды')
|
|
return { packageKey, capturedAt: new Date(captured).toISOString(), questions, teams }
|
|
}
|