minotor 1.0.7 → 2.0.1

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 (60) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/README.md +3 -2
  3. package/dist/cli.mjs +604 -531
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/gtfs/stops.d.ts +19 -5
  6. package/dist/gtfs/transfers.d.ts +5 -4
  7. package/dist/gtfs/trips.d.ts +7 -5
  8. package/dist/gtfs/utils.d.ts +7 -8
  9. package/dist/parser.cjs.js +569 -501
  10. package/dist/parser.cjs.js.map +1 -1
  11. package/dist/parser.esm.js +569 -501
  12. package/dist/parser.esm.js.map +1 -1
  13. package/dist/router.cjs.js +1 -1
  14. package/dist/router.cjs.js.map +1 -1
  15. package/dist/router.d.ts +3 -3
  16. package/dist/router.esm.js +1 -1
  17. package/dist/router.esm.js.map +1 -1
  18. package/dist/router.umd.js +1 -1
  19. package/dist/router.umd.js.map +1 -1
  20. package/dist/routing/__tests__/route.test.d.ts +1 -0
  21. package/dist/routing/query.d.ts +7 -7
  22. package/dist/routing/result.d.ts +3 -3
  23. package/dist/routing/route.d.ts +1 -0
  24. package/dist/stops/proto/stops.d.ts +5 -4
  25. package/dist/stops/stops.d.ts +10 -1
  26. package/dist/stops/stopsIndex.d.ts +21 -4
  27. package/dist/timetable/proto/timetable.d.ts +21 -18
  28. package/dist/timetable/timetable.d.ts +38 -14
  29. package/package.json +4 -3
  30. package/src/cli/repl.ts +13 -10
  31. package/src/gtfs/__tests__/parser.test.ts +50 -579
  32. package/src/gtfs/__tests__/stops.test.ts +181 -112
  33. package/src/gtfs/__tests__/transfers.test.ts +170 -12
  34. package/src/gtfs/__tests__/trips.test.ts +212 -141
  35. package/src/gtfs/__tests__/utils.test.ts +4 -4
  36. package/src/gtfs/parser.ts +22 -13
  37. package/src/gtfs/stops.ts +63 -28
  38. package/src/gtfs/transfers.ts +14 -6
  39. package/src/gtfs/trips.ts +110 -47
  40. package/src/gtfs/utils.ts +11 -11
  41. package/src/router.ts +2 -3
  42. package/src/routing/__tests__/route.test.ts +112 -0
  43. package/src/routing/__tests__/router.test.ts +234 -244
  44. package/src/routing/query.ts +7 -7
  45. package/src/routing/result.ts +9 -6
  46. package/src/routing/route.ts +11 -0
  47. package/src/routing/router.ts +26 -24
  48. package/src/stops/__tests__/io.test.ts +9 -8
  49. package/src/stops/__tests__/stopFinder.test.ts +45 -36
  50. package/src/stops/io.ts +8 -5
  51. package/src/stops/proto/stops.proto +8 -7
  52. package/src/stops/proto/stops.ts +68 -38
  53. package/src/stops/stops.ts +13 -1
  54. package/src/stops/stopsIndex.ts +50 -7
  55. package/src/timetable/__tests__/io.test.ts +40 -49
  56. package/src/timetable/__tests__/timetable.test.ts +50 -58
  57. package/src/timetable/io.ts +69 -56
  58. package/src/timetable/proto/timetable.proto +22 -17
  59. package/src/timetable/proto/timetable.ts +94 -184
  60. package/src/timetable/timetable.ts +62 -29
package/dist/cli.mjs CHANGED
@@ -13430,7 +13430,6 @@ var StreamZip = /*@__PURE__*/getDefaultExportFromCjs(node_stream_zipExports);
13430
13430
  // of the input file used when generating it. This code is not
13431
13431
  // standalone and requires a support library to be linked with it. This
13432
13432
  // support library is itself covered by the above license.
13433
- /* eslint-disable prefer-const,@typescript-eslint/restrict-plus-operands */
13434
13433
  /**
13435
13434
  * Read a 64 bit varint as two JS numbers.
13436
13435
  *
@@ -13713,7 +13712,7 @@ function varint32read() {
13713
13712
  return result >>> 0;
13714
13713
  }
13715
13714
 
13716
- // Copyright 2021-2024 Buf Technologies, Inc.
13715
+ // Copyright 2021-2025 Buf Technologies, Inc.
13717
13716
  //
13718
13717
  // Licensed under the Apache License, Version 2.0 (the "License");
13719
13718
  // you may not use this file except in compliance with the License.
@@ -13742,7 +13741,10 @@ function makeInt64Support() {
13742
13741
  typeof process.env != "object" ||
13743
13742
  process.env.BUF_BIGINT_DISABLE !== "1");
13744
13743
  if (ok) {
13745
- const MIN = BigInt("-9223372036854775808"), MAX = BigInt("9223372036854775807"), UMIN = BigInt("0"), UMAX = BigInt("18446744073709551615");
13744
+ const MIN = BigInt("-9223372036854775808");
13745
+ const MAX = BigInt("9223372036854775807");
13746
+ const UMIN = BigInt("0");
13747
+ const UMAX = BigInt("18446744073709551615");
13746
13748
  return {
13747
13749
  zero: BigInt(0),
13748
13750
  supported: true,
@@ -13836,7 +13838,7 @@ function assertUInt64String(value) {
13836
13838
  }
13837
13839
  }
13838
13840
 
13839
- // Copyright 2021-2024 Buf Technologies, Inc.
13841
+ // Copyright 2021-2025 Buf Technologies, Inc.
13840
13842
  //
13841
13843
  // Licensed under the Apache License, Version 2.0 (the "License");
13842
13844
  // you may not use this file except in compliance with the License.
@@ -13866,7 +13868,7 @@ function getTextEncoding() {
13866
13868
  encodeURIComponent(text);
13867
13869
  return true;
13868
13870
  }
13869
- catch (e) {
13871
+ catch (_) {
13870
13872
  return false;
13871
13873
  }
13872
13874
  },
@@ -13875,7 +13877,7 @@ function getTextEncoding() {
13875
13877
  return globalThis[symbol];
13876
13878
  }
13877
13879
 
13878
- // Copyright 2021-2024 Buf Technologies, Inc.
13880
+ // Copyright 2021-2025 Buf Technologies, Inc.
13879
13881
  //
13880
13882
  // Licensed under the Apache License, Version 2.0 (the "License");
13881
13883
  // you may not use this file except in compliance with the License.
@@ -13888,7 +13890,6 @@ function getTextEncoding() {
13888
13890
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13889
13891
  // See the License for the specific language governing permissions and
13890
13892
  // limitations under the License.
13891
- /* eslint-disable prefer-const,no-case-declarations,@typescript-eslint/restrict-plus-operands */
13892
13893
  /**
13893
13894
  * Protobuf binary format wire types.
13894
13895
  *
@@ -14149,7 +14150,7 @@ class BinaryWriter {
14149
14150
  * Write a `sint64` value, a signed, zig-zag-encoded 64-bit varint.
14150
14151
  */
14151
14152
  sint64(value) {
14152
- let tc = protoInt64.enc(value),
14153
+ const tc = protoInt64.enc(value),
14153
14154
  // zigzag encode
14154
14155
  sign = tc.hi >> 31, lo = (tc.lo << 1) ^ sign, hi = ((tc.hi << 1) | (tc.lo >>> 31)) ^ sign;
14155
14156
  varint64write(lo, hi, this.buf);
@@ -14159,7 +14160,7 @@ class BinaryWriter {
14159
14160
  * Write a `uint64` value, an unsigned 64-bit varint.
14160
14161
  */
14161
14162
  uint64(value) {
14162
- let tc = protoInt64.uEnc(value);
14163
+ const tc = protoInt64.uEnc(value);
14163
14164
  varint64write(tc.lo, tc.hi, this.buf);
14164
14165
  return this;
14165
14166
  }
@@ -14200,11 +14201,9 @@ class BinaryReader {
14200
14201
  // ignore
14201
14202
  }
14202
14203
  break;
14203
- // eslint-disable-next-line
14204
14204
  // @ts-expect-error TS7029: Fallthrough case in switch
14205
14205
  case WireType.Bit64:
14206
14206
  this.pos += 4;
14207
- // eslint-disable-next-line no-fallthrough
14208
14207
  case WireType.Bit32:
14209
14208
  this.pos += 4;
14210
14209
  break;
@@ -14285,12 +14284,14 @@ class BinaryReader {
14285
14284
  * Read a `fixed32` field, an unsigned, fixed-length 32-bit integer.
14286
14285
  */
14287
14286
  fixed32() {
14287
+ // biome-ignore lint/suspicious/noAssignInExpressions: no
14288
14288
  return this.view.getUint32((this.pos += 4) - 4, true);
14289
14289
  }
14290
14290
  /**
14291
14291
  * Read a `sfixed32` field, a signed, fixed-length 32-bit integer.
14292
14292
  */
14293
14293
  sfixed32() {
14294
+ // biome-ignore lint/suspicious/noAssignInExpressions: no
14294
14295
  return this.view.getInt32((this.pos += 4) - 4, true);
14295
14296
  }
14296
14297
  /**
@@ -14309,12 +14310,14 @@ class BinaryReader {
14309
14310
  * Read a `float` field, 32-bit floating point number.
14310
14311
  */
14311
14312
  float() {
14313
+ // biome-ignore lint/suspicious/noAssignInExpressions: no
14312
14314
  return this.view.getFloat32((this.pos += 4) - 4, true);
14313
14315
  }
14314
14316
  /**
14315
14317
  * Read a `double` field, a 64-bit floating point number.
14316
14318
  */
14317
14319
  double() {
14320
+ // biome-ignore lint/suspicious/noAssignInExpressions: no
14318
14321
  return this.view.getFloat64((this.pos += 8) - 8, true);
14319
14322
  }
14320
14323
  /**
@@ -14370,7 +14373,7 @@ function assertFloat32(arg) {
14370
14373
  if (typeof arg == "string") {
14371
14374
  const o = arg;
14372
14375
  arg = Number(arg);
14373
- if (isNaN(arg) && o !== "NaN") {
14376
+ if (Number.isNaN(arg) && o !== "NaN") {
14374
14377
  throw new Error("invalid float32: " + o);
14375
14378
  }
14376
14379
  }
@@ -15045,6 +15048,7 @@ function locationTypeToJSON(object) {
15045
15048
  function createBaseStop() {
15046
15049
  return {
15047
15050
  name: "",
15051
+ sourceStopId: "",
15048
15052
  lat: undefined,
15049
15053
  lon: undefined,
15050
15054
  children: [],
@@ -15058,23 +15062,28 @@ const Stop = {
15058
15062
  if (message.name !== "") {
15059
15063
  writer.uint32(10).string(message.name);
15060
15064
  }
15065
+ if (message.sourceStopId !== "") {
15066
+ writer.uint32(18).string(message.sourceStopId);
15067
+ }
15061
15068
  if (message.lat !== undefined) {
15062
- writer.uint32(17).double(message.lat);
15069
+ writer.uint32(25).double(message.lat);
15063
15070
  }
15064
15071
  if (message.lon !== undefined) {
15065
- writer.uint32(25).double(message.lon);
15072
+ writer.uint32(33).double(message.lon);
15066
15073
  }
15074
+ writer.uint32(42).fork();
15067
15075
  for (const v of message.children) {
15068
- writer.uint32(34).string(v);
15076
+ writer.uint32(v);
15069
15077
  }
15078
+ writer.join();
15070
15079
  if (message.parent !== undefined) {
15071
- writer.uint32(42).string(message.parent);
15080
+ writer.uint32(48).uint32(message.parent);
15072
15081
  }
15073
15082
  if (message.locationType !== 0) {
15074
- writer.uint32(48).int32(message.locationType);
15083
+ writer.uint32(56).int32(message.locationType);
15075
15084
  }
15076
15085
  if (message.platform !== undefined) {
15077
- writer.uint32(58).string(message.platform);
15086
+ writer.uint32(66).string(message.platform);
15078
15087
  }
15079
15088
  return writer;
15080
15089
  },
@@ -15093,42 +15102,56 @@ const Stop = {
15093
15102
  continue;
15094
15103
  }
15095
15104
  case 2: {
15096
- if (tag !== 17) {
15105
+ if (tag !== 18) {
15097
15106
  break;
15098
15107
  }
15099
- message.lat = reader.double();
15108
+ message.sourceStopId = reader.string();
15100
15109
  continue;
15101
15110
  }
15102
15111
  case 3: {
15103
15112
  if (tag !== 25) {
15104
15113
  break;
15105
15114
  }
15106
- message.lon = reader.double();
15115
+ message.lat = reader.double();
15107
15116
  continue;
15108
15117
  }
15109
15118
  case 4: {
15110
- if (tag !== 34) {
15119
+ if (tag !== 33) {
15111
15120
  break;
15112
15121
  }
15113
- message.children.push(reader.string());
15122
+ message.lon = reader.double();
15114
15123
  continue;
15115
15124
  }
15116
15125
  case 5: {
15117
- if (tag !== 42) {
15118
- break;
15126
+ if (tag === 40) {
15127
+ message.children.push(reader.uint32());
15128
+ continue;
15119
15129
  }
15120
- message.parent = reader.string();
15121
- continue;
15130
+ if (tag === 42) {
15131
+ const end2 = reader.uint32() + reader.pos;
15132
+ while (reader.pos < end2) {
15133
+ message.children.push(reader.uint32());
15134
+ }
15135
+ continue;
15136
+ }
15137
+ break;
15122
15138
  }
15123
15139
  case 6: {
15124
15140
  if (tag !== 48) {
15125
15141
  break;
15126
15142
  }
15127
- message.locationType = reader.int32();
15143
+ message.parent = reader.uint32();
15128
15144
  continue;
15129
15145
  }
15130
15146
  case 7: {
15131
- if (tag !== 58) {
15147
+ if (tag !== 56) {
15148
+ break;
15149
+ }
15150
+ message.locationType = reader.int32();
15151
+ continue;
15152
+ }
15153
+ case 8: {
15154
+ if (tag !== 66) {
15132
15155
  break;
15133
15156
  }
15134
15157
  message.platform = reader.string();
@@ -15145,10 +15168,11 @@ const Stop = {
15145
15168
  fromJSON(object) {
15146
15169
  return {
15147
15170
  name: isSet$1(object.name) ? globalThis.String(object.name) : "",
15171
+ sourceStopId: isSet$1(object.sourceStopId) ? globalThis.String(object.sourceStopId) : "",
15148
15172
  lat: isSet$1(object.lat) ? globalThis.Number(object.lat) : undefined,
15149
15173
  lon: isSet$1(object.lon) ? globalThis.Number(object.lon) : undefined,
15150
- children: globalThis.Array.isArray(object === null || object === undefined ? undefined : object.children) ? object.children.map((e) => globalThis.String(e)) : [],
15151
- parent: isSet$1(object.parent) ? globalThis.String(object.parent) : undefined,
15174
+ children: globalThis.Array.isArray(object === null || object === undefined ? undefined : object.children) ? object.children.map((e) => globalThis.Number(e)) : [],
15175
+ parent: isSet$1(object.parent) ? globalThis.Number(object.parent) : undefined,
15152
15176
  locationType: isSet$1(object.locationType) ? locationTypeFromJSON(object.locationType) : 0,
15153
15177
  platform: isSet$1(object.platform) ? globalThis.String(object.platform) : undefined,
15154
15178
  };
@@ -15159,6 +15183,9 @@ const Stop = {
15159
15183
  if (message.name !== "") {
15160
15184
  obj.name = message.name;
15161
15185
  }
15186
+ if (message.sourceStopId !== "") {
15187
+ obj.sourceStopId = message.sourceStopId;
15188
+ }
15162
15189
  if (message.lat !== undefined) {
15163
15190
  obj.lat = message.lat;
15164
15191
  }
@@ -15166,10 +15193,10 @@ const Stop = {
15166
15193
  obj.lon = message.lon;
15167
15194
  }
15168
15195
  if ((_a = message.children) === null || _a === undefined ? undefined : _a.length) {
15169
- obj.children = message.children;
15196
+ obj.children = message.children.map((e) => Math.round(e));
15170
15197
  }
15171
15198
  if (message.parent !== undefined) {
15172
- obj.parent = message.parent;
15199
+ obj.parent = Math.round(message.parent);
15173
15200
  }
15174
15201
  if (message.locationType !== 0) {
15175
15202
  obj.locationType = locationTypeToJSON(message.locationType);
@@ -15183,15 +15210,16 @@ const Stop = {
15183
15210
  return Stop.fromPartial(base !== null && base !== undefined ? base : {});
15184
15211
  },
15185
15212
  fromPartial(object) {
15186
- var _a, _b, _c, _d, _e, _f, _g;
15213
+ var _a, _b, _c, _d, _e, _f, _g, _h;
15187
15214
  const message = createBaseStop();
15188
15215
  message.name = (_a = object.name) !== null && _a !== undefined ? _a : "";
15189
- message.lat = (_b = object.lat) !== null && _b !== undefined ? _b : undefined;
15190
- message.lon = (_c = object.lon) !== null && _c !== undefined ? _c : undefined;
15191
- message.children = ((_d = object.children) === null || _d === undefined ? undefined : _d.map((e) => e)) || [];
15192
- message.parent = (_e = object.parent) !== null && _e !== undefined ? _e : undefined;
15193
- message.locationType = (_f = object.locationType) !== null && _f !== undefined ? _f : 0;
15194
- message.platform = (_g = object.platform) !== null && _g !== undefined ? _g : undefined;
15216
+ message.sourceStopId = (_b = object.sourceStopId) !== null && _b !== undefined ? _b : "";
15217
+ message.lat = (_c = object.lat) !== null && _c !== undefined ? _c : undefined;
15218
+ message.lon = (_d = object.lon) !== null && _d !== undefined ? _d : undefined;
15219
+ message.children = ((_e = object.children) === null || _e === undefined ? undefined : _e.map((e) => e)) || [];
15220
+ message.parent = (_f = object.parent) !== null && _f !== undefined ? _f : undefined;
15221
+ message.locationType = (_g = object.locationType) !== null && _g !== undefined ? _g : 0;
15222
+ message.platform = (_h = object.platform) !== null && _h !== undefined ? _h : undefined;
15195
15223
  return message;
15196
15224
  },
15197
15225
  };
@@ -15245,7 +15273,7 @@ const StopsMap = {
15245
15273
  version: isSet$1(object.version) ? globalThis.String(object.version) : "",
15246
15274
  stops: isObject$1(object.stops)
15247
15275
  ? Object.entries(object.stops).reduce((acc, [key, value]) => {
15248
- acc[key] = Stop.fromJSON(value);
15276
+ acc[globalThis.Number(key)] = Stop.fromJSON(value);
15249
15277
  return acc;
15250
15278
  }, {})
15251
15279
  : {},
@@ -15276,7 +15304,7 @@ const StopsMap = {
15276
15304
  message.version = (_a = object.version) !== null && _a !== undefined ? _a : "";
15277
15305
  message.stops = Object.entries((_b = object.stops) !== null && _b !== undefined ? _b : {}).reduce((acc, [key, value]) => {
15278
15306
  if (value !== undefined) {
15279
- acc[key] = Stop.fromPartial(value);
15307
+ acc[globalThis.Number(key)] = Stop.fromPartial(value);
15280
15308
  }
15281
15309
  return acc;
15282
15310
  }, {});
@@ -15284,12 +15312,12 @@ const StopsMap = {
15284
15312
  },
15285
15313
  };
15286
15314
  function createBaseStopsMap_StopsEntry() {
15287
- return { key: "", value: undefined };
15315
+ return { key: 0, value: undefined };
15288
15316
  }
15289
15317
  const StopsMap_StopsEntry = {
15290
15318
  encode(message, writer = new BinaryWriter()) {
15291
- if (message.key !== "") {
15292
- writer.uint32(10).string(message.key);
15319
+ if (message.key !== 0) {
15320
+ writer.uint32(8).uint32(message.key);
15293
15321
  }
15294
15322
  if (message.value !== undefined) {
15295
15323
  Stop.encode(message.value, writer.uint32(18).fork()).join();
@@ -15304,10 +15332,10 @@ const StopsMap_StopsEntry = {
15304
15332
  const tag = reader.uint32();
15305
15333
  switch (tag >>> 3) {
15306
15334
  case 1: {
15307
- if (tag !== 10) {
15335
+ if (tag !== 8) {
15308
15336
  break;
15309
15337
  }
15310
- message.key = reader.string();
15338
+ message.key = reader.uint32();
15311
15339
  continue;
15312
15340
  }
15313
15341
  case 2: {
@@ -15327,14 +15355,14 @@ const StopsMap_StopsEntry = {
15327
15355
  },
15328
15356
  fromJSON(object) {
15329
15357
  return {
15330
- key: isSet$1(object.key) ? globalThis.String(object.key) : "",
15358
+ key: isSet$1(object.key) ? globalThis.Number(object.key) : 0,
15331
15359
  value: isSet$1(object.value) ? Stop.fromJSON(object.value) : undefined,
15332
15360
  };
15333
15361
  },
15334
15362
  toJSON(message) {
15335
15363
  const obj = {};
15336
- if (message.key !== "") {
15337
- obj.key = message.key;
15364
+ if (message.key !== 0) {
15365
+ obj.key = Math.round(message.key);
15338
15366
  }
15339
15367
  if (message.value !== undefined) {
15340
15368
  obj.value = Stop.toJSON(message.value);
@@ -15347,7 +15375,7 @@ const StopsMap_StopsEntry = {
15347
15375
  fromPartial(object) {
15348
15376
  var _a;
15349
15377
  const message = createBaseStopsMap_StopsEntry();
15350
- message.key = (_a = object.key) !== null && _a !== undefined ? _a : "";
15378
+ message.key = (_a = object.key) !== null && _a !== undefined ? _a : 0;
15351
15379
  message.value = (object.value !== undefined && object.value !== null) ? Stop.fromPartial(object.value) : undefined;
15352
15380
  return message;
15353
15381
  },
@@ -15359,10 +15387,11 @@ function isSet$1(value) {
15359
15387
  return value !== null && value !== undefined;
15360
15388
  }
15361
15389
 
15362
- const CURRENT_VERSION$1 = '0.0.1';
15390
+ const CURRENT_VERSION$1 = '0.0.2';
15363
15391
  const serializeStop = (stop) => {
15364
15392
  return {
15365
15393
  name: stop.name,
15394
+ sourceStopId: stop.sourceStopId,
15366
15395
  lat: stop.lat,
15367
15396
  lon: stop.lon,
15368
15397
  children: stop.children,
@@ -15384,6 +15413,7 @@ const serializeStopsMap = (stopsMap) => {
15384
15413
  const deserializeStop = (stopId, protoStop) => {
15385
15414
  return {
15386
15415
  id: stopId,
15416
+ sourceStopId: protoStop.sourceStopId,
15387
15417
  name: protoStop.name,
15388
15418
  lat: protoStop.lat,
15389
15419
  lon: protoStop.lon,
@@ -15399,7 +15429,8 @@ const deserializeStopsMap = (protoStopsMap) => {
15399
15429
  }
15400
15430
  const stopsMap = new Map();
15401
15431
  Object.entries(protoStopsMap.stops).forEach(([key, value]) => {
15402
- stopsMap.set(key, deserializeStop(key, value));
15432
+ const intKey = parseInt(key, 10);
15433
+ stopsMap.set(intKey, deserializeStop(intKey, value));
15403
15434
  });
15404
15435
  return stopsMap;
15405
15436
  };
@@ -15443,6 +15474,10 @@ class StopsIndex {
15443
15474
  constructor(stopsMap) {
15444
15475
  var _a;
15445
15476
  this.stopsMap = stopsMap;
15477
+ this.sourceStopsMap = new Map();
15478
+ for (const [id, stop] of stopsMap.entries()) {
15479
+ this.sourceStopsMap.set(stop.sourceStopId, id);
15480
+ }
15446
15481
  this.textIndex = lt({
15447
15482
  fields: ['name'],
15448
15483
  storeFields: ['id'],
@@ -15501,6 +15536,14 @@ class StopsIndex {
15501
15536
  StopsMap.encode(protoStopsMap, writer);
15502
15537
  return writer.finish();
15503
15538
  }
15539
+ /**
15540
+ * Returns the number of stops in the index.
15541
+ *
15542
+ * @returns The total number of stops.
15543
+ */
15544
+ size() {
15545
+ return this.stopsMap.size;
15546
+ }
15504
15547
  /**
15505
15548
  * Finds stops by their name using a text search.
15506
15549
  *
@@ -15529,16 +15572,36 @@ class StopsIndex {
15529
15572
  return nearestStops;
15530
15573
  }
15531
15574
  /**
15532
- * Finds a stop by its ID.
15575
+ * Finds a stop by its internal ID.
15533
15576
  *
15534
- * @param id - The ID of the stop to search for.
15577
+ * @param id - The internal ID of the stop to search for.
15535
15578
  * @returns The Stop object that matches the specified ID, or undefined if not found.
15536
15579
  */
15537
15580
  findStopById(id) {
15538
15581
  return this.stopsMap.get(id);
15539
15582
  }
15540
- equivalentStops(id) {
15583
+ /**
15584
+ * Finds a stop by its ID in the transit data source (e.g. GTFS).
15585
+ *
15586
+ * @param id - The source ID of the stop to search for.
15587
+ * @returns The Stop object that matches the specified ID, or undefined if not found.
15588
+ */
15589
+ findStopBySourceStopId(sourceStopId) {
15590
+ const stopId = this.sourceStopsMap.get(sourceStopId);
15591
+ if (stopId === undefined) {
15592
+ return;
15593
+ }
15594
+ return this.findStopById(stopId);
15595
+ }
15596
+ /**
15597
+ * Find ids of all sibling stops.
15598
+ */
15599
+ equivalentStops(sourceId) {
15541
15600
  var _a, _b;
15601
+ const id = this.sourceStopsMap.get(sourceId);
15602
+ if (id === undefined) {
15603
+ return [];
15604
+ }
15542
15605
  const stop = this.stopsMap.get(id);
15543
15606
  if (!stop) {
15544
15607
  return [];
@@ -15546,7 +15609,7 @@ class StopsIndex {
15546
15609
  const equivalentStops = stop.parent
15547
15610
  ? ((_b = (_a = this.stopsMap.get(stop.parent)) === null || _a === undefined ? undefined : _a.children) !== null && _b !== undefined ? _b : [])
15548
15611
  : stop.children;
15549
- return Array.from(new Set([id, ...equivalentStops]));
15612
+ return Array.from(new Set([id, ...equivalentStops])).map((stopId) => this.stopsMap.get(stopId));
15550
15613
  }
15551
15614
  }
15552
15615
 
@@ -15637,43 +15700,6 @@ class Duration {
15637
15700
  // protoc v4.23.4
15638
15701
  // source: src/timetable/proto/timetable.proto
15639
15702
  /* eslint-disable */
15640
- var PickUpDropOffType;
15641
- (function (PickUpDropOffType) {
15642
- PickUpDropOffType[PickUpDropOffType["NOT_AVAILABLE"] = 0] = "NOT_AVAILABLE";
15643
- PickUpDropOffType[PickUpDropOffType["MUST_PHONE_AGENCY"] = 1] = "MUST_PHONE_AGENCY";
15644
- PickUpDropOffType[PickUpDropOffType["MUST_COORDINATE_WITH_DRIVER"] = 2] = "MUST_COORDINATE_WITH_DRIVER";
15645
- PickUpDropOffType[PickUpDropOffType["UNRECOGNIZED"] = -1] = "UNRECOGNIZED";
15646
- })(PickUpDropOffType || (PickUpDropOffType = {}));
15647
- function pickUpDropOffTypeFromJSON(object) {
15648
- switch (object) {
15649
- case 0:
15650
- case "NOT_AVAILABLE":
15651
- return PickUpDropOffType.NOT_AVAILABLE;
15652
- case 1:
15653
- case "MUST_PHONE_AGENCY":
15654
- return PickUpDropOffType.MUST_PHONE_AGENCY;
15655
- case 2:
15656
- case "MUST_COORDINATE_WITH_DRIVER":
15657
- return PickUpDropOffType.MUST_COORDINATE_WITH_DRIVER;
15658
- case -1:
15659
- case "UNRECOGNIZED":
15660
- default:
15661
- return PickUpDropOffType.UNRECOGNIZED;
15662
- }
15663
- }
15664
- function pickUpDropOffTypeToJSON(object) {
15665
- switch (object) {
15666
- case PickUpDropOffType.NOT_AVAILABLE:
15667
- return "NOT_AVAILABLE";
15668
- case PickUpDropOffType.MUST_PHONE_AGENCY:
15669
- return "MUST_PHONE_AGENCY";
15670
- case PickUpDropOffType.MUST_COORDINATE_WITH_DRIVER:
15671
- return "MUST_COORDINATE_WITH_DRIVER";
15672
- case PickUpDropOffType.UNRECOGNIZED:
15673
- default:
15674
- return "UNRECOGNIZED";
15675
- }
15676
- }
15677
15703
  var TransferType;
15678
15704
  (function (TransferType) {
15679
15705
  TransferType[TransferType["RECOMMENDED_TRANSFER_POINT"] = 0] = "RECOMMENDED_TRANSFER_POINT";
@@ -15796,118 +15822,27 @@ function routeTypeToJSON(object) {
15796
15822
  return "UNRECOGNIZED";
15797
15823
  }
15798
15824
  }
15799
- function createBaseStopTimes() {
15800
- return { arrival: 0, departure: 0, pickUpType: undefined, dropOffType: undefined };
15801
- }
15802
- const StopTimes = {
15803
- encode(message, writer = new BinaryWriter()) {
15804
- if (message.arrival !== 0) {
15805
- writer.uint32(8).int32(message.arrival);
15806
- }
15807
- if (message.departure !== 0) {
15808
- writer.uint32(16).int32(message.departure);
15809
- }
15810
- if (message.pickUpType !== undefined) {
15811
- writer.uint32(24).int32(message.pickUpType);
15812
- }
15813
- if (message.dropOffType !== undefined) {
15814
- writer.uint32(32).int32(message.dropOffType);
15815
- }
15816
- return writer;
15817
- },
15818
- decode(input, length) {
15819
- const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
15820
- let end = length === undefined ? reader.len : reader.pos + length;
15821
- const message = createBaseStopTimes();
15822
- while (reader.pos < end) {
15823
- const tag = reader.uint32();
15824
- switch (tag >>> 3) {
15825
- case 1: {
15826
- if (tag !== 8) {
15827
- break;
15828
- }
15829
- message.arrival = reader.int32();
15830
- continue;
15831
- }
15832
- case 2: {
15833
- if (tag !== 16) {
15834
- break;
15835
- }
15836
- message.departure = reader.int32();
15837
- continue;
15838
- }
15839
- case 3: {
15840
- if (tag !== 24) {
15841
- break;
15842
- }
15843
- message.pickUpType = reader.int32();
15844
- continue;
15845
- }
15846
- case 4: {
15847
- if (tag !== 32) {
15848
- break;
15849
- }
15850
- message.dropOffType = reader.int32();
15851
- continue;
15852
- }
15853
- }
15854
- if ((tag & 7) === 4 || tag === 0) {
15855
- break;
15856
- }
15857
- reader.skip(tag & 7);
15858
- }
15859
- return message;
15860
- },
15861
- fromJSON(object) {
15862
- return {
15863
- arrival: isSet(object.arrival) ? globalThis.Number(object.arrival) : 0,
15864
- departure: isSet(object.departure) ? globalThis.Number(object.departure) : 0,
15865
- pickUpType: isSet(object.pickUpType) ? pickUpDropOffTypeFromJSON(object.pickUpType) : undefined,
15866
- dropOffType: isSet(object.dropOffType) ? pickUpDropOffTypeFromJSON(object.dropOffType) : undefined,
15867
- };
15868
- },
15869
- toJSON(message) {
15870
- const obj = {};
15871
- if (message.arrival !== 0) {
15872
- obj.arrival = Math.round(message.arrival);
15873
- }
15874
- if (message.departure !== 0) {
15875
- obj.departure = Math.round(message.departure);
15876
- }
15877
- if (message.pickUpType !== undefined) {
15878
- obj.pickUpType = pickUpDropOffTypeToJSON(message.pickUpType);
15879
- }
15880
- if (message.dropOffType !== undefined) {
15881
- obj.dropOffType = pickUpDropOffTypeToJSON(message.dropOffType);
15882
- }
15883
- return obj;
15884
- },
15885
- create(base) {
15886
- return StopTimes.fromPartial(base !== null && base !== undefined ? base : {});
15887
- },
15888
- fromPartial(object) {
15889
- var _a, _b, _c, _d;
15890
- const message = createBaseStopTimes();
15891
- message.arrival = (_a = object.arrival) !== null && _a !== undefined ? _a : 0;
15892
- message.departure = (_b = object.departure) !== null && _b !== undefined ? _b : 0;
15893
- message.pickUpType = (_c = object.pickUpType) !== null && _c !== undefined ? _c : undefined;
15894
- message.dropOffType = (_d = object.dropOffType) !== null && _d !== undefined ? _d : undefined;
15895
- return message;
15896
- },
15897
- };
15898
15825
  function createBaseRoute() {
15899
- return { stopTimes: [], stops: [], serviceRouteId: "" };
15826
+ return {
15827
+ stopTimes: new Uint8Array(0),
15828
+ pickUpDropOffTypes: new Uint8Array(0),
15829
+ stops: new Uint8Array(0),
15830
+ serviceRouteId: "",
15831
+ };
15900
15832
  }
15901
15833
  const Route$1 = {
15902
15834
  encode(message, writer = new BinaryWriter()) {
15903
- for (const v of message.stopTimes) {
15904
- StopTimes.encode(v, writer.uint32(10).fork()).join();
15835
+ if (message.stopTimes.length !== 0) {
15836
+ writer.uint32(10).bytes(message.stopTimes);
15905
15837
  }
15906
- for (const v of message.stops) {
15907
- writer.uint32(18).string(v);
15838
+ if (message.pickUpDropOffTypes.length !== 0) {
15839
+ writer.uint32(18).bytes(message.pickUpDropOffTypes);
15840
+ }
15841
+ if (message.stops.length !== 0) {
15842
+ writer.uint32(26).bytes(message.stops);
15908
15843
  }
15909
15844
  if (message.serviceRouteId !== "") {
15910
- writer.uint32(26).string(message.serviceRouteId);
15845
+ writer.uint32(34).string(message.serviceRouteId);
15911
15846
  }
15912
15847
  return writer;
15913
15848
  },
@@ -15922,20 +15857,27 @@ const Route$1 = {
15922
15857
  if (tag !== 10) {
15923
15858
  break;
15924
15859
  }
15925
- message.stopTimes.push(StopTimes.decode(reader, reader.uint32()));
15860
+ message.stopTimes = reader.bytes();
15926
15861
  continue;
15927
15862
  }
15928
15863
  case 2: {
15929
15864
  if (tag !== 18) {
15930
15865
  break;
15931
15866
  }
15932
- message.stops.push(reader.string());
15867
+ message.pickUpDropOffTypes = reader.bytes();
15933
15868
  continue;
15934
15869
  }
15935
15870
  case 3: {
15936
15871
  if (tag !== 26) {
15937
15872
  break;
15938
15873
  }
15874
+ message.stops = reader.bytes();
15875
+ continue;
15876
+ }
15877
+ case 4: {
15878
+ if (tag !== 34) {
15879
+ break;
15880
+ }
15939
15881
  message.serviceRouteId = reader.string();
15940
15882
  continue;
15941
15883
  }
@@ -15949,21 +15891,24 @@ const Route$1 = {
15949
15891
  },
15950
15892
  fromJSON(object) {
15951
15893
  return {
15952
- stopTimes: globalThis.Array.isArray(object === null || object === undefined ? undefined : object.stopTimes)
15953
- ? object.stopTimes.map((e) => StopTimes.fromJSON(e))
15954
- : [],
15955
- stops: globalThis.Array.isArray(object === null || object === undefined ? undefined : object.stops) ? object.stops.map((e) => globalThis.String(e)) : [],
15894
+ stopTimes: isSet(object.stopTimes) ? bytesFromBase64(object.stopTimes) : new Uint8Array(0),
15895
+ pickUpDropOffTypes: isSet(object.pickUpDropOffTypes)
15896
+ ? bytesFromBase64(object.pickUpDropOffTypes)
15897
+ : new Uint8Array(0),
15898
+ stops: isSet(object.stops) ? bytesFromBase64(object.stops) : new Uint8Array(0),
15956
15899
  serviceRouteId: isSet(object.serviceRouteId) ? globalThis.String(object.serviceRouteId) : "",
15957
15900
  };
15958
15901
  },
15959
15902
  toJSON(message) {
15960
- var _a, _b;
15961
15903
  const obj = {};
15962
- if ((_a = message.stopTimes) === null || _a === undefined ? undefined : _a.length) {
15963
- obj.stopTimes = message.stopTimes.map((e) => StopTimes.toJSON(e));
15904
+ if (message.stopTimes.length !== 0) {
15905
+ obj.stopTimes = base64FromBytes(message.stopTimes);
15906
+ }
15907
+ if (message.pickUpDropOffTypes.length !== 0) {
15908
+ obj.pickUpDropOffTypes = base64FromBytes(message.pickUpDropOffTypes);
15964
15909
  }
15965
- if ((_b = message.stops) === null || _b === undefined ? undefined : _b.length) {
15966
- obj.stops = message.stops;
15910
+ if (message.stops.length !== 0) {
15911
+ obj.stops = base64FromBytes(message.stops);
15967
15912
  }
15968
15913
  if (message.serviceRouteId !== "") {
15969
15914
  obj.serviceRouteId = message.serviceRouteId;
@@ -15974,11 +15919,12 @@ const Route$1 = {
15974
15919
  return Route$1.fromPartial(base !== null && base !== undefined ? base : {});
15975
15920
  },
15976
15921
  fromPartial(object) {
15977
- var _a, _b, _c;
15922
+ var _a, _b, _c, _d;
15978
15923
  const message = createBaseRoute();
15979
- message.stopTimes = ((_a = object.stopTimes) === null || _a === undefined ? undefined : _a.map((e) => StopTimes.fromPartial(e))) || [];
15980
- message.stops = ((_b = object.stops) === null || _b === undefined ? undefined : _b.map((e) => e)) || [];
15981
- message.serviceRouteId = (_c = object.serviceRouteId) !== null && _c !== undefined ? _c : "";
15924
+ message.stopTimes = (_a = object.stopTimes) !== null && _a !== undefined ? _a : new Uint8Array(0);
15925
+ message.pickUpDropOffTypes = (_b = object.pickUpDropOffTypes) !== null && _b !== undefined ? _b : new Uint8Array(0);
15926
+ message.stops = (_c = object.stops) !== null && _c !== undefined ? _c : new Uint8Array(0);
15927
+ message.serviceRouteId = (_d = object.serviceRouteId) !== null && _d !== undefined ? _d : "";
15982
15928
  return message;
15983
15929
  },
15984
15930
  };
@@ -16125,12 +16071,12 @@ const RoutesAdjacency_RoutesEntry = {
16125
16071
  },
16126
16072
  };
16127
16073
  function createBaseTransfer() {
16128
- return { destination: "", type: 0, minTransferTime: undefined };
16074
+ return { destination: 0, type: 0, minTransferTime: undefined };
16129
16075
  }
16130
16076
  const Transfer = {
16131
16077
  encode(message, writer = new BinaryWriter()) {
16132
- if (message.destination !== "") {
16133
- writer.uint32(10).string(message.destination);
16078
+ if (message.destination !== 0) {
16079
+ writer.uint32(8).uint32(message.destination);
16134
16080
  }
16135
16081
  if (message.type !== 0) {
16136
16082
  writer.uint32(16).int32(message.type);
@@ -16148,10 +16094,10 @@ const Transfer = {
16148
16094
  const tag = reader.uint32();
16149
16095
  switch (tag >>> 3) {
16150
16096
  case 1: {
16151
- if (tag !== 10) {
16097
+ if (tag !== 8) {
16152
16098
  break;
16153
16099
  }
16154
- message.destination = reader.string();
16100
+ message.destination = reader.uint32();
16155
16101
  continue;
16156
16102
  }
16157
16103
  case 2: {
@@ -16178,15 +16124,15 @@ const Transfer = {
16178
16124
  },
16179
16125
  fromJSON(object) {
16180
16126
  return {
16181
- destination: isSet(object.destination) ? globalThis.String(object.destination) : "",
16127
+ destination: isSet(object.destination) ? globalThis.Number(object.destination) : 0,
16182
16128
  type: isSet(object.type) ? transferTypeFromJSON(object.type) : 0,
16183
16129
  minTransferTime: isSet(object.minTransferTime) ? globalThis.Number(object.minTransferTime) : undefined,
16184
16130
  };
16185
16131
  },
16186
16132
  toJSON(message) {
16187
16133
  const obj = {};
16188
- if (message.destination !== "") {
16189
- obj.destination = message.destination;
16134
+ if (message.destination !== 0) {
16135
+ obj.destination = Math.round(message.destination);
16190
16136
  }
16191
16137
  if (message.type !== 0) {
16192
16138
  obj.type = transferTypeToJSON(message.type);
@@ -16202,7 +16148,7 @@ const Transfer = {
16202
16148
  fromPartial(object) {
16203
16149
  var _a, _b, _c;
16204
16150
  const message = createBaseTransfer();
16205
- message.destination = (_a = object.destination) !== null && _a !== undefined ? _a : "";
16151
+ message.destination = (_a = object.destination) !== null && _a !== undefined ? _a : 0;
16206
16152
  message.type = (_b = object.type) !== null && _b !== undefined ? _b : 0;
16207
16153
  message.minTransferTime = (_c = object.minTransferTime) !== null && _c !== undefined ? _c : undefined;
16208
16154
  return message;
@@ -16742,6 +16688,31 @@ const Timetable$1 = {
16742
16688
  return message;
16743
16689
  },
16744
16690
  };
16691
+ function bytesFromBase64(b64) {
16692
+ if (globalThis.Buffer) {
16693
+ return Uint8Array.from(globalThis.Buffer.from(b64, "base64"));
16694
+ }
16695
+ else {
16696
+ const bin = globalThis.atob(b64);
16697
+ const arr = new Uint8Array(bin.length);
16698
+ for (let i = 0; i < bin.length; ++i) {
16699
+ arr[i] = bin.charCodeAt(i);
16700
+ }
16701
+ return arr;
16702
+ }
16703
+ }
16704
+ function base64FromBytes(arr) {
16705
+ if (globalThis.Buffer) {
16706
+ return globalThis.Buffer.from(arr).toString("base64");
16707
+ }
16708
+ else {
16709
+ const bin = [];
16710
+ arr.forEach((byte) => {
16711
+ bin.push(globalThis.String.fromCharCode(byte));
16712
+ });
16713
+ return globalThis.btoa(bin.join(""));
16714
+ }
16715
+ }
16745
16716
  function isObject(value) {
16746
16717
  return typeof value === "object" && value !== null;
16747
16718
  }
@@ -16749,6 +16720,202 @@ function isSet(value) {
16749
16720
  return value !== null && value !== undefined;
16750
16721
  }
16751
16722
 
16723
+ const isLittleEndian = (() => {
16724
+ const buffer = new ArrayBuffer(4);
16725
+ const view = new DataView(buffer);
16726
+ view.setUint32(0, 0x12345678);
16727
+ return new Uint8Array(buffer)[0] === 0x78;
16728
+ })();
16729
+ const STANDARD_ENDIANNESS = true; // true = little-endian
16730
+ function uint32ArrayToBytes(array) {
16731
+ if (isLittleEndian === STANDARD_ENDIANNESS) {
16732
+ return new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
16733
+ }
16734
+ // If endianness doesn't match, we need to swap byte order
16735
+ const result = new Uint8Array(array.length * 4);
16736
+ const view = new DataView(result.buffer);
16737
+ for (let i = 0; i < array.length; i++) {
16738
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16739
+ view.setUint32(i * 4, array[i], STANDARD_ENDIANNESS);
16740
+ }
16741
+ return result;
16742
+ }
16743
+ function bytesToUint32Array(bytes) {
16744
+ if (bytes.byteLength % 4 !== 0) {
16745
+ throw new Error('Byte array length must be a multiple of 4 to convert to Uint32Array');
16746
+ }
16747
+ // If system endianness matches our standard, we can create a view directly
16748
+ if (isLittleEndian === STANDARD_ENDIANNESS) {
16749
+ return new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4);
16750
+ }
16751
+ // If endianness doesn't match, we need to swap byte order
16752
+ const result = new Uint32Array(bytes.byteLength / 4);
16753
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
16754
+ for (let i = 0; i < result.length; i++) {
16755
+ result[i] = view.getUint32(i * 4, STANDARD_ENDIANNESS);
16756
+ }
16757
+ return result;
16758
+ }
16759
+ const serializeStopsAdjacency = (stopsAdjacency) => {
16760
+ const protoStopsAdjacency = {
16761
+ stops: {},
16762
+ };
16763
+ stopsAdjacency.forEach((value, key) => {
16764
+ protoStopsAdjacency.stops[key] = {
16765
+ transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: serializeTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
16766
+ minTransferTime: transfer.minTransferTime.toSeconds(),
16767
+ })))),
16768
+ routes: value.routes,
16769
+ };
16770
+ });
16771
+ return protoStopsAdjacency;
16772
+ };
16773
+ const serializeRoutesAdjacency = (routesAdjacency) => {
16774
+ const protoRoutesAdjacency = {
16775
+ routes: {},
16776
+ };
16777
+ routesAdjacency.forEach((value, key) => {
16778
+ protoRoutesAdjacency.routes[key] = {
16779
+ stopTimes: uint32ArrayToBytes(value.stopTimes),
16780
+ pickUpDropOffTypes: value.pickUpDropOffTypes,
16781
+ stops: uint32ArrayToBytes(value.stops),
16782
+ serviceRouteId: value.serviceRouteId,
16783
+ };
16784
+ });
16785
+ return protoRoutesAdjacency;
16786
+ };
16787
+ const serializeServiceRoutesMap = (serviceRoutesMap) => {
16788
+ const protoServiceRoutesMap = {
16789
+ routes: {},
16790
+ };
16791
+ serviceRoutesMap.forEach((value, key) => {
16792
+ protoServiceRoutesMap.routes[key] = {
16793
+ type: serializeRouteType(value.type),
16794
+ name: value.name,
16795
+ };
16796
+ });
16797
+ return protoServiceRoutesMap;
16798
+ };
16799
+ const deserializeStopsAdjacency = (protoStopsAdjacency) => {
16800
+ const stopsAdjacency = new Map();
16801
+ Object.entries(protoStopsAdjacency.stops).forEach(([keyStr, value]) => {
16802
+ const key = parseInt(keyStr, 10);
16803
+ stopsAdjacency.set(key, {
16804
+ transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: parseTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
16805
+ minTransferTime: Duration.fromSeconds(transfer.minTransferTime),
16806
+ })))),
16807
+ routes: value.routes,
16808
+ });
16809
+ });
16810
+ return stopsAdjacency;
16811
+ };
16812
+ const deserializeRoutesAdjacency = (protoRoutesAdjacency) => {
16813
+ const routesAdjacency = new Map();
16814
+ Object.entries(protoRoutesAdjacency.routes).forEach(([key, value]) => {
16815
+ const stops = bytesToUint32Array(value.stops);
16816
+ const indices = new Map();
16817
+ for (let i = 0; i < stops.length; i++) {
16818
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16819
+ indices.set(stops[i], i);
16820
+ }
16821
+ routesAdjacency.set(key, {
16822
+ stopTimes: bytesToUint32Array(value.stopTimes),
16823
+ pickUpDropOffTypes: value.pickUpDropOffTypes,
16824
+ stops: stops,
16825
+ stopIndices: indices,
16826
+ serviceRouteId: value.serviceRouteId,
16827
+ });
16828
+ });
16829
+ return routesAdjacency;
16830
+ };
16831
+ const deserializeServiceRoutesMap = (protoServiceRoutesMap) => {
16832
+ const serviceRoutesMap = new Map();
16833
+ Object.entries(protoServiceRoutesMap.routes).forEach(([key, value]) => {
16834
+ serviceRoutesMap.set(key, {
16835
+ type: parseRouteType(value.type),
16836
+ name: value.name,
16837
+ });
16838
+ });
16839
+ return serviceRoutesMap;
16840
+ };
16841
+ const parseTransferType = (type) => {
16842
+ switch (type) {
16843
+ case TransferType.RECOMMENDED_TRANSFER_POINT:
16844
+ return 'RECOMMENDED';
16845
+ case TransferType.TIMED_TRANSFER:
16846
+ return 'GUARANTEED';
16847
+ case TransferType.REQUIRES_MINIMAL_TIME:
16848
+ return 'REQUIRES_MINIMAL_TIME';
16849
+ case TransferType.IN_SEAT_TRANSFER:
16850
+ return 'IN_SEAT';
16851
+ case TransferType.UNRECOGNIZED:
16852
+ throw new Error('Unrecognized protobuf transfer type.');
16853
+ }
16854
+ };
16855
+ const serializeTransferType = (type) => {
16856
+ switch (type) {
16857
+ case 'RECOMMENDED':
16858
+ return TransferType.RECOMMENDED_TRANSFER_POINT;
16859
+ case 'GUARANTEED':
16860
+ return TransferType.TIMED_TRANSFER;
16861
+ case 'REQUIRES_MINIMAL_TIME':
16862
+ return TransferType.REQUIRES_MINIMAL_TIME;
16863
+ case 'IN_SEAT':
16864
+ return TransferType.IN_SEAT_TRANSFER;
16865
+ }
16866
+ };
16867
+ const parseRouteType = (type) => {
16868
+ switch (type) {
16869
+ case RouteType.TRAM:
16870
+ return 'TRAM';
16871
+ case RouteType.SUBWAY:
16872
+ return 'SUBWAY';
16873
+ case RouteType.RAIL:
16874
+ return 'RAIL';
16875
+ case RouteType.BUS:
16876
+ return 'BUS';
16877
+ case RouteType.FERRY:
16878
+ return 'FERRY';
16879
+ case RouteType.CABLE_TRAM:
16880
+ return 'CABLE_TRAM';
16881
+ case RouteType.AERIAL_LIFT:
16882
+ return 'AERIAL_LIFT';
16883
+ case RouteType.FUNICULAR:
16884
+ return 'FUNICULAR';
16885
+ case RouteType.TROLLEYBUS:
16886
+ return 'TROLLEYBUS';
16887
+ case RouteType.MONORAIL:
16888
+ return 'MONORAIL';
16889
+ case RouteType.UNRECOGNIZED:
16890
+ default:
16891
+ throw new Error('Unrecognized protobuf route type.');
16892
+ }
16893
+ };
16894
+ const serializeRouteType = (type) => {
16895
+ switch (type) {
16896
+ case 'TRAM':
16897
+ return RouteType.TRAM;
16898
+ case 'SUBWAY':
16899
+ return RouteType.SUBWAY;
16900
+ case 'RAIL':
16901
+ return RouteType.RAIL;
16902
+ case 'BUS':
16903
+ return RouteType.BUS;
16904
+ case 'FERRY':
16905
+ return RouteType.FERRY;
16906
+ case 'CABLE_TRAM':
16907
+ return RouteType.CABLE_TRAM;
16908
+ case 'AERIAL_LIFT':
16909
+ return RouteType.AERIAL_LIFT;
16910
+ case 'FUNICULAR':
16911
+ return RouteType.FUNICULAR;
16912
+ case 'TROLLEYBUS':
16913
+ return RouteType.TROLLEYBUS;
16914
+ case 'MONORAIL':
16915
+ return RouteType.MONORAIL;
16916
+ }
16917
+ };
16918
+
16752
16919
  /**
16753
16920
  * A class representing a time in hours, minutes, and seconds.
16754
16921
  */
@@ -16920,195 +17087,10 @@ class Time {
16920
17087
  }
16921
17088
  }
16922
17089
 
16923
- const serializeStopsAdjacency = (stopsAdjacency) => {
16924
- const protoStopsAdjacency = {
16925
- stops: {},
16926
- };
16927
- stopsAdjacency.forEach((value, key) => {
16928
- protoStopsAdjacency.stops[key] = {
16929
- transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: serializeTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
16930
- minTransferTime: transfer.minTransferTime.toSeconds(),
16931
- })))),
16932
- routes: value.routes,
16933
- };
16934
- });
16935
- return protoStopsAdjacency;
16936
- };
16937
- const serializeRoutesAdjacency = (routesAdjacency) => {
16938
- const protoRoutesAdjacency = {
16939
- routes: {},
16940
- };
16941
- routesAdjacency.forEach((value, key) => {
16942
- protoRoutesAdjacency.routes[key] = {
16943
- stopTimes: value.stopTimes.map((stopTimes) => ({
16944
- arrival: stopTimes.arrival.toSeconds(),
16945
- departure: stopTimes.departure.toSeconds(),
16946
- pickUpType: serializePickUpDropOffType(stopTimes.pickUpType),
16947
- dropOffType: serializePickUpDropOffType(stopTimes.dropOffType),
16948
- })),
16949
- stops: value.stops,
16950
- serviceRouteId: value.serviceRouteId,
16951
- };
16952
- });
16953
- return protoRoutesAdjacency;
16954
- };
16955
- const serializeServiceRoutesMap = (serviceRoutesMap) => {
16956
- const protoServiceRoutesMap = {
16957
- routes: {},
16958
- };
16959
- serviceRoutesMap.forEach((value, key) => {
16960
- protoServiceRoutesMap.routes[key] = {
16961
- type: serializeRouteType(value.type),
16962
- name: value.name,
16963
- };
16964
- });
16965
- return protoServiceRoutesMap;
16966
- };
16967
- const deserializeStopsAdjacency = (protoStopsAdjacency) => {
16968
- const stopsAdjacency = new Map();
16969
- Object.entries(protoStopsAdjacency.stops).forEach(([key, value]) => {
16970
- stopsAdjacency.set(key, {
16971
- transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: parseTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
16972
- minTransferTime: Duration.fromSeconds(transfer.minTransferTime),
16973
- })))),
16974
- routes: value.routes,
16975
- });
16976
- });
16977
- return stopsAdjacency;
16978
- };
16979
- const deserializeRoutesAdjacency = (protoRoutesAdjacency) => {
16980
- const routesAdjacency = new Map();
16981
- Object.entries(protoRoutesAdjacency.routes).forEach(([key, value]) => {
16982
- routesAdjacency.set(key, {
16983
- stopTimes: value.stopTimes.map((stopTimes) => ({
16984
- arrival: Time.fromSeconds(stopTimes.arrival),
16985
- departure: Time.fromSeconds(stopTimes.departure),
16986
- pickUpType: stopTimes.pickUpType !== undefined
16987
- ? parsePickUpDropOffType(stopTimes.pickUpType)
16988
- : 'REGULAR',
16989
- dropOffType: stopTimes.dropOffType !== undefined
16990
- ? parsePickUpDropOffType(stopTimes.dropOffType)
16991
- : 'REGULAR',
16992
- })),
16993
- stops: value.stops,
16994
- stopIndices: new Map(value.stops.map((stop, index) => [stop, index])),
16995
- serviceRouteId: value.serviceRouteId,
16996
- });
16997
- });
16998
- return routesAdjacency;
16999
- };
17000
- const deserializeServiceRoutesMap = (protoServiceRoutesMap) => {
17001
- const serviceRoutesMap = new Map();
17002
- Object.entries(protoServiceRoutesMap.routes).forEach(([key, value]) => {
17003
- serviceRoutesMap.set(key, {
17004
- type: parseRouteType(value.type),
17005
- name: value.name,
17006
- });
17007
- });
17008
- return serviceRoutesMap;
17009
- };
17010
- const parseTransferType = (type) => {
17011
- switch (type) {
17012
- case TransferType.RECOMMENDED_TRANSFER_POINT:
17013
- return 'RECOMMENDED';
17014
- case TransferType.TIMED_TRANSFER:
17015
- return 'GUARANTEED';
17016
- case TransferType.REQUIRES_MINIMAL_TIME:
17017
- return 'REQUIRES_MINIMAL_TIME';
17018
- case TransferType.IN_SEAT_TRANSFER:
17019
- return 'IN_SEAT';
17020
- case TransferType.UNRECOGNIZED:
17021
- throw new Error('Unrecognized protobuf transfer type.');
17022
- }
17023
- };
17024
- const serializeTransferType = (type) => {
17025
- switch (type) {
17026
- case 'RECOMMENDED':
17027
- return TransferType.RECOMMENDED_TRANSFER_POINT;
17028
- case 'GUARANTEED':
17029
- return TransferType.TIMED_TRANSFER;
17030
- case 'REQUIRES_MINIMAL_TIME':
17031
- return TransferType.REQUIRES_MINIMAL_TIME;
17032
- case 'IN_SEAT':
17033
- return TransferType.IN_SEAT_TRANSFER;
17034
- }
17035
- };
17036
- const parseRouteType = (type) => {
17037
- switch (type) {
17038
- case RouteType.TRAM:
17039
- return 'TRAM';
17040
- case RouteType.SUBWAY:
17041
- return 'SUBWAY';
17042
- case RouteType.RAIL:
17043
- return 'RAIL';
17044
- case RouteType.BUS:
17045
- return 'BUS';
17046
- case RouteType.FERRY:
17047
- return 'FERRY';
17048
- case RouteType.CABLE_TRAM:
17049
- return 'CABLE_TRAM';
17050
- case RouteType.AERIAL_LIFT:
17051
- return 'AERIAL_LIFT';
17052
- case RouteType.FUNICULAR:
17053
- return 'FUNICULAR';
17054
- case RouteType.TROLLEYBUS:
17055
- return 'TROLLEYBUS';
17056
- case RouteType.MONORAIL:
17057
- return 'MONORAIL';
17058
- case RouteType.UNRECOGNIZED:
17059
- default:
17060
- throw new Error('Unrecognized protobuf route type.');
17061
- }
17062
- };
17063
- const serializeRouteType = (type) => {
17064
- switch (type) {
17065
- case 'TRAM':
17066
- return RouteType.TRAM;
17067
- case 'SUBWAY':
17068
- return RouteType.SUBWAY;
17069
- case 'RAIL':
17070
- return RouteType.RAIL;
17071
- case 'BUS':
17072
- return RouteType.BUS;
17073
- case 'FERRY':
17074
- return RouteType.FERRY;
17075
- case 'CABLE_TRAM':
17076
- return RouteType.CABLE_TRAM;
17077
- case 'AERIAL_LIFT':
17078
- return RouteType.AERIAL_LIFT;
17079
- case 'FUNICULAR':
17080
- return RouteType.FUNICULAR;
17081
- case 'TROLLEYBUS':
17082
- return RouteType.TROLLEYBUS;
17083
- case 'MONORAIL':
17084
- return RouteType.MONORAIL;
17085
- }
17086
- };
17087
- const parsePickUpDropOffType = (type) => {
17088
- switch (type) {
17089
- case PickUpDropOffType.MUST_PHONE_AGENCY:
17090
- return 'MUST_PHONE_AGENCY';
17091
- case PickUpDropOffType.MUST_COORDINATE_WITH_DRIVER:
17092
- return 'MUST_COORDINATE_WITH_DRIVER';
17093
- case PickUpDropOffType.NOT_AVAILABLE:
17094
- return 'NOT_AVAILABLE';
17095
- default:
17096
- return 'REGULAR';
17097
- }
17098
- };
17099
- const serializePickUpDropOffType = (type) => {
17100
- switch (type) {
17101
- case 'REGULAR':
17102
- return undefined;
17103
- case 'NOT_AVAILABLE':
17104
- return PickUpDropOffType.NOT_AVAILABLE;
17105
- case 'MUST_COORDINATE_WITH_DRIVER':
17106
- return PickUpDropOffType.MUST_COORDINATE_WITH_DRIVER;
17107
- case 'MUST_PHONE_AGENCY':
17108
- return PickUpDropOffType.MUST_PHONE_AGENCY;
17109
- }
17110
- };
17111
-
17090
+ const REGULAR = 0;
17091
+ const NOT_AVAILABLE = 1;
17092
+ const MUST_PHONE_AGENCY = 2;
17093
+ const MUST_COORDINATE_WITH_DRIVER = 3;
17112
17094
  const ALL_TRANSPORT_MODES = [
17113
17095
  'TRAM',
17114
17096
  'SUBWAY',
@@ -17121,7 +17103,7 @@ const ALL_TRANSPORT_MODES = [
17121
17103
  'TROLLEYBUS',
17122
17104
  'MONORAIL',
17123
17105
  ];
17124
- const CURRENT_VERSION = '0.0.1';
17106
+ const CURRENT_VERSION = '0.0.2';
17125
17107
  /**
17126
17108
  * The internal transit timetable format
17127
17109
  * reuses some GTFS concepts for the sake of simplicity for now.
@@ -17168,6 +17150,13 @@ class Timetable {
17168
17150
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
17169
17151
  deserializeServiceRoutesMap(protoTimetable.routes));
17170
17152
  }
17153
+ getRoutesThroughStop(stopId) {
17154
+ const stopAdjacency = this.stopsAdjacency.get(stopId);
17155
+ if (!stopAdjacency) {
17156
+ return [];
17157
+ }
17158
+ return stopAdjacency.routes;
17159
+ }
17171
17160
  getRoute(routeId) {
17172
17161
  return this.routesAdjacency.get(routeId);
17173
17162
  }
@@ -17234,9 +17223,9 @@ class Timetable {
17234
17223
  if (beforeTrip === undefined) {
17235
17224
  for (let tripIndex = 0; tripIndex < route.stopTimes.length / stopsNumber; tripIndex++) {
17236
17225
  const stopTimeIndex = tripIndex * stopsNumber + stopIndex;
17237
- const stopTime = route.stopTimes[stopTimeIndex];
17238
- if (stopTime.departure >= after &&
17239
- stopTime.pickUpType !== 'NOT_AVAILABLE') {
17226
+ const departure = route.stopTimes[stopTimeIndex * 2 + 1];
17227
+ const pickUpType = route.pickUpDropOffTypes[stopTimeIndex * 2];
17228
+ if (departure >= after.toSeconds() && pickUpType !== NOT_AVAILABLE) {
17240
17229
  return tripIndex;
17241
17230
  }
17242
17231
  }
@@ -17248,15 +17237,16 @@ class Timetable {
17248
17237
  for (let tripIndex = beforeTrip; // ?? route.stopTimes.length / stopsNumber - 1;
17249
17238
  tripIndex >= 0; tripIndex--) {
17250
17239
  const stopTimeIndex = tripIndex * stopsNumber + stopIndex;
17251
- const stopTime = route.stopTimes[stopTimeIndex];
17252
- if (stopTime.departure < after) {
17240
+ const departure = route.stopTimes[stopTimeIndex * 2 + 1];
17241
+ const pickUpType = route.pickUpDropOffTypes[stopTimeIndex * 2];
17242
+ if (departure < after.toSeconds()) {
17253
17243
  break;
17254
17244
  }
17255
- if (stopTime.pickUpType !== 'NOT_AVAILABLE' &&
17245
+ if (pickUpType !== NOT_AVAILABLE &&
17256
17246
  (earliestDeparture === undefined ||
17257
- stopTime.departure < earliestDeparture)) {
17247
+ departure < earliestDeparture.toSeconds())) {
17258
17248
  earliestTripIndex = tripIndex;
17259
- earliestDeparture = stopTime.departure;
17249
+ earliestDeparture = Time.fromSeconds(departure);
17260
17250
  }
17261
17251
  }
17262
17252
  return earliestTripIndex;
@@ -19182,23 +19172,23 @@ const parse = function () {
19182
19172
  };
19183
19173
 
19184
19174
  /**
19185
- * Generates a simple hash from a string.
19175
+ * Generates a simple hash from an array of numeric IDs.
19186
19176
  *
19187
- * This function computes a hash for a given string by iterating over each
19188
- * character and applying bitwise operations to accumulate a hash value.
19189
- * The final hash is then converted to a base-36 string and padded to
19190
- * ensure a minimum length of 6 characters.
19177
+ * This function computes a hash for a given array of numbers by iterating over each
19178
+ * ID and applying bitwise operations to accumulate a hash value.
19179
+ * The final hash is then converted to a base-36 string.
19191
19180
  *
19192
- * @param str - The input string to hash.
19193
- * @returns A hashed string representation of the input.
19181
+ * @param ids - The array of numeric IDs to hash.
19182
+ * @returns A hashed string representation of the input array.
19194
19183
  */
19195
- const hash = (str) => {
19184
+ const hashIds = (ids) => {
19196
19185
  let hash = 0;
19197
- for (let i = 0; i < str.length; i++) {
19198
- hash = (hash << 5) - hash + str.charCodeAt(i);
19186
+ for (let i = 0; i < ids.length; i++) {
19187
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19188
+ hash = (hash << 5) - hash + ids[i];
19199
19189
  hash &= hash;
19200
19190
  }
19201
- return (hash >>> 0).toString(36).padStart(6, '0');
19191
+ return (hash >>> 0).toString(36);
19202
19192
  };
19203
19193
  /**
19204
19194
  * Parses a CSV stream with a sensible configuration for GTFS feeds.
@@ -19366,18 +19356,19 @@ const parseCalendarDates = (calendarDatesStream, serviceIds, date) => __awaiter(
19366
19356
  * @param stopsStream The readable stream containing the stops data.
19367
19357
  * @return A mapping of stop IDs to corresponding stop details.
19368
19358
  */
19369
- const parseStops = (stopsStream, platformParser, validStops) => __awaiter(undefined, undefined, undefined, function* () {
19359
+ const parseStops = (stopsStream, platformParser) => __awaiter(undefined, undefined, undefined, function* () {
19370
19360
  var _a, e_1, _b, _c;
19371
- const stops = new Map();
19361
+ const parsedStops = new Map();
19362
+ let i = 0;
19372
19363
  try {
19373
19364
  for (var _d = true, _e = __asyncValues(parseCsv(stopsStream)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
19374
19365
  _c = _f.value;
19375
19366
  _d = false;
19376
19367
  const rawLine = _c;
19377
19368
  const line = rawLine;
19378
- const stop = Object.assign({ id: line.stop_id, name: line.stop_name, lat: line.stop_lat, lon: line.stop_lon, locationType: line.location_type
19369
+ 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
19379
19370
  ? parseGtfsLocationType(line.location_type)
19380
- : 'SIMPLE_STOP_OR_PLATFORM', children: [] }, (line.parent_station && { parent: line.parent_station }));
19371
+ : 'SIMPLE_STOP_OR_PLATFORM', children: [] }, (line.parent_station && { parentSourceId: line.parent_station }));
19381
19372
  if (platformParser) {
19382
19373
  try {
19383
19374
  const platform = platformParser(line);
@@ -19389,7 +19380,8 @@ const parseStops = (stopsStream, platformParser, validStops) => __awaiter(undefi
19389
19380
  console.info(`Could not parse platform for stop ${line.stop_id}.`);
19390
19381
  }
19391
19382
  }
19392
- stops.set(line.stop_id, stop);
19383
+ parsedStops.set(line.stop_id + '', stop);
19384
+ i = i + 1;
19393
19385
  }
19394
19386
  }
19395
19387
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -19399,29 +19391,50 @@ const parseStops = (stopsStream, platformParser, validStops) => __awaiter(undefi
19399
19391
  }
19400
19392
  finally { if (e_1) throw e_1.error; }
19401
19393
  }
19402
- for (const [stopId, stop] of stops) {
19403
- if (stop.parent) {
19404
- const parentStop = stops.get(stop.parent);
19394
+ for (const [sourceStopId, stop] of parsedStops) {
19395
+ if (stop.parentSourceId) {
19396
+ const parentStop = parsedStops.get(stop.parentSourceId);
19405
19397
  if (!parentStop) {
19406
- console.warn(`Cannot find parent stop ${stop.parent} of ${stopId}`);
19398
+ console.warn(`Cannot find parent stop ${stop.parentSourceId} of ${sourceStopId}`);
19407
19399
  continue;
19408
19400
  }
19409
- parentStop.children.push(stopId);
19401
+ stop.parent = parentStop.id;
19402
+ parentStop.children.push(stop.id);
19410
19403
  }
19411
19404
  }
19412
- if (validStops) {
19413
- // Remove all stops which don't have at least one valid stopId as a child,
19414
- // a parent or as its own.
19415
- for (const [stopId, stop] of stops) {
19416
- if (!validStops.has(stopId) &&
19417
- (!stop.parent || !validStops.has(stop.parent)) &&
19418
- !stop.children.some((childId) => validStops.has(childId))) {
19419
- stops.delete(stopId);
19420
- }
19405
+ return parsedStops;
19406
+ });
19407
+ /**
19408
+ * Builds the final stop map indexed by internal IDs.
19409
+ * Excludes all stops that do not have at least one valid stopId
19410
+ * as a child, a parent, or being valid itself.
19411
+ *
19412
+ * @param parsedStops - The map of parsed stops.
19413
+ * @param validStops - A set of valid stop IDs.
19414
+ * @returns A map of stops indexed by internal IDs.
19415
+ */
19416
+ const indexStops = (parsedStops, validStops) => {
19417
+ const stops = new Map();
19418
+ for (const [, stop] of parsedStops) {
19419
+ if (!validStops ||
19420
+ validStops.has(stop.id) ||
19421
+ (stop.parent && validStops.has(stop.parent)) ||
19422
+ stop.children.some((childId) => validStops.has(childId))) {
19423
+ stops.set(stop.id, {
19424
+ id: stop.id,
19425
+ sourceStopId: stop.sourceStopId,
19426
+ name: stop.name,
19427
+ lat: stop.lat,
19428
+ lon: stop.lon,
19429
+ locationType: stop.locationType,
19430
+ platform: stop.platform,
19431
+ children: stop.children.filter((childId) => !validStops || validStops.has(childId)),
19432
+ parent: stop.parent,
19433
+ });
19421
19434
  }
19422
19435
  }
19423
19436
  return stops;
19424
- });
19437
+ };
19425
19438
  const parseGtfsLocationType = (gtfsLocationType) => {
19426
19439
  switch (gtfsLocationType) {
19427
19440
  case 0:
@@ -19444,7 +19457,7 @@ const parseGtfsLocationType = (gtfsLocationType) => {
19444
19457
  * @param stopsStream The readable stream containing the stops data.
19445
19458
  * @return A mapping of stop IDs to corresponding stop details.
19446
19459
  */
19447
- const parseTransfers = (transfersStream) => __awaiter(undefined, undefined, undefined, function* () {
19460
+ const parseTransfers = (transfersStream, stopsMap) => __awaiter(undefined, undefined, undefined, function* () {
19448
19461
  var _a, e_1, _b, _c;
19449
19462
  const transfers = new Map();
19450
19463
  try {
@@ -19472,12 +19485,16 @@ const parseTransfers = (transfersStream) => __awaiter(undefined, undefined, unde
19472
19485
  if (transferEntry.transfer_type === 2 && !transferEntry.min_transfer_time) {
19473
19486
  console.info(`Missing minimum transfer time between ${transferEntry.from_stop_id} and ${transferEntry.to_stop_id}.`);
19474
19487
  }
19475
- const transfer = Object.assign({ destination: transferEntry.to_stop_id, type: parseGtfsTransferType(transferEntry.transfer_type) }, (transferEntry.min_transfer_time && {
19488
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19489
+ const fromStop = stopsMap.get(transferEntry.from_stop_id + '');
19490
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19491
+ const toStop = stopsMap.get(transferEntry.to_stop_id + '');
19492
+ const transfer = Object.assign({ destination: toStop.id, type: parseGtfsTransferType(transferEntry.transfer_type) }, (transferEntry.min_transfer_time && {
19476
19493
  minTransferTime: Duration.fromSeconds(transferEntry.min_transfer_time),
19477
19494
  }));
19478
- const fromStopTransfers = transfers.get(transferEntry.from_stop_id) || [];
19495
+ const fromStopTransfers = transfers.get(fromStop.id) || [];
19479
19496
  fromStopTransfers.push(transfer);
19480
- transfers.set(transferEntry.from_stop_id, fromStopTransfers);
19497
+ transfers.set(fromStop.id, fromStopTransfers);
19481
19498
  }
19482
19499
  }
19483
19500
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -19568,28 +19585,52 @@ const buildStopsAdjacencyStructure = (validStops, routes, transfersMap) => {
19568
19585
  * Parses the stop_times.txt data from a GTFS feed.
19569
19586
  *
19570
19587
  * @param stopTimesStream The readable stream containing the stop times data.
19588
+ * @param stopsMap A map of parsed stops from the GTFS feed.
19571
19589
  * @param validTripIds A map of valid trip IDs to corresponding route IDs.
19572
- * @param validStopIds A map of valid stop IDs.
19573
- * @returns A mapping of route IDs to route details. The routes return corresponds to the set of trips from GTFS that share the same stop list.
19590
+ * @param validStopIds A set of valid stop IDs.
19591
+ * @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.
19574
19592
  */
19575
- const parseStopTimes = (stopTimesStream, validTripIds, validStopIds) => __awaiter(undefined, undefined, undefined, function* () {
19593
+ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) => __awaiter(undefined, undefined, undefined, function* () {
19576
19594
  var _a, e_2, _b, _c;
19577
19595
  var _d, _e;
19596
+ /**
19597
+ * Inserts a trip at the right place in the routes adjacency structure.
19598
+ */
19578
19599
  const addTrip = (currentTripId) => {
19579
19600
  const gtfsRouteId = validTripIds.get(currentTripId);
19580
19601
  if (!gtfsRouteId) {
19581
19602
  stops = [];
19582
- stopTimes = [];
19603
+ arrivalTimes = [];
19604
+ departureTimes = [];
19605
+ pickUpTypes = [];
19606
+ dropOffTypes = [];
19583
19607
  return;
19584
19608
  }
19585
- const routeId = `${gtfsRouteId}_${hash(stops.join('$'))}`;
19609
+ const routeId = `${gtfsRouteId}_${hashIds(stops)}`;
19586
19610
  let route = routes.get(routeId);
19587
19611
  if (!route) {
19612
+ const stopsCount = stops.length;
19613
+ const stopsArray = new Uint32Array(stops);
19614
+ const stopTimesArray = new Uint32Array(stopsCount * 2);
19615
+ for (let i = 0; i < stopsCount; i++) {
19616
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19617
+ stopTimesArray[i * 2] = arrivalTimes[i];
19618
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19619
+ stopTimesArray[i * 2 + 1] = departureTimes[i];
19620
+ }
19621
+ const pickUpDropOffTypesArray = new Uint8Array(stopsCount * 2);
19622
+ for (let i = 0; i < stopsCount; i++) {
19623
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19624
+ pickUpDropOffTypesArray[i * 2] = pickUpTypes[i];
19625
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19626
+ pickUpDropOffTypesArray[i * 2 + 1] = dropOffTypes[i];
19627
+ }
19588
19628
  route = {
19589
19629
  serviceRouteId: gtfsRouteId,
19590
- stops: [...stops],
19630
+ stops: stopsArray,
19591
19631
  stopIndices: new Map(stops.map((stop, i) => [stop, i])),
19592
- stopTimes: [...stopTimes],
19632
+ stopTimes: stopTimesArray,
19633
+ pickUpDropOffTypes: pickUpDropOffTypesArray,
19593
19634
  };
19594
19635
  routes.set(routeId, route);
19595
19636
  for (const stop of stops) {
@@ -19597,31 +19638,59 @@ const parseStopTimes = (stopTimesStream, validTripIds, validStopIds) => __awaite
19597
19638
  }
19598
19639
  }
19599
19640
  else {
19600
- const tripFirstStop = stopTimes[0];
19601
- if (!tripFirstStop) {
19641
+ const tripFirstStopDeparture = departureTimes[0];
19642
+ if (tripFirstStopDeparture === undefined) {
19602
19643
  throw new Error(`Empty trip ${currentTripId}`);
19603
19644
  }
19604
- // insert the stopTimes at the right position
19605
- let stopTimesIndex = 0;
19606
- for (let i = 0; i < route.stopTimes.length; i += stops.length) {
19607
- const currentDeparture = route.stopTimes[i];
19608
- if (currentDeparture &&
19609
- tripFirstStop.departure > currentDeparture.departure) {
19610
- stopTimesIndex = i + stops.length;
19645
+ // Find the correct position to insert the new trip
19646
+ const stopsCount = stops.length;
19647
+ let insertPosition = 0;
19648
+ const existingTripsCount = route.stopTimes.length / (stopsCount * 2);
19649
+ for (let tripIndex = 0; tripIndex < existingTripsCount; tripIndex++) {
19650
+ const currentDeparture = route.stopTimes[tripIndex * stopsCount * 2 + 1];
19651
+ if (currentDeparture && tripFirstStopDeparture > currentDeparture) {
19652
+ insertPosition = (tripIndex + 1) * stopsCount;
19611
19653
  }
19612
19654
  else {
19613
19655
  break;
19614
19656
  }
19615
19657
  }
19616
- route.stopTimes.splice(stopTimesIndex, 0, ...stopTimes);
19658
+ // insert data for the new trip at the right place
19659
+ const newStopTimesLength = route.stopTimes.length + stopsCount * 2;
19660
+ const newStopTimes = new Uint32Array(newStopTimesLength);
19661
+ const newPickUpDropOffTypes = new Uint8Array(newStopTimesLength);
19662
+ newStopTimes.set(route.stopTimes.slice(0, insertPosition * 2), 0);
19663
+ newPickUpDropOffTypes.set(route.pickUpDropOffTypes.slice(0, insertPosition * 2), 0);
19664
+ for (let i = 0; i < stopsCount; i++) {
19665
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19666
+ newStopTimes[(insertPosition + i) * 2] = arrivalTimes[i];
19667
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19668
+ newStopTimes[(insertPosition + i) * 2 + 1] = departureTimes[i];
19669
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19670
+ newPickUpDropOffTypes[(insertPosition + i) * 2] = pickUpTypes[i];
19671
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19672
+ newPickUpDropOffTypes[(insertPosition + i) * 2 + 1] = dropOffTypes[i];
19673
+ }
19674
+ const afterInsertionSlice = route.stopTimes.slice(insertPosition * 2);
19675
+ newStopTimes.set(afterInsertionSlice, (insertPosition + stopsCount) * 2);
19676
+ const afterInsertionTypesSlice = route.pickUpDropOffTypes.slice(insertPosition * 2);
19677
+ newPickUpDropOffTypes.set(afterInsertionTypesSlice, (insertPosition + stopsCount) * 2);
19678
+ route.stopTimes = newStopTimes;
19679
+ route.pickUpDropOffTypes = newPickUpDropOffTypes;
19617
19680
  }
19618
19681
  stops = [];
19619
- stopTimes = [];
19682
+ arrivalTimes = [];
19683
+ departureTimes = [];
19684
+ pickUpTypes = [];
19685
+ dropOffTypes = [];
19620
19686
  };
19621
19687
  const routes = new Map();
19622
19688
  let previousSeq = 0;
19623
19689
  let stops = [];
19624
- let stopTimes = [];
19690
+ let arrivalTimes = [];
19691
+ let departureTimes = [];
19692
+ let pickUpTypes = [];
19693
+ let dropOffTypes = [];
19625
19694
  let currentTripId = undefined;
19626
19695
  try {
19627
19696
  for (var _f = true, _g = __asyncValues(parseCsv(stopTimesStream)), _h; _h = yield _g.next(), _a = _h.done, !_a; _f = true) {
@@ -19640,24 +19709,20 @@ const parseStopTimes = (stopTimesStream, validTripIds, validStopIds) => __awaite
19640
19709
  if (line.pickup_type === 1 && line.drop_off_type === 1) {
19641
19710
  continue;
19642
19711
  }
19643
- if (currentTripId &&
19644
- line.trip_id !== currentTripId &&
19645
- stops.length > 0 &&
19646
- stopTimes.length > 0) {
19712
+ if (currentTripId && line.trip_id !== currentTripId && stops.length > 0) {
19647
19713
  addTrip(currentTripId);
19648
19714
  }
19649
19715
  currentTripId = line.trip_id;
19650
- stops.push(line.stop_id);
19716
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19717
+ stops.push(stopsMap.get(line.stop_id + '').id);
19651
19718
  const departure = (_d = line.departure_time) !== null && _d !== void 0 ? _d : line.arrival_time;
19652
19719
  const arrival = (_e = line.arrival_time) !== null && _e !== void 0 ? _e : line.departure_time;
19653
- stopTimes.push({
19654
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19655
- departure: toTime(departure),
19656
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19657
- arrival: toTime(arrival),
19658
- pickUpType: parsePickupDropOffType(line.pickup_type),
19659
- dropOffType: parsePickupDropOffType(line.drop_off_type),
19660
- });
19720
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19721
+ arrivalTimes.push(toTime(arrival).toSeconds());
19722
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19723
+ departureTimes.push(toTime(departure).toSeconds());
19724
+ pickUpTypes.push(parsePickupDropOffType(line.pickup_type));
19725
+ dropOffTypes.push(parsePickupDropOffType(line.drop_off_type));
19661
19726
  previousSeq = line.stop_sequence;
19662
19727
  }
19663
19728
  }
@@ -19677,15 +19742,15 @@ const parsePickupDropOffType = (gtfsType) => {
19677
19742
  switch (gtfsType) {
19678
19743
  default:
19679
19744
  console.warn(`Unknown pickup/drop-off type ${gtfsType}`);
19680
- return 'REGULAR';
19745
+ return REGULAR;
19681
19746
  case 0:
19682
- return 'REGULAR';
19747
+ return REGULAR;
19683
19748
  case 1:
19684
- return 'NOT_AVAILABLE';
19749
+ return NOT_AVAILABLE;
19685
19750
  case 2:
19686
- return 'MUST_PHONE_AGENCY';
19751
+ return MUST_PHONE_AGENCY;
19687
19752
  case 3:
19688
- return 'MUST_COORDINATE_WITH_DRIVER';
19753
+ return MUST_COORDINATE_WITH_DRIVER;
19689
19754
  }
19690
19755
  };
19691
19756
 
@@ -19717,6 +19782,10 @@ class GtfsParser {
19717
19782
  const datetime = DateTime.fromJSDate(date);
19718
19783
  const validServiceIds = new Set();
19719
19784
  const validStopIds = new Set();
19785
+ log.info(`Parsing ${STOPS_FILE}`);
19786
+ const stopsStream = yield zip.stream(STOPS_FILE);
19787
+ const parsedStops = yield parseStops(stopsStream, this.profile.platformParser);
19788
+ log.info(`${parsedStops.size} parsed stops.`);
19720
19789
  if (entries[CALENDAR_FILE]) {
19721
19790
  log.info(`Parsing ${CALENDAR_FILE}`);
19722
19791
  const calendarStream = yield zip.stream(CALENDAR_FILE);
@@ -19741,18 +19810,17 @@ class GtfsParser {
19741
19810
  if (entries[TRANSFERS_FILE]) {
19742
19811
  log.info(`Parsing ${TRANSFERS_FILE}`);
19743
19812
  const transfersStream = yield zip.stream(TRANSFERS_FILE);
19744
- transfers = yield parseTransfers(transfersStream);
19813
+ transfers = yield parseTransfers(transfersStream, parsedStops);
19745
19814
  log.info(`${transfers.size} valid transfers.`);
19746
19815
  }
19747
19816
  log.info(`Parsing ${STOP_TIMES_FILE}`);
19748
19817
  const stopTimesStream = yield zip.stream(STOP_TIMES_FILE);
19749
- const routesAdjacency = yield parseStopTimes(stopTimesStream, trips, validStopIds);
19818
+ const routesAdjacency = yield parseStopTimes(stopTimesStream, parsedStops, trips, validStopIds);
19750
19819
  const stopsAdjacency = buildStopsAdjacencyStructure(validStopIds, routesAdjacency, transfers);
19751
19820
  log.info(`${routesAdjacency.size} valid unique routes.`);
19752
- log.info(`Parsing ${STOPS_FILE}`);
19753
- const stopsStream = yield zip.stream(STOPS_FILE);
19754
- const stops = yield parseStops(stopsStream, this.profile.platformParser, validStopIds);
19755
- log.info(`${stops.size} valid stops.`);
19821
+ log.info(`Removing unused stops.`);
19822
+ const stops = indexStops(parsedStops, validStopIds);
19823
+ log.info(`${stops.size} used stop stops, ${parsedStops.size - stops.size} unused.`);
19756
19824
  yield zip.close();
19757
19825
  const timetable = new Timetable(stopsAdjacency, routesAdjacency, validGtfsRoutes);
19758
19826
  log.info(`Building stops index.`);
@@ -19773,8 +19841,8 @@ class GtfsParser {
19773
19841
  const zip = new StreamZip.async({ file: this.path });
19774
19842
  log.info(`Parsing ${STOPS_FILE}`);
19775
19843
  const stopsStream = yield zip.stream(STOPS_FILE);
19776
- const stops = yield parseStops(stopsStream, this.profile.platformParser);
19777
- log.info(`${stops.size} valid stops.`);
19844
+ const stops = indexStops(yield parseStops(stopsStream, this.profile.platformParser));
19845
+ log.info(`${stops.size} parsed stops.`);
19778
19846
  yield zip.close();
19779
19847
  return new StopsIndex(stops);
19780
19848
  });
@@ -20028,11 +20096,11 @@ class Result {
20028
20096
  let fastestDestination = undefined;
20029
20097
  let fastestTime = undefined;
20030
20098
  for (const destination of destinations) {
20031
- const arrivalTime = this.earliestArrivals.get(destination);
20099
+ const arrivalTime = this.earliestArrivals.get(destination.id);
20032
20100
  if (arrivalTime !== undefined) {
20033
20101
  if (fastestTime === undefined ||
20034
20102
  arrivalTime.time.toSeconds() < fastestTime.time.toSeconds()) {
20035
- fastestDestination = destination;
20103
+ fastestDestination = destination.id;
20036
20104
  fastestTime = arrivalTime;
20037
20105
  }
20038
20106
  }
@@ -20071,7 +20139,7 @@ class Result {
20071
20139
  this.earliestArrivalsPerRound[maxTransfers - 1]
20072
20140
  : this.earliestArrivals;
20073
20141
  for (const equivalentStop of equivalentStops) {
20074
- const arrivalTime = relevantArrivals.get(equivalentStop);
20142
+ const arrivalTime = relevantArrivals.get(equivalentStop.id);
20075
20143
  if (arrivalTime !== undefined) {
20076
20144
  if (earliestArrival === undefined ||
20077
20145
  arrivalTime.time.toSeconds() < earliestArrival.time.toSeconds()) {
@@ -20159,16 +20227,16 @@ class Router {
20159
20227
  // Stops that have been improved at round k-1
20160
20228
  const markedStops = new Set();
20161
20229
  for (const originStop of origins) {
20162
- markedStops.add(originStop);
20163
- earliestArrivals.set(originStop, {
20230
+ markedStops.add(originStop.id);
20231
+ earliestArrivals.set(originStop.id, {
20164
20232
  time: departureTime,
20165
20233
  legNumber: 0,
20166
- origin: originStop,
20234
+ origin: originStop.id,
20167
20235
  });
20168
- earliestArrivalsWithoutAnyLeg.set(originStop, {
20236
+ earliestArrivalsWithoutAnyLeg.set(originStop.id, {
20169
20237
  time: departureTime,
20170
20238
  legNumber: 0,
20171
- origin: originStop,
20239
+ origin: originStop.id,
20172
20240
  });
20173
20241
  }
20174
20242
  // on the first round we need to first consider transfers to discover all possible route origins
@@ -20186,12 +20254,14 @@ class Router {
20186
20254
  const route = this.timetable.getRoute(routeId);
20187
20255
  let currentTrip = undefined;
20188
20256
  const hopOnIndex = route.stopIndices.get(hopOnStop);
20189
- // for each stops in the route starting with the hop-on one
20257
+ // for each stop in the route starting with the hop-on one
20190
20258
  for (let i = hopOnIndex; i < route.stops.length; i++) {
20191
20259
  const currentStop = route.stops[i];
20192
20260
  const stopNumbers = route.stops.length;
20193
20261
  if (currentTrip !== undefined) {
20194
- const currentStopTimes = route.stopTimes[currentTrip.trip * stopNumbers + i];
20262
+ const currentArrivalIndex = (currentTrip.trip * stopNumbers + i) * 2;
20263
+ const currentArrivalTime = Time.fromSeconds(route.stopTimes[currentArrivalIndex]);
20264
+ const currentDropOffType = route.pickUpDropOffTypes[i * 2 + 1];
20195
20265
  const earliestArrivalAtCurrentStop = (_b = (_a = earliestArrivals.get(currentStop)) === null || _a === undefined ? undefined : _a.time) !== null && _b !== undefined ? _b : UNREACHED;
20196
20266
  let arrivalToImprove = earliestArrivalAtCurrentStop;
20197
20267
  if (destinations.length > 0) {
@@ -20199,31 +20269,31 @@ class Router {
20199
20269
  // if multiple destinations are specified, the target pruning
20200
20270
  // should compare to the earliest arrival at any of them
20201
20271
  for (const destinationStop of destinations) {
20202
- const earliestArrivalAtDestination = (_d = (_c = earliestArrivals.get(destinationStop)) === null || _c === undefined ? undefined : _c.time) !== null && _d !== undefined ? _d : UNREACHED;
20272
+ const earliestArrivalAtDestination = (_d = (_c = earliestArrivals.get(destinationStop.id)) === null || _c === undefined ? undefined : _c.time) !== null && _d !== undefined ? _d : UNREACHED;
20203
20273
  earliestArrivalsAtDestinations.push(earliestArrivalAtDestination);
20204
20274
  }
20205
20275
  const earliestArrivalAtDestination = Time.min(...earliestArrivalsAtDestinations);
20206
20276
  arrivalToImprove = Time.min(earliestArrivalAtCurrentStop, earliestArrivalAtDestination);
20207
20277
  }
20208
- if (currentStopTimes.dropOffType !== 'NOT_AVAILABLE' &&
20209
- currentStopTimes.arrival.toSeconds() <
20210
- arrivalToImprove.toSeconds()) {
20278
+ if (currentDropOffType !== NOT_AVAILABLE &&
20279
+ currentArrivalTime.toSeconds() < arrivalToImprove.toSeconds()) {
20211
20280
  const bestHopOnStopIndex = route.stopIndices.get(currentTrip.bestHopOnStop);
20212
- const bestHopOnStopTimes = route.stopTimes[currentTrip.trip * stopNumbers + bestHopOnStopIndex];
20281
+ const bestHopOnStopDepartureIndex = currentTrip.trip * stopNumbers * 2 + bestHopOnStopIndex * 2 + 1;
20282
+ const bestHopOnDepartureTime = Time.fromSeconds(route.stopTimes[bestHopOnStopDepartureIndex]);
20213
20283
  arrivalsAtCurrentRound.set(currentStop, {
20214
- time: currentStopTimes.arrival,
20284
+ time: currentArrivalTime,
20215
20285
  legNumber: round,
20216
20286
  origin: currentTrip.origin,
20217
20287
  leg: {
20218
20288
  from: this.stopsIndex.findStopById(currentTrip.bestHopOnStop),
20219
20289
  to: this.stopsIndex.findStopById(currentStop),
20220
- departureTime: bestHopOnStopTimes.departure,
20221
- arrivalTime: currentStopTimes.arrival,
20290
+ departureTime: bestHopOnDepartureTime,
20291
+ arrivalTime: currentArrivalTime,
20222
20292
  route: this.timetable.getServiceRoute(route.serviceRouteId),
20223
20293
  },
20224
20294
  });
20225
20295
  earliestArrivals.set(currentStop, {
20226
- time: currentStopTimes.arrival,
20296
+ time: currentArrivalTime,
20227
20297
  legNumber: round,
20228
20298
  origin: currentTrip.origin,
20229
20299
  });
@@ -20236,7 +20306,7 @@ class Router {
20236
20306
  if (earliestArrivalOnPreviousRound !== undefined &&
20237
20307
  (currentTrip === undefined ||
20238
20308
  earliestArrivalOnPreviousRound.toSeconds() <=
20239
- route.stopTimes[currentTrip.trip * stopNumbers + i].departure.toSeconds())) {
20309
+ route.stopTimes[(currentTrip.trip * stopNumbers + i) * 2])) {
20240
20310
  const earliestTrip = this.timetable.findEarliestTrip(route, currentStop, currentTrip === null || currentTrip === undefined ? undefined : currentTrip.trip, earliestArrivalOnPreviousRound);
20241
20311
  if (earliestTrip !== undefined) {
20242
20312
  currentTrip = {
@@ -20291,6 +20361,7 @@ const plotGraphToDotFile = (result, filePath) => {
20291
20361
  const startRepl = (stopsPath, timetablePath) => {
20292
20362
  const stopsIndex = StopsIndex.fromData(fs.readFileSync(stopsPath));
20293
20363
  const timetable = Timetable.fromData(fs.readFileSync(timetablePath));
20364
+ console.log(`Minotor Transit Router CLI`);
20294
20365
  console.log('Enter your stop (.find) or routing (.route) queries. Type ".exit" to quit.');
20295
20366
  const replServer = repl.start({
20296
20367
  prompt: 'minotor> ',
@@ -20334,9 +20405,10 @@ const startRepl = (stopsPath, timetablePath) => {
20334
20405
  this.displayPrompt();
20335
20406
  return;
20336
20407
  }
20337
- const fromStop = stopsIndex.findStopById(fromId) ||
20408
+ const fromStop = stopsIndex.findStopBySourceStopId(fromId) ||
20338
20409
  stopsIndex.findStopsByName(fromId)[0];
20339
- const toStop = stopsIndex.findStopById(toId) || stopsIndex.findStopsByName(toId)[0];
20410
+ const toStop = stopsIndex.findStopBySourceStopId(toId) ||
20411
+ stopsIndex.findStopsByName(toId)[0];
20340
20412
  if (!fromStop) {
20341
20413
  console.log(`No stop found for 'from' ID or name: ${fromId}`);
20342
20414
  this.displayPrompt();
@@ -20350,21 +20422,21 @@ const startRepl = (stopsPath, timetablePath) => {
20350
20422
  const departureTime = Time.fromString(atTime);
20351
20423
  try {
20352
20424
  const query = new Query.Builder()
20353
- .from(fromStop.id)
20354
- .to([toStop.id])
20425
+ .from(fromStop.sourceStopId)
20426
+ .to([toStop.sourceStopId])
20355
20427
  .departureTime(departureTime)
20356
20428
  .maxTransfers(maxTransfers)
20357
20429
  .build();
20358
20430
  const router = new Router(timetable, stopsIndex);
20359
20431
  const result = router.route(query);
20360
- const arrivalTime = result.arrivalAt(toStop.id);
20432
+ const arrivalTime = result.arrivalAt(toStop.sourceStopId);
20361
20433
  if (arrivalTime === undefined) {
20362
20434
  console.log(`Destination not reachable`);
20363
20435
  }
20364
20436
  else {
20365
20437
  console.log(`Arriving to ${toStop.name} at ${arrivalTime.time.toString()} with ${arrivalTime.legNumber - 1} transfers from ${(_a = stopsIndex.findStopById(arrivalTime.origin)) === null || _a === void 0 ? void 0 : _a.name}.`);
20366
20438
  }
20367
- const bestRoute = result.bestRoute(toStop.id);
20439
+ const bestRoute = result.bestRoute(toStop.sourceStopId);
20368
20440
  if (bestRoute) {
20369
20441
  console.log(`Found route from ${fromStop.name} to ${toStop.name}:`);
20370
20442
  prettyPrintRoute(bestRoute);
@@ -20411,9 +20483,10 @@ const startRepl = (stopsPath, timetablePath) => {
20411
20483
  this.displayPrompt();
20412
20484
  return;
20413
20485
  }
20414
- const fromStop = stopsIndex.findStopById(fromId) ||
20486
+ const fromStop = stopsIndex.findStopBySourceStopId(fromId) ||
20415
20487
  stopsIndex.findStopsByName(fromId)[0];
20416
- const toStop = stopsIndex.findStopById(toId) || stopsIndex.findStopsByName(toId)[0];
20488
+ const toStop = stopsIndex.findStopBySourceStopId(toId) ||
20489
+ stopsIndex.findStopsByName(toId)[0];
20417
20490
  if (!fromStop) {
20418
20491
  console.log(`No stop found for 'from' ID or name: ${fromId}`);
20419
20492
  this.displayPrompt();
@@ -20427,8 +20500,8 @@ const startRepl = (stopsPath, timetablePath) => {
20427
20500
  const departureTime = Time.fromString(atTime);
20428
20501
  try {
20429
20502
  const query = new Query.Builder()
20430
- .from(fromStop.id)
20431
- .to([toStop.id])
20503
+ .from(fromStop.sourceStopId)
20504
+ .to([toStop.sourceStopId])
20432
20505
  .departureTime(departureTime)
20433
20506
  .maxTransfers(maxTransfers)
20434
20507
  .build();