minotor 8.0.0 → 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 (50) hide show
  1. package/CHANGELOG.md +4 -4
  2. package/README.md +1 -1
  3. package/dist/cli.mjs +835 -816
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/gtfs/transfers.d.ts +21 -6
  6. package/dist/gtfs/trips.d.ts +2 -2
  7. package/dist/parser.cjs.js +666 -642
  8. package/dist/parser.cjs.js.map +1 -1
  9. package/dist/parser.esm.js +666 -642
  10. package/dist/parser.esm.js.map +1 -1
  11. package/dist/router.cjs.js +1 -1
  12. package/dist/router.cjs.js.map +1 -1
  13. package/dist/router.esm.js +1 -1
  14. package/dist/router.esm.js.map +1 -1
  15. package/dist/router.umd.js +1 -1
  16. package/dist/router.umd.js.map +1 -1
  17. package/dist/routing/router.d.ts +4 -4
  18. package/dist/timetable/io.d.ts +3 -3
  19. package/dist/timetable/proto/timetable.d.ts +6 -4
  20. package/dist/timetable/route.d.ts +13 -21
  21. package/dist/timetable/timetable.d.ts +13 -11
  22. package/dist/timetable/tripBoardingId.d.ts +34 -0
  23. package/package.json +1 -1
  24. package/src/__e2e__/timetable/timetable.bin +2 -2
  25. package/src/cli/repl.ts +53 -67
  26. package/src/gtfs/__tests__/parser.test.ts +19 -4
  27. package/src/gtfs/__tests__/transfers.test.ts +598 -318
  28. package/src/gtfs/__tests__/trips.test.ts +3 -44
  29. package/src/gtfs/parser.ts +26 -8
  30. package/src/gtfs/transfers.ts +151 -20
  31. package/src/gtfs/trips.ts +1 -39
  32. package/src/routing/__tests__/result.test.ts +10 -10
  33. package/src/routing/__tests__/router.test.ts +11 -9
  34. package/src/routing/result.ts +2 -2
  35. package/src/routing/router.ts +34 -22
  36. package/src/timetable/__tests__/io.test.ts +8 -7
  37. package/src/timetable/__tests__/route.test.ts +66 -80
  38. package/src/timetable/__tests__/timetable.test.ts +32 -29
  39. package/src/timetable/__tests__/tripBoardingId.test.ts +57 -0
  40. package/src/timetable/io.ts +21 -20
  41. package/src/timetable/proto/timetable.proto +6 -4
  42. package/src/timetable/proto/timetable.ts +84 -48
  43. package/src/timetable/route.ts +39 -56
  44. package/src/timetable/timetable.ts +37 -26
  45. package/src/timetable/tripBoardingId.ts +94 -0
  46. package/tsconfig.json +2 -2
  47. package/dist/timetable/tripId.d.ts +0 -15
  48. package/src/timetable/__tests__/tripId.test.ts +0 -27
  49. package/src/timetable/tripId.ts +0 -29
  50. /package/dist/timetable/__tests__/{tripId.test.d.ts → tripBoardingId.test.d.ts} +0 -0
@@ -5,58 +5,6 @@ import require$$3 from 'events';
5
5
  import require$$4 from 'zlib';
6
6
  import require$$5, { Transform } from 'stream';
7
7
 
8
- /******************************************************************************
9
- Copyright (c) Microsoft Corporation.
10
-
11
- Permission to use, copy, modify, and/or distribute this software for any
12
- purpose with or without fee is hereby granted.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
15
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
16
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
17
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
18
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
19
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20
- PERFORMANCE OF THIS SOFTWARE.
21
- ***************************************************************************** */
22
- /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
23
-
24
-
25
- function __awaiter(thisArg, _arguments, P, generator) {
26
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
- return new (P || (P = Promise))(function (resolve, reject) {
28
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
- step((generator = generator.apply(thisArg, _arguments || [])).next());
32
- });
33
- }
34
-
35
- function __values(o) {
36
- var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
37
- if (m) return m.call(o);
38
- if (o && typeof o.length === "number") return {
39
- next: function () {
40
- if (o && i >= o.length) o = void 0;
41
- return { value: o && o[i++], done: !o };
42
- }
43
- };
44
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
45
- }
46
-
47
- function __asyncValues(o) {
48
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
49
- var m = o[Symbol.asyncIterator], i;
50
- return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
51
- function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
52
- function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
53
- }
54
-
55
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
56
- var e = new Error(message);
57
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
58
- };
59
-
60
8
  function getDefaultExportFromCjs (x) {
61
9
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
62
10
  }
@@ -11552,14 +11500,13 @@ const Stop = {
11552
11500
  sourceStopId: isSet$1(object.sourceStopId) ? globalThis.String(object.sourceStopId) : "",
11553
11501
  lat: isSet$1(object.lat) ? globalThis.Number(object.lat) : undefined,
11554
11502
  lon: isSet$1(object.lon) ? globalThis.Number(object.lon) : undefined,
11555
- children: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.children) ? object.children.map((e) => globalThis.Number(e)) : [],
11503
+ children: globalThis.Array.isArray(object?.children) ? object.children.map((e) => globalThis.Number(e)) : [],
11556
11504
  parent: isSet$1(object.parent) ? globalThis.Number(object.parent) : undefined,
11557
11505
  locationType: isSet$1(object.locationType) ? locationTypeFromJSON(object.locationType) : 0,
11558
11506
  platform: isSet$1(object.platform) ? globalThis.String(object.platform) : undefined,
11559
11507
  };
11560
11508
  },
11561
11509
  toJSON(message) {
11562
- var _a;
11563
11510
  const obj = {};
11564
11511
  if (message.name !== "") {
11565
11512
  obj.name = message.name;
@@ -11573,7 +11520,7 @@ const Stop = {
11573
11520
  if (message.lon !== undefined) {
11574
11521
  obj.lon = message.lon;
11575
11522
  }
11576
- if ((_a = message.children) === null || _a === void 0 ? void 0 : _a.length) {
11523
+ if (message.children?.length) {
11577
11524
  obj.children = message.children.map((e) => Math.round(e));
11578
11525
  }
11579
11526
  if (message.parent !== undefined) {
@@ -11588,19 +11535,18 @@ const Stop = {
11588
11535
  return obj;
11589
11536
  },
11590
11537
  create(base) {
11591
- return Stop.fromPartial(base !== null && base !== void 0 ? base : {});
11538
+ return Stop.fromPartial(base ?? {});
11592
11539
  },
11593
11540
  fromPartial(object) {
11594
- var _a, _b, _c, _d, _e, _f, _g, _h;
11595
11541
  const message = createBaseStop();
11596
- message.name = (_a = object.name) !== null && _a !== void 0 ? _a : "";
11597
- message.sourceStopId = (_b = object.sourceStopId) !== null && _b !== void 0 ? _b : "";
11598
- message.lat = (_c = object.lat) !== null && _c !== void 0 ? _c : undefined;
11599
- message.lon = (_d = object.lon) !== null && _d !== void 0 ? _d : undefined;
11600
- message.children = ((_e = object.children) === null || _e === void 0 ? void 0 : _e.map((e) => e)) || [];
11601
- message.parent = (_f = object.parent) !== null && _f !== void 0 ? _f : undefined;
11602
- message.locationType = (_g = object.locationType) !== null && _g !== void 0 ? _g : 0;
11603
- message.platform = (_h = object.platform) !== null && _h !== void 0 ? _h : undefined;
11542
+ message.name = object.name ?? "";
11543
+ message.sourceStopId = object.sourceStopId ?? "";
11544
+ message.lat = object.lat ?? undefined;
11545
+ message.lon = object.lon ?? undefined;
11546
+ message.children = object.children?.map((e) => e) || [];
11547
+ message.parent = object.parent ?? undefined;
11548
+ message.locationType = object.locationType ?? 0;
11549
+ message.platform = object.platform ?? undefined;
11604
11550
  return message;
11605
11551
  },
11606
11552
  };
@@ -11649,28 +11595,26 @@ const StopsMap = {
11649
11595
  fromJSON(object) {
11650
11596
  return {
11651
11597
  version: isSet$1(object.version) ? globalThis.String(object.version) : "",
11652
- stops: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.stops) ? object.stops.map((e) => Stop.fromJSON(e)) : [],
11598
+ stops: globalThis.Array.isArray(object?.stops) ? object.stops.map((e) => Stop.fromJSON(e)) : [],
11653
11599
  };
11654
11600
  },
11655
11601
  toJSON(message) {
11656
- var _a;
11657
11602
  const obj = {};
11658
11603
  if (message.version !== "") {
11659
11604
  obj.version = message.version;
11660
11605
  }
11661
- if ((_a = message.stops) === null || _a === void 0 ? void 0 : _a.length) {
11606
+ if (message.stops?.length) {
11662
11607
  obj.stops = message.stops.map((e) => Stop.toJSON(e));
11663
11608
  }
11664
11609
  return obj;
11665
11610
  },
11666
11611
  create(base) {
11667
- return StopsMap.fromPartial(base !== null && base !== void 0 ? base : {});
11612
+ return StopsMap.fromPartial(base ?? {});
11668
11613
  },
11669
11614
  fromPartial(object) {
11670
- var _a, _b;
11671
11615
  const message = createBaseStopsMap();
11672
- message.version = (_a = object.version) !== null && _a !== void 0 ? _a : "";
11673
- message.stops = ((_b = object.stops) === null || _b === void 0 ? void 0 : _b.map((e) => Stop.fromPartial(e))) || [];
11616
+ message.version = object.version ?? "";
11617
+ message.stops = object.stops?.map((e) => Stop.fromPartial(e)) || [];
11674
11618
  return message;
11675
11619
  },
11676
11620
  };
@@ -11754,8 +11698,12 @@ const serializeLocationType = (locationType) => {
11754
11698
  * to efficiently find stops based on user queries.
11755
11699
  */
11756
11700
  class StopsIndex {
11701
+ stops;
11702
+ sourceStopsMap;
11703
+ textIndex;
11704
+ geoIndex;
11705
+ stopPoints;
11757
11706
  constructor(stops) {
11758
- var _a;
11759
11707
  this.stops = stops;
11760
11708
  this.sourceStopsMap = new Map();
11761
11709
  const stopsSet = new Map();
@@ -11764,7 +11712,7 @@ class StopsIndex {
11764
11712
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
11765
11713
  const stop = stops[id];
11766
11714
  this.sourceStopsMap.set(stop.sourceStopId, id);
11767
- const effectiveStopId = (_a = stop.parent) !== null && _a !== void 0 ? _a : id;
11715
+ const effectiveStopId = stop.parent ?? id;
11768
11716
  if (!stopsSet.has(effectiveStopId)) {
11769
11717
  stopsSet.set(effectiveStopId, {
11770
11718
  id: effectiveStopId,
@@ -11879,7 +11827,6 @@ class StopsIndex {
11879
11827
  * Find ids of all sibling stops.
11880
11828
  */
11881
11829
  equivalentStops(sourceId) {
11882
- var _a, _b;
11883
11830
  const id = this.sourceStopsMap.get(sourceId);
11884
11831
  if (id === undefined) {
11885
11832
  return [];
@@ -11889,13 +11836,14 @@ class StopsIndex {
11889
11836
  return [];
11890
11837
  }
11891
11838
  const equivalentStops = stop.parent
11892
- ? ((_b = (_a = this.stops[stop.parent]) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : [])
11839
+ ? (this.stops[stop.parent]?.children ?? [])
11893
11840
  : stop.children;
11894
11841
  return Array.from(new Set([id, ...equivalentStops])).map((stopId) => this.stops[stopId]);
11895
11842
  }
11896
11843
  }
11897
11844
 
11898
11845
  class Duration {
11846
+ totalSeconds;
11899
11847
  constructor(totalSeconds) {
11900
11848
  this.totalSeconds = totalSeconds;
11901
11849
  }
@@ -12198,15 +12146,14 @@ const Route$1 = {
12198
12146
  return obj;
12199
12147
  },
12200
12148
  create(base) {
12201
- return Route$1.fromPartial(base !== null && base !== void 0 ? base : {});
12149
+ return Route$1.fromPartial(base ?? {});
12202
12150
  },
12203
12151
  fromPartial(object) {
12204
- var _a, _b, _c, _d;
12205
12152
  const message = createBaseRoute();
12206
- message.stopTimes = (_a = object.stopTimes) !== null && _a !== void 0 ? _a : new Uint8Array(0);
12207
- message.pickUpDropOffTypes = (_b = object.pickUpDropOffTypes) !== null && _b !== void 0 ? _b : new Uint8Array(0);
12208
- message.stops = (_c = object.stops) !== null && _c !== void 0 ? _c : new Uint8Array(0);
12209
- message.serviceRouteId = (_d = object.serviceRouteId) !== null && _d !== void 0 ? _d : 0;
12153
+ message.stopTimes = object.stopTimes ?? new Uint8Array(0);
12154
+ message.pickUpDropOffTypes = object.pickUpDropOffTypes ?? new Uint8Array(0);
12155
+ message.stops = object.stops ?? new Uint8Array(0);
12156
+ message.serviceRouteId = object.serviceRouteId ?? 0;
12210
12157
  return message;
12211
12158
  },
12212
12159
  };
@@ -12283,24 +12230,23 @@ const Transfer = {
12283
12230
  return obj;
12284
12231
  },
12285
12232
  create(base) {
12286
- return Transfer.fromPartial(base !== null && base !== void 0 ? base : {});
12233
+ return Transfer.fromPartial(base ?? {});
12287
12234
  },
12288
12235
  fromPartial(object) {
12289
- var _a, _b, _c;
12290
12236
  const message = createBaseTransfer();
12291
- message.destination = (_a = object.destination) !== null && _a !== void 0 ? _a : 0;
12292
- message.type = (_b = object.type) !== null && _b !== void 0 ? _b : 0;
12293
- message.minTransferTime = (_c = object.minTransferTime) !== null && _c !== void 0 ? _c : undefined;
12237
+ message.destination = object.destination ?? 0;
12238
+ message.type = object.type ?? 0;
12239
+ message.minTransferTime = object.minTransferTime ?? undefined;
12294
12240
  return message;
12295
12241
  },
12296
12242
  };
12297
12243
  function createBaseTripBoarding() {
12298
- return { hopOnStop: 0, routeId: 0, tripIndex: 0 };
12244
+ return { hopOnStopIndex: 0, routeId: 0, tripIndex: 0 };
12299
12245
  }
12300
12246
  const TripBoarding = {
12301
12247
  encode(message, writer = new BinaryWriter()) {
12302
- if (message.hopOnStop !== 0) {
12303
- writer.uint32(8).uint32(message.hopOnStop);
12248
+ if (message.hopOnStopIndex !== 0) {
12249
+ writer.uint32(8).uint32(message.hopOnStopIndex);
12304
12250
  }
12305
12251
  if (message.routeId !== 0) {
12306
12252
  writer.uint32(16).uint32(message.routeId);
@@ -12321,7 +12267,7 @@ const TripBoarding = {
12321
12267
  if (tag !== 8) {
12322
12268
  break;
12323
12269
  }
12324
- message.hopOnStop = reader.uint32();
12270
+ message.hopOnStopIndex = reader.uint32();
12325
12271
  continue;
12326
12272
  }
12327
12273
  case 2: {
@@ -12348,15 +12294,15 @@ const TripBoarding = {
12348
12294
  },
12349
12295
  fromJSON(object) {
12350
12296
  return {
12351
- hopOnStop: isSet(object.hopOnStop) ? globalThis.Number(object.hopOnStop) : 0,
12297
+ hopOnStopIndex: isSet(object.hopOnStopIndex) ? globalThis.Number(object.hopOnStopIndex) : 0,
12352
12298
  routeId: isSet(object.routeId) ? globalThis.Number(object.routeId) : 0,
12353
12299
  tripIndex: isSet(object.tripIndex) ? globalThis.Number(object.tripIndex) : 0,
12354
12300
  };
12355
12301
  },
12356
12302
  toJSON(message) {
12357
12303
  const obj = {};
12358
- if (message.hopOnStop !== 0) {
12359
- obj.hopOnStop = Math.round(message.hopOnStop);
12304
+ if (message.hopOnStopIndex !== 0) {
12305
+ obj.hopOnStopIndex = Math.round(message.hopOnStopIndex);
12360
12306
  }
12361
12307
  if (message.routeId !== 0) {
12362
12308
  obj.routeId = Math.round(message.routeId);
@@ -12367,27 +12313,32 @@ const TripBoarding = {
12367
12313
  return obj;
12368
12314
  },
12369
12315
  create(base) {
12370
- return TripBoarding.fromPartial(base !== null && base !== void 0 ? base : {});
12316
+ return TripBoarding.fromPartial(base ?? {});
12371
12317
  },
12372
12318
  fromPartial(object) {
12373
- var _a, _b, _c;
12374
12319
  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;
12320
+ message.hopOnStopIndex = object.hopOnStopIndex ?? 0;
12321
+ message.routeId = object.routeId ?? 0;
12322
+ message.tripIndex = object.tripIndex ?? 0;
12378
12323
  return message;
12379
12324
  },
12380
12325
  };
12381
12326
  function createBaseTripContinuationEntry() {
12382
- return { key: 0, value: [] };
12327
+ return { originStopIndex: 0, originRouteId: 0, originTripIndex: 0, continuations: [] };
12383
12328
  }
12384
12329
  const TripContinuationEntry = {
12385
12330
  encode(message, writer = new BinaryWriter()) {
12386
- if (message.key !== 0) {
12387
- writer.uint32(8).uint32(message.key);
12331
+ if (message.originStopIndex !== 0) {
12332
+ writer.uint32(8).uint32(message.originStopIndex);
12333
+ }
12334
+ if (message.originRouteId !== 0) {
12335
+ writer.uint32(16).uint32(message.originRouteId);
12336
+ }
12337
+ if (message.originTripIndex !== 0) {
12338
+ writer.uint32(24).uint32(message.originTripIndex);
12388
12339
  }
12389
- for (const v of message.value) {
12390
- TripBoarding.encode(v, writer.uint32(18).fork()).join();
12340
+ for (const v of message.continuations) {
12341
+ TripBoarding.encode(v, writer.uint32(34).fork()).join();
12391
12342
  }
12392
12343
  return writer;
12393
12344
  },
@@ -12402,14 +12353,28 @@ const TripContinuationEntry = {
12402
12353
  if (tag !== 8) {
12403
12354
  break;
12404
12355
  }
12405
- message.key = reader.uint32();
12356
+ message.originStopIndex = reader.uint32();
12406
12357
  continue;
12407
12358
  }
12408
12359
  case 2: {
12409
- if (tag !== 18) {
12360
+ if (tag !== 16) {
12361
+ break;
12362
+ }
12363
+ message.originRouteId = reader.uint32();
12364
+ continue;
12365
+ }
12366
+ case 3: {
12367
+ if (tag !== 24) {
12410
12368
  break;
12411
12369
  }
12412
- message.value.push(TripBoarding.decode(reader, reader.uint32()));
12370
+ message.originTripIndex = reader.uint32();
12371
+ continue;
12372
+ }
12373
+ case 4: {
12374
+ if (tag !== 34) {
12375
+ break;
12376
+ }
12377
+ message.continuations.push(TripBoarding.decode(reader, reader.uint32()));
12413
12378
  continue;
12414
12379
  }
12415
12380
  }
@@ -12422,34 +12387,44 @@ const TripContinuationEntry = {
12422
12387
  },
12423
12388
  fromJSON(object) {
12424
12389
  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)) : [],
12390
+ originStopIndex: isSet(object.originStopIndex) ? globalThis.Number(object.originStopIndex) : 0,
12391
+ originRouteId: isSet(object.originRouteId) ? globalThis.Number(object.originRouteId) : 0,
12392
+ originTripIndex: isSet(object.originTripIndex) ? globalThis.Number(object.originTripIndex) : 0,
12393
+ continuations: globalThis.Array.isArray(object?.continuations)
12394
+ ? object.continuations.map((e) => TripBoarding.fromJSON(e))
12395
+ : [],
12427
12396
  };
12428
12397
  },
12429
12398
  toJSON(message) {
12430
- var _a;
12431
12399
  const obj = {};
12432
- if (message.key !== 0) {
12433
- obj.key = Math.round(message.key);
12400
+ if (message.originStopIndex !== 0) {
12401
+ obj.originStopIndex = Math.round(message.originStopIndex);
12402
+ }
12403
+ if (message.originRouteId !== 0) {
12404
+ obj.originRouteId = Math.round(message.originRouteId);
12434
12405
  }
12435
- if ((_a = message.value) === null || _a === void 0 ? void 0 : _a.length) {
12436
- obj.value = message.value.map((e) => TripBoarding.toJSON(e));
12406
+ if (message.originTripIndex !== 0) {
12407
+ obj.originTripIndex = Math.round(message.originTripIndex);
12408
+ }
12409
+ if (message.continuations?.length) {
12410
+ obj.continuations = message.continuations.map((e) => TripBoarding.toJSON(e));
12437
12411
  }
12438
12412
  return obj;
12439
12413
  },
12440
12414
  create(base) {
12441
- return TripContinuationEntry.fromPartial(base !== null && base !== void 0 ? base : {});
12415
+ return TripContinuationEntry.fromPartial(base ?? {});
12442
12416
  },
12443
12417
  fromPartial(object) {
12444
- var _a, _b;
12445
12418
  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))) || [];
12419
+ message.originStopIndex = object.originStopIndex ?? 0;
12420
+ message.originRouteId = object.originRouteId ?? 0;
12421
+ message.originTripIndex = object.originTripIndex ?? 0;
12422
+ message.continuations = object.continuations?.map((e) => TripBoarding.fromPartial(e)) || [];
12448
12423
  return message;
12449
12424
  },
12450
12425
  };
12451
12426
  function createBaseStopAdjacency() {
12452
- return { routes: [], transfers: [], tripContinuations: [] };
12427
+ return { routes: [], transfers: [] };
12453
12428
  }
12454
12429
  const StopAdjacency = {
12455
12430
  encode(message, writer = new BinaryWriter()) {
@@ -12461,9 +12436,6 @@ const StopAdjacency = {
12461
12436
  for (const v of message.transfers) {
12462
12437
  Transfer.encode(v, writer.uint32(18).fork()).join();
12463
12438
  }
12464
- for (const v of message.tripContinuations) {
12465
- TripContinuationEntry.encode(v, writer.uint32(26).fork()).join();
12466
- }
12467
12439
  return writer;
12468
12440
  },
12469
12441
  decode(input, length) {
@@ -12494,13 +12466,6 @@ const StopAdjacency = {
12494
12466
  message.transfers.push(Transfer.decode(reader, reader.uint32()));
12495
12467
  continue;
12496
12468
  }
12497
- case 3: {
12498
- if (tag !== 26) {
12499
- break;
12500
- }
12501
- message.tripContinuations.push(TripContinuationEntry.decode(reader, reader.uint32()));
12502
- continue;
12503
- }
12504
12469
  }
12505
12470
  if ((tag & 7) === 4 || tag === 0) {
12506
12471
  break;
@@ -12511,38 +12476,29 @@ const StopAdjacency = {
12511
12476
  },
12512
12477
  fromJSON(object) {
12513
12478
  return {
12514
- routes: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.routes) ? object.routes.map((e) => globalThis.Number(e)) : [],
12515
- transfers: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.transfers)
12479
+ routes: globalThis.Array.isArray(object?.routes) ? object.routes.map((e) => globalThis.Number(e)) : [],
12480
+ transfers: globalThis.Array.isArray(object?.transfers)
12516
12481
  ? object.transfers.map((e) => Transfer.fromJSON(e))
12517
12482
  : [],
12518
- tripContinuations: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.tripContinuations)
12519
- ? object.tripContinuations.map((e) => TripContinuationEntry.fromJSON(e))
12520
- : [],
12521
12483
  };
12522
12484
  },
12523
12485
  toJSON(message) {
12524
- var _a, _b, _c;
12525
12486
  const obj = {};
12526
- if ((_a = message.routes) === null || _a === void 0 ? void 0 : _a.length) {
12487
+ if (message.routes?.length) {
12527
12488
  obj.routes = message.routes.map((e) => Math.round(e));
12528
12489
  }
12529
- if ((_b = message.transfers) === null || _b === void 0 ? void 0 : _b.length) {
12490
+ if (message.transfers?.length) {
12530
12491
  obj.transfers = message.transfers.map((e) => Transfer.toJSON(e));
12531
12492
  }
12532
- if ((_c = message.tripContinuations) === null || _c === void 0 ? void 0 : _c.length) {
12533
- obj.tripContinuations = message.tripContinuations.map((e) => TripContinuationEntry.toJSON(e));
12534
- }
12535
12493
  return obj;
12536
12494
  },
12537
12495
  create(base) {
12538
- return StopAdjacency.fromPartial(base !== null && base !== void 0 ? base : {});
12496
+ return StopAdjacency.fromPartial(base ?? {});
12539
12497
  },
12540
12498
  fromPartial(object) {
12541
- var _a, _b, _c;
12542
12499
  const message = createBaseStopAdjacency();
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))) || [];
12500
+ message.routes = object.routes?.map((e) => e) || [];
12501
+ message.transfers = object.transfers?.map((e) => Transfer.fromPartial(e)) || [];
12546
12502
  return message;
12547
12503
  },
12548
12504
  };
@@ -12611,11 +12567,10 @@ const ServiceRoute = {
12611
12567
  return {
12612
12568
  type: isSet(object.type) ? routeTypeFromJSON(object.type) : 0,
12613
12569
  name: isSet(object.name) ? globalThis.String(object.name) : "",
12614
- routes: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.routes) ? object.routes.map((e) => globalThis.Number(e)) : [],
12570
+ routes: globalThis.Array.isArray(object?.routes) ? object.routes.map((e) => globalThis.Number(e)) : [],
12615
12571
  };
12616
12572
  },
12617
12573
  toJSON(message) {
12618
- var _a;
12619
12574
  const obj = {};
12620
12575
  if (message.type !== 0) {
12621
12576
  obj.type = routeTypeToJSON(message.type);
@@ -12623,25 +12578,24 @@ const ServiceRoute = {
12623
12578
  if (message.name !== "") {
12624
12579
  obj.name = message.name;
12625
12580
  }
12626
- if ((_a = message.routes) === null || _a === void 0 ? void 0 : _a.length) {
12581
+ if (message.routes?.length) {
12627
12582
  obj.routes = message.routes.map((e) => Math.round(e));
12628
12583
  }
12629
12584
  return obj;
12630
12585
  },
12631
12586
  create(base) {
12632
- return ServiceRoute.fromPartial(base !== null && base !== void 0 ? base : {});
12587
+ return ServiceRoute.fromPartial(base ?? {});
12633
12588
  },
12634
12589
  fromPartial(object) {
12635
- var _a, _b, _c;
12636
12590
  const message = createBaseServiceRoute();
12637
- message.type = (_a = object.type) !== null && _a !== void 0 ? _a : 0;
12638
- message.name = (_b = object.name) !== null && _b !== void 0 ? _b : "";
12639
- message.routes = ((_c = object.routes) === null || _c === void 0 ? void 0 : _c.map((e) => e)) || [];
12591
+ message.type = object.type ?? 0;
12592
+ message.name = object.name ?? "";
12593
+ message.routes = object.routes?.map((e) => e) || [];
12640
12594
  return message;
12641
12595
  },
12642
12596
  };
12643
12597
  function createBaseTimetable() {
12644
- return { version: "", stopsAdjacency: [], routesAdjacency: [], serviceRoutes: [] };
12598
+ return { version: "", stopsAdjacency: [], routesAdjacency: [], serviceRoutes: [], tripContinuations: [] };
12645
12599
  }
12646
12600
  const Timetable$1 = {
12647
12601
  encode(message, writer = new BinaryWriter()) {
@@ -12657,6 +12611,9 @@ const Timetable$1 = {
12657
12611
  for (const v of message.serviceRoutes) {
12658
12612
  ServiceRoute.encode(v, writer.uint32(34).fork()).join();
12659
12613
  }
12614
+ for (const v of message.tripContinuations) {
12615
+ TripContinuationEntry.encode(v, writer.uint32(42).fork()).join();
12616
+ }
12660
12617
  return writer;
12661
12618
  },
12662
12619
  decode(input, length) {
@@ -12694,6 +12651,13 @@ const Timetable$1 = {
12694
12651
  message.serviceRoutes.push(ServiceRoute.decode(reader, reader.uint32()));
12695
12652
  continue;
12696
12653
  }
12654
+ case 5: {
12655
+ if (tag !== 42) {
12656
+ break;
12657
+ }
12658
+ message.tripContinuations.push(TripContinuationEntry.decode(reader, reader.uint32()));
12659
+ continue;
12660
+ }
12697
12661
  }
12698
12662
  if ((tag & 7) === 4 || tag === 0) {
12699
12663
  break;
@@ -12705,44 +12669,49 @@ const Timetable$1 = {
12705
12669
  fromJSON(object) {
12706
12670
  return {
12707
12671
  version: isSet(object.version) ? globalThis.String(object.version) : "",
12708
- stopsAdjacency: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.stopsAdjacency)
12672
+ stopsAdjacency: globalThis.Array.isArray(object?.stopsAdjacency)
12709
12673
  ? object.stopsAdjacency.map((e) => StopAdjacency.fromJSON(e))
12710
12674
  : [],
12711
- routesAdjacency: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.routesAdjacency)
12675
+ routesAdjacency: globalThis.Array.isArray(object?.routesAdjacency)
12712
12676
  ? object.routesAdjacency.map((e) => Route$1.fromJSON(e))
12713
12677
  : [],
12714
- serviceRoutes: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.serviceRoutes)
12678
+ serviceRoutes: globalThis.Array.isArray(object?.serviceRoutes)
12715
12679
  ? object.serviceRoutes.map((e) => ServiceRoute.fromJSON(e))
12716
12680
  : [],
12681
+ tripContinuations: globalThis.Array.isArray(object?.tripContinuations)
12682
+ ? object.tripContinuations.map((e) => TripContinuationEntry.fromJSON(e))
12683
+ : [],
12717
12684
  };
12718
12685
  },
12719
12686
  toJSON(message) {
12720
- var _a, _b, _c;
12721
12687
  const obj = {};
12722
12688
  if (message.version !== "") {
12723
12689
  obj.version = message.version;
12724
12690
  }
12725
- if ((_a = message.stopsAdjacency) === null || _a === void 0 ? void 0 : _a.length) {
12691
+ if (message.stopsAdjacency?.length) {
12726
12692
  obj.stopsAdjacency = message.stopsAdjacency.map((e) => StopAdjacency.toJSON(e));
12727
12693
  }
12728
- if ((_b = message.routesAdjacency) === null || _b === void 0 ? void 0 : _b.length) {
12694
+ if (message.routesAdjacency?.length) {
12729
12695
  obj.routesAdjacency = message.routesAdjacency.map((e) => Route$1.toJSON(e));
12730
12696
  }
12731
- if ((_c = message.serviceRoutes) === null || _c === void 0 ? void 0 : _c.length) {
12697
+ if (message.serviceRoutes?.length) {
12732
12698
  obj.serviceRoutes = message.serviceRoutes.map((e) => ServiceRoute.toJSON(e));
12733
12699
  }
12700
+ if (message.tripContinuations?.length) {
12701
+ obj.tripContinuations = message.tripContinuations.map((e) => TripContinuationEntry.toJSON(e));
12702
+ }
12734
12703
  return obj;
12735
12704
  },
12736
12705
  create(base) {
12737
- return Timetable$1.fromPartial(base !== null && base !== void 0 ? base : {});
12706
+ return Timetable$1.fromPartial(base ?? {});
12738
12707
  },
12739
12708
  fromPartial(object) {
12740
- var _a, _b, _c, _d;
12741
12709
  const message = createBaseTimetable();
12742
- message.version = (_a = object.version) !== null && _a !== void 0 ? _a : "";
12743
- message.stopsAdjacency = ((_b = object.stopsAdjacency) === null || _b === void 0 ? void 0 : _b.map((e) => StopAdjacency.fromPartial(e))) || [];
12744
- message.routesAdjacency = ((_c = object.routesAdjacency) === null || _c === void 0 ? void 0 : _c.map((e) => Route$1.fromPartial(e))) || [];
12745
- message.serviceRoutes = ((_d = object.serviceRoutes) === null || _d === void 0 ? void 0 : _d.map((e) => ServiceRoute.fromPartial(e))) || [];
12710
+ message.version = object.version ?? "";
12711
+ message.stopsAdjacency = object.stopsAdjacency?.map((e) => StopAdjacency.fromPartial(e)) || [];
12712
+ message.routesAdjacency = object.routesAdjacency?.map((e) => Route$1.fromPartial(e)) || [];
12713
+ message.serviceRoutes = object.serviceRoutes?.map((e) => ServiceRoute.fromPartial(e)) || [];
12714
+ message.tripContinuations = object.tripContinuations?.map((e) => TripContinuationEntry.fromPartial(e)) || [];
12746
12715
  return message;
12747
12716
  },
12748
12717
  };
@@ -12779,6 +12748,11 @@ function isSet(value) {
12779
12748
  * A class representing a time as minutes since midnight.
12780
12749
  */
12781
12750
  class Time {
12751
+ /*
12752
+ * Number of minutes since midnight.
12753
+ Note that this value can go beyond 3600 to model services overlapping with the next day.
12754
+ */
12755
+ minutesSinceMidnight;
12782
12756
  /**
12783
12757
  * Gets the infinity time as a Time instance.
12784
12758
  * This represents a time that is conceptually beyond any real possible time.
@@ -13031,6 +13005,51 @@ const toPickupDropOffType = (numericalType) => {
13031
13005
  * A route identifies all trips of a given service route sharing the same list of stops.
13032
13006
  */
13033
13007
  class Route {
13008
+ id;
13009
+ /**
13010
+ * Arrivals and departures encoded as minutes from midnight.
13011
+ * Format: [arrival1, departure1, arrival2, departure2, etc.]
13012
+ */
13013
+ stopTimes;
13014
+ /**
13015
+ * PickUp and DropOff types represented as a 2-bit encoded Uint8Array.
13016
+ * Values (2 bits each):
13017
+ * 0: REGULAR
13018
+ * 1: NOT_AVAILABLE
13019
+ * 2: MUST_PHONE_AGENCY
13020
+ * 3: MUST_COORDINATE_WITH_DRIVER
13021
+ *
13022
+ * Encoding format: Each byte contains 2 pickup/drop-off pairs (4 bits each)
13023
+ * Bit layout per byte: [pickup_1 (2 bits)][drop_off_1 (2 bits)][pickup_0 (2 bits)][drop_off_0 (2 bits)]
13024
+ * Example: For stops 0 and 1 in a trip, one byte encodes all 4 values
13025
+ */
13026
+ pickUpDropOffTypes;
13027
+ /**
13028
+ * A binary array of stopIds in the route.
13029
+ * [stop1, stop2, stop3,...]
13030
+ */
13031
+ stops;
13032
+ /**
13033
+ * A reverse mapping of each stop with their index in the route:
13034
+ * {
13035
+ * 4: 0,
13036
+ * 5: 1,
13037
+ * ...
13038
+ * }
13039
+ */
13040
+ stopIndices;
13041
+ /**
13042
+ * The identifier of the route as a service shown to users.
13043
+ */
13044
+ serviceRouteId;
13045
+ /**
13046
+ * The total number of stops in the route.
13047
+ */
13048
+ nbStops;
13049
+ /**
13050
+ * The total number of trips in the route.
13051
+ */
13052
+ nbTrips;
13034
13053
  constructor(id, stopTimes, pickUpDropOffTypes, stops, serviceRouteId) {
13035
13054
  this.id = id;
13036
13055
  this.stopTimes = stopTimes;
@@ -13042,7 +13061,14 @@ class Route {
13042
13061
  this.stopIndices = new Map();
13043
13062
  for (let i = 0; i < stops.length; i++) {
13044
13063
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13045
- this.stopIndices.set(stops[i], i);
13064
+ const stopId = stops[i];
13065
+ const existingIndices = this.stopIndices.get(stopId);
13066
+ if (existingIndices) {
13067
+ existingIndices.push(i);
13068
+ }
13069
+ else {
13070
+ this.stopIndices.set(stopId, [i]);
13071
+ }
13046
13072
  }
13047
13073
  }
13048
13074
  /**
@@ -13052,7 +13078,6 @@ class Route {
13052
13078
  * @returns The new route.
13053
13079
  */
13054
13080
  static of(params) {
13055
- var _a, _b;
13056
13081
  const { id, serviceRouteId, trips } = params;
13057
13082
  if (trips.length === 0) {
13058
13083
  throw new Error('At least one trip must be provided');
@@ -13099,8 +13124,8 @@ class Route {
13099
13124
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13100
13125
  const stop = trip.stops[stopIndex];
13101
13126
  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;
13127
+ const pickUp = stop.pickUpType ?? REGULAR;
13128
+ const dropOff = stop.dropOffType ?? REGULAR;
13104
13129
  const byteIndex = Math.floor(globalIndex / 2);
13105
13130
  const isSecondPair = globalIndex % 2 === 1;
13106
13131
  if (isSecondPair) {
@@ -13130,24 +13155,6 @@ class Route {
13130
13155
  serviceRouteId: this.serviceRouteId,
13131
13156
  };
13132
13157
  }
13133
- /**
13134
- * Checks if stop A is before stop B in the route.
13135
- *
13136
- * @param stopA - The StopId of the first stop.
13137
- * @param stopB - The StopId of the second stop.
13138
- * @returns True if stop A is before stop B, false otherwise.
13139
- */
13140
- isBefore(stopA, stopB) {
13141
- const stopAIndex = this.stopIndices.get(stopA);
13142
- if (stopAIndex === undefined) {
13143
- throw new Error(`Stop index not found for ${stopA} in route ${this.serviceRouteId}`);
13144
- }
13145
- const stopBIndex = this.stopIndices.get(stopB);
13146
- if (stopBIndex === undefined) {
13147
- throw new Error(`Stop index not found for ${stopB} in route ${this.serviceRouteId}`);
13148
- }
13149
- return stopAIndex < stopBIndex;
13150
- }
13151
13158
  /**
13152
13159
  * Retrieves the number of stops in the route.
13153
13160
  *
@@ -13176,47 +13183,47 @@ class Route {
13176
13183
  /**
13177
13184
  * Retrieves the arrival time at a specific stop for a given trip.
13178
13185
  *
13179
- * @param stopId - The identifier of the stop.
13186
+ * @param stopIndex - The index of the stop in the route.
13180
13187
  * @param tripIndex - The index of the trip.
13181
13188
  * @returns The arrival time at the specified stop and trip as a Time object.
13182
13189
  */
13183
- arrivalAt(stopId, tripIndex) {
13184
- const arrivalIndex = (tripIndex * this.stops.length + this.stopRouteIndex(stopId)) * 2;
13190
+ arrivalAt(stopIndex, tripIndex) {
13191
+ const arrivalIndex = (tripIndex * this.stops.length + stopIndex) * 2;
13185
13192
  const arrival = this.stopTimes[arrivalIndex];
13186
13193
  if (arrival === undefined) {
13187
- throw new Error(`Arrival time not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13194
+ throw new Error(`Arrival time not found for stop ${this.stopId(stopIndex)} (${stopIndex}) at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13188
13195
  }
13189
13196
  return Time.fromMinutes(arrival);
13190
13197
  }
13191
13198
  /**
13192
13199
  * Retrieves the departure time at a specific stop for a given trip.
13193
13200
  *
13194
- * @param stopId - The identifier of the stop.
13201
+ * @param stopIndex - The index of the stop in the route.
13195
13202
  * @param tripIndex - The index of the trip.
13196
13203
  * @returns The departure time at the specified stop and trip as a Time object.
13197
13204
  */
13198
- departureFrom(stopId, tripIndex) {
13199
- const departureIndex = (tripIndex * this.stops.length + this.stopRouteIndex(stopId)) * 2 + 1;
13205
+ departureFrom(stopIndex, tripIndex) {
13206
+ const departureIndex = (tripIndex * this.stops.length + stopIndex) * 2 + 1;
13200
13207
  const departure = this.stopTimes[departureIndex];
13201
13208
  if (departure === undefined) {
13202
- throw new Error(`Departure time not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13209
+ throw new Error(`Departure time not found for stop ${this.stopId(stopIndex)} (${stopIndex}) at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13203
13210
  }
13204
13211
  return Time.fromMinutes(departure);
13205
13212
  }
13206
13213
  /**
13207
13214
  * Retrieves the pick-up type for a specific stop and trip.
13208
13215
  *
13209
- * @param stopId - The identifier of the stop.
13216
+ * @param stopIndex - The index of the stop in the route.
13210
13217
  * @param tripIndex - The index of the trip.
13211
13218
  * @returns The pick-up type at the specified stop and trip.
13212
13219
  */
13213
- pickUpTypeFrom(stopId, tripIndex) {
13214
- const globalIndex = tripIndex * this.stops.length + this.stopRouteIndex(stopId);
13220
+ pickUpTypeFrom(stopIndex, tripIndex) {
13221
+ const globalIndex = tripIndex * this.stops.length + stopIndex;
13215
13222
  const byteIndex = Math.floor(globalIndex / 2);
13216
13223
  const isSecondPair = globalIndex % 2 === 1;
13217
13224
  const byte = this.pickUpDropOffTypes[byteIndex];
13218
13225
  if (byte === undefined) {
13219
- throw new Error(`Pick up type not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13226
+ throw new Error(`Pick up type not found for stop ${this.stopId(stopIndex)} (${stopIndex}) at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13220
13227
  }
13221
13228
  const pickUpValue = isSecondPair
13222
13229
  ? (byte >> 6) & 0x03 // Upper 2 bits for second pair
@@ -13226,17 +13233,17 @@ class Route {
13226
13233
  /**
13227
13234
  * Retrieves the drop-off type for a specific stop and trip.
13228
13235
  *
13229
- * @param stopId - The identifier of the stop.
13236
+ * @param stopIndex - The index of the stop in the route.
13230
13237
  * @param tripIndex - The index of the trip.
13231
13238
  * @returns The drop-off type at the specified stop and trip.
13232
13239
  */
13233
- dropOffTypeAt(stopId, tripIndex) {
13234
- const globalIndex = tripIndex * this.stops.length + this.stopRouteIndex(stopId);
13240
+ dropOffTypeAt(stopIndex, tripIndex) {
13241
+ const globalIndex = tripIndex * this.stops.length + stopIndex;
13235
13242
  const byteIndex = Math.floor(globalIndex / 2);
13236
13243
  const isSecondPair = globalIndex % 2 === 1;
13237
13244
  const byte = this.pickUpDropOffTypes[byteIndex];
13238
13245
  if (byte === undefined) {
13239
- throw new Error(`Drop off type not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13246
+ throw new Error(`Drop off type not found for stop ${this.stopId(stopIndex)} (${stopIndex}) at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13240
13247
  }
13241
13248
  const dropOffValue = isSecondPair
13242
13249
  ? (byte >> 4) & 0x03 // Bits 4-5 for second pair
@@ -13248,14 +13255,14 @@ class Route {
13248
13255
  * optionally constrained by a latest trip index and a time before which the trip
13249
13256
  * should not depart.
13250
13257
  * *
13251
- * @param stopId - The StopId of the stop where the trip should be found.
13258
+ * @param stopIndex - The route index of the stop where the trip should be found.
13252
13259
  * @param [after=Time.origin()] - The earliest time after which the trip should depart.
13253
13260
  * If not provided, searches all available trips.
13254
13261
  * @param [beforeTrip] - (Optional) The index of the trip before which the search should be constrained.
13255
13262
  * If not provided, searches all available trips.
13256
13263
  * @returns The index of the earliest trip meeting the criteria, or undefined if no such trip is found.
13257
13264
  */
13258
- findEarliestTrip(stopId, after = Time.origin(), beforeTrip) {
13265
+ findEarliestTrip(stopIndex, after = Time.origin(), beforeTrip) {
13259
13266
  if (this.nbTrips <= 0)
13260
13267
  return undefined;
13261
13268
  let hi = this.nbTrips - 1;
@@ -13267,7 +13274,7 @@ class Route {
13267
13274
  let lb = -1;
13268
13275
  while (lo <= hi) {
13269
13276
  const mid = (lo + hi) >>> 1;
13270
- const depMid = this.departureFrom(stopId, mid);
13277
+ const depMid = this.departureFrom(stopIndex, mid);
13271
13278
  if (depMid.isBefore(after)) {
13272
13279
  lo = mid + 1;
13273
13280
  }
@@ -13278,8 +13285,8 @@ class Route {
13278
13285
  }
13279
13286
  if (lb === -1)
13280
13287
  return undefined;
13281
- for (let t = lb; t < (beforeTrip !== null && beforeTrip !== void 0 ? beforeTrip : this.nbTrips); t++) {
13282
- const pickup = this.pickUpTypeFrom(stopId, t);
13288
+ for (let t = lb; t < (beforeTrip ?? this.nbTrips); t++) {
13289
+ const pickup = this.pickUpTypeFrom(stopIndex, t);
13283
13290
  if (pickup !== 'NOT_AVAILABLE') {
13284
13291
  return t;
13285
13292
  }
@@ -13287,14 +13294,14 @@ class Route {
13287
13294
  return undefined;
13288
13295
  }
13289
13296
  /**
13290
- * Retrieves the index of a stop within the route.
13297
+ * Retrieves the indices of a stop within the route.
13291
13298
  * @param stopId The StopId of the stop to locate in the route.
13292
- * @returns The index of the stop in the route.
13299
+ * @returns An array of indices where the stop appears in the route, or an empty array if the stop is not found.
13293
13300
  */
13294
- stopRouteIndex(stopId) {
13301
+ stopRouteIndices(stopId) {
13295
13302
  const stopIndex = this.stopIndices.get(stopId);
13296
13303
  if (stopIndex === undefined) {
13297
- throw new Error(`Stop index for ${stopId} not found in route ${this.serviceRouteId}`);
13304
+ return [];
13298
13305
  }
13299
13306
  return stopIndex;
13300
13307
  }
@@ -13312,6 +13319,51 @@ class Route {
13312
13319
  }
13313
13320
  }
13314
13321
 
13322
+ // Each value uses 20 bits, allowing values from 0 to 1,048,575 (2^20 - 1)
13323
+ const VALUE_MASK = (1n << 20n) - 1n; // 0xFFFFF
13324
+ const MAX_VALUE = 1_048_575; // 2^20 - 1
13325
+ // Bit positions for each value in the 60-bit bigint
13326
+ const TRIP_INDEX_SHIFT = 0n;
13327
+ const ROUTE_ID_SHIFT = 20n;
13328
+ const STOP_INDEX_SHIFT = 40n;
13329
+ /**
13330
+ * Validates that a value fits within 20 bits (0 to 1,048,575)
13331
+ * @param value - The value to validate
13332
+ * @param name - The name of the value for error reporting
13333
+ * @throws Error if the value is out of range
13334
+ */
13335
+ const validateValue = (value, name) => {
13336
+ if (value < 0 || value > MAX_VALUE) {
13337
+ throw new Error(`${name} must be between 0 and ${MAX_VALUE}, got ${value}`);
13338
+ }
13339
+ };
13340
+ /**
13341
+ * Encodes a stop index, route ID, and trip index into a single trip boarding ID.
13342
+ * @param stopIndex - The index of the stop within the route (0 to 1,048,575)
13343
+ * @param routeId - The route identifier (0 to 1,048,575)
13344
+ * @param tripIndex - The index of the trip within the route (0 to 1,048,575)
13345
+ * @returns The encoded trip ID as a bigint
13346
+ */
13347
+ const encode = (stopIndex, routeId, tripIndex) => {
13348
+ validateValue(stopIndex, 'stopIndex');
13349
+ validateValue(routeId, 'routeId');
13350
+ validateValue(tripIndex, 'tripIndex');
13351
+ return ((BigInt(stopIndex) << STOP_INDEX_SHIFT) |
13352
+ (BigInt(routeId) << ROUTE_ID_SHIFT) |
13353
+ (BigInt(tripIndex) << TRIP_INDEX_SHIFT));
13354
+ };
13355
+ /**
13356
+ * Decodes a trip boarding ID back into its constituent stop index, route ID, and trip index.
13357
+ * @param tripBoardingId - The encoded trip ID
13358
+ * @returns A tuple containing [stopIndex, routeId, tripIndex]
13359
+ */
13360
+ const decode = (tripBoardingId) => {
13361
+ const stopIndex = Number((tripBoardingId >> STOP_INDEX_SHIFT) & VALUE_MASK);
13362
+ const routeId = Number((tripBoardingId >> ROUTE_ID_SHIFT) & VALUE_MASK);
13363
+ const tripIndex = Number((tripBoardingId >> TRIP_INDEX_SHIFT) & VALUE_MASK);
13364
+ return [stopIndex, routeId, tripIndex];
13365
+ };
13366
+
13315
13367
  const isLittleEndian = (() => {
13316
13368
  const buffer = new ArrayBuffer(4);
13317
13369
  const view = new DataView(buffer);
@@ -13381,14 +13433,15 @@ const serializeStopsAdjacency = (stopsAdjacency) => {
13381
13433
  return stopsAdjacency.map((value) => {
13382
13434
  return {
13383
13435
  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
- }))))
13436
+ ? value.transfers.map((transfer) => ({
13437
+ destination: transfer.destination,
13438
+ type: serializeTransferType(transfer.type),
13439
+ ...(transfer.minTransferTime !== undefined && {
13440
+ minTransferTime: transfer.minTransferTime.toSeconds(),
13441
+ }),
13442
+ }))
13387
13443
  : [],
13388
13444
  routes: value.routes,
13389
- tripContinuations: value.tripContinuations
13390
- ? serializeTripContinuations(value.tripContinuations)
13391
- : [],
13392
13445
  };
13393
13446
  });
13394
13447
  };
@@ -13423,9 +13476,13 @@ const deserializeStopsAdjacency = (protoStopsAdjacency) => {
13423
13476
  for (let j = 0; j < value.transfers.length; j++) {
13424
13477
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13425
13478
  const transfer = value.transfers[j];
13426
- const newTransfer = Object.assign({ destination: transfer.destination, type: parseTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
13427
- minTransferTime: Duration.fromSeconds(transfer.minTransferTime),
13428
- }));
13479
+ const newTransfer = {
13480
+ destination: transfer.destination,
13481
+ type: parseTransferType(transfer.type),
13482
+ ...(transfer.minTransferTime !== undefined && {
13483
+ minTransferTime: Duration.fromSeconds(transfer.minTransferTime),
13484
+ }),
13485
+ };
13429
13486
  transfers.push(newTransfer);
13430
13487
  }
13431
13488
  const stopAdjacency = {
@@ -13434,10 +13491,6 @@ const deserializeStopsAdjacency = (protoStopsAdjacency) => {
13434
13491
  if (transfers.length > 0) {
13435
13492
  stopAdjacency.transfers = transfers;
13436
13493
  }
13437
- const deserializedTripContinuations = deserializeTripContinuations(value.tripContinuations);
13438
- if (deserializedTripContinuations.size > 0) {
13439
- stopAdjacency.tripContinuations = deserializedTripContinuations;
13440
- }
13441
13494
  result.push(stopAdjacency);
13442
13495
  }
13443
13496
  return result;
@@ -13544,11 +13597,14 @@ const serializeRouteType = (type) => {
13544
13597
  };
13545
13598
  const serializeTripContinuations = (tripContinuations) => {
13546
13599
  const result = [];
13547
- for (const [key, value] of tripContinuations.entries()) {
13600
+ for (const [tripBoardingId, boardings] of tripContinuations.entries()) {
13601
+ const [originStopIndex, originRouteId, originTripIndex] = decode(tripBoardingId);
13548
13602
  result.push({
13549
- key: key,
13550
- value: value.map((tripBoarding) => ({
13551
- hopOnStop: tripBoarding.hopOnStop,
13603
+ originStopIndex,
13604
+ originRouteId,
13605
+ originTripIndex,
13606
+ continuations: boardings.map((tripBoarding) => ({
13607
+ hopOnStopIndex: tripBoarding.hopOnStopIndex,
13552
13608
  routeId: tripBoarding.routeId,
13553
13609
  tripIndex: tripBoarding.tripIndex,
13554
13610
  })),
@@ -13561,28 +13617,17 @@ const deserializeTripContinuations = (protoTripContinuations) => {
13561
13617
  for (let i = 0; i < protoTripContinuations.length; i++) {
13562
13618
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13563
13619
  const entry = protoTripContinuations[i];
13564
- const tripBoardings = entry.value.map((protoTripBoarding) => ({
13565
- hopOnStop: protoTripBoarding.hopOnStop,
13620
+ const tripBoardingId = encode(entry.originStopIndex, entry.originRouteId, entry.originTripIndex);
13621
+ const tripBoardings = entry.continuations.map((protoTripBoarding) => ({
13622
+ hopOnStopIndex: protoTripBoarding.hopOnStopIndex,
13566
13623
  routeId: protoTripBoarding.routeId,
13567
13624
  tripIndex: protoTripBoarding.tripIndex,
13568
13625
  }));
13569
- result.set(entry.key, tripBoardings);
13626
+ result.set(tripBoardingId, tripBoardings);
13570
13627
  }
13571
13628
  return result;
13572
13629
  };
13573
13630
 
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
- };
13585
-
13586
13631
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
13587
13632
  const ALL_TRANSPORT_MODES = new Set([
13588
13633
  'TRAM',
@@ -13597,21 +13642,26 @@ const ALL_TRANSPORT_MODES = new Set([
13597
13642
  'MONORAIL',
13598
13643
  ]);
13599
13644
  const EMPTY_TRIP_CONTINUATIONS = [];
13600
- const CURRENT_VERSION = '0.0.8';
13645
+ const CURRENT_VERSION = '0.0.9';
13601
13646
  /**
13602
13647
  * The internal transit timetable format.
13603
13648
  */
13604
13649
  class Timetable {
13605
- constructor(stopsAdjacency, routesAdjacency, routes) {
13650
+ stopsAdjacency;
13651
+ routesAdjacency;
13652
+ serviceRoutes;
13653
+ tripContinuations;
13654
+ activeStops;
13655
+ constructor(stopsAdjacency, routesAdjacency, routes, tripContinuations) {
13606
13656
  this.stopsAdjacency = stopsAdjacency;
13607
13657
  this.routesAdjacency = routesAdjacency;
13608
13658
  this.serviceRoutes = routes;
13659
+ this.tripContinuations = tripContinuations;
13609
13660
  this.activeStops = new Set();
13610
13661
  for (let i = 0; i < stopsAdjacency.length; i++) {
13611
13662
  const stop = stopsAdjacency[i];
13612
13663
  if (stop.routes.length > 0 ||
13613
- (stop.transfers && stop.transfers.length > 0) ||
13614
- (stop.tripContinuations && stop.tripContinuations.size > 0)) {
13664
+ (stop.transfers && stop.transfers.length > 0)) {
13615
13665
  this.activeStops.add(i);
13616
13666
  }
13617
13667
  }
@@ -13627,6 +13677,7 @@ class Timetable {
13627
13677
  stopsAdjacency: serializeStopsAdjacency(this.stopsAdjacency),
13628
13678
  routesAdjacency: serializeRoutesAdjacency(this.routesAdjacency),
13629
13679
  serviceRoutes: serializeServiceRoutesMap(this.serviceRoutes),
13680
+ tripContinuations: serializeTripContinuations(this.tripContinuations || new Map()),
13630
13681
  };
13631
13682
  const writer = new BinaryWriter();
13632
13683
  Timetable$1.encode(protoTimetable, writer);
@@ -13644,7 +13695,7 @@ class Timetable {
13644
13695
  if (protoTimetable.version !== CURRENT_VERSION) {
13645
13696
  throw new Error(`Unsupported timetable version ${protoTimetable.version}`);
13646
13697
  }
13647
- return new Timetable(deserializeStopsAdjacency(protoTimetable.stopsAdjacency), deserializeRoutesAdjacency(protoTimetable.routesAdjacency), deserializeServiceRoutesMap(protoTimetable.serviceRoutes));
13698
+ return new Timetable(deserializeStopsAdjacency(protoTimetable.stopsAdjacency), deserializeRoutesAdjacency(protoTimetable.routesAdjacency), deserializeServiceRoutesMap(protoTimetable.serviceRoutes), deserializeTripContinuations(protoTimetable.tripContinuations));
13648
13699
  }
13649
13700
  /**
13650
13701
  * Checks if the given stop is active on the timetable.
@@ -13683,18 +13734,17 @@ class Timetable {
13683
13734
  /**
13684
13735
  * Retrieves all trip continuation options available at the specified stop for a given trip.
13685
13736
  *
13686
- * @param stopId - The ID of the stop to get trip continuations for.
13737
+ * @param stopIndex - The index in the route of the stop to get trip continuations for.
13738
+ * @param routeId - The ID of the route to get continuations for.
13687
13739
  * @param tripIndex - The index of the trip to get continuations for.
13688
13740
  * @returns An array of trip continuation options available at the stop for the specified trip.
13689
13741
  */
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`);
13742
+ getContinuousTrips(stopIndex, routeId, tripIndex) {
13743
+ const tripContinuations = this.tripContinuations?.get(encode(stopIndex, routeId, tripIndex));
13744
+ if (!tripContinuations) {
13745
+ return EMPTY_TRIP_CONTINUATIONS;
13695
13746
  }
13696
- return (((_a = stopAdjacency.tripContinuations) === null || _a === void 0 ? void 0 : _a.get(encode(routeId, tripIndex))) ||
13697
- EMPTY_TRIP_CONTINUATIONS);
13747
+ return tripContinuations;
13698
13748
  }
13699
13749
  /**
13700
13750
  * Retrieves the service route associated with the given route.
@@ -13734,12 +13784,12 @@ class Timetable {
13734
13784
  }
13735
13785
  /**
13736
13786
  * Finds routes that are reachable from a set of stop IDs.
13737
- * Also identifies the first stop available to hop on each route among
13787
+ * Also identifies the first stop index available to hop on each route among
13738
13788
  * the input stops.
13739
13789
  *
13740
13790
  * @param fromStops - The set of stop IDs to find reachable routes from.
13741
13791
  * @param transportModes - The set of transport modes to consider for reachable routes.
13742
- * @returns A map of reachable routes to the first stop available to hop on each route.
13792
+ * @returns A map of reachable routes to the first stop index available to hop on each route.
13743
13793
  */
13744
13794
  findReachableRoutes(fromStops, transportModes = ALL_TRANSPORT_MODES) {
13745
13795
  const reachableRoutes = new Map();
@@ -13752,15 +13802,17 @@ class Timetable {
13752
13802
  });
13753
13803
  for (let j = 0; j < validRoutes.length; j++) {
13754
13804
  const route = validRoutes[j];
13755
- const hopOnStop = reachableRoutes.get(route);
13756
- if (hopOnStop) {
13757
- if (route.isBefore(originStop, hopOnStop)) {
13805
+ const originStopIndices = route.stopRouteIndices(originStop);
13806
+ const originStopIndex = originStopIndices[0];
13807
+ const existingHopOnStopIndex = reachableRoutes.get(route);
13808
+ if (existingHopOnStopIndex !== undefined) {
13809
+ if (originStopIndex < existingHopOnStopIndex) {
13758
13810
  // if the current stop is before the existing hop on stop, replace it
13759
- reachableRoutes.set(route, originStop);
13811
+ reachableRoutes.set(route, originStopIndex);
13760
13812
  }
13761
13813
  }
13762
13814
  else {
13763
- reachableRoutes.set(route, originStop);
13815
+ reachableRoutes.set(route, originStopIndex);
13764
13816
  }
13765
13817
  }
13766
13818
  }
@@ -15736,35 +15788,22 @@ const parseCsv = (stream, numericColumns = []) => {
15736
15788
  * @param profile A configuration object defining the specificities of the GTFS feed.
15737
15789
  * @returns A map of all the valid routes.
15738
15790
  */
15739
- const parseRoutes = (routesStream_1, ...args_1) => __awaiter(void 0, [routesStream_1, ...args_1], void 0, function* (routesStream, profile = standardProfile) {
15740
- var _a, e_1, _b, _c;
15791
+ const parseRoutes = async (routesStream, profile = standardProfile) => {
15741
15792
  const routes = new Map();
15742
- try {
15743
- for (var _d = true, _e = __asyncValues(parseCsv(routesStream, ['route_type'])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15744
- _c = _f.value;
15745
- _d = false;
15746
- const rawLine = _c;
15747
- const line = rawLine;
15748
- const routeType = profile.routeTypeParser(line.route_type);
15749
- if (routeType === undefined) {
15750
- log.info(`Unsupported route type ${line.route_type} for route ${line.route_id}.`);
15751
- continue;
15752
- }
15753
- routes.set(line.route_id, {
15754
- name: line.route_short_name,
15755
- type: routeType,
15756
- });
15757
- }
15758
- }
15759
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
15760
- finally {
15761
- try {
15762
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
15793
+ for await (const rawLine of parseCsv(routesStream, ['route_type'])) {
15794
+ const line = rawLine;
15795
+ const routeType = profile.routeTypeParser(line.route_type);
15796
+ if (routeType === undefined) {
15797
+ log.info(`Unsupported route type ${line.route_type} for route ${line.route_id}.`);
15798
+ continue;
15763
15799
  }
15764
- finally { if (e_1) throw e_1.error; }
15800
+ routes.set(line.route_id, {
15801
+ name: line.route_short_name,
15802
+ type: routeType,
15803
+ });
15765
15804
  }
15766
15805
  return routes;
15767
- });
15806
+ };
15768
15807
  /**
15769
15808
  * Creates an array of ServiceRoute objects by combining GTFS route data with service route mappings.
15770
15809
  *
@@ -15827,46 +15866,33 @@ const weekdays = {
15827
15866
  * @param date The active date.
15828
15867
  * @param calendarStream A readable stream for the GTFS calendar.txt file.
15829
15868
  */
15830
- const parseCalendar = (calendarStream, serviceIds, date) => __awaiter(void 0, void 0, void 0, function* () {
15831
- var _a, e_1, _b, _c;
15869
+ const parseCalendar = async (calendarStream, serviceIds, date) => {
15832
15870
  const activeDate = toGtfsDate(date);
15833
15871
  const weekday = date.weekday;
15834
15872
  const weekdayIndex = weekdays[weekday];
15835
- try {
15836
- for (var _d = true, _e = __asyncValues(parseCsv(calendarStream, [
15837
- 'monday',
15838
- 'tuesday',
15839
- 'wednesday',
15840
- 'thursday',
15841
- 'friday',
15842
- 'saturday',
15843
- 'sunday',
15844
- 'start_date',
15845
- 'end_date',
15846
- ])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15847
- _c = _f.value;
15848
- _d = false;
15849
- const rawLine = _c;
15850
- const line = rawLine;
15851
- if (activeDate < line.start_date || activeDate > line.end_date) {
15852
- // If the service is not valid on this date
15853
- continue;
15854
- }
15855
- if (line[weekdayIndex] !== 1) {
15856
- // If the service is not valid on this week day
15857
- continue;
15858
- }
15859
- serviceIds.add(line['service_id']);
15873
+ for await (const rawLine of parseCsv(calendarStream, [
15874
+ 'monday',
15875
+ 'tuesday',
15876
+ 'wednesday',
15877
+ 'thursday',
15878
+ 'friday',
15879
+ 'saturday',
15880
+ 'sunday',
15881
+ 'start_date',
15882
+ 'end_date',
15883
+ ])) {
15884
+ const line = rawLine;
15885
+ if (activeDate < line.start_date || activeDate > line.end_date) {
15886
+ // If the service is not valid on this date
15887
+ continue;
15860
15888
  }
15861
- }
15862
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
15863
- finally {
15864
- try {
15865
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
15889
+ if (line[weekdayIndex] !== 1) {
15890
+ // If the service is not valid on this week day
15891
+ continue;
15866
15892
  }
15867
- finally { if (e_1) throw e_1.error; }
15893
+ serviceIds.add(line['service_id']);
15868
15894
  }
15869
- });
15895
+ };
15870
15896
  /**
15871
15897
  * Parses a gtfs calendar_dates.txt file and finds the service ids valid at a given date.
15872
15898
  *
@@ -15874,39 +15900,24 @@ const parseCalendar = (calendarStream, serviceIds, date) => __awaiter(void 0, vo
15874
15900
  * @param date The active date, in the format "YYYYMMDD".
15875
15901
  * @param calendarDatesStream A readable stream for the GTFS calendar_dates.txt file.
15876
15902
  */
15877
- const parseCalendarDates = (calendarDatesStream, serviceIds, date) => __awaiter(void 0, void 0, void 0, function* () {
15878
- var _a, e_2, _b, _c;
15903
+ const parseCalendarDates = async (calendarDatesStream, serviceIds, date) => {
15879
15904
  const activeDate = toGtfsDate(date);
15880
- try {
15881
- for (var _d = true, _e = __asyncValues(parseCsv(calendarDatesStream, [
15882
- 'date',
15883
- 'exception_type',
15884
- ])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15885
- _c = _f.value;
15886
- _d = false;
15887
- const rawLine = _c;
15888
- const line = rawLine;
15889
- if (line.date !== activeDate) {
15890
- // No rule on the active date
15891
- }
15892
- else if (line.exception_type === 2 && serviceIds.has(line.service_id)) {
15893
- // Service has been removed for the specified date.
15894
- serviceIds.delete(line.service_id);
15895
- }
15896
- else if (line.exception_type === 1) {
15897
- // Service is present on the active date
15898
- serviceIds.add(line.service_id);
15899
- }
15905
+ for await (const rawLine of parseCsv(calendarDatesStream, [
15906
+ 'date',
15907
+ 'exception_type',
15908
+ ])) {
15909
+ const line = rawLine;
15910
+ if (line.date !== activeDate) ;
15911
+ else if (line.exception_type === 2 && serviceIds.has(line.service_id)) {
15912
+ // Service has been removed for the specified date.
15913
+ serviceIds.delete(line.service_id);
15900
15914
  }
15901
- }
15902
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
15903
- finally {
15904
- try {
15905
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
15915
+ else if (line.exception_type === 1) {
15916
+ // Service is present on the active date
15917
+ serviceIds.add(line.service_id);
15906
15918
  }
15907
- finally { if (e_2) throw e_2.error; }
15908
15919
  }
15909
- });
15920
+ };
15910
15921
 
15911
15922
  /**
15912
15923
  * Parses the stops.txt file from a GTFS feed.
@@ -15914,33 +15925,30 @@ const parseCalendarDates = (calendarDatesStream, serviceIds, date) => __awaiter(
15914
15925
  * @param stopsStream The readable stream containing the stops data.
15915
15926
  * @return A mapping of stop IDs to corresponding stop details.
15916
15927
  */
15917
- const parseStops = (stopsStream) => __awaiter(void 0, void 0, void 0, function* () {
15918
- var _a, e_1, _b, _c;
15928
+ const parseStops = async (stopsStream) => {
15919
15929
  const parsedStops = new Map();
15920
15930
  let i = 0;
15921
- try {
15922
- for (var _d = true, _e = __asyncValues(parseCsv(stopsStream, [
15923
- 'stop_lat',
15924
- 'stop_lon',
15925
- 'location_type',
15926
- ])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15927
- _c = _f.value;
15928
- _d = false;
15929
- const rawLine = _c;
15930
- const line = rawLine;
15931
- const stop = Object.assign(Object.assign(Object.assign({ id: i, sourceStopId: line.stop_id, name: line.stop_name, lat: line.stop_lat, lon: line.stop_lon, locationType: line.location_type
15932
- ? parseGtfsLocationType(line.location_type)
15933
- : 'SIMPLE_STOP_OR_PLATFORM' }, (line.platform_code && { platform: line.platform_code })), { children: [] }), (line.parent_station && { parentSourceId: line.parent_station }));
15934
- parsedStops.set(line.stop_id, stop);
15935
- i = i + 1;
15936
- }
15937
- }
15938
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
15939
- finally {
15940
- try {
15941
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
15942
- }
15943
- finally { if (e_1) throw e_1.error; }
15931
+ for await (const rawLine of parseCsv(stopsStream, [
15932
+ 'stop_lat',
15933
+ 'stop_lon',
15934
+ 'location_type',
15935
+ ])) {
15936
+ const line = rawLine;
15937
+ const stop = {
15938
+ id: i,
15939
+ sourceStopId: line.stop_id,
15940
+ name: line.stop_name,
15941
+ lat: line.stop_lat,
15942
+ lon: line.stop_lon,
15943
+ locationType: line.location_type
15944
+ ? parseGtfsLocationType(line.location_type)
15945
+ : 'SIMPLE_STOP_OR_PLATFORM',
15946
+ ...(line.platform_code && { platform: line.platform_code }),
15947
+ children: [],
15948
+ ...(line.parent_station && { parentSourceId: line.parent_station }),
15949
+ };
15950
+ parsedStops.set(line.stop_id, stop);
15951
+ i = i + 1;
15944
15952
  }
15945
15953
  for (const [sourceStopId, stop] of parsedStops) {
15946
15954
  if (stop.parentSourceId) {
@@ -15954,7 +15962,7 @@ const parseStops = (stopsStream) => __awaiter(void 0, void 0, void 0, function*
15954
15962
  }
15955
15963
  }
15956
15964
  return parsedStops;
15957
- });
15965
+ };
15958
15966
  const parseGtfsLocationType = (gtfsLocationType) => {
15959
15967
  switch (gtfsLocationType) {
15960
15968
  case 0:
@@ -15977,85 +15985,158 @@ const parseGtfsLocationType = (gtfsLocationType) => {
15977
15985
  * @param stopsStream The readable stream containing the stops data.
15978
15986
  * @return A mapping of stop IDs to corresponding stop details.
15979
15987
  */
15980
- const parseTransfers = (transfersStream, stopsMap) => __awaiter(void 0, void 0, void 0, function* () {
15981
- var _a, e_1, _b, _c;
15988
+ const parseTransfers = async (transfersStream, stopsMap) => {
15982
15989
  const transfers = new Map();
15983
- const tripContinuations = new Map();
15984
- try {
15985
- for (var _d = true, _e = __asyncValues(parseCsv(transfersStream, [
15986
- 'transfer_type',
15987
- 'min_transfer_time',
15988
- ])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15989
- _c = _f.value;
15990
- _d = false;
15991
- const rawLine = _c;
15992
- const transferEntry = rawLine;
15993
- if (transferEntry.transfer_type === 3 ||
15994
- transferEntry.transfer_type === 5) {
15995
- continue;
15996
- }
15997
- if (!transferEntry.from_stop_id || !transferEntry.to_stop_id) {
15998
- console.warn(`Missing transfer origin or destination stop.`);
15999
- continue;
16000
- }
16001
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16002
- const fromStop = stopsMap.get(transferEntry.from_stop_id);
16003
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
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}.`);
15990
+ const tripContinuations = [];
15991
+ for await (const rawLine of parseCsv(transfersStream, [
15992
+ 'transfer_type',
15993
+ 'min_transfer_time',
15994
+ ])) {
15995
+ const transferEntry = rawLine;
15996
+ if (transferEntry.transfer_type === 3 ||
15997
+ transferEntry.transfer_type === 5) {
15998
+ continue;
15999
+ }
16000
+ if (!transferEntry.from_stop_id || !transferEntry.to_stop_id) {
16001
+ console.warn(`Missing transfer origin or destination stop.`);
16002
+ continue;
16003
+ }
16004
+ const fromStop = stopsMap.get(transferEntry.from_stop_id);
16005
+ const toStop = stopsMap.get(transferEntry.to_stop_id);
16006
+ if (!fromStop || !toStop) {
16007
+ console.warn(`Transfer references non-existent stop(s): from_stop_id=${transferEntry.from_stop_id}, to_stop_id=${transferEntry.to_stop_id}`);
16008
+ continue;
16009
+ }
16010
+ if (transferEntry.transfer_type === 4) {
16011
+ if (transferEntry.from_trip_id === undefined ||
16012
+ transferEntry.from_trip_id === '' ||
16013
+ transferEntry.to_trip_id === undefined ||
16014
+ transferEntry.to_trip_id === '') {
16015
+ console.warn(`Unsupported in-seat transfer, missing from_trip_id and/or to_trip_id.`);
16033
16016
  continue;
16034
16017
  }
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
- }
16039
- const transfer = Object.assign({ destination: toStop.id, type: parseGtfsTransferType(transferEntry.transfer_type) }, (transferEntry.min_transfer_time && {
16040
- minTransferTime: Duration.fromSeconds(transferEntry.min_transfer_time),
16041
- }));
16042
- const fromStopTransfers = transfers.get(fromStop.id) || [];
16043
- fromStopTransfers.push(transfer);
16044
- transfers.set(fromStop.id, fromStopTransfers);
16018
+ const tripBoardingEntry = {
16019
+ fromStop: fromStop.id,
16020
+ fromTrip: transferEntry.from_trip_id,
16021
+ toStop: toStop.id,
16022
+ toTrip: transferEntry.to_trip_id,
16023
+ };
16024
+ tripContinuations.push(tripBoardingEntry);
16025
+ continue;
16045
16026
  }
16046
- }
16047
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
16048
- finally {
16049
- try {
16050
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
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;
16051
16034
  }
16052
- finally { if (e_1) throw e_1.error; }
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
+ }
16039
+ const transfer = {
16040
+ destination: toStop.id,
16041
+ type: parseGtfsTransferType(transferEntry.transfer_type),
16042
+ ...(transferEntry.min_transfer_time !== undefined && {
16043
+ minTransferTime: Duration.fromSeconds(transferEntry.min_transfer_time),
16044
+ }),
16045
+ };
16046
+ const fromStopTransfers = transfers.get(fromStop.id) || [];
16047
+ fromStopTransfers.push(transfer);
16048
+ transfers.set(fromStop.id, fromStopTransfers);
16053
16049
  }
16054
16050
  return {
16055
16051
  transfers,
16056
16052
  tripContinuations,
16057
16053
  };
16058
- });
16054
+ };
16055
+ /**
16056
+ * Disambiguates stops involved in a transfer.
16057
+ *
16058
+ * The GTFS specification only refers to a stopId in the trip-to-trip transfers and not the
16059
+ * specific stop index in the route. For routes that have multiple stops with the same stopId,
16060
+ * we need to determine which are the from / to stop indices in respective routes.
16061
+ * We do so by picking the stop indices leading to the most coherent transfer.
16062
+ * (we pick the closest from stop index happening after the to stop index).
16063
+ */
16064
+ const disambiguateTransferStopsIndices = (fromStop, fromRoute, fromTripIndex, toStop, toRoute, toTripIndex) => {
16065
+ const fromStopIndices = fromRoute.stopRouteIndices(fromStop);
16066
+ const toStopIndices = toRoute.stopRouteIndices(toStop);
16067
+ let bestFromStopIndex;
16068
+ let bestToStopIndex;
16069
+ let bestTimeDifference = Infinity;
16070
+ for (const originStopIndex of fromStopIndices) {
16071
+ const fromArrivalTime = fromRoute.arrivalAt(originStopIndex, fromTripIndex);
16072
+ for (const toStopIndex of toStopIndices) {
16073
+ const toDepartureTime = toRoute.departureFrom(toStopIndex, toTripIndex);
16074
+ if (toDepartureTime.isAfter(fromArrivalTime)) {
16075
+ const timeDifference = toDepartureTime.toMinutes() - fromArrivalTime.toMinutes();
16076
+ if (timeDifference < bestTimeDifference) {
16077
+ bestTimeDifference = timeDifference;
16078
+ bestFromStopIndex = originStopIndex;
16079
+ bestToStopIndex = toStopIndex;
16080
+ }
16081
+ }
16082
+ }
16083
+ }
16084
+ if (bestFromStopIndex !== undefined && bestToStopIndex !== undefined) {
16085
+ return {
16086
+ fromStopIndex: bestFromStopIndex,
16087
+ toStopIndex: bestToStopIndex,
16088
+ };
16089
+ }
16090
+ return undefined;
16091
+ };
16092
+ /**
16093
+ * Builds trip continuations map from GTFS trip continuation data.
16094
+ *
16095
+ * This function processes GTFS in-seat transfer data and creates a mapping
16096
+ * from trip boarding IDs to continuation boarding information. It disambiguates
16097
+ * stop indices when routes have multiple stops with the same ID by finding
16098
+ * the most coherent transfer timing.
16099
+ *
16100
+ * @param tripsMapping Mapping from GTFS trip IDs to internal trip representations
16101
+ * @param tripContinuations Array of GTFS trip continuation data from transfers.txt
16102
+ * @param timetable The timetable containing route and timing information
16103
+ * @param activeStopIds Set of stop IDs that are active/enabled in the system
16104
+ * @returns A map from trip boarding IDs to arrays of continuation boarding options
16105
+ */
16106
+ const buildTripContinuations = (tripsMapping, tripContinuations, timetable, activeStopIds) => {
16107
+ const continuations = new Map();
16108
+ for (const gtfsContinuation of tripContinuations) {
16109
+ if (!activeStopIds.has(gtfsContinuation.fromStop) ||
16110
+ !activeStopIds.has(gtfsContinuation.toStop)) {
16111
+ continue;
16112
+ }
16113
+ const fromTripMapping = tripsMapping.get(gtfsContinuation.fromTrip);
16114
+ const toTripMapping = tripsMapping.get(gtfsContinuation.toTrip);
16115
+ if (!fromTripMapping || !toTripMapping) {
16116
+ continue;
16117
+ }
16118
+ const fromRoute = timetable.getRoute(fromTripMapping.routeId);
16119
+ const toRoute = timetable.getRoute(toTripMapping.routeId);
16120
+ if (!fromRoute || !toRoute) {
16121
+ continue;
16122
+ }
16123
+ const bestStopIndices = disambiguateTransferStopsIndices(gtfsContinuation.fromStop, fromRoute, fromTripMapping.tripRouteIndex, gtfsContinuation.toStop, toRoute, toTripMapping.tripRouteIndex);
16124
+ if (!bestStopIndices) {
16125
+ // No valid continuation found
16126
+ continue;
16127
+ }
16128
+ const tripBoardingId = encode(bestStopIndices.fromStopIndex, fromTripMapping.routeId, fromTripMapping.tripRouteIndex);
16129
+ const continuationBoarding = {
16130
+ hopOnStopIndex: bestStopIndices.toStopIndex,
16131
+ routeId: toTripMapping.routeId,
16132
+ tripIndex: toTripMapping.tripRouteIndex,
16133
+ };
16134
+ const existingContinuations = continuations.get(tripBoardingId) || [];
16135
+ existingContinuations.push(continuationBoarding);
16136
+ continuations.set(tripBoardingId, existingContinuations);
16137
+ }
16138
+ return continuations;
16139
+ };
16059
16140
  const parseGtfsTransferType = (gtfsTransferType) => {
16060
16141
  switch (gtfsTransferType) {
16061
16142
  case 0:
@@ -16163,36 +16244,23 @@ const finalizeRouteFromBuilder = (builder) => {
16163
16244
  * @param serviceRoutes A mapping of route IDs to route details.
16164
16245
  * @returns A mapping of trip IDs to corresponding route IDs.
16165
16246
  */
16166
- const parseTrips = (tripsStream, serviceIds, validGtfsRoutes) => __awaiter(void 0, void 0, void 0, function* () {
16167
- var _a, e_1, _b, _c;
16247
+ const parseTrips = async (tripsStream, serviceIds, validGtfsRoutes) => {
16168
16248
  const trips = new Map();
16169
- try {
16170
- for (var _d = true, _e = __asyncValues(parseCsv(tripsStream, ['stop_sequence'])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
16171
- _c = _f.value;
16172
- _d = false;
16173
- const rawLine = _c;
16174
- const line = rawLine;
16175
- if (!serviceIds.has(line.service_id)) {
16176
- // The trip doesn't correspond to an active service
16177
- continue;
16178
- }
16179
- if (!validGtfsRoutes.has(line.route_id)) {
16180
- // The trip doesn't correspond to a supported route
16181
- continue;
16182
- }
16183
- trips.set(line.trip_id, line.route_id);
16249
+ for await (const rawLine of parseCsv(tripsStream, ['stop_sequence'])) {
16250
+ const line = rawLine;
16251
+ if (!serviceIds.has(line.service_id)) {
16252
+ // The trip doesn't correspond to an active service
16253
+ continue;
16184
16254
  }
16185
- }
16186
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
16187
- finally {
16188
- try {
16189
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
16255
+ if (!validGtfsRoutes.has(line.route_id)) {
16256
+ // The trip doesn't correspond to a supported route
16257
+ continue;
16190
16258
  }
16191
- finally { if (e_1) throw e_1.error; }
16259
+ trips.set(line.trip_id, line.route_id);
16192
16260
  }
16193
16261
  return trips;
16194
- });
16195
- const buildStopsAdjacencyStructure = (tripsMapping, serviceRoutes, routes, transfersMap, tripContinuationsMap, nbStops, activeStops) => {
16262
+ };
16263
+ const buildStopsAdjacencyStructure = (serviceRoutes, routes, transfersMap, nbStops, activeStops) => {
16196
16264
  const stopsAdjacency = new Array(nbStops);
16197
16265
  for (let i = 0; i < nbStops; i++) {
16198
16266
  stopsAdjacency[i] = {
@@ -16232,40 +16300,6 @@ const buildStopsAdjacencyStructure = (tripsMapping, serviceRoutes, routes, trans
16232
16300
  }
16233
16301
  }
16234
16302
  }
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
- }
16269
16303
  return stopsAdjacency;
16270
16304
  };
16271
16305
  /**
@@ -16277,9 +16311,7 @@ const buildStopsAdjacencyStructure = (tripsMapping, serviceRoutes, routes, trans
16277
16311
  * @param activeStopIds A set of valid stop IDs.
16278
16312
  * @returns A mapping of route IDs to route details. The routes returned correspond to the set of trips from GTFS that share the same stop list.
16279
16313
  */
16280
- const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds) => __awaiter(void 0, void 0, void 0, function* () {
16281
- var _a, e_2, _b, _c;
16282
- var _d, _e;
16314
+ const parseStopTimes = async (stopTimesStream, stopsMap, activeTripIds, activeStopIds) => {
16283
16315
  /**
16284
16316
  * Adds a trip to the appropriate route builder
16285
16317
  */
@@ -16347,55 +16379,43 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
16347
16379
  let pickUpTypes = [];
16348
16380
  let dropOffTypes = [];
16349
16381
  let currentTripId = undefined;
16350
- try {
16351
- for (var _f = true, _g = __asyncValues(parseCsv(stopTimesStream, ['stop_sequence'])), _h; _h = yield _g.next(), _a = _h.done, !_a; _f = true) {
16352
- _c = _h.value;
16353
- _f = false;
16354
- const rawLine = _c;
16355
- const line = rawLine;
16356
- if (line.trip_id === currentTripId && line.stop_sequence <= previousSeq) {
16357
- console.warn(`Stop sequences not increasing for trip ${line.trip_id}: ${line.stop_sequence} > ${previousSeq}.`);
16358
- continue;
16359
- }
16360
- if (!line.arrival_time && !line.departure_time) {
16361
- console.warn(`Missing arrival or departure time for ${line.trip_id} at stop ${line.stop_id}.`);
16362
- continue;
16363
- }
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.
16368
- continue;
16369
- }
16370
- if (currentTripId && line.trip_id !== currentTripId && stops.length > 0) {
16371
- addTrip(currentTripId);
16372
- }
16373
- currentTripId = line.trip_id;
16374
- const stopData = stopsMap.get(line.stop_id);
16375
- if (!stopData) {
16376
- console.warn(`Unknown stop ID: ${line.stop_id}`);
16377
- continue;
16378
- }
16379
- stops.push(stopData.id);
16380
- const departure = (_d = line.departure_time) !== null && _d !== void 0 ? _d : line.arrival_time;
16381
- const arrival = (_e = line.arrival_time) !== null && _e !== void 0 ? _e : line.departure_time;
16382
- if (!arrival || !departure) {
16383
- console.warn(`Missing time data for ${line.trip_id} at stop ${line.stop_id}`);
16384
- continue;
16385
- }
16386
- arrivalTimes.push(toTime(arrival).toMinutes());
16387
- departureTimes.push(toTime(departure).toMinutes());
16388
- pickUpTypes.push(parsePickupDropOffType(line.pickup_type));
16389
- dropOffTypes.push(parsePickupDropOffType(line.drop_off_type));
16390
- previousSeq = line.stop_sequence;
16382
+ for await (const rawLine of parseCsv(stopTimesStream, ['stop_sequence'])) {
16383
+ const line = rawLine;
16384
+ if (line.trip_id === currentTripId && line.stop_sequence <= previousSeq) {
16385
+ console.warn(`Stop sequences not increasing for trip ${line.trip_id}: ${line.stop_sequence} > ${previousSeq}.`);
16386
+ continue;
16391
16387
  }
16392
- }
16393
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
16394
- finally {
16395
- try {
16396
- if (!_f && !_a && (_b = _g.return)) yield _b.call(_g);
16388
+ if (!line.arrival_time && !line.departure_time) {
16389
+ console.warn(`Missing arrival or departure time for ${line.trip_id} at stop ${line.stop_id}.`);
16390
+ continue;
16391
+ }
16392
+ if (line.pickup_type === '1' && line.drop_off_type === '1') {
16393
+ // Warning: could potentially lead to issues if there is an in-seat transfer
16394
+ // at this stop - it can be not boardable nor alightable but still useful for an in-seat transfer.
16395
+ // This doesn't seem to happen in practice for now so keeping this condition to save memory.
16396
+ continue;
16397
16397
  }
16398
- finally { if (e_2) throw e_2.error; }
16398
+ if (currentTripId && line.trip_id !== currentTripId && stops.length > 0) {
16399
+ addTrip(currentTripId);
16400
+ }
16401
+ currentTripId = line.trip_id;
16402
+ const stopData = stopsMap.get(line.stop_id);
16403
+ if (!stopData) {
16404
+ console.warn(`Unknown stop ID: ${line.stop_id}`);
16405
+ continue;
16406
+ }
16407
+ stops.push(stopData.id);
16408
+ const departure = line.departure_time ?? line.arrival_time;
16409
+ const arrival = line.arrival_time ?? line.departure_time;
16410
+ if (!arrival || !departure) {
16411
+ console.warn(`Missing time data for ${line.trip_id} at stop ${line.stop_id}`);
16412
+ continue;
16413
+ }
16414
+ arrivalTimes.push(toTime(arrival).toMinutes());
16415
+ departureTimes.push(toTime(departure).toMinutes());
16416
+ pickUpTypes.push(parsePickupDropOffType(line.pickup_type));
16417
+ dropOffTypes.push(parsePickupDropOffType(line.drop_off_type));
16418
+ previousSeq = line.stop_sequence;
16399
16419
  }
16400
16420
  if (currentTripId) {
16401
16421
  addTrip(currentTripId);
@@ -16414,7 +16434,7 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
16414
16434
  });
16415
16435
  }
16416
16436
  return { routes: routesAdjacency, serviceRoutesMap, tripsMapping };
16417
- });
16437
+ };
16418
16438
  const parsePickupDropOffType = (gtfsType) => {
16419
16439
  switch (gtfsType) {
16420
16440
  default:
@@ -16438,6 +16458,8 @@ const STOP_TIMES_FILE = 'stop_times.txt';
16438
16458
  const STOPS_FILE = 'stops.txt';
16439
16459
  const TRANSFERS_FILE = 'transfers.txt';
16440
16460
  class GtfsParser {
16461
+ path;
16462
+ profile;
16441
16463
  constructor(path, profile = standardProfile) {
16442
16464
  // TODO: support input from multiple sources
16443
16465
  this.path = path;
@@ -16449,77 +16471,81 @@ class GtfsParser {
16449
16471
  * @param date The active date.
16450
16472
  * @returns The parsed timetable.
16451
16473
  */
16452
- parseTimetable(date) {
16453
- return __awaiter(this, void 0, void 0, function* () {
16454
- log.setLevel('INFO');
16455
- const zip = new StreamZip.async({ file: this.path });
16456
- const entries = yield zip.entries();
16457
- const datetime = DateTime.fromJSDate(date);
16458
- const activeServiceIds = new Set();
16459
- const activeStopIds = new Set();
16460
- log.info(`Parsing ${STOPS_FILE}`);
16461
- const stopsStart = performance.now();
16462
- const stopsStream = yield zip.stream(STOPS_FILE);
16463
- const parsedStops = yield parseStops(stopsStream);
16464
- const stopsEnd = performance.now();
16465
- log.info(`${parsedStops.size} parsed stops. (${(stopsEnd - stopsStart).toFixed(2)}ms)`);
16466
- if (entries[CALENDAR_FILE]) {
16467
- log.info(`Parsing ${CALENDAR_FILE}`);
16468
- const calendarStart = performance.now();
16469
- const calendarStream = yield zip.stream(CALENDAR_FILE);
16470
- yield parseCalendar(calendarStream, activeServiceIds, datetime);
16471
- const calendarEnd = performance.now();
16472
- log.info(`${activeServiceIds.size} valid services. (${(calendarEnd - calendarStart).toFixed(2)}ms)`);
16473
- }
16474
- if (entries[CALENDAR_DATES_FILE]) {
16475
- log.info(`Parsing ${CALENDAR_DATES_FILE}`);
16476
- const calendarDatesStart = performance.now();
16477
- const calendarDatesStream = yield zip.stream(CALENDAR_DATES_FILE);
16478
- yield parseCalendarDates(calendarDatesStream, activeServiceIds, datetime);
16479
- const calendarDatesEnd = performance.now();
16480
- log.info(`${activeServiceIds.size} valid services. (${(calendarDatesEnd - calendarDatesStart).toFixed(2)}ms)`);
16481
- }
16482
- log.info(`Parsing ${ROUTES_FILE}`);
16483
- const routesStart = performance.now();
16484
- const routesStream = yield zip.stream(ROUTES_FILE);
16485
- const validGtfsRoutes = yield parseRoutes(routesStream, this.profile);
16486
- const routesEnd = performance.now();
16487
- log.info(`${validGtfsRoutes.size} valid GTFS routes. (${(routesEnd - routesStart).toFixed(2)}ms)`);
16488
- log.info(`Parsing ${TRIPS_FILE}`);
16489
- const tripsStart = performance.now();
16490
- const tripsStream = yield zip.stream(TRIPS_FILE);
16491
- const trips = yield parseTrips(tripsStream, activeServiceIds, validGtfsRoutes);
16492
- const tripsEnd = performance.now();
16493
- log.info(`${trips.size} valid trips. (${(tripsEnd - tripsStart).toFixed(2)}ms)`);
16494
- let transfers = new Map();
16495
- let tripContinuations = new Map();
16496
- if (entries[TRANSFERS_FILE]) {
16497
- log.info(`Parsing ${TRANSFERS_FILE}`);
16498
- const transfersStart = performance.now();
16499
- const transfersStream = yield zip.stream(TRANSFERS_FILE);
16500
- const { transfers: parsedTransfers, tripContinuations: parsedTripContinuations, } = yield parseTransfers(transfersStream, parsedStops);
16501
- transfers = parsedTransfers;
16502
- tripContinuations = parsedTripContinuations;
16503
- const transfersEnd = performance.now();
16504
- log.info(`${transfers.size} valid transfers and ${tripContinuations.size} trip continuations. (${(transfersEnd - transfersStart).toFixed(2)}ms)`);
16505
- }
16506
- log.info(`Parsing ${STOP_TIMES_FILE}`);
16507
- const stopTimesStart = performance.now();
16508
- const stopTimesStream = yield zip.stream(STOP_TIMES_FILE);
16509
- const { routes, serviceRoutesMap, tripsMapping } = yield parseStopTimes(stopTimesStream, parsedStops, trips, activeStopIds);
16510
- const serviceRoutes = indexRoutes(validGtfsRoutes, serviceRoutesMap);
16511
- const stopTimesEnd = performance.now();
16512
- log.info(`${routes.length} valid unique routes. (${(stopTimesEnd - stopTimesStart).toFixed(2)}ms)`);
16513
- log.info('Building stops adjacency structure');
16514
- const stopsAdjacencyStart = performance.now();
16515
- const stopsAdjacency = buildStopsAdjacencyStructure(tripsMapping, serviceRoutes, routes, transfers, tripContinuations, parsedStops.size, activeStopIds);
16516
- const stopsAdjacencyEnd = performance.now();
16517
- log.info(`${stopsAdjacency.length} valid stops in the structure. (${(stopsAdjacencyEnd - stopsAdjacencyStart).toFixed(2)}ms)`);
16518
- yield zip.close();
16519
- const timetable = new Timetable(stopsAdjacency, routes, serviceRoutes);
16520
- log.info('Parsing complete.');
16521
- return timetable;
16522
- });
16474
+ async parseTimetable(date) {
16475
+ log.setLevel('INFO');
16476
+ const zip = new StreamZip.async({ file: this.path });
16477
+ const entries = await zip.entries();
16478
+ const datetime = DateTime.fromJSDate(date);
16479
+ const activeServiceIds = new Set();
16480
+ const activeStopIds = new Set();
16481
+ log.info(`Parsing ${STOPS_FILE}`);
16482
+ const stopsStart = performance.now();
16483
+ const stopsStream = await zip.stream(STOPS_FILE);
16484
+ const parsedStops = await parseStops(stopsStream);
16485
+ const stopsEnd = performance.now();
16486
+ log.info(`${parsedStops.size} parsed stops. (${(stopsEnd - stopsStart).toFixed(2)}ms)`);
16487
+ if (entries[CALENDAR_FILE]) {
16488
+ log.info(`Parsing ${CALENDAR_FILE}`);
16489
+ const calendarStart = performance.now();
16490
+ const calendarStream = await zip.stream(CALENDAR_FILE);
16491
+ await parseCalendar(calendarStream, activeServiceIds, datetime);
16492
+ const calendarEnd = performance.now();
16493
+ log.info(`${activeServiceIds.size} valid services. (${(calendarEnd - calendarStart).toFixed(2)}ms)`);
16494
+ }
16495
+ if (entries[CALENDAR_DATES_FILE]) {
16496
+ log.info(`Parsing ${CALENDAR_DATES_FILE}`);
16497
+ const calendarDatesStart = performance.now();
16498
+ const calendarDatesStream = await zip.stream(CALENDAR_DATES_FILE);
16499
+ await parseCalendarDates(calendarDatesStream, activeServiceIds, datetime);
16500
+ const calendarDatesEnd = performance.now();
16501
+ log.info(`${activeServiceIds.size} valid services. (${(calendarDatesEnd - calendarDatesStart).toFixed(2)}ms)`);
16502
+ }
16503
+ log.info(`Parsing ${ROUTES_FILE}`);
16504
+ const routesStart = performance.now();
16505
+ const routesStream = await zip.stream(ROUTES_FILE);
16506
+ const validGtfsRoutes = await parseRoutes(routesStream, this.profile);
16507
+ const routesEnd = performance.now();
16508
+ log.info(`${validGtfsRoutes.size} valid GTFS routes. (${(routesEnd - routesStart).toFixed(2)}ms)`);
16509
+ log.info(`Parsing ${TRIPS_FILE}`);
16510
+ const tripsStart = performance.now();
16511
+ const tripsStream = await zip.stream(TRIPS_FILE);
16512
+ const trips = await parseTrips(tripsStream, activeServiceIds, validGtfsRoutes);
16513
+ const tripsEnd = performance.now();
16514
+ log.info(`${trips.size} valid trips. (${(tripsEnd - tripsStart).toFixed(2)}ms)`);
16515
+ let transfers = new Map();
16516
+ let tripContinuationsMap = [];
16517
+ if (entries[TRANSFERS_FILE]) {
16518
+ log.info(`Parsing ${TRANSFERS_FILE}`);
16519
+ const transfersStart = performance.now();
16520
+ const transfersStream = await zip.stream(TRANSFERS_FILE);
16521
+ const { transfers: parsedTransfers, tripContinuations: parsedTripContinuations, } = await parseTransfers(transfersStream, parsedStops);
16522
+ transfers = parsedTransfers;
16523
+ tripContinuationsMap = parsedTripContinuations;
16524
+ const transfersEnd = performance.now();
16525
+ log.info(`${transfers.size} valid transfers and ${tripContinuationsMap.length} trip continuations. (${(transfersEnd - transfersStart).toFixed(2)}ms)`);
16526
+ }
16527
+ log.info(`Parsing ${STOP_TIMES_FILE}`);
16528
+ const stopTimesStart = performance.now();
16529
+ const stopTimesStream = await zip.stream(STOP_TIMES_FILE);
16530
+ const { routes, serviceRoutesMap, tripsMapping } = await parseStopTimes(stopTimesStream, parsedStops, trips, activeStopIds);
16531
+ const serviceRoutes = indexRoutes(validGtfsRoutes, serviceRoutesMap);
16532
+ const stopTimesEnd = performance.now();
16533
+ log.info(`${routes.length} valid unique routes. (${(stopTimesEnd - stopTimesStart).toFixed(2)}ms)`);
16534
+ log.info('Building stops adjacency structure');
16535
+ const stopsAdjacencyStart = performance.now();
16536
+ const stopsAdjacency = buildStopsAdjacencyStructure(serviceRoutes, routes, transfers, parsedStops.size, activeStopIds);
16537
+ const stopsAdjacencyEnd = performance.now();
16538
+ log.info(`${stopsAdjacency.length} valid stops in the structure. (${(stopsAdjacencyEnd - stopsAdjacencyStart).toFixed(2)}ms)`);
16539
+ await zip.close();
16540
+ // temporary timetable for building continuations
16541
+ const timetable = new Timetable(stopsAdjacency, routes, serviceRoutes);
16542
+ log.info('Building in-seat trip continuations');
16543
+ const tripContinuationsStart = performance.now();
16544
+ const tripContinuations = buildTripContinuations(tripsMapping, tripContinuationsMap, timetable, activeStopIds);
16545
+ const tripContinuationsEnd = performance.now();
16546
+ log.info(`${tripContinuations.size} in-seat trip continuations origins created. (${(tripContinuationsEnd - tripContinuationsStart).toFixed(2)}ms)`);
16547
+ log.info('Parsing complete.');
16548
+ return new Timetable(stopsAdjacency, routes, serviceRoutes, tripContinuations);
16523
16549
  }
16524
16550
  /**
16525
16551
  * Parses a GTFS feed to extract all stops.
@@ -16527,18 +16553,16 @@ class GtfsParser {
16527
16553
  * @param activeStops The set of active stop IDs to include in the index.
16528
16554
  * @returns An index of stops.
16529
16555
  */
16530
- parseStops() {
16531
- return __awaiter(this, void 0, void 0, function* () {
16532
- const zip = new StreamZip.async({ file: this.path });
16533
- log.info(`Parsing ${STOPS_FILE}`);
16534
- const stopsStart = performance.now();
16535
- const stopsStream = yield zip.stream(STOPS_FILE);
16536
- const stops = yield parseStops(stopsStream);
16537
- const stopsEnd = performance.now();
16538
- log.info(`${stops.size} parsed stops. (${(stopsEnd - stopsStart).toFixed(2)}ms)`);
16539
- yield zip.close();
16540
- return new StopsIndex(Array.from(stops.values()));
16541
- });
16556
+ async parseStops() {
16557
+ const zip = new StreamZip.async({ file: this.path });
16558
+ log.info(`Parsing ${STOPS_FILE}`);
16559
+ const stopsStart = performance.now();
16560
+ const stopsStream = await zip.stream(STOPS_FILE);
16561
+ const stops = await parseStops(stopsStream);
16562
+ const stopsEnd = performance.now();
16563
+ log.info(`${stops.size} parsed stops. (${(stopsEnd - stopsStart).toFixed(2)}ms)`);
16564
+ await zip.close();
16565
+ return new StopsIndex(Array.from(stops.values()));
16542
16566
  }
16543
16567
  }
16544
16568