minotor 7.0.2 → 8.0.0

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.
Files changed (58) hide show
  1. package/.cspell.json +11 -1
  2. package/CHANGELOG.md +8 -3
  3. package/README.md +26 -24
  4. package/dist/cli.mjs +1243 -267
  5. package/dist/cli.mjs.map +1 -1
  6. package/dist/gtfs/transfers.d.ts +13 -4
  7. package/dist/gtfs/trips.d.ts +12 -7
  8. package/dist/parser.cjs.js +494 -71
  9. package/dist/parser.cjs.js.map +1 -1
  10. package/dist/parser.esm.js +494 -71
  11. package/dist/parser.esm.js.map +1 -1
  12. package/dist/router.cjs.js +1 -1
  13. package/dist/router.cjs.js.map +1 -1
  14. package/dist/router.d.ts +2 -2
  15. package/dist/router.esm.js +1 -1
  16. package/dist/router.esm.js.map +1 -1
  17. package/dist/router.umd.js +1 -1
  18. package/dist/router.umd.js.map +1 -1
  19. package/dist/routing/__tests__/plotter.test.d.ts +1 -0
  20. package/dist/routing/plotter.d.ts +42 -3
  21. package/dist/routing/result.d.ts +23 -7
  22. package/dist/routing/route.d.ts +2 -0
  23. package/dist/routing/router.d.ts +78 -19
  24. package/dist/timetable/__tests__/tripId.test.d.ts +1 -0
  25. package/dist/timetable/io.d.ts +4 -2
  26. package/dist/timetable/proto/timetable.d.ts +13 -1
  27. package/dist/timetable/route.d.ts +41 -8
  28. package/dist/timetable/timetable.d.ts +18 -3
  29. package/dist/timetable/tripId.d.ts +15 -0
  30. package/package.json +1 -1
  31. package/src/__e2e__/router.test.ts +114 -105
  32. package/src/__e2e__/timetable/stops.bin +2 -2
  33. package/src/__e2e__/timetable/timetable.bin +2 -2
  34. package/src/cli/repl.ts +259 -1
  35. package/src/gtfs/__tests__/transfers.test.ts +468 -12
  36. package/src/gtfs/__tests__/trips.test.ts +350 -28
  37. package/src/gtfs/parser.ts +16 -4
  38. package/src/gtfs/transfers.ts +61 -18
  39. package/src/gtfs/trips.ts +97 -22
  40. package/src/router.ts +2 -2
  41. package/src/routing/__tests__/plotter.test.ts +230 -0
  42. package/src/routing/__tests__/result.test.ts +486 -125
  43. package/src/routing/__tests__/route.test.ts +7 -3
  44. package/src/routing/__tests__/router.test.ts +378 -172
  45. package/src/routing/plotter.ts +279 -48
  46. package/src/routing/result.ts +114 -34
  47. package/src/routing/route.ts +0 -3
  48. package/src/routing/router.ts +332 -211
  49. package/src/timetable/__tests__/io.test.ts +33 -1
  50. package/src/timetable/__tests__/route.test.ts +10 -3
  51. package/src/timetable/__tests__/timetable.test.ts +225 -57
  52. package/src/timetable/__tests__/tripId.test.ts +27 -0
  53. package/src/timetable/io.ts +71 -10
  54. package/src/timetable/proto/timetable.proto +14 -2
  55. package/src/timetable/proto/timetable.ts +218 -20
  56. package/src/timetable/route.ts +152 -19
  57. package/src/timetable/timetable.ts +45 -6
  58. package/src/timetable/tripId.ts +29 -0
@@ -9,37 +9,56 @@ import { ServiceRoute } from '../../timetable/timetable.js';
9
9
  import { GtfsRoutesMap } from '../routes.js';
10
10
  import { ServiceIds } from '../services.js';
11
11
  import { GtfsStopsMap } from '../stops.js';
12
- import { TransfersMap } from '../transfers.js';
12
+ import { TransfersMap, TripContinuationsMap } from '../transfers.js';
13
13
  import {
14
14
  buildStopsAdjacencyStructure,
15
15
  encodePickUpDropOffTypes,
16
+ GtfsTripIdsMap,
16
17
  parseStopTimes,
17
18
  parseTrips,
18
- TripIdsMap,
19
+ TripsMapping,
19
20
  } from '../trips.js';
20
21
 
21
22
  describe('buildStopsAdjacencyStructure', () => {
22
23
  it('should correctly build stops adjacency for valid routes and transfers', () => {
23
24
  const validStops: Set<StopId> = new Set([0]);
24
- const routesAdjacency = [
25
- new Route(
26
- new Uint16Array(),
27
- new Uint8Array(),
28
- new Uint32Array([0, 1]),
29
- 0,
30
- ),
25
+ const routes = [
26
+ Route.of({
27
+ id: 0,
28
+ serviceRouteId: 0,
29
+ trips: [
30
+ {
31
+ stops: [
32
+ {
33
+ id: 0,
34
+ arrivalTime: Time.fromHMS(8, 0, 0),
35
+ departureTime: Time.fromHMS(8, 0, 0),
36
+ },
37
+ {
38
+ id: 1,
39
+ arrivalTime: Time.fromHMS(8, 5, 0),
40
+ departureTime: Time.fromHMS(8, 5, 0),
41
+ },
42
+ ],
43
+ },
44
+ ],
45
+ }),
31
46
  ];
32
47
  const transfersMap: TransfersMap = new Map([
33
48
  [0, [{ destination: 1, type: 'RECOMMENDED' }]],
34
49
  ]);
50
+ const tripContinuationsMap: TripContinuationsMap = new Map();
35
51
  const serviceRoutes: ServiceRoute[] = [
36
52
  { type: 'BUS', name: 'B1', routes: [] },
37
53
  ];
54
+ const tripsMapping: TripsMapping = new Map();
38
55
 
39
56
  const stopsAdjacency = buildStopsAdjacencyStructure(
57
+ tripsMapping,
40
58
  serviceRoutes,
41
- routesAdjacency,
59
+ routes,
42
60
  transfersMap,
61
+ tripContinuationsMap,
43
62
  2,
44
63
  validStops,
45
64
  );
@@ -61,7 +80,6 @@ describe('buildStopsAdjacencyStructure', () => {
61
80
  1,
62
81
  {
63
82
  routes: [],
64
- transfers: [],
65
83
  },
66
84
  ],
67
85
  ]);
@@ -70,25 +88,43 @@ describe('buildStopsAdjacencyStructure', () => {
70
88
 
71
89
  it('should ignore transfers to invalid stops', () => {
72
90
  const validStops: Set<StopId> = new Set([0, 1]);
73
- const routesAdjacency = [
74
- new Route(
75
- new Uint16Array(),
76
- new Uint8Array(),
77
- new Uint32Array([0, 1]),
78
- 0,
79
- ),
91
+ const routes = [
92
+ Route.of({
93
+ id: 0,
94
+ serviceRouteId: 0,
95
+ trips: [
96
+ {
97
+ stops: [
98
+ {
99
+ id: 0,
100
+ arrivalTime: Time.fromHMS(8, 0, 0),
101
+ departureTime: Time.fromHMS(8, 0, 0),
102
+ },
103
+ {
104
+ id: 1,
105
+ arrivalTime: Time.fromHMS(8, 5, 0),
106
+ departureTime: Time.fromHMS(8, 5, 0),
107
+ },
108
+ ],
109
+ },
110
+ ],
111
+ }),
80
112
  ];
81
113
  const transfersMap: TransfersMap = new Map([
82
114
  [3, [{ destination: 2, type: 'RECOMMENDED' }]],
83
115
  ]);
116
+ const tripContinuationsMap: TripContinuationsMap = new Map();
84
117
  const serviceRoutes: ServiceRoute[] = [
85
118
  { type: 'BUS', name: 'B1', routes: [] },
86
119
  ];
120
+ const tripsMapping: TripsMapping = new Map();
87
121
 
88
122
  const stopsAdjacency = buildStopsAdjacencyStructure(
123
+ tripsMapping,
89
124
  serviceRoutes,
90
- routesAdjacency,
125
+ routes,
91
126
  transfersMap,
127
+ tripContinuationsMap,
92
128
  4,
93
129
  validStops,
94
130
  );
@@ -98,33 +134,227 @@ describe('buildStopsAdjacencyStructure', () => {
98
134
  0,
99
135
  {
100
136
  routes: [0],
101
- transfers: [],
102
137
  },
103
138
  ],
104
139
  [
105
140
  1,
106
141
  {
107
142
  routes: [0],
108
- transfers: [],
109
143
  },
110
144
  ],
111
145
  [
112
146
  2,
113
147
  {
114
148
  routes: [],
115
- transfers: [],
116
149
  },
117
150
  ],
118
151
  [
119
152
  3,
120
153
  {
121
154
  routes: [],
122
- transfers: [],
123
155
  },
124
156
  ],
125
157
  ]);
126
158
  assert.deepEqual(serviceRoutes[0]?.routes, [0]);
127
159
  });
160
+
161
+ it('should correctly handle trip continuations', () => {
162
+ const validStops: Set<StopId> = new Set([0, 1]);
163
+ const routes = [
164
+ Route.of({
165
+ id: 0,
166
+ serviceRouteId: 0,
167
+ trips: [
168
+ {
169
+ stops: [
170
+ {
171
+ id: 0,
172
+ arrivalTime: Time.fromHMS(8, 0, 0),
173
+ departureTime: Time.fromHMS(8, 0, 0),
174
+ },
175
+ ],
176
+ },
177
+ ],
178
+ }),
179
+ Route.of({
180
+ id: 1,
181
+ serviceRouteId: 0,
182
+ trips: [
183
+ {
184
+ stops: [
185
+ {
186
+ id: 1,
187
+ arrivalTime: Time.fromHMS(8, 30, 0),
188
+ departureTime: Time.fromHMS(8, 30, 0),
189
+ },
190
+ ],
191
+ },
192
+ ],
193
+ }),
194
+ ];
195
+ const transfersMap: TransfersMap = new Map();
196
+ const tripContinuationsMap: TripContinuationsMap = new Map([
197
+ [0, [{ fromTrip: 'trip1', toTrip: 'trip2', hopOnStop: 1 }]],
198
+ ]);
199
+ const serviceRoutes: ServiceRoute[] = [
200
+ { type: 'BUS', name: 'B1', routes: [] },
201
+ ];
202
+ const tripsMapping: TripsMapping = new Map([
203
+ ['trip1', { routeId: 0, tripRouteIndex: 0 }],
204
+ ['trip2', { routeId: 1, tripRouteIndex: 0 }],
205
+ ]);
206
+
207
+ const stopsAdjacency = buildStopsAdjacencyStructure(
208
+ tripsMapping,
209
+ serviceRoutes,
210
+ routes,
211
+ transfersMap,
212
+ tripContinuationsMap,
213
+ 2,
214
+ validStops,
215
+ );
216
+
217
+ assert.deepEqual(Array.from(stopsAdjacency.entries()), [
218
+ [
219
+ 0,
220
+ {
221
+ routes: [0],
222
+ tripContinuations: new Map([
223
+ [0, [{ hopOnStop: 1, routeId: 1, tripIndex: 0 }]],
224
+ ]),
225
+ },
226
+ ],
227
+ [
228
+ 1,
229
+ {
230
+ routes: [1],
231
+ },
232
+ ],
233
+ ]);
234
+ });
235
+
236
+ it('should ignore trip continuations with invalid trip IDs', () => {
237
+ const validStops: Set<StopId> = new Set([0]);
238
+ const routes = [
239
+ Route.of({
240
+ id: 0,
241
+ serviceRouteId: 0,
242
+ trips: [
243
+ {
244
+ stops: [
245
+ {
246
+ id: 0,
247
+ arrivalTime: Time.fromHMS(8, 0, 0),
248
+ departureTime: Time.fromHMS(8, 0, 0),
249
+ },
250
+ ],
251
+ },
252
+ ],
253
+ }),
254
+ ];
255
+ const transfersMap: TransfersMap = new Map();
256
+ const tripContinuationsMap: TripContinuationsMap = new Map([
257
+ [
258
+ 0,
259
+ [{ fromTrip: 'invalid_trip', toTrip: 'invalid_trip2', hopOnStop: 1 }],
260
+ ],
261
+ ]);
262
+ const serviceRoutes: ServiceRoute[] = [
263
+ { type: 'BUS', name: 'B1', routes: [] },
264
+ ];
265
+ const tripsMapping: TripsMapping = new Map([
266
+ ['trip1', { routeId: 0, tripRouteIndex: 0 }],
267
+ ]);
268
+
269
+ const stopsAdjacency = buildStopsAdjacencyStructure(
270
+ tripsMapping,
271
+ serviceRoutes,
272
+ routes,
273
+ transfersMap,
274
+ tripContinuationsMap,
275
+ 1,
276
+ validStops,
277
+ );
278
+
279
+ assert.deepEqual(Array.from(stopsAdjacency.entries()), [
280
+ [
281
+ 0,
282
+ {
283
+ routes: [0],
284
+ tripContinuations: new Map(),
285
+ },
286
+ ],
287
+ ]);
288
+ });
289
+
290
+ it('should ignore trip continuations for inactive stops', () => {
291
+ const validStops: Set<StopId> = new Set([0]); // Only stop 0 is active
292
+ const routes = [
293
+ Route.of({
294
+ id: 0,
295
+ serviceRouteId: 0,
296
+ trips: [
297
+ {
298
+ stops: [
299
+ {
300
+ id: 0,
301
+ arrivalTime: Time.fromHMS(8, 0, 0),
302
+ departureTime: Time.fromHMS(8, 0, 0),
303
+ },
304
+ ],
305
+ },
306
+ ],
307
+ }),
308
+ ];
309
+ const transfersMap: TransfersMap = new Map();
310
+ const tripContinuationsMap: TripContinuationsMap = new Map([
311
+ [2, [{ fromTrip: 'trip1', toTrip: 'trip2', hopOnStop: 3 }]], // Stop 2 and 3 are inactive
312
+ ]);
313
+ const serviceRoutes: ServiceRoute[] = [
314
+ { type: 'BUS', name: 'B1', routes: [] },
315
+ ];
316
+ const tripsMapping: TripsMapping = new Map([
317
+ ['trip1', { routeId: 0, tripRouteIndex: 0 }],
318
+ ['trip2', { routeId: 0, tripRouteIndex: 1 }],
319
+ ]);
320
+
321
+ const stopsAdjacency = buildStopsAdjacencyStructure(
322
+ tripsMapping,
323
+ serviceRoutes,
324
+ routes,
325
+ transfersMap,
326
+ tripContinuationsMap,
327
+ 4, // 4 stops total but only stop 0 is active
328
+ validStops,
329
+ );
330
+
331
+ assert.deepEqual(Array.from(stopsAdjacency.entries()), [
332
+ [
333
+ 0,
334
+ {
335
+ routes: [0],
336
+ },
337
+ ],
338
+ [
339
+ 1,
340
+ {
341
+ routes: [],
342
+ },
343
+ ],
344
+ [
345
+ 2,
346
+ {
347
+ routes: [],
348
+ },
349
+ ],
350
+ [
351
+ 3,
352
+ {
353
+ routes: [],
354
+ },
355
+ ],
356
+ ]);
357
+ });
128
358
  });
129
359
  describe('GTFS trips parser', () => {
130
360
  it('should correctly parse valid trips', async () => {
@@ -207,7 +437,7 @@ describe('GTFS stop times parser', () => {
207
437
  mockedStream.push('"tripA","08:10:00","08:15:00","stop2","2","0","0"\n');
208
438
  mockedStream.push(null);
209
439
 
210
- const validTripIds: TripIdsMap = new Map([['tripA', 'routeA']]);
440
+ const validTripIds: GtfsTripIdsMap = new Map([['tripA', 'routeA']]);
211
441
  const validStopIds: Set<StopId> = new Set([0, 1]);
212
442
  const stopsMap: GtfsStopsMap = new Map([
213
443
  [
@@ -243,6 +473,7 @@ describe('GTFS stop times parser', () => {
243
473
  );
244
474
  assert.deepEqual(result.routes, [
245
475
  new Route(
476
+ 0,
246
477
  new Uint16Array([
247
478
  Time.fromHMS(8, 0, 0).toMinutes(),
248
479
  Time.fromHMS(8, 5, 0).toMinutes(),
@@ -254,6 +485,10 @@ describe('GTFS stop times parser', () => {
254
485
  0,
255
486
  ),
256
487
  ]);
488
+ assert.deepEqual(
489
+ result.tripsMapping,
490
+ new Map([['tripA', { routeId: 0, tripRouteIndex: 0 }]]),
491
+ );
257
492
  });
258
493
 
259
494
  it('should create same route for same GTFS route with same stops', async () => {
@@ -267,7 +502,7 @@ describe('GTFS stop times parser', () => {
267
502
  mockedStream.push('"tripB","09:10:00","09:15:00","stop2","2","0","0"\n');
268
503
  mockedStream.push(null);
269
504
 
270
- const validTripIds: TripIdsMap = new Map([
505
+ const validTripIds: GtfsTripIdsMap = new Map([
271
506
  ['tripA', 'routeA'],
272
507
  ['tripB', 'routeA'],
273
508
  ]);
@@ -303,6 +538,7 @@ describe('GTFS stop times parser', () => {
303
538
  );
304
539
  assert.deepEqual(result.routes, [
305
540
  new Route(
541
+ 0,
306
542
  new Uint16Array([
307
543
  Time.fromHMS(8, 0, 0).toMinutes(),
308
544
  Time.fromHMS(8, 5, 0).toMinutes(),
@@ -321,6 +557,13 @@ describe('GTFS stop times parser', () => {
321
557
  0,
322
558
  ),
323
559
  ]);
560
+ assert.deepEqual(
561
+ result.tripsMapping,
562
+ new Map([
563
+ ['tripA', { routeId: 0, tripRouteIndex: 0 }],
564
+ ['tripB', { routeId: 0, tripRouteIndex: 1 }],
565
+ ]),
566
+ );
324
567
  });
325
568
 
326
569
  it('should support unsorted trips within a route', async () => {
@@ -334,7 +577,7 @@ describe('GTFS stop times parser', () => {
334
577
  mockedStream.push('"tripA","08:10:00","08:15:00","stop2","2","0","0"\n');
335
578
  mockedStream.push(null);
336
579
 
337
- const validTripIds: TripIdsMap = new Map([
580
+ const validTripIds: GtfsTripIdsMap = new Map([
338
581
  ['tripA', 'routeA'],
339
582
  ['tripB', 'routeA'],
340
583
  ]);
@@ -370,6 +613,7 @@ describe('GTFS stop times parser', () => {
370
613
  );
371
614
  assert.deepEqual(result.routes, [
372
615
  new Route(
616
+ 0,
373
617
  new Uint16Array([
374
618
  Time.fromHMS(8, 0, 0).toMinutes(),
375
619
  Time.fromHMS(8, 5, 0).toMinutes(),
@@ -400,7 +644,7 @@ describe('GTFS stop times parser', () => {
400
644
  mockedStream.push('"tripB","09:00:00","09:15:00","stop1","1","0","0"\n');
401
645
  mockedStream.push(null);
402
646
 
403
- const validTripIds: TripIdsMap = new Map([
647
+ const validTripIds: GtfsTripIdsMap = new Map([
404
648
  ['tripA', 'routeA'],
405
649
  ['tripB', 'routeA'],
406
650
  ]);
@@ -436,6 +680,7 @@ describe('GTFS stop times parser', () => {
436
680
  );
437
681
  assert.deepEqual(result.routes, [
438
682
  new Route(
683
+ 0,
439
684
  new Uint16Array([
440
685
  Time.fromHMS(8, 0, 0).toMinutes(),
441
686
  Time.fromHMS(8, 5, 0).toMinutes(),
@@ -447,6 +692,7 @@ describe('GTFS stop times parser', () => {
447
692
  0,
448
693
  ),
449
694
  new Route(
695
+ 1,
450
696
  new Uint16Array([
451
697
  Time.fromHMS(9, 0, 0).toMinutes(),
452
698
  Time.fromHMS(9, 15, 0).toMinutes(),
@@ -467,7 +713,7 @@ describe('GTFS stop times parser', () => {
467
713
  mockedStream.push('"tripA","08:10:00","08:15:00","stop2","1","0","0"\n');
468
714
  mockedStream.push(null);
469
715
 
470
- const validTripIds: TripIdsMap = new Map([['tripA', 'routeA']]);
716
+ const validTripIds: GtfsTripIdsMap = new Map([['tripA', 'routeA']]);
471
717
  const validStopIds: Set<StopId> = new Set([0, 1]);
472
718
  const stopsMap: GtfsStopsMap = new Map([
473
719
  [
@@ -500,6 +746,7 @@ describe('GTFS stop times parser', () => {
500
746
  );
501
747
  assert.deepEqual(result.routes, [
502
748
  new Route(
749
+ 0,
503
750
  new Uint16Array([
504
751
  Time.fromHMS(8, 0, 0).toMinutes(),
505
752
  Time.fromHMS(8, 5, 0).toMinutes(),
@@ -509,5 +756,80 @@ describe('GTFS stop times parser', () => {
509
756
  0,
510
757
  ),
511
758
  ]);
759
+ assert.deepEqual(
760
+ result.tripsMapping,
761
+ new Map([['tripA', { routeId: 0, tripRouteIndex: 0 }]]),
762
+ );
763
+ });
764
+
765
+ it('should create trip continuations mapping correctly', async () => {
766
+ const mockedStream = new Readable();
767
+ mockedStream.push(
768
+ 'trip_id,arrival_time,departure_time,stop_id,stop_sequence,pickup_type,drop_off_type\n',
769
+ );
770
+ mockedStream.push('"trip1","08:00:00","08:05:00","stop1","1","0","0"\n');
771
+ mockedStream.push('"trip1","08:10:00","08:15:00","stop2","2","0","0"\n');
772
+ mockedStream.push('"trip2","09:00:00","09:05:00","stop3","1","0","0"\n');
773
+ mockedStream.push(null);
774
+
775
+ const validTripIds: GtfsTripIdsMap = new Map([
776
+ ['trip1', 'routeA'],
777
+ ['trip2', 'routeB'],
778
+ ]);
779
+ const validStopIds: Set<StopId> = new Set([0, 1, 2]);
780
+ const stopsMap: GtfsStopsMap = new Map([
781
+ [
782
+ 'stop1',
783
+ {
784
+ id: 0,
785
+ sourceStopId: 'stop1',
786
+ name: 'Stop 1',
787
+ children: [],
788
+ locationType: 'SIMPLE_STOP_OR_PLATFORM',
789
+ },
790
+ ],
791
+ [
792
+ 'stop2',
793
+ {
794
+ id: 1,
795
+ sourceStopId: 'stop2',
796
+ name: 'Stop 2',
797
+ children: [],
798
+ locationType: 'SIMPLE_STOP_OR_PLATFORM',
799
+ },
800
+ ],
801
+ [
802
+ 'stop3',
803
+ {
804
+ id: 2,
805
+ sourceStopId: 'stop3',
806
+ name: 'Stop 3',
807
+ children: [],
808
+ locationType: 'SIMPLE_STOP_OR_PLATFORM',
809
+ },
810
+ ],
811
+ ]);
812
+
813
+ const result = await parseStopTimes(
814
+ mockedStream,
815
+ stopsMap,
816
+ validTripIds,
817
+ validStopIds,
818
+ );
819
+
820
+ assert.deepEqual(
821
+ result.tripsMapping,
822
+ new Map([
823
+ ['trip1', { routeId: 0, tripRouteIndex: 0 }],
824
+ ['trip2', { routeId: 1, tripRouteIndex: 0 }],
825
+ ]),
826
+ );
827
+ assert.deepEqual(
828
+ result.serviceRoutesMap,
829
+ new Map([
830
+ ['routeA', 0],
831
+ ['routeB', 1],
832
+ ]),
833
+ );
512
834
  });
513
835
  });
@@ -9,7 +9,11 @@ import { standardProfile } from './profiles/standard.js';
9
9
  import { indexRoutes, parseRoutes } from './routes.js';
10
10
  import { parseCalendar, parseCalendarDates, ServiceIds } from './services.js';
11
11
  import { parseStops } from './stops.js';
12
- import { parseTransfers, TransfersMap } from './transfers.js';
12
+ import {
13
+ parseTransfers,
14
+ TransfersMap,
15
+ TripContinuationsMap,
16
+ } from './transfers.js';
13
17
  import {
14
18
  buildStopsAdjacencyStructure,
15
19
  parseStopTimes,
@@ -108,21 +112,27 @@ export class GtfsParser {
108
112
  );
109
113
 
110
114
  let transfers = new Map() as TransfersMap;
115
+ let tripContinuations = new Map() as TripContinuationsMap;
111
116
  if (entries[TRANSFERS_FILE]) {
112
117
  log.info(`Parsing ${TRANSFERS_FILE}`);
113
118
  const transfersStart = performance.now();
114
119
  const transfersStream = await zip.stream(TRANSFERS_FILE);
115
- transfers = await parseTransfers(transfersStream, parsedStops);
120
+ const {
121
+ transfers: parsedTransfers,
122
+ tripContinuations: parsedTripContinuations,
123
+ } = await parseTransfers(transfersStream, parsedStops);
124
+ transfers = parsedTransfers;
125
+ tripContinuations = parsedTripContinuations;
116
126
  const transfersEnd = performance.now();
117
127
  log.info(
118
- `${transfers.size} valid transfers. (${(transfersEnd - transfersStart).toFixed(2)}ms)`,
128
+ `${transfers.size} valid transfers and ${tripContinuations.size} trip continuations. (${(transfersEnd - transfersStart).toFixed(2)}ms)`,
119
129
  );
120
130
  }
121
131
 
122
132
  log.info(`Parsing ${STOP_TIMES_FILE}`);
123
133
  const stopTimesStart = performance.now();
124
134
  const stopTimesStream = await zip.stream(STOP_TIMES_FILE);
125
- const { routes, serviceRoutesMap } = await parseStopTimes(
135
+ const { routes, serviceRoutesMap, tripsMapping } = await parseStopTimes(
126
136
  stopTimesStream,
127
137
  parsedStops,
128
138
  trips,
@@ -136,9 +146,11 @@ export class GtfsParser {
136
146
  log.info('Building stops adjacency structure');
137
147
  const stopsAdjacencyStart = performance.now();
138
148
  const stopsAdjacency = buildStopsAdjacencyStructure(
149
+ tripsMapping,
139
150
  serviceRoutes,
140
151
  routes,
141
152
  transfers,
153
+ tripContinuations,
142
154
  parsedStops.size,
143
155
  activeStopIds,
144
156
  );