minotor
Version:
A lightweight client-side transit routing library.
112 lines (102 loc) • 3.02 kB
text/typescript
import { DateTime } from 'luxon';
import { toGtfsDate } from './time.js';
import { parseCsv } from './utils.js';
export type ServiceId = string;
export type ServiceIds = Set<ServiceId>;
type Weekday = 1 | 2 | 3 | 4 | 5 | 6 | 7;
type ActiveFlag = 0 | 1;
type RawGtfsDate = number;
type ExceptionType = 1 | 2;
type CalendarEntry = {
service_id: string;
monday: ActiveFlag;
tuesday: ActiveFlag;
wednesday: ActiveFlag;
thursday: ActiveFlag;
friday: ActiveFlag;
saturday: ActiveFlag;
sunday: ActiveFlag;
start_date: RawGtfsDate;
end_date: RawGtfsDate;
};
type CalendarDatesEntry = {
service_id: ServiceId;
date: RawGtfsDate;
exception_type: ExceptionType;
};
const weekdays = {
1: 'monday',
2: 'tuesday',
3: 'wednesday',
4: 'thursday',
5: 'friday',
6: 'saturday',
7: 'sunday',
};
/**
* Parses a GTFS calendar.txt file and finds the service_ids of a given date.
*
* @param serviceIds A map of the active service ids (will be populated with active service_ids).
* @param date The active date.
* @param calendarStream A readable stream for the GTFS calendar.txt file.
*/
export const parseCalendar = async (
calendarStream: NodeJS.ReadableStream,
serviceIds: ServiceIds,
date: DateTime,
) => {
const activeDate: number = toGtfsDate(date);
const weekday = date.weekday as Weekday;
const weekdayIndex = weekdays[weekday] as keyof CalendarEntry;
for await (const rawLine of parseCsv(calendarStream, [
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
'sunday',
'start_date',
'end_date',
])) {
const line = rawLine as CalendarEntry;
if (activeDate < line.start_date || activeDate > line.end_date) {
// If the service is not valid on this date
continue;
}
if (line[weekdayIndex] !== 1) {
// If the service is not valid on this week day
continue;
}
serviceIds.add(line['service_id']);
}
};
/**
* Parses a gtfs calendar_dates.txt file and finds the service ids valid at a given date.
*
* @param serviceIds A map of the active service ids (will be populated and filtered).
* @param date The active date, in the format "YYYYMMDD".
* @param calendarDatesStream A readable stream for the GTFS calendar_dates.txt file.
*/
export const parseCalendarDates = async (
calendarDatesStream: NodeJS.ReadableStream,
serviceIds: ServiceIds,
date: DateTime,
) => {
const activeDate: number = toGtfsDate(date);
for await (const rawLine of parseCsv(calendarDatesStream, [
'date',
'exception_type',
])) {
const line = rawLine as CalendarDatesEntry;
if (line.date !== activeDate) {
// No rule on the active date
} else if (line.exception_type === 2 && serviceIds.has(line.service_id)) {
// Service has been removed for the specified date.
serviceIds.delete(line.service_id);
} else if (line.exception_type === 1) {
// Service is present on the active date
serviceIds.add(line.service_id);
}
}
};