minotor 7.0.2 → 9.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 (60) 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 +1786 -791
  5. package/dist/cli.mjs.map +1 -1
  6. package/dist/gtfs/transfers.d.ts +29 -5
  7. package/dist/gtfs/trips.d.ts +10 -5
  8. package/dist/parser.cjs.js +972 -525
  9. package/dist/parser.cjs.js.map +1 -1
  10. package/dist/parser.esm.js +972 -525
  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__/tripBoardingId.test.d.ts +1 -0
  25. package/dist/timetable/io.d.ts +4 -2
  26. package/dist/timetable/proto/timetable.d.ts +15 -1
  27. package/dist/timetable/route.d.ts +48 -23
  28. package/dist/timetable/timetable.d.ts +24 -7
  29. package/dist/timetable/tripBoardingId.d.ts +34 -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 +245 -1
  35. package/src/gtfs/__tests__/parser.test.ts +19 -4
  36. package/src/gtfs/__tests__/transfers.test.ts +773 -37
  37. package/src/gtfs/__tests__/trips.test.ts +308 -27
  38. package/src/gtfs/parser.ts +36 -6
  39. package/src/gtfs/transfers.ts +193 -19
  40. package/src/gtfs/trips.ts +58 -21
  41. package/src/router.ts +2 -2
  42. package/src/routing/__tests__/plotter.test.ts +230 -0
  43. package/src/routing/__tests__/result.test.ts +486 -125
  44. package/src/routing/__tests__/route.test.ts +7 -3
  45. package/src/routing/__tests__/router.test.ts +380 -172
  46. package/src/routing/plotter.ts +279 -48
  47. package/src/routing/result.ts +114 -34
  48. package/src/routing/route.ts +0 -3
  49. package/src/routing/router.ts +344 -211
  50. package/src/timetable/__tests__/io.test.ts +34 -1
  51. package/src/timetable/__tests__/route.test.ts +74 -81
  52. package/src/timetable/__tests__/timetable.test.ts +232 -61
  53. package/src/timetable/__tests__/tripBoardingId.test.ts +57 -0
  54. package/src/timetable/io.ts +72 -10
  55. package/src/timetable/proto/timetable.proto +16 -2
  56. package/src/timetable/proto/timetable.ts +256 -22
  57. package/src/timetable/route.ts +174 -58
  58. package/src/timetable/timetable.ts +66 -16
  59. package/src/timetable/tripBoardingId.ts +94 -0
  60. package/tsconfig.json +2 -2
@@ -13,32 +13,47 @@ import { TransfersMap } from '../transfers.js';
13
13
  import {
14
14
  buildStopsAdjacencyStructure,
15
15
  encodePickUpDropOffTypes,
16
+ GtfsTripIdsMap,
16
17
  parseStopTimes,
17
18
  parseTrips,
18
- TripIdsMap,
19
19
  } from '../trips.js';
20
20
 
21
21
  describe('buildStopsAdjacencyStructure', () => {
22
22
  it('should correctly build stops adjacency for valid routes and transfers', () => {
23
23
  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
- ),
24
+ const routes = [
25
+ Route.of({
26
+ id: 0,
27
+ serviceRouteId: 0,
28
+ trips: [
29
+ {
30
+ stops: [
31
+ {
32
+ id: 0,
33
+ arrivalTime: Time.fromHMS(8, 0, 0),
34
+ departureTime: Time.fromHMS(8, 0, 0),
35
+ },
36
+ {
37
+ id: 1,
38
+ arrivalTime: Time.fromHMS(8, 5, 0),
39
+ departureTime: Time.fromHMS(8, 5, 0),
40
+ },
41
+ ],
42
+ },
43
+ ],
44
+ }),
31
45
  ];
32
46
  const transfersMap: TransfersMap = new Map([
33
47
  [0, [{ destination: 1, type: 'RECOMMENDED' }]],
34
48
  ]);
49
+
35
50
  const serviceRoutes: ServiceRoute[] = [
36
51
  { type: 'BUS', name: 'B1', routes: [] },
37
52
  ];
38
53
 
39
54
  const stopsAdjacency = buildStopsAdjacencyStructure(
40
55
  serviceRoutes,
41
- routesAdjacency,
56
+ routes,
42
57
  transfersMap,
43
58
  2,
44
59
  validStops,
@@ -61,7 +76,6 @@ describe('buildStopsAdjacencyStructure', () => {
61
76
  1,
62
77
  {
63
78
  routes: [],
64
- transfers: [],
65
79
  },
66
80
  ],
67
81
  ]);
@@ -70,13 +84,27 @@ describe('buildStopsAdjacencyStructure', () => {
70
84
 
71
85
  it('should ignore transfers to invalid stops', () => {
72
86
  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
- ),
87
+ const routes = [
88
+ Route.of({
89
+ id: 0,
90
+ serviceRouteId: 0,
91
+ trips: [
92
+ {
93
+ stops: [
94
+ {
95
+ id: 0,
96
+ arrivalTime: Time.fromHMS(8, 0, 0),
97
+ departureTime: Time.fromHMS(8, 0, 0),
98
+ },
99
+ {
100
+ id: 1,
101
+ arrivalTime: Time.fromHMS(8, 5, 0),
102
+ departureTime: Time.fromHMS(8, 5, 0),
103
+ },
104
+ ],
105
+ },
106
+ ],
107
+ }),
80
108
  ];
81
109
  const transfersMap: TransfersMap = new Map([
82
110
  [3, [{ destination: 2, type: 'RECOMMENDED' }]],
@@ -87,7 +115,7 @@ describe('buildStopsAdjacencyStructure', () => {
87
115
 
88
116
  const stopsAdjacency = buildStopsAdjacencyStructure(
89
117
  serviceRoutes,
90
- routesAdjacency,
118
+ routes,
91
119
  transfersMap,
92
120
  4,
93
121
  validStops,
@@ -98,33 +126,194 @@ describe('buildStopsAdjacencyStructure', () => {
98
126
  0,
99
127
  {
100
128
  routes: [0],
101
- transfers: [],
102
129
  },
103
130
  ],
104
131
  [
105
132
  1,
106
133
  {
107
134
  routes: [0],
108
- transfers: [],
109
135
  },
110
136
  ],
111
137
  [
112
138
  2,
113
139
  {
114
140
  routes: [],
115
- transfers: [],
116
141
  },
117
142
  ],
118
143
  [
119
144
  3,
120
145
  {
121
146
  routes: [],
122
- transfers: [],
123
147
  },
124
148
  ],
125
149
  ]);
126
150
  assert.deepEqual(serviceRoutes[0]?.routes, [0]);
127
151
  });
152
+
153
+ it('should correctly handle trip continuations', () => {
154
+ const validStops: Set<StopId> = new Set([0, 1]);
155
+ const routes = [
156
+ Route.of({
157
+ id: 0,
158
+ serviceRouteId: 0,
159
+ trips: [
160
+ {
161
+ stops: [
162
+ {
163
+ id: 0,
164
+ arrivalTime: Time.fromHMS(8, 0, 0),
165
+ departureTime: Time.fromHMS(8, 0, 0),
166
+ },
167
+ ],
168
+ },
169
+ ],
170
+ }),
171
+ Route.of({
172
+ id: 1,
173
+ serviceRouteId: 0,
174
+ trips: [
175
+ {
176
+ stops: [
177
+ {
178
+ id: 1,
179
+ arrivalTime: Time.fromHMS(8, 30, 0),
180
+ departureTime: Time.fromHMS(8, 30, 0),
181
+ },
182
+ ],
183
+ },
184
+ ],
185
+ }),
186
+ ];
187
+ const transfersMap: TransfersMap = new Map();
188
+ const serviceRoutes: ServiceRoute[] = [
189
+ { type: 'BUS', name: 'B1', routes: [] },
190
+ ];
191
+
192
+ const stopsAdjacency = buildStopsAdjacencyStructure(
193
+ serviceRoutes,
194
+ routes,
195
+ transfersMap,
196
+ 2,
197
+ validStops,
198
+ );
199
+
200
+ assert.deepEqual(Array.from(stopsAdjacency.entries()), [
201
+ [
202
+ 0,
203
+ {
204
+ routes: [0],
205
+ },
206
+ ],
207
+ [
208
+ 1,
209
+ {
210
+ routes: [1],
211
+ },
212
+ ],
213
+ ]);
214
+ });
215
+
216
+ it('should ignore trip continuations with invalid trip IDs', () => {
217
+ const validStops: Set<StopId> = new Set([0]);
218
+ const routes = [
219
+ Route.of({
220
+ id: 0,
221
+ serviceRouteId: 0,
222
+ trips: [
223
+ {
224
+ stops: [
225
+ {
226
+ id: 0,
227
+ arrivalTime: Time.fromHMS(8, 0, 0),
228
+ departureTime: Time.fromHMS(8, 0, 0),
229
+ },
230
+ ],
231
+ },
232
+ ],
233
+ }),
234
+ ];
235
+ const transfersMap: TransfersMap = new Map();
236
+ const serviceRoutes: ServiceRoute[] = [
237
+ { type: 'BUS', name: 'B1', routes: [] },
238
+ ];
239
+
240
+ const stopsAdjacency = buildStopsAdjacencyStructure(
241
+ serviceRoutes,
242
+ routes,
243
+ transfersMap,
244
+ 1,
245
+ validStops,
246
+ );
247
+
248
+ assert.deepEqual(Array.from(stopsAdjacency.entries()), [
249
+ [
250
+ 0,
251
+ {
252
+ routes: [0],
253
+ },
254
+ ],
255
+ ]);
256
+ });
257
+
258
+ it('should ignore trip continuations for inactive stops', () => {
259
+ const validStops: Set<StopId> = new Set([0]); // Only stop 0 is active
260
+ const routes = [
261
+ Route.of({
262
+ id: 0,
263
+ serviceRouteId: 0,
264
+ trips: [
265
+ {
266
+ stops: [
267
+ {
268
+ id: 0,
269
+ arrivalTime: Time.fromHMS(8, 0, 0),
270
+ departureTime: Time.fromHMS(8, 0, 0),
271
+ },
272
+ ],
273
+ },
274
+ ],
275
+ }),
276
+ ];
277
+ const transfersMap: TransfersMap = new Map();
278
+ const serviceRoutes: ServiceRoute[] = [
279
+ { type: 'BUS', name: 'B1', routes: [] },
280
+ ];
281
+
282
+ const stopsAdjacency = buildStopsAdjacencyStructure(
283
+ serviceRoutes,
284
+ routes,
285
+ transfersMap,
286
+ 4,
287
+ validStops,
288
+ );
289
+
290
+ assert.deepEqual(Array.from(stopsAdjacency.entries()), [
291
+ [
292
+ 0,
293
+ {
294
+ routes: [0],
295
+ },
296
+ ],
297
+ [
298
+ 1,
299
+ {
300
+ routes: [],
301
+ },
302
+ ],
303
+ [
304
+ 2,
305
+ {
306
+ routes: [],
307
+ },
308
+ ],
309
+ [
310
+ 3,
311
+ {
312
+ routes: [],
313
+ },
314
+ ],
315
+ ]);
316
+ });
128
317
  });
129
318
  describe('GTFS trips parser', () => {
130
319
  it('should correctly parse valid trips', async () => {
@@ -207,7 +396,7 @@ describe('GTFS stop times parser', () => {
207
396
  mockedStream.push('"tripA","08:10:00","08:15:00","stop2","2","0","0"\n');
208
397
  mockedStream.push(null);
209
398
 
210
- const validTripIds: TripIdsMap = new Map([['tripA', 'routeA']]);
399
+ const validTripIds: GtfsTripIdsMap = new Map([['tripA', 'routeA']]);
211
400
  const validStopIds: Set<StopId> = new Set([0, 1]);
212
401
  const stopsMap: GtfsStopsMap = new Map([
213
402
  [
@@ -243,6 +432,7 @@ describe('GTFS stop times parser', () => {
243
432
  );
244
433
  assert.deepEqual(result.routes, [
245
434
  new Route(
435
+ 0,
246
436
  new Uint16Array([
247
437
  Time.fromHMS(8, 0, 0).toMinutes(),
248
438
  Time.fromHMS(8, 5, 0).toMinutes(),
@@ -254,6 +444,10 @@ describe('GTFS stop times parser', () => {
254
444
  0,
255
445
  ),
256
446
  ]);
447
+ assert.deepEqual(
448
+ result.tripsMapping,
449
+ new Map([['tripA', { routeId: 0, tripRouteIndex: 0 }]]),
450
+ );
257
451
  });
258
452
 
259
453
  it('should create same route for same GTFS route with same stops', async () => {
@@ -267,7 +461,7 @@ describe('GTFS stop times parser', () => {
267
461
  mockedStream.push('"tripB","09:10:00","09:15:00","stop2","2","0","0"\n');
268
462
  mockedStream.push(null);
269
463
 
270
- const validTripIds: TripIdsMap = new Map([
464
+ const validTripIds: GtfsTripIdsMap = new Map([
271
465
  ['tripA', 'routeA'],
272
466
  ['tripB', 'routeA'],
273
467
  ]);
@@ -303,6 +497,7 @@ describe('GTFS stop times parser', () => {
303
497
  );
304
498
  assert.deepEqual(result.routes, [
305
499
  new Route(
500
+ 0,
306
501
  new Uint16Array([
307
502
  Time.fromHMS(8, 0, 0).toMinutes(),
308
503
  Time.fromHMS(8, 5, 0).toMinutes(),
@@ -321,6 +516,13 @@ describe('GTFS stop times parser', () => {
321
516
  0,
322
517
  ),
323
518
  ]);
519
+ assert.deepEqual(
520
+ result.tripsMapping,
521
+ new Map([
522
+ ['tripA', { routeId: 0, tripRouteIndex: 0 }],
523
+ ['tripB', { routeId: 0, tripRouteIndex: 1 }],
524
+ ]),
525
+ );
324
526
  });
325
527
 
326
528
  it('should support unsorted trips within a route', async () => {
@@ -334,7 +536,7 @@ describe('GTFS stop times parser', () => {
334
536
  mockedStream.push('"tripA","08:10:00","08:15:00","stop2","2","0","0"\n');
335
537
  mockedStream.push(null);
336
538
 
337
- const validTripIds: TripIdsMap = new Map([
539
+ const validTripIds: GtfsTripIdsMap = new Map([
338
540
  ['tripA', 'routeA'],
339
541
  ['tripB', 'routeA'],
340
542
  ]);
@@ -370,6 +572,7 @@ describe('GTFS stop times parser', () => {
370
572
  );
371
573
  assert.deepEqual(result.routes, [
372
574
  new Route(
575
+ 0,
373
576
  new Uint16Array([
374
577
  Time.fromHMS(8, 0, 0).toMinutes(),
375
578
  Time.fromHMS(8, 5, 0).toMinutes(),
@@ -400,7 +603,7 @@ describe('GTFS stop times parser', () => {
400
603
  mockedStream.push('"tripB","09:00:00","09:15:00","stop1","1","0","0"\n');
401
604
  mockedStream.push(null);
402
605
 
403
- const validTripIds: TripIdsMap = new Map([
606
+ const validTripIds: GtfsTripIdsMap = new Map([
404
607
  ['tripA', 'routeA'],
405
608
  ['tripB', 'routeA'],
406
609
  ]);
@@ -436,6 +639,7 @@ describe('GTFS stop times parser', () => {
436
639
  );
437
640
  assert.deepEqual(result.routes, [
438
641
  new Route(
642
+ 0,
439
643
  new Uint16Array([
440
644
  Time.fromHMS(8, 0, 0).toMinutes(),
441
645
  Time.fromHMS(8, 5, 0).toMinutes(),
@@ -447,6 +651,7 @@ describe('GTFS stop times parser', () => {
447
651
  0,
448
652
  ),
449
653
  new Route(
654
+ 1,
450
655
  new Uint16Array([
451
656
  Time.fromHMS(9, 0, 0).toMinutes(),
452
657
  Time.fromHMS(9, 15, 0).toMinutes(),
@@ -467,7 +672,7 @@ describe('GTFS stop times parser', () => {
467
672
  mockedStream.push('"tripA","08:10:00","08:15:00","stop2","1","0","0"\n');
468
673
  mockedStream.push(null);
469
674
 
470
- const validTripIds: TripIdsMap = new Map([['tripA', 'routeA']]);
675
+ const validTripIds: GtfsTripIdsMap = new Map([['tripA', 'routeA']]);
471
676
  const validStopIds: Set<StopId> = new Set([0, 1]);
472
677
  const stopsMap: GtfsStopsMap = new Map([
473
678
  [
@@ -500,6 +705,7 @@ describe('GTFS stop times parser', () => {
500
705
  );
501
706
  assert.deepEqual(result.routes, [
502
707
  new Route(
708
+ 0,
503
709
  new Uint16Array([
504
710
  Time.fromHMS(8, 0, 0).toMinutes(),
505
711
  Time.fromHMS(8, 5, 0).toMinutes(),
@@ -509,5 +715,80 @@ describe('GTFS stop times parser', () => {
509
715
  0,
510
716
  ),
511
717
  ]);
718
+ assert.deepEqual(
719
+ result.tripsMapping,
720
+ new Map([['tripA', { routeId: 0, tripRouteIndex: 0 }]]),
721
+ );
722
+ });
723
+
724
+ it('should create trip continuations mapping correctly', async () => {
725
+ const mockedStream = new Readable();
726
+ mockedStream.push(
727
+ 'trip_id,arrival_time,departure_time,stop_id,stop_sequence,pickup_type,drop_off_type\n',
728
+ );
729
+ mockedStream.push('"trip1","08:00:00","08:05:00","stop1","1","0","0"\n');
730
+ mockedStream.push('"trip1","08:10:00","08:15:00","stop2","2","0","0"\n');
731
+ mockedStream.push('"trip2","09:00:00","09:05:00","stop3","1","0","0"\n');
732
+ mockedStream.push(null);
733
+
734
+ const validTripIds: GtfsTripIdsMap = new Map([
735
+ ['trip1', 'routeA'],
736
+ ['trip2', 'routeB'],
737
+ ]);
738
+ const validStopIds: Set<StopId> = new Set([0, 1, 2]);
739
+ const stopsMap: GtfsStopsMap = new Map([
740
+ [
741
+ 'stop1',
742
+ {
743
+ id: 0,
744
+ sourceStopId: 'stop1',
745
+ name: 'Stop 1',
746
+ children: [],
747
+ locationType: 'SIMPLE_STOP_OR_PLATFORM',
748
+ },
749
+ ],
750
+ [
751
+ 'stop2',
752
+ {
753
+ id: 1,
754
+ sourceStopId: 'stop2',
755
+ name: 'Stop 2',
756
+ children: [],
757
+ locationType: 'SIMPLE_STOP_OR_PLATFORM',
758
+ },
759
+ ],
760
+ [
761
+ 'stop3',
762
+ {
763
+ id: 2,
764
+ sourceStopId: 'stop3',
765
+ name: 'Stop 3',
766
+ children: [],
767
+ locationType: 'SIMPLE_STOP_OR_PLATFORM',
768
+ },
769
+ ],
770
+ ]);
771
+
772
+ const result = await parseStopTimes(
773
+ mockedStream,
774
+ stopsMap,
775
+ validTripIds,
776
+ validStopIds,
777
+ );
778
+
779
+ assert.deepEqual(
780
+ result.tripsMapping,
781
+ new Map([
782
+ ['trip1', { routeId: 0, tripRouteIndex: 0 }],
783
+ ['trip2', { routeId: 1, tripRouteIndex: 0 }],
784
+ ]),
785
+ );
786
+ assert.deepEqual(
787
+ result.serviceRoutesMap,
788
+ new Map([
789
+ ['routeA', 0],
790
+ ['routeB', 1],
791
+ ]),
792
+ );
512
793
  });
513
794
  });
@@ -9,7 +9,12 @@ 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
+ buildTripContinuations,
14
+ GtfsTripContinuation,
15
+ parseTransfers,
16
+ TransfersMap,
17
+ } from './transfers.js';
13
18
  import {
14
19
  buildStopsAdjacencyStructure,
15
20
  parseStopTimes,
@@ -107,22 +112,28 @@ export class GtfsParser {
107
112
  `${trips.size} valid trips. (${(tripsEnd - tripsStart).toFixed(2)}ms)`,
108
113
  );
109
114
 
110
- let transfers = new Map() as TransfersMap;
115
+ let transfers: TransfersMap = new Map();
116
+ let tripContinuationsMap: GtfsTripContinuation[] = [];
111
117
  if (entries[TRANSFERS_FILE]) {
112
118
  log.info(`Parsing ${TRANSFERS_FILE}`);
113
119
  const transfersStart = performance.now();
114
120
  const transfersStream = await zip.stream(TRANSFERS_FILE);
115
- transfers = await parseTransfers(transfersStream, parsedStops);
121
+ const {
122
+ transfers: parsedTransfers,
123
+ tripContinuations: parsedTripContinuations,
124
+ } = await parseTransfers(transfersStream, parsedStops);
125
+ transfers = parsedTransfers;
126
+ tripContinuationsMap = parsedTripContinuations;
116
127
  const transfersEnd = performance.now();
117
128
  log.info(
118
- `${transfers.size} valid transfers. (${(transfersEnd - transfersStart).toFixed(2)}ms)`,
129
+ `${transfers.size} valid transfers and ${tripContinuationsMap.length} trip continuations. (${(transfersEnd - transfersStart).toFixed(2)}ms)`,
119
130
  );
120
131
  }
121
132
 
122
133
  log.info(`Parsing ${STOP_TIMES_FILE}`);
123
134
  const stopTimesStart = performance.now();
124
135
  const stopTimesStream = await zip.stream(STOP_TIMES_FILE);
125
- const { routes, serviceRoutesMap } = await parseStopTimes(
136
+ const { routes, serviceRoutesMap, tripsMapping } = await parseStopTimes(
126
137
  stopTimesStream,
127
138
  parsedStops,
128
139
  trips,
@@ -149,10 +160,29 @@ export class GtfsParser {
149
160
  );
150
161
  await zip.close();
151
162
 
163
+ // temporary timetable for building continuations
152
164
  const timetable = new Timetable(stopsAdjacency, routes, serviceRoutes);
153
165
 
166
+ log.info('Building in-seat trip continuations');
167
+ const tripContinuationsStart = performance.now();
168
+ const tripContinuations = buildTripContinuations(
169
+ tripsMapping,
170
+ tripContinuationsMap,
171
+ timetable,
172
+ activeStopIds,
173
+ );
174
+ const tripContinuationsEnd = performance.now();
175
+ log.info(
176
+ `${tripContinuations.size} in-seat trip continuations origins created. (${(tripContinuationsEnd - tripContinuationsStart).toFixed(2)}ms)`,
177
+ );
154
178
  log.info('Parsing complete.');
155
- return timetable;
179
+
180
+ return new Timetable(
181
+ stopsAdjacency,
182
+ routes,
183
+ serviceRoutes,
184
+ tripContinuations,
185
+ );
156
186
  }
157
187
 
158
188
  /**