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