corequery-gtfs 0.1.0 → 0.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.
- package/README.md +1 -1
- package/dist/config/gtfs-config.d.ts +10 -0
- package/dist/config/gtfs-config.js +2 -0
- package/dist/config/gtfs-config.js.map +1 -0
- package/dist/config/ids.d.ts +13 -0
- package/dist/config/ids.js +2 -0
- package/dist/config/ids.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/routes.d.ts +16 -0
- package/dist/config/routes.js +2 -0
- package/dist/config/routes.js.map +1 -0
- package/dist/config/timezone-data.d.ts +5 -0
- package/dist/config/timezone-data.js +2 -0
- package/dist/config/timezone-data.js.map +1 -0
- package/dist/corequery-types.d.ts +2 -0
- package/dist/corequery-types.js +3 -0
- package/dist/corequery-types.js.map +1 -0
- package/dist/data/bounded-instant-range.d.ts +10 -0
- package/dist/data/bounded-instant-range.js +30 -0
- package/dist/data/bounded-instant-range.js.map +1 -0
- package/dist/data/gtfs-calendar.d.ts +38 -0
- package/dist/data/gtfs-calendar.js +116 -0
- package/dist/data/gtfs-calendar.js.map +1 -0
- package/dist/data/gtfs-feed.d.ts +16 -0
- package/dist/data/gtfs-feed.js +33 -0
- package/dist/data/gtfs-feed.js.map +1 -0
- package/dist/data/gtfs-realtime-data.d.ts +9 -0
- package/dist/data/gtfs-realtime-data.js +20 -0
- package/dist/data/gtfs-realtime-data.js.map +1 -0
- package/dist/data/gtfs-schedule-data.d.ts +13 -0
- package/dist/data/gtfs-schedule-data.js +40 -0
- package/dist/data/gtfs-schedule-data.js.map +1 -0
- package/dist/data/gtfs-scheduled-trip-movements.d.ts +118 -0
- package/dist/data/gtfs-scheduled-trip-movements.js +233 -0
- package/dist/data/gtfs-scheduled-trip-movements.js.map +1 -0
- package/dist/data/gtfs-scheduled-trip.d.ts +41 -0
- package/dist/data/gtfs-scheduled-trip.js +100 -0
- package/dist/data/gtfs-scheduled-trip.js.map +1 -0
- package/dist/data/gtfs-stop-time.d.ts +38 -0
- package/dist/data/gtfs-stop-time.js +105 -0
- package/dist/data/gtfs-stop-time.js.map +1 -0
- package/dist/data/gtfs-updated-trip-movements.d.ts +124 -0
- package/dist/data/gtfs-updated-trip-movements.js +150 -0
- package/dist/data/gtfs-updated-trip-movements.js.map +1 -0
- package/dist/data/gtfs-updated-trip.d.ts +21 -0
- package/dist/data/gtfs-updated-trip.js +55 -0
- package/dist/data/gtfs-updated-trip.js.map +1 -0
- package/dist/data/ids/index.d.ts +2 -0
- package/dist/data/ids/index.js +3 -0
- package/dist/data/ids/index.js.map +1 -0
- package/dist/data/ids/line-gtfs-id-collection.d.ts +16 -0
- package/dist/data/ids/line-gtfs-id-collection.js +47 -0
- package/dist/data/ids/line-gtfs-id-collection.js.map +1 -0
- package/dist/data/ids/line-gtfs-id-mapping.d.ts +17 -0
- package/dist/data/ids/line-gtfs-id-mapping.js +50 -0
- package/dist/data/ids/line-gtfs-id-mapping.js.map +1 -0
- package/dist/data/ids/line-gtfs-id-metadata.d.ts +17 -0
- package/dist/data/ids/line-gtfs-id-metadata.js +2 -0
- package/dist/data/ids/line-gtfs-id-metadata.js.map +1 -0
- package/dist/data/ids/stop-gtfs-id-collection.d.ts +14 -0
- package/dist/data/ids/stop-gtfs-id-collection.js +55 -0
- package/dist/data/ids/stop-gtfs-id-collection.js.map +1 -0
- package/dist/data/ids/stop-gtfs-id-mapping.d.ts +17 -0
- package/dist/data/ids/stop-gtfs-id-mapping.js +50 -0
- package/dist/data/ids/stop-gtfs-id-mapping.js.map +1 -0
- package/dist/data/ids/stop-gtfs-id-metadata.d.ts +23 -0
- package/dist/data/ids/stop-gtfs-id-metadata.js +2 -0
- package/dist/data/ids/stop-gtfs-id-metadata.js.map +1 -0
- package/dist/data/index.d.ts +3 -0
- package/dist/data/index.js +4 -0
- package/dist/data/index.js.map +1 -0
- package/dist/data/plain-date-range.d.ts +11 -0
- package/dist/data/plain-date-range.js +36 -0
- package/dist/data/plain-date-range.js.map +1 -0
- package/dist/data/raw/realtime-data-json.d.ts +26 -0
- package/dist/data/raw/realtime-data-json.js +2 -0
- package/dist/data/raw/realtime-data-json.js.map +1 -0
- package/dist/data/raw/schedule-csvs.d.ts +69 -0
- package/dist/data/raw/schedule-csvs.js +2 -0
- package/dist/data/raw/schedule-csvs.js.map +1 -0
- package/dist/data/route/bonus-lines-mapping.d.ts +17 -0
- package/dist/data/route/bonus-lines-mapping.js +29 -0
- package/dist/data/route/bonus-lines-mapping.js.map +1 -0
- package/dist/data/route/index.d.ts +1 -0
- package/dist/data/route/index.js +2 -0
- package/dist/data/route/index.js.map +1 -0
- package/dist/data/route/line-routes-mapping.d.ts +8 -0
- package/dist/data/route/line-routes-mapping.js +20 -0
- package/dist/data/route/line-routes-mapping.js.map +1 -0
- package/dist/data/route/route-stop.d.ts +12 -0
- package/dist/data/route/route-stop.js +18 -0
- package/dist/data/route/route-stop.js.map +1 -0
- package/dist/data/route/route.d.ts +19 -0
- package/dist/data/route/route.js +43 -0
- package/dist/data/route/route.js.map +1 -0
- package/dist/data/utils.d.ts +3 -0
- package/dist/data/utils.js +2 -0
- package/dist/data/utils.js.map +1 -0
- package/dist/departures/departures-block-iterator.d.ts +18 -0
- package/dist/departures/departures-block-iterator.js +70 -0
- package/dist/departures/departures-block-iterator.js.map +1 -0
- package/dist/departures/departures-block.d.ts +19 -0
- package/dist/departures/departures-block.js +13 -0
- package/dist/departures/departures-block.js.map +1 -0
- package/dist/departures/departures-iterator.d.ts +16 -0
- package/dist/departures/departures-iterator.js +15 -0
- package/dist/departures/departures-iterator.js.map +1 -0
- package/dist/departures/gtfs-scheduled-movements-index.d.ts +18 -0
- package/dist/departures/gtfs-scheduled-movements-index.js +66 -0
- package/dist/departures/gtfs-scheduled-movements-index.js.map +1 -0
- package/dist/departures/index.d.ts +1 -0
- package/dist/departures/index.js +2 -0
- package/dist/departures/index.js.map +1 -0
- package/dist/departures/multifeed-departures-iterator.d.ts +20 -0
- package/dist/departures/multifeed-departures-iterator.js +52 -0
- package/dist/departures/multifeed-departures-iterator.js.map +1 -0
- package/dist/departures/realtime-departures-block-iterator.d.ts +12 -0
- package/dist/departures/realtime-departures-block-iterator.js +38 -0
- package/dist/departures/realtime-departures-block-iterator.js.map +1 -0
- package/dist/departures/realtime-departures-block.d.ts +16 -0
- package/dist/departures/realtime-departures-block.js +43 -0
- package/dist/departures/realtime-departures-block.js.map +1 -0
- package/dist/departures/scheduled-departures-block-iterator.d.ts +12 -0
- package/dist/departures/scheduled-departures-block-iterator.js +55 -0
- package/dist/departures/scheduled-departures-block-iterator.js.map +1 -0
- package/dist/departures/scheduled-departures-block.d.ts +18 -0
- package/dist/departures/scheduled-departures-block.js +54 -0
- package/dist/departures/scheduled-departures-block.js.map +1 -0
- package/dist/departures/scheduled-departures-blocks-builder.d.ts +20 -0
- package/dist/departures/scheduled-departures-blocks-builder.js +222 -0
- package/dist/departures/scheduled-departures-blocks-builder.js.map +1 -0
- package/dist/departures/scheduled-departures-iterator.d.ts +30 -0
- package/dist/departures/scheduled-departures-iterator.js +204 -0
- package/dist/departures/scheduled-departures-iterator.js.map +1 -0
- package/dist/departures/zipper-departures-iterator.d.ts +18 -0
- package/dist/departures/zipper-departures-iterator.js +68 -0
- package/dist/departures/zipper-departures-iterator.js.map +1 -0
- package/dist/gtfs-system.d.ts +31 -0
- package/dist/gtfs-system.js +86 -0
- package/dist/gtfs-system.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/gtfs-feed-parser.d.ts +18 -0
- package/dist/parser/gtfs-feed-parser.js +23 -0
- package/dist/parser/gtfs-feed-parser.js.map +1 -0
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/index.js +3 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/realtime/gtfs-realtime-data-parser.d.ts +11 -0
- package/dist/parser/realtime/gtfs-realtime-data-parser.js +19 -0
- package/dist/parser/realtime/gtfs-realtime-data-parser.js.map +1 -0
- package/dist/parser/realtime/gtfs-trip-update-parser.d.ts +99 -0
- package/dist/parser/realtime/gtfs-trip-update-parser.js +335 -0
- package/dist/parser/realtime/gtfs-trip-update-parser.js.map +1 -0
- package/dist/parser/realtime/gtfs-trip-update-trip-identifier.d.ts +35 -0
- package/dist/parser/realtime/gtfs-trip-update-trip-identifier.js +95 -0
- package/dist/parser/realtime/gtfs-trip-update-trip-identifier.js.map +1 -0
- package/dist/parser/realtime/index.d.ts +3 -0
- package/dist/parser/realtime/index.js +2 -0
- package/dist/parser/realtime/index.js.map +1 -0
- package/dist/parser/schedule/gtfs-calendar-parser.d.ts +28 -0
- package/dist/parser/schedule/gtfs-calendar-parser.js +113 -0
- package/dist/parser/schedule/gtfs-calendar-parser.js.map +1 -0
- package/dist/parser/schedule/gtfs-route-matcher.d.ts +48 -0
- package/dist/parser/schedule/gtfs-route-matcher.js +199 -0
- package/dist/parser/schedule/gtfs-route-matcher.js.map +1 -0
- package/dist/parser/schedule/gtfs-schedule-parser.d.ts +15 -0
- package/dist/parser/schedule/gtfs-schedule-parser.js +19 -0
- package/dist/parser/schedule/gtfs-schedule-parser.js.map +1 -0
- package/dist/parser/schedule/gtfs-stop-time-normaliser.d.ts +47 -0
- package/dist/parser/schedule/gtfs-stop-time-normaliser.js +119 -0
- package/dist/parser/schedule/gtfs-stop-time-normaliser.js.map +1 -0
- package/dist/parser/schedule/gtfs-transfer-connector.d.ts +52 -0
- package/dist/parser/schedule/gtfs-transfer-connector.js +168 -0
- package/dist/parser/schedule/gtfs-transfer-connector.js.map +1 -0
- package/dist/parser/schedule/gtfs-trip-parser.d.ts +45 -0
- package/dist/parser/schedule/gtfs-trip-parser.js +169 -0
- package/dist/parser/schedule/gtfs-trip-parser.js.map +1 -0
- package/dist/parser/schedule/index.d.ts +6 -0
- package/dist/parser/schedule/index.js +2 -0
- package/dist/parser/schedule/index.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { GtfsCalendar } from "../../data/gtfs-calendar.js";
|
|
2
|
+
import { PlainDateRange } from "../../data/plain-date-range.js";
|
|
3
|
+
const CALENDAR_DATE_EXCEPTION_TYPE_ADDED = 1;
|
|
4
|
+
const CALENDAR_DATE_EXCEPTION_TYPE_REMOVED = 2;
|
|
5
|
+
export class GtfsCalendarParser {
|
|
6
|
+
_onError;
|
|
7
|
+
constructor(_onError) {
|
|
8
|
+
this._onError = _onError;
|
|
9
|
+
}
|
|
10
|
+
parse(calendarCsv, calendarDatesCsv) {
|
|
11
|
+
const calendarData = new Map();
|
|
12
|
+
const calendarsToIgnore = new Set();
|
|
13
|
+
// Step 1: Process rows in calendar.txt.
|
|
14
|
+
for (const row of calendarCsv) {
|
|
15
|
+
if (calendarData.has(row.service_id)) {
|
|
16
|
+
// We only keep the calendar we see for a given service_id, I guess.
|
|
17
|
+
this._onError(new DuplicateCalendarIdError(row));
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (Temporal.PlainDate.compare(row.start_date, row.end_date) > 0) {
|
|
21
|
+
this._onError(new InvalidCalendarDateRangeError(row));
|
|
22
|
+
calendarsToIgnore.add(row.service_id);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
calendarData.set(row.service_id, {
|
|
26
|
+
id: row.service_id,
|
|
27
|
+
baseRow: row,
|
|
28
|
+
addedDates: [],
|
|
29
|
+
removedDates: [],
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
// Step 2: Process rows in calendar_dates.txt, modifying or adding new
|
|
33
|
+
// calendars as necessary.
|
|
34
|
+
for (const row of calendarDatesCsv) {
|
|
35
|
+
// If something goes wrong parsing the row in calendar.txt, don't act as
|
|
36
|
+
// though no row was present. Ignore calendar_dates.txt rows for it too.
|
|
37
|
+
if (calendarsToIgnore.has(row.service_id))
|
|
38
|
+
continue;
|
|
39
|
+
const calendar = calendarData.get(row.service_id) ?? {
|
|
40
|
+
id: row.service_id,
|
|
41
|
+
baseRow: null,
|
|
42
|
+
addedDates: [],
|
|
43
|
+
removedDates: [],
|
|
44
|
+
};
|
|
45
|
+
if (calendar.addedDates.includes(row.date) ||
|
|
46
|
+
calendar.removedDates.includes(row.date)) {
|
|
47
|
+
// Report this weirdness, but keep going. My GtfsCalendar implementation
|
|
48
|
+
// will ultimately give added dates priority.
|
|
49
|
+
this._onError(new MultipleExceptionsForSameDateError(row));
|
|
50
|
+
}
|
|
51
|
+
if (row.exception_type === CALENDAR_DATE_EXCEPTION_TYPE_ADDED) {
|
|
52
|
+
calendar.addedDates.push(row.date);
|
|
53
|
+
}
|
|
54
|
+
else if (row.exception_type === CALENDAR_DATE_EXCEPTION_TYPE_REMOVED) {
|
|
55
|
+
calendar.removedDates.push(row.date);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
this._onError(new UnexpectedCalendarDateExceptionTypeError(row));
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
calendarData.set(row.service_id, calendar);
|
|
62
|
+
}
|
|
63
|
+
// Step 3: Convert to GtfsCalendar instances.
|
|
64
|
+
return Array.from(calendarData.values()).map((data) => {
|
|
65
|
+
const baseRow = data.baseRow ?? {
|
|
66
|
+
service_id: data.id,
|
|
67
|
+
monday: false,
|
|
68
|
+
tuesday: false,
|
|
69
|
+
wednesday: false,
|
|
70
|
+
thursday: false,
|
|
71
|
+
friday: false,
|
|
72
|
+
saturday: false,
|
|
73
|
+
sunday: false,
|
|
74
|
+
start_date: null,
|
|
75
|
+
end_date: null,
|
|
76
|
+
};
|
|
77
|
+
return new GtfsCalendar(data.id, baseRow.monday, baseRow.tuesday, baseRow.wednesday, baseRow.thursday, baseRow.friday, baseRow.saturday, baseRow.sunday, new PlainDateRange(baseRow.start_date, baseRow.end_date), data.addedDates, data.removedDates);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export class DuplicateCalendarIdError extends Error {
|
|
82
|
+
subsequentRowWithDuplicateId;
|
|
83
|
+
type = "duplicate-calendar";
|
|
84
|
+
constructor(subsequentRowWithDuplicateId) {
|
|
85
|
+
super();
|
|
86
|
+
this.subsequentRowWithDuplicateId = subsequentRowWithDuplicateId;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export class InvalidCalendarDateRangeError extends Error {
|
|
90
|
+
row;
|
|
91
|
+
type = "invalid-calendar-date-range";
|
|
92
|
+
constructor(row) {
|
|
93
|
+
super();
|
|
94
|
+
this.row = row;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export class UnexpectedCalendarDateExceptionTypeError extends Error {
|
|
98
|
+
row;
|
|
99
|
+
type = "unexpected-calendar-date-exception-type";
|
|
100
|
+
constructor(row) {
|
|
101
|
+
super();
|
|
102
|
+
this.row = row;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export class MultipleExceptionsForSameDateError extends Error {
|
|
106
|
+
subsequentRowForSameDate;
|
|
107
|
+
type = "multiple-exceptions-for-same-date";
|
|
108
|
+
constructor(subsequentRowForSameDate) {
|
|
109
|
+
super();
|
|
110
|
+
this.subsequentRowForSameDate = subsequentRowForSameDate;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=gtfs-calendar-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gtfs-calendar-parser.js","sourceRoot":"","sources":["../../../src/parser/schedule/gtfs-calendar-parser.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,MAAM,kCAAkC,GAAG,CAAC,CAAC;AAC7C,MAAM,oCAAoC,GAAG,CAAC,CAAC;AAE/C,MAAM,OAAO,kBAAkB;IAEV;IADnB,YACmB,QAAmD;QAAnD,aAAQ,GAAR,QAAQ,CAA2C;IACnE,CAAC;IAEJ,KAAK,CACH,WAAwB,EACxB,gBAAkC;QASlC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAqC,CAAC;QAClE,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;QAE5C,wCAAwC;QACxC,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,IAAI,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBACrC,oEAAoE;gBACpE,IAAI,CAAC,QAAQ,CAAC,IAAI,wBAAwB,CAAC,GAAG,CAAC,CAAC,CAAC;gBACjD,SAAS;YACX,CAAC;YAED,IAAI,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACjE,IAAI,CAAC,QAAQ,CAAC,IAAI,6BAA6B,CAAC,GAAG,CAAC,CAAC,CAAC;gBACtD,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBACtC,SAAS;YACX,CAAC;YAED,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE;gBAC/B,EAAE,EAAE,GAAG,CAAC,UAAU;gBAClB,OAAO,EAAE,GAAG;gBACZ,UAAU,EAAE,EAAE;gBACd,YAAY,EAAE,EAAE;aACjB,CAAC,CAAC;QACL,CAAC;QAED,sEAAsE;QACtE,0BAA0B;QAC1B,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;YACnC,wEAAwE;YACxE,wEAAwE;YACxE,IAAI,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;gBAAE,SAAS;YAEpD,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI;gBACnD,EAAE,EAAE,GAAG,CAAC,UAAU;gBAClB,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,EAAE;gBACd,YAAY,EAAE,EAAE;aACjB,CAAC;YAEF,IACE,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;gBACtC,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EACxC,CAAC;gBACD,wEAAwE;gBACxE,6CAA6C;gBAC7C,IAAI,CAAC,QAAQ,CAAC,IAAI,kCAAkC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7D,CAAC;YAED,IAAI,GAAG,CAAC,cAAc,KAAK,kCAAkC,EAAE,CAAC;gBAC9D,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACrC,CAAC;iBAAM,IAAI,GAAG,CAAC,cAAc,KAAK,oCAAoC,EAAE,CAAC;gBACvE,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,QAAQ,CAAC,IAAI,wCAAwC,CAAC,GAAG,CAAC,CAAC,CAAC;gBACjE,SAAS;YACX,CAAC;YAED,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC7C,CAAC;QAED,6CAA6C;QAC7C,OAAO,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACpD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI;gBAC9B,UAAU,EAAE,IAAI,CAAC,EAAE;gBACnB,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,KAAK;gBACd,SAAS,EAAE,KAAK;gBAChB,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,KAAK;gBACb,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,KAAK;gBACb,UAAU,EAAE,IAAI;gBAChB,QAAQ,EAAE,IAAI;aACf,CAAC;YAEF,OAAO,IAAI,YAAY,CACrB,IAAI,CAAC,EAAE,EACP,OAAO,CAAC,MAAM,EACd,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,MAAM,EACd,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,MAAM,EACd,IAAI,cAAc,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,EACxD,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,YAAY,CAClB,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAQD,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAE5B;IADZ,IAAI,GAAG,oBAAoB,CAAC;IACrC,YAAqB,4BAA4C;QAC/D,KAAK,EAAE,CAAC;QADW,iCAA4B,GAA5B,4BAA4B,CAAgB;IAEjE,CAAC;CACF;AAED,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IAEjC;IADZ,IAAI,GAAG,6BAA6B,CAAC;IAC9C,YAAqB,GAAmB;QACtC,KAAK,EAAE,CAAC;QADW,QAAG,GAAH,GAAG,CAAgB;IAExC,CAAC;CACF;AAED,MAAM,OAAO,wCAAyC,SAAQ,KAAK;IAE5C;IADZ,IAAI,GAAG,yCAAyC,CAAC;IAC1D,YAAqB,GAAwB;QAC3C,KAAK,EAAE,CAAC;QADW,QAAG,GAAH,GAAG,CAAqB;IAE7C,CAAC;CACF;AAED,MAAM,OAAO,kCAAmC,SAAQ,KAAK;IAEtC;IADZ,IAAI,GAAG,mCAAmC,CAAC;IACpD,YAAqB,wBAA6C;QAChE,KAAK,EAAE,CAAC;QADW,6BAAwB,GAAxB,wBAAwB,CAAqB;IAElE,CAAC;CACF"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Color } from "../../corequery-types.js";
|
|
2
|
+
import type { StopTimesCsv, StopTimesCsvRow } from "../../data/raw/schedule-csvs.js";
|
|
3
|
+
import type { StopGtfsIdMapping } from "../../data/ids/stop-gtfs-id-mapping.js";
|
|
4
|
+
import type { Route } from "../../data/route/route.js";
|
|
5
|
+
import { type GtfsScheduledTripMovement } from "../../data/gtfs-scheduled-trip-movements.js";
|
|
6
|
+
export type MatchedRoute = {
|
|
7
|
+
movements: readonly GtfsScheduledTripMovement[];
|
|
8
|
+
color: Color | null;
|
|
9
|
+
serviceTags: readonly number[];
|
|
10
|
+
};
|
|
11
|
+
export declare class GtfsRouteMatcher {
|
|
12
|
+
private readonly _onError;
|
|
13
|
+
constructor(_onError: (error: GtfsRouteMatchingError) => void);
|
|
14
|
+
match(stopTimes: StopTimesCsv, routesForLine: readonly Route[], stopGtfsIdMapping: StopGtfsIdMapping): MatchedRoute | null;
|
|
15
|
+
private _matchToRoute;
|
|
16
|
+
private _addPassingMovementsFromRoute;
|
|
17
|
+
/**
|
|
18
|
+
* Take the rows from stop_times.txt and form a
|
|
19
|
+
* GtfsScheduledTripServicingMovement for each. Note that passing movements
|
|
20
|
+
* are not added at this stage. They're sprinkled in later once we've matched
|
|
21
|
+
* the trip to a route.
|
|
22
|
+
*/
|
|
23
|
+
private _convertToServicingMovements;
|
|
24
|
+
private _doesPickUp;
|
|
25
|
+
private _doesDropOff;
|
|
26
|
+
}
|
|
27
|
+
export type GtfsRouteMatchingError = NoMatchingRouteError | StopTimeReferencesUnmappedStopIdError | UnexpectedPickupTypeError | UnexpectedDropOffTypeError;
|
|
28
|
+
export declare class NoMatchingRouteError extends Error {
|
|
29
|
+
readonly stopTimes: StopTimesCsv;
|
|
30
|
+
readonly resolvedStopIds: readonly number[];
|
|
31
|
+
readonly type = "no-matching-route";
|
|
32
|
+
constructor(stopTimes: StopTimesCsv, resolvedStopIds: readonly number[]);
|
|
33
|
+
}
|
|
34
|
+
export declare class StopTimeReferencesUnmappedStopIdError extends Error {
|
|
35
|
+
readonly stopTime: StopTimesCsvRow;
|
|
36
|
+
readonly type = "stop-time-references-unmapped-stop-id";
|
|
37
|
+
constructor(stopTime: StopTimesCsvRow);
|
|
38
|
+
}
|
|
39
|
+
export declare class UnexpectedPickupTypeError extends Error {
|
|
40
|
+
readonly stopTime: StopTimesCsvRow;
|
|
41
|
+
readonly type = "unexpected-pickup-type";
|
|
42
|
+
constructor(stopTime: StopTimesCsvRow);
|
|
43
|
+
}
|
|
44
|
+
export declare class UnexpectedDropOffTypeError extends Error {
|
|
45
|
+
readonly stopTime: StopTimesCsvRow;
|
|
46
|
+
readonly type = "unexpected-drop-off-type";
|
|
47
|
+
constructor(stopTime: StopTimesCsvRow);
|
|
48
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { GtfsScheduledTripOriginatingMovement, GtfsScheduledTripPassingMovement, GtfsScheduledTripRegularMovement, GtfsScheduledTripTerminatingMovement, } from "../../data/gtfs-scheduled-trip-movements.js";
|
|
2
|
+
import { itsOk } from "@dan-schel/js-utils";
|
|
3
|
+
const STOP_TIME_PICKUP_TYPE_REGULAR = 0;
|
|
4
|
+
const STOP_TIME_PICKUP_TYPE_NO_PICKUP = 1;
|
|
5
|
+
const STOP_TIME_DROP_OFF_TYPE_REGULAR = 0;
|
|
6
|
+
const STOP_TIME_DROP_OFF_TYPE_NO_DROP_OFF = 1;
|
|
7
|
+
export class GtfsRouteMatcher {
|
|
8
|
+
_onError;
|
|
9
|
+
constructor(_onError) {
|
|
10
|
+
this._onError = _onError;
|
|
11
|
+
}
|
|
12
|
+
match(stopTimes, routesForLine, stopGtfsIdMapping) {
|
|
13
|
+
const servicingMovements = this._convertToServicingMovements(stopTimes, stopGtfsIdMapping);
|
|
14
|
+
if (servicingMovements == null)
|
|
15
|
+
return null;
|
|
16
|
+
const match = this._matchToRoute(servicingMovements, routesForLine);
|
|
17
|
+
if (match == null) {
|
|
18
|
+
const stopIds = servicingMovements.map((movement) => movement.stopId);
|
|
19
|
+
this._onError(new NoMatchingRouteError(stopTimes, stopIds));
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return match;
|
|
23
|
+
}
|
|
24
|
+
_matchToRoute(servicingMovements, routesForLine) {
|
|
25
|
+
// Step 1: Find the shortest route for this line which contains all the
|
|
26
|
+
// stops where the trip services as a subsequence.
|
|
27
|
+
const shortestMatch = routesForLine
|
|
28
|
+
.filter((r) => r.matchesStoppingOrder(servicingMovements.map((m) => m.stopId)))
|
|
29
|
+
.reduce((prev, me) => (prev == null || me.isShorterThan(prev) ? me : prev), null);
|
|
30
|
+
if (shortestMatch == null)
|
|
31
|
+
return null;
|
|
32
|
+
const { color, serviceTags } = shortestMatch;
|
|
33
|
+
// Step 2: Since stop_times.txt in GTFS only lists the stops the service
|
|
34
|
+
// actually serves (i.e. it doesn't have the express stops), use the matched
|
|
35
|
+
// route as a guide for which stops the service skipped, and add those into
|
|
36
|
+
// the list as passing movements.
|
|
37
|
+
const movements = this._addPassingMovementsFromRoute(servicingMovements, shortestMatch);
|
|
38
|
+
return { movements, color, serviceTags };
|
|
39
|
+
}
|
|
40
|
+
_addPassingMovementsFromRoute(servicingMovements, matchingRoute) {
|
|
41
|
+
const result = [];
|
|
42
|
+
let nextServicingMovementIndex = 0;
|
|
43
|
+
// Broadly: Iterate through the route's stops, and step through the trip
|
|
44
|
+
// movements simultaneously when they match. Add all route stops between
|
|
45
|
+
// first and last trip movements as servicing movements where found or
|
|
46
|
+
// passing movements otherwise.
|
|
47
|
+
for (const routeStop of matchingRoute.stops) {
|
|
48
|
+
const nextServicingMovement = servicingMovements[nextServicingMovementIndex];
|
|
49
|
+
// If there's no next servicing movement, then the index must be off the
|
|
50
|
+
// end of the array, so we're done (the service has terminated).
|
|
51
|
+
if (nextServicingMovement == null)
|
|
52
|
+
break;
|
|
53
|
+
if (routeStop.stopId === nextServicingMovement.stopId) {
|
|
54
|
+
// When the next movement from the trip matches the one in the route
|
|
55
|
+
// we're up to, add the servicing movement.
|
|
56
|
+
result.push(nextServicingMovement);
|
|
57
|
+
nextServicingMovementIndex++;
|
|
58
|
+
}
|
|
59
|
+
else if (nextServicingMovementIndex > 0 &&
|
|
60
|
+
!routeStop.collapseInStoppingPatterns) {
|
|
61
|
+
// Otherwise the stop from the route is an `type: "passing"` movement.
|
|
62
|
+
// `nextServicingMovementIndex > 0` stops us adding passing movements
|
|
63
|
+
// from the route before the service originates.
|
|
64
|
+
//
|
|
65
|
+
// For now, I'm skipping adding `collapseInStoppingPatterns` stops as
|
|
66
|
+
// passing movements. This flag means we don't want this stop to show up
|
|
67
|
+
// in stopping patterns normally, unless it's servicing (e.g. East
|
|
68
|
+
// Pakenham on the Gippsland line is one of these). I'm assuming there's
|
|
69
|
+
// nothing downstream that'll need to consider these collapsed stops.
|
|
70
|
+
//
|
|
71
|
+
// (If I need to reconsider this decision for some reason, maybe instead
|
|
72
|
+
// of adding those stops back in to this array with some sort of flag, I
|
|
73
|
+
// could consider adding the matched route itself as metadata to the
|
|
74
|
+
// trip? Probably having the index of the route stop in this array will
|
|
75
|
+
// be useful to reconcile the two.)
|
|
76
|
+
result.push(new GtfsScheduledTripPassingMovement({
|
|
77
|
+
stopId: routeStop.stopId,
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Take the rows from stop_times.txt and form a
|
|
85
|
+
* GtfsScheduledTripServicingMovement for each. Note that passing movements
|
|
86
|
+
* are not added at this stage. They're sprinkled in later once we've matched
|
|
87
|
+
* the trip to a route.
|
|
88
|
+
*/
|
|
89
|
+
_convertToServicingMovements(stopTimes, stopGtfsIdMapping) {
|
|
90
|
+
const result = [];
|
|
91
|
+
for (let i = 0; i < stopTimes.length; i++) {
|
|
92
|
+
const stopTime = itsOk(stopTimes[i]);
|
|
93
|
+
const gtfsIdMetadata = stopGtfsIdMapping.tryResolve(stopTime.stop_id);
|
|
94
|
+
if (gtfsIdMetadata == null) {
|
|
95
|
+
this._onError(new StopTimeReferencesUnmappedStopIdError(stopTime));
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const positionId = gtfsIdMetadata.type === "platform" ? gtfsIdMetadata.positionId : null;
|
|
99
|
+
const picksUp = this._doesPickUp(stopTime);
|
|
100
|
+
const dropsOff = this._doesDropOff(stopTime);
|
|
101
|
+
if (i === 0) {
|
|
102
|
+
result.push(new GtfsScheduledTripOriginatingMovement({
|
|
103
|
+
stopId: gtfsIdMetadata.stopId,
|
|
104
|
+
positionId,
|
|
105
|
+
departureTime: stopTime.departure_time,
|
|
106
|
+
gtfsIdMetadata,
|
|
107
|
+
gtfsStopSequence: stopTime.stop_sequence,
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
else if (i === stopTimes.length - 1) {
|
|
111
|
+
result.push(new GtfsScheduledTripTerminatingMovement({
|
|
112
|
+
stopId: gtfsIdMetadata.stopId,
|
|
113
|
+
positionId,
|
|
114
|
+
arrivalTime: stopTime.arrival_time,
|
|
115
|
+
gtfsIdMetadata,
|
|
116
|
+
gtfsStopSequence: stopTime.stop_sequence,
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
result.push(new GtfsScheduledTripRegularMovement({
|
|
121
|
+
stopId: gtfsIdMetadata.stopId,
|
|
122
|
+
positionId,
|
|
123
|
+
arrivalTime: stopTime.arrival_time,
|
|
124
|
+
departureTime: stopTime.departure_time,
|
|
125
|
+
picksUp,
|
|
126
|
+
dropsOff,
|
|
127
|
+
gtfsIdMetadata,
|
|
128
|
+
gtfsStopSequence: stopTime.stop_sequence,
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
_doesPickUp(stopTime) {
|
|
135
|
+
if (stopTime.pickup_type === STOP_TIME_PICKUP_TYPE_REGULAR) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
else if (stopTime.pickup_type === STOP_TIME_PICKUP_TYPE_NO_PICKUP) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
this._onError(new UnexpectedPickupTypeError(stopTime));
|
|
143
|
+
// If pickup_type is unexpected, let's just treat it like a normal stop. I
|
|
144
|
+
// don't think we need to exclude the whole trip for something as minor as
|
|
145
|
+
// mislabelling pick up only stops.
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
_doesDropOff(stopTime) {
|
|
150
|
+
if (stopTime.drop_off_type === STOP_TIME_DROP_OFF_TYPE_REGULAR) {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
else if (stopTime.drop_off_type === STOP_TIME_DROP_OFF_TYPE_NO_DROP_OFF) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
this._onError(new UnexpectedDropOffTypeError(stopTime));
|
|
158
|
+
// If drop_off_type is unexpected, let's just treat it like a normal stop.
|
|
159
|
+
// I don't think we need to exclude the whole trip for something as minor
|
|
160
|
+
// as mislabelling drop off only stops.
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
export class NoMatchingRouteError extends Error {
|
|
166
|
+
stopTimes;
|
|
167
|
+
resolvedStopIds;
|
|
168
|
+
type = "no-matching-route";
|
|
169
|
+
constructor(stopTimes, resolvedStopIds) {
|
|
170
|
+
super();
|
|
171
|
+
this.stopTimes = stopTimes;
|
|
172
|
+
this.resolvedStopIds = resolvedStopIds;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
export class StopTimeReferencesUnmappedStopIdError extends Error {
|
|
176
|
+
stopTime;
|
|
177
|
+
type = "stop-time-references-unmapped-stop-id";
|
|
178
|
+
constructor(stopTime) {
|
|
179
|
+
super();
|
|
180
|
+
this.stopTime = stopTime;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
export class UnexpectedPickupTypeError extends Error {
|
|
184
|
+
stopTime;
|
|
185
|
+
type = "unexpected-pickup-type";
|
|
186
|
+
constructor(stopTime) {
|
|
187
|
+
super();
|
|
188
|
+
this.stopTime = stopTime;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
export class UnexpectedDropOffTypeError extends Error {
|
|
192
|
+
stopTime;
|
|
193
|
+
type = "unexpected-drop-off-type";
|
|
194
|
+
constructor(stopTime) {
|
|
195
|
+
super();
|
|
196
|
+
this.stopTime = stopTime;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=gtfs-route-matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gtfs-route-matcher.js","sourceRoot":"","sources":["../../../src/parser/schedule/gtfs-route-matcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { GtfsScheduleData } from "../../data/gtfs-schedule-data.js";
|
|
2
|
+
import { type GtfsCalendarParsingError } from "./gtfs-calendar-parser.js";
|
|
3
|
+
import { type GtfsTripParsingError } from "./gtfs-trip-parser.js";
|
|
4
|
+
import type { LineGtfsIdMapping } from "../../data/ids/line-gtfs-id-mapping.js";
|
|
5
|
+
import type { StopGtfsIdMapping } from "../../data/ids/stop-gtfs-id-mapping.js";
|
|
6
|
+
import type { LineRoutesMapping } from "../../data/route/line-routes-mapping.js";
|
|
7
|
+
import type { BonusLinesMapping } from "../../data/route/bonus-lines-mapping.js";
|
|
8
|
+
import type { GtfsFeedCsv } from "../../data/raw/schedule-csvs.js";
|
|
9
|
+
export declare class GtfsScheduleParser {
|
|
10
|
+
private readonly _calendarParser;
|
|
11
|
+
private readonly _tripParser;
|
|
12
|
+
constructor(lineRoutesMapping: LineRoutesMapping, bonusLinesMapping: BonusLinesMapping, onError: (error: GtfsScheduleParsingError) => void);
|
|
13
|
+
parse(csvs: GtfsFeedCsv, lineGtfsIdMapping: LineGtfsIdMapping, stopGtfsIdMapping: StopGtfsIdMapping): GtfsScheduleData;
|
|
14
|
+
}
|
|
15
|
+
export type GtfsScheduleParsingError = GtfsCalendarParsingError | GtfsTripParsingError;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { GtfsScheduleData } from "../../data/gtfs-schedule-data.js";
|
|
2
|
+
import { GtfsCalendarParser, } from "./gtfs-calendar-parser.js";
|
|
3
|
+
import { GtfsTripParser, } from "./gtfs-trip-parser.js";
|
|
4
|
+
// TODO: Rename GtfsScheduleDataParser.
|
|
5
|
+
export class GtfsScheduleParser {
|
|
6
|
+
_calendarParser;
|
|
7
|
+
_tripParser;
|
|
8
|
+
constructor(lineRoutesMapping, bonusLinesMapping, onError) {
|
|
9
|
+
this._calendarParser = new GtfsCalendarParser(onError);
|
|
10
|
+
this._tripParser = new GtfsTripParser(lineRoutesMapping, bonusLinesMapping, onError);
|
|
11
|
+
}
|
|
12
|
+
parse(csvs, lineGtfsIdMapping, stopGtfsIdMapping) {
|
|
13
|
+
const { calendar, calendarDates, trips, stopTimes, transfers } = csvs;
|
|
14
|
+
const parsedCalendars = this._calendarParser.parse(calendar, calendarDates);
|
|
15
|
+
const parsedTrips = this._tripParser.parse(trips, stopTimes, transfers, parsedCalendars, lineGtfsIdMapping, stopGtfsIdMapping);
|
|
16
|
+
return new GtfsScheduleData(parsedTrips, parsedCalendars);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=gtfs-schedule-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gtfs-schedule-parser.js","sourceRoot":"","sources":["../../../src/parser/schedule/gtfs-schedule-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EACL,kBAAkB,GAEnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,cAAc,GAEf,MAAM,uBAAuB,CAAC;AAO/B,uCAAuC;AACvC,MAAM,OAAO,kBAAkB;IACZ,eAAe,CAAqB;IACpC,WAAW,CAAiB;IAE7C,YACE,iBAAoC,EACpC,iBAAoC,EACpC,OAAkD;QAElD,IAAI,CAAC,eAAe,GAAG,IAAI,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,WAAW,GAAG,IAAI,cAAc,CACnC,iBAAiB,EACjB,iBAAiB,EACjB,OAAO,CACR,CAAC;IACJ,CAAC;IAED,KAAK,CACH,IAAiB,EACjB,iBAAoC,EACpC,iBAAoC;QAEpC,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;QAEtE,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAE5E,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CACxC,KAAK,EACL,SAAS,EACT,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,iBAAiB,CAClB,CAAC;QAEF,OAAO,IAAI,gBAAgB,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;IAC5D,CAAC;CACF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { StopTimesCsv } from "../../data/raw/schedule-csvs.js";
|
|
2
|
+
/**
|
|
3
|
+
* Responsible for checking that in a list of stop times, the stop_sequence
|
|
4
|
+
* values start from 1 and increment by 1 each time. Where stop_sequence values
|
|
5
|
+
* are duplicated, this classes uses the earlier stop time for that stop. Any
|
|
6
|
+
* deviation from the incrementing pattern is reported and then rectified as
|
|
7
|
+
* best as possible.
|
|
8
|
+
*/
|
|
9
|
+
export declare class GtfsStopTimeNormaliser {
|
|
10
|
+
private readonly _onError;
|
|
11
|
+
constructor(_onError: (error: GtfsStopTimeNormalisationError) => void);
|
|
12
|
+
normalise(unsortedStopTimes: StopTimesCsv): StopTimesCsv | null;
|
|
13
|
+
/**
|
|
14
|
+
* Returns true if the stop times make a perfect sequence starting from 1, and
|
|
15
|
+
* is at least of length 2.
|
|
16
|
+
*/
|
|
17
|
+
private _isRegular;
|
|
18
|
+
/**
|
|
19
|
+
* Returns true if the stop times (unsorted, so in the order given in
|
|
20
|
+
* stop_times.csv) form one or more regular sequences restarting at 1 each
|
|
21
|
+
* time. The only caveat is that all sequences must be at least of length 2.
|
|
22
|
+
*
|
|
23
|
+
* Valid:
|
|
24
|
+
* - `1, 2, 3, 4, 1, 2, 3`
|
|
25
|
+
*
|
|
26
|
+
* Invalid:
|
|
27
|
+
* - `1, 2, 3, 2, 3, 4`
|
|
28
|
+
* - `1, 2, 4, 5, 6, 1, 2`
|
|
29
|
+
* - `1, 2, 3, 1, 1, 2, 3`
|
|
30
|
+
* - `1`
|
|
31
|
+
* - `1, 1, 1`
|
|
32
|
+
*/
|
|
33
|
+
private _isMultipleRegularSequences;
|
|
34
|
+
private _extractFirstRegularSequence;
|
|
35
|
+
private _requiresTimeTravelInFirstRegularSequence;
|
|
36
|
+
}
|
|
37
|
+
export type GtfsStopTimeNormalisationError = InvalidStopSequenceError | MultipleStopSequencesError;
|
|
38
|
+
export declare class InvalidStopSequenceError extends Error {
|
|
39
|
+
readonly stopTimes: StopTimesCsv;
|
|
40
|
+
readonly type = "stop-sequence-duplicated";
|
|
41
|
+
constructor(stopTimes: StopTimesCsv);
|
|
42
|
+
}
|
|
43
|
+
export declare class MultipleStopSequencesError extends Error {
|
|
44
|
+
readonly stopTimes: StopTimesCsv;
|
|
45
|
+
readonly type = "multiple-stop-sequences";
|
|
46
|
+
constructor(stopTimes: StopTimesCsv);
|
|
47
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Responsible for checking that in a list of stop times, the stop_sequence
|
|
3
|
+
* values start from 1 and increment by 1 each time. Where stop_sequence values
|
|
4
|
+
* are duplicated, this classes uses the earlier stop time for that stop. Any
|
|
5
|
+
* deviation from the incrementing pattern is reported and then rectified as
|
|
6
|
+
* best as possible.
|
|
7
|
+
*/
|
|
8
|
+
export class GtfsStopTimeNormaliser {
|
|
9
|
+
_onError;
|
|
10
|
+
constructor(_onError) {
|
|
11
|
+
this._onError = _onError;
|
|
12
|
+
}
|
|
13
|
+
normalise(unsortedStopTimes) {
|
|
14
|
+
const sortedStopTimes = [...unsortedStopTimes].sort((a, b) => a.stop_sequence - b.stop_sequence);
|
|
15
|
+
if (this._isRegular(sortedStopTimes))
|
|
16
|
+
return sortedStopTimes;
|
|
17
|
+
// Sometimes we've seen trips in the regional feed where the rows are
|
|
18
|
+
// duplicated (sometimes with different arrival/departure times). In these
|
|
19
|
+
// cases, it seems like Google Maps just uses whichever sequence comes
|
|
20
|
+
// first, so that's what this code is doing.
|
|
21
|
+
//
|
|
22
|
+
// In an ideal future world, if we detect that both trips contain the same
|
|
23
|
+
// stops, we should use the earliest departure times for each stop to be
|
|
24
|
+
// pessimistic (and still show the other sequence of stopping times as a
|
|
25
|
+
// disruption about having ambiguous stopping times).
|
|
26
|
+
if (this._isMultipleRegularSequences(unsortedStopTimes)) {
|
|
27
|
+
this._onError(new MultipleStopSequencesError(unsortedStopTimes));
|
|
28
|
+
return this._extractFirstRegularSequence(unsortedStopTimes);
|
|
29
|
+
}
|
|
30
|
+
// Are there any other cases we can handle gracefully? I expect we might see
|
|
31
|
+
// some other cases pop up in the future, but this is all I know for now!
|
|
32
|
+
//
|
|
33
|
+
// ⚠️ IMPORTANT: This class is meant to output the stop times in the order
|
|
34
|
+
// they should be interpreted as for TrainQuery. It should NOT modify the
|
|
35
|
+
// stop_sequence values themselves (i.e. if there's gaps, leave them in)
|
|
36
|
+
// because we may need to use those when matching updates in the GTFS-RT
|
|
37
|
+
// feed to certain stops on the trip.
|
|
38
|
+
this._onError(new InvalidStopSequenceError(unsortedStopTimes));
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Returns true if the stop times make a perfect sequence starting from 1, and
|
|
43
|
+
* is at least of length 2.
|
|
44
|
+
*/
|
|
45
|
+
_isRegular(sortedStopTimes) {
|
|
46
|
+
return (sortedStopTimes.length >= 2 &&
|
|
47
|
+
sortedStopTimes.every((x, i) => x.stop_sequence === i + 1) &&
|
|
48
|
+
!this._requiresTimeTravelInFirstRegularSequence(sortedStopTimes));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Returns true if the stop times (unsorted, so in the order given in
|
|
52
|
+
* stop_times.csv) form one or more regular sequences restarting at 1 each
|
|
53
|
+
* time. The only caveat is that all sequences must be at least of length 2.
|
|
54
|
+
*
|
|
55
|
+
* Valid:
|
|
56
|
+
* - `1, 2, 3, 4, 1, 2, 3`
|
|
57
|
+
*
|
|
58
|
+
* Invalid:
|
|
59
|
+
* - `1, 2, 3, 2, 3, 4`
|
|
60
|
+
* - `1, 2, 4, 5, 6, 1, 2`
|
|
61
|
+
* - `1, 2, 3, 1, 1, 2, 3`
|
|
62
|
+
* - `1`
|
|
63
|
+
* - `1, 1, 1`
|
|
64
|
+
*/
|
|
65
|
+
_isMultipleRegularSequences(unsortedStopTimes) {
|
|
66
|
+
let expectedStopSequence = 1;
|
|
67
|
+
for (const stopTime of unsortedStopTimes) {
|
|
68
|
+
if (stopTime.stop_sequence === expectedStopSequence) {
|
|
69
|
+
expectedStopSequence++;
|
|
70
|
+
}
|
|
71
|
+
else if (stopTime.stop_sequence === 1 && expectedStopSequence > 2) {
|
|
72
|
+
expectedStopSequence = 2;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// If we left the loop where we'd next expect a 3 (or more), then we must've
|
|
79
|
+
// found (at least) 2 stops in the last sequence.
|
|
80
|
+
const lastSequenceHadAtLeastTwoStops = expectedStopSequence > 2;
|
|
81
|
+
return (lastSequenceHadAtLeastTwoStops &&
|
|
82
|
+
!this._requiresTimeTravelInFirstRegularSequence(unsortedStopTimes));
|
|
83
|
+
}
|
|
84
|
+
_extractFirstRegularSequence(stopTimes) {
|
|
85
|
+
return stopTimes.filter((x, i) => x.stop_sequence === i + 1);
|
|
86
|
+
}
|
|
87
|
+
_requiresTimeTravelInFirstRegularSequence(stopTimes) {
|
|
88
|
+
return stopTimes.some((x, i) => {
|
|
89
|
+
// We're ignoring everything after the first regular sequence.
|
|
90
|
+
if (x.stop_sequence !== i + 1)
|
|
91
|
+
return false;
|
|
92
|
+
if (x.arrival_time.isAfter(x.departure_time))
|
|
93
|
+
return true;
|
|
94
|
+
const previousStopTime = stopTimes[i - 1];
|
|
95
|
+
if (previousStopTime != null &&
|
|
96
|
+
previousStopTime.departure_time.isAfter(x.arrival_time)) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export class InvalidStopSequenceError extends Error {
|
|
104
|
+
stopTimes;
|
|
105
|
+
type = "stop-sequence-duplicated";
|
|
106
|
+
constructor(stopTimes) {
|
|
107
|
+
super();
|
|
108
|
+
this.stopTimes = stopTimes;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
export class MultipleStopSequencesError extends Error {
|
|
112
|
+
stopTimes;
|
|
113
|
+
type = "multiple-stop-sequences";
|
|
114
|
+
constructor(stopTimes) {
|
|
115
|
+
super();
|
|
116
|
+
this.stopTimes = stopTimes;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=gtfs-stop-time-normaliser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gtfs-stop-time-normaliser.js","sourceRoot":"","sources":["../../../src/parser/schedule/gtfs-stop-time-normaliser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { TransfersCsv, TransfersCsvRow } from "../../data/raw/schedule-csvs.js";
|
|
2
|
+
import { GtfsScheduledTrip } from "../../data/gtfs-scheduled-trip.js";
|
|
3
|
+
export declare class GtfsTransferConnector {
|
|
4
|
+
private readonly _onError;
|
|
5
|
+
constructor(_onError: (error: GtfsTransferConnectionError) => void);
|
|
6
|
+
connect(trips: readonly GtfsScheduledTrip[], transfers: TransfersCsv): readonly GtfsScheduledTrip[];
|
|
7
|
+
}
|
|
8
|
+
export type GtfsTransferConnectionError = TransferReferencesNonExistentTrip | TransferIsNotFromTerminusError | TransferIsNotToOriginError | TransferReferencesTripAlreadyConnectedError | TransferIsNotInSeatTransferError | TransferIsNotSameStopAndPositionError | TransferCrossesCalendarsError | TransferRequiresTimeTravelError;
|
|
9
|
+
export declare class TransferReferencesNonExistentTrip extends Error {
|
|
10
|
+
readonly transfer: TransfersCsvRow;
|
|
11
|
+
readonly field: "from_trip_id" | "to_trip_id";
|
|
12
|
+
readonly type = "transfer-references-non-existent-trip";
|
|
13
|
+
constructor(transfer: TransfersCsvRow, field: "from_trip_id" | "to_trip_id");
|
|
14
|
+
}
|
|
15
|
+
export declare class TransferIsNotFromTerminusError extends Error {
|
|
16
|
+
readonly transfer: TransfersCsvRow;
|
|
17
|
+
readonly fromTrip: GtfsScheduledTrip;
|
|
18
|
+
readonly type = "transfer-is-not-from-terminus";
|
|
19
|
+
constructor(transfer: TransfersCsvRow, fromTrip: GtfsScheduledTrip);
|
|
20
|
+
}
|
|
21
|
+
export declare class TransferIsNotToOriginError extends Error {
|
|
22
|
+
readonly transfer: TransfersCsvRow;
|
|
23
|
+
readonly toTrip: GtfsScheduledTrip;
|
|
24
|
+
readonly type = "transfer-is-not-to-origin";
|
|
25
|
+
constructor(transfer: TransfersCsvRow, toTrip: GtfsScheduledTrip);
|
|
26
|
+
}
|
|
27
|
+
export declare class TransferReferencesTripAlreadyConnectedError extends Error {
|
|
28
|
+
readonly transfer: TransfersCsvRow;
|
|
29
|
+
readonly tripWithExistingConnection: GtfsScheduledTrip;
|
|
30
|
+
readonly type = "transfer-references-trip-already-connected";
|
|
31
|
+
constructor(transfer: TransfersCsvRow, tripWithExistingConnection: GtfsScheduledTrip);
|
|
32
|
+
}
|
|
33
|
+
export declare class TransferIsNotInSeatTransferError extends Error {
|
|
34
|
+
readonly transfer: TransfersCsvRow;
|
|
35
|
+
readonly type = "transfer-is-not-in-seat-transfer";
|
|
36
|
+
constructor(transfer: TransfersCsvRow);
|
|
37
|
+
}
|
|
38
|
+
export declare class TransferIsNotSameStopAndPositionError extends Error {
|
|
39
|
+
readonly transfer: TransfersCsvRow;
|
|
40
|
+
readonly type = "transfer-is-not-same-stop-and-position";
|
|
41
|
+
constructor(transfer: TransfersCsvRow);
|
|
42
|
+
}
|
|
43
|
+
export declare class TransferCrossesCalendarsError extends Error {
|
|
44
|
+
readonly transfer: TransfersCsvRow;
|
|
45
|
+
readonly type = "transfer-crosses-calendars";
|
|
46
|
+
constructor(transfer: TransfersCsvRow);
|
|
47
|
+
}
|
|
48
|
+
export declare class TransferRequiresTimeTravelError extends Error {
|
|
49
|
+
readonly transfer: TransfersCsvRow;
|
|
50
|
+
readonly type = "transfer-requires-time-travel";
|
|
51
|
+
constructor(transfer: TransfersCsvRow);
|
|
52
|
+
}
|