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
package/dist/cli.mjs CHANGED
@@ -13,58 +13,6 @@ import require$$5, { Transform } from 'stream';
13
13
  import { performance as performance$1 } from 'perf_hooks';
14
14
  import repl from 'node:repl';
15
15
 
16
- /******************************************************************************
17
- Copyright (c) Microsoft Corporation.
18
-
19
- Permission to use, copy, modify, and/or distribute this software for any
20
- purpose with or without fee is hereby granted.
21
-
22
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
23
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
24
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
25
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
26
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
27
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28
- PERFORMANCE OF THIS SOFTWARE.
29
- ***************************************************************************** */
30
- /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
31
-
32
-
33
- function __awaiter(thisArg, _arguments, P, generator) {
34
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
35
- return new (P || (P = Promise))(function (resolve, reject) {
36
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
37
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
38
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
39
- step((generator = generator.apply(thisArg, _arguments || [])).next());
40
- });
41
- }
42
-
43
- function __values(o) {
44
- var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
45
- if (m) return m.call(o);
46
- if (o && typeof o.length === "number") return {
47
- next: function () {
48
- if (o && i >= o.length) o = void 0;
49
- return { value: o && o[i++], done: !o };
50
- }
51
- };
52
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
53
- }
54
-
55
- function __asyncValues(o) {
56
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
57
- var m = o[Symbol.asyncIterator], i;
58
- 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);
59
- 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); }); }; }
60
- function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
61
- }
62
-
63
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
64
- var e = new Error(message);
65
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
66
- };
67
-
68
16
  function getDefaultExportFromCjs (x) {
69
17
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
70
18
  }
@@ -15864,14 +15812,13 @@ const Stop = {
15864
15812
  sourceStopId: isSet$1(object.sourceStopId) ? globalThis.String(object.sourceStopId) : "",
15865
15813
  lat: isSet$1(object.lat) ? globalThis.Number(object.lat) : undefined,
15866
15814
  lon: isSet$1(object.lon) ? globalThis.Number(object.lon) : undefined,
15867
- children: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.children) ? object.children.map((e) => globalThis.Number(e)) : [],
15815
+ children: globalThis.Array.isArray(object?.children) ? object.children.map((e) => globalThis.Number(e)) : [],
15868
15816
  parent: isSet$1(object.parent) ? globalThis.Number(object.parent) : undefined,
15869
15817
  locationType: isSet$1(object.locationType) ? locationTypeFromJSON(object.locationType) : 0,
15870
15818
  platform: isSet$1(object.platform) ? globalThis.String(object.platform) : undefined,
15871
15819
  };
15872
15820
  },
15873
15821
  toJSON(message) {
15874
- var _a;
15875
15822
  const obj = {};
15876
15823
  if (message.name !== "") {
15877
15824
  obj.name = message.name;
@@ -15885,7 +15832,7 @@ const Stop = {
15885
15832
  if (message.lon !== undefined) {
15886
15833
  obj.lon = message.lon;
15887
15834
  }
15888
- if ((_a = message.children) === null || _a === void 0 ? void 0 : _a.length) {
15835
+ if (message.children?.length) {
15889
15836
  obj.children = message.children.map((e) => Math.round(e));
15890
15837
  }
15891
15838
  if (message.parent !== undefined) {
@@ -15900,19 +15847,18 @@ const Stop = {
15900
15847
  return obj;
15901
15848
  },
15902
15849
  create(base) {
15903
- return Stop.fromPartial(base !== null && base !== void 0 ? base : {});
15850
+ return Stop.fromPartial(base ?? {});
15904
15851
  },
15905
15852
  fromPartial(object) {
15906
- var _a, _b, _c, _d, _e, _f, _g, _h;
15907
15853
  const message = createBaseStop();
15908
- message.name = (_a = object.name) !== null && _a !== void 0 ? _a : "";
15909
- message.sourceStopId = (_b = object.sourceStopId) !== null && _b !== void 0 ? _b : "";
15910
- message.lat = (_c = object.lat) !== null && _c !== void 0 ? _c : undefined;
15911
- message.lon = (_d = object.lon) !== null && _d !== void 0 ? _d : undefined;
15912
- message.children = ((_e = object.children) === null || _e === void 0 ? void 0 : _e.map((e) => e)) || [];
15913
- message.parent = (_f = object.parent) !== null && _f !== void 0 ? _f : undefined;
15914
- message.locationType = (_g = object.locationType) !== null && _g !== void 0 ? _g : 0;
15915
- message.platform = (_h = object.platform) !== null && _h !== void 0 ? _h : undefined;
15854
+ message.name = object.name ?? "";
15855
+ message.sourceStopId = object.sourceStopId ?? "";
15856
+ message.lat = object.lat ?? undefined;
15857
+ message.lon = object.lon ?? undefined;
15858
+ message.children = object.children?.map((e) => e) || [];
15859
+ message.parent = object.parent ?? undefined;
15860
+ message.locationType = object.locationType ?? 0;
15861
+ message.platform = object.platform ?? undefined;
15916
15862
  return message;
15917
15863
  },
15918
15864
  };
@@ -15961,28 +15907,26 @@ const StopsMap = {
15961
15907
  fromJSON(object) {
15962
15908
  return {
15963
15909
  version: isSet$1(object.version) ? globalThis.String(object.version) : "",
15964
- stops: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.stops) ? object.stops.map((e) => Stop.fromJSON(e)) : [],
15910
+ stops: globalThis.Array.isArray(object?.stops) ? object.stops.map((e) => Stop.fromJSON(e)) : [],
15965
15911
  };
15966
15912
  },
15967
15913
  toJSON(message) {
15968
- var _a;
15969
15914
  const obj = {};
15970
15915
  if (message.version !== "") {
15971
15916
  obj.version = message.version;
15972
15917
  }
15973
- if ((_a = message.stops) === null || _a === void 0 ? void 0 : _a.length) {
15918
+ if (message.stops?.length) {
15974
15919
  obj.stops = message.stops.map((e) => Stop.toJSON(e));
15975
15920
  }
15976
15921
  return obj;
15977
15922
  },
15978
15923
  create(base) {
15979
- return StopsMap.fromPartial(base !== null && base !== void 0 ? base : {});
15924
+ return StopsMap.fromPartial(base ?? {});
15980
15925
  },
15981
15926
  fromPartial(object) {
15982
- var _a, _b;
15983
15927
  const message = createBaseStopsMap();
15984
- message.version = (_a = object.version) !== null && _a !== void 0 ? _a : "";
15985
- message.stops = ((_b = object.stops) === null || _b === void 0 ? void 0 : _b.map((e) => Stop.fromPartial(e))) || [];
15928
+ message.version = object.version ?? "";
15929
+ message.stops = object.stops?.map((e) => Stop.fromPartial(e)) || [];
15986
15930
  return message;
15987
15931
  },
15988
15932
  };
@@ -16066,8 +16010,12 @@ const serializeLocationType = (locationType) => {
16066
16010
  * to efficiently find stops based on user queries.
16067
16011
  */
16068
16012
  class StopsIndex {
16013
+ stops;
16014
+ sourceStopsMap;
16015
+ textIndex;
16016
+ geoIndex;
16017
+ stopPoints;
16069
16018
  constructor(stops) {
16070
- var _a;
16071
16019
  this.stops = stops;
16072
16020
  this.sourceStopsMap = new Map();
16073
16021
  const stopsSet = new Map();
@@ -16076,7 +16024,7 @@ class StopsIndex {
16076
16024
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16077
16025
  const stop = stops[id];
16078
16026
  this.sourceStopsMap.set(stop.sourceStopId, id);
16079
- const effectiveStopId = (_a = stop.parent) !== null && _a !== void 0 ? _a : id;
16027
+ const effectiveStopId = stop.parent ?? id;
16080
16028
  if (!stopsSet.has(effectiveStopId)) {
16081
16029
  stopsSet.set(effectiveStopId, {
16082
16030
  id: effectiveStopId,
@@ -16191,7 +16139,6 @@ class StopsIndex {
16191
16139
  * Find ids of all sibling stops.
16192
16140
  */
16193
16141
  equivalentStops(sourceId) {
16194
- var _a, _b;
16195
16142
  const id = this.sourceStopsMap.get(sourceId);
16196
16143
  if (id === undefined) {
16197
16144
  return [];
@@ -16201,13 +16148,14 @@ class StopsIndex {
16201
16148
  return [];
16202
16149
  }
16203
16150
  const equivalentStops = stop.parent
16204
- ? ((_b = (_a = this.stops[stop.parent]) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : [])
16151
+ ? (this.stops[stop.parent]?.children ?? [])
16205
16152
  : stop.children;
16206
16153
  return Array.from(new Set([id, ...equivalentStops])).map((stopId) => this.stops[stopId]);
16207
16154
  }
16208
16155
  }
16209
16156
 
16210
16157
  class Duration {
16158
+ totalSeconds;
16211
16159
  constructor(totalSeconds) {
16212
16160
  this.totalSeconds = totalSeconds;
16213
16161
  }
@@ -16510,15 +16458,14 @@ const Route$2 = {
16510
16458
  return obj;
16511
16459
  },
16512
16460
  create(base) {
16513
- return Route$2.fromPartial(base !== null && base !== void 0 ? base : {});
16461
+ return Route$2.fromPartial(base ?? {});
16514
16462
  },
16515
16463
  fromPartial(object) {
16516
- var _a, _b, _c, _d;
16517
16464
  const message = createBaseRoute();
16518
- message.stopTimes = (_a = object.stopTimes) !== null && _a !== void 0 ? _a : new Uint8Array(0);
16519
- message.pickUpDropOffTypes = (_b = object.pickUpDropOffTypes) !== null && _b !== void 0 ? _b : new Uint8Array(0);
16520
- message.stops = (_c = object.stops) !== null && _c !== void 0 ? _c : new Uint8Array(0);
16521
- message.serviceRouteId = (_d = object.serviceRouteId) !== null && _d !== void 0 ? _d : 0;
16465
+ message.stopTimes = object.stopTimes ?? new Uint8Array(0);
16466
+ message.pickUpDropOffTypes = object.pickUpDropOffTypes ?? new Uint8Array(0);
16467
+ message.stops = object.stops ?? new Uint8Array(0);
16468
+ message.serviceRouteId = object.serviceRouteId ?? 0;
16522
16469
  return message;
16523
16470
  },
16524
16471
  };
@@ -16595,24 +16542,23 @@ const Transfer = {
16595
16542
  return obj;
16596
16543
  },
16597
16544
  create(base) {
16598
- return Transfer.fromPartial(base !== null && base !== void 0 ? base : {});
16545
+ return Transfer.fromPartial(base ?? {});
16599
16546
  },
16600
16547
  fromPartial(object) {
16601
- var _a, _b, _c;
16602
16548
  const message = createBaseTransfer();
16603
- message.destination = (_a = object.destination) !== null && _a !== void 0 ? _a : 0;
16604
- message.type = (_b = object.type) !== null && _b !== void 0 ? _b : 0;
16605
- message.minTransferTime = (_c = object.minTransferTime) !== null && _c !== void 0 ? _c : undefined;
16549
+ message.destination = object.destination ?? 0;
16550
+ message.type = object.type ?? 0;
16551
+ message.minTransferTime = object.minTransferTime ?? undefined;
16606
16552
  return message;
16607
16553
  },
16608
16554
  };
16609
16555
  function createBaseTripBoarding() {
16610
- return { hopOnStop: 0, routeId: 0, tripIndex: 0 };
16556
+ return { hopOnStopIndex: 0, routeId: 0, tripIndex: 0 };
16611
16557
  }
16612
16558
  const TripBoarding = {
16613
16559
  encode(message, writer = new BinaryWriter()) {
16614
- if (message.hopOnStop !== 0) {
16615
- writer.uint32(8).uint32(message.hopOnStop);
16560
+ if (message.hopOnStopIndex !== 0) {
16561
+ writer.uint32(8).uint32(message.hopOnStopIndex);
16616
16562
  }
16617
16563
  if (message.routeId !== 0) {
16618
16564
  writer.uint32(16).uint32(message.routeId);
@@ -16633,7 +16579,7 @@ const TripBoarding = {
16633
16579
  if (tag !== 8) {
16634
16580
  break;
16635
16581
  }
16636
- message.hopOnStop = reader.uint32();
16582
+ message.hopOnStopIndex = reader.uint32();
16637
16583
  continue;
16638
16584
  }
16639
16585
  case 2: {
@@ -16660,15 +16606,15 @@ const TripBoarding = {
16660
16606
  },
16661
16607
  fromJSON(object) {
16662
16608
  return {
16663
- hopOnStop: isSet(object.hopOnStop) ? globalThis.Number(object.hopOnStop) : 0,
16609
+ hopOnStopIndex: isSet(object.hopOnStopIndex) ? globalThis.Number(object.hopOnStopIndex) : 0,
16664
16610
  routeId: isSet(object.routeId) ? globalThis.Number(object.routeId) : 0,
16665
16611
  tripIndex: isSet(object.tripIndex) ? globalThis.Number(object.tripIndex) : 0,
16666
16612
  };
16667
16613
  },
16668
16614
  toJSON(message) {
16669
16615
  const obj = {};
16670
- if (message.hopOnStop !== 0) {
16671
- obj.hopOnStop = Math.round(message.hopOnStop);
16616
+ if (message.hopOnStopIndex !== 0) {
16617
+ obj.hopOnStopIndex = Math.round(message.hopOnStopIndex);
16672
16618
  }
16673
16619
  if (message.routeId !== 0) {
16674
16620
  obj.routeId = Math.round(message.routeId);
@@ -16679,27 +16625,32 @@ const TripBoarding = {
16679
16625
  return obj;
16680
16626
  },
16681
16627
  create(base) {
16682
- return TripBoarding.fromPartial(base !== null && base !== void 0 ? base : {});
16628
+ return TripBoarding.fromPartial(base ?? {});
16683
16629
  },
16684
16630
  fromPartial(object) {
16685
- var _a, _b, _c;
16686
16631
  const message = createBaseTripBoarding();
16687
- message.hopOnStop = (_a = object.hopOnStop) !== null && _a !== void 0 ? _a : 0;
16688
- message.routeId = (_b = object.routeId) !== null && _b !== void 0 ? _b : 0;
16689
- message.tripIndex = (_c = object.tripIndex) !== null && _c !== void 0 ? _c : 0;
16632
+ message.hopOnStopIndex = object.hopOnStopIndex ?? 0;
16633
+ message.routeId = object.routeId ?? 0;
16634
+ message.tripIndex = object.tripIndex ?? 0;
16690
16635
  return message;
16691
16636
  },
16692
16637
  };
16693
16638
  function createBaseTripContinuationEntry() {
16694
- return { key: 0, value: [] };
16639
+ return { originStopIndex: 0, originRouteId: 0, originTripIndex: 0, continuations: [] };
16695
16640
  }
16696
16641
  const TripContinuationEntry = {
16697
16642
  encode(message, writer = new BinaryWriter()) {
16698
- if (message.key !== 0) {
16699
- writer.uint32(8).uint32(message.key);
16643
+ if (message.originStopIndex !== 0) {
16644
+ writer.uint32(8).uint32(message.originStopIndex);
16645
+ }
16646
+ if (message.originRouteId !== 0) {
16647
+ writer.uint32(16).uint32(message.originRouteId);
16700
16648
  }
16701
- for (const v of message.value) {
16702
- TripBoarding.encode(v, writer.uint32(18).fork()).join();
16649
+ if (message.originTripIndex !== 0) {
16650
+ writer.uint32(24).uint32(message.originTripIndex);
16651
+ }
16652
+ for (const v of message.continuations) {
16653
+ TripBoarding.encode(v, writer.uint32(34).fork()).join();
16703
16654
  }
16704
16655
  return writer;
16705
16656
  },
@@ -16714,14 +16665,28 @@ const TripContinuationEntry = {
16714
16665
  if (tag !== 8) {
16715
16666
  break;
16716
16667
  }
16717
- message.key = reader.uint32();
16668
+ message.originStopIndex = reader.uint32();
16718
16669
  continue;
16719
16670
  }
16720
16671
  case 2: {
16721
- if (tag !== 18) {
16672
+ if (tag !== 16) {
16673
+ break;
16674
+ }
16675
+ message.originRouteId = reader.uint32();
16676
+ continue;
16677
+ }
16678
+ case 3: {
16679
+ if (tag !== 24) {
16680
+ break;
16681
+ }
16682
+ message.originTripIndex = reader.uint32();
16683
+ continue;
16684
+ }
16685
+ case 4: {
16686
+ if (tag !== 34) {
16722
16687
  break;
16723
16688
  }
16724
- message.value.push(TripBoarding.decode(reader, reader.uint32()));
16689
+ message.continuations.push(TripBoarding.decode(reader, reader.uint32()));
16725
16690
  continue;
16726
16691
  }
16727
16692
  }
@@ -16734,34 +16699,44 @@ const TripContinuationEntry = {
16734
16699
  },
16735
16700
  fromJSON(object) {
16736
16701
  return {
16737
- key: isSet(object.key) ? globalThis.Number(object.key) : 0,
16738
- value: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.value) ? object.value.map((e) => TripBoarding.fromJSON(e)) : [],
16702
+ originStopIndex: isSet(object.originStopIndex) ? globalThis.Number(object.originStopIndex) : 0,
16703
+ originRouteId: isSet(object.originRouteId) ? globalThis.Number(object.originRouteId) : 0,
16704
+ originTripIndex: isSet(object.originTripIndex) ? globalThis.Number(object.originTripIndex) : 0,
16705
+ continuations: globalThis.Array.isArray(object?.continuations)
16706
+ ? object.continuations.map((e) => TripBoarding.fromJSON(e))
16707
+ : [],
16739
16708
  };
16740
16709
  },
16741
16710
  toJSON(message) {
16742
- var _a;
16743
16711
  const obj = {};
16744
- if (message.key !== 0) {
16745
- obj.key = Math.round(message.key);
16712
+ if (message.originStopIndex !== 0) {
16713
+ obj.originStopIndex = Math.round(message.originStopIndex);
16714
+ }
16715
+ if (message.originRouteId !== 0) {
16716
+ obj.originRouteId = Math.round(message.originRouteId);
16746
16717
  }
16747
- if ((_a = message.value) === null || _a === void 0 ? void 0 : _a.length) {
16748
- obj.value = message.value.map((e) => TripBoarding.toJSON(e));
16718
+ if (message.originTripIndex !== 0) {
16719
+ obj.originTripIndex = Math.round(message.originTripIndex);
16720
+ }
16721
+ if (message.continuations?.length) {
16722
+ obj.continuations = message.continuations.map((e) => TripBoarding.toJSON(e));
16749
16723
  }
16750
16724
  return obj;
16751
16725
  },
16752
16726
  create(base) {
16753
- return TripContinuationEntry.fromPartial(base !== null && base !== void 0 ? base : {});
16727
+ return TripContinuationEntry.fromPartial(base ?? {});
16754
16728
  },
16755
16729
  fromPartial(object) {
16756
- var _a, _b;
16757
16730
  const message = createBaseTripContinuationEntry();
16758
- message.key = (_a = object.key) !== null && _a !== void 0 ? _a : 0;
16759
- message.value = ((_b = object.value) === null || _b === void 0 ? void 0 : _b.map((e) => TripBoarding.fromPartial(e))) || [];
16731
+ message.originStopIndex = object.originStopIndex ?? 0;
16732
+ message.originRouteId = object.originRouteId ?? 0;
16733
+ message.originTripIndex = object.originTripIndex ?? 0;
16734
+ message.continuations = object.continuations?.map((e) => TripBoarding.fromPartial(e)) || [];
16760
16735
  return message;
16761
16736
  },
16762
16737
  };
16763
16738
  function createBaseStopAdjacency() {
16764
- return { routes: [], transfers: [], tripContinuations: [] };
16739
+ return { routes: [], transfers: [] };
16765
16740
  }
16766
16741
  const StopAdjacency = {
16767
16742
  encode(message, writer = new BinaryWriter()) {
@@ -16773,9 +16748,6 @@ const StopAdjacency = {
16773
16748
  for (const v of message.transfers) {
16774
16749
  Transfer.encode(v, writer.uint32(18).fork()).join();
16775
16750
  }
16776
- for (const v of message.tripContinuations) {
16777
- TripContinuationEntry.encode(v, writer.uint32(26).fork()).join();
16778
- }
16779
16751
  return writer;
16780
16752
  },
16781
16753
  decode(input, length) {
@@ -16806,13 +16778,6 @@ const StopAdjacency = {
16806
16778
  message.transfers.push(Transfer.decode(reader, reader.uint32()));
16807
16779
  continue;
16808
16780
  }
16809
- case 3: {
16810
- if (tag !== 26) {
16811
- break;
16812
- }
16813
- message.tripContinuations.push(TripContinuationEntry.decode(reader, reader.uint32()));
16814
- continue;
16815
- }
16816
16781
  }
16817
16782
  if ((tag & 7) === 4 || tag === 0) {
16818
16783
  break;
@@ -16823,38 +16788,29 @@ const StopAdjacency = {
16823
16788
  },
16824
16789
  fromJSON(object) {
16825
16790
  return {
16826
- routes: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.routes) ? object.routes.map((e) => globalThis.Number(e)) : [],
16827
- transfers: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.transfers)
16791
+ routes: globalThis.Array.isArray(object?.routes) ? object.routes.map((e) => globalThis.Number(e)) : [],
16792
+ transfers: globalThis.Array.isArray(object?.transfers)
16828
16793
  ? object.transfers.map((e) => Transfer.fromJSON(e))
16829
16794
  : [],
16830
- tripContinuations: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.tripContinuations)
16831
- ? object.tripContinuations.map((e) => TripContinuationEntry.fromJSON(e))
16832
- : [],
16833
16795
  };
16834
16796
  },
16835
16797
  toJSON(message) {
16836
- var _a, _b, _c;
16837
16798
  const obj = {};
16838
- if ((_a = message.routes) === null || _a === void 0 ? void 0 : _a.length) {
16799
+ if (message.routes?.length) {
16839
16800
  obj.routes = message.routes.map((e) => Math.round(e));
16840
16801
  }
16841
- if ((_b = message.transfers) === null || _b === void 0 ? void 0 : _b.length) {
16802
+ if (message.transfers?.length) {
16842
16803
  obj.transfers = message.transfers.map((e) => Transfer.toJSON(e));
16843
16804
  }
16844
- if ((_c = message.tripContinuations) === null || _c === void 0 ? void 0 : _c.length) {
16845
- obj.tripContinuations = message.tripContinuations.map((e) => TripContinuationEntry.toJSON(e));
16846
- }
16847
16805
  return obj;
16848
16806
  },
16849
16807
  create(base) {
16850
- return StopAdjacency.fromPartial(base !== null && base !== void 0 ? base : {});
16808
+ return StopAdjacency.fromPartial(base ?? {});
16851
16809
  },
16852
16810
  fromPartial(object) {
16853
- var _a, _b, _c;
16854
16811
  const message = createBaseStopAdjacency();
16855
- message.routes = ((_a = object.routes) === null || _a === void 0 ? void 0 : _a.map((e) => e)) || [];
16856
- message.transfers = ((_b = object.transfers) === null || _b === void 0 ? void 0 : _b.map((e) => Transfer.fromPartial(e))) || [];
16857
- message.tripContinuations = ((_c = object.tripContinuations) === null || _c === void 0 ? void 0 : _c.map((e) => TripContinuationEntry.fromPartial(e))) || [];
16812
+ message.routes = object.routes?.map((e) => e) || [];
16813
+ message.transfers = object.transfers?.map((e) => Transfer.fromPartial(e)) || [];
16858
16814
  return message;
16859
16815
  },
16860
16816
  };
@@ -16923,11 +16879,10 @@ const ServiceRoute = {
16923
16879
  return {
16924
16880
  type: isSet(object.type) ? routeTypeFromJSON(object.type) : 0,
16925
16881
  name: isSet(object.name) ? globalThis.String(object.name) : "",
16926
- routes: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.routes) ? object.routes.map((e) => globalThis.Number(e)) : [],
16882
+ routes: globalThis.Array.isArray(object?.routes) ? object.routes.map((e) => globalThis.Number(e)) : [],
16927
16883
  };
16928
16884
  },
16929
16885
  toJSON(message) {
16930
- var _a;
16931
16886
  const obj = {};
16932
16887
  if (message.type !== 0) {
16933
16888
  obj.type = routeTypeToJSON(message.type);
@@ -16935,25 +16890,24 @@ const ServiceRoute = {
16935
16890
  if (message.name !== "") {
16936
16891
  obj.name = message.name;
16937
16892
  }
16938
- if ((_a = message.routes) === null || _a === void 0 ? void 0 : _a.length) {
16893
+ if (message.routes?.length) {
16939
16894
  obj.routes = message.routes.map((e) => Math.round(e));
16940
16895
  }
16941
16896
  return obj;
16942
16897
  },
16943
16898
  create(base) {
16944
- return ServiceRoute.fromPartial(base !== null && base !== void 0 ? base : {});
16899
+ return ServiceRoute.fromPartial(base ?? {});
16945
16900
  },
16946
16901
  fromPartial(object) {
16947
- var _a, _b, _c;
16948
16902
  const message = createBaseServiceRoute();
16949
- message.type = (_a = object.type) !== null && _a !== void 0 ? _a : 0;
16950
- message.name = (_b = object.name) !== null && _b !== void 0 ? _b : "";
16951
- message.routes = ((_c = object.routes) === null || _c === void 0 ? void 0 : _c.map((e) => e)) || [];
16903
+ message.type = object.type ?? 0;
16904
+ message.name = object.name ?? "";
16905
+ message.routes = object.routes?.map((e) => e) || [];
16952
16906
  return message;
16953
16907
  },
16954
16908
  };
16955
16909
  function createBaseTimetable() {
16956
- return { version: "", stopsAdjacency: [], routesAdjacency: [], serviceRoutes: [] };
16910
+ return { version: "", stopsAdjacency: [], routesAdjacency: [], serviceRoutes: [], tripContinuations: [] };
16957
16911
  }
16958
16912
  const Timetable$1 = {
16959
16913
  encode(message, writer = new BinaryWriter()) {
@@ -16969,6 +16923,9 @@ const Timetable$1 = {
16969
16923
  for (const v of message.serviceRoutes) {
16970
16924
  ServiceRoute.encode(v, writer.uint32(34).fork()).join();
16971
16925
  }
16926
+ for (const v of message.tripContinuations) {
16927
+ TripContinuationEntry.encode(v, writer.uint32(42).fork()).join();
16928
+ }
16972
16929
  return writer;
16973
16930
  },
16974
16931
  decode(input, length) {
@@ -17006,6 +16963,13 @@ const Timetable$1 = {
17006
16963
  message.serviceRoutes.push(ServiceRoute.decode(reader, reader.uint32()));
17007
16964
  continue;
17008
16965
  }
16966
+ case 5: {
16967
+ if (tag !== 42) {
16968
+ break;
16969
+ }
16970
+ message.tripContinuations.push(TripContinuationEntry.decode(reader, reader.uint32()));
16971
+ continue;
16972
+ }
17009
16973
  }
17010
16974
  if ((tag & 7) === 4 || tag === 0) {
17011
16975
  break;
@@ -17017,44 +16981,49 @@ const Timetable$1 = {
17017
16981
  fromJSON(object) {
17018
16982
  return {
17019
16983
  version: isSet(object.version) ? globalThis.String(object.version) : "",
17020
- stopsAdjacency: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.stopsAdjacency)
16984
+ stopsAdjacency: globalThis.Array.isArray(object?.stopsAdjacency)
17021
16985
  ? object.stopsAdjacency.map((e) => StopAdjacency.fromJSON(e))
17022
16986
  : [],
17023
- routesAdjacency: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.routesAdjacency)
16987
+ routesAdjacency: globalThis.Array.isArray(object?.routesAdjacency)
17024
16988
  ? object.routesAdjacency.map((e) => Route$2.fromJSON(e))
17025
16989
  : [],
17026
- serviceRoutes: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.serviceRoutes)
16990
+ serviceRoutes: globalThis.Array.isArray(object?.serviceRoutes)
17027
16991
  ? object.serviceRoutes.map((e) => ServiceRoute.fromJSON(e))
17028
16992
  : [],
16993
+ tripContinuations: globalThis.Array.isArray(object?.tripContinuations)
16994
+ ? object.tripContinuations.map((e) => TripContinuationEntry.fromJSON(e))
16995
+ : [],
17029
16996
  };
17030
16997
  },
17031
16998
  toJSON(message) {
17032
- var _a, _b, _c;
17033
16999
  const obj = {};
17034
17000
  if (message.version !== "") {
17035
17001
  obj.version = message.version;
17036
17002
  }
17037
- if ((_a = message.stopsAdjacency) === null || _a === void 0 ? void 0 : _a.length) {
17003
+ if (message.stopsAdjacency?.length) {
17038
17004
  obj.stopsAdjacency = message.stopsAdjacency.map((e) => StopAdjacency.toJSON(e));
17039
17005
  }
17040
- if ((_b = message.routesAdjacency) === null || _b === void 0 ? void 0 : _b.length) {
17006
+ if (message.routesAdjacency?.length) {
17041
17007
  obj.routesAdjacency = message.routesAdjacency.map((e) => Route$2.toJSON(e));
17042
17008
  }
17043
- if ((_c = message.serviceRoutes) === null || _c === void 0 ? void 0 : _c.length) {
17009
+ if (message.serviceRoutes?.length) {
17044
17010
  obj.serviceRoutes = message.serviceRoutes.map((e) => ServiceRoute.toJSON(e));
17045
17011
  }
17012
+ if (message.tripContinuations?.length) {
17013
+ obj.tripContinuations = message.tripContinuations.map((e) => TripContinuationEntry.toJSON(e));
17014
+ }
17046
17015
  return obj;
17047
17016
  },
17048
17017
  create(base) {
17049
- return Timetable$1.fromPartial(base !== null && base !== void 0 ? base : {});
17018
+ return Timetable$1.fromPartial(base ?? {});
17050
17019
  },
17051
17020
  fromPartial(object) {
17052
- var _a, _b, _c, _d;
17053
17021
  const message = createBaseTimetable();
17054
- message.version = (_a = object.version) !== null && _a !== void 0 ? _a : "";
17055
- message.stopsAdjacency = ((_b = object.stopsAdjacency) === null || _b === void 0 ? void 0 : _b.map((e) => StopAdjacency.fromPartial(e))) || [];
17056
- message.routesAdjacency = ((_c = object.routesAdjacency) === null || _c === void 0 ? void 0 : _c.map((e) => Route$2.fromPartial(e))) || [];
17057
- message.serviceRoutes = ((_d = object.serviceRoutes) === null || _d === void 0 ? void 0 : _d.map((e) => ServiceRoute.fromPartial(e))) || [];
17022
+ message.version = object.version ?? "";
17023
+ message.stopsAdjacency = object.stopsAdjacency?.map((e) => StopAdjacency.fromPartial(e)) || [];
17024
+ message.routesAdjacency = object.routesAdjacency?.map((e) => Route$2.fromPartial(e)) || [];
17025
+ message.serviceRoutes = object.serviceRoutes?.map((e) => ServiceRoute.fromPartial(e)) || [];
17026
+ message.tripContinuations = object.tripContinuations?.map((e) => TripContinuationEntry.fromPartial(e)) || [];
17058
17027
  return message;
17059
17028
  },
17060
17029
  };
@@ -17091,6 +17060,11 @@ function isSet(value) {
17091
17060
  * A class representing a time as minutes since midnight.
17092
17061
  */
17093
17062
  class Time {
17063
+ /*
17064
+ * Number of minutes since midnight.
17065
+ Note that this value can go beyond 3600 to model services overlapping with the next day.
17066
+ */
17067
+ minutesSinceMidnight;
17094
17068
  /**
17095
17069
  * Gets the infinity time as a Time instance.
17096
17070
  * This represents a time that is conceptually beyond any real possible time.
@@ -17343,6 +17317,51 @@ const toPickupDropOffType = (numericalType) => {
17343
17317
  * A route identifies all trips of a given service route sharing the same list of stops.
17344
17318
  */
17345
17319
  let Route$1 = class Route {
17320
+ id;
17321
+ /**
17322
+ * Arrivals and departures encoded as minutes from midnight.
17323
+ * Format: [arrival1, departure1, arrival2, departure2, etc.]
17324
+ */
17325
+ stopTimes;
17326
+ /**
17327
+ * PickUp and DropOff types represented as a 2-bit encoded Uint8Array.
17328
+ * Values (2 bits each):
17329
+ * 0: REGULAR
17330
+ * 1: NOT_AVAILABLE
17331
+ * 2: MUST_PHONE_AGENCY
17332
+ * 3: MUST_COORDINATE_WITH_DRIVER
17333
+ *
17334
+ * Encoding format: Each byte contains 2 pickup/drop-off pairs (4 bits each)
17335
+ * Bit layout per byte: [pickup_1 (2 bits)][drop_off_1 (2 bits)][pickup_0 (2 bits)][drop_off_0 (2 bits)]
17336
+ * Example: For stops 0 and 1 in a trip, one byte encodes all 4 values
17337
+ */
17338
+ pickUpDropOffTypes;
17339
+ /**
17340
+ * A binary array of stopIds in the route.
17341
+ * [stop1, stop2, stop3,...]
17342
+ */
17343
+ stops;
17344
+ /**
17345
+ * A reverse mapping of each stop with their index in the route:
17346
+ * {
17347
+ * 4: 0,
17348
+ * 5: 1,
17349
+ * ...
17350
+ * }
17351
+ */
17352
+ stopIndices;
17353
+ /**
17354
+ * The identifier of the route as a service shown to users.
17355
+ */
17356
+ serviceRouteId;
17357
+ /**
17358
+ * The total number of stops in the route.
17359
+ */
17360
+ nbStops;
17361
+ /**
17362
+ * The total number of trips in the route.
17363
+ */
17364
+ nbTrips;
17346
17365
  constructor(id, stopTimes, pickUpDropOffTypes, stops, serviceRouteId) {
17347
17366
  this.id = id;
17348
17367
  this.stopTimes = stopTimes;
@@ -17354,7 +17373,14 @@ let Route$1 = class Route {
17354
17373
  this.stopIndices = new Map();
17355
17374
  for (let i = 0; i < stops.length; i++) {
17356
17375
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
17357
- this.stopIndices.set(stops[i], i);
17376
+ const stopId = stops[i];
17377
+ const existingIndices = this.stopIndices.get(stopId);
17378
+ if (existingIndices) {
17379
+ existingIndices.push(i);
17380
+ }
17381
+ else {
17382
+ this.stopIndices.set(stopId, [i]);
17383
+ }
17358
17384
  }
17359
17385
  }
17360
17386
  /**
@@ -17364,7 +17390,6 @@ let Route$1 = class Route {
17364
17390
  * @returns The new route.
17365
17391
  */
17366
17392
  static of(params) {
17367
- var _a, _b;
17368
17393
  const { id, serviceRouteId, trips } = params;
17369
17394
  if (trips.length === 0) {
17370
17395
  throw new Error('At least one trip must be provided');
@@ -17411,8 +17436,8 @@ let Route$1 = class Route {
17411
17436
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
17412
17437
  const stop = trip.stops[stopIndex];
17413
17438
  const globalIndex = tripIndex * numStops + stopIndex;
17414
- const pickUp = (_a = stop.pickUpType) !== null && _a !== void 0 ? _a : REGULAR;
17415
- const dropOff = (_b = stop.dropOffType) !== null && _b !== void 0 ? _b : REGULAR;
17439
+ const pickUp = stop.pickUpType ?? REGULAR;
17440
+ const dropOff = stop.dropOffType ?? REGULAR;
17416
17441
  const byteIndex = Math.floor(globalIndex / 2);
17417
17442
  const isSecondPair = globalIndex % 2 === 1;
17418
17443
  if (isSecondPair) {
@@ -17442,24 +17467,6 @@ let Route$1 = class Route {
17442
17467
  serviceRouteId: this.serviceRouteId,
17443
17468
  };
17444
17469
  }
17445
- /**
17446
- * Checks if stop A is before stop B in the route.
17447
- *
17448
- * @param stopA - The StopId of the first stop.
17449
- * @param stopB - The StopId of the second stop.
17450
- * @returns True if stop A is before stop B, false otherwise.
17451
- */
17452
- isBefore(stopA, stopB) {
17453
- const stopAIndex = this.stopIndices.get(stopA);
17454
- if (stopAIndex === undefined) {
17455
- throw new Error(`Stop index not found for ${stopA} in route ${this.serviceRouteId}`);
17456
- }
17457
- const stopBIndex = this.stopIndices.get(stopB);
17458
- if (stopBIndex === undefined) {
17459
- throw new Error(`Stop index not found for ${stopB} in route ${this.serviceRouteId}`);
17460
- }
17461
- return stopAIndex < stopBIndex;
17462
- }
17463
17470
  /**
17464
17471
  * Retrieves the number of stops in the route.
17465
17472
  *
@@ -17488,47 +17495,47 @@ let Route$1 = class Route {
17488
17495
  /**
17489
17496
  * Retrieves the arrival time at a specific stop for a given trip.
17490
17497
  *
17491
- * @param stopId - The identifier of the stop.
17498
+ * @param stopIndex - The index of the stop in the route.
17492
17499
  * @param tripIndex - The index of the trip.
17493
17500
  * @returns The arrival time at the specified stop and trip as a Time object.
17494
17501
  */
17495
- arrivalAt(stopId, tripIndex) {
17496
- const arrivalIndex = (tripIndex * this.stops.length + this.stopRouteIndex(stopId)) * 2;
17502
+ arrivalAt(stopIndex, tripIndex) {
17503
+ const arrivalIndex = (tripIndex * this.stops.length + stopIndex) * 2;
17497
17504
  const arrival = this.stopTimes[arrivalIndex];
17498
17505
  if (arrival === undefined) {
17499
- throw new Error(`Arrival time not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
17506
+ throw new Error(`Arrival time not found for stop ${this.stopId(stopIndex)} (${stopIndex}) at trip index ${tripIndex} in route ${this.serviceRouteId}`);
17500
17507
  }
17501
17508
  return Time.fromMinutes(arrival);
17502
17509
  }
17503
17510
  /**
17504
17511
  * Retrieves the departure time at a specific stop for a given trip.
17505
17512
  *
17506
- * @param stopId - The identifier of the stop.
17513
+ * @param stopIndex - The index of the stop in the route.
17507
17514
  * @param tripIndex - The index of the trip.
17508
17515
  * @returns The departure time at the specified stop and trip as a Time object.
17509
17516
  */
17510
- departureFrom(stopId, tripIndex) {
17511
- const departureIndex = (tripIndex * this.stops.length + this.stopRouteIndex(stopId)) * 2 + 1;
17517
+ departureFrom(stopIndex, tripIndex) {
17518
+ const departureIndex = (tripIndex * this.stops.length + stopIndex) * 2 + 1;
17512
17519
  const departure = this.stopTimes[departureIndex];
17513
17520
  if (departure === undefined) {
17514
- throw new Error(`Departure time not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
17521
+ throw new Error(`Departure time not found for stop ${this.stopId(stopIndex)} (${stopIndex}) at trip index ${tripIndex} in route ${this.serviceRouteId}`);
17515
17522
  }
17516
17523
  return Time.fromMinutes(departure);
17517
17524
  }
17518
17525
  /**
17519
17526
  * Retrieves the pick-up type for a specific stop and trip.
17520
17527
  *
17521
- * @param stopId - The identifier of the stop.
17528
+ * @param stopIndex - The index of the stop in the route.
17522
17529
  * @param tripIndex - The index of the trip.
17523
17530
  * @returns The pick-up type at the specified stop and trip.
17524
17531
  */
17525
- pickUpTypeFrom(stopId, tripIndex) {
17526
- const globalIndex = tripIndex * this.stops.length + this.stopRouteIndex(stopId);
17532
+ pickUpTypeFrom(stopIndex, tripIndex) {
17533
+ const globalIndex = tripIndex * this.stops.length + stopIndex;
17527
17534
  const byteIndex = Math.floor(globalIndex / 2);
17528
17535
  const isSecondPair = globalIndex % 2 === 1;
17529
17536
  const byte = this.pickUpDropOffTypes[byteIndex];
17530
17537
  if (byte === undefined) {
17531
- throw new Error(`Pick up type not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
17538
+ throw new Error(`Pick up type not found for stop ${this.stopId(stopIndex)} (${stopIndex}) at trip index ${tripIndex} in route ${this.serviceRouteId}`);
17532
17539
  }
17533
17540
  const pickUpValue = isSecondPair
17534
17541
  ? (byte >> 6) & 0x03 // Upper 2 bits for second pair
@@ -17538,17 +17545,17 @@ let Route$1 = class Route {
17538
17545
  /**
17539
17546
  * Retrieves the drop-off type for a specific stop and trip.
17540
17547
  *
17541
- * @param stopId - The identifier of the stop.
17548
+ * @param stopIndex - The index of the stop in the route.
17542
17549
  * @param tripIndex - The index of the trip.
17543
17550
  * @returns The drop-off type at the specified stop and trip.
17544
17551
  */
17545
- dropOffTypeAt(stopId, tripIndex) {
17546
- const globalIndex = tripIndex * this.stops.length + this.stopRouteIndex(stopId);
17552
+ dropOffTypeAt(stopIndex, tripIndex) {
17553
+ const globalIndex = tripIndex * this.stops.length + stopIndex;
17547
17554
  const byteIndex = Math.floor(globalIndex / 2);
17548
17555
  const isSecondPair = globalIndex % 2 === 1;
17549
17556
  const byte = this.pickUpDropOffTypes[byteIndex];
17550
17557
  if (byte === undefined) {
17551
- throw new Error(`Drop off type not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
17558
+ throw new Error(`Drop off type not found for stop ${this.stopId(stopIndex)} (${stopIndex}) at trip index ${tripIndex} in route ${this.serviceRouteId}`);
17552
17559
  }
17553
17560
  const dropOffValue = isSecondPair
17554
17561
  ? (byte >> 4) & 0x03 // Bits 4-5 for second pair
@@ -17560,14 +17567,14 @@ let Route$1 = class Route {
17560
17567
  * optionally constrained by a latest trip index and a time before which the trip
17561
17568
  * should not depart.
17562
17569
  * *
17563
- * @param stopId - The StopId of the stop where the trip should be found.
17570
+ * @param stopIndex - The route index of the stop where the trip should be found.
17564
17571
  * @param [after=Time.origin()] - The earliest time after which the trip should depart.
17565
17572
  * If not provided, searches all available trips.
17566
17573
  * @param [beforeTrip] - (Optional) The index of the trip before which the search should be constrained.
17567
17574
  * If not provided, searches all available trips.
17568
17575
  * @returns The index of the earliest trip meeting the criteria, or undefined if no such trip is found.
17569
17576
  */
17570
- findEarliestTrip(stopId, after = Time.origin(), beforeTrip) {
17577
+ findEarliestTrip(stopIndex, after = Time.origin(), beforeTrip) {
17571
17578
  if (this.nbTrips <= 0)
17572
17579
  return undefined;
17573
17580
  let hi = this.nbTrips - 1;
@@ -17579,7 +17586,7 @@ let Route$1 = class Route {
17579
17586
  let lb = -1;
17580
17587
  while (lo <= hi) {
17581
17588
  const mid = (lo + hi) >>> 1;
17582
- const depMid = this.departureFrom(stopId, mid);
17589
+ const depMid = this.departureFrom(stopIndex, mid);
17583
17590
  if (depMid.isBefore(after)) {
17584
17591
  lo = mid + 1;
17585
17592
  }
@@ -17590,8 +17597,8 @@ let Route$1 = class Route {
17590
17597
  }
17591
17598
  if (lb === -1)
17592
17599
  return undefined;
17593
- for (let t = lb; t < (beforeTrip !== null && beforeTrip !== void 0 ? beforeTrip : this.nbTrips); t++) {
17594
- const pickup = this.pickUpTypeFrom(stopId, t);
17600
+ for (let t = lb; t < (beforeTrip ?? this.nbTrips); t++) {
17601
+ const pickup = this.pickUpTypeFrom(stopIndex, t);
17595
17602
  if (pickup !== 'NOT_AVAILABLE') {
17596
17603
  return t;
17597
17604
  }
@@ -17599,14 +17606,14 @@ let Route$1 = class Route {
17599
17606
  return undefined;
17600
17607
  }
17601
17608
  /**
17602
- * Retrieves the index of a stop within the route.
17609
+ * Retrieves the indices of a stop within the route.
17603
17610
  * @param stopId The StopId of the stop to locate in the route.
17604
- * @returns The index of the stop in the route.
17611
+ * @returns An array of indices where the stop appears in the route, or an empty array if the stop is not found.
17605
17612
  */
17606
- stopRouteIndex(stopId) {
17613
+ stopRouteIndices(stopId) {
17607
17614
  const stopIndex = this.stopIndices.get(stopId);
17608
17615
  if (stopIndex === undefined) {
17609
- throw new Error(`Stop index for ${stopId} not found in route ${this.serviceRouteId}`);
17616
+ return [];
17610
17617
  }
17611
17618
  return stopIndex;
17612
17619
  }
@@ -17624,6 +17631,51 @@ let Route$1 = class Route {
17624
17631
  }
17625
17632
  };
17626
17633
 
17634
+ // Each value uses 20 bits, allowing values from 0 to 1,048,575 (2^20 - 1)
17635
+ const VALUE_MASK = (1n << 20n) - 1n; // 0xFFFFF
17636
+ const MAX_VALUE = 1_048_575; // 2^20 - 1
17637
+ // Bit positions for each value in the 60-bit bigint
17638
+ const TRIP_INDEX_SHIFT = 0n;
17639
+ const ROUTE_ID_SHIFT = 20n;
17640
+ const STOP_INDEX_SHIFT = 40n;
17641
+ /**
17642
+ * Validates that a value fits within 20 bits (0 to 1,048,575)
17643
+ * @param value - The value to validate
17644
+ * @param name - The name of the value for error reporting
17645
+ * @throws Error if the value is out of range
17646
+ */
17647
+ const validateValue = (value, name) => {
17648
+ if (value < 0 || value > MAX_VALUE) {
17649
+ throw new Error(`${name} must be between 0 and ${MAX_VALUE}, got ${value}`);
17650
+ }
17651
+ };
17652
+ /**
17653
+ * Encodes a stop index, route ID, and trip index into a single trip boarding ID.
17654
+ * @param stopIndex - The index of the stop within the route (0 to 1,048,575)
17655
+ * @param routeId - The route identifier (0 to 1,048,575)
17656
+ * @param tripIndex - The index of the trip within the route (0 to 1,048,575)
17657
+ * @returns The encoded trip ID as a bigint
17658
+ */
17659
+ const encode = (stopIndex, routeId, tripIndex) => {
17660
+ validateValue(stopIndex, 'stopIndex');
17661
+ validateValue(routeId, 'routeId');
17662
+ validateValue(tripIndex, 'tripIndex');
17663
+ return ((BigInt(stopIndex) << STOP_INDEX_SHIFT) |
17664
+ (BigInt(routeId) << ROUTE_ID_SHIFT) |
17665
+ (BigInt(tripIndex) << TRIP_INDEX_SHIFT));
17666
+ };
17667
+ /**
17668
+ * Decodes a trip boarding ID back into its constituent stop index, route ID, and trip index.
17669
+ * @param tripBoardingId - The encoded trip ID
17670
+ * @returns A tuple containing [stopIndex, routeId, tripIndex]
17671
+ */
17672
+ const decode = (tripBoardingId) => {
17673
+ const stopIndex = Number((tripBoardingId >> STOP_INDEX_SHIFT) & VALUE_MASK);
17674
+ const routeId = Number((tripBoardingId >> ROUTE_ID_SHIFT) & VALUE_MASK);
17675
+ const tripIndex = Number((tripBoardingId >> TRIP_INDEX_SHIFT) & VALUE_MASK);
17676
+ return [stopIndex, routeId, tripIndex];
17677
+ };
17678
+
17627
17679
  const isLittleEndian = (() => {
17628
17680
  const buffer = new ArrayBuffer(4);
17629
17681
  const view = new DataView(buffer);
@@ -17693,14 +17745,15 @@ const serializeStopsAdjacency = (stopsAdjacency) => {
17693
17745
  return stopsAdjacency.map((value) => {
17694
17746
  return {
17695
17747
  transfers: value.transfers
17696
- ? value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: serializeTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
17697
- minTransferTime: transfer.minTransferTime.toSeconds(),
17698
- }))))
17748
+ ? value.transfers.map((transfer) => ({
17749
+ destination: transfer.destination,
17750
+ type: serializeTransferType(transfer.type),
17751
+ ...(transfer.minTransferTime !== undefined && {
17752
+ minTransferTime: transfer.minTransferTime.toSeconds(),
17753
+ }),
17754
+ }))
17699
17755
  : [],
17700
17756
  routes: value.routes,
17701
- tripContinuations: value.tripContinuations
17702
- ? serializeTripContinuations(value.tripContinuations)
17703
- : [],
17704
17757
  };
17705
17758
  });
17706
17759
  };
@@ -17735,9 +17788,13 @@ const deserializeStopsAdjacency = (protoStopsAdjacency) => {
17735
17788
  for (let j = 0; j < value.transfers.length; j++) {
17736
17789
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
17737
17790
  const transfer = value.transfers[j];
17738
- const newTransfer = Object.assign({ destination: transfer.destination, type: parseTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
17739
- minTransferTime: Duration.fromSeconds(transfer.minTransferTime),
17740
- }));
17791
+ const newTransfer = {
17792
+ destination: transfer.destination,
17793
+ type: parseTransferType(transfer.type),
17794
+ ...(transfer.minTransferTime !== undefined && {
17795
+ minTransferTime: Duration.fromSeconds(transfer.minTransferTime),
17796
+ }),
17797
+ };
17741
17798
  transfers.push(newTransfer);
17742
17799
  }
17743
17800
  const stopAdjacency = {
@@ -17746,10 +17803,6 @@ const deserializeStopsAdjacency = (protoStopsAdjacency) => {
17746
17803
  if (transfers.length > 0) {
17747
17804
  stopAdjacency.transfers = transfers;
17748
17805
  }
17749
- const deserializedTripContinuations = deserializeTripContinuations(value.tripContinuations);
17750
- if (deserializedTripContinuations.size > 0) {
17751
- stopAdjacency.tripContinuations = deserializedTripContinuations;
17752
- }
17753
17806
  result.push(stopAdjacency);
17754
17807
  }
17755
17808
  return result;
@@ -17856,11 +17909,14 @@ const serializeRouteType = (type) => {
17856
17909
  };
17857
17910
  const serializeTripContinuations = (tripContinuations) => {
17858
17911
  const result = [];
17859
- for (const [key, value] of tripContinuations.entries()) {
17912
+ for (const [tripBoardingId, boardings] of tripContinuations.entries()) {
17913
+ const [originStopIndex, originRouteId, originTripIndex] = decode(tripBoardingId);
17860
17914
  result.push({
17861
- key: key,
17862
- value: value.map((tripBoarding) => ({
17863
- hopOnStop: tripBoarding.hopOnStop,
17915
+ originStopIndex,
17916
+ originRouteId,
17917
+ originTripIndex,
17918
+ continuations: boardings.map((tripBoarding) => ({
17919
+ hopOnStopIndex: tripBoarding.hopOnStopIndex,
17864
17920
  routeId: tripBoarding.routeId,
17865
17921
  tripIndex: tripBoarding.tripIndex,
17866
17922
  })),
@@ -17873,28 +17929,17 @@ const deserializeTripContinuations = (protoTripContinuations) => {
17873
17929
  for (let i = 0; i < protoTripContinuations.length; i++) {
17874
17930
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
17875
17931
  const entry = protoTripContinuations[i];
17876
- const tripBoardings = entry.value.map((protoTripBoarding) => ({
17877
- hopOnStop: protoTripBoarding.hopOnStop,
17932
+ const tripBoardingId = encode(entry.originStopIndex, entry.originRouteId, entry.originTripIndex);
17933
+ const tripBoardings = entry.continuations.map((protoTripBoarding) => ({
17934
+ hopOnStopIndex: protoTripBoarding.hopOnStopIndex,
17878
17935
  routeId: protoTripBoarding.routeId,
17879
17936
  tripIndex: protoTripBoarding.tripIndex,
17880
17937
  }));
17881
- result.set(entry.key, tripBoardings);
17938
+ result.set(tripBoardingId, tripBoardings);
17882
17939
  }
17883
17940
  return result;
17884
17941
  };
17885
17942
 
17886
- // const ROUTE_ID_BITS = 17;
17887
- const TRIP_INDEX_BITS = 15;
17888
- /**
17889
- * Encodes a route ID and trip index into a single trip ID.
17890
- * @param routeId - The route identifier, needs to fit on 17 bits
17891
- * @param tripIndex - The index of the trip within the route, needs to fit on 15 bits
17892
- * @returns The encoded trip ID
17893
- */
17894
- const encode = (routeId, tripIndex) => {
17895
- return (routeId << TRIP_INDEX_BITS) | tripIndex;
17896
- };
17897
-
17898
17943
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
17899
17944
  const ALL_TRANSPORT_MODES = new Set([
17900
17945
  'TRAM',
@@ -17909,21 +17954,26 @@ const ALL_TRANSPORT_MODES = new Set([
17909
17954
  'MONORAIL',
17910
17955
  ]);
17911
17956
  const EMPTY_TRIP_CONTINUATIONS = [];
17912
- const CURRENT_VERSION = '0.0.8';
17957
+ const CURRENT_VERSION = '0.0.9';
17913
17958
  /**
17914
17959
  * The internal transit timetable format.
17915
17960
  */
17916
17961
  class Timetable {
17917
- constructor(stopsAdjacency, routesAdjacency, routes) {
17962
+ stopsAdjacency;
17963
+ routesAdjacency;
17964
+ serviceRoutes;
17965
+ tripContinuations;
17966
+ activeStops;
17967
+ constructor(stopsAdjacency, routesAdjacency, routes, tripContinuations) {
17918
17968
  this.stopsAdjacency = stopsAdjacency;
17919
17969
  this.routesAdjacency = routesAdjacency;
17920
17970
  this.serviceRoutes = routes;
17971
+ this.tripContinuations = tripContinuations;
17921
17972
  this.activeStops = new Set();
17922
17973
  for (let i = 0; i < stopsAdjacency.length; i++) {
17923
17974
  const stop = stopsAdjacency[i];
17924
17975
  if (stop.routes.length > 0 ||
17925
- (stop.transfers && stop.transfers.length > 0) ||
17926
- (stop.tripContinuations && stop.tripContinuations.size > 0)) {
17976
+ (stop.transfers && stop.transfers.length > 0)) {
17927
17977
  this.activeStops.add(i);
17928
17978
  }
17929
17979
  }
@@ -17939,6 +17989,7 @@ class Timetable {
17939
17989
  stopsAdjacency: serializeStopsAdjacency(this.stopsAdjacency),
17940
17990
  routesAdjacency: serializeRoutesAdjacency(this.routesAdjacency),
17941
17991
  serviceRoutes: serializeServiceRoutesMap(this.serviceRoutes),
17992
+ tripContinuations: serializeTripContinuations(this.tripContinuations || new Map()),
17942
17993
  };
17943
17994
  const writer = new BinaryWriter();
17944
17995
  Timetable$1.encode(protoTimetable, writer);
@@ -17956,7 +18007,7 @@ class Timetable {
17956
18007
  if (protoTimetable.version !== CURRENT_VERSION) {
17957
18008
  throw new Error(`Unsupported timetable version ${protoTimetable.version}`);
17958
18009
  }
17959
- return new Timetable(deserializeStopsAdjacency(protoTimetable.stopsAdjacency), deserializeRoutesAdjacency(protoTimetable.routesAdjacency), deserializeServiceRoutesMap(protoTimetable.serviceRoutes));
18010
+ return new Timetable(deserializeStopsAdjacency(protoTimetable.stopsAdjacency), deserializeRoutesAdjacency(protoTimetable.routesAdjacency), deserializeServiceRoutesMap(protoTimetable.serviceRoutes), deserializeTripContinuations(protoTimetable.tripContinuations));
17960
18011
  }
17961
18012
  /**
17962
18013
  * Checks if the given stop is active on the timetable.
@@ -17995,18 +18046,17 @@ class Timetable {
17995
18046
  /**
17996
18047
  * Retrieves all trip continuation options available at the specified stop for a given trip.
17997
18048
  *
17998
- * @param stopId - The ID of the stop to get trip continuations for.
18049
+ * @param stopIndex - The index in the route of the stop to get trip continuations for.
18050
+ * @param routeId - The ID of the route to get continuations for.
17999
18051
  * @param tripIndex - The index of the trip to get continuations for.
18000
18052
  * @returns An array of trip continuation options available at the stop for the specified trip.
18001
18053
  */
18002
- getContinuousTrips(stopId, routeId, tripIndex) {
18003
- var _a;
18004
- const stopAdjacency = this.stopsAdjacency[stopId];
18005
- if (!stopAdjacency) {
18006
- throw new Error(`Stop ID ${stopId} not found`);
18054
+ getContinuousTrips(stopIndex, routeId, tripIndex) {
18055
+ const tripContinuations = this.tripContinuations?.get(encode(stopIndex, routeId, tripIndex));
18056
+ if (!tripContinuations) {
18057
+ return EMPTY_TRIP_CONTINUATIONS;
18007
18058
  }
18008
- return (((_a = stopAdjacency.tripContinuations) === null || _a === void 0 ? void 0 : _a.get(encode(routeId, tripIndex))) ||
18009
- EMPTY_TRIP_CONTINUATIONS);
18059
+ return tripContinuations;
18010
18060
  }
18011
18061
  /**
18012
18062
  * Retrieves the service route associated with the given route.
@@ -18046,12 +18096,12 @@ class Timetable {
18046
18096
  }
18047
18097
  /**
18048
18098
  * Finds routes that are reachable from a set of stop IDs.
18049
- * Also identifies the first stop available to hop on each route among
18099
+ * Also identifies the first stop index available to hop on each route among
18050
18100
  * the input stops.
18051
18101
  *
18052
18102
  * @param fromStops - The set of stop IDs to find reachable routes from.
18053
18103
  * @param transportModes - The set of transport modes to consider for reachable routes.
18054
- * @returns A map of reachable routes to the first stop available to hop on each route.
18104
+ * @returns A map of reachable routes to the first stop index available to hop on each route.
18055
18105
  */
18056
18106
  findReachableRoutes(fromStops, transportModes = ALL_TRANSPORT_MODES) {
18057
18107
  const reachableRoutes = new Map();
@@ -18064,15 +18114,17 @@ class Timetable {
18064
18114
  });
18065
18115
  for (let j = 0; j < validRoutes.length; j++) {
18066
18116
  const route = validRoutes[j];
18067
- const hopOnStop = reachableRoutes.get(route);
18068
- if (hopOnStop) {
18069
- if (route.isBefore(originStop, hopOnStop)) {
18117
+ const originStopIndices = route.stopRouteIndices(originStop);
18118
+ const originStopIndex = originStopIndices[0];
18119
+ const existingHopOnStopIndex = reachableRoutes.get(route);
18120
+ if (existingHopOnStopIndex !== undefined) {
18121
+ if (originStopIndex < existingHopOnStopIndex) {
18070
18122
  // if the current stop is before the existing hop on stop, replace it
18071
- reachableRoutes.set(route, originStop);
18123
+ reachableRoutes.set(route, originStopIndex);
18072
18124
  }
18073
18125
  }
18074
18126
  else {
18075
- reachableRoutes.set(route, originStop);
18127
+ reachableRoutes.set(route, originStopIndex);
18076
18128
  }
18077
18129
  }
18078
18130
  }
@@ -20048,35 +20100,22 @@ const parseCsv = (stream, numericColumns = []) => {
20048
20100
  * @param profile A configuration object defining the specificities of the GTFS feed.
20049
20101
  * @returns A map of all the valid routes.
20050
20102
  */
20051
- const parseRoutes = (routesStream_1, ...args_1) => __awaiter(void 0, [routesStream_1, ...args_1], void 0, function* (routesStream, profile = standardProfile) {
20052
- var _a, e_1, _b, _c;
20103
+ const parseRoutes = async (routesStream, profile = standardProfile) => {
20053
20104
  const routes = new Map();
20054
- try {
20055
- for (var _d = true, _e = __asyncValues(parseCsv(routesStream, ['route_type'])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
20056
- _c = _f.value;
20057
- _d = false;
20058
- const rawLine = _c;
20059
- const line = rawLine;
20060
- const routeType = profile.routeTypeParser(line.route_type);
20061
- if (routeType === undefined) {
20062
- log.info(`Unsupported route type ${line.route_type} for route ${line.route_id}.`);
20063
- continue;
20064
- }
20065
- routes.set(line.route_id, {
20066
- name: line.route_short_name,
20067
- type: routeType,
20068
- });
20069
- }
20070
- }
20071
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
20072
- finally {
20073
- try {
20074
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
20105
+ for await (const rawLine of parseCsv(routesStream, ['route_type'])) {
20106
+ const line = rawLine;
20107
+ const routeType = profile.routeTypeParser(line.route_type);
20108
+ if (routeType === undefined) {
20109
+ log.info(`Unsupported route type ${line.route_type} for route ${line.route_id}.`);
20110
+ continue;
20075
20111
  }
20076
- finally { if (e_1) throw e_1.error; }
20112
+ routes.set(line.route_id, {
20113
+ name: line.route_short_name,
20114
+ type: routeType,
20115
+ });
20077
20116
  }
20078
20117
  return routes;
20079
- });
20118
+ };
20080
20119
  /**
20081
20120
  * Creates an array of ServiceRoute objects by combining GTFS route data with service route mappings.
20082
20121
  *
@@ -20139,46 +20178,33 @@ const weekdays = {
20139
20178
  * @param date The active date.
20140
20179
  * @param calendarStream A readable stream for the GTFS calendar.txt file.
20141
20180
  */
20142
- const parseCalendar = (calendarStream, serviceIds, date) => __awaiter(void 0, void 0, void 0, function* () {
20143
- var _a, e_1, _b, _c;
20181
+ const parseCalendar = async (calendarStream, serviceIds, date) => {
20144
20182
  const activeDate = toGtfsDate(date);
20145
20183
  const weekday = date.weekday;
20146
20184
  const weekdayIndex = weekdays[weekday];
20147
- try {
20148
- for (var _d = true, _e = __asyncValues(parseCsv(calendarStream, [
20149
- 'monday',
20150
- 'tuesday',
20151
- 'wednesday',
20152
- 'thursday',
20153
- 'friday',
20154
- 'saturday',
20155
- 'sunday',
20156
- 'start_date',
20157
- 'end_date',
20158
- ])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
20159
- _c = _f.value;
20160
- _d = false;
20161
- const rawLine = _c;
20162
- const line = rawLine;
20163
- if (activeDate < line.start_date || activeDate > line.end_date) {
20164
- // If the service is not valid on this date
20165
- continue;
20166
- }
20167
- if (line[weekdayIndex] !== 1) {
20168
- // If the service is not valid on this week day
20169
- continue;
20170
- }
20171
- serviceIds.add(line['service_id']);
20185
+ for await (const rawLine of parseCsv(calendarStream, [
20186
+ 'monday',
20187
+ 'tuesday',
20188
+ 'wednesday',
20189
+ 'thursday',
20190
+ 'friday',
20191
+ 'saturday',
20192
+ 'sunday',
20193
+ 'start_date',
20194
+ 'end_date',
20195
+ ])) {
20196
+ const line = rawLine;
20197
+ if (activeDate < line.start_date || activeDate > line.end_date) {
20198
+ // If the service is not valid on this date
20199
+ continue;
20172
20200
  }
20173
- }
20174
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
20175
- finally {
20176
- try {
20177
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
20201
+ if (line[weekdayIndex] !== 1) {
20202
+ // If the service is not valid on this week day
20203
+ continue;
20178
20204
  }
20179
- finally { if (e_1) throw e_1.error; }
20205
+ serviceIds.add(line['service_id']);
20180
20206
  }
20181
- });
20207
+ };
20182
20208
  /**
20183
20209
  * Parses a gtfs calendar_dates.txt file and finds the service ids valid at a given date.
20184
20210
  *
@@ -20186,39 +20212,24 @@ const parseCalendar = (calendarStream, serviceIds, date) => __awaiter(void 0, vo
20186
20212
  * @param date The active date, in the format "YYYYMMDD".
20187
20213
  * @param calendarDatesStream A readable stream for the GTFS calendar_dates.txt file.
20188
20214
  */
20189
- const parseCalendarDates = (calendarDatesStream, serviceIds, date) => __awaiter(void 0, void 0, void 0, function* () {
20190
- var _a, e_2, _b, _c;
20215
+ const parseCalendarDates = async (calendarDatesStream, serviceIds, date) => {
20191
20216
  const activeDate = toGtfsDate(date);
20192
- try {
20193
- for (var _d = true, _e = __asyncValues(parseCsv(calendarDatesStream, [
20194
- 'date',
20195
- 'exception_type',
20196
- ])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
20197
- _c = _f.value;
20198
- _d = false;
20199
- const rawLine = _c;
20200
- const line = rawLine;
20201
- if (line.date !== activeDate) {
20202
- // No rule on the active date
20203
- }
20204
- else if (line.exception_type === 2 && serviceIds.has(line.service_id)) {
20205
- // Service has been removed for the specified date.
20206
- serviceIds.delete(line.service_id);
20207
- }
20208
- else if (line.exception_type === 1) {
20209
- // Service is present on the active date
20210
- serviceIds.add(line.service_id);
20211
- }
20217
+ for await (const rawLine of parseCsv(calendarDatesStream, [
20218
+ 'date',
20219
+ 'exception_type',
20220
+ ])) {
20221
+ const line = rawLine;
20222
+ if (line.date !== activeDate) ;
20223
+ else if (line.exception_type === 2 && serviceIds.has(line.service_id)) {
20224
+ // Service has been removed for the specified date.
20225
+ serviceIds.delete(line.service_id);
20212
20226
  }
20213
- }
20214
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
20215
- finally {
20216
- try {
20217
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
20227
+ else if (line.exception_type === 1) {
20228
+ // Service is present on the active date
20229
+ serviceIds.add(line.service_id);
20218
20230
  }
20219
- finally { if (e_2) throw e_2.error; }
20220
20231
  }
20221
- });
20232
+ };
20222
20233
 
20223
20234
  /**
20224
20235
  * Parses the stops.txt file from a GTFS feed.
@@ -20226,33 +20237,30 @@ const parseCalendarDates = (calendarDatesStream, serviceIds, date) => __awaiter(
20226
20237
  * @param stopsStream The readable stream containing the stops data.
20227
20238
  * @return A mapping of stop IDs to corresponding stop details.
20228
20239
  */
20229
- const parseStops = (stopsStream) => __awaiter(void 0, void 0, void 0, function* () {
20230
- var _a, e_1, _b, _c;
20240
+ const parseStops = async (stopsStream) => {
20231
20241
  const parsedStops = new Map();
20232
20242
  let i = 0;
20233
- try {
20234
- for (var _d = true, _e = __asyncValues(parseCsv(stopsStream, [
20235
- 'stop_lat',
20236
- 'stop_lon',
20237
- 'location_type',
20238
- ])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
20239
- _c = _f.value;
20240
- _d = false;
20241
- const rawLine = _c;
20242
- const line = rawLine;
20243
- 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
20244
- ? parseGtfsLocationType(line.location_type)
20245
- : 'SIMPLE_STOP_OR_PLATFORM' }, (line.platform_code && { platform: line.platform_code })), { children: [] }), (line.parent_station && { parentSourceId: line.parent_station }));
20246
- parsedStops.set(line.stop_id, stop);
20247
- i = i + 1;
20248
- }
20249
- }
20250
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
20251
- finally {
20252
- try {
20253
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
20254
- }
20255
- finally { if (e_1) throw e_1.error; }
20243
+ for await (const rawLine of parseCsv(stopsStream, [
20244
+ 'stop_lat',
20245
+ 'stop_lon',
20246
+ 'location_type',
20247
+ ])) {
20248
+ const line = rawLine;
20249
+ const stop = {
20250
+ id: i,
20251
+ sourceStopId: line.stop_id,
20252
+ name: line.stop_name,
20253
+ lat: line.stop_lat,
20254
+ lon: line.stop_lon,
20255
+ locationType: line.location_type
20256
+ ? parseGtfsLocationType(line.location_type)
20257
+ : 'SIMPLE_STOP_OR_PLATFORM',
20258
+ ...(line.platform_code && { platform: line.platform_code }),
20259
+ children: [],
20260
+ ...(line.parent_station && { parentSourceId: line.parent_station }),
20261
+ };
20262
+ parsedStops.set(line.stop_id, stop);
20263
+ i = i + 1;
20256
20264
  }
20257
20265
  for (const [sourceStopId, stop] of parsedStops) {
20258
20266
  if (stop.parentSourceId) {
@@ -20266,7 +20274,7 @@ const parseStops = (stopsStream) => __awaiter(void 0, void 0, void 0, function*
20266
20274
  }
20267
20275
  }
20268
20276
  return parsedStops;
20269
- });
20277
+ };
20270
20278
  const parseGtfsLocationType = (gtfsLocationType) => {
20271
20279
  switch (gtfsLocationType) {
20272
20280
  case 0:
@@ -20289,85 +20297,158 @@ const parseGtfsLocationType = (gtfsLocationType) => {
20289
20297
  * @param stopsStream The readable stream containing the stops data.
20290
20298
  * @return A mapping of stop IDs to corresponding stop details.
20291
20299
  */
20292
- const parseTransfers = (transfersStream, stopsMap) => __awaiter(void 0, void 0, void 0, function* () {
20293
- var _a, e_1, _b, _c;
20300
+ const parseTransfers = async (transfersStream, stopsMap) => {
20294
20301
  const transfers = new Map();
20295
- const tripContinuations = new Map();
20296
- try {
20297
- for (var _d = true, _e = __asyncValues(parseCsv(transfersStream, [
20298
- 'transfer_type',
20299
- 'min_transfer_time',
20300
- ])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
20301
- _c = _f.value;
20302
- _d = false;
20303
- const rawLine = _c;
20304
- const transferEntry = rawLine;
20305
- if (transferEntry.transfer_type === 3 ||
20306
- transferEntry.transfer_type === 5) {
20307
- continue;
20308
- }
20309
- if (!transferEntry.from_stop_id || !transferEntry.to_stop_id) {
20310
- console.warn(`Missing transfer origin or destination stop.`);
20311
- continue;
20312
- }
20313
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
20314
- const fromStop = stopsMap.get(transferEntry.from_stop_id);
20315
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
20316
- const toStop = stopsMap.get(transferEntry.to_stop_id);
20317
- if (transferEntry.transfer_type === 4) {
20318
- if (transferEntry.from_trip_id === undefined ||
20319
- transferEntry.from_trip_id === '' ||
20320
- transferEntry.to_trip_id === undefined ||
20321
- transferEntry.to_trip_id === '') {
20322
- console.warn(`Unsupported in-seat transfer, missing from_trip_id and/or to_trip_id.`);
20323
- continue;
20324
- }
20325
- const tripBoardingEntry = {
20326
- fromTrip: transferEntry.from_trip_id,
20327
- toTrip: transferEntry.to_trip_id,
20328
- hopOnStop: toStop.id,
20329
- };
20330
- const existingBoardings = tripContinuations.get(fromStop.id);
20331
- if (existingBoardings) {
20332
- existingBoardings.push(tripBoardingEntry);
20333
- }
20334
- else {
20335
- tripContinuations.set(fromStop.id, [tripBoardingEntry]);
20336
- }
20337
- continue;
20338
- }
20339
- if (transferEntry.from_trip_id && transferEntry.to_trip_id) {
20340
- console.warn(`Unsupported transfer of type ${transferEntry.transfer_type} between trips ${transferEntry.from_trip_id} and ${transferEntry.to_trip_id}.`);
20341
- continue;
20342
- }
20343
- if (transferEntry.from_route_id && transferEntry.to_route_id) {
20344
- console.warn(`Unsupported transfer of type ${transferEntry.transfer_type} between routes ${transferEntry.from_route_id} and ${transferEntry.to_route_id}.`);
20302
+ const tripContinuations = [];
20303
+ for await (const rawLine of parseCsv(transfersStream, [
20304
+ 'transfer_type',
20305
+ 'min_transfer_time',
20306
+ ])) {
20307
+ const transferEntry = rawLine;
20308
+ if (transferEntry.transfer_type === 3 ||
20309
+ transferEntry.transfer_type === 5) {
20310
+ continue;
20311
+ }
20312
+ if (!transferEntry.from_stop_id || !transferEntry.to_stop_id) {
20313
+ console.warn(`Missing transfer origin or destination stop.`);
20314
+ continue;
20315
+ }
20316
+ const fromStop = stopsMap.get(transferEntry.from_stop_id);
20317
+ const toStop = stopsMap.get(transferEntry.to_stop_id);
20318
+ if (!fromStop || !toStop) {
20319
+ console.warn(`Transfer references non-existent stop(s): from_stop_id=${transferEntry.from_stop_id}, to_stop_id=${transferEntry.to_stop_id}`);
20320
+ continue;
20321
+ }
20322
+ if (transferEntry.transfer_type === 4) {
20323
+ if (transferEntry.from_trip_id === undefined ||
20324
+ transferEntry.from_trip_id === '' ||
20325
+ transferEntry.to_trip_id === undefined ||
20326
+ transferEntry.to_trip_id === '') {
20327
+ console.warn(`Unsupported in-seat transfer, missing from_trip_id and/or to_trip_id.`);
20345
20328
  continue;
20346
20329
  }
20347
- if (transferEntry.transfer_type === 2 &&
20348
- transferEntry.min_transfer_time === undefined) {
20349
- console.info(`Missing minimum transfer time between ${transferEntry.from_stop_id} and ${transferEntry.to_stop_id}.`);
20350
- }
20351
- const transfer = Object.assign({ destination: toStop.id, type: parseGtfsTransferType(transferEntry.transfer_type) }, (transferEntry.min_transfer_time && {
20352
- minTransferTime: Duration.fromSeconds(transferEntry.min_transfer_time),
20353
- }));
20354
- const fromStopTransfers = transfers.get(fromStop.id) || [];
20355
- fromStopTransfers.push(transfer);
20356
- transfers.set(fromStop.id, fromStopTransfers);
20330
+ const tripBoardingEntry = {
20331
+ fromStop: fromStop.id,
20332
+ fromTrip: transferEntry.from_trip_id,
20333
+ toStop: toStop.id,
20334
+ toTrip: transferEntry.to_trip_id,
20335
+ };
20336
+ tripContinuations.push(tripBoardingEntry);
20337
+ continue;
20357
20338
  }
20358
- }
20359
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
20360
- finally {
20361
- try {
20362
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
20339
+ if (transferEntry.from_trip_id && transferEntry.to_trip_id) {
20340
+ console.warn(`Unsupported transfer of type ${transferEntry.transfer_type} between trips ${transferEntry.from_trip_id} and ${transferEntry.to_trip_id}.`);
20341
+ continue;
20363
20342
  }
20364
- finally { if (e_1) throw e_1.error; }
20343
+ if (transferEntry.from_route_id && transferEntry.to_route_id) {
20344
+ console.warn(`Unsupported transfer of type ${transferEntry.transfer_type} between routes ${transferEntry.from_route_id} and ${transferEntry.to_route_id}.`);
20345
+ continue;
20346
+ }
20347
+ if (transferEntry.transfer_type === 2 &&
20348
+ transferEntry.min_transfer_time === undefined) {
20349
+ console.info(`Missing minimum transfer time between ${transferEntry.from_stop_id} and ${transferEntry.to_stop_id}.`);
20350
+ }
20351
+ const transfer = {
20352
+ destination: toStop.id,
20353
+ type: parseGtfsTransferType(transferEntry.transfer_type),
20354
+ ...(transferEntry.min_transfer_time !== undefined && {
20355
+ minTransferTime: Duration.fromSeconds(transferEntry.min_transfer_time),
20356
+ }),
20357
+ };
20358
+ const fromStopTransfers = transfers.get(fromStop.id) || [];
20359
+ fromStopTransfers.push(transfer);
20360
+ transfers.set(fromStop.id, fromStopTransfers);
20365
20361
  }
20366
20362
  return {
20367
20363
  transfers,
20368
20364
  tripContinuations,
20369
20365
  };
20370
- });
20366
+ };
20367
+ /**
20368
+ * Disambiguates stops involved in a transfer.
20369
+ *
20370
+ * The GTFS specification only refers to a stopId in the trip-to-trip transfers and not the
20371
+ * specific stop index in the route. For routes that have multiple stops with the same stopId,
20372
+ * we need to determine which are the from / to stop indices in respective routes.
20373
+ * We do so by picking the stop indices leading to the most coherent transfer.
20374
+ * (we pick the closest from stop index happening after the to stop index).
20375
+ */
20376
+ const disambiguateTransferStopsIndices = (fromStop, fromRoute, fromTripIndex, toStop, toRoute, toTripIndex) => {
20377
+ const fromStopIndices = fromRoute.stopRouteIndices(fromStop);
20378
+ const toStopIndices = toRoute.stopRouteIndices(toStop);
20379
+ let bestFromStopIndex;
20380
+ let bestToStopIndex;
20381
+ let bestTimeDifference = Infinity;
20382
+ for (const originStopIndex of fromStopIndices) {
20383
+ const fromArrivalTime = fromRoute.arrivalAt(originStopIndex, fromTripIndex);
20384
+ for (const toStopIndex of toStopIndices) {
20385
+ const toDepartureTime = toRoute.departureFrom(toStopIndex, toTripIndex);
20386
+ if (toDepartureTime.isAfter(fromArrivalTime)) {
20387
+ const timeDifference = toDepartureTime.toMinutes() - fromArrivalTime.toMinutes();
20388
+ if (timeDifference < bestTimeDifference) {
20389
+ bestTimeDifference = timeDifference;
20390
+ bestFromStopIndex = originStopIndex;
20391
+ bestToStopIndex = toStopIndex;
20392
+ }
20393
+ }
20394
+ }
20395
+ }
20396
+ if (bestFromStopIndex !== undefined && bestToStopIndex !== undefined) {
20397
+ return {
20398
+ fromStopIndex: bestFromStopIndex,
20399
+ toStopIndex: bestToStopIndex,
20400
+ };
20401
+ }
20402
+ return undefined;
20403
+ };
20404
+ /**
20405
+ * Builds trip continuations map from GTFS trip continuation data.
20406
+ *
20407
+ * This function processes GTFS in-seat transfer data and creates a mapping
20408
+ * from trip boarding IDs to continuation boarding information. It disambiguates
20409
+ * stop indices when routes have multiple stops with the same ID by finding
20410
+ * the most coherent transfer timing.
20411
+ *
20412
+ * @param tripsMapping Mapping from GTFS trip IDs to internal trip representations
20413
+ * @param tripContinuations Array of GTFS trip continuation data from transfers.txt
20414
+ * @param timetable The timetable containing route and timing information
20415
+ * @param activeStopIds Set of stop IDs that are active/enabled in the system
20416
+ * @returns A map from trip boarding IDs to arrays of continuation boarding options
20417
+ */
20418
+ const buildTripContinuations = (tripsMapping, tripContinuations, timetable, activeStopIds) => {
20419
+ const continuations = new Map();
20420
+ for (const gtfsContinuation of tripContinuations) {
20421
+ if (!activeStopIds.has(gtfsContinuation.fromStop) ||
20422
+ !activeStopIds.has(gtfsContinuation.toStop)) {
20423
+ continue;
20424
+ }
20425
+ const fromTripMapping = tripsMapping.get(gtfsContinuation.fromTrip);
20426
+ const toTripMapping = tripsMapping.get(gtfsContinuation.toTrip);
20427
+ if (!fromTripMapping || !toTripMapping) {
20428
+ continue;
20429
+ }
20430
+ const fromRoute = timetable.getRoute(fromTripMapping.routeId);
20431
+ const toRoute = timetable.getRoute(toTripMapping.routeId);
20432
+ if (!fromRoute || !toRoute) {
20433
+ continue;
20434
+ }
20435
+ const bestStopIndices = disambiguateTransferStopsIndices(gtfsContinuation.fromStop, fromRoute, fromTripMapping.tripRouteIndex, gtfsContinuation.toStop, toRoute, toTripMapping.tripRouteIndex);
20436
+ if (!bestStopIndices) {
20437
+ // No valid continuation found
20438
+ continue;
20439
+ }
20440
+ const tripBoardingId = encode(bestStopIndices.fromStopIndex, fromTripMapping.routeId, fromTripMapping.tripRouteIndex);
20441
+ const continuationBoarding = {
20442
+ hopOnStopIndex: bestStopIndices.toStopIndex,
20443
+ routeId: toTripMapping.routeId,
20444
+ tripIndex: toTripMapping.tripRouteIndex,
20445
+ };
20446
+ const existingContinuations = continuations.get(tripBoardingId) || [];
20447
+ existingContinuations.push(continuationBoarding);
20448
+ continuations.set(tripBoardingId, existingContinuations);
20449
+ }
20450
+ return continuations;
20451
+ };
20371
20452
  const parseGtfsTransferType = (gtfsTransferType) => {
20372
20453
  switch (gtfsTransferType) {
20373
20454
  case 0:
@@ -20475,36 +20556,23 @@ const finalizeRouteFromBuilder = (builder) => {
20475
20556
  * @param serviceRoutes A mapping of route IDs to route details.
20476
20557
  * @returns A mapping of trip IDs to corresponding route IDs.
20477
20558
  */
20478
- const parseTrips = (tripsStream, serviceIds, validGtfsRoutes) => __awaiter(void 0, void 0, void 0, function* () {
20479
- var _a, e_1, _b, _c;
20559
+ const parseTrips = async (tripsStream, serviceIds, validGtfsRoutes) => {
20480
20560
  const trips = new Map();
20481
- try {
20482
- for (var _d = true, _e = __asyncValues(parseCsv(tripsStream, ['stop_sequence'])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
20483
- _c = _f.value;
20484
- _d = false;
20485
- const rawLine = _c;
20486
- const line = rawLine;
20487
- if (!serviceIds.has(line.service_id)) {
20488
- // The trip doesn't correspond to an active service
20489
- continue;
20490
- }
20491
- if (!validGtfsRoutes.has(line.route_id)) {
20492
- // The trip doesn't correspond to a supported route
20493
- continue;
20494
- }
20495
- trips.set(line.trip_id, line.route_id);
20561
+ for await (const rawLine of parseCsv(tripsStream, ['stop_sequence'])) {
20562
+ const line = rawLine;
20563
+ if (!serviceIds.has(line.service_id)) {
20564
+ // The trip doesn't correspond to an active service
20565
+ continue;
20496
20566
  }
20497
- }
20498
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
20499
- finally {
20500
- try {
20501
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
20567
+ if (!validGtfsRoutes.has(line.route_id)) {
20568
+ // The trip doesn't correspond to a supported route
20569
+ continue;
20502
20570
  }
20503
- finally { if (e_1) throw e_1.error; }
20571
+ trips.set(line.trip_id, line.route_id);
20504
20572
  }
20505
20573
  return trips;
20506
- });
20507
- const buildStopsAdjacencyStructure = (tripsMapping, serviceRoutes, routes, transfersMap, tripContinuationsMap, nbStops, activeStops) => {
20574
+ };
20575
+ const buildStopsAdjacencyStructure = (serviceRoutes, routes, transfersMap, nbStops, activeStops) => {
20508
20576
  const stopsAdjacency = new Array(nbStops);
20509
20577
  for (let i = 0; i < nbStops; i++) {
20510
20578
  stopsAdjacency[i] = {
@@ -20544,40 +20612,6 @@ const buildStopsAdjacencyStructure = (tripsMapping, serviceRoutes, routes, trans
20544
20612
  }
20545
20613
  }
20546
20614
  }
20547
- for (const [stop, tripContinuations] of tripContinuationsMap) {
20548
- for (let i = 0; i < tripContinuations.length; i++) {
20549
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
20550
- const tripContinuation = tripContinuations[i];
20551
- if (activeStops.has(stop) ||
20552
- activeStops.has(tripContinuation.hopOnStop)) {
20553
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
20554
- const stopAdj = stopsAdjacency[stop];
20555
- if (!stopAdj.tripContinuations) {
20556
- stopAdj.tripContinuations = new Map();
20557
- }
20558
- const originTrip = tripsMapping.get(tripContinuation.fromTrip);
20559
- const destinationTrip = tripsMapping.get(tripContinuation.toTrip);
20560
- if (destinationTrip === undefined || originTrip === undefined) {
20561
- continue;
20562
- }
20563
- const tripBoarding = {
20564
- hopOnStop: tripContinuation.hopOnStop,
20565
- routeId: destinationTrip.routeId,
20566
- tripIndex: destinationTrip.tripRouteIndex,
20567
- };
20568
- const tripId = encode(originTrip.routeId, originTrip.tripRouteIndex);
20569
- const existingContinuations = stopAdj.tripContinuations.get(tripId);
20570
- if (existingContinuations) {
20571
- existingContinuations.push(tripBoarding);
20572
- }
20573
- else {
20574
- stopAdj.tripContinuations.set(tripId, [tripBoarding]);
20575
- }
20576
- activeStops.add(tripContinuation.hopOnStop);
20577
- activeStops.add(stop);
20578
- }
20579
- }
20580
- }
20581
20615
  return stopsAdjacency;
20582
20616
  };
20583
20617
  /**
@@ -20589,9 +20623,7 @@ const buildStopsAdjacencyStructure = (tripsMapping, serviceRoutes, routes, trans
20589
20623
  * @param activeStopIds A set of valid stop IDs.
20590
20624
  * @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.
20591
20625
  */
20592
- const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds) => __awaiter(void 0, void 0, void 0, function* () {
20593
- var _a, e_2, _b, _c;
20594
- var _d, _e;
20626
+ const parseStopTimes = async (stopTimesStream, stopsMap, activeTripIds, activeStopIds) => {
20595
20627
  /**
20596
20628
  * Adds a trip to the appropriate route builder
20597
20629
  */
@@ -20659,55 +20691,43 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
20659
20691
  let pickUpTypes = [];
20660
20692
  let dropOffTypes = [];
20661
20693
  let currentTripId = undefined;
20662
- try {
20663
- for (var _f = true, _g = __asyncValues(parseCsv(stopTimesStream, ['stop_sequence'])), _h; _h = yield _g.next(), _a = _h.done, !_a; _f = true) {
20664
- _c = _h.value;
20665
- _f = false;
20666
- const rawLine = _c;
20667
- const line = rawLine;
20668
- if (line.trip_id === currentTripId && line.stop_sequence <= previousSeq) {
20669
- console.warn(`Stop sequences not increasing for trip ${line.trip_id}: ${line.stop_sequence} > ${previousSeq}.`);
20670
- continue;
20671
- }
20672
- if (!line.arrival_time && !line.departure_time) {
20673
- console.warn(`Missing arrival or departure time for ${line.trip_id} at stop ${line.stop_id}.`);
20674
- continue;
20675
- }
20676
- if (line.pickup_type === '1' && line.drop_off_type === '1') {
20677
- // Warning: could potentially lead to issues if there is an in-seat transfer
20678
- // at this stop - it can be not boardable nor alightable but still useful for an in-seat transfer.
20679
- // This doesn't seem to happen in practice for now so keeping this condition to save memory.
20680
- continue;
20681
- }
20682
- if (currentTripId && line.trip_id !== currentTripId && stops.length > 0) {
20683
- addTrip(currentTripId);
20684
- }
20685
- currentTripId = line.trip_id;
20686
- const stopData = stopsMap.get(line.stop_id);
20687
- if (!stopData) {
20688
- console.warn(`Unknown stop ID: ${line.stop_id}`);
20689
- continue;
20690
- }
20691
- stops.push(stopData.id);
20692
- const departure = (_d = line.departure_time) !== null && _d !== void 0 ? _d : line.arrival_time;
20693
- const arrival = (_e = line.arrival_time) !== null && _e !== void 0 ? _e : line.departure_time;
20694
- if (!arrival || !departure) {
20695
- console.warn(`Missing time data for ${line.trip_id} at stop ${line.stop_id}`);
20696
- continue;
20697
- }
20698
- arrivalTimes.push(toTime(arrival).toMinutes());
20699
- departureTimes.push(toTime(departure).toMinutes());
20700
- pickUpTypes.push(parsePickupDropOffType(line.pickup_type));
20701
- dropOffTypes.push(parsePickupDropOffType(line.drop_off_type));
20702
- previousSeq = line.stop_sequence;
20694
+ for await (const rawLine of parseCsv(stopTimesStream, ['stop_sequence'])) {
20695
+ const line = rawLine;
20696
+ if (line.trip_id === currentTripId && line.stop_sequence <= previousSeq) {
20697
+ console.warn(`Stop sequences not increasing for trip ${line.trip_id}: ${line.stop_sequence} > ${previousSeq}.`);
20698
+ continue;
20703
20699
  }
20704
- }
20705
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
20706
- finally {
20707
- try {
20708
- if (!_f && !_a && (_b = _g.return)) yield _b.call(_g);
20700
+ if (!line.arrival_time && !line.departure_time) {
20701
+ console.warn(`Missing arrival or departure time for ${line.trip_id} at stop ${line.stop_id}.`);
20702
+ continue;
20703
+ }
20704
+ if (line.pickup_type === '1' && line.drop_off_type === '1') {
20705
+ // Warning: could potentially lead to issues if there is an in-seat transfer
20706
+ // at this stop - it can be not boardable nor alightable but still useful for an in-seat transfer.
20707
+ // This doesn't seem to happen in practice for now so keeping this condition to save memory.
20708
+ continue;
20709
+ }
20710
+ if (currentTripId && line.trip_id !== currentTripId && stops.length > 0) {
20711
+ addTrip(currentTripId);
20712
+ }
20713
+ currentTripId = line.trip_id;
20714
+ const stopData = stopsMap.get(line.stop_id);
20715
+ if (!stopData) {
20716
+ console.warn(`Unknown stop ID: ${line.stop_id}`);
20717
+ continue;
20709
20718
  }
20710
- finally { if (e_2) throw e_2.error; }
20719
+ stops.push(stopData.id);
20720
+ const departure = line.departure_time ?? line.arrival_time;
20721
+ const arrival = line.arrival_time ?? line.departure_time;
20722
+ if (!arrival || !departure) {
20723
+ console.warn(`Missing time data for ${line.trip_id} at stop ${line.stop_id}`);
20724
+ continue;
20725
+ }
20726
+ arrivalTimes.push(toTime(arrival).toMinutes());
20727
+ departureTimes.push(toTime(departure).toMinutes());
20728
+ pickUpTypes.push(parsePickupDropOffType(line.pickup_type));
20729
+ dropOffTypes.push(parsePickupDropOffType(line.drop_off_type));
20730
+ previousSeq = line.stop_sequence;
20711
20731
  }
20712
20732
  if (currentTripId) {
20713
20733
  addTrip(currentTripId);
@@ -20726,7 +20746,7 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
20726
20746
  });
20727
20747
  }
20728
20748
  return { routes: routesAdjacency, serviceRoutesMap, tripsMapping };
20729
- });
20749
+ };
20730
20750
  const parsePickupDropOffType = (gtfsType) => {
20731
20751
  switch (gtfsType) {
20732
20752
  default:
@@ -20750,6 +20770,8 @@ const STOP_TIMES_FILE = 'stop_times.txt';
20750
20770
  const STOPS_FILE = 'stops.txt';
20751
20771
  const TRANSFERS_FILE = 'transfers.txt';
20752
20772
  class GtfsParser {
20773
+ path;
20774
+ profile;
20753
20775
  constructor(path, profile = standardProfile) {
20754
20776
  // TODO: support input from multiple sources
20755
20777
  this.path = path;
@@ -20761,77 +20783,81 @@ class GtfsParser {
20761
20783
  * @param date The active date.
20762
20784
  * @returns The parsed timetable.
20763
20785
  */
20764
- parseTimetable(date) {
20765
- return __awaiter(this, void 0, void 0, function* () {
20766
- log.setLevel('INFO');
20767
- const zip = new StreamZip.async({ file: this.path });
20768
- const entries = yield zip.entries();
20769
- const datetime = DateTime.fromJSDate(date);
20770
- const activeServiceIds = new Set();
20771
- const activeStopIds = new Set();
20772
- log.info(`Parsing ${STOPS_FILE}`);
20773
- const stopsStart = performance.now();
20774
- const stopsStream = yield zip.stream(STOPS_FILE);
20775
- const parsedStops = yield parseStops(stopsStream);
20776
- const stopsEnd = performance.now();
20777
- log.info(`${parsedStops.size} parsed stops. (${(stopsEnd - stopsStart).toFixed(2)}ms)`);
20778
- if (entries[CALENDAR_FILE]) {
20779
- log.info(`Parsing ${CALENDAR_FILE}`);
20780
- const calendarStart = performance.now();
20781
- const calendarStream = yield zip.stream(CALENDAR_FILE);
20782
- yield parseCalendar(calendarStream, activeServiceIds, datetime);
20783
- const calendarEnd = performance.now();
20784
- log.info(`${activeServiceIds.size} valid services. (${(calendarEnd - calendarStart).toFixed(2)}ms)`);
20785
- }
20786
- if (entries[CALENDAR_DATES_FILE]) {
20787
- log.info(`Parsing ${CALENDAR_DATES_FILE}`);
20788
- const calendarDatesStart = performance.now();
20789
- const calendarDatesStream = yield zip.stream(CALENDAR_DATES_FILE);
20790
- yield parseCalendarDates(calendarDatesStream, activeServiceIds, datetime);
20791
- const calendarDatesEnd = performance.now();
20792
- log.info(`${activeServiceIds.size} valid services. (${(calendarDatesEnd - calendarDatesStart).toFixed(2)}ms)`);
20793
- }
20794
- log.info(`Parsing ${ROUTES_FILE}`);
20795
- const routesStart = performance.now();
20796
- const routesStream = yield zip.stream(ROUTES_FILE);
20797
- const validGtfsRoutes = yield parseRoutes(routesStream, this.profile);
20798
- const routesEnd = performance.now();
20799
- log.info(`${validGtfsRoutes.size} valid GTFS routes. (${(routesEnd - routesStart).toFixed(2)}ms)`);
20800
- log.info(`Parsing ${TRIPS_FILE}`);
20801
- const tripsStart = performance.now();
20802
- const tripsStream = yield zip.stream(TRIPS_FILE);
20803
- const trips = yield parseTrips(tripsStream, activeServiceIds, validGtfsRoutes);
20804
- const tripsEnd = performance.now();
20805
- log.info(`${trips.size} valid trips. (${(tripsEnd - tripsStart).toFixed(2)}ms)`);
20806
- let transfers = new Map();
20807
- let tripContinuations = new Map();
20808
- if (entries[TRANSFERS_FILE]) {
20809
- log.info(`Parsing ${TRANSFERS_FILE}`);
20810
- const transfersStart = performance.now();
20811
- const transfersStream = yield zip.stream(TRANSFERS_FILE);
20812
- const { transfers: parsedTransfers, tripContinuations: parsedTripContinuations, } = yield parseTransfers(transfersStream, parsedStops);
20813
- transfers = parsedTransfers;
20814
- tripContinuations = parsedTripContinuations;
20815
- const transfersEnd = performance.now();
20816
- log.info(`${transfers.size} valid transfers and ${tripContinuations.size} trip continuations. (${(transfersEnd - transfersStart).toFixed(2)}ms)`);
20817
- }
20818
- log.info(`Parsing ${STOP_TIMES_FILE}`);
20819
- const stopTimesStart = performance.now();
20820
- const stopTimesStream = yield zip.stream(STOP_TIMES_FILE);
20821
- const { routes, serviceRoutesMap, tripsMapping } = yield parseStopTimes(stopTimesStream, parsedStops, trips, activeStopIds);
20822
- const serviceRoutes = indexRoutes(validGtfsRoutes, serviceRoutesMap);
20823
- const stopTimesEnd = performance.now();
20824
- log.info(`${routes.length} valid unique routes. (${(stopTimesEnd - stopTimesStart).toFixed(2)}ms)`);
20825
- log.info('Building stops adjacency structure');
20826
- const stopsAdjacencyStart = performance.now();
20827
- const stopsAdjacency = buildStopsAdjacencyStructure(tripsMapping, serviceRoutes, routes, transfers, tripContinuations, parsedStops.size, activeStopIds);
20828
- const stopsAdjacencyEnd = performance.now();
20829
- log.info(`${stopsAdjacency.length} valid stops in the structure. (${(stopsAdjacencyEnd - stopsAdjacencyStart).toFixed(2)}ms)`);
20830
- yield zip.close();
20831
- const timetable = new Timetable(stopsAdjacency, routes, serviceRoutes);
20832
- log.info('Parsing complete.');
20833
- return timetable;
20834
- });
20786
+ async parseTimetable(date) {
20787
+ log.setLevel('INFO');
20788
+ const zip = new StreamZip.async({ file: this.path });
20789
+ const entries = await zip.entries();
20790
+ const datetime = DateTime.fromJSDate(date);
20791
+ const activeServiceIds = new Set();
20792
+ const activeStopIds = new Set();
20793
+ log.info(`Parsing ${STOPS_FILE}`);
20794
+ const stopsStart = performance.now();
20795
+ const stopsStream = await zip.stream(STOPS_FILE);
20796
+ const parsedStops = await parseStops(stopsStream);
20797
+ const stopsEnd = performance.now();
20798
+ log.info(`${parsedStops.size} parsed stops. (${(stopsEnd - stopsStart).toFixed(2)}ms)`);
20799
+ if (entries[CALENDAR_FILE]) {
20800
+ log.info(`Parsing ${CALENDAR_FILE}`);
20801
+ const calendarStart = performance.now();
20802
+ const calendarStream = await zip.stream(CALENDAR_FILE);
20803
+ await parseCalendar(calendarStream, activeServiceIds, datetime);
20804
+ const calendarEnd = performance.now();
20805
+ log.info(`${activeServiceIds.size} valid services. (${(calendarEnd - calendarStart).toFixed(2)}ms)`);
20806
+ }
20807
+ if (entries[CALENDAR_DATES_FILE]) {
20808
+ log.info(`Parsing ${CALENDAR_DATES_FILE}`);
20809
+ const calendarDatesStart = performance.now();
20810
+ const calendarDatesStream = await zip.stream(CALENDAR_DATES_FILE);
20811
+ await parseCalendarDates(calendarDatesStream, activeServiceIds, datetime);
20812
+ const calendarDatesEnd = performance.now();
20813
+ log.info(`${activeServiceIds.size} valid services. (${(calendarDatesEnd - calendarDatesStart).toFixed(2)}ms)`);
20814
+ }
20815
+ log.info(`Parsing ${ROUTES_FILE}`);
20816
+ const routesStart = performance.now();
20817
+ const routesStream = await zip.stream(ROUTES_FILE);
20818
+ const validGtfsRoutes = await parseRoutes(routesStream, this.profile);
20819
+ const routesEnd = performance.now();
20820
+ log.info(`${validGtfsRoutes.size} valid GTFS routes. (${(routesEnd - routesStart).toFixed(2)}ms)`);
20821
+ log.info(`Parsing ${TRIPS_FILE}`);
20822
+ const tripsStart = performance.now();
20823
+ const tripsStream = await zip.stream(TRIPS_FILE);
20824
+ const trips = await parseTrips(tripsStream, activeServiceIds, validGtfsRoutes);
20825
+ const tripsEnd = performance.now();
20826
+ log.info(`${trips.size} valid trips. (${(tripsEnd - tripsStart).toFixed(2)}ms)`);
20827
+ let transfers = new Map();
20828
+ let tripContinuationsMap = [];
20829
+ if (entries[TRANSFERS_FILE]) {
20830
+ log.info(`Parsing ${TRANSFERS_FILE}`);
20831
+ const transfersStart = performance.now();
20832
+ const transfersStream = await zip.stream(TRANSFERS_FILE);
20833
+ const { transfers: parsedTransfers, tripContinuations: parsedTripContinuations, } = await parseTransfers(transfersStream, parsedStops);
20834
+ transfers = parsedTransfers;
20835
+ tripContinuationsMap = parsedTripContinuations;
20836
+ const transfersEnd = performance.now();
20837
+ log.info(`${transfers.size} valid transfers and ${tripContinuationsMap.length} trip continuations. (${(transfersEnd - transfersStart).toFixed(2)}ms)`);
20838
+ }
20839
+ log.info(`Parsing ${STOP_TIMES_FILE}`);
20840
+ const stopTimesStart = performance.now();
20841
+ const stopTimesStream = await zip.stream(STOP_TIMES_FILE);
20842
+ const { routes, serviceRoutesMap, tripsMapping } = await parseStopTimes(stopTimesStream, parsedStops, trips, activeStopIds);
20843
+ const serviceRoutes = indexRoutes(validGtfsRoutes, serviceRoutesMap);
20844
+ const stopTimesEnd = performance.now();
20845
+ log.info(`${routes.length} valid unique routes. (${(stopTimesEnd - stopTimesStart).toFixed(2)}ms)`);
20846
+ log.info('Building stops adjacency structure');
20847
+ const stopsAdjacencyStart = performance.now();
20848
+ const stopsAdjacency = buildStopsAdjacencyStructure(serviceRoutes, routes, transfers, parsedStops.size, activeStopIds);
20849
+ const stopsAdjacencyEnd = performance.now();
20850
+ log.info(`${stopsAdjacency.length} valid stops in the structure. (${(stopsAdjacencyEnd - stopsAdjacencyStart).toFixed(2)}ms)`);
20851
+ await zip.close();
20852
+ // temporary timetable for building continuations
20853
+ const timetable = new Timetable(stopsAdjacency, routes, serviceRoutes);
20854
+ log.info('Building in-seat trip continuations');
20855
+ const tripContinuationsStart = performance.now();
20856
+ const tripContinuations = buildTripContinuations(tripsMapping, tripContinuationsMap, timetable, activeStopIds);
20857
+ const tripContinuationsEnd = performance.now();
20858
+ log.info(`${tripContinuations.size} in-seat trip continuations origins created. (${(tripContinuationsEnd - tripContinuationsStart).toFixed(2)}ms)`);
20859
+ log.info('Parsing complete.');
20860
+ return new Timetable(stopsAdjacency, routes, serviceRoutes, tripContinuations);
20835
20861
  }
20836
20862
  /**
20837
20863
  * Parses a GTFS feed to extract all stops.
@@ -20839,18 +20865,16 @@ class GtfsParser {
20839
20865
  * @param activeStops The set of active stop IDs to include in the index.
20840
20866
  * @returns An index of stops.
20841
20867
  */
20842
- parseStops() {
20843
- return __awaiter(this, void 0, void 0, function* () {
20844
- const zip = new StreamZip.async({ file: this.path });
20845
- log.info(`Parsing ${STOPS_FILE}`);
20846
- const stopsStart = performance.now();
20847
- const stopsStream = yield zip.stream(STOPS_FILE);
20848
- const stops = yield parseStops(stopsStream);
20849
- const stopsEnd = performance.now();
20850
- log.info(`${stops.size} parsed stops. (${(stopsEnd - stopsStart).toFixed(2)}ms)`);
20851
- yield zip.close();
20852
- return new StopsIndex(Array.from(stops.values()));
20853
- });
20868
+ async parseStops() {
20869
+ const zip = new StreamZip.async({ file: this.path });
20870
+ log.info(`Parsing ${STOPS_FILE}`);
20871
+ const stopsStart = performance.now();
20872
+ const stopsStream = await zip.stream(STOPS_FILE);
20873
+ const stops = await parseStops(stopsStream);
20874
+ const stopsEnd = performance.now();
20875
+ log.info(`${stops.size} parsed stops. (${(stopsEnd - stopsStart).toFixed(2)}ms)`);
20876
+ await zip.close();
20877
+ return new StopsIndex(Array.from(stops.values()));
20854
20878
  }
20855
20879
  }
20856
20880
 
@@ -20904,27 +20928,27 @@ const chGtfsProfile = {
20904
20928
  };
20905
20929
 
20906
20930
  class Plotter {
20931
+ result;
20932
+ ROUND_COLORS = [
20933
+ '#60a5fa', // Round 1
20934
+ '#ff9800', // Round 2
20935
+ '#14b8a6', // Round 3
20936
+ '#fb7185', // Round 4
20937
+ '#ffdf00', // Round 5
20938
+ '#b600ff', // Round 6
20939
+ '#ee82ee', // Round 7+
20940
+ ];
20907
20941
  constructor(result) {
20908
- this.ROUND_COLORS = [
20909
- '#60a5fa', // Round 1
20910
- '#ff9800', // Round 2
20911
- '#14b8a6', // Round 3
20912
- '#fb7185', // Round 4
20913
- '#ffdf00', // Round 5
20914
- '#b600ff', // Round 6
20915
- '#ee82ee', // Round 7+
20916
- ];
20917
20942
  this.result = result;
20918
20943
  }
20919
20944
  /**
20920
20945
  * Gets the color for a round based on the specified palette.
20921
20946
  */
20922
20947
  getRoundColor(round) {
20923
- var _a;
20924
20948
  if (round === 0)
20925
20949
  return '#888888';
20926
20950
  const colorIndex = Math.min(round - 1, this.ROUND_COLORS.length - 1);
20927
- return (_a = this.ROUND_COLORS[colorIndex]) !== null && _a !== void 0 ? _a : '#ee82ee';
20951
+ return this.ROUND_COLORS[colorIndex] ?? '#ee82ee';
20928
20952
  }
20929
20953
  /**
20930
20954
  * Escapes special characters in DOT strings to prevent syntax errors.
@@ -20941,8 +20965,7 @@ class Plotter {
20941
20965
  * Determines station type (origin/destination) information.
20942
20966
  */
20943
20967
  getStationInfo(stopId) {
20944
- var _a, _b;
20945
- const isOrigin = (_b = (_a = this.result.routingState.graph[0]) === null || _a === void 0 ? void 0 : _a.has(stopId)) !== null && _b !== void 0 ? _b : false;
20968
+ const isOrigin = this.result.routingState.graph[0]?.has(stopId) ?? false;
20946
20969
  const isDestination = this.result.routingState.destinations.includes(stopId);
20947
20970
  return { isOrigin, isDestination };
20948
20971
  }
@@ -20989,7 +21012,6 @@ class Plotter {
20989
21012
  * Creates a vehicle edge with route information oval in the middle.
20990
21013
  */
20991
21014
  createVehicleEdge(edge, round) {
20992
- var _a;
20993
21015
  const fromNodeId = `s_${edge.from}`;
20994
21016
  const toNodeId = `s_${edge.to}`;
20995
21017
  const roundColor = this.getRoundColor(round);
@@ -20998,8 +21020,8 @@ class Plotter {
20998
21020
  const serviceRouteInfo = route
20999
21021
  ? this.result.timetable.getServiceRouteInfo(route)
21000
21022
  : null;
21001
- const routeName = (_a = serviceRouteInfo === null || serviceRouteInfo === void 0 ? void 0 : serviceRouteInfo.name) !== null && _a !== void 0 ? _a : `Route ${String(edge.routeId)}`;
21002
- const routeType = (serviceRouteInfo === null || serviceRouteInfo === void 0 ? void 0 : serviceRouteInfo.type) || 'UNKNOWN';
21023
+ const routeName = serviceRouteInfo?.name ?? `Route ${String(edge.routeId)}`;
21024
+ const routeType = serviceRouteInfo?.type || 'UNKNOWN';
21003
21025
  const departureTime = route
21004
21026
  ? route.departureFrom(edge.from, edge.tripIndex).toString()
21005
21027
  : 'N/A';
@@ -21018,12 +21040,11 @@ class Plotter {
21018
21040
  * Creates a transfer edge with transfer information oval in the middle.
21019
21041
  */
21020
21042
  createTransferEdge(edge, round) {
21021
- var _a;
21022
21043
  const fromNodeId = `s_${edge.from}`;
21023
21044
  const toNodeId = `s_${edge.to}`;
21024
21045
  const roundColor = this.getRoundColor(round);
21025
21046
  const transferOvalId = `e_${edge.from}_${edge.to}_${round}`;
21026
- const transferTime = ((_a = edge.minTransferTime) === null || _a === void 0 ? void 0 : _a.toString()) || 'N/A';
21047
+ const transferTime = edge.minTransferTime?.toString() || 'N/A';
21027
21048
  const escapedTransferTime = this.escapeDotString(transferTime);
21028
21049
  const ovalLabel = `Transfer\\n${escapedTransferTime}`;
21029
21050
  return [
@@ -21036,7 +21057,6 @@ class Plotter {
21036
21057
  * Creates a continuation edge to visually link trip continuations.
21037
21058
  */
21038
21059
  createContinuationEdge(fromEdge, toEdge, round) {
21039
- var _a, _b;
21040
21060
  const fromStationId = `s_${fromEdge.to}`;
21041
21061
  const toStationId = `s_${toEdge.from}`;
21042
21062
  const roundColor = this.getRoundColor(round);
@@ -21049,10 +21069,10 @@ class Plotter {
21049
21069
  const toServiceRouteInfo = toRoute
21050
21070
  ? this.result.timetable.getServiceRouteInfo(toRoute)
21051
21071
  : null;
21052
- const fromRouteName = (_a = fromServiceRouteInfo === null || fromServiceRouteInfo === void 0 ? void 0 : fromServiceRouteInfo.name) !== null && _a !== void 0 ? _a : `Route ${String(fromEdge.routeId)}`;
21053
- const toRouteName = (_b = toServiceRouteInfo === null || toServiceRouteInfo === void 0 ? void 0 : toServiceRouteInfo.name) !== null && _b !== void 0 ? _b : `Route ${String(toEdge.routeId)}`;
21054
- const fromRouteType = (fromServiceRouteInfo === null || fromServiceRouteInfo === void 0 ? void 0 : fromServiceRouteInfo.type) || 'UNKNOWN';
21055
- const toRouteType = (toServiceRouteInfo === null || toServiceRouteInfo === void 0 ? void 0 : toServiceRouteInfo.type) || 'UNKNOWN';
21072
+ const fromRouteName = fromServiceRouteInfo?.name ?? `Route ${String(fromEdge.routeId)}`;
21073
+ const toRouteName = toServiceRouteInfo?.name ?? `Route ${String(toEdge.routeId)}`;
21074
+ const fromRouteType = fromServiceRouteInfo?.type || 'UNKNOWN';
21075
+ const toRouteType = toServiceRouteInfo?.type || 'UNKNOWN';
21056
21076
  const fromArrivalTime = fromEdge.arrival.toString();
21057
21077
  const toDepartureTime = toRoute
21058
21078
  ? toRoute.departureFrom(toEdge.from, toEdge.tripIndex).toString()
@@ -21147,79 +21167,85 @@ class Plotter {
21147
21167
  }
21148
21168
 
21149
21169
  class Query {
21170
+ from;
21171
+ to;
21172
+ departureTime;
21173
+ lastDepartureTime;
21174
+ options;
21150
21175
  constructor(builder) {
21151
21176
  this.from = builder.fromValue;
21152
21177
  this.to = builder.toValue;
21153
21178
  this.departureTime = builder.departureTimeValue;
21154
21179
  this.options = builder.optionsValue;
21155
21180
  }
21156
- }
21157
- Query.Builder = class {
21158
- constructor() {
21159
- this.toValue = new Set();
21181
+ static Builder = class {
21182
+ fromValue;
21183
+ toValue = new Set();
21184
+ departureTimeValue;
21160
21185
  // lastDepartureTimeValue?: Date;
21161
21186
  // via: StopId[] = [];
21162
- this.optionsValue = {
21187
+ optionsValue = {
21163
21188
  maxTransfers: 5,
21164
21189
  minTransferTime: Duration.fromSeconds(120),
21165
21190
  transportModes: ALL_TRANSPORT_MODES,
21166
21191
  };
21167
- }
21168
- /**
21169
- * Sets the starting stop.
21170
- */
21171
- from(from) {
21172
- this.fromValue = from;
21173
- return this;
21174
- }
21175
- /**
21176
- * Sets the destination stops(s), routing will stop when all the provided stops are reached.
21177
- */
21178
- to(to) {
21179
- this.toValue = to instanceof Set ? to : new Set([to]);
21180
- return this;
21181
- }
21182
- /**
21183
- * Sets the departure time for the query.
21184
- * Note that the router will favor routes that depart shortly after the provided departure time,
21185
- * even if a later route might arrive at the same time.
21186
- * Range queries will allow to specify a range of departure times in the future.
21187
- */
21188
- departureTime(departureTime) {
21189
- this.departureTimeValue = departureTime;
21190
- return this;
21191
- }
21192
- /**
21193
- * Sets the maximum number of transfers allowed.
21194
- */
21195
- maxTransfers(maxTransfers) {
21196
- this.optionsValue.maxTransfers = maxTransfers;
21197
- return this;
21198
- }
21199
- /**
21200
- * Sets the minimum transfer time to use when no transfer time is provided in the data.
21201
- */
21202
- minTransferTime(minTransferTime) {
21203
- this.optionsValue.minTransferTime = minTransferTime;
21204
- return this;
21205
- }
21206
- /**
21207
- * Sets the transport modes to consider.
21208
- */
21209
- transportModes(transportModes) {
21210
- this.optionsValue.transportModes = transportModes;
21211
- return this;
21212
- }
21213
- build() {
21214
- return new Query(this);
21215
- }
21216
- };
21192
+ /**
21193
+ * Sets the starting stop.
21194
+ */
21195
+ from(from) {
21196
+ this.fromValue = from;
21197
+ return this;
21198
+ }
21199
+ /**
21200
+ * Sets the destination stops(s), routing will stop when all the provided stops are reached.
21201
+ */
21202
+ to(to) {
21203
+ this.toValue = to instanceof Set ? to : new Set([to]);
21204
+ return this;
21205
+ }
21206
+ /**
21207
+ * Sets the departure time for the query.
21208
+ * Note that the router will favor routes that depart shortly after the provided departure time,
21209
+ * even if a later route might arrive at the same time.
21210
+ * Range queries will allow to specify a range of departure times in the future.
21211
+ */
21212
+ departureTime(departureTime) {
21213
+ this.departureTimeValue = departureTime;
21214
+ return this;
21215
+ }
21216
+ /**
21217
+ * Sets the maximum number of transfers allowed.
21218
+ */
21219
+ maxTransfers(maxTransfers) {
21220
+ this.optionsValue.maxTransfers = maxTransfers;
21221
+ return this;
21222
+ }
21223
+ /**
21224
+ * Sets the minimum transfer time to use when no transfer time is provided in the data.
21225
+ */
21226
+ minTransferTime(minTransferTime) {
21227
+ this.optionsValue.minTransferTime = minTransferTime;
21228
+ return this;
21229
+ }
21230
+ /**
21231
+ * Sets the transport modes to consider.
21232
+ */
21233
+ transportModes(transportModes) {
21234
+ this.optionsValue.transportModes = transportModes;
21235
+ return this;
21236
+ }
21237
+ build() {
21238
+ return new Query(this);
21239
+ }
21240
+ };
21241
+ }
21217
21242
 
21218
21243
  /**
21219
21244
  * Represents a resolved route consisting of multiple legs,
21220
21245
  * which can be either vehicle legs or transfer legs.
21221
21246
  */
21222
21247
  class Route {
21248
+ legs;
21223
21249
  constructor(legs) {
21224
21250
  this.legs = legs;
21225
21251
  }
@@ -21289,11 +21315,10 @@ class Route {
21289
21315
  toString() {
21290
21316
  return this.legs
21291
21317
  .map((leg, index) => {
21292
- var _a;
21293
21318
  const fromStop = `From: ${leg.from.name}${leg.from.platform ? ` (Pl. ${leg.from.platform})` : ''}`;
21294
21319
  const toStop = `To: ${leg.to.name}${leg.to.platform ? ` (Pl. ${leg.to.platform})` : ''}`;
21295
21320
  const transferDetails = 'minTransferTime' in leg
21296
- ? `Minimum Transfer Time: ${(_a = leg.minTransferTime) === null || _a === void 0 ? void 0 : _a.toString()}`
21321
+ ? `Minimum Transfer Time: ${leg.minTransferTime?.toString()}`
21297
21322
  : '';
21298
21323
  const travelDetails = 'route' in leg && 'departureTime' in leg && 'arrivalTime' in leg
21299
21324
  ? `Route: ${leg.route.type} ${leg.route.name}, Departure: ${leg.departureTime.toString()}, Arrival: ${leg.arrivalTime.toString()}`
@@ -21329,9 +21354,14 @@ class Route {
21329
21354
  };
21330
21355
  }
21331
21356
  else {
21332
- return Object.assign({ from: leg.from.sourceStopId, to: leg.to.sourceStopId, type: leg.type }, (leg.minTransferTime !== undefined && {
21333
- minTransferTime: leg.minTransferTime.toString(),
21334
- }));
21357
+ return {
21358
+ from: leg.from.sourceStopId,
21359
+ to: leg.to.sourceStopId,
21360
+ type: leg.type,
21361
+ ...(leg.minTransferTime !== undefined && {
21362
+ minTransferTime: leg.minTransferTime.toString(),
21363
+ }),
21364
+ };
21335
21365
  }
21336
21366
  });
21337
21367
  return jsonLegs;
@@ -21339,6 +21369,10 @@ class Route {
21339
21369
  }
21340
21370
 
21341
21371
  class Result {
21372
+ query;
21373
+ routingState;
21374
+ stopsIndex;
21375
+ timetable;
21342
21376
  constructor(query, routingState, stopsIndex, timetable) {
21343
21377
  this.query = query;
21344
21378
  this.routingState = routingState;
@@ -21353,7 +21387,6 @@ class Result {
21353
21387
  * @returns a route to the destination stop if it exists.
21354
21388
  */
21355
21389
  bestRoute(to) {
21356
- var _a;
21357
21390
  const destinationList = to instanceof Set
21358
21391
  ? Array.from(to)
21359
21392
  : to
@@ -21380,7 +21413,7 @@ class Result {
21380
21413
  let currentStop = fastestDestination;
21381
21414
  let round = fastestTime.legNumber;
21382
21415
  while (round > 0) {
21383
- const edge = (_a = this.routingState.graph[round]) === null || _a === void 0 ? void 0 : _a.get(currentStop);
21416
+ const edge = this.routingState.graph[round]?.get(currentStop);
21384
21417
  if (!edge) {
21385
21418
  throw new Error(`No edge arriving at stop ${currentStop} at round ${round}`);
21386
21419
  }
@@ -21430,9 +21463,9 @@ class Result {
21430
21463
  const lastRoute = this.timetable.getRoute(lastEdge.routeId);
21431
21464
  return {
21432
21465
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
21433
- from: this.stopsIndex.findStopById(firstEdge.from),
21466
+ from: this.stopsIndex.findStopById(firstRoute.stopId(firstEdge.from)),
21434
21467
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
21435
- to: this.stopsIndex.findStopById(lastEdge.to),
21468
+ to: this.stopsIndex.findStopById(lastRoute.stopId(lastEdge.to)),
21436
21469
  // The route info comes from the first boarded route in case on continuous trips
21437
21470
  route: this.timetable.getServiceRouteInfo(firstRoute),
21438
21471
  departureTime: firstRoute.departureFrom(firstEdge.from, firstEdge.tripIndex),
@@ -21465,7 +21498,6 @@ class Result {
21465
21498
  * @returns The arrival time if the target stop is reachable, otherwise undefined.
21466
21499
  */
21467
21500
  arrivalAt(stop, maxTransfers) {
21468
- var _a;
21469
21501
  const equivalentStops = this.stopsIndex.equivalentStops(stop);
21470
21502
  let earliestArrival = undefined;
21471
21503
  for (const equivalentStop of equivalentStops) {
@@ -21477,7 +21509,7 @@ class Result {
21477
21509
  // We have no guarantee that the stop was visited in the last round,
21478
21510
  // so we need to check all rounds if it's not found in the last one.
21479
21511
  for (let i = maxTransfers + 1; i >= 0; i--) {
21480
- const arrivalEdge = (_a = this.routingState.graph[i]) === null || _a === void 0 ? void 0 : _a.get(equivalentStop.id);
21512
+ const arrivalEdge = this.routingState.graph[i]?.get(equivalentStop.id);
21481
21513
  if (arrivalEdge !== undefined) {
21482
21514
  arrivalTime = {
21483
21515
  arrival: arrivalEdge.arrival,
@@ -21506,6 +21538,8 @@ const UNREACHED = Time.infinity();
21506
21538
  * https://www.microsoft.com/en-us/research/wp-content/uploads/2012/01/raptor_alenex.pdf
21507
21539
  */
21508
21540
  class Router {
21541
+ timetable;
21542
+ stopsIndex;
21509
21543
  constructor(timetable, stopsIndex) {
21510
21544
  this.timetable = timetable;
21511
21545
  this.stopsIndex = stopsIndex;
@@ -21533,8 +21567,8 @@ class Router {
21533
21567
  const reachableRoutes = this.timetable.findReachableRoutes(markedStops, query.options.transportModes);
21534
21568
  markedStops.clear();
21535
21569
  // for each route that can be reached with at least round - 1 trips
21536
- for (const [route, hopOnStop] of reachableRoutes) {
21537
- const newlyMarkedStops = this.scanRoute(route, hopOnStop, round, routingState);
21570
+ for (const [route, hopOnStopIndex] of reachableRoutes) {
21571
+ const newlyMarkedStops = this.scanRoute(route, hopOnStopIndex, round, routingState);
21538
21572
  for (const newStop of newlyMarkedStops) {
21539
21573
  markedStops.add(newStop);
21540
21574
  }
@@ -21545,7 +21579,7 @@ class Router {
21545
21579
  const stopsFromContinuations = new Set();
21546
21580
  for (const continuation of continuations) {
21547
21581
  const route = this.timetable.getRoute(continuation.routeId);
21548
- const routeScanResults = this.scanRoute(route, continuation.hopOnStop, round, routingState, continuation);
21582
+ const routeScanResults = this.scanRoute(route, continuation.hopOnStopIndex, round, routingState, continuation);
21549
21583
  for (const newStop of routeScanResults) {
21550
21584
  stopsFromContinuations.add(newStop);
21551
21585
  }
@@ -21576,12 +21610,12 @@ class Router {
21576
21610
  const arrival = edgesAtCurrentRound.get(stopId);
21577
21611
  if (!arrival || !('routeId' in arrival))
21578
21612
  continue;
21579
- const continuousTrips = this.timetable.getContinuousTrips(stopId, arrival.routeId, arrival.tripIndex);
21613
+ const continuousTrips = this.timetable.getContinuousTrips(arrival.to, arrival.routeId, arrival.tripIndex);
21580
21614
  for (let i = 0; i < continuousTrips.length; i++) {
21581
21615
  const trip = continuousTrips[i];
21582
21616
  continuations.push({
21583
21617
  routeId: trip.routeId,
21584
- hopOnStop: trip.hopOnStop,
21618
+ hopOnStopIndex: trip.hopOnStopIndex,
21585
21619
  tripIndex: trip.tripIndex,
21586
21620
  previousEdge: arrival,
21587
21621
  });
@@ -21636,33 +21670,31 @@ class Router {
21636
21670
  * are available if no given trip is provided as a parameter.
21637
21671
  *
21638
21672
  * @param route The route to scan for possible trips
21639
- * @param hopOnStop The stop ID where passengers can board the route
21673
+ * @param hopOnStopIndex The stop index where passengers can board the route
21640
21674
  * @param round The current round number in the RAPTOR algorithm
21641
21675
  * @param routingState The current routing state containing arrival times and marked stops
21642
21676
  */
21643
- scanRoute(route, hopOnStop, round, routingState, tripContinuation) {
21644
- var _a, _b, _c;
21677
+ scanRoute(route, hopOnStopIndex, round, routingState, tripContinuation) {
21645
21678
  const newlyMarkedStops = new Set();
21646
21679
  let activeTrip = tripContinuation
21647
21680
  ? {
21648
21681
  routeId: route.id,
21649
- hopOnStop,
21682
+ hopOnStopIndex,
21650
21683
  tripIndex: tripContinuation.tripIndex,
21651
21684
  }
21652
21685
  : undefined;
21653
21686
  const edgesAtCurrentRound = routingState.graph[round];
21654
21687
  const edgesAtPreviousRound = routingState.graph[round - 1];
21655
- const startIndex = route.stopRouteIndex(hopOnStop);
21656
21688
  // Compute target pruning criteria only once per route
21657
21689
  const earliestArrivalAtAnyDestination = this.earliestArrivalAtAnyStop(routingState.earliestArrivals, routingState.destinations);
21658
- for (let j = startIndex; j < route.getNbStops(); j++) {
21659
- const currentStop = route.stops[j];
21690
+ for (let currentStopIndex = hopOnStopIndex; currentStopIndex < route.getNbStops(); currentStopIndex++) {
21691
+ const currentStop = route.stops[currentStopIndex];
21660
21692
  // If we're currently on a trip,
21661
21693
  // check if arrival at the stop improves the earliest arrival time
21662
21694
  if (activeTrip !== undefined) {
21663
- const arrivalTime = route.arrivalAt(currentStop, activeTrip.tripIndex);
21664
- const dropOffType = route.dropOffTypeAt(currentStop, activeTrip.tripIndex);
21665
- const earliestArrivalAtCurrentStop = (_b = (_a = routingState.earliestArrivals.get(currentStop)) === null || _a === void 0 ? void 0 : _a.arrival) !== null && _b !== void 0 ? _b : UNREACHED;
21695
+ const arrivalTime = route.arrivalAt(currentStopIndex, activeTrip.tripIndex);
21696
+ const dropOffType = route.dropOffTypeAt(currentStopIndex, activeTrip.tripIndex);
21697
+ const earliestArrivalAtCurrentStop = routingState.earliestArrivals.get(currentStop)?.arrival ?? UNREACHED;
21666
21698
  if (dropOffType !== 'NOT_AVAILABLE' &&
21667
21699
  arrivalTime.isBefore(earliestArrivalAtCurrentStop) &&
21668
21700
  arrivalTime.isBefore(earliestArrivalAtAnyDestination)) {
@@ -21670,8 +21702,8 @@ class Router {
21670
21702
  arrival: arrivalTime,
21671
21703
  routeId: route.id,
21672
21704
  tripIndex: activeTrip.tripIndex,
21673
- from: activeTrip.hopOnStop,
21674
- to: currentStop,
21705
+ from: activeTrip.hopOnStopIndex,
21706
+ to: currentStopIndex,
21675
21707
  };
21676
21708
  if (tripContinuation) {
21677
21709
  // In case of continuous trip, we set a pointer to the previous edge
@@ -21691,21 +21723,21 @@ class Router {
21691
21723
  }
21692
21724
  // check if we can board an earlier trip at the current stop
21693
21725
  // if there was no current trip, find the first one reachable
21694
- const earliestArrivalOnPreviousRound = (_c = edgesAtPreviousRound.get(currentStop)) === null || _c === void 0 ? void 0 : _c.arrival;
21726
+ const earliestArrivalOnPreviousRound = edgesAtPreviousRound.get(currentStop)?.arrival;
21695
21727
  // TODO if the last edge is not a transfer, and if there is no trip continuation of type 1 (guaranteed)
21696
21728
  // Add the minTransferTime to make sure there's at least 2 minutes to transfer.
21697
21729
  // If platforms are collapsed, make sure to apply the station level transfer time
21698
21730
  // (or later at route reconstruction time)
21699
21731
  if (earliestArrivalOnPreviousRound !== undefined &&
21700
21732
  (activeTrip === undefined ||
21701
- earliestArrivalOnPreviousRound.isBefore(route.departureFrom(currentStop, activeTrip.tripIndex)) ||
21702
- earliestArrivalOnPreviousRound.equals(route.departureFrom(currentStop, activeTrip.tripIndex)))) {
21703
- const earliestTrip = route.findEarliestTrip(currentStop, earliestArrivalOnPreviousRound, activeTrip === null || activeTrip === void 0 ? void 0 : activeTrip.tripIndex);
21733
+ earliestArrivalOnPreviousRound.isBefore(route.departureFrom(currentStopIndex, activeTrip.tripIndex)) ||
21734
+ earliestArrivalOnPreviousRound.equals(route.departureFrom(currentStopIndex, activeTrip.tripIndex)))) {
21735
+ const earliestTrip = route.findEarliestTrip(currentStopIndex, earliestArrivalOnPreviousRound, activeTrip?.tripIndex);
21704
21736
  if (earliestTrip !== undefined) {
21705
21737
  activeTrip = {
21706
21738
  routeId: route.id,
21707
21739
  tripIndex: earliestTrip,
21708
- hopOnStop: currentStop,
21740
+ hopOnStopIndex: currentStopIndex,
21709
21741
  };
21710
21742
  }
21711
21743
  }
@@ -21723,7 +21755,6 @@ class Router {
21723
21755
  * @param routingState The current routing state containing arrival times and marked stops
21724
21756
  */
21725
21757
  considerTransfers(query, round, markedStops, routingState) {
21726
- var _a, _b;
21727
21758
  const { options } = query;
21728
21759
  const arrivalsAtCurrentRound = routingState.graph[round];
21729
21760
  const newlyMarkedStops = new Set();
@@ -21747,7 +21778,8 @@ class Router {
21747
21778
  transferTime = options.minTransferTime;
21748
21779
  }
21749
21780
  const arrivalAfterTransfer = currentArrival.arrival.plus(transferTime);
21750
- const originalArrival = (_b = (_a = arrivalsAtCurrentRound.get(transfer.destination)) === null || _a === void 0 ? void 0 : _a.arrival) !== null && _b !== void 0 ? _b : UNREACHED;
21781
+ const originalArrival = arrivalsAtCurrentRound.get(transfer.destination)?.arrival ??
21782
+ UNREACHED;
21751
21783
  if (arrivalAfterTransfer.isBefore(originalArrival)) {
21752
21784
  arrivalsAtCurrentRound.set(transfer.destination, {
21753
21785
  arrival: arrivalAfterTransfer,
@@ -21774,11 +21806,10 @@ class Router {
21774
21806
  * @returns The earliest arrival time among the provided destinations.
21775
21807
  */
21776
21808
  earliestArrivalAtAnyStop(earliestArrivals, destinations) {
21777
- var _a, _b;
21778
21809
  let earliestArrivalAtAnyDestination = UNREACHED;
21779
21810
  for (let i = 0; i < destinations.length; i++) {
21780
21811
  const destination = destinations[i];
21781
- const arrival = (_b = (_a = earliestArrivals.get(destination)) === null || _a === void 0 ? void 0 : _a.arrival) !== null && _b !== void 0 ? _b : UNREACHED;
21812
+ const arrival = earliestArrivals.get(destination)?.arrival ?? UNREACHED;
21782
21813
  earliestArrivalAtAnyDestination = Time.min(earliestArrivalAtAnyDestination, arrival);
21783
21814
  }
21784
21815
  return earliestArrivalAtAnyDestination;
@@ -21980,7 +22011,6 @@ const startRepl = (stopsPath, timetablePath) => {
21980
22011
  if (bestRoute) {
21981
22012
  console.log(`Found route from ${fromStop.name} to ${toStop.name}:`);
21982
22013
  console.log(bestRoute.toString());
21983
- console.log(bestRoute.asJson());
21984
22014
  }
21985
22015
  else {
21986
22016
  console.log('No route found');
@@ -22087,7 +22117,6 @@ const startRepl = (stopsPath, timetablePath) => {
22087
22117
  return;
22088
22118
  }
22089
22119
  const inspectRoute = (routeIdStr) => {
22090
- var _a, _b, _c;
22091
22120
  const routeId = parseInt(routeIdStr.trim());
22092
22121
  if (isNaN(routeId)) {
22093
22122
  console.log('Usage: .inspect route <routeId>');
@@ -22109,29 +22138,30 @@ const startRepl = (stopsPath, timetablePath) => {
22109
22138
  console.log('\n--- Stops ---');
22110
22139
  for (let i = 0; i < route.stops.length; i++) {
22111
22140
  const stopId = route.stopId(i);
22141
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
22112
22142
  const stop = stopsIndex.findStopById(stopId);
22113
- const platform = (stop === null || stop === void 0 ? void 0 : stop.platform) ? ` (Pl. ${stop.platform})` : '';
22114
- console.log(`${i + 1}. ${(_a = stop === null || stop === void 0 ? void 0 : stop.name) !== null && _a !== void 0 ? _a : 'Unknown'}${platform} (${stopId}, ${(_b = stop === null || stop === void 0 ? void 0 : stop.sourceStopId) !== null && _b !== void 0 ? _b : 'N/A'})`);
22143
+ const platform = stop.platform ? ` (Pl. ${stop.platform})` : '';
22144
+ console.log(`${i + 1}. ${stop.name}${platform} (${stopId}, ${stop.sourceStopId})`);
22115
22145
  }
22116
22146
  console.log('\n--- Trips ---');
22117
22147
  for (let tripIndex = 0; tripIndex < route.getNbTrips(); tripIndex++) {
22118
22148
  console.log(`\nTrip ${tripIndex}:`);
22119
22149
  for (let stopIndex = 0; stopIndex < route.stops.length; stopIndex++) {
22120
22150
  const stopId = route.stopId(stopIndex);
22151
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
22121
22152
  const stop = stopsIndex.findStopById(stopId);
22122
- const departure = route.departureFrom(stopId, tripIndex);
22123
- const arrival = route.arrivalAt(stopId, tripIndex);
22124
- const pickupType = route.pickUpTypeFrom(stopId, tripIndex);
22125
- const dropOffType = route.dropOffTypeAt(stopId, tripIndex);
22153
+ const departure = route.departureFrom(stopIndex, tripIndex);
22154
+ const arrival = route.arrivalAt(stopIndex, tripIndex);
22155
+ const pickupType = route.pickUpTypeFrom(stopIndex, tripIndex);
22156
+ const dropOffType = route.dropOffTypeAt(stopIndex, tripIndex);
22126
22157
  const pickupStr = formatPickupDropoffType(pickupType);
22127
22158
  const dropOffStr = formatPickupDropoffType(dropOffType);
22128
- console.log(` ${stopIndex + 1}. ${(_c = stop === null || stop === void 0 ? void 0 : stop.name) !== null && _c !== void 0 ? _c : 'Unknown'}: arr ${arrival.toString()} (${pickupStr}) → dep ${departure.toString()} (${dropOffStr})`);
22159
+ console.log(` ${stopIndex + 1}. ${stop.name}: arr ${arrival.toString()} (${pickupStr}) → dep ${departure.toString()} (${dropOffStr})`);
22129
22160
  }
22130
22161
  }
22131
22162
  console.log();
22132
22163
  };
22133
22164
  const inspectStop = (stopIdStr) => {
22134
- var _a, _b, _c;
22135
22165
  let stop;
22136
22166
  const stopBySourceId = stopsIndex.findStopBySourceStopId(stopIdStr);
22137
22167
  if (stopBySourceId !== undefined) {
@@ -22187,68 +22217,57 @@ const startRepl = (stopsPath, timetablePath) => {
22187
22217
  if (transfers.length > 0) {
22188
22218
  console.log('\n--- Transfers ---');
22189
22219
  transfers.forEach((transfer, index) => {
22190
- var _a, _b;
22191
22220
  const destStop = stopsIndex.findStopById(transfer.destination);
22192
- const platform = (destStop === null || destStop === void 0 ? void 0 : destStop.platform)
22221
+ const platform = destStop?.platform
22193
22222
  ? ` (Pl. ${destStop.platform})`
22194
22223
  : '';
22195
22224
  const minTime = transfer.minTransferTime
22196
22225
  ? ` (min: ${Math.floor(transfer.minTransferTime.toSeconds() / 60)}min)`
22197
22226
  : '';
22198
- console.log(`${index + 1}. ${transfer.type} to ${(_a = destStop === null || destStop === void 0 ? void 0 : destStop.name) !== null && _a !== void 0 ? _a : 'Unknown'}${platform} (${transfer.destination}, ${(_b = destStop === null || destStop === void 0 ? void 0 : destStop.sourceStopId) !== null && _b !== void 0 ? _b : 'N/A'})${minTime}`);
22227
+ console.log(`${index + 1}. ${transfer.type} to ${destStop?.name ?? 'Unknown'}${platform} (${transfer.destination}, ${destStop?.sourceStopId ?? 'N/A'})${minTime}`);
22199
22228
  });
22200
22229
  }
22201
22230
  let totalContinuations = 0;
22202
- const continuationsByTrip = new Map();
22231
+ console.log('\n--- Trip Continuations ---');
22203
22232
  routes.forEach((route) => {
22233
+ const serviceRouteInfo = timetable.getServiceRouteInfo(route);
22234
+ const stopIndices = route.stopRouteIndices(stop.id);
22204
22235
  for (let tripIndex = 0; tripIndex < route.getNbTrips(); tripIndex++) {
22205
- const continuations = timetable.getContinuousTrips(stop.id, route.id, tripIndex);
22206
- if (continuations.length > 0) {
22207
- totalContinuations += continuations.length;
22208
- const tripKey = `${route.id}-${tripIndex}`;
22209
- continuationsByTrip.set(tripKey, {
22210
- route,
22211
- tripIndex,
22212
- continuations,
22213
- });
22236
+ for (const stopIndex of stopIndices) {
22237
+ const continuations = timetable.getContinuousTrips(stopIndex, route.id, tripIndex);
22238
+ for (const continuation of continuations) {
22239
+ totalContinuations++;
22240
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
22241
+ const destRoute = timetable.getRoute(continuation.routeId);
22242
+ const destStopId = destRoute.stopId(continuation.hopOnStopIndex);
22243
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
22244
+ const destStop = stopsIndex.findStopById(destStopId);
22245
+ const destPlatform = destStop.platform
22246
+ ? ` (Pl. ${destStop.platform})`
22247
+ : '';
22248
+ const destServiceRouteInfo = timetable.getServiceRouteInfo(destRoute);
22249
+ const originTime = route.departureFrom(stopIndex, tripIndex);
22250
+ const continuationTime = destRoute.departureFrom(continuation.hopOnStopIndex, continuation.tripIndex);
22251
+ console.log(`${totalContinuations}. From Route ${route.id} (${serviceRouteInfo.name}) Trip ${tripIndex} at ${originTime.toString()} → ` +
22252
+ `Route ${continuation.routeId} (${destServiceRouteInfo.name}) Trip ${continuation.tripIndex} at ${continuationTime.toString()} ` +
22253
+ `at ${destStop.name}${destPlatform} (${destStopId}, ${destStop.sourceStopId})`);
22254
+ }
22214
22255
  }
22215
22256
  }
22216
22257
  });
22217
- console.log(`Number of trip continuations: ${totalContinuations}`);
22218
- if (totalContinuations > 0) {
22219
- console.log('\n--- Trip Continuations ---');
22220
- let continuationIndex = 1;
22221
- for (const [, value] of continuationsByTrip) {
22222
- const { route, tripIndex, continuations } = value;
22223
- const serviceRouteInfo = timetable.getServiceRouteInfo(route);
22224
- for (const continuation of continuations) {
22225
- const destStop = stopsIndex.findStopById(continuation.hopOnStop);
22226
- const destPlatform = (destStop === null || destStop === void 0 ? void 0 : destStop.platform)
22227
- ? ` (Pl. ${destStop.platform})`
22228
- : '';
22229
- const destRoute = timetable.getRoute(continuation.routeId);
22230
- const destServiceRouteInfo = destRoute
22231
- ? timetable.getServiceRouteInfo(destRoute)
22232
- : null;
22233
- const originTime = route.departureFrom(stop.id, tripIndex);
22234
- const continuationTime = destRoute === null || destRoute === void 0 ? void 0 : destRoute.departureFrom(continuation.hopOnStop, continuation.tripIndex);
22235
- const continuationTimeStr = continuationTime
22236
- ? ` at ${continuationTime.toString()}`
22237
- : '';
22238
- console.log(`${continuationIndex}. From Route ${route.id} (${serviceRouteInfo.name}) Trip ${tripIndex} at ${originTime.toString()} → ` +
22239
- `Route ${continuation.routeId} (${(_a = destServiceRouteInfo === null || destServiceRouteInfo === void 0 ? void 0 : destServiceRouteInfo.name) !== null && _a !== void 0 ? _a : 'Unknown'}) Trip ${continuation.tripIndex}${continuationTimeStr} ` +
22240
- `at ${(_b = destStop === null || destStop === void 0 ? void 0 : destStop.name) !== null && _b !== void 0 ? _b : 'Unknown'}${destPlatform} (${continuation.hopOnStop}, ${(_c = destStop === null || destStop === void 0 ? void 0 : destStop.sourceStopId) !== null && _c !== void 0 ? _c : 'N/A'})`);
22241
- continuationIndex++;
22242
- }
22243
- }
22258
+ if (totalContinuations === 0) {
22259
+ console.log('No trip continuations found.');
22260
+ }
22261
+ else {
22262
+ console.log(`\nTotal trip continuations: ${totalContinuations}`);
22244
22263
  }
22245
22264
  console.log();
22246
22265
  };
22247
22266
  if (type === 'route') {
22248
- inspectRoute(idStr !== null && idStr !== void 0 ? idStr : '');
22267
+ inspectRoute(idStr ?? '');
22249
22268
  }
22250
22269
  else {
22251
- inspectStop(idStr !== null && idStr !== void 0 ? idStr : '');
22270
+ inspectStop(idStr ?? '');
22252
22271
  }
22253
22272
  this.displayPrompt();
22254
22273
  },
@@ -22272,7 +22291,7 @@ program
22272
22291
  .option('-s, --stopsOutputPath <path>', 'Path to output stops file', '/tmp/stops')
22273
22292
  .option('-p, --profileName <name>', 'Profile name for GTFS config', 'CH')
22274
22293
  .option('-v, --verbose', 'Verbose mode', false)
22275
- .action((gtfsPath, options) => __awaiter(void 0, void 0, void 0, function* () {
22294
+ .action(async (gtfsPath, options) => {
22276
22295
  if (options.verbose) {
22277
22296
  log.setDefaultLevel(log.levels.INFO);
22278
22297
  }
@@ -22280,11 +22299,11 @@ program
22280
22299
  log.setDefaultLevel(log.levels.ERROR);
22281
22300
  }
22282
22301
  const parser = new GtfsParser(gtfsPath, profiles[options.profileName]);
22283
- const stopsIndex = yield parser.parseStops();
22302
+ const stopsIndex = await parser.parseStops();
22284
22303
  fs.writeFileSync(options.stopsOutputPath, stopsIndex.serialize());
22285
- const timetable = yield parser.parseTimetable(new Date(options.date));
22304
+ const timetable = await parser.parseTimetable(new Date(options.date));
22286
22305
  fs.writeFileSync(options.timetableOutputPath, timetable.serialize());
22287
- }));
22306
+ });
22288
22307
  program
22289
22308
  .command('parse-stops')
22290
22309
  .description('Parse a GTFS feed and output a stops file.')
@@ -22292,7 +22311,7 @@ program
22292
22311
  .option('-s, --outputPath <path>', 'Path to output stops file', '/tmp/stops')
22293
22312
  .option('-p, --profileName <name>', 'Profile name for GTFS config', 'CH')
22294
22313
  .option('-v, --verbose', 'Verbose mode', false)
22295
- .action((gtfsPath, options) => __awaiter(void 0, void 0, void 0, function* () {
22314
+ .action(async (gtfsPath, options) => {
22296
22315
  if (options.verbose) {
22297
22316
  log.setDefaultLevel(log.levels.INFO);
22298
22317
  }
@@ -22300,9 +22319,9 @@ program
22300
22319
  log.setDefaultLevel(log.levels.ERROR);
22301
22320
  }
22302
22321
  const parser = new GtfsParser(gtfsPath, profiles[options.profileName]);
22303
- const stopsIndex = yield parser.parseStops();
22322
+ const stopsIndex = await parser.parseStops();
22304
22323
  fs.writeFileSync(options.stopsOutputPath, stopsIndex.serialize());
22305
- }));
22324
+ });
22306
22325
  program
22307
22326
  .command('repl')
22308
22327
  .description('Find stops matching a textual query')