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