38 lines
2.7 KiB
JavaScript
38 lines
2.7 KiB
JavaScript
import { ApiError } from './errors.mjs';
|
|
|
|
const routeNumber = value => typeof value === 'string' ? value.replace(/[\s№]/g, '').toLocaleUpperCase('ru') : '';
|
|
const positive = value => Number.isSafeInteger(Number(value)) && Number(value) > 0;
|
|
|
|
export function normalizeAlerts(raw, cityId) {
|
|
if (!Array.isArray(raw)) throw new ApiError(502);
|
|
const seen = new Set();
|
|
return raw.flatMap(alert => {
|
|
if (!alert || !positive(alert.id)) throw new ApiError(502);
|
|
if (alert.is_active === false || (alert.city_id != null && Number(alert.city_id) !== cityId) || seen.has(Number(alert.id))) return [];
|
|
if ((alert.route_numbers != null && (!Array.isArray(alert.route_numbers) || alert.route_numbers.some(value => !routeNumber(value))))
|
|
|| (alert.route_ids != null && (!Array.isArray(alert.route_ids) || alert.route_ids.some(value => !positive(value))))) throw new ApiError(502);
|
|
const numbers = Array.isArray(alert.route_numbers) ? alert.route_numbers.map(routeNumber).filter(Boolean) : [];
|
|
const ids = Array.isArray(alert.route_ids) ? alert.route_ids.filter(positive).map(Number) : [];
|
|
if (!numbers.length && routeNumber(alert.route_number)) numbers.push(routeNumber(alert.route_number));
|
|
if (!ids.length && positive(alert.route_id)) ids.push(Number(alert.route_id));
|
|
const startTime = Date.parse(alert.start_time);
|
|
const endTime = alert.end_time == null ? null : Date.parse(alert.end_time);
|
|
if (!Number.isFinite(startTime) || (endTime !== null && !Number.isFinite(endTime)) || typeof alert.title !== 'string' || typeof alert.message !== 'string') throw new ApiError(502);
|
|
seen.add(Number(alert.id));
|
|
return [{ id: Number(alert.id), cityId, title: alert.title.trim(), message: alert.message.trim(),
|
|
type: ['cancellation', 'delay', 'detour'].includes(alert.alert_type) ? alert.alert_type : 'info',
|
|
routeNumbers: [...new Set(numbers)].sort((a, b) => a.localeCompare(b, 'ru', { numeric: true })), routeIds: [...new Set(ids)], isCityWide: !numbers.length && !ids.length,
|
|
startTime: new Date(startTime).toISOString(), endTime: endTime === null ? null : new Date(endTime).toISOString() }];
|
|
});
|
|
}
|
|
|
|
export function normalizeNearby(raw) {
|
|
if (!Array.isArray(raw)) throw new ApiError(502);
|
|
return raw.map(stop => {
|
|
const distance = Number(stop?.distance_meters);
|
|
if (!stop || !positive(stop.id) || typeof stop.name !== 'string' || !stop.name.trim() || stop.distance_meters == null || !Number.isFinite(distance) || distance < 0) throw new ApiError(502);
|
|
return { id: Number(stop.id), name: stop.name.trim(), direction: typeof stop.description === 'string' ? stop.description.trim() : '',
|
|
routesCount: Number(stop.routes_count) || 0, distance: Math.round(distance) };
|
|
}).sort((a, b) => a.distance - b.distance);
|
|
}
|