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
@@ -12294,41 +12294,191 @@ const Transfer = {
12294
12294
  return message;
12295
12295
  },
12296
12296
  };
12297
- function createBaseStopAdjacency() {
12298
- return { transfers: [], routes: [] };
12297
+ function createBaseTripBoarding() {
12298
+ return { hopOnStop: 0, routeId: 0, tripIndex: 0 };
12299
12299
  }
12300
- const StopAdjacency = {
12300
+ const TripBoarding = {
12301
12301
  encode(message, writer = new BinaryWriter()) {
12302
- for (const v of message.transfers) {
12303
- Transfer.encode(v, writer.uint32(10).fork()).join();
12302
+ if (message.hopOnStop !== 0) {
12303
+ writer.uint32(8).uint32(message.hopOnStop);
12304
12304
  }
12305
- writer.uint32(18).fork();
12306
- for (const v of message.routes) {
12307
- writer.uint32(v);
12305
+ if (message.routeId !== 0) {
12306
+ writer.uint32(16).uint32(message.routeId);
12307
+ }
12308
+ if (message.tripIndex !== 0) {
12309
+ writer.uint32(24).uint32(message.tripIndex);
12308
12310
  }
12309
- writer.join();
12310
12311
  return writer;
12311
12312
  },
12312
12313
  decode(input, length) {
12313
12314
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12314
12315
  const end = length === undefined ? reader.len : reader.pos + length;
12315
- const message = createBaseStopAdjacency();
12316
+ const message = createBaseTripBoarding();
12316
12317
  while (reader.pos < end) {
12317
12318
  const tag = reader.uint32();
12318
12319
  switch (tag >>> 3) {
12319
12320
  case 1: {
12320
- if (tag !== 10) {
12321
+ if (tag !== 8) {
12321
12322
  break;
12322
12323
  }
12323
- message.transfers.push(Transfer.decode(reader, reader.uint32()));
12324
+ message.hopOnStop = reader.uint32();
12325
+ continue;
12326
+ }
12327
+ case 2: {
12328
+ if (tag !== 16) {
12329
+ break;
12330
+ }
12331
+ message.routeId = reader.uint32();
12332
+ continue;
12333
+ }
12334
+ case 3: {
12335
+ if (tag !== 24) {
12336
+ break;
12337
+ }
12338
+ message.tripIndex = reader.uint32();
12339
+ continue;
12340
+ }
12341
+ }
12342
+ if ((tag & 7) === 4 || tag === 0) {
12343
+ break;
12344
+ }
12345
+ reader.skip(tag & 7);
12346
+ }
12347
+ return message;
12348
+ },
12349
+ fromJSON(object) {
12350
+ return {
12351
+ hopOnStop: isSet(object.hopOnStop) ? globalThis.Number(object.hopOnStop) : 0,
12352
+ routeId: isSet(object.routeId) ? globalThis.Number(object.routeId) : 0,
12353
+ tripIndex: isSet(object.tripIndex) ? globalThis.Number(object.tripIndex) : 0,
12354
+ };
12355
+ },
12356
+ toJSON(message) {
12357
+ const obj = {};
12358
+ if (message.hopOnStop !== 0) {
12359
+ obj.hopOnStop = Math.round(message.hopOnStop);
12360
+ }
12361
+ if (message.routeId !== 0) {
12362
+ obj.routeId = Math.round(message.routeId);
12363
+ }
12364
+ if (message.tripIndex !== 0) {
12365
+ obj.tripIndex = Math.round(message.tripIndex);
12366
+ }
12367
+ return obj;
12368
+ },
12369
+ create(base) {
12370
+ return TripBoarding.fromPartial(base !== null && base !== void 0 ? base : {});
12371
+ },
12372
+ fromPartial(object) {
12373
+ var _a, _b, _c;
12374
+ const message = createBaseTripBoarding();
12375
+ message.hopOnStop = (_a = object.hopOnStop) !== null && _a !== void 0 ? _a : 0;
12376
+ message.routeId = (_b = object.routeId) !== null && _b !== void 0 ? _b : 0;
12377
+ message.tripIndex = (_c = object.tripIndex) !== null && _c !== void 0 ? _c : 0;
12378
+ return message;
12379
+ },
12380
+ };
12381
+ function createBaseTripContinuationEntry() {
12382
+ return { key: 0, value: [] };
12383
+ }
12384
+ const TripContinuationEntry = {
12385
+ encode(message, writer = new BinaryWriter()) {
12386
+ if (message.key !== 0) {
12387
+ writer.uint32(8).uint32(message.key);
12388
+ }
12389
+ for (const v of message.value) {
12390
+ TripBoarding.encode(v, writer.uint32(18).fork()).join();
12391
+ }
12392
+ return writer;
12393
+ },
12394
+ decode(input, length) {
12395
+ const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12396
+ const end = length === undefined ? reader.len : reader.pos + length;
12397
+ const message = createBaseTripContinuationEntry();
12398
+ while (reader.pos < end) {
12399
+ const tag = reader.uint32();
12400
+ switch (tag >>> 3) {
12401
+ case 1: {
12402
+ if (tag !== 8) {
12403
+ break;
12404
+ }
12405
+ message.key = reader.uint32();
12324
12406
  continue;
12325
12407
  }
12326
12408
  case 2: {
12327
- if (tag === 16) {
12409
+ if (tag !== 18) {
12410
+ break;
12411
+ }
12412
+ message.value.push(TripBoarding.decode(reader, reader.uint32()));
12413
+ continue;
12414
+ }
12415
+ }
12416
+ if ((tag & 7) === 4 || tag === 0) {
12417
+ break;
12418
+ }
12419
+ reader.skip(tag & 7);
12420
+ }
12421
+ return message;
12422
+ },
12423
+ fromJSON(object) {
12424
+ return {
12425
+ key: isSet(object.key) ? globalThis.Number(object.key) : 0,
12426
+ value: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.value) ? object.value.map((e) => TripBoarding.fromJSON(e)) : [],
12427
+ };
12428
+ },
12429
+ toJSON(message) {
12430
+ var _a;
12431
+ const obj = {};
12432
+ if (message.key !== 0) {
12433
+ obj.key = Math.round(message.key);
12434
+ }
12435
+ if ((_a = message.value) === null || _a === void 0 ? void 0 : _a.length) {
12436
+ obj.value = message.value.map((e) => TripBoarding.toJSON(e));
12437
+ }
12438
+ return obj;
12439
+ },
12440
+ create(base) {
12441
+ return TripContinuationEntry.fromPartial(base !== null && base !== void 0 ? base : {});
12442
+ },
12443
+ fromPartial(object) {
12444
+ var _a, _b;
12445
+ const message = createBaseTripContinuationEntry();
12446
+ message.key = (_a = object.key) !== null && _a !== void 0 ? _a : 0;
12447
+ message.value = ((_b = object.value) === null || _b === void 0 ? void 0 : _b.map((e) => TripBoarding.fromPartial(e))) || [];
12448
+ return message;
12449
+ },
12450
+ };
12451
+ function createBaseStopAdjacency() {
12452
+ return { routes: [], transfers: [], tripContinuations: [] };
12453
+ }
12454
+ const StopAdjacency = {
12455
+ encode(message, writer = new BinaryWriter()) {
12456
+ writer.uint32(10).fork();
12457
+ for (const v of message.routes) {
12458
+ writer.uint32(v);
12459
+ }
12460
+ writer.join();
12461
+ for (const v of message.transfers) {
12462
+ Transfer.encode(v, writer.uint32(18).fork()).join();
12463
+ }
12464
+ for (const v of message.tripContinuations) {
12465
+ TripContinuationEntry.encode(v, writer.uint32(26).fork()).join();
12466
+ }
12467
+ return writer;
12468
+ },
12469
+ decode(input, length) {
12470
+ const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12471
+ const end = length === undefined ? reader.len : reader.pos + length;
12472
+ const message = createBaseStopAdjacency();
12473
+ while (reader.pos < end) {
12474
+ const tag = reader.uint32();
12475
+ switch (tag >>> 3) {
12476
+ case 1: {
12477
+ if (tag === 8) {
12328
12478
  message.routes.push(reader.uint32());
12329
12479
  continue;
12330
12480
  }
12331
- if (tag === 18) {
12481
+ if (tag === 10) {
12332
12482
  const end2 = reader.uint32() + reader.pos;
12333
12483
  while (reader.pos < end2) {
12334
12484
  message.routes.push(reader.uint32());
@@ -12337,6 +12487,20 @@ const StopAdjacency = {
12337
12487
  }
12338
12488
  break;
12339
12489
  }
12490
+ case 2: {
12491
+ if (tag !== 18) {
12492
+ break;
12493
+ }
12494
+ message.transfers.push(Transfer.decode(reader, reader.uint32()));
12495
+ continue;
12496
+ }
12497
+ case 3: {
12498
+ if (tag !== 26) {
12499
+ break;
12500
+ }
12501
+ message.tripContinuations.push(TripContinuationEntry.decode(reader, reader.uint32()));
12502
+ continue;
12503
+ }
12340
12504
  }
12341
12505
  if ((tag & 7) === 4 || tag === 0) {
12342
12506
  break;
@@ -12347,20 +12511,26 @@ const StopAdjacency = {
12347
12511
  },
12348
12512
  fromJSON(object) {
12349
12513
  return {
12514
+ routes: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.routes) ? object.routes.map((e) => globalThis.Number(e)) : [],
12350
12515
  transfers: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.transfers)
12351
12516
  ? object.transfers.map((e) => Transfer.fromJSON(e))
12352
12517
  : [],
12353
- routes: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.routes) ? object.routes.map((e) => globalThis.Number(e)) : [],
12518
+ tripContinuations: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.tripContinuations)
12519
+ ? object.tripContinuations.map((e) => TripContinuationEntry.fromJSON(e))
12520
+ : [],
12354
12521
  };
12355
12522
  },
12356
12523
  toJSON(message) {
12357
- var _a, _b;
12524
+ var _a, _b, _c;
12358
12525
  const obj = {};
12359
- if ((_a = message.transfers) === null || _a === void 0 ? void 0 : _a.length) {
12526
+ if ((_a = message.routes) === null || _a === void 0 ? void 0 : _a.length) {
12527
+ obj.routes = message.routes.map((e) => Math.round(e));
12528
+ }
12529
+ if ((_b = message.transfers) === null || _b === void 0 ? void 0 : _b.length) {
12360
12530
  obj.transfers = message.transfers.map((e) => Transfer.toJSON(e));
12361
12531
  }
12362
- if ((_b = message.routes) === null || _b === void 0 ? void 0 : _b.length) {
12363
- obj.routes = message.routes.map((e) => Math.round(e));
12532
+ if ((_c = message.tripContinuations) === null || _c === void 0 ? void 0 : _c.length) {
12533
+ obj.tripContinuations = message.tripContinuations.map((e) => TripContinuationEntry.toJSON(e));
12364
12534
  }
12365
12535
  return obj;
12366
12536
  },
@@ -12368,10 +12538,11 @@ const StopAdjacency = {
12368
12538
  return StopAdjacency.fromPartial(base !== null && base !== void 0 ? base : {});
12369
12539
  },
12370
12540
  fromPartial(object) {
12371
- var _a, _b;
12541
+ var _a, _b, _c;
12372
12542
  const message = createBaseStopAdjacency();
12373
- message.transfers = ((_a = object.transfers) === null || _a === void 0 ? void 0 : _a.map((e) => Transfer.fromPartial(e))) || [];
12374
- message.routes = ((_b = object.routes) === null || _b === void 0 ? void 0 : _b.map((e) => e)) || [];
12543
+ message.routes = ((_a = object.routes) === null || _a === void 0 ? void 0 : _a.map((e) => e)) || [];
12544
+ message.transfers = ((_b = object.transfers) === null || _b === void 0 ? void 0 : _b.map((e) => Transfer.fromPartial(e))) || [];
12545
+ message.tripContinuations = ((_c = object.tripContinuations) === null || _c === void 0 ? void 0 : _c.map((e) => TripContinuationEntry.fromPartial(e))) || [];
12375
12546
  return message;
12376
12547
  },
12377
12548
  };
@@ -12860,7 +13031,8 @@ const toPickupDropOffType = (numericalType) => {
12860
13031
  * A route identifies all trips of a given service route sharing the same list of stops.
12861
13032
  */
12862
13033
  class Route {
12863
- constructor(stopTimes, pickUpDropOffTypes, stops, serviceRouteId) {
13034
+ constructor(id, stopTimes, pickUpDropOffTypes, stops, serviceRouteId) {
13035
+ this.id = id;
12864
13036
  this.stopTimes = stopTimes;
12865
13037
  this.pickUpDropOffTypes = pickUpDropOffTypes;
12866
13038
  this.stops = stops;
@@ -12873,6 +13045,78 @@ class Route {
12873
13045
  this.stopIndices.set(stops[i], i);
12874
13046
  }
12875
13047
  }
13048
+ /**
13049
+ * Creates a new route from multiple trips with their stops.
13050
+ *
13051
+ * @param params The route parameters including ID, service route ID, and trips.
13052
+ * @returns The new route.
13053
+ */
13054
+ static of(params) {
13055
+ var _a, _b;
13056
+ const { id, serviceRouteId, trips } = params;
13057
+ if (trips.length === 0) {
13058
+ throw new Error('At least one trip must be provided');
13059
+ }
13060
+ // All trips must have the same stops in the same order
13061
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13062
+ const firstTrip = trips[0];
13063
+ const stopIds = new Uint32Array(firstTrip.stops.map((stop) => stop.id));
13064
+ const numStops = stopIds.length;
13065
+ // Validate all trips have the same stops
13066
+ for (let tripIndex = 1; tripIndex < trips.length; tripIndex++) {
13067
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13068
+ const trip = trips[tripIndex];
13069
+ if (trip.stops.length !== numStops) {
13070
+ throw new Error(`Trip ${tripIndex} has ${trip.stops.length} stops, expected ${numStops}`);
13071
+ }
13072
+ for (let stopIndex = 0; stopIndex < numStops; stopIndex++) {
13073
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13074
+ if (trip.stops[stopIndex].id !== stopIds[stopIndex]) {
13075
+ throw new Error(`Trip ${tripIndex} has different stop at index ${stopIndex}`);
13076
+ }
13077
+ }
13078
+ }
13079
+ // Create stopTimes array with arrivals and departures for all trips
13080
+ const stopTimes = new Uint16Array(trips.length * numStops * 2);
13081
+ for (let tripIndex = 0; tripIndex < trips.length; tripIndex++) {
13082
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13083
+ const trip = trips[tripIndex];
13084
+ for (let stopIndex = 0; stopIndex < numStops; stopIndex++) {
13085
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13086
+ const stop = trip.stops[stopIndex];
13087
+ const baseIndex = (tripIndex * numStops + stopIndex) * 2;
13088
+ stopTimes[baseIndex] = stop.arrivalTime.toMinutes();
13089
+ stopTimes[baseIndex + 1] = stop.departureTime.toMinutes();
13090
+ }
13091
+ }
13092
+ // Create pickUpDropOffTypes array (2-bit encoded) for all trips
13093
+ const totalStopEntries = trips.length * numStops;
13094
+ const pickUpDropOffTypes = new Uint8Array(Math.ceil(totalStopEntries / 2));
13095
+ for (let tripIndex = 0; tripIndex < trips.length; tripIndex++) {
13096
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13097
+ const trip = trips[tripIndex];
13098
+ for (let stopIndex = 0; stopIndex < numStops; stopIndex++) {
13099
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13100
+ const stop = trip.stops[stopIndex];
13101
+ const globalIndex = tripIndex * numStops + stopIndex;
13102
+ const pickUp = (_a = stop.pickUpType) !== null && _a !== void 0 ? _a : REGULAR;
13103
+ const dropOff = (_b = stop.dropOffType) !== null && _b !== void 0 ? _b : REGULAR;
13104
+ const byteIndex = Math.floor(globalIndex / 2);
13105
+ const isSecondPair = globalIndex % 2 === 1;
13106
+ if (isSecondPair) {
13107
+ // Second pair: pickup in upper 2 bits, dropOff in bits 4-5
13108
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13109
+ pickUpDropOffTypes[byteIndex] |= (pickUp << 6) | (dropOff << 4);
13110
+ }
13111
+ else {
13112
+ // First pair: pickup in bits 2-3, dropOff in lower 2 bits
13113
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13114
+ pickUpDropOffTypes[byteIndex] |= (pickUp << 2) | dropOff;
13115
+ }
13116
+ }
13117
+ }
13118
+ return new Route(id, stopTimes, pickUpDropOffTypes, stopIds, serviceRouteId);
13119
+ }
12876
13120
  /**
12877
13121
  * Serializes the Route into binary arrays.
12878
13122
  *
@@ -12896,11 +13140,11 @@ class Route {
12896
13140
  isBefore(stopA, stopB) {
12897
13141
  const stopAIndex = this.stopIndices.get(stopA);
12898
13142
  if (stopAIndex === undefined) {
12899
- throw new Error(`Stop index ${stopAIndex} not found in route ${this.serviceRouteId}`);
13143
+ throw new Error(`Stop index not found for ${stopA} in route ${this.serviceRouteId}`);
12900
13144
  }
12901
13145
  const stopBIndex = this.stopIndices.get(stopB);
12902
13146
  if (stopBIndex === undefined) {
12903
- throw new Error(`Stop index ${stopBIndex} not found in route ${this.serviceRouteId}`);
13147
+ throw new Error(`Stop index not found for ${stopB} in route ${this.serviceRouteId}`);
12904
13148
  }
12905
13149
  return stopAIndex < stopBIndex;
12906
13150
  }
@@ -12912,6 +13156,14 @@ class Route {
12912
13156
  getNbStops() {
12913
13157
  return this.nbStops;
12914
13158
  }
13159
+ /**
13160
+ * Retrieves the number of trips in the route.
13161
+ *
13162
+ * @returns The total number of trips in the route.
13163
+ */
13164
+ getNbTrips() {
13165
+ return this.nbTrips;
13166
+ }
12915
13167
  /**
12916
13168
  * Finds the ServiceRouteId of the route. It corresponds the identifier
12917
13169
  * of the service shown to the end user as a route.
@@ -12929,7 +13181,7 @@ class Route {
12929
13181
  * @returns The arrival time at the specified stop and trip as a Time object.
12930
13182
  */
12931
13183
  arrivalAt(stopId, tripIndex) {
12932
- const arrivalIndex = (tripIndex * this.stops.length + this.stopIndex(stopId)) * 2;
13184
+ const arrivalIndex = (tripIndex * this.stops.length + this.stopRouteIndex(stopId)) * 2;
12933
13185
  const arrival = this.stopTimes[arrivalIndex];
12934
13186
  if (arrival === undefined) {
12935
13187
  throw new Error(`Arrival time not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
@@ -12944,7 +13196,7 @@ class Route {
12944
13196
  * @returns The departure time at the specified stop and trip as a Time object.
12945
13197
  */
12946
13198
  departureFrom(stopId, tripIndex) {
12947
- const departureIndex = (tripIndex * this.stops.length + this.stopIndex(stopId)) * 2 + 1;
13199
+ const departureIndex = (tripIndex * this.stops.length + this.stopRouteIndex(stopId)) * 2 + 1;
12948
13200
  const departure = this.stopTimes[departureIndex];
12949
13201
  if (departure === undefined) {
12950
13202
  throw new Error(`Departure time not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
@@ -12959,7 +13211,7 @@ class Route {
12959
13211
  * @returns The pick-up type at the specified stop and trip.
12960
13212
  */
12961
13213
  pickUpTypeFrom(stopId, tripIndex) {
12962
- const globalIndex = tripIndex * this.stops.length + this.stopIndex(stopId);
13214
+ const globalIndex = tripIndex * this.stops.length + this.stopRouteIndex(stopId);
12963
13215
  const byteIndex = Math.floor(globalIndex / 2);
12964
13216
  const isSecondPair = globalIndex % 2 === 1;
12965
13217
  const byte = this.pickUpDropOffTypes[byteIndex];
@@ -12979,7 +13231,7 @@ class Route {
12979
13231
  * @returns The drop-off type at the specified stop and trip.
12980
13232
  */
12981
13233
  dropOffTypeAt(stopId, tripIndex) {
12982
- const globalIndex = tripIndex * this.stops.length + this.stopIndex(stopId);
13234
+ const globalIndex = tripIndex * this.stops.length + this.stopRouteIndex(stopId);
12983
13235
  const byteIndex = Math.floor(globalIndex / 2);
12984
13236
  const isSecondPair = globalIndex % 2 === 1;
12985
13237
  const byte = this.pickUpDropOffTypes[byteIndex];
@@ -13039,13 +13291,25 @@ class Route {
13039
13291
  * @param stopId The StopId of the stop to locate in the route.
13040
13292
  * @returns The index of the stop in the route.
13041
13293
  */
13042
- stopIndex(stopId) {
13294
+ stopRouteIndex(stopId) {
13043
13295
  const stopIndex = this.stopIndices.get(stopId);
13044
13296
  if (stopIndex === undefined) {
13045
13297
  throw new Error(`Stop index for ${stopId} not found in route ${this.serviceRouteId}`);
13046
13298
  }
13047
13299
  return stopIndex;
13048
13300
  }
13301
+ /**
13302
+ * Retrieves the id of a stop at a given index in a route.
13303
+ * @param stopRouteIndex The route index of the stop.
13304
+ * @returns The id of the stop at the given index in the route.
13305
+ */
13306
+ stopId(stopRouteIndex) {
13307
+ const stopId = this.stops[stopRouteIndex];
13308
+ if (stopId === undefined) {
13309
+ throw new Error(`StopId for stop at index ${stopRouteIndex} not found in route ${this.serviceRouteId}`);
13310
+ }
13311
+ return stopId;
13312
+ }
13049
13313
  }
13050
13314
 
13051
13315
  const isLittleEndian = (() => {
@@ -13116,10 +13380,15 @@ const bytesToUint16Array = (bytes) => {
13116
13380
  const serializeStopsAdjacency = (stopsAdjacency) => {
13117
13381
  return stopsAdjacency.map((value) => {
13118
13382
  return {
13119
- transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: serializeTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
13120
- minTransferTime: transfer.minTransferTime.toSeconds(),
13121
- })))),
13383
+ transfers: value.transfers
13384
+ ? value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: serializeTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
13385
+ minTransferTime: transfer.minTransferTime.toSeconds(),
13386
+ }))))
13387
+ : [],
13122
13388
  routes: value.routes,
13389
+ tripContinuations: value.tripContinuations
13390
+ ? serializeTripContinuations(value.tripContinuations)
13391
+ : [],
13123
13392
  };
13124
13393
  });
13125
13394
  };
@@ -13159,10 +13428,17 @@ const deserializeStopsAdjacency = (protoStopsAdjacency) => {
13159
13428
  }));
13160
13429
  transfers.push(newTransfer);
13161
13430
  }
13162
- result.push({
13163
- transfers: transfers,
13431
+ const stopAdjacency = {
13164
13432
  routes: value.routes,
13165
- });
13433
+ };
13434
+ if (transfers.length > 0) {
13435
+ stopAdjacency.transfers = transfers;
13436
+ }
13437
+ const deserializedTripContinuations = deserializeTripContinuations(value.tripContinuations);
13438
+ if (deserializedTripContinuations.size > 0) {
13439
+ stopAdjacency.tripContinuations = deserializedTripContinuations;
13440
+ }
13441
+ result.push(stopAdjacency);
13166
13442
  }
13167
13443
  return result;
13168
13444
  };
@@ -13172,7 +13448,7 @@ const deserializeRoutesAdjacency = (protoRoutesAdjacency) => {
13172
13448
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13173
13449
  const value = protoRoutesAdjacency[i];
13174
13450
  const stops = bytesToUint32Array(value.stops);
13175
- routesAdjacency.push(new Route(bytesToUint16Array(value.stopTimes), value.pickUpDropOffTypes, stops, value.serviceRouteId));
13451
+ routesAdjacency.push(new Route(i, bytesToUint16Array(value.stopTimes), value.pickUpDropOffTypes, stops, value.serviceRouteId));
13176
13452
  }
13177
13453
  return routesAdjacency;
13178
13454
  };
@@ -13266,6 +13542,46 @@ const serializeRouteType = (type) => {
13266
13542
  return RouteType.MONORAIL;
13267
13543
  }
13268
13544
  };
13545
+ const serializeTripContinuations = (tripContinuations) => {
13546
+ const result = [];
13547
+ for (const [key, value] of tripContinuations.entries()) {
13548
+ result.push({
13549
+ key: key,
13550
+ value: value.map((tripBoarding) => ({
13551
+ hopOnStop: tripBoarding.hopOnStop,
13552
+ routeId: tripBoarding.routeId,
13553
+ tripIndex: tripBoarding.tripIndex,
13554
+ })),
13555
+ });
13556
+ }
13557
+ return result;
13558
+ };
13559
+ const deserializeTripContinuations = (protoTripContinuations) => {
13560
+ const result = new Map();
13561
+ for (let i = 0; i < protoTripContinuations.length; i++) {
13562
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13563
+ const entry = protoTripContinuations[i];
13564
+ const tripBoardings = entry.value.map((protoTripBoarding) => ({
13565
+ hopOnStop: protoTripBoarding.hopOnStop,
13566
+ routeId: protoTripBoarding.routeId,
13567
+ tripIndex: protoTripBoarding.tripIndex,
13568
+ }));
13569
+ result.set(entry.key, tripBoardings);
13570
+ }
13571
+ return result;
13572
+ };
13573
+
13574
+ // const ROUTE_ID_BITS = 17;
13575
+ const TRIP_INDEX_BITS = 15;
13576
+ /**
13577
+ * Encodes a route ID and trip index into a single trip ID.
13578
+ * @param routeId - The route identifier, needs to fit on 17 bits
13579
+ * @param tripIndex - The index of the trip within the route, needs to fit on 15 bits
13580
+ * @returns The encoded trip ID
13581
+ */
13582
+ const encode = (routeId, tripIndex) => {
13583
+ return (routeId << TRIP_INDEX_BITS) | tripIndex;
13584
+ };
13269
13585
 
13270
13586
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
13271
13587
  const ALL_TRANSPORT_MODES = new Set([
@@ -13280,7 +13596,8 @@ const ALL_TRANSPORT_MODES = new Set([
13280
13596
  'TROLLEYBUS',
13281
13597
  'MONORAIL',
13282
13598
  ]);
13283
- const CURRENT_VERSION = '0.0.7';
13599
+ const EMPTY_TRIP_CONTINUATIONS = [];
13600
+ const CURRENT_VERSION = '0.0.8';
13284
13601
  /**
13285
13602
  * The internal transit timetable format.
13286
13603
  */
@@ -13291,9 +13608,10 @@ class Timetable {
13291
13608
  this.serviceRoutes = routes;
13292
13609
  this.activeStops = new Set();
13293
13610
  for (let i = 0; i < stopsAdjacency.length; i++) {
13294
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13295
13611
  const stop = stopsAdjacency[i];
13296
- if (stop.routes.length > 0 || stop.transfers.length > 0) {
13612
+ if (stop.routes.length > 0 ||
13613
+ (stop.transfers && stop.transfers.length > 0) ||
13614
+ (stop.tripContinuations && stop.tripContinuations.size > 0)) {
13297
13615
  this.activeStops.add(i);
13298
13616
  }
13299
13617
  }
@@ -13356,8 +13674,27 @@ class Timetable {
13356
13674
  * @returns An array of transfer options available at the stop.
13357
13675
  */
13358
13676
  getTransfers(stopId) {
13359
- var _a, _b;
13360
- return (_b = (_a = this.stopsAdjacency[stopId]) === null || _a === void 0 ? void 0 : _a.transfers) !== null && _b !== void 0 ? _b : [];
13677
+ const stopAdjacency = this.stopsAdjacency[stopId];
13678
+ if (!stopAdjacency) {
13679
+ throw new Error(`Stop ID ${stopId} not found`);
13680
+ }
13681
+ return stopAdjacency.transfers || [];
13682
+ }
13683
+ /**
13684
+ * Retrieves all trip continuation options available at the specified stop for a given trip.
13685
+ *
13686
+ * @param stopId - The ID of the stop to get trip continuations for.
13687
+ * @param tripIndex - The index of the trip to get continuations for.
13688
+ * @returns An array of trip continuation options available at the stop for the specified trip.
13689
+ */
13690
+ getContinuousTrips(stopId, routeId, tripIndex) {
13691
+ var _a;
13692
+ const stopAdjacency = this.stopsAdjacency[stopId];
13693
+ if (!stopAdjacency) {
13694
+ throw new Error(`Stop ID ${stopId} not found`);
13695
+ }
13696
+ return (((_a = stopAdjacency.tripContinuations) === null || _a === void 0 ? void 0 : _a.get(encode(routeId, tripIndex))) ||
13697
+ EMPTY_TRIP_CONTINUATIONS);
13361
13698
  }
13362
13699
  /**
13363
13700
  * Retrieves the service route associated with the given route.
@@ -15643,6 +15980,7 @@ const parseGtfsLocationType = (gtfsLocationType) => {
15643
15980
  const parseTransfers = (transfersStream, stopsMap) => __awaiter(void 0, void 0, void 0, function* () {
15644
15981
  var _a, e_1, _b, _c;
15645
15982
  const transfers = new Map();
15983
+ const tripContinuations = new Map();
15646
15984
  try {
15647
15985
  for (var _d = true, _e = __asyncValues(parseCsv(transfersStream, [
15648
15986
  'transfer_type',
@@ -15656,25 +15994,48 @@ const parseTransfers = (transfersStream, stopsMap) => __awaiter(void 0, void 0,
15656
15994
  transferEntry.transfer_type === 5) {
15657
15995
  continue;
15658
15996
  }
15659
- if (transferEntry.from_trip_id && transferEntry.to_trip_id) {
15660
- console.warn(`Unsupported transfer between trips ${transferEntry.from_trip_id} and ${transferEntry.to_trip_id}.`);
15661
- continue;
15662
- }
15663
- if (transferEntry.from_route_id && transferEntry.to_route_id) {
15664
- console.warn(`Unsupported transfer between routes ${transferEntry.from_route_id} and ${transferEntry.to_route_id}.`);
15665
- continue;
15666
- }
15667
15997
  if (!transferEntry.from_stop_id || !transferEntry.to_stop_id) {
15668
15998
  console.warn(`Missing transfer origin or destination stop.`);
15669
15999
  continue;
15670
16000
  }
15671
- if (transferEntry.transfer_type === 2 && !transferEntry.min_transfer_time) {
15672
- console.info(`Missing minimum transfer time between ${transferEntry.from_stop_id} and ${transferEntry.to_stop_id}.`);
15673
- }
15674
16001
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15675
16002
  const fromStop = stopsMap.get(transferEntry.from_stop_id);
15676
16003
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15677
16004
  const toStop = stopsMap.get(transferEntry.to_stop_id);
16005
+ if (transferEntry.transfer_type === 4) {
16006
+ if (transferEntry.from_trip_id === undefined ||
16007
+ transferEntry.from_trip_id === '' ||
16008
+ transferEntry.to_trip_id === undefined ||
16009
+ transferEntry.to_trip_id === '') {
16010
+ console.warn(`Unsupported in-seat transfer, missing from_trip_id and/or to_trip_id.`);
16011
+ continue;
16012
+ }
16013
+ const tripBoardingEntry = {
16014
+ fromTrip: transferEntry.from_trip_id,
16015
+ toTrip: transferEntry.to_trip_id,
16016
+ hopOnStop: toStop.id,
16017
+ };
16018
+ const existingBoardings = tripContinuations.get(fromStop.id);
16019
+ if (existingBoardings) {
16020
+ existingBoardings.push(tripBoardingEntry);
16021
+ }
16022
+ else {
16023
+ tripContinuations.set(fromStop.id, [tripBoardingEntry]);
16024
+ }
16025
+ continue;
16026
+ }
16027
+ if (transferEntry.from_trip_id && transferEntry.to_trip_id) {
16028
+ console.warn(`Unsupported transfer of type ${transferEntry.transfer_type} between trips ${transferEntry.from_trip_id} and ${transferEntry.to_trip_id}.`);
16029
+ continue;
16030
+ }
16031
+ if (transferEntry.from_route_id && transferEntry.to_route_id) {
16032
+ console.warn(`Unsupported transfer of type ${transferEntry.transfer_type} between routes ${transferEntry.from_route_id} and ${transferEntry.to_route_id}.`);
16033
+ continue;
16034
+ }
16035
+ if (transferEntry.transfer_type === 2 &&
16036
+ transferEntry.min_transfer_time === undefined) {
16037
+ console.info(`Missing minimum transfer time between ${transferEntry.from_stop_id} and ${transferEntry.to_stop_id}.`);
16038
+ }
15678
16039
  const transfer = Object.assign({ destination: toStop.id, type: parseGtfsTransferType(transferEntry.transfer_type) }, (transferEntry.min_transfer_time && {
15679
16040
  minTransferTime: Duration.fromSeconds(transferEntry.min_transfer_time),
15680
16041
  }));
@@ -15690,7 +16051,10 @@ const parseTransfers = (transfersStream, stopsMap) => __awaiter(void 0, void 0,
15690
16051
  }
15691
16052
  finally { if (e_1) throw e_1.error; }
15692
16053
  }
15693
- return transfers;
16054
+ return {
16055
+ transfers,
16056
+ tripContinuations,
16057
+ };
15694
16058
  });
15695
16059
  const parseGtfsTransferType = (gtfsTransferType) => {
15696
16060
  switch (gtfsTransferType) {
@@ -15753,11 +16117,13 @@ const finalizeRouteFromBuilder = (builder) => {
15753
16117
  const stopTimesArray = new Uint16Array(stopsCount * tripsCount * 2);
15754
16118
  const allPickUpTypes = [];
15755
16119
  const allDropOffTypes = [];
16120
+ const gtfsTripIds = [];
15756
16121
  for (let tripIndex = 0; tripIndex < tripsCount; tripIndex++) {
15757
16122
  const trip = builder.trips[tripIndex];
15758
16123
  if (!trip) {
15759
16124
  throw new Error(`Missing trip data at index ${tripIndex}`);
15760
16125
  }
16126
+ gtfsTripIds.push(trip.gtfsTripId);
15761
16127
  const baseIndex = tripIndex * stopsCount * 2;
15762
16128
  for (let stopIndex = 0; stopIndex < stopsCount; stopIndex++) {
15763
16129
  const timeIndex = baseIndex + stopIndex * 2;
@@ -15779,12 +16145,15 @@ const finalizeRouteFromBuilder = (builder) => {
15779
16145
  }
15780
16146
  // Use 2-bit encoding for pickup/drop-off types
15781
16147
  const pickUpDropOffTypesArray = encodePickUpDropOffTypes(allPickUpTypes, allDropOffTypes);
15782
- return {
15783
- serviceRouteId: builder.serviceRouteId,
15784
- stops: stopsArray,
15785
- stopTimes: stopTimesArray,
15786
- pickUpDropOffTypes: pickUpDropOffTypesArray,
15787
- };
16148
+ return [
16149
+ {
16150
+ serviceRouteId: builder.serviceRouteId,
16151
+ stops: stopsArray,
16152
+ stopTimes: stopTimesArray,
16153
+ pickUpDropOffTypes: pickUpDropOffTypesArray,
16154
+ },
16155
+ gtfsTripIds,
16156
+ ];
15788
16157
  };
15789
16158
  /**
15790
16159
  * Parses the trips.txt file from a GTFS feed
@@ -15823,11 +16192,12 @@ const parseTrips = (tripsStream, serviceIds, validGtfsRoutes) => __awaiter(void
15823
16192
  }
15824
16193
  return trips;
15825
16194
  });
15826
- const buildStopsAdjacencyStructure = (serviceRoutes, routes, transfersMap, nbStops, activeStops) => {
15827
- // TODO somehow works when it's a map
16195
+ const buildStopsAdjacencyStructure = (tripsMapping, serviceRoutes, routes, transfersMap, tripContinuationsMap, nbStops, activeStops) => {
15828
16196
  const stopsAdjacency = new Array(nbStops);
15829
16197
  for (let i = 0; i < nbStops; i++) {
15830
- stopsAdjacency[i] = { routes: [], transfers: [] };
16198
+ stopsAdjacency[i] = {
16199
+ routes: [],
16200
+ };
15831
16201
  }
15832
16202
  for (let index = 0; index < routes.length; index++) {
15833
16203
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -15852,12 +16222,50 @@ const buildStopsAdjacencyStructure = (serviceRoutes, routes, transfersMap, nbSto
15852
16222
  const transfer = transfers[i];
15853
16223
  if (activeStops.has(stop) || activeStops.has(transfer.destination)) {
15854
16224
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15855
- stopsAdjacency[stop].transfers.push(transfer);
16225
+ const stopAdj = stopsAdjacency[stop];
16226
+ if (!stopAdj.transfers) {
16227
+ stopAdj.transfers = [];
16228
+ }
16229
+ stopAdj.transfers.push(transfer);
15856
16230
  activeStops.add(transfer.destination);
15857
16231
  activeStops.add(stop);
15858
16232
  }
15859
16233
  }
15860
16234
  }
16235
+ for (const [stop, tripContinuations] of tripContinuationsMap) {
16236
+ for (let i = 0; i < tripContinuations.length; i++) {
16237
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16238
+ const tripContinuation = tripContinuations[i];
16239
+ if (activeStops.has(stop) ||
16240
+ activeStops.has(tripContinuation.hopOnStop)) {
16241
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16242
+ const stopAdj = stopsAdjacency[stop];
16243
+ if (!stopAdj.tripContinuations) {
16244
+ stopAdj.tripContinuations = new Map();
16245
+ }
16246
+ const originTrip = tripsMapping.get(tripContinuation.fromTrip);
16247
+ const destinationTrip = tripsMapping.get(tripContinuation.toTrip);
16248
+ if (destinationTrip === undefined || originTrip === undefined) {
16249
+ continue;
16250
+ }
16251
+ const tripBoarding = {
16252
+ hopOnStop: tripContinuation.hopOnStop,
16253
+ routeId: destinationTrip.routeId,
16254
+ tripIndex: destinationTrip.tripRouteIndex,
16255
+ };
16256
+ const tripId = encode(originTrip.routeId, originTrip.tripRouteIndex);
16257
+ const existingContinuations = stopAdj.tripContinuations.get(tripId);
16258
+ if (existingContinuations) {
16259
+ existingContinuations.push(tripBoarding);
16260
+ }
16261
+ else {
16262
+ stopAdj.tripContinuations.set(tripId, [tripBoarding]);
16263
+ }
16264
+ activeStops.add(tripContinuation.hopOnStop);
16265
+ activeStops.add(stop);
16266
+ }
16267
+ }
16268
+ }
15861
16269
  return stopsAdjacency;
15862
16270
  };
15863
16271
  /**
@@ -15916,6 +16324,7 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
15916
16324
  }
15917
16325
  routeBuilder.trips.push({
15918
16326
  firstDeparture,
16327
+ gtfsTripId: currentTripId,
15919
16328
  arrivalTimes: arrivalTimes,
15920
16329
  departureTimes: departureTimes,
15921
16330
  pickUpTypes: pickUpTypes,
@@ -15953,6 +16362,9 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
15953
16362
  continue;
15954
16363
  }
15955
16364
  if (line.pickup_type === '1' && line.drop_off_type === '1') {
16365
+ // Warning: could potentially lead to issues if there is an in-seat transfer
16366
+ // at this stop - it can be not boardable nor alightable but still useful for an in-seat transfer.
16367
+ // This doesn't seem to happen in practice for now so keeping this condition to save memory.
15956
16368
  continue;
15957
16369
  }
15958
16370
  if (currentTripId && line.trip_id !== currentTripId && stops.length > 0) {
@@ -15989,11 +16401,19 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
15989
16401
  addTrip(currentTripId);
15990
16402
  }
15991
16403
  const routesAdjacency = [];
16404
+ const tripsMapping = new Map();
15992
16405
  for (const [, routeBuilder] of routeBuilders) {
15993
- const routeData = finalizeRouteFromBuilder(routeBuilder);
15994
- routesAdjacency.push(new Route(routeData.stopTimes, routeData.pickUpDropOffTypes, routeData.stops, routeData.serviceRouteId));
16406
+ const [routeData, gtfsTripIds] = finalizeRouteFromBuilder(routeBuilder);
16407
+ const routeId = routesAdjacency.length;
16408
+ routesAdjacency.push(new Route(routeId, routeData.stopTimes, routeData.pickUpDropOffTypes, routeData.stops, routeData.serviceRouteId));
16409
+ gtfsTripIds.forEach((tripId, index) => {
16410
+ tripsMapping.set(tripId, {
16411
+ routeId,
16412
+ tripRouteIndex: index,
16413
+ });
16414
+ });
15995
16415
  }
15996
- return { routes: routesAdjacency, serviceRoutesMap };
16416
+ return { routes: routesAdjacency, serviceRoutesMap, tripsMapping };
15997
16417
  });
15998
16418
  const parsePickupDropOffType = (gtfsType) => {
15999
16419
  switch (gtfsType) {
@@ -16072,24 +16492,27 @@ class GtfsParser {
16072
16492
  const tripsEnd = performance.now();
16073
16493
  log.info(`${trips.size} valid trips. (${(tripsEnd - tripsStart).toFixed(2)}ms)`);
16074
16494
  let transfers = new Map();
16495
+ let tripContinuations = new Map();
16075
16496
  if (entries[TRANSFERS_FILE]) {
16076
16497
  log.info(`Parsing ${TRANSFERS_FILE}`);
16077
16498
  const transfersStart = performance.now();
16078
16499
  const transfersStream = yield zip.stream(TRANSFERS_FILE);
16079
- transfers = yield parseTransfers(transfersStream, parsedStops);
16500
+ const { transfers: parsedTransfers, tripContinuations: parsedTripContinuations, } = yield parseTransfers(transfersStream, parsedStops);
16501
+ transfers = parsedTransfers;
16502
+ tripContinuations = parsedTripContinuations;
16080
16503
  const transfersEnd = performance.now();
16081
- log.info(`${transfers.size} valid transfers. (${(transfersEnd - transfersStart).toFixed(2)}ms)`);
16504
+ log.info(`${transfers.size} valid transfers and ${tripContinuations.size} trip continuations. (${(transfersEnd - transfersStart).toFixed(2)}ms)`);
16082
16505
  }
16083
16506
  log.info(`Parsing ${STOP_TIMES_FILE}`);
16084
16507
  const stopTimesStart = performance.now();
16085
16508
  const stopTimesStream = yield zip.stream(STOP_TIMES_FILE);
16086
- const { routes, serviceRoutesMap } = yield parseStopTimes(stopTimesStream, parsedStops, trips, activeStopIds);
16509
+ const { routes, serviceRoutesMap, tripsMapping } = yield parseStopTimes(stopTimesStream, parsedStops, trips, activeStopIds);
16087
16510
  const serviceRoutes = indexRoutes(validGtfsRoutes, serviceRoutesMap);
16088
16511
  const stopTimesEnd = performance.now();
16089
16512
  log.info(`${routes.length} valid unique routes. (${(stopTimesEnd - stopTimesStart).toFixed(2)}ms)`);
16090
16513
  log.info('Building stops adjacency structure');
16091
16514
  const stopsAdjacencyStart = performance.now();
16092
- const stopsAdjacency = buildStopsAdjacencyStructure(serviceRoutes, routes, transfers, parsedStops.size, activeStopIds);
16515
+ const stopsAdjacency = buildStopsAdjacencyStructure(tripsMapping, serviceRoutes, routes, transfers, tripContinuations, parsedStops.size, activeStopIds);
16093
16516
  const stopsAdjacencyEnd = performance.now();
16094
16517
  log.info(`${stopsAdjacency.length} valid stops in the structure. (${(stopsAdjacencyEnd - stopsAdjacencyStart).toFixed(2)}ms)`);
16095
16518
  yield zip.close();