minotor 3.0.0 → 3.0.2

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 (81) hide show
  1. package/.cspell.json +14 -1
  2. package/.gitattributes +3 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +3 -0
  4. package/.github/workflows/minotor.yml +17 -1
  5. package/CHANGELOG.md +3 -9
  6. package/README.md +47 -17
  7. package/dist/__e2e__/router.test.d.ts +1 -0
  8. package/dist/cli/perf.d.ts +28 -0
  9. package/dist/cli/utils.d.ts +6 -2
  10. package/dist/cli.mjs +1967 -823
  11. package/dist/cli.mjs.map +1 -1
  12. package/dist/gtfs/trips.d.ts +1 -0
  13. package/dist/gtfs/utils.d.ts +1 -1
  14. package/dist/parser.cjs.js +1030 -627
  15. package/dist/parser.cjs.js.map +1 -1
  16. package/dist/parser.d.ts +4 -2
  17. package/dist/parser.esm.js +1030 -627
  18. package/dist/parser.esm.js.map +1 -1
  19. package/dist/router.cjs.js +1 -1
  20. package/dist/router.cjs.js.map +1 -1
  21. package/dist/router.d.ts +10 -5
  22. package/dist/router.esm.js +1 -1
  23. package/dist/router.esm.js.map +1 -1
  24. package/dist/router.umd.js +1 -1
  25. package/dist/router.umd.js.map +1 -1
  26. package/dist/routing/__tests__/result.test.d.ts +1 -0
  27. package/dist/routing/query.d.ts +27 -6
  28. package/dist/routing/result.d.ts +1 -1
  29. package/dist/routing/route.d.ts +47 -2
  30. package/dist/routing/router.d.ts +15 -1
  31. package/dist/stops/stopsIndex.d.ts +3 -3
  32. package/dist/timetable/__tests__/route.test.d.ts +1 -0
  33. package/dist/timetable/__tests__/time.test.d.ts +1 -0
  34. package/dist/timetable/io.d.ts +7 -1
  35. package/dist/timetable/proto/timetable.d.ts +1 -1
  36. package/dist/timetable/route.d.ts +155 -0
  37. package/dist/timetable/time.d.ts +21 -0
  38. package/dist/timetable/timetable.d.ts +41 -61
  39. package/package.json +36 -35
  40. package/src/__e2e__/benchmark.json +22 -0
  41. package/src/__e2e__/router.test.ts +209 -0
  42. package/src/__e2e__/timetable/stops.bin +3 -0
  43. package/src/__e2e__/timetable/timetable.bin +3 -0
  44. package/src/cli/minotor.ts +51 -1
  45. package/src/cli/perf.ts +136 -0
  46. package/src/cli/repl.ts +26 -13
  47. package/src/cli/utils.ts +6 -28
  48. package/src/gtfs/__tests__/parser.test.ts +12 -15
  49. package/src/gtfs/__tests__/services.test.ts +1 -0
  50. package/src/gtfs/__tests__/transfers.test.ts +0 -1
  51. package/src/gtfs/__tests__/trips.test.ts +67 -74
  52. package/src/gtfs/profiles/ch.ts +1 -1
  53. package/src/gtfs/routes.ts +4 -4
  54. package/src/gtfs/services.ts +15 -2
  55. package/src/gtfs/stops.ts +7 -3
  56. package/src/gtfs/transfers.ts +6 -3
  57. package/src/gtfs/trips.ts +33 -16
  58. package/src/gtfs/utils.ts +13 -2
  59. package/src/parser.ts +4 -2
  60. package/src/router.ts +17 -11
  61. package/src/routing/__tests__/result.test.ts +392 -0
  62. package/src/routing/__tests__/router.test.ts +94 -137
  63. package/src/routing/query.ts +28 -7
  64. package/src/routing/result.ts +10 -5
  65. package/src/routing/route.ts +95 -9
  66. package/src/routing/router.ts +82 -66
  67. package/src/stops/__tests__/io.test.ts +1 -1
  68. package/src/stops/__tests__/stopFinder.test.ts +1 -1
  69. package/src/stops/proto/stops.ts +4 -4
  70. package/src/stops/stopsIndex.ts +3 -3
  71. package/src/timetable/__tests__/io.test.ts +16 -23
  72. package/src/timetable/__tests__/route.test.ts +317 -0
  73. package/src/timetable/__tests__/time.test.ts +494 -0
  74. package/src/timetable/__tests__/timetable.test.ts +64 -75
  75. package/src/timetable/io.ts +32 -26
  76. package/src/timetable/proto/timetable.proto +1 -1
  77. package/src/timetable/proto/timetable.ts +13 -13
  78. package/src/timetable/route.ts +347 -0
  79. package/src/timetable/time.ts +40 -8
  80. package/src/timetable/timetable.ts +74 -165
  81. package/tsconfig.build.json +1 -1
@@ -39,7 +39,7 @@ function __values(o) {
39
39
  if (m) return m.call(o);
40
40
  if (o && typeof o.length === "number") return {
41
41
  next: function () {
42
- if (o && i >= o.length) o = undefined;
42
+ if (o && i >= o.length) o = void 0;
43
43
  return { value: o && o[i++], done: !o };
44
44
  }
45
45
  };
@@ -827,12 +827,13 @@ class SystemZone extends Zone {
827
827
  }
828
828
  }
829
829
 
830
- let dtfCache = {};
831
- function makeDTF(zone) {
832
- if (!dtfCache[zone]) {
833
- dtfCache[zone] = new Intl.DateTimeFormat("en-US", {
830
+ const dtfCache = new Map();
831
+ function makeDTF(zoneName) {
832
+ let dtf = dtfCache.get(zoneName);
833
+ if (dtf === undefined) {
834
+ dtf = new Intl.DateTimeFormat("en-US", {
834
835
  hour12: false,
835
- timeZone: zone,
836
+ timeZone: zoneName,
836
837
  year: "numeric",
837
838
  month: "2-digit",
838
839
  day: "2-digit",
@@ -841,8 +842,9 @@ function makeDTF(zone) {
841
842
  second: "2-digit",
842
843
  era: "short",
843
844
  });
845
+ dtfCache.set(zoneName, dtf);
844
846
  }
845
- return dtfCache[zone];
847
+ return dtf;
846
848
  }
847
849
 
848
850
  const typeToPos = {
@@ -878,7 +880,7 @@ function partsOffset(dtf, date) {
878
880
  return filled;
879
881
  }
880
882
 
881
- let ianaZoneCache = {};
883
+ const ianaZoneCache = new Map();
882
884
  /**
883
885
  * A zone identified by an IANA identifier, like America/New_York
884
886
  * @implements {Zone}
@@ -889,10 +891,11 @@ class IANAZone extends Zone {
889
891
  * @return {IANAZone}
890
892
  */
891
893
  static create(name) {
892
- if (!ianaZoneCache[name]) {
893
- ianaZoneCache[name] = new IANAZone(name);
894
+ let zone = ianaZoneCache.get(name);
895
+ if (zone === undefined) {
896
+ ianaZoneCache.set(name, (zone = new IANAZone(name)));
894
897
  }
895
- return ianaZoneCache[name];
898
+ return zone;
896
899
  }
897
900
 
898
901
  /**
@@ -900,8 +903,8 @@ class IANAZone extends Zone {
900
903
  * @return {void}
901
904
  */
902
905
  static resetCache() {
903
- ianaZoneCache = {};
904
- dtfCache = {};
906
+ ianaZoneCache.clear();
907
+ dtfCache.clear();
905
908
  }
906
909
 
907
910
  /**
@@ -1004,6 +1007,7 @@ class IANAZone extends Zone {
1004
1007
  * @return {number}
1005
1008
  */
1006
1009
  offset(ts) {
1010
+ if (!this.valid) return NaN;
1007
1011
  const date = new Date(ts);
1008
1012
 
1009
1013
  if (isNaN(date)) return NaN;
@@ -1069,36 +1073,36 @@ function getCachedLF(locString, opts = {}) {
1069
1073
  return dtf;
1070
1074
  }
1071
1075
 
1072
- let intlDTCache = {};
1076
+ const intlDTCache = new Map();
1073
1077
  function getCachedDTF(locString, opts = {}) {
1074
1078
  const key = JSON.stringify([locString, opts]);
1075
- let dtf = intlDTCache[key];
1076
- if (!dtf) {
1079
+ let dtf = intlDTCache.get(key);
1080
+ if (dtf === undefined) {
1077
1081
  dtf = new Intl.DateTimeFormat(locString, opts);
1078
- intlDTCache[key] = dtf;
1082
+ intlDTCache.set(key, dtf);
1079
1083
  }
1080
1084
  return dtf;
1081
1085
  }
1082
1086
 
1083
- let intlNumCache = {};
1087
+ const intlNumCache = new Map();
1084
1088
  function getCachedINF(locString, opts = {}) {
1085
1089
  const key = JSON.stringify([locString, opts]);
1086
- let inf = intlNumCache[key];
1087
- if (!inf) {
1090
+ let inf = intlNumCache.get(key);
1091
+ if (inf === undefined) {
1088
1092
  inf = new Intl.NumberFormat(locString, opts);
1089
- intlNumCache[key] = inf;
1093
+ intlNumCache.set(key, inf);
1090
1094
  }
1091
1095
  return inf;
1092
1096
  }
1093
1097
 
1094
- let intlRelCache = {};
1098
+ const intlRelCache = new Map();
1095
1099
  function getCachedRTF(locString, opts = {}) {
1096
1100
  const { base, ...cacheKeyOpts } = opts; // exclude `base` from the options
1097
1101
  const key = JSON.stringify([locString, cacheKeyOpts]);
1098
- let inf = intlRelCache[key];
1099
- if (!inf) {
1102
+ let inf = intlRelCache.get(key);
1103
+ if (inf === undefined) {
1100
1104
  inf = new Intl.RelativeTimeFormat(locString, opts);
1101
- intlRelCache[key] = inf;
1105
+ intlRelCache.set(key, inf);
1102
1106
  }
1103
1107
  return inf;
1104
1108
  }
@@ -1113,14 +1117,28 @@ function systemLocale() {
1113
1117
  }
1114
1118
  }
1115
1119
 
1116
- let weekInfoCache = {};
1120
+ const intlResolvedOptionsCache = new Map();
1121
+ function getCachedIntResolvedOptions(locString) {
1122
+ let opts = intlResolvedOptionsCache.get(locString);
1123
+ if (opts === undefined) {
1124
+ opts = new Intl.DateTimeFormat(locString).resolvedOptions();
1125
+ intlResolvedOptionsCache.set(locString, opts);
1126
+ }
1127
+ return opts;
1128
+ }
1129
+
1130
+ const weekInfoCache = new Map();
1117
1131
  function getCachedWeekInfo(locString) {
1118
- let data = weekInfoCache[locString];
1132
+ let data = weekInfoCache.get(locString);
1119
1133
  if (!data) {
1120
1134
  const locale = new Intl.Locale(locString);
1121
1135
  // browsers currently implement this as a property, but spec says it should be a getter function
1122
1136
  data = "getWeekInfo" in locale ? locale.getWeekInfo() : locale.weekInfo;
1123
- weekInfoCache[locString] = data;
1137
+ // minimalDays was removed from WeekInfo: https://github.com/tc39/proposal-intl-locale-info/issues/86
1138
+ if (!("minimalDays" in data)) {
1139
+ data = { ...fallbackWeekSettings, ...data };
1140
+ }
1141
+ weekInfoCache.set(locString, data);
1124
1142
  }
1125
1143
  return data;
1126
1144
  }
@@ -1219,7 +1237,7 @@ function supportsFastNumbers(loc) {
1219
1237
  loc.numberingSystem === "latn" ||
1220
1238
  !loc.locale ||
1221
1239
  loc.locale.startsWith("en") ||
1222
- new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem === "latn"
1240
+ getCachedIntResolvedOptions(loc.locale).numberingSystem === "latn"
1223
1241
  );
1224
1242
  }
1225
1243
  }
@@ -1378,7 +1396,6 @@ const fallbackWeekSettings = {
1378
1396
  /**
1379
1397
  * @private
1380
1398
  */
1381
-
1382
1399
  class Locale {
1383
1400
  static fromOpts(opts) {
1384
1401
  return Locale.create(
@@ -1402,9 +1419,11 @@ class Locale {
1402
1419
 
1403
1420
  static resetCache() {
1404
1421
  sysLocaleCache = null;
1405
- intlDTCache = {};
1406
- intlNumCache = {};
1407
- intlRelCache = {};
1422
+ intlDTCache.clear();
1423
+ intlNumCache.clear();
1424
+ intlRelCache.clear();
1425
+ intlResolvedOptionsCache.clear();
1426
+ weekInfoCache.clear();
1408
1427
  }
1409
1428
 
1410
1429
  static fromObject({ locale, numberingSystem, outputCalendar, weekSettings } = {}) {
@@ -1469,10 +1488,18 @@ class Locale {
1469
1488
 
1470
1489
  months(length, format = false) {
1471
1490
  return listStuff(this, length, months, () => {
1491
+ // Workaround for "ja" locale: formatToParts does not label all parts of the month
1492
+ // as "month" and for this locale there is no difference between "format" and "non-format".
1493
+ // As such, just use format() instead of formatToParts() and take the whole string
1494
+ const monthSpecialCase = this.intl === "ja" || this.intl.startsWith("ja-");
1495
+ format &= !monthSpecialCase;
1472
1496
  const intl = format ? { month: length, day: "numeric" } : { month: length },
1473
1497
  formatStr = format ? "format" : "standalone";
1474
1498
  if (!this.monthsCache[formatStr][length]) {
1475
- this.monthsCache[formatStr][length] = mapMonths((dt) => this.extract(dt, intl, "month"));
1499
+ const mapper = !monthSpecialCase
1500
+ ? (dt) => this.extract(dt, intl, "month")
1501
+ : (dt) => this.dtFormatter(dt, intl).format();
1502
+ this.monthsCache[formatStr][length] = mapMonths(mapper);
1476
1503
  }
1477
1504
  return this.monthsCache[formatStr][length];
1478
1505
  });
@@ -1558,7 +1585,7 @@ class Locale {
1558
1585
  return (
1559
1586
  this.locale === "en" ||
1560
1587
  this.locale.toLowerCase() === "en-us" ||
1561
- new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us")
1588
+ getCachedIntResolvedOptions(this.intl).locale.startsWith("en-us")
1562
1589
  );
1563
1590
  }
1564
1591
 
@@ -1897,22 +1924,26 @@ function parseDigits(str) {
1897
1924
  }
1898
1925
 
1899
1926
  // cache of {numberingSystem: {append: regex}}
1900
- let digitRegexCache = {};
1927
+ const digitRegexCache = new Map();
1901
1928
  function resetDigitRegexCache() {
1902
- digitRegexCache = {};
1929
+ digitRegexCache.clear();
1903
1930
  }
1904
1931
 
1905
1932
  function digitRegex({ numberingSystem }, append = "") {
1906
1933
  const ns = numberingSystem || "latn";
1907
1934
 
1908
- if (!digitRegexCache[ns]) {
1909
- digitRegexCache[ns] = {};
1935
+ let appendCache = digitRegexCache.get(ns);
1936
+ if (appendCache === undefined) {
1937
+ appendCache = new Map();
1938
+ digitRegexCache.set(ns, appendCache);
1910
1939
  }
1911
- if (!digitRegexCache[ns][append]) {
1912
- digitRegexCache[ns][append] = new RegExp(`${numberingSystems[ns]}${append}`);
1940
+ let regex = appendCache.get(append);
1941
+ if (regex === undefined) {
1942
+ regex = new RegExp(`${numberingSystems[ns]}${append}`);
1943
+ appendCache.set(append, regex);
1913
1944
  }
1914
1945
 
1915
- return digitRegexCache[ns][append];
1946
+ return regex;
1916
1947
  }
1917
1948
 
1918
1949
  let now = () => Date.now(),
@@ -2454,10 +2485,24 @@ function parseMillis(fraction) {
2454
2485
  }
2455
2486
  }
2456
2487
 
2457
- function roundTo(number, digits, towardZero = false) {
2458
- const factor = 10 ** digits,
2459
- rounder = towardZero ? Math.trunc : Math.round;
2460
- return rounder(number * factor) / factor;
2488
+ function roundTo(number, digits, rounding = "round") {
2489
+ const factor = 10 ** digits;
2490
+ switch (rounding) {
2491
+ case "expand":
2492
+ return number > 0
2493
+ ? Math.ceil(number * factor) / factor
2494
+ : Math.floor(number * factor) / factor;
2495
+ case "trunc":
2496
+ return Math.trunc(number * factor) / factor;
2497
+ case "round":
2498
+ return Math.round(number * factor) / factor;
2499
+ case "floor":
2500
+ return Math.floor(number * factor) / factor;
2501
+ case "ceil":
2502
+ return Math.ceil(number * factor) / factor;
2503
+ default:
2504
+ throw new RangeError(`Value rounding ${rounding} is out of range`);
2505
+ }
2461
2506
  }
2462
2507
 
2463
2508
  // DATE BASICS
@@ -2565,7 +2610,7 @@ function signedOffset(offHourStr, offMinuteStr) {
2565
2610
 
2566
2611
  function asNumber(value) {
2567
2612
  const numericValue = Number(value);
2568
- if (typeof value === "boolean" || value === "" || Number.isNaN(numericValue))
2613
+ if (typeof value === "boolean" || value === "" || !Number.isFinite(numericValue))
2569
2614
  throw new InvalidArgumentError(`Invalid unit value ${value}`);
2570
2615
  return numericValue;
2571
2616
  }
@@ -2824,8 +2869,12 @@ class Formatter {
2824
2869
  for (let i = 0; i < fmt.length; i++) {
2825
2870
  const c = fmt.charAt(i);
2826
2871
  if (c === "'") {
2827
- if (currentFull.length > 0) {
2828
- splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull });
2872
+ // turn '' into a literal signal quote instead of just skipping the empty literal
2873
+ if (currentFull.length > 0 || bracketed) {
2874
+ splits.push({
2875
+ literal: bracketed || /^\s+$/.test(currentFull),
2876
+ val: currentFull === "" ? "'" : currentFull,
2877
+ });
2829
2878
  }
2830
2879
  current = null;
2831
2880
  currentFull = "";
@@ -2889,7 +2938,7 @@ class Formatter {
2889
2938
  return this.dtFormatter(dt, opts).resolvedOptions();
2890
2939
  }
2891
2940
 
2892
- num(n, p = 0) {
2941
+ num(n, p = 0, signDisplay = undefined) {
2893
2942
  // we get some perf out of doing this here, annoyingly
2894
2943
  if (this.opts.forceSimple) {
2895
2944
  return padStart(n, p);
@@ -2900,6 +2949,9 @@ class Formatter {
2900
2949
  if (p > 0) {
2901
2950
  opts.padTo = p;
2902
2951
  }
2952
+ if (signDisplay) {
2953
+ opts.signDisplay = signDisplay;
2954
+ }
2903
2955
 
2904
2956
  return this.loc.numberFormatter(opts).format(n);
2905
2957
  }
@@ -3135,32 +3187,44 @@ class Formatter {
3135
3187
  }
3136
3188
 
3137
3189
  formatDurationFromString(dur, fmt) {
3190
+ const invertLargest = this.opts.signMode === "negativeLargestOnly" ? -1 : 1;
3138
3191
  const tokenToField = (token) => {
3139
3192
  switch (token[0]) {
3140
3193
  case "S":
3141
- return "millisecond";
3194
+ return "milliseconds";
3142
3195
  case "s":
3143
- return "second";
3196
+ return "seconds";
3144
3197
  case "m":
3145
- return "minute";
3198
+ return "minutes";
3146
3199
  case "h":
3147
- return "hour";
3200
+ return "hours";
3148
3201
  case "d":
3149
- return "day";
3202
+ return "days";
3150
3203
  case "w":
3151
- return "week";
3204
+ return "weeks";
3152
3205
  case "M":
3153
- return "month";
3206
+ return "months";
3154
3207
  case "y":
3155
- return "year";
3208
+ return "years";
3156
3209
  default:
3157
3210
  return null;
3158
3211
  }
3159
3212
  },
3160
- tokenToString = (lildur) => (token) => {
3213
+ tokenToString = (lildur, info) => (token) => {
3161
3214
  const mapped = tokenToField(token);
3162
3215
  if (mapped) {
3163
- return this.num(lildur.get(mapped), token.length);
3216
+ const inversionFactor =
3217
+ info.isNegativeDuration && mapped !== info.largestUnit ? invertLargest : 1;
3218
+ let signDisplay;
3219
+ if (this.opts.signMode === "negativeLargestOnly" && mapped !== info.largestUnit) {
3220
+ signDisplay = "never";
3221
+ } else if (this.opts.signMode === "all") {
3222
+ signDisplay = "always";
3223
+ } else {
3224
+ // "auto" and "negative" are the same, but "auto" has better support
3225
+ signDisplay = "auto";
3226
+ }
3227
+ return this.num(lildur.get(mapped) * inversionFactor, token.length, signDisplay);
3164
3228
  } else {
3165
3229
  return token;
3166
3230
  }
@@ -3170,8 +3234,14 @@ class Formatter {
3170
3234
  (found, { literal, val }) => (literal ? found : found.concat(val)),
3171
3235
  []
3172
3236
  ),
3173
- collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter((t) => t));
3174
- return stringifyTokens(tokens, tokenToString(collapsed));
3237
+ collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter((t) => t)),
3238
+ durationInfo = {
3239
+ isNegativeDuration: collapsed < 0,
3240
+ // this relies on "collapsed" being based on "shiftTo", which builds up the object
3241
+ // in order
3242
+ largestUnit: Object.keys(collapsed.values)[0],
3243
+ };
3244
+ return stringifyTokens(tokens, tokenToString(collapsed, durationInfo));
3175
3245
  }
3176
3246
  }
3177
3247
 
@@ -3232,11 +3302,11 @@ function simpleParse(...keys) {
3232
3302
  }
3233
3303
 
3234
3304
  // ISO and SQL parsing
3235
- const offsetRegex = /(?:(Z)|([+-]\d\d)(?::?(\d\d))?)/;
3305
+ const offsetRegex = /(?:([Zz])|([+-]\d\d)(?::?(\d\d))?)/;
3236
3306
  const isoExtendedZone = `(?:${offsetRegex.source}?(?:\\[(${ianaRegex.source})\\])?)?`;
3237
3307
  const isoTimeBaseRegex = /(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?/;
3238
3308
  const isoTimeRegex = RegExp(`${isoTimeBaseRegex.source}${isoExtendedZone}`);
3239
- const isoTimeExtensionRegex = RegExp(`(?:T${isoTimeRegex.source})?`);
3309
+ const isoTimeExtensionRegex = RegExp(`(?:[Tt]${isoTimeRegex.source})?`);
3240
3310
  const isoYmdRegex = /([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/;
3241
3311
  const isoWeekRegex = /(\d{4})-?W(\d\d)(?:-?(\d))?/;
3242
3312
  const isoOrdinalRegex = /(\d{4})-?(\d{3})/;
@@ -3951,9 +4021,13 @@ let Duration$1 = class Duration {
3951
4021
  * @param {string} fmt - the format string
3952
4022
  * @param {Object} opts - options
3953
4023
  * @param {boolean} [opts.floor=true] - floor numerical values
4024
+ * @param {'negative'|'all'|'negativeLargestOnly'} [opts.signMode=negative] - How to handle signs
3954
4025
  * @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toFormat("y d s") //=> "1 6 2"
3955
4026
  * @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toFormat("yy dd sss") //=> "01 06 002"
3956
4027
  * @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toFormat("M S") //=> "12 518402000"
4028
+ * @example Duration.fromObject({ days: 6, seconds: 2 }).toFormat("d s", { signMode: "all" }) //=> "+6 +2"
4029
+ * @example Duration.fromObject({ days: -6, seconds: -2 }).toFormat("d s", { signMode: "all" }) //=> "-6 -2"
4030
+ * @example Duration.fromObject({ days: -6, seconds: -2 }).toFormat("d s", { signMode: "negativeLargestOnly" }) //=> "-6 2"
3957
4031
  * @return {string}
3958
4032
  */
3959
4033
  toFormat(fmt, opts = {}) {
@@ -3973,21 +4047,25 @@ let Duration$1 = class Duration {
3973
4047
  * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options
3974
4048
  * @param {Object} opts - Formatting options. Accepts the same keys as the options parameter of the native `Intl.NumberFormat` constructor, as well as `listStyle`.
3975
4049
  * @param {string} [opts.listStyle='narrow'] - How to format the merged list. Corresponds to the `style` property of the options parameter of the native `Intl.ListFormat` constructor.
4050
+ * @param {boolean} [opts.showZeros=true] - Show all units previously used by the duration even if they are zero
3976
4051
  * @example
3977
4052
  * ```js
3978
- * var dur = Duration.fromObject({ days: 1, hours: 5, minutes: 6 })
3979
- * dur.toHuman() //=> '1 day, 5 hours, 6 minutes'
3980
- * dur.toHuman({ listStyle: "long" }) //=> '1 day, 5 hours, and 6 minutes'
3981
- * dur.toHuman({ unitDisplay: "short" }) //=> '1 day, 5 hr, 6 min'
4053
+ * var dur = Duration.fromObject({ months: 1, weeks: 0, hours: 5, minutes: 6 })
4054
+ * dur.toHuman() //=> '1 month, 0 weeks, 5 hours, 6 minutes'
4055
+ * dur.toHuman({ listStyle: "long" }) //=> '1 month, 0 weeks, 5 hours, and 6 minutes'
4056
+ * dur.toHuman({ unitDisplay: "short" }) //=> '1 mth, 0 wks, 5 hr, 6 min'
4057
+ * dur.toHuman({ showZeros: false }) //=> '1 month, 5 hours, 6 minutes'
3982
4058
  * ```
3983
4059
  */
3984
4060
  toHuman(opts = {}) {
3985
4061
  if (!this.isValid) return INVALID$2;
3986
4062
 
4063
+ const showZeros = opts.showZeros !== false;
4064
+
3987
4065
  const l = orderedUnits$1
3988
4066
  .map((unit) => {
3989
4067
  const val = this.values[unit];
3990
- if (isUndefined(val)) {
4068
+ if (isUndefined(val) || (val === 0 && !showZeros)) {
3991
4069
  return null;
3992
4070
  }
3993
4071
  return this.loc
@@ -4347,6 +4425,17 @@ let Duration$1 = class Duration {
4347
4425
  return clone$1(this, { values: negated }, true);
4348
4426
  }
4349
4427
 
4428
+ /**
4429
+ * Removes all units with values equal to 0 from this Duration.
4430
+ * @example Duration.fromObject({ years: 2, days: 0, hours: 0, minutes: 0 }).removeZeros().toObject() //=> { years: 2 }
4431
+ * @return {Duration}
4432
+ */
4433
+ removeZeros() {
4434
+ if (!this.isValid) return this;
4435
+ const vals = removeZeroes(this.values);
4436
+ return clone$1(this, { values: vals }, true);
4437
+ }
4438
+
4350
4439
  /**
4351
4440
  * Get the years.
4352
4441
  * @type {number}
@@ -4657,13 +4746,22 @@ class Interval {
4657
4746
  }
4658
4747
 
4659
4748
  /**
4660
- * Returns the end of the Interval
4749
+ * Returns the end of the Interval. This is the first instant which is not part of the interval
4750
+ * (Interval is half-open).
4661
4751
  * @type {DateTime}
4662
4752
  */
4663
4753
  get end() {
4664
4754
  return this.isValid ? this.e : null;
4665
4755
  }
4666
4756
 
4757
+ /**
4758
+ * Returns the last DateTime included in the interval (since end is not part of the interval)
4759
+ * @type {DateTime}
4760
+ */
4761
+ get lastDateTime() {
4762
+ return this.isValid ? (this.e ? this.e.minus(1) : null) : null;
4763
+ }
4764
+
4667
4765
  /**
4668
4766
  * Returns whether this Interval's end is at least its start, meaning that the Interval isn't 'backwards'.
4669
4767
  * @type {boolean}
@@ -4928,8 +5026,11 @@ class Interval {
4928
5026
  }
4929
5027
 
4930
5028
  /**
4931
- * Merge an array of Intervals into a equivalent minimal set of Intervals.
5029
+ * Merge an array of Intervals into an equivalent minimal set of Intervals.
4932
5030
  * Combines overlapping and adjacent Intervals.
5031
+ * The resulting array will contain the Intervals in ascending order, that is, starting with the earliest Interval
5032
+ * and ending with the latest.
5033
+ *
4933
5034
  * @param {Array} intervals
4934
5035
  * @return {Array}
4935
5036
  */
@@ -6077,21 +6178,22 @@ function toTechFormat(dt, format, allowZ = true) {
6077
6178
  : null;
6078
6179
  }
6079
6180
 
6080
- function toISODate(o, extended) {
6181
+ function toISODate(o, extended, precision) {
6081
6182
  const longFormat = o.c.year > 9999 || o.c.year < 0;
6082
6183
  let c = "";
6083
6184
  if (longFormat && o.c.year >= 0) c += "+";
6084
6185
  c += padStart(o.c.year, longFormat ? 6 : 4);
6085
-
6186
+ if (precision === "year") return c;
6086
6187
  if (extended) {
6087
6188
  c += "-";
6088
6189
  c += padStart(o.c.month);
6190
+ if (precision === "month") return c;
6089
6191
  c += "-";
6090
- c += padStart(o.c.day);
6091
6192
  } else {
6092
6193
  c += padStart(o.c.month);
6093
- c += padStart(o.c.day);
6194
+ if (precision === "month") return c;
6094
6195
  }
6196
+ c += padStart(o.c.day);
6095
6197
  return c;
6096
6198
  }
6097
6199
 
@@ -6101,26 +6203,39 @@ function toISOTime(
6101
6203
  suppressSeconds,
6102
6204
  suppressMilliseconds,
6103
6205
  includeOffset,
6104
- extendedZone
6206
+ extendedZone,
6207
+ precision
6105
6208
  ) {
6106
- let c = padStart(o.c.hour);
6107
- if (extended) {
6108
- c += ":";
6109
- c += padStart(o.c.minute);
6110
- if (o.c.millisecond !== 0 || o.c.second !== 0 || !suppressSeconds) {
6111
- c += ":";
6112
- }
6113
- } else {
6114
- c += padStart(o.c.minute);
6115
- }
6116
-
6117
- if (o.c.millisecond !== 0 || o.c.second !== 0 || !suppressSeconds) {
6118
- c += padStart(o.c.second);
6119
-
6120
- if (o.c.millisecond !== 0 || !suppressMilliseconds) {
6121
- c += ".";
6122
- c += padStart(o.c.millisecond, 3);
6123
- }
6209
+ let showSeconds = !suppressSeconds || o.c.millisecond !== 0 || o.c.second !== 0,
6210
+ c = "";
6211
+ switch (precision) {
6212
+ case "day":
6213
+ case "month":
6214
+ case "year":
6215
+ break;
6216
+ default:
6217
+ c += padStart(o.c.hour);
6218
+ if (precision === "hour") break;
6219
+ if (extended) {
6220
+ c += ":";
6221
+ c += padStart(o.c.minute);
6222
+ if (precision === "minute") break;
6223
+ if (showSeconds) {
6224
+ c += ":";
6225
+ c += padStart(o.c.second);
6226
+ }
6227
+ } else {
6228
+ c += padStart(o.c.minute);
6229
+ if (precision === "minute") break;
6230
+ if (showSeconds) {
6231
+ c += padStart(o.c.second);
6232
+ }
6233
+ }
6234
+ if (precision === "second") break;
6235
+ if (showSeconds && (!suppressMilliseconds || o.c.millisecond !== 0)) {
6236
+ c += ".";
6237
+ c += padStart(o.c.millisecond, 3);
6238
+ }
6124
6239
  }
6125
6240
 
6126
6241
  if (includeOffset) {
@@ -6252,15 +6367,27 @@ function normalizeUnitWithLocalWeeks(unit) {
6252
6367
  // This is safe for quickDT (used by local() and utc()) because we don't fill in
6253
6368
  // higher-order units from tsNow (as we do in fromObject, this requires that
6254
6369
  // offset is calculated from tsNow).
6370
+ /**
6371
+ * @param {Zone} zone
6372
+ * @return {number}
6373
+ */
6255
6374
  function guessOffsetForZone(zone) {
6256
- if (!zoneOffsetGuessCache[zone]) {
6257
- if (zoneOffsetTs === undefined) {
6258
- zoneOffsetTs = Settings.now();
6259
- }
6375
+ if (zoneOffsetTs === undefined) {
6376
+ zoneOffsetTs = Settings.now();
6377
+ }
6260
6378
 
6261
- zoneOffsetGuessCache[zone] = zone.offset(zoneOffsetTs);
6379
+ // Do not cache anything but IANA zones, because it is not safe to do so.
6380
+ // Guessing an offset which is not present in the zone can cause wrong results from fixOffset
6381
+ if (zone.type !== "iana") {
6382
+ return zone.offset(zoneOffsetTs);
6262
6383
  }
6263
- return zoneOffsetGuessCache[zone];
6384
+ const zoneName = zone.name;
6385
+ let offsetGuess = zoneOffsetGuessCache.get(zoneName);
6386
+ if (offsetGuess === undefined) {
6387
+ offsetGuess = zone.offset(zoneOffsetTs);
6388
+ zoneOffsetGuessCache.set(zoneName, offsetGuess);
6389
+ }
6390
+ return offsetGuess;
6264
6391
  }
6265
6392
 
6266
6393
  // this is a dumbed down version of fromObject() that runs about 60% faster
@@ -6300,8 +6427,9 @@ function quickDT(obj, opts) {
6300
6427
 
6301
6428
  function diffRelative(start, end, opts) {
6302
6429
  const round = isUndefined(opts.round) ? true : opts.round,
6430
+ rounding = isUndefined(opts.rounding) ? "trunc" : opts.rounding,
6303
6431
  format = (c, unit) => {
6304
- c = roundTo(c, round || opts.calendary ? 0 : 2, true);
6432
+ c = roundTo(c, round || opts.calendary ? 0 : 2, opts.calendary ? "round" : rounding);
6305
6433
  const formatter = end.loc.clone(opts).relFormatter(opts);
6306
6434
  return formatter.format(c, unit);
6307
6435
  },
@@ -6350,7 +6478,7 @@ let zoneOffsetTs;
6350
6478
  * This optimizes quickDT via guessOffsetForZone to avoid repeated calls of
6351
6479
  * zone.offset().
6352
6480
  */
6353
- let zoneOffsetGuessCache = {};
6481
+ const zoneOffsetGuessCache = new Map();
6354
6482
 
6355
6483
  /**
6356
6484
  * A DateTime is an immutable data structure representing a specific date and time and accompanying methods. It contains class and instance methods for creating, parsing, interrogating, transforming, and formatting them.
@@ -6554,7 +6682,7 @@ class DateTime {
6554
6682
  throw new InvalidArgumentError(
6555
6683
  `fromMillis requires a numerical input, but received a ${typeof milliseconds} with value ${milliseconds}`
6556
6684
  );
6557
- } else if (milliseconds < -864e13 || milliseconds > MAX_DATE) {
6685
+ } else if (milliseconds < -MAX_DATE || milliseconds > MAX_DATE) {
6558
6686
  // this isn't perfect because we can still end up out of range because of additional shifting, but it's a start
6559
6687
  return DateTime.invalid("Timestamp out of range");
6560
6688
  } else {
@@ -6915,7 +7043,7 @@ class DateTime {
6915
7043
 
6916
7044
  static resetCache() {
6917
7045
  zoneOffsetTs = undefined;
6918
- zoneOffsetGuessCache = {};
7046
+ zoneOffsetGuessCache.clear();
6919
7047
  }
6920
7048
 
6921
7049
  // INFO
@@ -7680,11 +7808,14 @@ class DateTime {
7680
7808
  * @param {boolean} [opts.includeOffset=true] - include the offset, such as 'Z' or '-04:00'
7681
7809
  * @param {boolean} [opts.extendedZone=false] - add the time zone format extension
7682
7810
  * @param {string} [opts.format='extended'] - choose between the basic and extended format
7811
+ * @param {string} [opts.precision='milliseconds'] - truncate output to desired presicion: 'years', 'months', 'days', 'hours', 'minutes', 'seconds' or 'milliseconds'. When precision and suppressSeconds or suppressMilliseconds are used together, precision sets the maximum unit shown in the output, however seconds or milliseconds will still be suppressed if they are 0.
7683
7812
  * @example DateTime.utc(1983, 5, 25).toISO() //=> '1982-05-25T00:00:00.000Z'
7684
7813
  * @example DateTime.now().toISO() //=> '2017-04-22T20:47:05.335-04:00'
7685
7814
  * @example DateTime.now().toISO({ includeOffset: false }) //=> '2017-04-22T20:47:05.335'
7686
7815
  * @example DateTime.now().toISO({ format: 'basic' }) //=> '20170422T204705.335-0400'
7687
- * @return {string}
7816
+ * @example DateTime.now().toISO({ precision: 'day' }) //=> '2017-04-22Z'
7817
+ * @example DateTime.now().toISO({ precision: 'minute' }) //=> '2017-04-22T20:47Z'
7818
+ * @return {string|null}
7688
7819
  */
7689
7820
  toISO({
7690
7821
  format = "extended",
@@ -7692,16 +7823,26 @@ class DateTime {
7692
7823
  suppressMilliseconds = false,
7693
7824
  includeOffset = true,
7694
7825
  extendedZone = false,
7826
+ precision = "milliseconds",
7695
7827
  } = {}) {
7696
7828
  if (!this.isValid) {
7697
7829
  return null;
7698
7830
  }
7699
7831
 
7832
+ precision = normalizeUnit(precision);
7700
7833
  const ext = format === "extended";
7701
7834
 
7702
- let c = toISODate(this, ext);
7703
- c += "T";
7704
- c += toISOTime(this, ext, suppressSeconds, suppressMilliseconds, includeOffset, extendedZone);
7835
+ let c = toISODate(this, ext, precision);
7836
+ if (orderedUnits.indexOf(precision) >= 3) c += "T";
7837
+ c += toISOTime(
7838
+ this,
7839
+ ext,
7840
+ suppressSeconds,
7841
+ suppressMilliseconds,
7842
+ includeOffset,
7843
+ extendedZone,
7844
+ precision
7845
+ );
7705
7846
  return c;
7706
7847
  }
7707
7848
 
@@ -7709,16 +7850,17 @@ class DateTime {
7709
7850
  * Returns an ISO 8601-compliant string representation of this DateTime's date component
7710
7851
  * @param {Object} opts - options
7711
7852
  * @param {string} [opts.format='extended'] - choose between the basic and extended format
7853
+ * @param {string} [opts.precision='day'] - truncate output to desired precision: 'years', 'months', or 'days'.
7712
7854
  * @example DateTime.utc(1982, 5, 25).toISODate() //=> '1982-05-25'
7713
7855
  * @example DateTime.utc(1982, 5, 25).toISODate({ format: 'basic' }) //=> '19820525'
7714
- * @return {string}
7856
+ * @example DateTime.utc(1982, 5, 25).toISODate({ precision: 'month' }) //=> '1982-05'
7857
+ * @return {string|null}
7715
7858
  */
7716
- toISODate({ format = "extended" } = {}) {
7859
+ toISODate({ format = "extended", precision = "day" } = {}) {
7717
7860
  if (!this.isValid) {
7718
7861
  return null;
7719
7862
  }
7720
-
7721
- return toISODate(this, format === "extended");
7863
+ return toISODate(this, format === "extended", normalizeUnit(precision));
7722
7864
  }
7723
7865
 
7724
7866
  /**
@@ -7739,10 +7881,12 @@ class DateTime {
7739
7881
  * @param {boolean} [opts.extendedZone=true] - add the time zone format extension
7740
7882
  * @param {boolean} [opts.includePrefix=false] - include the `T` prefix
7741
7883
  * @param {string} [opts.format='extended'] - choose between the basic and extended format
7884
+ * @param {string} [opts.precision='milliseconds'] - truncate output to desired presicion: 'hours', 'minutes', 'seconds' or 'milliseconds'. When precision and suppressSeconds or suppressMilliseconds are used together, precision sets the maximum unit shown in the output, however seconds or milliseconds will still be suppressed if they are 0.
7742
7885
  * @example DateTime.utc().set({ hour: 7, minute: 34 }).toISOTime() //=> '07:34:19.361Z'
7743
7886
  * @example DateTime.utc().set({ hour: 7, minute: 34, seconds: 0, milliseconds: 0 }).toISOTime({ suppressSeconds: true }) //=> '07:34Z'
7744
7887
  * @example DateTime.utc().set({ hour: 7, minute: 34 }).toISOTime({ format: 'basic' }) //=> '073419.361Z'
7745
7888
  * @example DateTime.utc().set({ hour: 7, minute: 34 }).toISOTime({ includePrefix: true }) //=> 'T07:34:19.361Z'
7889
+ * @example DateTime.utc().set({ hour: 7, minute: 34, second: 56 }).toISOTime({ precision: 'minute' }) //=> '07:34Z'
7746
7890
  * @return {string}
7747
7891
  */
7748
7892
  toISOTime({
@@ -7752,12 +7896,14 @@ class DateTime {
7752
7896
  includePrefix = false,
7753
7897
  extendedZone = false,
7754
7898
  format = "extended",
7899
+ precision = "milliseconds",
7755
7900
  } = {}) {
7756
7901
  if (!this.isValid) {
7757
7902
  return null;
7758
7903
  }
7759
7904
 
7760
- let c = includePrefix ? "T" : "";
7905
+ precision = normalizeUnit(precision);
7906
+ let c = includePrefix && orderedUnits.indexOf(precision) >= 3 ? "T" : "";
7761
7907
  return (
7762
7908
  c +
7763
7909
  toISOTime(
@@ -7766,7 +7912,8 @@ class DateTime {
7766
7912
  suppressSeconds,
7767
7913
  suppressMilliseconds,
7768
7914
  includeOffset,
7769
- extendedZone
7915
+ extendedZone,
7916
+ precision
7770
7917
  )
7771
7918
  );
7772
7919
  }
@@ -7796,7 +7943,7 @@ class DateTime {
7796
7943
  /**
7797
7944
  * Returns a string representation of this DateTime appropriate for use in SQL Date
7798
7945
  * @example DateTime.utc(2014, 7, 13).toSQLDate() //=> '2014-07-13'
7799
- * @return {string}
7946
+ * @return {string|null}
7800
7947
  */
7801
7948
  toSQLDate() {
7802
7949
  if (!this.isValid) {
@@ -7891,7 +8038,7 @@ class DateTime {
7891
8038
  }
7892
8039
 
7893
8040
  /**
7894
- * Returns the epoch seconds of this DateTime.
8041
+ * Returns the epoch seconds (including milliseconds in the fractional part) of this DateTime.
7895
8042
  * @return {number}
7896
8043
  */
7897
8044
  toSeconds() {
@@ -7998,7 +8145,7 @@ class DateTime {
7998
8145
  /**
7999
8146
  * Return an Interval spanning between this DateTime and another DateTime
8000
8147
  * @param {DateTime} otherDateTime - the other end point of the Interval
8001
- * @return {Interval}
8148
+ * @return {Interval|DateTime}
8002
8149
  */
8003
8150
  until(otherDateTime) {
8004
8151
  return this.isValid ? Interval.fromDateTimes(this, otherDateTime) : this;
@@ -8044,12 +8191,13 @@ class DateTime {
8044
8191
 
8045
8192
  /**
8046
8193
  * Returns a string representation of a this time relative to now, such as "in two days". Can only internationalize if your
8047
- * platform supports Intl.RelativeTimeFormat. Rounds down by default.
8194
+ * platform supports Intl.RelativeTimeFormat. Rounds towards zero by default.
8048
8195
  * @param {Object} options - options that affect the output
8049
8196
  * @param {DateTime} [options.base=DateTime.now()] - the DateTime to use as the basis to which this time is compared. Defaults to now.
8050
8197
  * @param {string} [options.style="long"] - the style of units, must be "long", "short", or "narrow"
8051
8198
  * @param {string|string[]} options.unit - use a specific unit or array of units; if omitted, or an array, the method will pick the best unit. Use an array or one of "years", "quarters", "months", "weeks", "days", "hours", "minutes", or "seconds"
8052
8199
  * @param {boolean} [options.round=true] - whether to round the numbers in the output.
8200
+ * @param {string} [options.rounding="trunc"] - rounding method to use when rounding the numbers in the output. Can be "trunc" (toward zero), "expand" (away from zero), "round", "floor", or "ceil".
8053
8201
  * @param {number} [options.padding=0] - padding in milliseconds. This allows you to round up the result if it fits inside the threshold. Don't use in combination with {round: false} because the decimal output will include the padding.
8054
8202
  * @param {string} options.locale - override the locale of this DateTime
8055
8203
  * @param {string} options.numberingSystem - override the numberingSystem of this DateTime. The Intl system may choose not to honor this
@@ -10437,7 +10585,7 @@ class BinaryReader {
10437
10585
  // ignore
10438
10586
  }
10439
10587
  break;
10440
- // @ts-expect-error TS7029: Fallthrough case in switch
10588
+ // @ts-ignore TS7029: Fallthrough case in switch -- ignore instead of expect-error for compiler settings without noFallthroughCasesInSwitch: true
10441
10589
  case WireType.Bit64:
10442
10590
  this.pos += 4;
10443
10591
  case WireType.Bit32:
@@ -10718,7 +10866,6 @@ function around(index, lng, lat, maxResults = Infinity, maxDistance = Infinity,
10718
10866
  left: 0, // left index in the kd-tree array
10719
10867
  right: index.ids.length - 1, // right index
10720
10868
  axis: 0, // 0 for longitude axis and 1 for latitude axis
10721
- dist: 0, // will hold the lower bound of children's distances to the query point
10722
10869
  minLng: -180, // bounding box of the node
10723
10870
  minLat: -90,
10724
10871
  maxLng: 180,
@@ -11186,7 +11333,7 @@ function sqDist(ax, ay, bx, by) {
11186
11333
  return dx * dx + dy * dy;
11187
11334
  }
11188
11335
 
11189
- const xt="ENTRIES",B="KEYS",G="VALUES",g="";class V{set;_type;_path;constructor(e,n){const o=e._tree,s=Array.from(o.keys());this.set=e,this._type=n,this._path=s.length>0?[{node:o,keys:s}]:[];}next(){const e=this.dive();return this.backtrack(),e}dive(){if(this._path.length===0)return {done:true,value:undefined};const{node:e,keys:n}=z(this._path);if(z(n)===g)return {done:false,value:this.result()};const o=e.get(z(n));return this._path.push({node:o,keys:Array.from(o.keys())}),this.dive()}backtrack(){if(this._path.length===0)return;const e=z(this._path).keys;e.pop(),!(e.length>0)&&(this._path.pop(),this.backtrack());}key(){return this.set._prefix+this._path.map(({keys:e})=>z(e)).filter(e=>e!==g).join("")}value(){return z(this._path).node.get(g)}result(){switch(this._type){case G:return this.value();case B:return this.key();default:return [this.key(),this.value()]}}[Symbol.iterator](){return this}}const z=t=>t[t.length-1],zt=(t,e,n)=>{const o=new Map;if(typeof e!="string")return o;const s=e.length+1,r=s+n,i=new Uint8Array(r*s).fill(n+1);for(let c=0;c<s;++c)i[c]=c;for(let c=1;c<r;++c)i[c*s]=c;return K(t,e,n,o,i,1,s,""),o},K=(t,e,n,o,s,r,i,c)=>{const u=r*i;t:for(const d of t.keys())if(d===g){const a=s[u-1];a<=n&&o.set(c,[t.get(d),a]);}else {let a=r;for(let h=0;h<d.length;++h,++a){const f=d[h],_=i*a,p=_-i;let l=s[_];const m=Math.max(0,a-n-1),y=Math.min(i-1,a+n);for(let w=m;w<y;++w){const C=f!==e[w],O=s[p+w]+ +C,b=s[p+w+1]+1,x=s[_+w]+1,S=s[_+w+1]=Math.min(O,b,x);S<l&&(l=S);}if(l>n)continue t}K(t.get(d),e,n,o,s,a,i,c+d);}};class I{_tree;_prefix;_size=undefined;constructor(e=new Map,n=""){this._tree=e,this._prefix=n;}atPrefix(e){if(!e.startsWith(this._prefix))throw new Error("Mismatched prefix");const[n,o]=v(this._tree,e.slice(this._prefix.length));if(n===undefined){const[s,r]=L(o);for(const i of s.keys())if(i!==g&&i.startsWith(r)){const c=new Map;return c.set(i.slice(r.length),s.get(i)),new I(c,e)}}return new I(n,e)}clear(){this._size=undefined,this._tree.clear();}delete(e){return this._size=undefined,St(this._tree,e)}entries(){return new V(this,xt)}forEach(e){for(const[n,o]of this)e(n,o,this);}fuzzyGet(e,n){return zt(this._tree,e,n)}get(e){const n=T(this._tree,e);return n!==undefined?n.get(g):undefined}has(e){return T(this._tree,e)?.has(g)??false}keys(){return new V(this,B)}set(e,n){if(typeof e!="string")throw new Error("key must be a string");return this._size=undefined,M(this._tree,e).set(g,n),this}get size(){if(this._size)return this._size;this._size=0;const e=this.entries();for(;!e.next().done;)this._size+=1;return this._size}update(e,n){if(typeof e!="string")throw new Error("key must be a string");this._size=undefined;const o=M(this._tree,e);return o.set(g,n(o.get(g))),this}fetch(e,n){if(typeof e!="string")throw new Error("key must be a string");this._size=undefined;const o=M(this._tree,e);let s=o.get(g);return s===undefined&&o.set(g,s=n()),s}values(){return new V(this,G)}[Symbol.iterator](){return this.entries()}static from(e){const n=new I;for(const[o,s]of e)n.set(o,s);return n}static fromObject(e){return I.from(Object.entries(e))}}const v=(t,e,n=[])=>{if(e.length===0||t==null)return [t,n];for(const o of t.keys())if(o!==g&&e.startsWith(o))return n.push([t,o]),v(t.get(o),e.slice(o.length),n);return n.push([t,e]),v(undefined,"",n)},T=(t,e)=>{if(e.length===0||!t)return t;for(const n of t.keys())if(n!==g&&e.startsWith(n))return T(t.get(n),e.slice(n.length))},M=(t,e)=>{const n=e.length;t:for(let o=0;t&&o<n;){for(const r of t.keys())if(r!==g&&e[o]===r[0]){const i=Math.min(n-o,r.length);let c=1;for(;c<i&&e[o+c]===r[c];)++c;const u=t.get(r);if(c===r.length)t=u;else {const d=new Map;d.set(r.slice(c),u),t.set(e.slice(o,o+c),d),t.delete(r),t=d;}o+=c;continue t}const s=new Map;return t.set(e.slice(o),s),s}return t},St=(t,e)=>{const[n,o]=v(t,e);if(n!==undefined){if(n.delete(g),n.size===0)Q(o);else if(n.size===1){const[s,r]=n.entries().next().value;Y(o,s,r);}}},Q=t=>{if(t.length===0)return;const[e,n]=L(t);if(e.delete(n),e.size===0)Q(t.slice(0,-1));else if(e.size===1){const[o,s]=e.entries().next().value;o!==g&&Y(t.slice(0,-1),o,s);}},Y=(t,e,n)=>{if(t.length===0)return;const[o,s]=L(t);o.set(s+e,n),o.delete(s);},L=t=>t[t.length-1],Z=(t,e)=>t._idToShortId.has(e),vt=/[\n\r\p{Z}\p{P}]+/u,D="or",H="and",Ft="and_not",kt=(t,e)=>{t.includes(e)||t.push(e);},tt=(t,e)=>{for(const n of e)t.includes(n)||t.push(n);},et=({score:t},{score:e})=>e-t,nt=()=>new Map,E=(t,e)=>Object.prototype.hasOwnProperty.call(t,e)?t[e]:undefined,ot={[D]:(t,e)=>{for(const n of e.keys()){const o=t.get(n);if(o==null)t.set(n,e.get(n));else {const{score:s,terms:r,match:i}=e.get(n);o.score=o.score+s,o.match=Object.assign(o.match,i),tt(o.terms,r);}}return t},[H]:(t,e)=>{const n=new Map;for(const o of e.keys()){const s=t.get(o);if(s==null)continue;const{score:r,terms:i,match:c}=e.get(o);tt(s.terms,i),n.set(o,{score:s.score+r,terms:s.terms,match:Object.assign(s.match,c)});}return n},[Ft]:(t,e)=>{for(const n of e.keys())t.delete(n);return t}},Ct=(t,e,n,o,s,r)=>{const{k:i,b:c,d:u}=r;return Math.log(1+(n-e+.5)/(e+.5))*(u+t*(i+1)/(t+i*(1-c+c*o/s)))},Ot=t=>(e,n,o)=>({term:e,fuzzy:typeof t.fuzzy=="function"?t.fuzzy(e,n,o):t.fuzzy??false,prefix:typeof t.prefix=="function"?t.prefix(e,n,o):t.prefix===true,termBoost:typeof t.boostTerm=="function"?t.boostTerm(e,n,o):1}),st=(t,e,n,o)=>{for(const s of Object.keys(t._fieldIds))if(t._fieldIds[s]===n){t._options.logger("warn",`SlimSearch: document with ID ${t._documentIds.get(e)} has changed before removal: term "${o}" was not present in field "${s}". Removing a document after it has changed can corrupt the index!`,"version_conflict");return}},it=(t,e,n,o)=>{const s=t._index.fetch(o,nt);let r=s.get(e);if(r==null)r=new Map,r.set(n,1),s.set(e,r);else {const i=r.get(n);r.set(n,(i??0)+1);}},A=(t,e,n,o)=>{if(!t._index.has(o)){st(t,n,e,o);return}const s=t._index.fetch(o,nt),r=s.get(e),i=r?.get(n);!r||typeof i>"u"?st(t,n,e,o):i<=1?r.size<=1?s.delete(e):r.delete(n):r.set(n,i-1),t._index.get(o).size===0&&t._index.delete(o);},Vt=(t,e,n,o,s)=>{let r=t._fieldLength.get(e);r==null&&t._fieldLength.set(e,r=[]),r[n]=s;const i=(t._avgFieldLength[n]||0)*o+s;t._avgFieldLength[n]=i/(o+1);},Tt=(t,e)=>{const n=t._nextId;return t._idToShortId.set(e,n),t._documentIds.set(n,e),t._documentCount+=1,t._nextId+=1,n},Mt=(t,e,n)=>{const{storeFields:o,extractField:s}=t._options;if(o?.length===0)return;let r=t._storedFields.get(e);r===undefined&&t._storedFields.set(e,r={});for(const i of o){const c=s(n,i);c!=null&&(r[i]=c);}},j=(t,e)=>{const{extractField:n,tokenize:o,processTerm:s,fields:r,idField:i}=t._options,c=n(e,i);if(c==null)throw new Error(`SlimSearch: document does not have ID field "${i}"`);if(Z(t,c))throw new Error(`SlimSearch: duplicate ID ${c}`);const u=Tt(t,c);Mt(t,u,e);for(const d of r){const a=n(e,d);if(a==null)continue;const h=o(a.toString(),d),f=t._fieldIds[d],_=new Set(h).size;Vt(t,u,f,t._documentCount-1,_);for(const p of h){const l=s(p,d);if(Array.isArray(l))for(const m of l)it(t,f,u,m);else l&&it(t,f,u,l);}}},q=(t,e)=>{for(const n of e)j(t,n);},Dt={k:1.2,b:.7,d:.5},$={idField:"id",extractField:(t,e)=>t[e],tokenize:t=>t.split(vt),processTerm:t=>t.toLowerCase(),fields:undefined,searchOptions:undefined,storeFields:[],logger:(t,e)=>{console?.[t]?.(e);},autoVacuum:true},rt={combineWith:D,prefix:false,fuzzy:false,maxFuzzy:6,boost:{},weights:{fuzzy:.45,prefix:.375},bm25:Dt},Et={combineWith:H,prefix:(t,e,n)=>e===n.length-1},N={batchSize:1e3,batchWait:10},W={minDirtFactor:.1,minDirtCount:20},P={...N,...W},R=Symbol("*"),jt=(t,e)=>{const n=new Map,o={...t._options.searchOptions,...e};for(const[s,r]of t._documentIds){const i=o.boostDocument?o.boostDocument(r,"",t._storedFields.get(s)):1;n.set(s,{score:i,terms:[],match:{}});}return n},ct=(t,e=D)=>{if(t.length===0)return new Map;const n=e.toLowerCase();if(!(n in ot))throw new Error(`Invalid combination operator: ${e}`);return t.reduce(ot[n])},J=(t,e,n,o,s,r,i,c,u,d=new Map)=>{if(r==null)return d;for(const a of Object.keys(i)){const h=i[a],f=t._fieldIds[a],_=r.get(f);if(_==null)continue;let p=_.size;const l=t._avgFieldLength[f];for(const m of _.keys()){if(!t._documentIds.has(m)){A(t,f,m,n),p-=1;continue}const y=c?c(t._documentIds.get(m),n,t._storedFields.get(m)):1;if(!y)continue;const w=_.get(m),C=t._fieldLength.get(m)[f],O=Ct(w,p,t._documentCount,C,l,u),b=o*s*h*y*O,x=d.get(m);if(x){x.score+=b,kt(x.terms,e);const S=E(x.match,n);S?S.push(a):x.match[n]=[a];}else d.set(m,{score:b,terms:[e],match:{[n]:[a]}});}}return d},qt=(t,e,n)=>{const o={...t._options.searchOptions,...n},s=(o.fields??t._options.fields).reduce((l,m)=>({...l,[m]:E(o.boost,m)||1}),{}),{boostDocument:r,weights:i,maxFuzzy:c,bm25:u}=o,{fuzzy:d,prefix:a}={...rt.weights,...i},h=t._index.get(e.term),f=J(t,e.term,e.term,1,e.termBoost,h,s,r,u);let _,p;if(e.prefix&&(_=t._index.atPrefix(e.term)),e.fuzzy){const l=e.fuzzy===true?.2:e.fuzzy,m=l<1?Math.min(c,Math.round(e.term.length*l)):l;m&&(p=t._index.fuzzyGet(e.term,m));}if(_)for(const[l,m]of _){const y=l.length-e.term.length;if(!y)continue;p?.delete(l);const w=a*l.length/(l.length+.3*y);J(t,e.term,l,w,e.termBoost,m,s,r,u,f);}if(p)for(const l of p.keys()){const[m,y]=p.get(l);if(!y)continue;const w=d*l.length/(l.length+y);J(t,e.term,l,w,e.termBoost,m,s,r,u,f);}return f},ut=(t,e,n={})=>{if(e===R)return jt(t,n);if(typeof e!="string"){const a={...n,...e,queries:undefined},h=e.queries.map(f=>ut(t,f,a));return ct(h,a.combineWith)}const{tokenize:o,processTerm:s,searchOptions:r}=t._options,i={tokenize:o,processTerm:s,...r,...n},{tokenize:c,processTerm:u}=i,d=c(e).flatMap(a=>u(a)).filter(a=>!!a).map(Ot(i)).map(a=>qt(t,a,i));return ct(d,i.combineWith)},dt=(t,e,n={})=>{const{searchOptions:o}=t._options,s={...o,...n},r=ut(t,e,n),i=[];for(const[c,{score:u,terms:d,match:a}]of r){const h=d.length||1,f={id:t._documentIds.get(c),score:u*h,terms:Object.keys(a),queryTerms:d,match:a};Object.assign(f,t._storedFields.get(c)),(s.filter==null||s.filter(f))&&i.push(f);}return e===R&&s.boostDocument==null||i.sort(et),i};class Nt{_options;_index;_documentCount;_documentIds;_idToShortId;_fieldIds;_fieldLength;_avgFieldLength;_nextId;_storedFields;_dirtCount;_currentVacuum;_enqueuedVacuum;_enqueuedVacuumConditions;constructor(e){if(!e?.fields)throw new Error('SlimSearch: option "fields" must be provided');const n=e.autoVacuum==null||e.autoVacuum===true?P:e.autoVacuum;this._options={...$,...e,autoVacuum:n,searchOptions:{...rt,...e.searchOptions},autoSuggestOptions:{...Et,...e.autoSuggestOptions}},this._index=new I,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldIds={},this._fieldLength=new Map,this._avgFieldLength=[],this._nextId=0,this._storedFields=new Map,this._dirtCount=0,this._currentVacuum=null,this._enqueuedVacuum=null,this._enqueuedVacuumConditions=W,this.addFields(this._options.fields);}get isVacuuming(){return this._currentVacuum!=null}get dirtCount(){return this._dirtCount}get dirtFactor(){return this._dirtCount/(1+this._documentCount+this._dirtCount)}get documentCount(){return this._documentCount}get termCount(){return this._index.size}toJSON(){const e=[];for(const[n,o]of this._index){const s={};for(const[r,i]of o)s[r]=Object.fromEntries(i);e.push([n,s]);}return {documentCount:this._documentCount,nextId:this._nextId,documentIds:Object.fromEntries(this._documentIds),fieldIds:this._fieldIds,fieldLength:Object.fromEntries(this._fieldLength),averageFieldLength:this._avgFieldLength,storedFields:Object.fromEntries(this._storedFields),dirtCount:this._dirtCount,index:e,version:2}}addFields(e){for(let n=0;n<e.length;n++)this._fieldIds[e[n]]=n;}}const lt=t=>new Nt(t);
11336
+ const xt="ENTRIES",B="KEYS",G="VALUES",g="";class V{set;_type;_path;constructor(e,n){const o=e._tree,s=Array.from(o.keys());this.set=e,this._type=n,this._path=s.length>0?[{node:o,keys:s}]:[];}next(){const e=this.dive();return this.backtrack(),e}dive(){if(this._path.length===0)return {done:true,value:void 0};const{node:e,keys:n}=z(this._path);if(z(n)===g)return {done:false,value:this.result()};const o=e.get(z(n));return this._path.push({node:o,keys:Array.from(o.keys())}),this.dive()}backtrack(){if(this._path.length===0)return;const e=z(this._path).keys;e.pop(),!(e.length>0)&&(this._path.pop(),this.backtrack());}key(){return this.set._prefix+this._path.map(({keys:e})=>z(e)).filter(e=>e!==g).join("")}value(){return z(this._path).node.get(g)}result(){switch(this._type){case G:return this.value();case B:return this.key();default:return [this.key(),this.value()]}}[Symbol.iterator](){return this}}const z=t=>t[t.length-1],zt=(t,e,n)=>{const o=new Map;if(typeof e!="string")return o;const s=e.length+1,r=s+n,i=new Uint8Array(r*s).fill(n+1);for(let c=0;c<s;++c)i[c]=c;for(let c=1;c<r;++c)i[c*s]=c;return K(t,e,n,o,i,1,s,""),o},K=(t,e,n,o,s,r,i,c)=>{const u=r*i;t:for(const d of t.keys())if(d===g){const a=s[u-1];a<=n&&o.set(c,[t.get(d),a]);}else {let a=r;for(let h=0;h<d.length;++h,++a){const f=d[h],_=i*a,p=_-i;let l=s[_];const m=Math.max(0,a-n-1),y=Math.min(i-1,a+n);for(let w=m;w<y;++w){const C=f!==e[w],O=s[p+w]+ +C,b=s[p+w+1]+1,x=s[_+w]+1,S=s[_+w+1]=Math.min(O,b,x);S<l&&(l=S);}if(l>n)continue t}K(t.get(d),e,n,o,s,a,i,c+d);}};class I{_tree;_prefix;_size=void 0;constructor(e=new Map,n=""){this._tree=e,this._prefix=n;}atPrefix(e){if(!e.startsWith(this._prefix))throw new Error("Mismatched prefix");const[n,o]=v(this._tree,e.slice(this._prefix.length));if(n===void 0){const[s,r]=L(o);for(const i of s.keys())if(i!==g&&i.startsWith(r)){const c=new Map;return c.set(i.slice(r.length),s.get(i)),new I(c,e)}}return new I(n,e)}clear(){this._size=void 0,this._tree.clear();}delete(e){return this._size=void 0,St(this._tree,e)}entries(){return new V(this,xt)}forEach(e){for(const[n,o]of this)e(n,o,this);}fuzzyGet(e,n){return zt(this._tree,e,n)}get(e){const n=T(this._tree,e);return n!==void 0?n.get(g):void 0}has(e){return T(this._tree,e)?.has(g)??false}keys(){return new V(this,B)}set(e,n){if(typeof e!="string")throw new Error("key must be a string");return this._size=void 0,M(this._tree,e).set(g,n),this}get size(){if(this._size)return this._size;this._size=0;const e=this.entries();for(;!e.next().done;)this._size+=1;return this._size}update(e,n){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;const o=M(this._tree,e);return o.set(g,n(o.get(g))),this}fetch(e,n){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;const o=M(this._tree,e);let s=o.get(g);return s===void 0&&o.set(g,s=n()),s}values(){return new V(this,G)}[Symbol.iterator](){return this.entries()}static from(e){const n=new I;for(const[o,s]of e)n.set(o,s);return n}static fromObject(e){return I.from(Object.entries(e))}}const v=(t,e,n=[])=>{if(e.length===0||t==null)return [t,n];for(const o of t.keys())if(o!==g&&e.startsWith(o))return n.push([t,o]),v(t.get(o),e.slice(o.length),n);return n.push([t,e]),v(void 0,"",n)},T=(t,e)=>{if(e.length===0||!t)return t;for(const n of t.keys())if(n!==g&&e.startsWith(n))return T(t.get(n),e.slice(n.length))},M=(t,e)=>{const n=e.length;t:for(let o=0;t&&o<n;){for(const r of t.keys())if(r!==g&&e[o]===r[0]){const i=Math.min(n-o,r.length);let c=1;for(;c<i&&e[o+c]===r[c];)++c;const u=t.get(r);if(c===r.length)t=u;else {const d=new Map;d.set(r.slice(c),u),t.set(e.slice(o,o+c),d),t.delete(r),t=d;}o+=c;continue t}const s=new Map;return t.set(e.slice(o),s),s}return t},St=(t,e)=>{const[n,o]=v(t,e);if(n!==void 0){if(n.delete(g),n.size===0)Q(o);else if(n.size===1){const[s,r]=n.entries().next().value;Y(o,s,r);}}},Q=t=>{if(t.length===0)return;const[e,n]=L(t);if(e.delete(n),e.size===0)Q(t.slice(0,-1));else if(e.size===1){const[o,s]=e.entries().next().value;o!==g&&Y(t.slice(0,-1),o,s);}},Y=(t,e,n)=>{if(t.length===0)return;const[o,s]=L(t);o.set(s+e,n),o.delete(s);},L=t=>t[t.length-1],Z=(t,e)=>t._idToShortId.has(e),vt=/[\n\r\p{Z}\p{P}]+/u,D="or",H="and",Ft="and_not",kt=(t,e)=>{t.includes(e)||t.push(e);},tt=(t,e)=>{for(const n of e)t.includes(n)||t.push(n);},et=({score:t},{score:e})=>e-t,nt=()=>new Map,E=(t,e)=>Object.prototype.hasOwnProperty.call(t,e)?t[e]:void 0,ot={[D]:(t,e)=>{for(const n of e.keys()){const o=t.get(n);if(o==null)t.set(n,e.get(n));else {const{score:s,terms:r,match:i}=e.get(n);o.score=o.score+s,o.match=Object.assign(o.match,i),tt(o.terms,r);}}return t},[H]:(t,e)=>{const n=new Map;for(const o of e.keys()){const s=t.get(o);if(s==null)continue;const{score:r,terms:i,match:c}=e.get(o);tt(s.terms,i),n.set(o,{score:s.score+r,terms:s.terms,match:Object.assign(s.match,c)});}return n},[Ft]:(t,e)=>{for(const n of e.keys())t.delete(n);return t}},Ct=(t,e,n,o,s,r)=>{const{k:i,b:c,d:u}=r;return Math.log(1+(n-e+.5)/(e+.5))*(u+t*(i+1)/(t+i*(1-c+c*o/s)))},Ot=t=>(e,n,o)=>({term:e,fuzzy:typeof t.fuzzy=="function"?t.fuzzy(e,n,o):t.fuzzy??false,prefix:typeof t.prefix=="function"?t.prefix(e,n,o):t.prefix===true,termBoost:typeof t.boostTerm=="function"?t.boostTerm(e,n,o):1}),st=(t,e,n,o)=>{for(const s of Object.keys(t._fieldIds))if(t._fieldIds[s]===n){t._options.logger("warn",`SlimSearch: document with ID ${t._documentIds.get(e)} has changed before removal: term "${o}" was not present in field "${s}". Removing a document after it has changed can corrupt the index!`,"version_conflict");return}},it=(t,e,n,o)=>{const s=t._index.fetch(o,nt);let r=s.get(e);if(r==null)r=new Map,r.set(n,1),s.set(e,r);else {const i=r.get(n);r.set(n,(i??0)+1);}},A=(t,e,n,o)=>{if(!t._index.has(o)){st(t,n,e,o);return}const s=t._index.fetch(o,nt),r=s.get(e),i=r?.get(n);!r||typeof i>"u"?st(t,n,e,o):i<=1?r.size<=1?s.delete(e):r.delete(n):r.set(n,i-1),t._index.get(o).size===0&&t._index.delete(o);},Vt=(t,e,n,o,s)=>{let r=t._fieldLength.get(e);r==null&&t._fieldLength.set(e,r=[]),r[n]=s;const i=(t._avgFieldLength[n]||0)*o+s;t._avgFieldLength[n]=i/(o+1);},Tt=(t,e)=>{const n=t._nextId;return t._idToShortId.set(e,n),t._documentIds.set(n,e),t._documentCount+=1,t._nextId+=1,n},Mt=(t,e,n)=>{const{storeFields:o,extractField:s}=t._options;if(o?.length===0)return;let r=t._storedFields.get(e);r===void 0&&t._storedFields.set(e,r={});for(const i of o){const c=s(n,i);c!=null&&(r[i]=c);}},j=(t,e)=>{const{extractField:n,tokenize:o,processTerm:s,fields:r,idField:i}=t._options,c=n(e,i);if(c==null)throw new Error(`SlimSearch: document does not have ID field "${i}"`);if(Z(t,c))throw new Error(`SlimSearch: duplicate ID ${c}`);const u=Tt(t,c);Mt(t,u,e);for(const d of r){const a=n(e,d);if(a==null)continue;const h=o(a.toString(),d),f=t._fieldIds[d],_=new Set(h).size;Vt(t,u,f,t._documentCount-1,_);for(const p of h){const l=s(p,d);if(Array.isArray(l))for(const m of l)it(t,f,u,m);else l&&it(t,f,u,l);}}},q=(t,e)=>{for(const n of e)j(t,n);},Dt={k:1.2,b:.7,d:.5},$={idField:"id",extractField:(t,e)=>t[e],tokenize:t=>t.split(vt),processTerm:t=>t.toLowerCase(),fields:void 0,searchOptions:void 0,storeFields:[],logger:(t,e)=>{console?.[t]?.(e);},autoVacuum:true},rt={combineWith:D,prefix:false,fuzzy:false,maxFuzzy:6,boost:{},weights:{fuzzy:.45,prefix:.375},bm25:Dt},Et={combineWith:H,prefix:(t,e,n)=>e===n.length-1},N={batchSize:1e3,batchWait:10},W={minDirtFactor:.1,minDirtCount:20},P={...N,...W},R=Symbol("*"),jt=(t,e)=>{const n=new Map,o={...t._options.searchOptions,...e};for(const[s,r]of t._documentIds){const i=o.boostDocument?o.boostDocument(r,"",t._storedFields.get(s)):1;n.set(s,{score:i,terms:[],match:{}});}return n},ct=(t,e=D)=>{if(t.length===0)return new Map;const n=e.toLowerCase();if(!(n in ot))throw new Error(`Invalid combination operator: ${e}`);return t.reduce(ot[n])},J=(t,e,n,o,s,r,i,c,u,d=new Map)=>{if(r==null)return d;for(const a of Object.keys(i)){const h=i[a],f=t._fieldIds[a],_=r.get(f);if(_==null)continue;let p=_.size;const l=t._avgFieldLength[f];for(const m of _.keys()){if(!t._documentIds.has(m)){A(t,f,m,n),p-=1;continue}const y=c?c(t._documentIds.get(m),n,t._storedFields.get(m)):1;if(!y)continue;const w=_.get(m),C=t._fieldLength.get(m)[f],O=Ct(w,p,t._documentCount,C,l,u),b=o*s*h*y*O,x=d.get(m);if(x){x.score+=b,kt(x.terms,e);const S=E(x.match,n);S?S.push(a):x.match[n]=[a];}else d.set(m,{score:b,terms:[e],match:{[n]:[a]}});}}return d},qt=(t,e,n)=>{const o={...t._options.searchOptions,...n},s=(o.fields??t._options.fields).reduce((l,m)=>({...l,[m]:E(o.boost,m)||1}),{}),{boostDocument:r,weights:i,maxFuzzy:c,bm25:u}=o,{fuzzy:d,prefix:a}={...rt.weights,...i},h=t._index.get(e.term),f=J(t,e.term,e.term,1,e.termBoost,h,s,r,u);let _,p;if(e.prefix&&(_=t._index.atPrefix(e.term)),e.fuzzy){const l=e.fuzzy===true?.2:e.fuzzy,m=l<1?Math.min(c,Math.round(e.term.length*l)):l;m&&(p=t._index.fuzzyGet(e.term,m));}if(_)for(const[l,m]of _){const y=l.length-e.term.length;if(!y)continue;p?.delete(l);const w=a*l.length/(l.length+.3*y);J(t,e.term,l,w,e.termBoost,m,s,r,u,f);}if(p)for(const l of p.keys()){const[m,y]=p.get(l);if(!y)continue;const w=d*l.length/(l.length+y);J(t,e.term,l,w,e.termBoost,m,s,r,u,f);}return f},ut=(t,e,n={})=>{if(e===R)return jt(t,n);if(typeof e!="string"){const a={...n,...e,queries:void 0},h=e.queries.map(f=>ut(t,f,a));return ct(h,a.combineWith)}const{tokenize:o,processTerm:s,searchOptions:r}=t._options,i={tokenize:o,processTerm:s,...r,...n},{tokenize:c,processTerm:u}=i,d=c(e).flatMap(a=>u(a)).filter(a=>!!a).map(Ot(i)).map(a=>qt(t,a,i));return ct(d,i.combineWith)},dt=(t,e,n={})=>{const{searchOptions:o}=t._options,s={...o,...n},r=ut(t,e,n),i=[];for(const[c,{score:u,terms:d,match:a}]of r){const h=d.length||1,f={id:t._documentIds.get(c),score:u*h,terms:Object.keys(a),queryTerms:d,match:a};Object.assign(f,t._storedFields.get(c)),(s.filter==null||s.filter(f))&&i.push(f);}return e===R&&s.boostDocument==null||i.sort(et),i};class Nt{_options;_index;_documentCount;_documentIds;_idToShortId;_fieldIds;_fieldLength;_avgFieldLength;_nextId;_storedFields;_dirtCount;_currentVacuum;_enqueuedVacuum;_enqueuedVacuumConditions;constructor(e){if(!e?.fields)throw new Error('SlimSearch: option "fields" must be provided');const n=e.autoVacuum==null||e.autoVacuum===true?P:e.autoVacuum;this._options={...$,...e,autoVacuum:n,searchOptions:{...rt,...e.searchOptions},autoSuggestOptions:{...Et,...e.autoSuggestOptions}},this._index=new I,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldIds={},this._fieldLength=new Map,this._avgFieldLength=[],this._nextId=0,this._storedFields=new Map,this._dirtCount=0,this._currentVacuum=null,this._enqueuedVacuum=null,this._enqueuedVacuumConditions=W,this.addFields(this._options.fields);}get isVacuuming(){return this._currentVacuum!=null}get dirtCount(){return this._dirtCount}get dirtFactor(){return this._dirtCount/(1+this._documentCount+this._dirtCount)}get documentCount(){return this._documentCount}get termCount(){return this._index.size}toJSON(){const e=[];for(const[n,o]of this._index){const s={};for(const[r,i]of o)s[r]=Object.fromEntries(i);e.push([n,s]);}return {documentCount:this._documentCount,nextId:this._nextId,documentIds:Object.fromEntries(this._documentIds),fieldIds:this._fieldIds,fieldLength:Object.fromEntries(this._fieldLength),averageFieldLength:this._avgFieldLength,storedFields:Object.fromEntries(this._storedFields),dirtCount:this._dirtCount,index:e,version:2}}addFields(e){for(let n=0;n<e.length;n++)this._fieldIds[e[n]]=n;}}const lt=t=>new Nt(t);
11190
11337
 
11191
11338
  /**
11192
11339
  * Generates a list of accent variants for a given term.
@@ -11228,7 +11375,7 @@ const generateAccentVariants = (term) => {
11228
11375
 
11229
11376
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
11230
11377
  // versions:
11231
- // protoc-gen-ts_proto v2.6.1
11378
+ // protoc-gen-ts_proto v2.7.7
11232
11379
  // protoc v4.23.4
11233
11380
  // source: src/stops/proto/stops.proto
11234
11381
  /* eslint-disable */
@@ -11325,7 +11472,7 @@ const Stop = {
11325
11472
  },
11326
11473
  decode(input, length) {
11327
11474
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
11328
- let end = length === undefined ? reader.len : reader.pos + length;
11475
+ const end = length === undefined ? reader.len : reader.pos + length;
11329
11476
  const message = createBaseStop();
11330
11477
  while (reader.pos < end) {
11331
11478
  const tag = reader.uint32();
@@ -11407,7 +11554,7 @@ const Stop = {
11407
11554
  sourceStopId: isSet$1(object.sourceStopId) ? globalThis.String(object.sourceStopId) : "",
11408
11555
  lat: isSet$1(object.lat) ? globalThis.Number(object.lat) : undefined,
11409
11556
  lon: isSet$1(object.lon) ? globalThis.Number(object.lon) : undefined,
11410
- children: globalThis.Array.isArray(object === null || object === undefined ? undefined : object.children) ? object.children.map((e) => globalThis.Number(e)) : [],
11557
+ children: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.children) ? object.children.map((e) => globalThis.Number(e)) : [],
11411
11558
  parent: isSet$1(object.parent) ? globalThis.Number(object.parent) : undefined,
11412
11559
  locationType: isSet$1(object.locationType) ? locationTypeFromJSON(object.locationType) : 0,
11413
11560
  platform: isSet$1(object.platform) ? globalThis.String(object.platform) : undefined,
@@ -11428,7 +11575,7 @@ const Stop = {
11428
11575
  if (message.lon !== undefined) {
11429
11576
  obj.lon = message.lon;
11430
11577
  }
11431
- if ((_a = message.children) === null || _a === undefined ? undefined : _a.length) {
11578
+ if ((_a = message.children) === null || _a === void 0 ? void 0 : _a.length) {
11432
11579
  obj.children = message.children.map((e) => Math.round(e));
11433
11580
  }
11434
11581
  if (message.parent !== undefined) {
@@ -11443,19 +11590,19 @@ const Stop = {
11443
11590
  return obj;
11444
11591
  },
11445
11592
  create(base) {
11446
- return Stop.fromPartial(base !== null && base !== undefined ? base : {});
11593
+ return Stop.fromPartial(base !== null && base !== void 0 ? base : {});
11447
11594
  },
11448
11595
  fromPartial(object) {
11449
11596
  var _a, _b, _c, _d, _e, _f, _g, _h;
11450
11597
  const message = createBaseStop();
11451
- message.name = (_a = object.name) !== null && _a !== undefined ? _a : "";
11452
- message.sourceStopId = (_b = object.sourceStopId) !== null && _b !== undefined ? _b : "";
11453
- message.lat = (_c = object.lat) !== null && _c !== undefined ? _c : undefined;
11454
- message.lon = (_d = object.lon) !== null && _d !== undefined ? _d : undefined;
11455
- message.children = ((_e = object.children) === null || _e === undefined ? undefined : _e.map((e) => e)) || [];
11456
- message.parent = (_f = object.parent) !== null && _f !== undefined ? _f : undefined;
11457
- message.locationType = (_g = object.locationType) !== null && _g !== undefined ? _g : 0;
11458
- message.platform = (_h = object.platform) !== null && _h !== undefined ? _h : undefined;
11598
+ message.name = (_a = object.name) !== null && _a !== void 0 ? _a : "";
11599
+ message.sourceStopId = (_b = object.sourceStopId) !== null && _b !== void 0 ? _b : "";
11600
+ message.lat = (_c = object.lat) !== null && _c !== void 0 ? _c : undefined;
11601
+ message.lon = (_d = object.lon) !== null && _d !== void 0 ? _d : undefined;
11602
+ message.children = ((_e = object.children) === null || _e === void 0 ? void 0 : _e.map((e) => e)) || [];
11603
+ message.parent = (_f = object.parent) !== null && _f !== void 0 ? _f : undefined;
11604
+ message.locationType = (_g = object.locationType) !== null && _g !== void 0 ? _g : 0;
11605
+ message.platform = (_h = object.platform) !== null && _h !== void 0 ? _h : undefined;
11459
11606
  return message;
11460
11607
  },
11461
11608
  };
@@ -11474,7 +11621,7 @@ const StopsMap = {
11474
11621
  },
11475
11622
  decode(input, length) {
11476
11623
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
11477
- let end = length === undefined ? reader.len : reader.pos + length;
11624
+ const end = length === undefined ? reader.len : reader.pos + length;
11478
11625
  const message = createBaseStopsMap();
11479
11626
  while (reader.pos < end) {
11480
11627
  const tag = reader.uint32();
@@ -11532,13 +11679,13 @@ const StopsMap = {
11532
11679
  return obj;
11533
11680
  },
11534
11681
  create(base) {
11535
- return StopsMap.fromPartial(base !== null && base !== undefined ? base : {});
11682
+ return StopsMap.fromPartial(base !== null && base !== void 0 ? base : {});
11536
11683
  },
11537
11684
  fromPartial(object) {
11538
11685
  var _a, _b;
11539
11686
  const message = createBaseStopsMap();
11540
- message.version = (_a = object.version) !== null && _a !== undefined ? _a : "";
11541
- message.stops = Object.entries((_b = object.stops) !== null && _b !== undefined ? _b : {}).reduce((acc, [key, value]) => {
11687
+ message.version = (_a = object.version) !== null && _a !== void 0 ? _a : "";
11688
+ message.stops = Object.entries((_b = object.stops) !== null && _b !== void 0 ? _b : {}).reduce((acc, [key, value]) => {
11542
11689
  if (value !== undefined) {
11543
11690
  acc[globalThis.Number(key)] = Stop.fromPartial(value);
11544
11691
  }
@@ -11562,7 +11709,7 @@ const StopsMap_StopsEntry = {
11562
11709
  },
11563
11710
  decode(input, length) {
11564
11711
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
11565
- let end = length === undefined ? reader.len : reader.pos + length;
11712
+ const end = length === undefined ? reader.len : reader.pos + length;
11566
11713
  const message = createBaseStopsMap_StopsEntry();
11567
11714
  while (reader.pos < end) {
11568
11715
  const tag = reader.uint32();
@@ -11606,12 +11753,12 @@ const StopsMap_StopsEntry = {
11606
11753
  return obj;
11607
11754
  },
11608
11755
  create(base) {
11609
- return StopsMap_StopsEntry.fromPartial(base !== null && base !== undefined ? base : {});
11756
+ return StopsMap_StopsEntry.fromPartial(base !== null && base !== void 0 ? base : {});
11610
11757
  },
11611
11758
  fromPartial(object) {
11612
11759
  var _a;
11613
11760
  const message = createBaseStopsMap_StopsEntry();
11614
- message.key = (_a = object.key) !== null && _a !== undefined ? _a : 0;
11761
+ message.key = (_a = object.key) !== null && _a !== void 0 ? _a : 0;
11615
11762
  message.value = (object.value !== undefined && object.value !== null) ? Stop.fromPartial(object.value) : undefined;
11616
11763
  return message;
11617
11764
  },
@@ -11722,7 +11869,7 @@ class StopsIndex {
11722
11869
  });
11723
11870
  const stopsSet = new Map();
11724
11871
  for (const [id, stop] of stopsMap.entries()) {
11725
- const effectiveStopId = (_a = stop.parent) !== null && _a !== undefined ? _a : id;
11872
+ const effectiveStopId = (_a = stop.parent) !== null && _a !== void 0 ? _a : id;
11726
11873
  if (!stopsSet.has(effectiveStopId)) {
11727
11874
  stopsSet.set(effectiveStopId, {
11728
11875
  id: effectiveStopId,
@@ -11753,8 +11900,8 @@ class StopsIndex {
11753
11900
  /**
11754
11901
  * Deserializes a binary representation of the stops.
11755
11902
  *
11756
- * @param {Uint8Array} data - The binary data to deserialize.
11757
- * @returns {StopsMap} - The deserialized StopFinder.
11903
+ * @param data - The binary data to deserialize.
11904
+ * @returns The deserialized StopFinder.
11758
11905
  */
11759
11906
  static fromData(data) {
11760
11907
  const reader = new BinaryReader(data);
@@ -11764,7 +11911,7 @@ class StopsIndex {
11764
11911
  /**
11765
11912
  * Serializes the stops into a binary protobuf.
11766
11913
  *
11767
- * @returns {Uint8Array} - The serialized binary data.
11914
+ * @returns The serialized binary data.
11768
11915
  */
11769
11916
  serialize() {
11770
11917
  const protoStopsMap = serializeStopsMap(this.stopsMap);
@@ -11843,7 +11990,7 @@ class StopsIndex {
11843
11990
  return [];
11844
11991
  }
11845
11992
  const equivalentStops = stop.parent
11846
- ? ((_b = (_a = this.stopsMap.get(stop.parent)) === null || _a === undefined ? undefined : _a.children) !== null && _b !== undefined ? _b : [])
11993
+ ? ((_b = (_a = this.stopsMap.get(stop.parent)) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : [])
11847
11994
  : stop.children;
11848
11995
  return Array.from(new Set([id, ...equivalentStops])).map((stopId) => this.stopsMap.get(stopId));
11849
11996
  }
@@ -11932,7 +12079,7 @@ class Duration {
11932
12079
 
11933
12080
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
11934
12081
  // versions:
11935
- // protoc-gen-ts_proto v2.6.1
12082
+ // protoc-gen-ts_proto v2.7.7
11936
12083
  // protoc v4.23.4
11937
12084
  // source: src/timetable/proto/timetable.proto
11938
12085
  /* eslint-disable */
@@ -12066,7 +12213,7 @@ function createBaseRoute() {
12066
12213
  serviceRouteId: "",
12067
12214
  };
12068
12215
  }
12069
- const Route = {
12216
+ const Route$1 = {
12070
12217
  encode(message, writer = new BinaryWriter()) {
12071
12218
  if (message.stopTimes.length !== 0) {
12072
12219
  writer.uint32(10).bytes(message.stopTimes);
@@ -12084,7 +12231,7 @@ const Route = {
12084
12231
  },
12085
12232
  decode(input, length) {
12086
12233
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12087
- let end = length === undefined ? reader.len : reader.pos + length;
12234
+ const end = length === undefined ? reader.len : reader.pos + length;
12088
12235
  const message = createBaseRoute();
12089
12236
  while (reader.pos < end) {
12090
12237
  const tag = reader.uint32();
@@ -12152,15 +12299,15 @@ const Route = {
12152
12299
  return obj;
12153
12300
  },
12154
12301
  create(base) {
12155
- return Route.fromPartial(base !== null && base !== undefined ? base : {});
12302
+ return Route$1.fromPartial(base !== null && base !== void 0 ? base : {});
12156
12303
  },
12157
12304
  fromPartial(object) {
12158
12305
  var _a, _b, _c, _d;
12159
12306
  const message = createBaseRoute();
12160
- message.stopTimes = (_a = object.stopTimes) !== null && _a !== undefined ? _a : new Uint8Array(0);
12161
- message.pickUpDropOffTypes = (_b = object.pickUpDropOffTypes) !== null && _b !== undefined ? _b : new Uint8Array(0);
12162
- message.stops = (_c = object.stops) !== null && _c !== undefined ? _c : new Uint8Array(0);
12163
- message.serviceRouteId = (_d = object.serviceRouteId) !== null && _d !== undefined ? _d : "";
12307
+ message.stopTimes = (_a = object.stopTimes) !== null && _a !== void 0 ? _a : new Uint8Array(0);
12308
+ message.pickUpDropOffTypes = (_b = object.pickUpDropOffTypes) !== null && _b !== void 0 ? _b : new Uint8Array(0);
12309
+ message.stops = (_c = object.stops) !== null && _c !== void 0 ? _c : new Uint8Array(0);
12310
+ message.serviceRouteId = (_d = object.serviceRouteId) !== null && _d !== void 0 ? _d : "";
12164
12311
  return message;
12165
12312
  },
12166
12313
  };
@@ -12176,7 +12323,7 @@ const RoutesAdjacency = {
12176
12323
  },
12177
12324
  decode(input, length) {
12178
12325
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12179
- let end = length === undefined ? reader.len : reader.pos + length;
12326
+ const end = length === undefined ? reader.len : reader.pos + length;
12180
12327
  const message = createBaseRoutesAdjacency();
12181
12328
  while (reader.pos < end) {
12182
12329
  const tag = reader.uint32();
@@ -12203,7 +12350,7 @@ const RoutesAdjacency = {
12203
12350
  return {
12204
12351
  routes: isObject(object.routes)
12205
12352
  ? Object.entries(object.routes).reduce((acc, [key, value]) => {
12206
- acc[key] = Route.fromJSON(value);
12353
+ acc[key] = Route$1.fromJSON(value);
12207
12354
  return acc;
12208
12355
  }, {})
12209
12356
  : {},
@@ -12216,21 +12363,21 @@ const RoutesAdjacency = {
12216
12363
  if (entries.length > 0) {
12217
12364
  obj.routes = {};
12218
12365
  entries.forEach(([k, v]) => {
12219
- obj.routes[k] = Route.toJSON(v);
12366
+ obj.routes[k] = Route$1.toJSON(v);
12220
12367
  });
12221
12368
  }
12222
12369
  }
12223
12370
  return obj;
12224
12371
  },
12225
12372
  create(base) {
12226
- return RoutesAdjacency.fromPartial(base !== null && base !== undefined ? base : {});
12373
+ return RoutesAdjacency.fromPartial(base !== null && base !== void 0 ? base : {});
12227
12374
  },
12228
12375
  fromPartial(object) {
12229
12376
  var _a;
12230
12377
  const message = createBaseRoutesAdjacency();
12231
- message.routes = Object.entries((_a = object.routes) !== null && _a !== undefined ? _a : {}).reduce((acc, [key, value]) => {
12378
+ message.routes = Object.entries((_a = object.routes) !== null && _a !== void 0 ? _a : {}).reduce((acc, [key, value]) => {
12232
12379
  if (value !== undefined) {
12233
- acc[key] = Route.fromPartial(value);
12380
+ acc[key] = Route$1.fromPartial(value);
12234
12381
  }
12235
12382
  return acc;
12236
12383
  }, {});
@@ -12246,13 +12393,13 @@ const RoutesAdjacency_RoutesEntry = {
12246
12393
  writer.uint32(10).string(message.key);
12247
12394
  }
12248
12395
  if (message.value !== undefined) {
12249
- Route.encode(message.value, writer.uint32(18).fork()).join();
12396
+ Route$1.encode(message.value, writer.uint32(18).fork()).join();
12250
12397
  }
12251
12398
  return writer;
12252
12399
  },
12253
12400
  decode(input, length) {
12254
12401
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12255
- let end = length === undefined ? reader.len : reader.pos + length;
12402
+ const end = length === undefined ? reader.len : reader.pos + length;
12256
12403
  const message = createBaseRoutesAdjacency_RoutesEntry();
12257
12404
  while (reader.pos < end) {
12258
12405
  const tag = reader.uint32();
@@ -12268,7 +12415,7 @@ const RoutesAdjacency_RoutesEntry = {
12268
12415
  if (tag !== 18) {
12269
12416
  break;
12270
12417
  }
12271
- message.value = Route.decode(reader, reader.uint32());
12418
+ message.value = Route$1.decode(reader, reader.uint32());
12272
12419
  continue;
12273
12420
  }
12274
12421
  }
@@ -12282,7 +12429,7 @@ const RoutesAdjacency_RoutesEntry = {
12282
12429
  fromJSON(object) {
12283
12430
  return {
12284
12431
  key: isSet(object.key) ? globalThis.String(object.key) : "",
12285
- value: isSet(object.value) ? Route.fromJSON(object.value) : undefined,
12432
+ value: isSet(object.value) ? Route$1.fromJSON(object.value) : undefined,
12286
12433
  };
12287
12434
  },
12288
12435
  toJSON(message) {
@@ -12291,18 +12438,18 @@ const RoutesAdjacency_RoutesEntry = {
12291
12438
  obj.key = message.key;
12292
12439
  }
12293
12440
  if (message.value !== undefined) {
12294
- obj.value = Route.toJSON(message.value);
12441
+ obj.value = Route$1.toJSON(message.value);
12295
12442
  }
12296
12443
  return obj;
12297
12444
  },
12298
12445
  create(base) {
12299
- return RoutesAdjacency_RoutesEntry.fromPartial(base !== null && base !== undefined ? base : {});
12446
+ return RoutesAdjacency_RoutesEntry.fromPartial(base !== null && base !== void 0 ? base : {});
12300
12447
  },
12301
12448
  fromPartial(object) {
12302
12449
  var _a;
12303
12450
  const message = createBaseRoutesAdjacency_RoutesEntry();
12304
- message.key = (_a = object.key) !== null && _a !== undefined ? _a : "";
12305
- message.value = (object.value !== undefined && object.value !== null) ? Route.fromPartial(object.value) : undefined;
12451
+ message.key = (_a = object.key) !== null && _a !== void 0 ? _a : "";
12452
+ message.value = (object.value !== undefined && object.value !== null) ? Route$1.fromPartial(object.value) : undefined;
12306
12453
  return message;
12307
12454
  },
12308
12455
  };
@@ -12324,7 +12471,7 @@ const Transfer = {
12324
12471
  },
12325
12472
  decode(input, length) {
12326
12473
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12327
- let end = length === undefined ? reader.len : reader.pos + length;
12474
+ const end = length === undefined ? reader.len : reader.pos + length;
12328
12475
  const message = createBaseTransfer();
12329
12476
  while (reader.pos < end) {
12330
12477
  const tag = reader.uint32();
@@ -12379,14 +12526,14 @@ const Transfer = {
12379
12526
  return obj;
12380
12527
  },
12381
12528
  create(base) {
12382
- return Transfer.fromPartial(base !== null && base !== undefined ? base : {});
12529
+ return Transfer.fromPartial(base !== null && base !== void 0 ? base : {});
12383
12530
  },
12384
12531
  fromPartial(object) {
12385
12532
  var _a, _b, _c;
12386
12533
  const message = createBaseTransfer();
12387
- message.destination = (_a = object.destination) !== null && _a !== undefined ? _a : 0;
12388
- message.type = (_b = object.type) !== null && _b !== undefined ? _b : 0;
12389
- message.minTransferTime = (_c = object.minTransferTime) !== null && _c !== undefined ? _c : undefined;
12534
+ message.destination = (_a = object.destination) !== null && _a !== void 0 ? _a : 0;
12535
+ message.type = (_b = object.type) !== null && _b !== void 0 ? _b : 0;
12536
+ message.minTransferTime = (_c = object.minTransferTime) !== null && _c !== void 0 ? _c : undefined;
12390
12537
  return message;
12391
12538
  },
12392
12539
  };
@@ -12402,7 +12549,7 @@ const StopsAdjacency = {
12402
12549
  },
12403
12550
  decode(input, length) {
12404
12551
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12405
- let end = length === undefined ? reader.len : reader.pos + length;
12552
+ const end = length === undefined ? reader.len : reader.pos + length;
12406
12553
  const message = createBaseStopsAdjacency();
12407
12554
  while (reader.pos < end) {
12408
12555
  const tag = reader.uint32();
@@ -12449,12 +12596,12 @@ const StopsAdjacency = {
12449
12596
  return obj;
12450
12597
  },
12451
12598
  create(base) {
12452
- return StopsAdjacency.fromPartial(base !== null && base !== undefined ? base : {});
12599
+ return StopsAdjacency.fromPartial(base !== null && base !== void 0 ? base : {});
12453
12600
  },
12454
12601
  fromPartial(object) {
12455
12602
  var _a;
12456
12603
  const message = createBaseStopsAdjacency();
12457
- message.stops = Object.entries((_a = object.stops) !== null && _a !== undefined ? _a : {}).reduce((acc, [key, value]) => {
12604
+ message.stops = Object.entries((_a = object.stops) !== null && _a !== void 0 ? _a : {}).reduce((acc, [key, value]) => {
12458
12605
  if (value !== undefined) {
12459
12606
  acc[key] = StopsAdjacency_StopAdjacency.fromPartial(value);
12460
12607
  }
@@ -12478,7 +12625,7 @@ const StopsAdjacency_StopAdjacency = {
12478
12625
  },
12479
12626
  decode(input, length) {
12480
12627
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12481
- let end = length === undefined ? reader.len : reader.pos + length;
12628
+ const end = length === undefined ? reader.len : reader.pos + length;
12482
12629
  const message = createBaseStopsAdjacency_StopAdjacency();
12483
12630
  while (reader.pos < end) {
12484
12631
  const tag = reader.uint32();
@@ -12507,31 +12654,31 @@ const StopsAdjacency_StopAdjacency = {
12507
12654
  },
12508
12655
  fromJSON(object) {
12509
12656
  return {
12510
- transfers: globalThis.Array.isArray(object === null || object === undefined ? undefined : object.transfers)
12657
+ transfers: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.transfers)
12511
12658
  ? object.transfers.map((e) => Transfer.fromJSON(e))
12512
12659
  : [],
12513
- routes: globalThis.Array.isArray(object === null || object === undefined ? undefined : object.routes) ? object.routes.map((e) => globalThis.String(e)) : [],
12660
+ routes: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.routes) ? object.routes.map((e) => globalThis.String(e)) : [],
12514
12661
  };
12515
12662
  },
12516
12663
  toJSON(message) {
12517
12664
  var _a, _b;
12518
12665
  const obj = {};
12519
- if ((_a = message.transfers) === null || _a === undefined ? undefined : _a.length) {
12666
+ if ((_a = message.transfers) === null || _a === void 0 ? void 0 : _a.length) {
12520
12667
  obj.transfers = message.transfers.map((e) => Transfer.toJSON(e));
12521
12668
  }
12522
- if ((_b = message.routes) === null || _b === undefined ? undefined : _b.length) {
12669
+ if ((_b = message.routes) === null || _b === void 0 ? void 0 : _b.length) {
12523
12670
  obj.routes = message.routes;
12524
12671
  }
12525
12672
  return obj;
12526
12673
  },
12527
12674
  create(base) {
12528
- return StopsAdjacency_StopAdjacency.fromPartial(base !== null && base !== undefined ? base : {});
12675
+ return StopsAdjacency_StopAdjacency.fromPartial(base !== null && base !== void 0 ? base : {});
12529
12676
  },
12530
12677
  fromPartial(object) {
12531
12678
  var _a, _b;
12532
12679
  const message = createBaseStopsAdjacency_StopAdjacency();
12533
- message.transfers = ((_a = object.transfers) === null || _a === undefined ? undefined : _a.map((e) => Transfer.fromPartial(e))) || [];
12534
- message.routes = ((_b = object.routes) === null || _b === undefined ? undefined : _b.map((e) => e)) || [];
12680
+ message.transfers = ((_a = object.transfers) === null || _a === void 0 ? void 0 : _a.map((e) => Transfer.fromPartial(e))) || [];
12681
+ message.routes = ((_b = object.routes) === null || _b === void 0 ? void 0 : _b.map((e) => e)) || [];
12535
12682
  return message;
12536
12683
  },
12537
12684
  };
@@ -12550,7 +12697,7 @@ const StopsAdjacency_StopsEntry = {
12550
12697
  },
12551
12698
  decode(input, length) {
12552
12699
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12553
- let end = length === undefined ? reader.len : reader.pos + length;
12700
+ const end = length === undefined ? reader.len : reader.pos + length;
12554
12701
  const message = createBaseStopsAdjacency_StopsEntry();
12555
12702
  while (reader.pos < end) {
12556
12703
  const tag = reader.uint32();
@@ -12594,12 +12741,12 @@ const StopsAdjacency_StopsEntry = {
12594
12741
  return obj;
12595
12742
  },
12596
12743
  create(base) {
12597
- return StopsAdjacency_StopsEntry.fromPartial(base !== null && base !== undefined ? base : {});
12744
+ return StopsAdjacency_StopsEntry.fromPartial(base !== null && base !== void 0 ? base : {});
12598
12745
  },
12599
12746
  fromPartial(object) {
12600
12747
  var _a;
12601
12748
  const message = createBaseStopsAdjacency_StopsEntry();
12602
- message.key = (_a = object.key) !== null && _a !== undefined ? _a : "";
12749
+ message.key = (_a = object.key) !== null && _a !== void 0 ? _a : "";
12603
12750
  message.value = (object.value !== undefined && object.value !== null)
12604
12751
  ? StopsAdjacency_StopAdjacency.fromPartial(object.value)
12605
12752
  : undefined;
@@ -12621,7 +12768,7 @@ const ServiceRoute = {
12621
12768
  },
12622
12769
  decode(input, length) {
12623
12770
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12624
- let end = length === undefined ? reader.len : reader.pos + length;
12771
+ const end = length === undefined ? reader.len : reader.pos + length;
12625
12772
  const message = createBaseServiceRoute();
12626
12773
  while (reader.pos < end) {
12627
12774
  const tag = reader.uint32();
@@ -12665,13 +12812,13 @@ const ServiceRoute = {
12665
12812
  return obj;
12666
12813
  },
12667
12814
  create(base) {
12668
- return ServiceRoute.fromPartial(base !== null && base !== undefined ? base : {});
12815
+ return ServiceRoute.fromPartial(base !== null && base !== void 0 ? base : {});
12669
12816
  },
12670
12817
  fromPartial(object) {
12671
12818
  var _a, _b;
12672
12819
  const message = createBaseServiceRoute();
12673
- message.type = (_a = object.type) !== null && _a !== undefined ? _a : 0;
12674
- message.name = (_b = object.name) !== null && _b !== undefined ? _b : "";
12820
+ message.type = (_a = object.type) !== null && _a !== void 0 ? _a : 0;
12821
+ message.name = (_b = object.name) !== null && _b !== void 0 ? _b : "";
12675
12822
  return message;
12676
12823
  },
12677
12824
  };
@@ -12687,7 +12834,7 @@ const ServiceRoutesMap = {
12687
12834
  },
12688
12835
  decode(input, length) {
12689
12836
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12690
- let end = length === undefined ? reader.len : reader.pos + length;
12837
+ const end = length === undefined ? reader.len : reader.pos + length;
12691
12838
  const message = createBaseServiceRoutesMap();
12692
12839
  while (reader.pos < end) {
12693
12840
  const tag = reader.uint32();
@@ -12734,12 +12881,12 @@ const ServiceRoutesMap = {
12734
12881
  return obj;
12735
12882
  },
12736
12883
  create(base) {
12737
- return ServiceRoutesMap.fromPartial(base !== null && base !== undefined ? base : {});
12884
+ return ServiceRoutesMap.fromPartial(base !== null && base !== void 0 ? base : {});
12738
12885
  },
12739
12886
  fromPartial(object) {
12740
12887
  var _a;
12741
12888
  const message = createBaseServiceRoutesMap();
12742
- message.routes = Object.entries((_a = object.routes) !== null && _a !== undefined ? _a : {}).reduce((acc, [key, value]) => {
12889
+ message.routes = Object.entries((_a = object.routes) !== null && _a !== void 0 ? _a : {}).reduce((acc, [key, value]) => {
12743
12890
  if (value !== undefined) {
12744
12891
  acc[key] = ServiceRoute.fromPartial(value);
12745
12892
  }
@@ -12763,7 +12910,7 @@ const ServiceRoutesMap_RoutesEntry = {
12763
12910
  },
12764
12911
  decode(input, length) {
12765
12912
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12766
- let end = length === undefined ? reader.len : reader.pos + length;
12913
+ const end = length === undefined ? reader.len : reader.pos + length;
12767
12914
  const message = createBaseServiceRoutesMap_RoutesEntry();
12768
12915
  while (reader.pos < end) {
12769
12916
  const tag = reader.uint32();
@@ -12807,12 +12954,12 @@ const ServiceRoutesMap_RoutesEntry = {
12807
12954
  return obj;
12808
12955
  },
12809
12956
  create(base) {
12810
- return ServiceRoutesMap_RoutesEntry.fromPartial(base !== null && base !== undefined ? base : {});
12957
+ return ServiceRoutesMap_RoutesEntry.fromPartial(base !== null && base !== void 0 ? base : {});
12811
12958
  },
12812
12959
  fromPartial(object) {
12813
12960
  var _a;
12814
12961
  const message = createBaseServiceRoutesMap_RoutesEntry();
12815
- message.key = (_a = object.key) !== null && _a !== undefined ? _a : "";
12962
+ message.key = (_a = object.key) !== null && _a !== void 0 ? _a : "";
12816
12963
  message.value = (object.value !== undefined && object.value !== null)
12817
12964
  ? ServiceRoute.fromPartial(object.value)
12818
12965
  : undefined;
@@ -12840,7 +12987,7 @@ const Timetable$1 = {
12840
12987
  },
12841
12988
  decode(input, length) {
12842
12989
  const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12843
- let end = length === undefined ? reader.len : reader.pos + length;
12990
+ const end = length === undefined ? reader.len : reader.pos + length;
12844
12991
  const message = createBaseTimetable();
12845
12992
  while (reader.pos < end) {
12846
12993
  const tag = reader.uint32();
@@ -12906,12 +13053,12 @@ const Timetable$1 = {
12906
13053
  return obj;
12907
13054
  },
12908
13055
  create(base) {
12909
- return Timetable$1.fromPartial(base !== null && base !== undefined ? base : {});
13056
+ return Timetable$1.fromPartial(base !== null && base !== void 0 ? base : {});
12910
13057
  },
12911
13058
  fromPartial(object) {
12912
13059
  var _a;
12913
13060
  const message = createBaseTimetable();
12914
- message.version = (_a = object.version) !== null && _a !== undefined ? _a : "";
13061
+ message.version = (_a = object.version) !== null && _a !== void 0 ? _a : "";
12915
13062
  message.stopsAdjacency = (object.stopsAdjacency !== undefined && object.stopsAdjacency !== null)
12916
13063
  ? StopsAdjacency.fromPartial(object.stopsAdjacency)
12917
13064
  : undefined;
@@ -12956,119 +13103,555 @@ function isSet(value) {
12956
13103
  return value !== null && value !== undefined;
12957
13104
  }
12958
13105
 
12959
- const isLittleEndian = (() => {
12960
- const buffer = new ArrayBuffer(4);
12961
- const view = new DataView(buffer);
12962
- view.setUint32(0, 0x12345678);
12963
- return new Uint8Array(buffer)[0] === 0x78;
12964
- })();
12965
- const STANDARD_ENDIANNESS = true; // true = little-endian
12966
- function uint32ArrayToBytes(array) {
12967
- if (isLittleEndian === STANDARD_ENDIANNESS) {
12968
- return new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
13106
+ /**
13107
+ * A class representing a time as minutes since midnight.
13108
+ */
13109
+ class Time {
13110
+ /**
13111
+ * Gets the infinity time as a Time instance.
13112
+ * This represents a time that is conceptually beyond any real possible time.
13113
+ *
13114
+ * @returns A Time instance representing an "infinity" time.
13115
+ */
13116
+ static infinity() {
13117
+ return new Time(Number.MAX_SAFE_INTEGER);
12969
13118
  }
12970
- // If endianness doesn't match, we need to swap byte order
12971
- const result = new Uint8Array(array.length * 4);
12972
- const view = new DataView(result.buffer);
12973
- for (let i = 0; i < array.length; i++) {
12974
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
12975
- view.setUint32(i * 4, array[i], STANDARD_ENDIANNESS);
13119
+ /**
13120
+ * Gets the midnight time as a Time instance.
13121
+ *
13122
+ * @returns A Time instance representing midnight.
13123
+ */
13124
+ static origin() {
13125
+ return new Time(0);
12976
13126
  }
12977
- return result;
12978
- }
12979
- function bytesToUint32Array(bytes) {
12980
- if (bytes.byteLength % 4 !== 0) {
12981
- throw new Error('Byte array length must be a multiple of 4 to convert to Uint32Array');
13127
+ constructor(minutes) {
13128
+ this.minutesSinceMidnight = minutes;
12982
13129
  }
12983
- // If system endianness matches our standard, we can create a view directly
12984
- if (isLittleEndian === STANDARD_ENDIANNESS) {
12985
- return new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4);
13130
+ /**
13131
+ * Creates a Time instance from the number of minutes since midnight.
13132
+ *
13133
+ * @param minutes - The number of minutes since midnight.
13134
+ * @returns A Time instance representing the specified time.
13135
+ */
13136
+ static fromMinutes(minutes) {
13137
+ return new Time(minutes);
12986
13138
  }
12987
- // If endianness doesn't match, we need to swap byte order
12988
- const result = new Uint32Array(bytes.byteLength / 4);
12989
- const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
12990
- for (let i = 0; i < result.length; i++) {
12991
- result[i] = view.getUint32(i * 4, STANDARD_ENDIANNESS);
13139
+ /**
13140
+ * Creates a Time instance from hours, minutes, and seconds.
13141
+ * Rounds to the closest minute as times are represented in minutes from midnight.
13142
+ *
13143
+ * @param hours - The hours component of the time.
13144
+ * @param minutes - The minutes component of the time.
13145
+ * @param seconds - The seconds component of the time.
13146
+ * @returns A Time instance representing the specified time.
13147
+ */
13148
+ static fromHMS(hours, minutes, seconds) {
13149
+ if (hours < 0 ||
13150
+ minutes < 0 ||
13151
+ seconds < 0 ||
13152
+ minutes >= 60 ||
13153
+ seconds >= 60) {
13154
+ throw new Error('Invalid time. Ensure hours, minutes, and seconds are valid values.');
13155
+ }
13156
+ const totalSeconds = seconds + 60 * minutes + 3600 * hours;
13157
+ const roundedMinutes = Math.round(totalSeconds / 60);
13158
+ return new Time(roundedMinutes);
12992
13159
  }
12993
- return result;
12994
- }
12995
- function uint16ArrayToBytes(array) {
12996
- if (isLittleEndian === STANDARD_ENDIANNESS) {
12997
- return new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
13160
+ /**
13161
+ * Creates a Time instance from hours, minutes.
13162
+ *
13163
+ * @param hours - The hours component of the time.
13164
+ * @param minutes - The minutes component of the time.
13165
+ * @returns A Time instance representing the specified time.
13166
+ */
13167
+ static fromHM(hours, minutes) {
13168
+ if (hours < 0 || minutes < 0 || minutes >= 60) {
13169
+ throw new Error('Invalid time. Ensure hours and minutes are valid values.');
13170
+ }
13171
+ return new Time(minutes + hours * 60);
12998
13172
  }
12999
- // If endianness doesn't match, we need to swap byte order
13000
- const result = new Uint8Array(array.length * 2);
13001
- const view = new DataView(result.buffer);
13002
- for (let i = 0; i < array.length; i++) {
13003
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13004
- view.setUint16(i * 2, array[i], STANDARD_ENDIANNESS);
13173
+ /**
13174
+ * Parses a JavaScript Date object and creates a Time instance.
13175
+ *
13176
+ * @param date - A JavaScript Date object representing the time.
13177
+ * @returns A Time instance representing the parsed time.
13178
+ */
13179
+ static fromDate(date) {
13180
+ const hours = date.getHours();
13181
+ const minutes = date.getMinutes();
13182
+ const seconds = date.getSeconds();
13183
+ return Time.fromHMS(hours, minutes, seconds);
13005
13184
  }
13006
- return result;
13007
- }
13008
- function bytesToUint16Array(bytes) {
13009
- if (bytes.byteLength % 2 !== 0) {
13010
- throw new Error('Byte array length must be a multiple of 2 to convert to Uint16Array');
13185
+ /**
13186
+ * Parses a time string in the format "HH:MM:SS" or "HH:MM" and creates a Time instance.
13187
+ *
13188
+ * @param timeStr - A string representing the time in "HH:MM:SS" or "HH:MM" format.
13189
+ * @returns A Time instance representing the parsed time.
13190
+ */
13191
+ static fromString(timeStr) {
13192
+ const [hoursStr, minutesStr, secondsStr] = timeStr.split(':');
13193
+ if (hoursStr === undefined ||
13194
+ minutesStr === undefined ||
13195
+ hoursStr.trim() === '' ||
13196
+ minutesStr.trim() === '' ||
13197
+ isNaN(Number(hoursStr)) ||
13198
+ isNaN(Number(minutesStr)) ||
13199
+ (secondsStr !== undefined &&
13200
+ (secondsStr.trim() === '' || isNaN(Number(secondsStr))))) {
13201
+ throw new Error('Input string must be in the format "HH:MM:SS" or "HH:MM".');
13202
+ }
13203
+ const hours = parseInt(hoursStr, 10);
13204
+ const minutes = parseInt(minutesStr, 10);
13205
+ const seconds = secondsStr !== undefined ? parseInt(secondsStr, 10) : 0;
13206
+ return Time.fromHMS(hours, minutes, seconds);
13011
13207
  }
13012
- // If system endianness matches our standard, we can create a view directly
13013
- if (isLittleEndian === STANDARD_ENDIANNESS) {
13014
- return new Uint16Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 2);
13208
+ /**
13209
+ * Converts the Time instance to a string in "HH:MM:SS" format.
13210
+ *
13211
+ * @returns A string representing the time.
13212
+ */
13213
+ toString() {
13214
+ let hours = Math.floor(this.minutesSinceMidnight / 60);
13215
+ const minutes = Math.floor(this.minutesSinceMidnight % 60);
13216
+ if (hours >= 24) {
13217
+ hours = hours % 24;
13218
+ }
13219
+ return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
13015
13220
  }
13016
- // If endianness doesn't match, we need to swap byte order
13017
- const result = new Uint16Array(bytes.byteLength / 2);
13018
- const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
13019
- for (let i = 0; i < result.length; i++) {
13020
- result[i] = view.getUint16(i * 2, STANDARD_ENDIANNESS);
13221
+ /**
13222
+ * Converts the Time instance to the total number of minutes since midnight, rounded to the closest minute.
13223
+ *
13224
+ * @returns The time in minutes since midnight.
13225
+ */
13226
+ toMinutes() {
13227
+ return this.minutesSinceMidnight;
13021
13228
  }
13022
- return result;
13023
- }
13024
- const serializeStopsAdjacency = (stopsAdjacency) => {
13025
- const protoStopsAdjacency = {
13026
- stops: {},
13027
- };
13028
- stopsAdjacency.forEach((value, key) => {
13029
- protoStopsAdjacency.stops[key] = {
13030
- transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: serializeTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
13031
- minTransferTime: transfer.minTransferTime.toSeconds(),
13032
- })))),
13033
- routes: value.routes,
13034
- };
13035
- });
13036
- return protoStopsAdjacency;
13037
- };
13038
- const serializeRoutesAdjacency = (routesAdjacency) => {
13039
- const protoRoutesAdjacency = {
13040
- routes: {},
13041
- };
13042
- routesAdjacency.forEach((value, key) => {
13043
- protoRoutesAdjacency.routes[key] = {
13044
- stopTimes: uint16ArrayToBytes(value.stopTimes),
13045
- pickUpDropOffTypes: value.pickUpDropOffTypes,
13046
- stops: uint32ArrayToBytes(value.stops),
13047
- serviceRouteId: value.serviceRouteId,
13048
- };
13049
- });
13050
- return protoRoutesAdjacency;
13051
- };
13052
- const serializeServiceRoutesMap = (serviceRoutesMap) => {
13053
- const protoServiceRoutesMap = {
13054
- routes: {},
13055
- };
13056
- serviceRoutesMap.forEach((value, key) => {
13057
- protoServiceRoutesMap.routes[key] = {
13058
- type: serializeRouteType(value.type),
13059
- name: value.name,
13060
- };
13061
- });
13062
- return protoServiceRoutesMap;
13063
- };
13064
- const deserializeStopsAdjacency = (protoStopsAdjacency) => {
13065
- const stopsAdjacency = new Map();
13066
- Object.entries(protoStopsAdjacency.stops).forEach(([keyStr, value]) => {
13067
- const key = parseInt(keyStr, 10);
13068
- stopsAdjacency.set(key, {
13069
- transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: parseTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
13070
- minTransferTime: Duration.fromSeconds(transfer.minTransferTime),
13071
- })))),
13229
+ /**
13230
+ * Adds a Duration to the current Time instance and returns a new Time instance.
13231
+ *
13232
+ * @param duration - A Duration instance representing the duration to add.
13233
+ * @returns A new Time instance with the added duration.
13234
+ */
13235
+ plus(duration) {
13236
+ const totalSeconds = this.minutesSinceMidnight * 60 + duration.toSeconds();
13237
+ return new Time(Math.round(totalSeconds / 60));
13238
+ }
13239
+ /**
13240
+ * Subtracts a Duration from the current Time instance and returns a new Time instance.
13241
+ *
13242
+ * @param duration - A Duration instance representing the duration to subtract.
13243
+ * @returns A new Time instance with the subtracted duration.
13244
+ */
13245
+ minus(duration) {
13246
+ let totalSeconds = this.minutesSinceMidnight * 60 - duration.toSeconds();
13247
+ if (totalSeconds < 0) {
13248
+ totalSeconds += 24 * 3600; // Adjust for negative time to loop back to previous day
13249
+ }
13250
+ return new Time(Math.round(totalSeconds / 60));
13251
+ }
13252
+ /**
13253
+ * Subtracts another Time instance from the current Time instance and returns the Duration.
13254
+ *
13255
+ * @param otherTime - A Time instance representing the time to subtract.
13256
+ * @returns A Duration instance representing the time difference.
13257
+ */
13258
+ diff(otherTime) {
13259
+ const totalMinutes = this.minutesSinceMidnight - otherTime.toMinutes();
13260
+ return Duration.fromSeconds(Math.abs(totalMinutes * 60));
13261
+ }
13262
+ /**
13263
+ * Computes the maximum Time instance among the provided Time instances.
13264
+ *
13265
+ * @param times - An array of Time instances to compare.
13266
+ * @returns A Time instance representing the maximum time.
13267
+ */
13268
+ static max(...times) {
13269
+ if (times.length === 0) {
13270
+ throw new Error('At least one Time instance is required.');
13271
+ }
13272
+ return times.reduce((maxTime, currentTime) => {
13273
+ return currentTime.isAfter(maxTime) ? currentTime : maxTime;
13274
+ });
13275
+ }
13276
+ /**
13277
+ * Computes the minimum Time instance among the provided Time instances.
13278
+ *
13279
+ * @param times - An array of Time instances to compare.
13280
+ * @returns A Time instance representing the minimum time.
13281
+ */
13282
+ static min(...times) {
13283
+ if (times.length === 0) {
13284
+ throw new Error('At least one Time instance is required.');
13285
+ }
13286
+ return times.reduce((minTime, currentTime) => {
13287
+ return currentTime.isBefore(minTime) ? currentTime : minTime;
13288
+ });
13289
+ }
13290
+ /**
13291
+ * Determines if the current Time instance is after another Time instance.
13292
+ *
13293
+ * @param otherTime - A Time instance to compare against.
13294
+ * @returns True if the current Time instance is after the other Time instance, otherwise false.
13295
+ */
13296
+ isAfter(otherTime) {
13297
+ return this.minutesSinceMidnight > otherTime.toMinutes();
13298
+ }
13299
+ /**
13300
+ * Determines if the current Time instance is before another Time instance.
13301
+ *
13302
+ * @param otherTime - A Time instance to compare against.
13303
+ * @returns True if the current Time instance is before the other Time instance, otherwise false.
13304
+ */
13305
+ isBefore(otherTime) {
13306
+ return this.minutesSinceMidnight < otherTime.toMinutes();
13307
+ }
13308
+ /**
13309
+ * Determines if the current Time instance is equal to another Time instance.
13310
+ *
13311
+ * @param otherTime - A Time instance to compare against.
13312
+ * @returns True if the current Time instance is equal to the other Time instance, otherwise false.
13313
+ */
13314
+ equals(otherTime) {
13315
+ return this.minutesSinceMidnight === otherTime.toMinutes();
13316
+ }
13317
+ }
13318
+
13319
+ const REGULAR = 0;
13320
+ const NOT_AVAILABLE = 1;
13321
+ const MUST_PHONE_AGENCY = 2;
13322
+ const MUST_COORDINATE_WITH_DRIVER = 3;
13323
+ const pickUpDropOffTypeMap = [
13324
+ 'REGULAR',
13325
+ 'NOT_AVAILABLE',
13326
+ 'MUST_PHONE_AGENCY',
13327
+ 'MUST_COORDINATE_WITH_DRIVER',
13328
+ ];
13329
+ /**
13330
+ * Converts a numerical representation of a pick-up/drop-off type
13331
+ * into its corresponding string representation.
13332
+ *
13333
+ * @param numericalType - The numerical value representing the pick-up/drop-off type.
13334
+ * @returns The corresponding PickUpDropOffType as a string.
13335
+ * @throws An error if the numerical type is invalid.
13336
+ */
13337
+ const toPickupDropOffType = (numericalType) => {
13338
+ const type = pickUpDropOffTypeMap[numericalType];
13339
+ if (!type) {
13340
+ throw new Error(`Invalid pickup/drop-off type ${numericalType}`);
13341
+ }
13342
+ return type;
13343
+ };
13344
+ /**
13345
+ * A route identifies all trips of a given service route sharing the same list of stops.
13346
+ */
13347
+ class Route {
13348
+ constructor(stopTimes, pickUpDropOffTypes, stops, serviceRouteId) {
13349
+ this.stopTimes = stopTimes;
13350
+ this.pickUpDropOffTypes = pickUpDropOffTypes;
13351
+ this.stops = stops;
13352
+ this.serviceRouteId = serviceRouteId;
13353
+ this.nbStops = stops.length;
13354
+ this.nbTrips = this.stopTimes.length / (this.stops.length * 2);
13355
+ this.stopIndices = new Map();
13356
+ for (let i = 0; i < stops.length; i++) {
13357
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13358
+ this.stopIndices.set(stops[i], i);
13359
+ }
13360
+ }
13361
+ /**
13362
+ * Serializes the Route into binary arrays.
13363
+ *
13364
+ * @returns The serialized binary data.
13365
+ */
13366
+ serialize() {
13367
+ return {
13368
+ stopTimes: this.stopTimes,
13369
+ pickUpDropOffTypes: this.pickUpDropOffTypes,
13370
+ stops: this.stops,
13371
+ serviceRouteId: this.serviceRouteId,
13372
+ };
13373
+ }
13374
+ /**
13375
+ * Checks if stop A is before stop B in the route.
13376
+ *
13377
+ * @param stopA - The StopId of the first stop.
13378
+ * @param stopB - The StopId of the second stop.
13379
+ * @returns True if stop A is before stop B, false otherwise.
13380
+ */
13381
+ isBefore(stopA, stopB) {
13382
+ const stopAIndex = this.stopIndices.get(stopA);
13383
+ if (stopAIndex === undefined) {
13384
+ throw new Error(`Stop index ${stopAIndex} not found in route ${this.serviceRouteId}`);
13385
+ }
13386
+ const stopBIndex = this.stopIndices.get(stopB);
13387
+ if (stopBIndex === undefined) {
13388
+ throw new Error(`Stop index ${stopBIndex} not found in route ${this.serviceRouteId}`);
13389
+ }
13390
+ return stopAIndex < stopBIndex;
13391
+ }
13392
+ /**
13393
+ * Retrieves the number of stops in the route.
13394
+ *
13395
+ * @returns The total number of stops in the route.
13396
+ */
13397
+ getNbStops() {
13398
+ return this.nbStops;
13399
+ }
13400
+ /**
13401
+ * Finds the ServiceRouteId of the route. It corresponds the identifier
13402
+ * of the service shown to the end user as a route.
13403
+ *
13404
+ * @returns The ServiceRouteId of the route.
13405
+ */
13406
+ serviceRoute() {
13407
+ return this.serviceRouteId;
13408
+ }
13409
+ /**
13410
+ * Retrieves the arrival time at a specific stop for a given trip.
13411
+ *
13412
+ * @param stopId - The identifier of the stop.
13413
+ * @param tripIndex - The index of the trip.
13414
+ * @returns The arrival time at the specified stop and trip as a Time object.
13415
+ */
13416
+ arrivalAt(stopId, tripIndex) {
13417
+ const arrivalIndex = (tripIndex * this.stops.length + this.stopIndex(stopId)) * 2;
13418
+ const arrival = this.stopTimes[arrivalIndex];
13419
+ if (arrival === undefined) {
13420
+ throw new Error(`Arrival time not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13421
+ }
13422
+ return Time.fromMinutes(arrival);
13423
+ }
13424
+ /**
13425
+ * Retrieves the departure time at a specific stop for a given trip.
13426
+ *
13427
+ * @param stopId - The identifier of the stop.
13428
+ * @param tripIndex - The index of the trip.
13429
+ * @returns The departure time at the specified stop and trip as a Time object.
13430
+ */
13431
+ departureFrom(stopId, tripIndex) {
13432
+ const departureIndex = (tripIndex * this.stops.length + this.stopIndex(stopId)) * 2 + 1;
13433
+ const departure = this.stopTimes[departureIndex];
13434
+ if (departure === undefined) {
13435
+ throw new Error(`Departure time not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13436
+ }
13437
+ return Time.fromMinutes(departure);
13438
+ }
13439
+ /**
13440
+ * Retrieves the pick-up type for a specific stop and trip.
13441
+ *
13442
+ * @param stopId - The identifier of the stop.
13443
+ * @param tripIndex - The index of the trip.
13444
+ * @returns The pick-up type at the specified stop and trip.
13445
+ */
13446
+ pickUpTypeFrom(stopId, tripIndex) {
13447
+ const pickUpIndex = (tripIndex * this.stops.length + this.stopIndex(stopId)) * 2;
13448
+ const pickUpValue = this.pickUpDropOffTypes[pickUpIndex];
13449
+ if (pickUpValue === undefined) {
13450
+ throw new Error(`Pick up type not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13451
+ }
13452
+ return toPickupDropOffType(pickUpValue);
13453
+ }
13454
+ /**
13455
+ * Retrieves the drop-off type for a specific stop and trip.
13456
+ *
13457
+ * @param stopId - The identifier of the stop.
13458
+ * @param tripIndex - The index of the trip.
13459
+ * @returns The drop-off type at the specified stop and trip.
13460
+ */
13461
+ dropOffTypeAt(stopId, tripIndex) {
13462
+ const dropOffIndex = (tripIndex * this.stops.length + this.stopIndex(stopId)) * 2 + 1;
13463
+ const dropOffValue = this.pickUpDropOffTypes[dropOffIndex];
13464
+ if (dropOffValue === undefined) {
13465
+ throw new Error(`Drop off type not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13466
+ }
13467
+ return toPickupDropOffType(dropOffValue);
13468
+ }
13469
+ /**
13470
+ * Iterates over the stops in the route, starting from an optional specified stop.
13471
+ * If no start stop is provided, the iteration begins from the first stop in the route.
13472
+ *
13473
+ * @param [startStopId] - (Optional) The StopId of the stop to start the iteration from.
13474
+ * @returns An IterableIterator of StopIds, starting from the specified stop or the first stop.
13475
+ * @throws An error if the specified start stop is not found in the route.
13476
+ */
13477
+ stopsIterator(startStopId) {
13478
+ const startIndex = startStopId !== undefined ? this.stopIndices.get(startStopId) : 0;
13479
+ if (startIndex === undefined) {
13480
+ throw new Error(`Start stop ${startStopId} not found in route ${this.serviceRouteId}`);
13481
+ }
13482
+ function* generator(stops, startIndex) {
13483
+ for (let i = startIndex; i < stops.length; i++) {
13484
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13485
+ yield stops[i];
13486
+ }
13487
+ }
13488
+ return generator(this.stops, startIndex);
13489
+ }
13490
+ /**
13491
+ * Finds the earliest trip that can be taken from a specific stop on a given route,
13492
+ * optionally constrained by a latest trip index and a time before which the trip
13493
+ * should not depart.
13494
+ * *
13495
+ * @param stopId - The StopId of the stop where the trip should be found.
13496
+ * @param [after=Time.origin()] - The earliest time after which the trip should depart.
13497
+ * If not provided, searches all available trips.
13498
+ * @param [beforeTrip] - (Optional) The index of the trip before which the search should be constrained.
13499
+ * If not provided, searches all available trips.
13500
+ * @returns The index of the earliest trip meeting the criteria, or undefined if no such trip is found.
13501
+ */
13502
+ findEarliestTrip(stopId, after = Time.origin(), beforeTrip) {
13503
+ const maxTripIndex = beforeTrip !== undefined
13504
+ ? Math.min(beforeTrip - 1, this.nbTrips - 1)
13505
+ : this.nbTrips - 1;
13506
+ if (maxTripIndex < 0) {
13507
+ return undefined;
13508
+ }
13509
+ let earliestTripIndex;
13510
+ let lowTrip = 0;
13511
+ let highTrip = maxTripIndex;
13512
+ while (lowTrip <= highTrip) {
13513
+ const midTrip = Math.floor((lowTrip + highTrip) / 2);
13514
+ const departure = this.departureFrom(stopId, midTrip);
13515
+ const pickUpType = this.pickUpTypeFrom(stopId, midTrip);
13516
+ if ((departure.isAfter(after) || departure.equals(after)) &&
13517
+ pickUpType !== 'NOT_AVAILABLE') {
13518
+ earliestTripIndex = midTrip;
13519
+ highTrip = midTrip - 1;
13520
+ }
13521
+ else {
13522
+ lowTrip = midTrip + 1;
13523
+ }
13524
+ }
13525
+ return earliestTripIndex;
13526
+ }
13527
+ /**
13528
+ * Retrieves the index of a stop within the route.
13529
+ * @param stopId The StopId of the stop to locate in the route.
13530
+ * @returns The index of the stop in the route.
13531
+ */
13532
+ stopIndex(stopId) {
13533
+ const stopIndex = this.stopIndices.get(stopId);
13534
+ if (stopIndex === undefined) {
13535
+ throw new Error(`Stop index for ${stopId} not found in route ${this.serviceRouteId}`);
13536
+ }
13537
+ return stopIndex;
13538
+ }
13539
+ }
13540
+
13541
+ const isLittleEndian = (() => {
13542
+ const buffer = new ArrayBuffer(4);
13543
+ const view = new DataView(buffer);
13544
+ view.setUint32(0, 0x12345678);
13545
+ return new Uint8Array(buffer)[0] === 0x78;
13546
+ })();
13547
+ const STANDARD_ENDIANNESS = true; // true = little-endian
13548
+ const uint32ArrayToBytes = (array) => {
13549
+ if (isLittleEndian === STANDARD_ENDIANNESS) {
13550
+ return new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
13551
+ }
13552
+ // If endianness doesn't match, we need to swap byte order
13553
+ const result = new Uint8Array(array.length * 4);
13554
+ const view = new DataView(result.buffer);
13555
+ for (let i = 0; i < array.length; i++) {
13556
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13557
+ view.setUint32(i * 4, array[i], STANDARD_ENDIANNESS);
13558
+ }
13559
+ return result;
13560
+ };
13561
+ const bytesToUint32Array = (bytes) => {
13562
+ if (bytes.byteLength % 4 !== 0) {
13563
+ throw new Error('Byte array length must be a multiple of 4 to convert to Uint32Array');
13564
+ }
13565
+ // If system endianness matches our standard, we can create a view directly
13566
+ if (isLittleEndian === STANDARD_ENDIANNESS) {
13567
+ return new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4);
13568
+ }
13569
+ // If endianness doesn't match, we need to swap byte order
13570
+ const result = new Uint32Array(bytes.byteLength / 4);
13571
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
13572
+ for (let i = 0; i < result.length; i++) {
13573
+ result[i] = view.getUint32(i * 4, STANDARD_ENDIANNESS);
13574
+ }
13575
+ return result;
13576
+ };
13577
+ const uint16ArrayToBytes = (array) => {
13578
+ if (isLittleEndian === STANDARD_ENDIANNESS) {
13579
+ return new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
13580
+ }
13581
+ // If endianness doesn't match, we need to swap byte order
13582
+ const result = new Uint8Array(array.length * 2);
13583
+ const view = new DataView(result.buffer);
13584
+ for (let i = 0; i < array.length; i++) {
13585
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13586
+ view.setUint16(i * 2, array[i], STANDARD_ENDIANNESS);
13587
+ }
13588
+ return result;
13589
+ };
13590
+ const bytesToUint16Array = (bytes) => {
13591
+ if (bytes.byteLength % 2 !== 0) {
13592
+ throw new Error('Byte array length must be a multiple of 2 to convert to Uint16Array');
13593
+ }
13594
+ // If system endianness matches our standard, we can create a view directly
13595
+ if (isLittleEndian === STANDARD_ENDIANNESS) {
13596
+ return new Uint16Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 2);
13597
+ }
13598
+ // If endianness doesn't match, we need to swap byte order
13599
+ const result = new Uint16Array(bytes.byteLength / 2);
13600
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
13601
+ for (let i = 0; i < result.length; i++) {
13602
+ result[i] = view.getUint16(i * 2, STANDARD_ENDIANNESS);
13603
+ }
13604
+ return result;
13605
+ };
13606
+ const serializeStopsAdjacency = (stopsAdjacency) => {
13607
+ const protoStopsAdjacency = {
13608
+ stops: {},
13609
+ };
13610
+ stopsAdjacency.forEach((value, key) => {
13611
+ protoStopsAdjacency.stops[key] = {
13612
+ transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: serializeTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
13613
+ minTransferTime: transfer.minTransferTime.toSeconds(),
13614
+ })))),
13615
+ routes: value.routes,
13616
+ };
13617
+ });
13618
+ return protoStopsAdjacency;
13619
+ };
13620
+ const serializeRoutesAdjacency = (routesAdjacency) => {
13621
+ const protoRoutesAdjacency = {
13622
+ routes: {},
13623
+ };
13624
+ routesAdjacency.forEach((route, key) => {
13625
+ const routeData = route.serialize();
13626
+ protoRoutesAdjacency.routes[key] = {
13627
+ stopTimes: uint16ArrayToBytes(routeData.stopTimes),
13628
+ pickUpDropOffTypes: routeData.pickUpDropOffTypes,
13629
+ stops: uint32ArrayToBytes(routeData.stops),
13630
+ serviceRouteId: routeData.serviceRouteId,
13631
+ };
13632
+ });
13633
+ return protoRoutesAdjacency;
13634
+ };
13635
+ const serializeServiceRoutesMap = (serviceRoutesMap) => {
13636
+ const protoServiceRoutesMap = {
13637
+ routes: {},
13638
+ };
13639
+ serviceRoutesMap.forEach((value, key) => {
13640
+ protoServiceRoutesMap.routes[key] = {
13641
+ type: serializeRouteType(value.type),
13642
+ name: value.name,
13643
+ };
13644
+ });
13645
+ return protoServiceRoutesMap;
13646
+ };
13647
+ const deserializeStopsAdjacency = (protoStopsAdjacency) => {
13648
+ const stopsAdjacency = new Map();
13649
+ Object.entries(protoStopsAdjacency.stops).forEach(([keyStr, value]) => {
13650
+ const key = parseInt(keyStr, 10);
13651
+ stopsAdjacency.set(key, {
13652
+ transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: parseTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
13653
+ minTransferTime: Duration.fromSeconds(transfer.minTransferTime),
13654
+ })))),
13072
13655
  routes: value.routes,
13073
13656
  });
13074
13657
  });
@@ -13078,18 +13661,7 @@ const deserializeRoutesAdjacency = (protoRoutesAdjacency) => {
13078
13661
  const routesAdjacency = new Map();
13079
13662
  Object.entries(protoRoutesAdjacency.routes).forEach(([key, value]) => {
13080
13663
  const stops = bytesToUint32Array(value.stops);
13081
- const indices = new Map();
13082
- for (let i = 0; i < stops.length; i++) {
13083
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13084
- indices.set(stops[i], i);
13085
- }
13086
- routesAdjacency.set(key, {
13087
- stopTimes: bytesToUint16Array(value.stopTimes),
13088
- pickUpDropOffTypes: value.pickUpDropOffTypes,
13089
- stops: stops,
13090
- stopIndices: indices,
13091
- serviceRouteId: value.serviceRouteId,
13092
- });
13664
+ routesAdjacency.set(key, new Route(bytesToUint16Array(value.stopTimes), value.pickUpDropOffTypes, stops, value.serviceRouteId));
13093
13665
  });
13094
13666
  return routesAdjacency;
13095
13667
  };
@@ -13181,195 +13753,7 @@ const serializeRouteType = (type) => {
13181
13753
  }
13182
13754
  };
13183
13755
 
13184
- /**
13185
- * A class representing a time as minutes since midnight.
13186
- */
13187
- class Time {
13188
- /**
13189
- * Gets the infinity time as a Time instance.
13190
- * This represents a time that is conceptually beyond any real possible time.
13191
- *
13192
- * @returns A Time instance representing an "infinity" time.
13193
- */
13194
- static infinity() {
13195
- return new Time(Number.MAX_SAFE_INTEGER);
13196
- }
13197
- /**
13198
- * Gets the midnight time as a Time instance.
13199
- *
13200
- * @returns A Time instance representing midnight.
13201
- */
13202
- static origin() {
13203
- return new Time(0);
13204
- }
13205
- constructor(minutes) {
13206
- this.minutesSinceMidnight = minutes;
13207
- }
13208
- /**
13209
- * Creates a Time instance from the number of minutes since midnight.
13210
- *
13211
- * @param minutes - The number of minutes since midnight.
13212
- * @returns A Time instance representing the specified time.
13213
- */
13214
- static fromMinutes(minutes) {
13215
- return new Time(minutes);
13216
- }
13217
- /**
13218
- * Creates a Time instance from hours, minutes, and seconds.
13219
- * Rounds to the closest minute as times are represented in minutes from midnight.
13220
- *
13221
- * @param hours - The hours component of the time.
13222
- * @param minutes - The minutes component of the time.
13223
- * @param seconds - The seconds component of the time.
13224
- * @returns A Time instance representing the specified time.
13225
- */
13226
- static fromHMS(hours, minutes, seconds) {
13227
- if (hours < 0 ||
13228
- minutes < 0 ||
13229
- seconds < 0 ||
13230
- minutes >= 60 ||
13231
- seconds >= 60) {
13232
- throw new Error('Invalid time. Ensure hours, minutes, and seconds are valid values.');
13233
- }
13234
- const totalSeconds = seconds + 60 * minutes + 3600 * hours;
13235
- const roundedMinutes = Math.round(totalSeconds / 60);
13236
- return new Time(roundedMinutes);
13237
- }
13238
- /**
13239
- * Creates a Time instance from hours, minutes.
13240
- *
13241
- * @param hours - The hours component of the time.
13242
- * @param minutes - The minutes component of the time.
13243
- * @returns A Time instance representing the specified time.
13244
- */
13245
- static fromHM(hours, minutes) {
13246
- if (hours < 0 || minutes < 0 || minutes >= 60) {
13247
- throw new Error('Invalid time. Ensure hours and minutes are valid values.');
13248
- }
13249
- return new Time(minutes + hours * 60);
13250
- }
13251
- /**
13252
- * Parses a JavaScript Date object and creates a Time instance.
13253
- *
13254
- * @param date - A JavaScript Date object representing the time.
13255
- * @returns A Time instance representing the parsed time.
13256
- */
13257
- static fromDate(date) {
13258
- const hours = date.getHours();
13259
- const minutes = date.getMinutes();
13260
- const seconds = date.getSeconds();
13261
- return Time.fromHMS(hours, minutes, seconds);
13262
- }
13263
- /**
13264
- * Parses a time string in the format "HH:MM:SS" or "HH:MM" and creates a Time instance.
13265
- *
13266
- * @param timeStr - A string representing the time in "HH:MM:SS" or "HH:MM" format.
13267
- * @returns A Time instance representing the parsed time.
13268
- */
13269
- static fromString(timeStr) {
13270
- const [hoursStr, minutesStr, secondsStr] = timeStr.split(':');
13271
- if (hoursStr === undefined ||
13272
- minutesStr === undefined ||
13273
- isNaN(Number(hoursStr)) ||
13274
- isNaN(Number(minutesStr)) ||
13275
- (secondsStr !== undefined && isNaN(Number(secondsStr)))) {
13276
- throw new Error('Input string must be in the format "HH:MM:SS" or "HH:MM".');
13277
- }
13278
- const hours = parseInt(hoursStr, 10);
13279
- const minutes = parseInt(minutesStr, 10);
13280
- const seconds = secondsStr !== undefined ? parseInt(secondsStr, 10) : 0;
13281
- return Time.fromHMS(hours, minutes, seconds);
13282
- }
13283
- /**
13284
- * Converts the Time instance to a string in "HH:MM:SS" format.
13285
- *
13286
- * @returns A string representing the time.
13287
- */
13288
- toString() {
13289
- const hours = Math.floor(this.minutesSinceMidnight / 60);
13290
- const minutes = Math.floor(this.minutesSinceMidnight % 60);
13291
- return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
13292
- }
13293
- /**
13294
- * Converts the Time instance to the total number of minutes since midnight, rounded to the closest minute.
13295
- *
13296
- * @returns The time in minutes since midnight.
13297
- */
13298
- toMinutes() {
13299
- return this.minutesSinceMidnight;
13300
- }
13301
- /**
13302
- * Adds a Duration to the current Time instance and returns a new Time instance.
13303
- *
13304
- * @param duration - A Duration instance representing the duration to add.
13305
- * @returns A new Time instance with the added duration.
13306
- */
13307
- plus(duration) {
13308
- const totalSeconds = this.minutesSinceMidnight * 60 + duration.toSeconds();
13309
- return new Time(Math.round(totalSeconds / 60));
13310
- }
13311
- /**
13312
- * Subtracts a Duration from the current Time instance and returns a new Time instance.
13313
- *
13314
- * @param duration - A Duration instance representing the duration to subtract.
13315
- * @returns A new Time instance with the subtracted duration.
13316
- */
13317
- minus(duration) {
13318
- let totalSeconds = this.minutesSinceMidnight * 60 - duration.toSeconds();
13319
- if (totalSeconds < 0) {
13320
- totalSeconds += 24 * 3600; // Adjust for negative time to loop back to previous day
13321
- }
13322
- return new Time(Math.round(totalSeconds / 60));
13323
- }
13324
- /**
13325
- * Subtracts another Time instance from the current Time instance and returns the Duration.
13326
- *
13327
- * @param otherTime - A Time instance representing the time to subtract.
13328
- * @returns A Duration instance representing the time difference.
13329
- */
13330
- diff(otherTime) {
13331
- const totalMinutes = this.minutesSinceMidnight - otherTime.toMinutes();
13332
- return Duration.fromSeconds(Math.abs(totalMinutes * 60));
13333
- }
13334
- /**
13335
- * Computes the maximum Time instance among the provided Time instances.
13336
- *
13337
- * @param times - An array of Time instances to compare.
13338
- * @returns A Time instance representing the maximum time.
13339
- */
13340
- static max(...times) {
13341
- if (times.length === 0) {
13342
- throw new Error('At least one Time instance is required.');
13343
- }
13344
- return times.reduce((maxTime, currentTime) => {
13345
- return currentTime.toMinutes() > maxTime.toMinutes()
13346
- ? currentTime
13347
- : maxTime;
13348
- });
13349
- }
13350
- /**
13351
- * Computes the minimum Time instance among the provided Time instances.
13352
- *
13353
- * @param times - An array of Time instances to compare.
13354
- * @returns A Time instance representing the minimum time.
13355
- */
13356
- static min(...times) {
13357
- if (times.length === 0) {
13358
- throw new Error('At least one Time instance is required.');
13359
- }
13360
- return times.reduce((minTime, currentTime) => {
13361
- return currentTime.toMinutes() < minTime.toMinutes()
13362
- ? currentTime
13363
- : minTime;
13364
- });
13365
- }
13366
- }
13367
-
13368
- const REGULAR = 0;
13369
- const NOT_AVAILABLE = 1;
13370
- const MUST_PHONE_AGENCY = 2;
13371
- const MUST_COORDINATE_WITH_DRIVER = 3;
13372
- const ALL_TRANSPORT_MODES = [
13756
+ const ALL_TRANSPORT_MODES = new Set([
13373
13757
  'TRAM',
13374
13758
  'SUBWAY',
13375
13759
  'RAIL',
@@ -13380,11 +13764,10 @@ const ALL_TRANSPORT_MODES = [
13380
13764
  'FUNICULAR',
13381
13765
  'TROLLEYBUS',
13382
13766
  'MONORAIL',
13383
- ];
13767
+ ]);
13384
13768
  const CURRENT_VERSION = '0.0.3';
13385
13769
  /**
13386
- * The internal transit timetable format
13387
- * reuses some GTFS concepts for the sake of simplicity for now.
13770
+ * The internal transit timetable format.
13388
13771
  */
13389
13772
  class Timetable {
13390
13773
  constructor(stopsAdjacency, routesAdjacency, routes) {
@@ -13393,9 +13776,9 @@ class Timetable {
13393
13776
  this.routes = routes;
13394
13777
  }
13395
13778
  /**
13396
- * Serializes the Timetable into a binary protobuf.
13779
+ * Serializes the Timetable into a binary array.
13397
13780
  *
13398
- * @returns {Uint8Array} - The serialized binary data.
13781
+ * @returns The serialized binary data.
13399
13782
  */
13400
13783
  serialize() {
13401
13784
  const protoTimetable = {
@@ -13411,8 +13794,8 @@ class Timetable {
13411
13794
  /**
13412
13795
  * Deserializes a binary protobuf into a Timetable object.
13413
13796
  *
13414
- * @param {Uint8Array} data - The binary data to deserialize.
13415
- * @returns {Timetable} - The deserialized Timetable object.
13797
+ * @param data - The binary data to deserialize.
13798
+ * @returns The deserialized Timetable object.
13416
13799
  */
13417
13800
  static fromData(data) {
13418
13801
  const reader = new BinaryReader(data);
@@ -13428,108 +13811,89 @@ class Timetable {
13428
13811
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13429
13812
  deserializeServiceRoutesMap(protoTimetable.routes));
13430
13813
  }
13431
- getRoutesThroughStop(stopId) {
13432
- const stopAdjacency = this.stopsAdjacency.get(stopId);
13433
- if (!stopAdjacency) {
13434
- return [];
13435
- }
13436
- return stopAdjacency.routes;
13437
- }
13814
+ /**
13815
+ * Retrieves the route associated with the given route ID.
13816
+ *
13817
+ * @param routeId - The ID of the route to be retrieved.
13818
+ * @returns The route corresponding to the provided ID,
13819
+ * or undefined if no such route exists.
13820
+ */
13438
13821
  getRoute(routeId) {
13439
13822
  return this.routesAdjacency.get(routeId);
13440
13823
  }
13824
+ /**
13825
+ * Retrieves all transfer options available at the specified stop.
13826
+ *
13827
+ * @param stopId - The ID of the stop to get transfers for.
13828
+ * @returns An array of transfer options available at the stop.
13829
+ */
13441
13830
  getTransfers(stopId) {
13442
13831
  var _a, _b;
13443
- return (_b = (_a = this.stopsAdjacency.get(stopId)) === null || _a === undefined ? undefined : _a.transfers) !== null && _b !== undefined ? _b : [];
13832
+ return (_b = (_a = this.stopsAdjacency.get(stopId)) === null || _a === void 0 ? void 0 : _a.transfers) !== null && _b !== void 0 ? _b : [];
13833
+ }
13834
+ /**
13835
+ * Retrieves the service route associated with the given route.
13836
+ * A service route refers to a collection of trips that are displayed
13837
+ * to riders as a single service.
13838
+ *
13839
+ * @param route - The route for which the service route is to be retrieved.
13840
+ * @returns The service route corresponding to the provided route.
13841
+ */
13842
+ getServiceRoute(route) {
13843
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13844
+ return this.routes.get(route.serviceRoute());
13845
+ }
13846
+ /**
13847
+ * Finds all routes passing through a stop.
13848
+ *
13849
+ * @param stopId - The ID of the stop to find routes for.
13850
+ * @returns An array of routes passing through the specified stop.
13851
+ */
13852
+ routesPassingThrough(stopId) {
13853
+ const stopData = this.stopsAdjacency.get(stopId);
13854
+ if (!stopData) {
13855
+ return [];
13856
+ }
13857
+ const routes = [];
13858
+ for (const routeId of stopData.routes) {
13859
+ const route = this.routesAdjacency.get(routeId);
13860
+ if (route) {
13861
+ routes.push(route);
13862
+ }
13863
+ }
13864
+ return routes;
13444
13865
  }
13445
13866
  /**
13446
13867
  * Finds routes that are reachable from a set of stop IDs.
13447
13868
  * Also identifies the first stop available to hop on each route among
13448
13869
  * the input stops.
13870
+ *
13871
+ * @param fromStops - The set of stop IDs to find reachable routes from.
13872
+ * @param transportModes - The set of transport modes to consider for reachable routes.
13873
+ * @returns A map of reachable routes to the first stop available to hop on each route.
13449
13874
  */
13450
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
13451
13875
  findReachableRoutes(fromStops, transportModes = ALL_TRANSPORT_MODES) {
13452
- var _a;
13453
13876
  const reachableRoutes = new Map();
13454
- for (const stop of fromStops) {
13455
- const validRoutes = (_a = this.stopsAdjacency
13456
- .get(stop)) === null || _a === undefined ? undefined : _a.routes.filter((routeId) => {
13457
- const serviceRoute = this.getServiceRouteFromRouteId(routeId);
13458
- if (!serviceRoute) {
13459
- return false;
13460
- }
13461
- return transportModes.includes(serviceRoute.type);
13877
+ for (const originStop of fromStops) {
13878
+ const validRoutes = this.routesPassingThrough(originStop).filter((route) => {
13879
+ const serviceRoute = this.getServiceRoute(route);
13880
+ return transportModes.has(serviceRoute.type);
13462
13881
  });
13463
- for (const routeId of validRoutes || []) {
13464
- const hopOnStop = reachableRoutes.get(routeId);
13882
+ for (const route of validRoutes) {
13883
+ const hopOnStop = reachableRoutes.get(route);
13465
13884
  if (hopOnStop) {
13466
- // Checks if the existing hop on stop is before the current stop
13467
- const routeStopIndices = this.routesAdjacency.get(routeId).stopIndices;
13468
- const stopIndex = routeStopIndices.get(stop);
13469
- const hopOnStopIndex = routeStopIndices.get(hopOnStop);
13470
- if (stopIndex < hopOnStopIndex) {
13885
+ if (route.isBefore(originStop, hopOnStop)) {
13471
13886
  // if the current stop is before the existing hop on stop, replace it
13472
- reachableRoutes.set(routeId, stop);
13887
+ reachableRoutes.set(route, originStop);
13473
13888
  }
13474
13889
  }
13475
13890
  else {
13476
- reachableRoutes.set(routeId, stop);
13891
+ reachableRoutes.set(route, originStop);
13477
13892
  }
13478
13893
  }
13479
13894
  }
13480
13895
  return reachableRoutes;
13481
13896
  }
13482
- getServiceRouteFromRouteId(routeId) {
13483
- const route = this.routesAdjacency.get(routeId);
13484
- if (!route) {
13485
- console.warn(`Route ${routeId} not found.`);
13486
- return undefined;
13487
- }
13488
- return this.routes.get(route.serviceRouteId);
13489
- }
13490
- getServiceRoute(serviceRouteId) {
13491
- return this.routes.get(serviceRouteId);
13492
- }
13493
- /**
13494
- * Finds the earliest trip that can be taken from a specific stop on a given route,
13495
- * optionally constrained by a latest trip index and a time before which the trip
13496
- * should not depart.
13497
- */
13498
- findEarliestTrip(route, stopId, beforeTrip, after = Time.origin()) {
13499
- const stopIndex = route.stopIndices.get(stopId);
13500
- const stopsNumber = route.stops.length;
13501
- if (beforeTrip === undefined) {
13502
- for (let tripIndex = 0; tripIndex < route.stopTimes.length / stopsNumber; tripIndex++) {
13503
- const stopTimeIndex = tripIndex * stopsNumber + stopIndex;
13504
- const departure = route.stopTimes[stopTimeIndex * 2 + 1];
13505
- const pickUpType = route.pickUpDropOffTypes[stopTimeIndex * 2];
13506
- if (departure >= after.toMinutes() && pickUpType !== NOT_AVAILABLE) {
13507
- return tripIndex;
13508
- }
13509
- }
13510
- return undefined;
13511
- }
13512
- else {
13513
- let earliestTripIndex;
13514
- let earliestDeparture;
13515
- for (let tripIndex = beforeTrip; // ?? route.stopTimes.length / stopsNumber - 1;
13516
- tripIndex >= 0; tripIndex--) {
13517
- const stopTimeIndex = tripIndex * stopsNumber + stopIndex;
13518
- const departure = route.stopTimes[stopTimeIndex * 2 + 1];
13519
- const pickUpType = route.pickUpDropOffTypes[stopTimeIndex * 2];
13520
- if (departure < after.toMinutes()) {
13521
- break;
13522
- }
13523
- if (pickUpType !== NOT_AVAILABLE &&
13524
- (earliestDeparture === undefined ||
13525
- departure < earliestDeparture.toMinutes())) {
13526
- earliestTripIndex = tripIndex;
13527
- earliestDeparture = Time.fromMinutes(departure);
13528
- }
13529
- }
13530
- return earliestTripIndex;
13531
- }
13532
- }
13533
13897
  }
13534
13898
 
13535
13899
  const standardProfile = {
@@ -13846,7 +14210,7 @@ const normalize_options = function (opts) {
13846
14210
  );
13847
14211
  }
13848
14212
  // Normalize option `columns`
13849
- options.cast_first_line_to_header = null;
14213
+ options.cast_first_line_to_header = undefined;
13850
14214
  if (options.columns === true) {
13851
14215
  // Fields in the first line are converted as-is to columns
13852
14216
  options.cast_first_line_to_header = undefined;
@@ -14378,7 +14742,7 @@ const normalize_options = function (opts) {
14378
14742
  // Normalize option `to`
14379
14743
  if (options.to === undefined || options.to === null) {
14380
14744
  options.to = -1;
14381
- } else {
14745
+ } else if (options.to !== -1) {
14382
14746
  if (typeof options.to === "string" && /\d+/.test(options.to)) {
14383
14747
  options.to = parseInt(options.to);
14384
14748
  }
@@ -14397,7 +14761,7 @@ const normalize_options = function (opts) {
14397
14761
  // Normalize option `to_line`
14398
14762
  if (options.to_line === undefined || options.to_line === null) {
14399
14763
  options.to_line = -1;
14400
- } else {
14764
+ } else if (options.to_line !== -1) {
14401
14765
  if (typeof options.to_line === "string" && /\d+/.test(options.to_line)) {
14402
14766
  options.to_line = parseInt(options.to_line);
14403
14767
  }
@@ -14528,10 +14892,14 @@ const transform = function (original_options = {}) {
14528
14892
  this.state.bufBytesStart += bomLength;
14529
14893
  buf = buf.slice(bomLength);
14530
14894
  // Renormalize original options with the new encoding
14531
- this.options = normalize_options({
14895
+ const options = normalize_options({
14532
14896
  ...this.original_options,
14533
14897
  encoding: encoding,
14534
14898
  });
14899
+ // Properties are merged with the existing options instance
14900
+ for (const key in options) {
14901
+ this.options[key] = options[key];
14902
+ }
14535
14903
  // Options will re-evaluate the Buffer with the new encoding
14536
14904
  ({ comment, escape, quote } = this.options);
14537
14905
  break;
@@ -15274,10 +15642,14 @@ const transform = function (original_options = {}) {
15274
15642
  if (skip_records_with_error) {
15275
15643
  this.state.recordHasError = true;
15276
15644
  if (this.options.on_skip !== undefined) {
15277
- this.options.on_skip(
15278
- err,
15279
- raw ? this.state.rawBuffer.toString(encoding) : undefined,
15280
- );
15645
+ try {
15646
+ this.options.on_skip(
15647
+ err,
15648
+ raw ? this.state.rawBuffer.toString(encoding) : undefined,
15649
+ );
15650
+ } catch (err) {
15651
+ return err;
15652
+ }
15281
15653
  }
15282
15654
  // this.emit('skip', err, raw ? this.state.rawBuffer.toString(encoding) : undefined);
15283
15655
  return undefined;
@@ -15474,11 +15846,17 @@ const hashIds = (ids) => {
15474
15846
  * @param stream The CSV stream.
15475
15847
  * @returns A parser from the csv-parse library.
15476
15848
  */
15477
- const parseCsv = (stream) => {
15849
+ const parseCsv = (stream, numericColumns = []) => {
15478
15850
  return stream.pipe(parse({
15479
15851
  delimiter: ',',
15480
15852
  columns: true,
15481
- cast: true,
15853
+ cast: (value, context) => {
15854
+ if (typeof context.column === 'string' &&
15855
+ numericColumns.includes(context.column)) {
15856
+ return Number(value);
15857
+ }
15858
+ return value;
15859
+ },
15482
15860
  bom: true,
15483
15861
  ignore_last_delimiters: true,
15484
15862
  relax_column_count: true,
@@ -15492,11 +15870,11 @@ const parseCsv = (stream) => {
15492
15870
  * @param profile A configuration object defining the specificities of the GTFS feed.
15493
15871
  * @returns A map of all the valid routes.
15494
15872
  */
15495
- const parseRoutes = (routesStream_1, ...args_1) => __awaiter(undefined, [routesStream_1, ...args_1], undefined, function* (routesStream, profile = standardProfile) {
15873
+ const parseRoutes = (routesStream_1, ...args_1) => __awaiter(void 0, [routesStream_1, ...args_1], void 0, function* (routesStream, profile = standardProfile) {
15496
15874
  var _a, e_1, _b, _c;
15497
15875
  const routes = new Map();
15498
15876
  try {
15499
- for (var _d = true, _e = __asyncValues(parseCsv(routesStream)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15877
+ for (var _d = true, _e = __asyncValues(parseCsv(routesStream, ['route_type'])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15500
15878
  _c = _f.value;
15501
15879
  _d = false;
15502
15880
  const rawLine = _c;
@@ -15507,7 +15885,7 @@ const parseRoutes = (routesStream_1, ...args_1) => __awaiter(undefined, [routesS
15507
15885
  continue;
15508
15886
  }
15509
15887
  routes.set(line.route_id, {
15510
- name: line.route_short_name + '',
15888
+ name: line.route_short_name,
15511
15889
  type: routeType,
15512
15890
  });
15513
15891
  }
@@ -15560,13 +15938,23 @@ const weekdays = {
15560
15938
  * @param date The active date.
15561
15939
  * @param calendarStream A readable stream for the GTFS calendar.txt file.
15562
15940
  */
15563
- const parseCalendar = (calendarStream, serviceIds, date) => __awaiter(undefined, undefined, undefined, function* () {
15941
+ const parseCalendar = (calendarStream, serviceIds, date) => __awaiter(void 0, void 0, void 0, function* () {
15564
15942
  var _a, e_1, _b, _c;
15565
15943
  const activeDate = toGtfsDate(date);
15566
15944
  const weekday = date.weekday;
15567
15945
  const weekdayIndex = weekdays[weekday];
15568
15946
  try {
15569
- for (var _d = true, _e = __asyncValues(parseCsv(calendarStream)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15947
+ for (var _d = true, _e = __asyncValues(parseCsv(calendarStream, [
15948
+ 'monday',
15949
+ 'tuesday',
15950
+ 'wednesday',
15951
+ 'thursday',
15952
+ 'friday',
15953
+ 'saturday',
15954
+ 'sunday',
15955
+ 'start_date',
15956
+ 'end_date',
15957
+ ])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15570
15958
  _c = _f.value;
15571
15959
  _d = false;
15572
15960
  const rawLine = _c;
@@ -15597,11 +15985,14 @@ const parseCalendar = (calendarStream, serviceIds, date) => __awaiter(undefined,
15597
15985
  * @param date The active date, in the format "YYYYMMDD".
15598
15986
  * @param calendarDatesStream A readable stream for the GTFS calendar_dates.txt file.
15599
15987
  */
15600
- const parseCalendarDates = (calendarDatesStream, serviceIds, date) => __awaiter(undefined, undefined, undefined, function* () {
15988
+ const parseCalendarDates = (calendarDatesStream, serviceIds, date) => __awaiter(void 0, void 0, void 0, function* () {
15601
15989
  var _a, e_2, _b, _c;
15602
15990
  const activeDate = toGtfsDate(date);
15603
15991
  try {
15604
- for (var _d = true, _e = __asyncValues(parseCsv(calendarDatesStream)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15992
+ for (var _d = true, _e = __asyncValues(parseCsv(calendarDatesStream, [
15993
+ 'date',
15994
+ 'exception_type',
15995
+ ])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15605
15996
  _c = _f.value;
15606
15997
  _d = false;
15607
15998
  const rawLine = _c;
@@ -15634,17 +16025,21 @@ const parseCalendarDates = (calendarDatesStream, serviceIds, date) => __awaiter(
15634
16025
  * @param stopsStream The readable stream containing the stops data.
15635
16026
  * @return A mapping of stop IDs to corresponding stop details.
15636
16027
  */
15637
- const parseStops = (stopsStream, platformParser) => __awaiter(undefined, undefined, undefined, function* () {
16028
+ const parseStops = (stopsStream, platformParser) => __awaiter(void 0, void 0, void 0, function* () {
15638
16029
  var _a, e_1, _b, _c;
15639
16030
  const parsedStops = new Map();
15640
16031
  let i = 0;
15641
16032
  try {
15642
- for (var _d = true, _e = __asyncValues(parseCsv(stopsStream)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
16033
+ for (var _d = true, _e = __asyncValues(parseCsv(stopsStream, [
16034
+ 'stop_lat',
16035
+ 'stop_lon',
16036
+ 'location_type',
16037
+ ])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15643
16038
  _c = _f.value;
15644
16039
  _d = false;
15645
16040
  const rawLine = _c;
15646
16041
  const line = rawLine;
15647
- const stop = Object.assign({ id: i, sourceStopId: line.stop_id + '', name: line.stop_name, lat: line.stop_lat, lon: line.stop_lon, locationType: line.location_type
16042
+ const stop = Object.assign({ id: i, sourceStopId: line.stop_id, name: line.stop_name, lat: line.stop_lat, lon: line.stop_lon, locationType: line.location_type
15648
16043
  ? parseGtfsLocationType(line.location_type)
15649
16044
  : 'SIMPLE_STOP_OR_PLATFORM', children: [] }, (line.parent_station && { parentSourceId: line.parent_station }));
15650
16045
  if (platformParser) {
@@ -15658,7 +16053,7 @@ const parseStops = (stopsStream, platformParser) => __awaiter(undefined, undefin
15658
16053
  console.info(`Could not parse platform for stop ${line.stop_id}.`);
15659
16054
  }
15660
16055
  }
15661
- parsedStops.set(line.stop_id + '', stop);
16056
+ parsedStops.set(line.stop_id, stop);
15662
16057
  i = i + 1;
15663
16058
  }
15664
16059
  }
@@ -15735,11 +16130,14 @@ const parseGtfsLocationType = (gtfsLocationType) => {
15735
16130
  * @param stopsStream The readable stream containing the stops data.
15736
16131
  * @return A mapping of stop IDs to corresponding stop details.
15737
16132
  */
15738
- const parseTransfers = (transfersStream, stopsMap) => __awaiter(undefined, undefined, undefined, function* () {
16133
+ const parseTransfers = (transfersStream, stopsMap) => __awaiter(void 0, void 0, void 0, function* () {
15739
16134
  var _a, e_1, _b, _c;
15740
16135
  const transfers = new Map();
15741
16136
  try {
15742
- for (var _d = true, _e = __asyncValues(parseCsv(transfersStream)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
16137
+ for (var _d = true, _e = __asyncValues(parseCsv(transfersStream, [
16138
+ 'transfer_type',
16139
+ 'min_transfer_time',
16140
+ ])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15743
16141
  _c = _f.value;
15744
16142
  _d = false;
15745
16143
  const rawLine = _c;
@@ -15764,9 +16162,9 @@ const parseTransfers = (transfersStream, stopsMap) => __awaiter(undefined, undef
15764
16162
  console.info(`Missing minimum transfer time between ${transferEntry.from_stop_id} and ${transferEntry.to_stop_id}.`);
15765
16163
  }
15766
16164
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15767
- const fromStop = stopsMap.get(transferEntry.from_stop_id + '');
16165
+ const fromStop = stopsMap.get(transferEntry.from_stop_id);
15768
16166
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15769
- const toStop = stopsMap.get(transferEntry.to_stop_id + '');
16167
+ const toStop = stopsMap.get(transferEntry.to_stop_id);
15770
16168
  const transfer = Object.assign({ destination: toStop.id, type: parseGtfsTransferType(transferEntry.transfer_type) }, (transferEntry.min_transfer_time && {
15771
16169
  minTransferTime: Duration.fromSeconds(transferEntry.min_transfer_time),
15772
16170
  }));
@@ -15806,11 +16204,11 @@ const parseGtfsTransferType = (gtfsTransferType) => {
15806
16204
  * @param routeIds A mapping of route IDs to route details.
15807
16205
  * @returns A mapping of trip IDs to corresponding route IDs.
15808
16206
  */
15809
- const parseTrips = (tripsStream, serviceIds, routeIds) => __awaiter(undefined, undefined, undefined, function* () {
16207
+ const parseTrips = (tripsStream, serviceIds, routeIds) => __awaiter(void 0, void 0, void 0, function* () {
15810
16208
  var _a, e_1, _b, _c;
15811
16209
  const trips = new Map();
15812
16210
  try {
15813
- for (var _d = true, _e = __asyncValues(parseCsv(tripsStream)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
16211
+ for (var _d = true, _e = __asyncValues(parseCsv(tripsStream, ['stop_sequence'])), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15814
16212
  _c = _f.value;
15815
16213
  _d = false;
15816
16214
  const rawLine = _c;
@@ -15840,11 +16238,14 @@ const buildStopsAdjacencyStructure = (validStops, routes, transfersMap) => {
15840
16238
  const stopsAdjacency = new Map();
15841
16239
  for (const routeId of routes.keys()) {
15842
16240
  const route = routes.get(routeId);
15843
- for (const stop of route.stops) {
16241
+ if (!route) {
16242
+ throw new Error(`Route ${routeId} not found`);
16243
+ }
16244
+ for (const stop of route.stopsIterator()) {
15844
16245
  if (!stopsAdjacency.get(stop) && validStops.has(stop)) {
15845
16246
  stopsAdjacency.set(stop, { routes: [], transfers: [] });
15846
16247
  }
15847
- (_a = stopsAdjacency.get(stop)) === null || _a === undefined ? undefined : _a.routes.push(routeId);
16248
+ (_a = stopsAdjacency.get(stop)) === null || _a === void 0 ? void 0 : _a.routes.push(routeId);
15848
16249
  }
15849
16250
  }
15850
16251
  for (const [stop, transfers] of transfersMap) {
@@ -15868,7 +16269,7 @@ const buildStopsAdjacencyStructure = (validStops, routes, transfersMap) => {
15868
16269
  * @param validStopIds A set of valid stop IDs.
15869
16270
  * @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.
15870
16271
  */
15871
- const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) => __awaiter(undefined, undefined, undefined, function* () {
16272
+ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) => __awaiter(void 0, void 0, void 0, function* () {
15872
16273
  var _a, e_2, _b, _c;
15873
16274
  var _d, _e;
15874
16275
  /**
@@ -15906,7 +16307,6 @@ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) =
15906
16307
  route = {
15907
16308
  serviceRouteId: gtfsRouteId,
15908
16309
  stops: stopsArray,
15909
- stopIndices: new Map(stops.map((stop, i) => [stop, i])),
15910
16310
  stopTimes: stopTimesArray,
15911
16311
  pickUpDropOffTypes: pickUpDropOffTypesArray,
15912
16312
  };
@@ -15971,7 +16371,7 @@ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) =
15971
16371
  let dropOffTypes = [];
15972
16372
  let currentTripId = undefined;
15973
16373
  try {
15974
- for (var _f = true, _g = __asyncValues(parseCsv(stopTimesStream)), _h; _h = yield _g.next(), _a = _h.done, !_a; _f = true) {
16374
+ for (var _f = true, _g = __asyncValues(parseCsv(stopTimesStream, ['stop_sequence'])), _h; _h = yield _g.next(), _a = _h.done, !_a; _f = true) {
15975
16375
  _c = _h.value;
15976
16376
  _f = false;
15977
16377
  const rawLine = _c;
@@ -15992,7 +16392,7 @@ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) =
15992
16392
  }
15993
16393
  currentTripId = line.trip_id;
15994
16394
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15995
- stops.push(stopsMap.get(line.stop_id + '').id);
16395
+ stops.push(stopsMap.get(line.stop_id).id);
15996
16396
  const departure = (_d = line.departure_time) !== null && _d !== void 0 ? _d : line.arrival_time;
15997
16397
  const arrival = (_e = line.arrival_time) !== null && _e !== void 0 ? _e : line.departure_time;
15998
16398
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -16014,12 +16414,15 @@ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) =
16014
16414
  if (currentTripId) {
16015
16415
  addTrip(currentTripId);
16016
16416
  }
16017
- return routes;
16417
+ const routesAdjacency = new Map();
16418
+ for (const [routeId, routeData] of routes) {
16419
+ routesAdjacency.set(routeId, new Route(routeData.stopTimes, routeData.pickUpDropOffTypes, routeData.stops, routeData.serviceRouteId));
16420
+ }
16421
+ return routesAdjacency;
16018
16422
  });
16019
16423
  const parsePickupDropOffType = (gtfsType) => {
16020
16424
  switch (gtfsType) {
16021
16425
  default:
16022
- console.warn(`Unknown pickup/drop-off type ${gtfsType}`);
16023
16426
  return REGULAR;
16024
16427
  case 0:
16025
16428
  return REGULAR;
@@ -16054,7 +16457,7 @@ class GtfsParser {
16054
16457
  * @returns An object containing the timetable and stops map.
16055
16458
  */
16056
16459
  parse(date) {
16057
- return __awaiter(this, undefined, undefined, function* () {
16460
+ return __awaiter(this, void 0, void 0, function* () {
16058
16461
  const zip = new StreamZip.async({ file: this.path });
16059
16462
  const entries = yield zip.entries();
16060
16463
  const datetime = DateTime.fromJSDate(date);
@@ -16115,7 +16518,7 @@ class GtfsParser {
16115
16518
  * @returns An object containing the timetable and stops map.
16116
16519
  */
16117
16520
  parseStops() {
16118
- return __awaiter(this, undefined, undefined, function* () {
16521
+ return __awaiter(this, void 0, void 0, function* () {
16119
16522
  const zip = new StreamZip.async({ file: this.path });
16120
16523
  log.info(`Parsing ${STOPS_FILE}`);
16121
16524
  const stopsStream = yield zip.stream(STOPS_FILE);
@@ -16133,7 +16536,7 @@ class GtfsParser {
16133
16536
  * @returns The platform corresponding to this stop.
16134
16537
  */
16135
16538
  const platformParser = (stopEntry) => {
16136
- const stopId = String(stopEntry.stop_id);
16539
+ const stopId = stopEntry.stop_id;
16137
16540
  const stopParts = stopId.split(':');
16138
16541
  if (stopParts.length > 2) {
16139
16542
  return stopParts[2];