minotor 1.0.7 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +9 -3
  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 -4
  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
@@ -9666,7 +9666,6 @@ var StreamZip = /*@__PURE__*/getDefaultExportFromCjs(node_stream_zipExports);
9666
9666
  // of the input file used when generating it. This code is not
9667
9667
  // standalone and requires a support library to be linked with it. This
9668
9668
  // support library is itself covered by the above license.
9669
- /* eslint-disable prefer-const,@typescript-eslint/restrict-plus-operands */
9670
9669
  /**
9671
9670
  * Read a 64 bit varint as two JS numbers.
9672
9671
  *
@@ -9949,7 +9948,7 @@ function varint32read() {
9949
9948
  return result >>> 0;
9950
9949
  }
9951
9950
 
9952
- // Copyright 2021-2024 Buf Technologies, Inc.
9951
+ // Copyright 2021-2025 Buf Technologies, Inc.
9953
9952
  //
9954
9953
  // Licensed under the Apache License, Version 2.0 (the "License");
9955
9954
  // you may not use this file except in compliance with the License.
@@ -9978,7 +9977,10 @@ function makeInt64Support() {
9978
9977
  typeof process.env != "object" ||
9979
9978
  process.env.BUF_BIGINT_DISABLE !== "1");
9980
9979
  if (ok) {
9981
- const MIN = BigInt("-9223372036854775808"), MAX = BigInt("9223372036854775807"), UMIN = BigInt("0"), UMAX = BigInt("18446744073709551615");
9980
+ const MIN = BigInt("-9223372036854775808");
9981
+ const MAX = BigInt("9223372036854775807");
9982
+ const UMIN = BigInt("0");
9983
+ const UMAX = BigInt("18446744073709551615");
9982
9984
  return {
9983
9985
  zero: BigInt(0),
9984
9986
  supported: true,
@@ -10072,7 +10074,7 @@ function assertUInt64String(value) {
10072
10074
  }
10073
10075
  }
10074
10076
 
10075
- // Copyright 2021-2024 Buf Technologies, Inc.
10077
+ // Copyright 2021-2025 Buf Technologies, Inc.
10076
10078
  //
10077
10079
  // Licensed under the Apache License, Version 2.0 (the "License");
10078
10080
  // you may not use this file except in compliance with the License.
@@ -10102,7 +10104,7 @@ function getTextEncoding() {
10102
10104
  encodeURIComponent(text);
10103
10105
  return true;
10104
10106
  }
10105
- catch (e) {
10107
+ catch (_) {
10106
10108
  return false;
10107
10109
  }
10108
10110
  },
@@ -10111,7 +10113,7 @@ function getTextEncoding() {
10111
10113
  return globalThis[symbol];
10112
10114
  }
10113
10115
 
10114
- // Copyright 2021-2024 Buf Technologies, Inc.
10116
+ // Copyright 2021-2025 Buf Technologies, Inc.
10115
10117
  //
10116
10118
  // Licensed under the Apache License, Version 2.0 (the "License");
10117
10119
  // you may not use this file except in compliance with the License.
@@ -10124,7 +10126,6 @@ function getTextEncoding() {
10124
10126
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10125
10127
  // See the License for the specific language governing permissions and
10126
10128
  // limitations under the License.
10127
- /* eslint-disable prefer-const,no-case-declarations,@typescript-eslint/restrict-plus-operands */
10128
10129
  /**
10129
10130
  * Protobuf binary format wire types.
10130
10131
  *
@@ -10385,7 +10386,7 @@ class BinaryWriter {
10385
10386
  * Write a `sint64` value, a signed, zig-zag-encoded 64-bit varint.
10386
10387
  */
10387
10388
  sint64(value) {
10388
- let tc = protoInt64.enc(value),
10389
+ const tc = protoInt64.enc(value),
10389
10390
  // zigzag encode
10390
10391
  sign = tc.hi >> 31, lo = (tc.lo << 1) ^ sign, hi = ((tc.hi << 1) | (tc.lo >>> 31)) ^ sign;
10391
10392
  varint64write(lo, hi, this.buf);
@@ -10395,7 +10396,7 @@ class BinaryWriter {
10395
10396
  * Write a `uint64` value, an unsigned 64-bit varint.
10396
10397
  */
10397
10398
  uint64(value) {
10398
- let tc = protoInt64.uEnc(value);
10399
+ const tc = protoInt64.uEnc(value);
10399
10400
  varint64write(tc.lo, tc.hi, this.buf);
10400
10401
  return this;
10401
10402
  }
@@ -10436,11 +10437,9 @@ class BinaryReader {
10436
10437
  // ignore
10437
10438
  }
10438
10439
  break;
10439
- // eslint-disable-next-line
10440
10440
  // @ts-expect-error TS7029: Fallthrough case in switch
10441
10441
  case WireType.Bit64:
10442
10442
  this.pos += 4;
10443
- // eslint-disable-next-line no-fallthrough
10444
10443
  case WireType.Bit32:
10445
10444
  this.pos += 4;
10446
10445
  break;
@@ -10521,12 +10520,14 @@ class BinaryReader {
10521
10520
  * Read a `fixed32` field, an unsigned, fixed-length 32-bit integer.
10522
10521
  */
10523
10522
  fixed32() {
10523
+ // biome-ignore lint/suspicious/noAssignInExpressions: no
10524
10524
  return this.view.getUint32((this.pos += 4) - 4, true);
10525
10525
  }
10526
10526
  /**
10527
10527
  * Read a `sfixed32` field, a signed, fixed-length 32-bit integer.
10528
10528
  */
10529
10529
  sfixed32() {
10530
+ // biome-ignore lint/suspicious/noAssignInExpressions: no
10530
10531
  return this.view.getInt32((this.pos += 4) - 4, true);
10531
10532
  }
10532
10533
  /**
@@ -10545,12 +10546,14 @@ class BinaryReader {
10545
10546
  * Read a `float` field, 32-bit floating point number.
10546
10547
  */
10547
10548
  float() {
10549
+ // biome-ignore lint/suspicious/noAssignInExpressions: no
10548
10550
  return this.view.getFloat32((this.pos += 4) - 4, true);
10549
10551
  }
10550
10552
  /**
10551
10553
  * Read a `double` field, a 64-bit floating point number.
10552
10554
  */
10553
10555
  double() {
10556
+ // biome-ignore lint/suspicious/noAssignInExpressions: no
10554
10557
  return this.view.getFloat64((this.pos += 8) - 8, true);
10555
10558
  }
10556
10559
  /**
@@ -10606,7 +10609,7 @@ function assertFloat32(arg) {
10606
10609
  if (typeof arg == "string") {
10607
10610
  const o = arg;
10608
10611
  arg = Number(arg);
10609
- if (isNaN(arg) && o !== "NaN") {
10612
+ if (Number.isNaN(arg) && o !== "NaN") {
10610
10613
  throw new Error("invalid float32: " + o);
10611
10614
  }
10612
10615
  }
@@ -11281,6 +11284,7 @@ function locationTypeToJSON(object) {
11281
11284
  function createBaseStop() {
11282
11285
  return {
11283
11286
  name: "",
11287
+ sourceStopId: "",
11284
11288
  lat: undefined,
11285
11289
  lon: undefined,
11286
11290
  children: [],
@@ -11294,23 +11298,28 @@ const Stop = {
11294
11298
  if (message.name !== "") {
11295
11299
  writer.uint32(10).string(message.name);
11296
11300
  }
11301
+ if (message.sourceStopId !== "") {
11302
+ writer.uint32(18).string(message.sourceStopId);
11303
+ }
11297
11304
  if (message.lat !== undefined) {
11298
- writer.uint32(17).double(message.lat);
11305
+ writer.uint32(25).double(message.lat);
11299
11306
  }
11300
11307
  if (message.lon !== undefined) {
11301
- writer.uint32(25).double(message.lon);
11308
+ writer.uint32(33).double(message.lon);
11302
11309
  }
11310
+ writer.uint32(42).fork();
11303
11311
  for (const v of message.children) {
11304
- writer.uint32(34).string(v);
11312
+ writer.uint32(v);
11305
11313
  }
11314
+ writer.join();
11306
11315
  if (message.parent !== undefined) {
11307
- writer.uint32(42).string(message.parent);
11316
+ writer.uint32(48).uint32(message.parent);
11308
11317
  }
11309
11318
  if (message.locationType !== 0) {
11310
- writer.uint32(48).int32(message.locationType);
11319
+ writer.uint32(56).int32(message.locationType);
11311
11320
  }
11312
11321
  if (message.platform !== undefined) {
11313
- writer.uint32(58).string(message.platform);
11322
+ writer.uint32(66).string(message.platform);
11314
11323
  }
11315
11324
  return writer;
11316
11325
  },
@@ -11329,42 +11338,56 @@ const Stop = {
11329
11338
  continue;
11330
11339
  }
11331
11340
  case 2: {
11332
- if (tag !== 17) {
11341
+ if (tag !== 18) {
11333
11342
  break;
11334
11343
  }
11335
- message.lat = reader.double();
11344
+ message.sourceStopId = reader.string();
11336
11345
  continue;
11337
11346
  }
11338
11347
  case 3: {
11339
11348
  if (tag !== 25) {
11340
11349
  break;
11341
11350
  }
11342
- message.lon = reader.double();
11351
+ message.lat = reader.double();
11343
11352
  continue;
11344
11353
  }
11345
11354
  case 4: {
11346
- if (tag !== 34) {
11355
+ if (tag !== 33) {
11347
11356
  break;
11348
11357
  }
11349
- message.children.push(reader.string());
11358
+ message.lon = reader.double();
11350
11359
  continue;
11351
11360
  }
11352
11361
  case 5: {
11353
- if (tag !== 42) {
11354
- break;
11362
+ if (tag === 40) {
11363
+ message.children.push(reader.uint32());
11364
+ continue;
11355
11365
  }
11356
- message.parent = reader.string();
11357
- continue;
11366
+ if (tag === 42) {
11367
+ const end2 = reader.uint32() + reader.pos;
11368
+ while (reader.pos < end2) {
11369
+ message.children.push(reader.uint32());
11370
+ }
11371
+ continue;
11372
+ }
11373
+ break;
11358
11374
  }
11359
11375
  case 6: {
11360
11376
  if (tag !== 48) {
11361
11377
  break;
11362
11378
  }
11363
- message.locationType = reader.int32();
11379
+ message.parent = reader.uint32();
11364
11380
  continue;
11365
11381
  }
11366
11382
  case 7: {
11367
- if (tag !== 58) {
11383
+ if (tag !== 56) {
11384
+ break;
11385
+ }
11386
+ message.locationType = reader.int32();
11387
+ continue;
11388
+ }
11389
+ case 8: {
11390
+ if (tag !== 66) {
11368
11391
  break;
11369
11392
  }
11370
11393
  message.platform = reader.string();
@@ -11381,10 +11404,11 @@ const Stop = {
11381
11404
  fromJSON(object) {
11382
11405
  return {
11383
11406
  name: isSet$1(object.name) ? globalThis.String(object.name) : "",
11407
+ sourceStopId: isSet$1(object.sourceStopId) ? globalThis.String(object.sourceStopId) : "",
11384
11408
  lat: isSet$1(object.lat) ? globalThis.Number(object.lat) : undefined,
11385
11409
  lon: isSet$1(object.lon) ? globalThis.Number(object.lon) : undefined,
11386
- children: globalThis.Array.isArray(object === null || object === undefined ? undefined : object.children) ? object.children.map((e) => globalThis.String(e)) : [],
11387
- parent: isSet$1(object.parent) ? globalThis.String(object.parent) : undefined,
11410
+ children: globalThis.Array.isArray(object === null || object === undefined ? undefined : object.children) ? object.children.map((e) => globalThis.Number(e)) : [],
11411
+ parent: isSet$1(object.parent) ? globalThis.Number(object.parent) : undefined,
11388
11412
  locationType: isSet$1(object.locationType) ? locationTypeFromJSON(object.locationType) : 0,
11389
11413
  platform: isSet$1(object.platform) ? globalThis.String(object.platform) : undefined,
11390
11414
  };
@@ -11395,6 +11419,9 @@ const Stop = {
11395
11419
  if (message.name !== "") {
11396
11420
  obj.name = message.name;
11397
11421
  }
11422
+ if (message.sourceStopId !== "") {
11423
+ obj.sourceStopId = message.sourceStopId;
11424
+ }
11398
11425
  if (message.lat !== undefined) {
11399
11426
  obj.lat = message.lat;
11400
11427
  }
@@ -11402,10 +11429,10 @@ const Stop = {
11402
11429
  obj.lon = message.lon;
11403
11430
  }
11404
11431
  if ((_a = message.children) === null || _a === undefined ? undefined : _a.length) {
11405
- obj.children = message.children;
11432
+ obj.children = message.children.map((e) => Math.round(e));
11406
11433
  }
11407
11434
  if (message.parent !== undefined) {
11408
- obj.parent = message.parent;
11435
+ obj.parent = Math.round(message.parent);
11409
11436
  }
11410
11437
  if (message.locationType !== 0) {
11411
11438
  obj.locationType = locationTypeToJSON(message.locationType);
@@ -11419,15 +11446,16 @@ const Stop = {
11419
11446
  return Stop.fromPartial(base !== null && base !== undefined ? base : {});
11420
11447
  },
11421
11448
  fromPartial(object) {
11422
- var _a, _b, _c, _d, _e, _f, _g;
11449
+ var _a, _b, _c, _d, _e, _f, _g, _h;
11423
11450
  const message = createBaseStop();
11424
11451
  message.name = (_a = object.name) !== null && _a !== undefined ? _a : "";
11425
- message.lat = (_b = object.lat) !== null && _b !== undefined ? _b : undefined;
11426
- message.lon = (_c = object.lon) !== null && _c !== undefined ? _c : undefined;
11427
- message.children = ((_d = object.children) === null || _d === undefined ? undefined : _d.map((e) => e)) || [];
11428
- message.parent = (_e = object.parent) !== null && _e !== undefined ? _e : undefined;
11429
- message.locationType = (_f = object.locationType) !== null && _f !== undefined ? _f : 0;
11430
- message.platform = (_g = object.platform) !== null && _g !== undefined ? _g : undefined;
11452
+ message.sourceStopId = (_b = object.sourceStopId) !== null && _b !== undefined ? _b : "";
11453
+ message.lat = (_c = object.lat) !== null && _c !== undefined ? _c : undefined;
11454
+ message.lon = (_d = object.lon) !== null && _d !== undefined ? _d : undefined;
11455
+ message.children = ((_e = object.children) === null || _e === undefined ? undefined : _e.map((e) => e)) || [];
11456
+ message.parent = (_f = object.parent) !== null && _f !== undefined ? _f : undefined;
11457
+ message.locationType = (_g = object.locationType) !== null && _g !== undefined ? _g : 0;
11458
+ message.platform = (_h = object.platform) !== null && _h !== undefined ? _h : undefined;
11431
11459
  return message;
11432
11460
  },
11433
11461
  };
@@ -11481,7 +11509,7 @@ const StopsMap = {
11481
11509
  version: isSet$1(object.version) ? globalThis.String(object.version) : "",
11482
11510
  stops: isObject$1(object.stops)
11483
11511
  ? Object.entries(object.stops).reduce((acc, [key, value]) => {
11484
- acc[key] = Stop.fromJSON(value);
11512
+ acc[globalThis.Number(key)] = Stop.fromJSON(value);
11485
11513
  return acc;
11486
11514
  }, {})
11487
11515
  : {},
@@ -11512,7 +11540,7 @@ const StopsMap = {
11512
11540
  message.version = (_a = object.version) !== null && _a !== undefined ? _a : "";
11513
11541
  message.stops = Object.entries((_b = object.stops) !== null && _b !== undefined ? _b : {}).reduce((acc, [key, value]) => {
11514
11542
  if (value !== undefined) {
11515
- acc[key] = Stop.fromPartial(value);
11543
+ acc[globalThis.Number(key)] = Stop.fromPartial(value);
11516
11544
  }
11517
11545
  return acc;
11518
11546
  }, {});
@@ -11520,12 +11548,12 @@ const StopsMap = {
11520
11548
  },
11521
11549
  };
11522
11550
  function createBaseStopsMap_StopsEntry() {
11523
- return { key: "", value: undefined };
11551
+ return { key: 0, value: undefined };
11524
11552
  }
11525
11553
  const StopsMap_StopsEntry = {
11526
11554
  encode(message, writer = new BinaryWriter()) {
11527
- if (message.key !== "") {
11528
- writer.uint32(10).string(message.key);
11555
+ if (message.key !== 0) {
11556
+ writer.uint32(8).uint32(message.key);
11529
11557
  }
11530
11558
  if (message.value !== undefined) {
11531
11559
  Stop.encode(message.value, writer.uint32(18).fork()).join();
@@ -11540,10 +11568,10 @@ const StopsMap_StopsEntry = {
11540
11568
  const tag = reader.uint32();
11541
11569
  switch (tag >>> 3) {
11542
11570
  case 1: {
11543
- if (tag !== 10) {
11571
+ if (tag !== 8) {
11544
11572
  break;
11545
11573
  }
11546
- message.key = reader.string();
11574
+ message.key = reader.uint32();
11547
11575
  continue;
11548
11576
  }
11549
11577
  case 2: {
@@ -11563,14 +11591,14 @@ const StopsMap_StopsEntry = {
11563
11591
  },
11564
11592
  fromJSON(object) {
11565
11593
  return {
11566
- key: isSet$1(object.key) ? globalThis.String(object.key) : "",
11594
+ key: isSet$1(object.key) ? globalThis.Number(object.key) : 0,
11567
11595
  value: isSet$1(object.value) ? Stop.fromJSON(object.value) : undefined,
11568
11596
  };
11569
11597
  },
11570
11598
  toJSON(message) {
11571
11599
  const obj = {};
11572
- if (message.key !== "") {
11573
- obj.key = message.key;
11600
+ if (message.key !== 0) {
11601
+ obj.key = Math.round(message.key);
11574
11602
  }
11575
11603
  if (message.value !== undefined) {
11576
11604
  obj.value = Stop.toJSON(message.value);
@@ -11583,7 +11611,7 @@ const StopsMap_StopsEntry = {
11583
11611
  fromPartial(object) {
11584
11612
  var _a;
11585
11613
  const message = createBaseStopsMap_StopsEntry();
11586
- message.key = (_a = object.key) !== null && _a !== undefined ? _a : "";
11614
+ message.key = (_a = object.key) !== null && _a !== undefined ? _a : 0;
11587
11615
  message.value = (object.value !== undefined && object.value !== null) ? Stop.fromPartial(object.value) : undefined;
11588
11616
  return message;
11589
11617
  },
@@ -11595,10 +11623,11 @@ function isSet$1(value) {
11595
11623
  return value !== null && value !== undefined;
11596
11624
  }
11597
11625
 
11598
- const CURRENT_VERSION$1 = '0.0.1';
11626
+ const CURRENT_VERSION$1 = '0.0.2';
11599
11627
  const serializeStop = (stop) => {
11600
11628
  return {
11601
11629
  name: stop.name,
11630
+ sourceStopId: stop.sourceStopId,
11602
11631
  lat: stop.lat,
11603
11632
  lon: stop.lon,
11604
11633
  children: stop.children,
@@ -11620,6 +11649,7 @@ const serializeStopsMap = (stopsMap) => {
11620
11649
  const deserializeStop = (stopId, protoStop) => {
11621
11650
  return {
11622
11651
  id: stopId,
11652
+ sourceStopId: protoStop.sourceStopId,
11623
11653
  name: protoStop.name,
11624
11654
  lat: protoStop.lat,
11625
11655
  lon: protoStop.lon,
@@ -11635,7 +11665,8 @@ const deserializeStopsMap = (protoStopsMap) => {
11635
11665
  }
11636
11666
  const stopsMap = new Map();
11637
11667
  Object.entries(protoStopsMap.stops).forEach(([key, value]) => {
11638
- stopsMap.set(key, deserializeStop(key, value));
11668
+ const intKey = parseInt(key, 10);
11669
+ stopsMap.set(intKey, deserializeStop(intKey, value));
11639
11670
  });
11640
11671
  return stopsMap;
11641
11672
  };
@@ -11679,6 +11710,10 @@ class StopsIndex {
11679
11710
  constructor(stopsMap) {
11680
11711
  var _a;
11681
11712
  this.stopsMap = stopsMap;
11713
+ this.sourceStopsMap = new Map();
11714
+ for (const [id, stop] of stopsMap.entries()) {
11715
+ this.sourceStopsMap.set(stop.sourceStopId, id);
11716
+ }
11682
11717
  this.textIndex = lt({
11683
11718
  fields: ['name'],
11684
11719
  storeFields: ['id'],
@@ -11737,6 +11772,14 @@ class StopsIndex {
11737
11772
  StopsMap.encode(protoStopsMap, writer);
11738
11773
  return writer.finish();
11739
11774
  }
11775
+ /**
11776
+ * Returns the number of stops in the index.
11777
+ *
11778
+ * @returns The total number of stops.
11779
+ */
11780
+ size() {
11781
+ return this.stopsMap.size;
11782
+ }
11740
11783
  /**
11741
11784
  * Finds stops by their name using a text search.
11742
11785
  *
@@ -11765,16 +11808,36 @@ class StopsIndex {
11765
11808
  return nearestStops;
11766
11809
  }
11767
11810
  /**
11768
- * Finds a stop by its ID.
11811
+ * Finds a stop by its internal ID.
11769
11812
  *
11770
- * @param id - The ID of the stop to search for.
11813
+ * @param id - The internal ID of the stop to search for.
11771
11814
  * @returns The Stop object that matches the specified ID, or undefined if not found.
11772
11815
  */
11773
11816
  findStopById(id) {
11774
11817
  return this.stopsMap.get(id);
11775
11818
  }
11776
- equivalentStops(id) {
11819
+ /**
11820
+ * Finds a stop by its ID in the transit data source (e.g. GTFS).
11821
+ *
11822
+ * @param id - The source ID of the stop to search for.
11823
+ * @returns The Stop object that matches the specified ID, or undefined if not found.
11824
+ */
11825
+ findStopBySourceStopId(sourceStopId) {
11826
+ const stopId = this.sourceStopsMap.get(sourceStopId);
11827
+ if (stopId === undefined) {
11828
+ return;
11829
+ }
11830
+ return this.findStopById(stopId);
11831
+ }
11832
+ /**
11833
+ * Find ids of all sibling stops.
11834
+ */
11835
+ equivalentStops(sourceId) {
11777
11836
  var _a, _b;
11837
+ const id = this.sourceStopsMap.get(sourceId);
11838
+ if (id === undefined) {
11839
+ return [];
11840
+ }
11778
11841
  const stop = this.stopsMap.get(id);
11779
11842
  if (!stop) {
11780
11843
  return [];
@@ -11782,7 +11845,7 @@ class StopsIndex {
11782
11845
  const equivalentStops = stop.parent
11783
11846
  ? ((_b = (_a = this.stopsMap.get(stop.parent)) === null || _a === undefined ? undefined : _a.children) !== null && _b !== undefined ? _b : [])
11784
11847
  : stop.children;
11785
- return Array.from(new Set([id, ...equivalentStops]));
11848
+ return Array.from(new Set([id, ...equivalentStops])).map((stopId) => this.stopsMap.get(stopId));
11786
11849
  }
11787
11850
  }
11788
11851
 
@@ -11873,43 +11936,6 @@ class Duration {
11873
11936
  // protoc v4.23.4
11874
11937
  // source: src/timetable/proto/timetable.proto
11875
11938
  /* eslint-disable */
11876
- var PickUpDropOffType;
11877
- (function (PickUpDropOffType) {
11878
- PickUpDropOffType[PickUpDropOffType["NOT_AVAILABLE"] = 0] = "NOT_AVAILABLE";
11879
- PickUpDropOffType[PickUpDropOffType["MUST_PHONE_AGENCY"] = 1] = "MUST_PHONE_AGENCY";
11880
- PickUpDropOffType[PickUpDropOffType["MUST_COORDINATE_WITH_DRIVER"] = 2] = "MUST_COORDINATE_WITH_DRIVER";
11881
- PickUpDropOffType[PickUpDropOffType["UNRECOGNIZED"] = -1] = "UNRECOGNIZED";
11882
- })(PickUpDropOffType || (PickUpDropOffType = {}));
11883
- function pickUpDropOffTypeFromJSON(object) {
11884
- switch (object) {
11885
- case 0:
11886
- case "NOT_AVAILABLE":
11887
- return PickUpDropOffType.NOT_AVAILABLE;
11888
- case 1:
11889
- case "MUST_PHONE_AGENCY":
11890
- return PickUpDropOffType.MUST_PHONE_AGENCY;
11891
- case 2:
11892
- case "MUST_COORDINATE_WITH_DRIVER":
11893
- return PickUpDropOffType.MUST_COORDINATE_WITH_DRIVER;
11894
- case -1:
11895
- case "UNRECOGNIZED":
11896
- default:
11897
- return PickUpDropOffType.UNRECOGNIZED;
11898
- }
11899
- }
11900
- function pickUpDropOffTypeToJSON(object) {
11901
- switch (object) {
11902
- case PickUpDropOffType.NOT_AVAILABLE:
11903
- return "NOT_AVAILABLE";
11904
- case PickUpDropOffType.MUST_PHONE_AGENCY:
11905
- return "MUST_PHONE_AGENCY";
11906
- case PickUpDropOffType.MUST_COORDINATE_WITH_DRIVER:
11907
- return "MUST_COORDINATE_WITH_DRIVER";
11908
- case PickUpDropOffType.UNRECOGNIZED:
11909
- default:
11910
- return "UNRECOGNIZED";
11911
- }
11912
- }
11913
11939
  var TransferType;
11914
11940
  (function (TransferType) {
11915
11941
  TransferType[TransferType["RECOMMENDED_TRANSFER_POINT"] = 0] = "RECOMMENDED_TRANSFER_POINT";
@@ -12032,118 +12058,27 @@ function routeTypeToJSON(object) {
12032
12058
  return "UNRECOGNIZED";
12033
12059
  }
12034
12060
  }
12035
- function createBaseStopTimes() {
12036
- return { arrival: 0, departure: 0, pickUpType: undefined, dropOffType: undefined };
12037
- }
12038
- const StopTimes = {
12039
- encode(message, writer = new BinaryWriter()) {
12040
- if (message.arrival !== 0) {
12041
- writer.uint32(8).int32(message.arrival);
12042
- }
12043
- if (message.departure !== 0) {
12044
- writer.uint32(16).int32(message.departure);
12045
- }
12046
- if (message.pickUpType !== undefined) {
12047
- writer.uint32(24).int32(message.pickUpType);
12048
- }
12049
- if (message.dropOffType !== undefined) {
12050
- writer.uint32(32).int32(message.dropOffType);
12051
- }
12052
- return writer;
12053
- },
12054
- decode(input, length) {
12055
- const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
12056
- let end = length === undefined ? reader.len : reader.pos + length;
12057
- const message = createBaseStopTimes();
12058
- while (reader.pos < end) {
12059
- const tag = reader.uint32();
12060
- switch (tag >>> 3) {
12061
- case 1: {
12062
- if (tag !== 8) {
12063
- break;
12064
- }
12065
- message.arrival = reader.int32();
12066
- continue;
12067
- }
12068
- case 2: {
12069
- if (tag !== 16) {
12070
- break;
12071
- }
12072
- message.departure = reader.int32();
12073
- continue;
12074
- }
12075
- case 3: {
12076
- if (tag !== 24) {
12077
- break;
12078
- }
12079
- message.pickUpType = reader.int32();
12080
- continue;
12081
- }
12082
- case 4: {
12083
- if (tag !== 32) {
12084
- break;
12085
- }
12086
- message.dropOffType = reader.int32();
12087
- continue;
12088
- }
12089
- }
12090
- if ((tag & 7) === 4 || tag === 0) {
12091
- break;
12092
- }
12093
- reader.skip(tag & 7);
12094
- }
12095
- return message;
12096
- },
12097
- fromJSON(object) {
12098
- return {
12099
- arrival: isSet(object.arrival) ? globalThis.Number(object.arrival) : 0,
12100
- departure: isSet(object.departure) ? globalThis.Number(object.departure) : 0,
12101
- pickUpType: isSet(object.pickUpType) ? pickUpDropOffTypeFromJSON(object.pickUpType) : undefined,
12102
- dropOffType: isSet(object.dropOffType) ? pickUpDropOffTypeFromJSON(object.dropOffType) : undefined,
12103
- };
12104
- },
12105
- toJSON(message) {
12106
- const obj = {};
12107
- if (message.arrival !== 0) {
12108
- obj.arrival = Math.round(message.arrival);
12109
- }
12110
- if (message.departure !== 0) {
12111
- obj.departure = Math.round(message.departure);
12112
- }
12113
- if (message.pickUpType !== undefined) {
12114
- obj.pickUpType = pickUpDropOffTypeToJSON(message.pickUpType);
12115
- }
12116
- if (message.dropOffType !== undefined) {
12117
- obj.dropOffType = pickUpDropOffTypeToJSON(message.dropOffType);
12118
- }
12119
- return obj;
12120
- },
12121
- create(base) {
12122
- return StopTimes.fromPartial(base !== null && base !== undefined ? base : {});
12123
- },
12124
- fromPartial(object) {
12125
- var _a, _b, _c, _d;
12126
- const message = createBaseStopTimes();
12127
- message.arrival = (_a = object.arrival) !== null && _a !== undefined ? _a : 0;
12128
- message.departure = (_b = object.departure) !== null && _b !== undefined ? _b : 0;
12129
- message.pickUpType = (_c = object.pickUpType) !== null && _c !== undefined ? _c : undefined;
12130
- message.dropOffType = (_d = object.dropOffType) !== null && _d !== undefined ? _d : undefined;
12131
- return message;
12132
- },
12133
- };
12134
12061
  function createBaseRoute() {
12135
- return { stopTimes: [], stops: [], serviceRouteId: "" };
12062
+ return {
12063
+ stopTimes: new Uint8Array(0),
12064
+ pickUpDropOffTypes: new Uint8Array(0),
12065
+ stops: new Uint8Array(0),
12066
+ serviceRouteId: "",
12067
+ };
12136
12068
  }
12137
12069
  const Route = {
12138
12070
  encode(message, writer = new BinaryWriter()) {
12139
- for (const v of message.stopTimes) {
12140
- StopTimes.encode(v, writer.uint32(10).fork()).join();
12071
+ if (message.stopTimes.length !== 0) {
12072
+ writer.uint32(10).bytes(message.stopTimes);
12141
12073
  }
12142
- for (const v of message.stops) {
12143
- writer.uint32(18).string(v);
12074
+ if (message.pickUpDropOffTypes.length !== 0) {
12075
+ writer.uint32(18).bytes(message.pickUpDropOffTypes);
12076
+ }
12077
+ if (message.stops.length !== 0) {
12078
+ writer.uint32(26).bytes(message.stops);
12144
12079
  }
12145
12080
  if (message.serviceRouteId !== "") {
12146
- writer.uint32(26).string(message.serviceRouteId);
12081
+ writer.uint32(34).string(message.serviceRouteId);
12147
12082
  }
12148
12083
  return writer;
12149
12084
  },
@@ -12158,20 +12093,27 @@ const Route = {
12158
12093
  if (tag !== 10) {
12159
12094
  break;
12160
12095
  }
12161
- message.stopTimes.push(StopTimes.decode(reader, reader.uint32()));
12096
+ message.stopTimes = reader.bytes();
12162
12097
  continue;
12163
12098
  }
12164
12099
  case 2: {
12165
12100
  if (tag !== 18) {
12166
12101
  break;
12167
12102
  }
12168
- message.stops.push(reader.string());
12103
+ message.pickUpDropOffTypes = reader.bytes();
12169
12104
  continue;
12170
12105
  }
12171
12106
  case 3: {
12172
12107
  if (tag !== 26) {
12173
12108
  break;
12174
12109
  }
12110
+ message.stops = reader.bytes();
12111
+ continue;
12112
+ }
12113
+ case 4: {
12114
+ if (tag !== 34) {
12115
+ break;
12116
+ }
12175
12117
  message.serviceRouteId = reader.string();
12176
12118
  continue;
12177
12119
  }
@@ -12185,21 +12127,24 @@ const Route = {
12185
12127
  },
12186
12128
  fromJSON(object) {
12187
12129
  return {
12188
- stopTimes: globalThis.Array.isArray(object === null || object === undefined ? undefined : object.stopTimes)
12189
- ? object.stopTimes.map((e) => StopTimes.fromJSON(e))
12190
- : [],
12191
- stops: globalThis.Array.isArray(object === null || object === undefined ? undefined : object.stops) ? object.stops.map((e) => globalThis.String(e)) : [],
12130
+ stopTimes: isSet(object.stopTimes) ? bytesFromBase64(object.stopTimes) : new Uint8Array(0),
12131
+ pickUpDropOffTypes: isSet(object.pickUpDropOffTypes)
12132
+ ? bytesFromBase64(object.pickUpDropOffTypes)
12133
+ : new Uint8Array(0),
12134
+ stops: isSet(object.stops) ? bytesFromBase64(object.stops) : new Uint8Array(0),
12192
12135
  serviceRouteId: isSet(object.serviceRouteId) ? globalThis.String(object.serviceRouteId) : "",
12193
12136
  };
12194
12137
  },
12195
12138
  toJSON(message) {
12196
- var _a, _b;
12197
12139
  const obj = {};
12198
- if ((_a = message.stopTimes) === null || _a === undefined ? undefined : _a.length) {
12199
- obj.stopTimes = message.stopTimes.map((e) => StopTimes.toJSON(e));
12140
+ if (message.stopTimes.length !== 0) {
12141
+ obj.stopTimes = base64FromBytes(message.stopTimes);
12142
+ }
12143
+ if (message.pickUpDropOffTypes.length !== 0) {
12144
+ obj.pickUpDropOffTypes = base64FromBytes(message.pickUpDropOffTypes);
12200
12145
  }
12201
- if ((_b = message.stops) === null || _b === undefined ? undefined : _b.length) {
12202
- obj.stops = message.stops;
12146
+ if (message.stops.length !== 0) {
12147
+ obj.stops = base64FromBytes(message.stops);
12203
12148
  }
12204
12149
  if (message.serviceRouteId !== "") {
12205
12150
  obj.serviceRouteId = message.serviceRouteId;
@@ -12210,11 +12155,12 @@ const Route = {
12210
12155
  return Route.fromPartial(base !== null && base !== undefined ? base : {});
12211
12156
  },
12212
12157
  fromPartial(object) {
12213
- var _a, _b, _c;
12158
+ var _a, _b, _c, _d;
12214
12159
  const message = createBaseRoute();
12215
- message.stopTimes = ((_a = object.stopTimes) === null || _a === undefined ? undefined : _a.map((e) => StopTimes.fromPartial(e))) || [];
12216
- message.stops = ((_b = object.stops) === null || _b === undefined ? undefined : _b.map((e) => e)) || [];
12217
- message.serviceRouteId = (_c = object.serviceRouteId) !== null && _c !== undefined ? _c : "";
12160
+ message.stopTimes = (_a = object.stopTimes) !== null && _a !== undefined ? _a : new Uint8Array(0);
12161
+ message.pickUpDropOffTypes = (_b = object.pickUpDropOffTypes) !== null && _b !== undefined ? _b : new Uint8Array(0);
12162
+ message.stops = (_c = object.stops) !== null && _c !== undefined ? _c : new Uint8Array(0);
12163
+ message.serviceRouteId = (_d = object.serviceRouteId) !== null && _d !== undefined ? _d : "";
12218
12164
  return message;
12219
12165
  },
12220
12166
  };
@@ -12361,12 +12307,12 @@ const RoutesAdjacency_RoutesEntry = {
12361
12307
  },
12362
12308
  };
12363
12309
  function createBaseTransfer() {
12364
- return { destination: "", type: 0, minTransferTime: undefined };
12310
+ return { destination: 0, type: 0, minTransferTime: undefined };
12365
12311
  }
12366
12312
  const Transfer = {
12367
12313
  encode(message, writer = new BinaryWriter()) {
12368
- if (message.destination !== "") {
12369
- writer.uint32(10).string(message.destination);
12314
+ if (message.destination !== 0) {
12315
+ writer.uint32(8).uint32(message.destination);
12370
12316
  }
12371
12317
  if (message.type !== 0) {
12372
12318
  writer.uint32(16).int32(message.type);
@@ -12384,10 +12330,10 @@ const Transfer = {
12384
12330
  const tag = reader.uint32();
12385
12331
  switch (tag >>> 3) {
12386
12332
  case 1: {
12387
- if (tag !== 10) {
12333
+ if (tag !== 8) {
12388
12334
  break;
12389
12335
  }
12390
- message.destination = reader.string();
12336
+ message.destination = reader.uint32();
12391
12337
  continue;
12392
12338
  }
12393
12339
  case 2: {
@@ -12414,15 +12360,15 @@ const Transfer = {
12414
12360
  },
12415
12361
  fromJSON(object) {
12416
12362
  return {
12417
- destination: isSet(object.destination) ? globalThis.String(object.destination) : "",
12363
+ destination: isSet(object.destination) ? globalThis.Number(object.destination) : 0,
12418
12364
  type: isSet(object.type) ? transferTypeFromJSON(object.type) : 0,
12419
12365
  minTransferTime: isSet(object.minTransferTime) ? globalThis.Number(object.minTransferTime) : undefined,
12420
12366
  };
12421
12367
  },
12422
12368
  toJSON(message) {
12423
12369
  const obj = {};
12424
- if (message.destination !== "") {
12425
- obj.destination = message.destination;
12370
+ if (message.destination !== 0) {
12371
+ obj.destination = Math.round(message.destination);
12426
12372
  }
12427
12373
  if (message.type !== 0) {
12428
12374
  obj.type = transferTypeToJSON(message.type);
@@ -12438,7 +12384,7 @@ const Transfer = {
12438
12384
  fromPartial(object) {
12439
12385
  var _a, _b, _c;
12440
12386
  const message = createBaseTransfer();
12441
- message.destination = (_a = object.destination) !== null && _a !== undefined ? _a : "";
12387
+ message.destination = (_a = object.destination) !== null && _a !== undefined ? _a : 0;
12442
12388
  message.type = (_b = object.type) !== null && _b !== undefined ? _b : 0;
12443
12389
  message.minTransferTime = (_c = object.minTransferTime) !== null && _c !== undefined ? _c : undefined;
12444
12390
  return message;
@@ -12978,6 +12924,31 @@ const Timetable$1 = {
12978
12924
  return message;
12979
12925
  },
12980
12926
  };
12927
+ function bytesFromBase64(b64) {
12928
+ if (globalThis.Buffer) {
12929
+ return Uint8Array.from(globalThis.Buffer.from(b64, "base64"));
12930
+ }
12931
+ else {
12932
+ const bin = globalThis.atob(b64);
12933
+ const arr = new Uint8Array(bin.length);
12934
+ for (let i = 0; i < bin.length; ++i) {
12935
+ arr[i] = bin.charCodeAt(i);
12936
+ }
12937
+ return arr;
12938
+ }
12939
+ }
12940
+ function base64FromBytes(arr) {
12941
+ if (globalThis.Buffer) {
12942
+ return globalThis.Buffer.from(arr).toString("base64");
12943
+ }
12944
+ else {
12945
+ const bin = [];
12946
+ arr.forEach((byte) => {
12947
+ bin.push(globalThis.String.fromCharCode(byte));
12948
+ });
12949
+ return globalThis.btoa(bin.join(""));
12950
+ }
12951
+ }
12981
12952
  function isObject(value) {
12982
12953
  return typeof value === "object" && value !== null;
12983
12954
  }
@@ -12985,6 +12956,202 @@ function isSet(value) {
12985
12956
  return value !== null && value !== undefined;
12986
12957
  }
12987
12958
 
12959
+ const isLittleEndian = (() => {
12960
+ const buffer = new ArrayBuffer(4);
12961
+ const view = new DataView(buffer);
12962
+ view.setUint32(0, 0x12345678);
12963
+ return new Uint8Array(buffer)[0] === 0x78;
12964
+ })();
12965
+ const STANDARD_ENDIANNESS = true; // true = little-endian
12966
+ function uint32ArrayToBytes(array) {
12967
+ if (isLittleEndian === STANDARD_ENDIANNESS) {
12968
+ return new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
12969
+ }
12970
+ // If endianness doesn't match, we need to swap byte order
12971
+ const result = new Uint8Array(array.length * 4);
12972
+ const view = new DataView(result.buffer);
12973
+ for (let i = 0; i < array.length; i++) {
12974
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
12975
+ view.setUint32(i * 4, array[i], STANDARD_ENDIANNESS);
12976
+ }
12977
+ return result;
12978
+ }
12979
+ function bytesToUint32Array(bytes) {
12980
+ if (bytes.byteLength % 4 !== 0) {
12981
+ throw new Error('Byte array length must be a multiple of 4 to convert to Uint32Array');
12982
+ }
12983
+ // If system endianness matches our standard, we can create a view directly
12984
+ if (isLittleEndian === STANDARD_ENDIANNESS) {
12985
+ return new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4);
12986
+ }
12987
+ // If endianness doesn't match, we need to swap byte order
12988
+ const result = new Uint32Array(bytes.byteLength / 4);
12989
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
12990
+ for (let i = 0; i < result.length; i++) {
12991
+ result[i] = view.getUint32(i * 4, STANDARD_ENDIANNESS);
12992
+ }
12993
+ return result;
12994
+ }
12995
+ const serializeStopsAdjacency = (stopsAdjacency) => {
12996
+ const protoStopsAdjacency = {
12997
+ stops: {},
12998
+ };
12999
+ stopsAdjacency.forEach((value, key) => {
13000
+ protoStopsAdjacency.stops[key] = {
13001
+ transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: serializeTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
13002
+ minTransferTime: transfer.minTransferTime.toSeconds(),
13003
+ })))),
13004
+ routes: value.routes,
13005
+ };
13006
+ });
13007
+ return protoStopsAdjacency;
13008
+ };
13009
+ const serializeRoutesAdjacency = (routesAdjacency) => {
13010
+ const protoRoutesAdjacency = {
13011
+ routes: {},
13012
+ };
13013
+ routesAdjacency.forEach((value, key) => {
13014
+ protoRoutesAdjacency.routes[key] = {
13015
+ stopTimes: uint32ArrayToBytes(value.stopTimes),
13016
+ pickUpDropOffTypes: value.pickUpDropOffTypes,
13017
+ stops: uint32ArrayToBytes(value.stops),
13018
+ serviceRouteId: value.serviceRouteId,
13019
+ };
13020
+ });
13021
+ return protoRoutesAdjacency;
13022
+ };
13023
+ const serializeServiceRoutesMap = (serviceRoutesMap) => {
13024
+ const protoServiceRoutesMap = {
13025
+ routes: {},
13026
+ };
13027
+ serviceRoutesMap.forEach((value, key) => {
13028
+ protoServiceRoutesMap.routes[key] = {
13029
+ type: serializeRouteType(value.type),
13030
+ name: value.name,
13031
+ };
13032
+ });
13033
+ return protoServiceRoutesMap;
13034
+ };
13035
+ const deserializeStopsAdjacency = (protoStopsAdjacency) => {
13036
+ const stopsAdjacency = new Map();
13037
+ Object.entries(protoStopsAdjacency.stops).forEach(([keyStr, value]) => {
13038
+ const key = parseInt(keyStr, 10);
13039
+ stopsAdjacency.set(key, {
13040
+ transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: parseTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
13041
+ minTransferTime: Duration.fromSeconds(transfer.minTransferTime),
13042
+ })))),
13043
+ routes: value.routes,
13044
+ });
13045
+ });
13046
+ return stopsAdjacency;
13047
+ };
13048
+ const deserializeRoutesAdjacency = (protoRoutesAdjacency) => {
13049
+ const routesAdjacency = new Map();
13050
+ Object.entries(protoRoutesAdjacency.routes).forEach(([key, value]) => {
13051
+ const stops = bytesToUint32Array(value.stops);
13052
+ const indices = new Map();
13053
+ for (let i = 0; i < stops.length; i++) {
13054
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13055
+ indices.set(stops[i], i);
13056
+ }
13057
+ routesAdjacency.set(key, {
13058
+ stopTimes: bytesToUint32Array(value.stopTimes),
13059
+ pickUpDropOffTypes: value.pickUpDropOffTypes,
13060
+ stops: stops,
13061
+ stopIndices: indices,
13062
+ serviceRouteId: value.serviceRouteId,
13063
+ });
13064
+ });
13065
+ return routesAdjacency;
13066
+ };
13067
+ const deserializeServiceRoutesMap = (protoServiceRoutesMap) => {
13068
+ const serviceRoutesMap = new Map();
13069
+ Object.entries(protoServiceRoutesMap.routes).forEach(([key, value]) => {
13070
+ serviceRoutesMap.set(key, {
13071
+ type: parseRouteType(value.type),
13072
+ name: value.name,
13073
+ });
13074
+ });
13075
+ return serviceRoutesMap;
13076
+ };
13077
+ const parseTransferType = (type) => {
13078
+ switch (type) {
13079
+ case TransferType.RECOMMENDED_TRANSFER_POINT:
13080
+ return 'RECOMMENDED';
13081
+ case TransferType.TIMED_TRANSFER:
13082
+ return 'GUARANTEED';
13083
+ case TransferType.REQUIRES_MINIMAL_TIME:
13084
+ return 'REQUIRES_MINIMAL_TIME';
13085
+ case TransferType.IN_SEAT_TRANSFER:
13086
+ return 'IN_SEAT';
13087
+ case TransferType.UNRECOGNIZED:
13088
+ throw new Error('Unrecognized protobuf transfer type.');
13089
+ }
13090
+ };
13091
+ const serializeTransferType = (type) => {
13092
+ switch (type) {
13093
+ case 'RECOMMENDED':
13094
+ return TransferType.RECOMMENDED_TRANSFER_POINT;
13095
+ case 'GUARANTEED':
13096
+ return TransferType.TIMED_TRANSFER;
13097
+ case 'REQUIRES_MINIMAL_TIME':
13098
+ return TransferType.REQUIRES_MINIMAL_TIME;
13099
+ case 'IN_SEAT':
13100
+ return TransferType.IN_SEAT_TRANSFER;
13101
+ }
13102
+ };
13103
+ const parseRouteType = (type) => {
13104
+ switch (type) {
13105
+ case RouteType.TRAM:
13106
+ return 'TRAM';
13107
+ case RouteType.SUBWAY:
13108
+ return 'SUBWAY';
13109
+ case RouteType.RAIL:
13110
+ return 'RAIL';
13111
+ case RouteType.BUS:
13112
+ return 'BUS';
13113
+ case RouteType.FERRY:
13114
+ return 'FERRY';
13115
+ case RouteType.CABLE_TRAM:
13116
+ return 'CABLE_TRAM';
13117
+ case RouteType.AERIAL_LIFT:
13118
+ return 'AERIAL_LIFT';
13119
+ case RouteType.FUNICULAR:
13120
+ return 'FUNICULAR';
13121
+ case RouteType.TROLLEYBUS:
13122
+ return 'TROLLEYBUS';
13123
+ case RouteType.MONORAIL:
13124
+ return 'MONORAIL';
13125
+ case RouteType.UNRECOGNIZED:
13126
+ default:
13127
+ throw new Error('Unrecognized protobuf route type.');
13128
+ }
13129
+ };
13130
+ const serializeRouteType = (type) => {
13131
+ switch (type) {
13132
+ case 'TRAM':
13133
+ return RouteType.TRAM;
13134
+ case 'SUBWAY':
13135
+ return RouteType.SUBWAY;
13136
+ case 'RAIL':
13137
+ return RouteType.RAIL;
13138
+ case 'BUS':
13139
+ return RouteType.BUS;
13140
+ case 'FERRY':
13141
+ return RouteType.FERRY;
13142
+ case 'CABLE_TRAM':
13143
+ return RouteType.CABLE_TRAM;
13144
+ case 'AERIAL_LIFT':
13145
+ return RouteType.AERIAL_LIFT;
13146
+ case 'FUNICULAR':
13147
+ return RouteType.FUNICULAR;
13148
+ case 'TROLLEYBUS':
13149
+ return RouteType.TROLLEYBUS;
13150
+ case 'MONORAIL':
13151
+ return RouteType.MONORAIL;
13152
+ }
13153
+ };
13154
+
12988
13155
  /**
12989
13156
  * A class representing a time in hours, minutes, and seconds.
12990
13157
  */
@@ -13156,195 +13323,10 @@ class Time {
13156
13323
  }
13157
13324
  }
13158
13325
 
13159
- const serializeStopsAdjacency = (stopsAdjacency) => {
13160
- const protoStopsAdjacency = {
13161
- stops: {},
13162
- };
13163
- stopsAdjacency.forEach((value, key) => {
13164
- protoStopsAdjacency.stops[key] = {
13165
- transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: serializeTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
13166
- minTransferTime: transfer.minTransferTime.toSeconds(),
13167
- })))),
13168
- routes: value.routes,
13169
- };
13170
- });
13171
- return protoStopsAdjacency;
13172
- };
13173
- const serializeRoutesAdjacency = (routesAdjacency) => {
13174
- const protoRoutesAdjacency = {
13175
- routes: {},
13176
- };
13177
- routesAdjacency.forEach((value, key) => {
13178
- protoRoutesAdjacency.routes[key] = {
13179
- stopTimes: value.stopTimes.map((stopTimes) => ({
13180
- arrival: stopTimes.arrival.toSeconds(),
13181
- departure: stopTimes.departure.toSeconds(),
13182
- pickUpType: serializePickUpDropOffType(stopTimes.pickUpType),
13183
- dropOffType: serializePickUpDropOffType(stopTimes.dropOffType),
13184
- })),
13185
- stops: value.stops,
13186
- serviceRouteId: value.serviceRouteId,
13187
- };
13188
- });
13189
- return protoRoutesAdjacency;
13190
- };
13191
- const serializeServiceRoutesMap = (serviceRoutesMap) => {
13192
- const protoServiceRoutesMap = {
13193
- routes: {},
13194
- };
13195
- serviceRoutesMap.forEach((value, key) => {
13196
- protoServiceRoutesMap.routes[key] = {
13197
- type: serializeRouteType(value.type),
13198
- name: value.name,
13199
- };
13200
- });
13201
- return protoServiceRoutesMap;
13202
- };
13203
- const deserializeStopsAdjacency = (protoStopsAdjacency) => {
13204
- const stopsAdjacency = new Map();
13205
- Object.entries(protoStopsAdjacency.stops).forEach(([key, value]) => {
13206
- stopsAdjacency.set(key, {
13207
- transfers: value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: parseTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
13208
- minTransferTime: Duration.fromSeconds(transfer.minTransferTime),
13209
- })))),
13210
- routes: value.routes,
13211
- });
13212
- });
13213
- return stopsAdjacency;
13214
- };
13215
- const deserializeRoutesAdjacency = (protoRoutesAdjacency) => {
13216
- const routesAdjacency = new Map();
13217
- Object.entries(protoRoutesAdjacency.routes).forEach(([key, value]) => {
13218
- routesAdjacency.set(key, {
13219
- stopTimes: value.stopTimes.map((stopTimes) => ({
13220
- arrival: Time.fromSeconds(stopTimes.arrival),
13221
- departure: Time.fromSeconds(stopTimes.departure),
13222
- pickUpType: stopTimes.pickUpType !== undefined
13223
- ? parsePickUpDropOffType(stopTimes.pickUpType)
13224
- : 'REGULAR',
13225
- dropOffType: stopTimes.dropOffType !== undefined
13226
- ? parsePickUpDropOffType(stopTimes.dropOffType)
13227
- : 'REGULAR',
13228
- })),
13229
- stops: value.stops,
13230
- stopIndices: new Map(value.stops.map((stop, index) => [stop, index])),
13231
- serviceRouteId: value.serviceRouteId,
13232
- });
13233
- });
13234
- return routesAdjacency;
13235
- };
13236
- const deserializeServiceRoutesMap = (protoServiceRoutesMap) => {
13237
- const serviceRoutesMap = new Map();
13238
- Object.entries(protoServiceRoutesMap.routes).forEach(([key, value]) => {
13239
- serviceRoutesMap.set(key, {
13240
- type: parseRouteType(value.type),
13241
- name: value.name,
13242
- });
13243
- });
13244
- return serviceRoutesMap;
13245
- };
13246
- const parseTransferType = (type) => {
13247
- switch (type) {
13248
- case TransferType.RECOMMENDED_TRANSFER_POINT:
13249
- return 'RECOMMENDED';
13250
- case TransferType.TIMED_TRANSFER:
13251
- return 'GUARANTEED';
13252
- case TransferType.REQUIRES_MINIMAL_TIME:
13253
- return 'REQUIRES_MINIMAL_TIME';
13254
- case TransferType.IN_SEAT_TRANSFER:
13255
- return 'IN_SEAT';
13256
- case TransferType.UNRECOGNIZED:
13257
- throw new Error('Unrecognized protobuf transfer type.');
13258
- }
13259
- };
13260
- const serializeTransferType = (type) => {
13261
- switch (type) {
13262
- case 'RECOMMENDED':
13263
- return TransferType.RECOMMENDED_TRANSFER_POINT;
13264
- case 'GUARANTEED':
13265
- return TransferType.TIMED_TRANSFER;
13266
- case 'REQUIRES_MINIMAL_TIME':
13267
- return TransferType.REQUIRES_MINIMAL_TIME;
13268
- case 'IN_SEAT':
13269
- return TransferType.IN_SEAT_TRANSFER;
13270
- }
13271
- };
13272
- const parseRouteType = (type) => {
13273
- switch (type) {
13274
- case RouteType.TRAM:
13275
- return 'TRAM';
13276
- case RouteType.SUBWAY:
13277
- return 'SUBWAY';
13278
- case RouteType.RAIL:
13279
- return 'RAIL';
13280
- case RouteType.BUS:
13281
- return 'BUS';
13282
- case RouteType.FERRY:
13283
- return 'FERRY';
13284
- case RouteType.CABLE_TRAM:
13285
- return 'CABLE_TRAM';
13286
- case RouteType.AERIAL_LIFT:
13287
- return 'AERIAL_LIFT';
13288
- case RouteType.FUNICULAR:
13289
- return 'FUNICULAR';
13290
- case RouteType.TROLLEYBUS:
13291
- return 'TROLLEYBUS';
13292
- case RouteType.MONORAIL:
13293
- return 'MONORAIL';
13294
- case RouteType.UNRECOGNIZED:
13295
- default:
13296
- throw new Error('Unrecognized protobuf route type.');
13297
- }
13298
- };
13299
- const serializeRouteType = (type) => {
13300
- switch (type) {
13301
- case 'TRAM':
13302
- return RouteType.TRAM;
13303
- case 'SUBWAY':
13304
- return RouteType.SUBWAY;
13305
- case 'RAIL':
13306
- return RouteType.RAIL;
13307
- case 'BUS':
13308
- return RouteType.BUS;
13309
- case 'FERRY':
13310
- return RouteType.FERRY;
13311
- case 'CABLE_TRAM':
13312
- return RouteType.CABLE_TRAM;
13313
- case 'AERIAL_LIFT':
13314
- return RouteType.AERIAL_LIFT;
13315
- case 'FUNICULAR':
13316
- return RouteType.FUNICULAR;
13317
- case 'TROLLEYBUS':
13318
- return RouteType.TROLLEYBUS;
13319
- case 'MONORAIL':
13320
- return RouteType.MONORAIL;
13321
- }
13322
- };
13323
- const parsePickUpDropOffType = (type) => {
13324
- switch (type) {
13325
- case PickUpDropOffType.MUST_PHONE_AGENCY:
13326
- return 'MUST_PHONE_AGENCY';
13327
- case PickUpDropOffType.MUST_COORDINATE_WITH_DRIVER:
13328
- return 'MUST_COORDINATE_WITH_DRIVER';
13329
- case PickUpDropOffType.NOT_AVAILABLE:
13330
- return 'NOT_AVAILABLE';
13331
- default:
13332
- return 'REGULAR';
13333
- }
13334
- };
13335
- const serializePickUpDropOffType = (type) => {
13336
- switch (type) {
13337
- case 'REGULAR':
13338
- return undefined;
13339
- case 'NOT_AVAILABLE':
13340
- return PickUpDropOffType.NOT_AVAILABLE;
13341
- case 'MUST_COORDINATE_WITH_DRIVER':
13342
- return PickUpDropOffType.MUST_COORDINATE_WITH_DRIVER;
13343
- case 'MUST_PHONE_AGENCY':
13344
- return PickUpDropOffType.MUST_PHONE_AGENCY;
13345
- }
13346
- };
13347
-
13326
+ const REGULAR = 0;
13327
+ const NOT_AVAILABLE = 1;
13328
+ const MUST_PHONE_AGENCY = 2;
13329
+ const MUST_COORDINATE_WITH_DRIVER = 3;
13348
13330
  const ALL_TRANSPORT_MODES = [
13349
13331
  'TRAM',
13350
13332
  'SUBWAY',
@@ -13357,7 +13339,7 @@ const ALL_TRANSPORT_MODES = [
13357
13339
  'TROLLEYBUS',
13358
13340
  'MONORAIL',
13359
13341
  ];
13360
- const CURRENT_VERSION = '0.0.1';
13342
+ const CURRENT_VERSION = '0.0.2';
13361
13343
  /**
13362
13344
  * The internal transit timetable format
13363
13345
  * reuses some GTFS concepts for the sake of simplicity for now.
@@ -13404,6 +13386,13 @@ class Timetable {
13404
13386
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13405
13387
  deserializeServiceRoutesMap(protoTimetable.routes));
13406
13388
  }
13389
+ getRoutesThroughStop(stopId) {
13390
+ const stopAdjacency = this.stopsAdjacency.get(stopId);
13391
+ if (!stopAdjacency) {
13392
+ return [];
13393
+ }
13394
+ return stopAdjacency.routes;
13395
+ }
13407
13396
  getRoute(routeId) {
13408
13397
  return this.routesAdjacency.get(routeId);
13409
13398
  }
@@ -13470,9 +13459,9 @@ class Timetable {
13470
13459
  if (beforeTrip === undefined) {
13471
13460
  for (let tripIndex = 0; tripIndex < route.stopTimes.length / stopsNumber; tripIndex++) {
13472
13461
  const stopTimeIndex = tripIndex * stopsNumber + stopIndex;
13473
- const stopTime = route.stopTimes[stopTimeIndex];
13474
- if (stopTime.departure >= after &&
13475
- stopTime.pickUpType !== 'NOT_AVAILABLE') {
13462
+ const departure = route.stopTimes[stopTimeIndex * 2 + 1];
13463
+ const pickUpType = route.pickUpDropOffTypes[stopTimeIndex * 2];
13464
+ if (departure >= after.toSeconds() && pickUpType !== NOT_AVAILABLE) {
13476
13465
  return tripIndex;
13477
13466
  }
13478
13467
  }
@@ -13484,15 +13473,16 @@ class Timetable {
13484
13473
  for (let tripIndex = beforeTrip; // ?? route.stopTimes.length / stopsNumber - 1;
13485
13474
  tripIndex >= 0; tripIndex--) {
13486
13475
  const stopTimeIndex = tripIndex * stopsNumber + stopIndex;
13487
- const stopTime = route.stopTimes[stopTimeIndex];
13488
- if (stopTime.departure < after) {
13476
+ const departure = route.stopTimes[stopTimeIndex * 2 + 1];
13477
+ const pickUpType = route.pickUpDropOffTypes[stopTimeIndex * 2];
13478
+ if (departure < after.toSeconds()) {
13489
13479
  break;
13490
13480
  }
13491
- if (stopTime.pickUpType !== 'NOT_AVAILABLE' &&
13481
+ if (pickUpType !== NOT_AVAILABLE &&
13492
13482
  (earliestDeparture === undefined ||
13493
- stopTime.departure < earliestDeparture)) {
13483
+ departure < earliestDeparture.toSeconds())) {
13494
13484
  earliestTripIndex = tripIndex;
13495
- earliestDeparture = stopTime.departure;
13485
+ earliestDeparture = Time.fromSeconds(departure);
13496
13486
  }
13497
13487
  }
13498
13488
  return earliestTripIndex;
@@ -15418,23 +15408,23 @@ const parse = function () {
15418
15408
  };
15419
15409
 
15420
15410
  /**
15421
- * Generates a simple hash from a string.
15411
+ * Generates a simple hash from an array of numeric IDs.
15422
15412
  *
15423
- * This function computes a hash for a given string by iterating over each
15424
- * character and applying bitwise operations to accumulate a hash value.
15425
- * The final hash is then converted to a base-36 string and padded to
15426
- * ensure a minimum length of 6 characters.
15413
+ * This function computes a hash for a given array of numbers by iterating over each
15414
+ * ID and applying bitwise operations to accumulate a hash value.
15415
+ * The final hash is then converted to a base-36 string.
15427
15416
  *
15428
- * @param str - The input string to hash.
15429
- * @returns A hashed string representation of the input.
15417
+ * @param ids - The array of numeric IDs to hash.
15418
+ * @returns A hashed string representation of the input array.
15430
15419
  */
15431
- const hash = (str) => {
15420
+ const hashIds = (ids) => {
15432
15421
  let hash = 0;
15433
- for (let i = 0; i < str.length; i++) {
15434
- hash = (hash << 5) - hash + str.charCodeAt(i);
15422
+ for (let i = 0; i < ids.length; i++) {
15423
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15424
+ hash = (hash << 5) - hash + ids[i];
15435
15425
  hash &= hash;
15436
15426
  }
15437
- return (hash >>> 0).toString(36).padStart(6, '0');
15427
+ return (hash >>> 0).toString(36);
15438
15428
  };
15439
15429
  /**
15440
15430
  * Parses a CSV stream with a sensible configuration for GTFS feeds.
@@ -15602,18 +15592,19 @@ const parseCalendarDates = (calendarDatesStream, serviceIds, date) => __awaiter(
15602
15592
  * @param stopsStream The readable stream containing the stops data.
15603
15593
  * @return A mapping of stop IDs to corresponding stop details.
15604
15594
  */
15605
- const parseStops = (stopsStream, platformParser, validStops) => __awaiter(undefined, undefined, undefined, function* () {
15595
+ const parseStops = (stopsStream, platformParser) => __awaiter(undefined, undefined, undefined, function* () {
15606
15596
  var _a, e_1, _b, _c;
15607
- const stops = new Map();
15597
+ const parsedStops = new Map();
15598
+ let i = 0;
15608
15599
  try {
15609
15600
  for (var _d = true, _e = __asyncValues(parseCsv(stopsStream)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
15610
15601
  _c = _f.value;
15611
15602
  _d = false;
15612
15603
  const rawLine = _c;
15613
15604
  const line = rawLine;
15614
- const stop = Object.assign({ id: line.stop_id, name: line.stop_name, lat: line.stop_lat, lon: line.stop_lon, locationType: line.location_type
15605
+ 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
15615
15606
  ? parseGtfsLocationType(line.location_type)
15616
- : 'SIMPLE_STOP_OR_PLATFORM', children: [] }, (line.parent_station && { parent: line.parent_station }));
15607
+ : 'SIMPLE_STOP_OR_PLATFORM', children: [] }, (line.parent_station && { parentSourceId: line.parent_station }));
15617
15608
  if (platformParser) {
15618
15609
  try {
15619
15610
  const platform = platformParser(line);
@@ -15625,7 +15616,8 @@ const parseStops = (stopsStream, platformParser, validStops) => __awaiter(undefi
15625
15616
  console.info(`Could not parse platform for stop ${line.stop_id}.`);
15626
15617
  }
15627
15618
  }
15628
- stops.set(line.stop_id, stop);
15619
+ parsedStops.set(line.stop_id + '', stop);
15620
+ i = i + 1;
15629
15621
  }
15630
15622
  }
15631
15623
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -15635,29 +15627,50 @@ const parseStops = (stopsStream, platformParser, validStops) => __awaiter(undefi
15635
15627
  }
15636
15628
  finally { if (e_1) throw e_1.error; }
15637
15629
  }
15638
- for (const [stopId, stop] of stops) {
15639
- if (stop.parent) {
15640
- const parentStop = stops.get(stop.parent);
15630
+ for (const [sourceStopId, stop] of parsedStops) {
15631
+ if (stop.parentSourceId) {
15632
+ const parentStop = parsedStops.get(stop.parentSourceId);
15641
15633
  if (!parentStop) {
15642
- console.warn(`Cannot find parent stop ${stop.parent} of ${stopId}`);
15634
+ console.warn(`Cannot find parent stop ${stop.parentSourceId} of ${sourceStopId}`);
15643
15635
  continue;
15644
15636
  }
15645
- parentStop.children.push(stopId);
15637
+ stop.parent = parentStop.id;
15638
+ parentStop.children.push(stop.id);
15646
15639
  }
15647
15640
  }
15648
- if (validStops) {
15649
- // Remove all stops which don't have at least one valid stopId as a child,
15650
- // a parent or as its own.
15651
- for (const [stopId, stop] of stops) {
15652
- if (!validStops.has(stopId) &&
15653
- (!stop.parent || !validStops.has(stop.parent)) &&
15654
- !stop.children.some((childId) => validStops.has(childId))) {
15655
- stops.delete(stopId);
15656
- }
15641
+ return parsedStops;
15642
+ });
15643
+ /**
15644
+ * Builds the final stop map indexed by internal IDs.
15645
+ * Excludes all stops that do not have at least one valid stopId
15646
+ * as a child, a parent, or being valid itself.
15647
+ *
15648
+ * @param parsedStops - The map of parsed stops.
15649
+ * @param validStops - A set of valid stop IDs.
15650
+ * @returns A map of stops indexed by internal IDs.
15651
+ */
15652
+ const indexStops = (parsedStops, validStops) => {
15653
+ const stops = new Map();
15654
+ for (const [, stop] of parsedStops) {
15655
+ if (!validStops ||
15656
+ validStops.has(stop.id) ||
15657
+ (stop.parent && validStops.has(stop.parent)) ||
15658
+ stop.children.some((childId) => validStops.has(childId))) {
15659
+ stops.set(stop.id, {
15660
+ id: stop.id,
15661
+ sourceStopId: stop.sourceStopId,
15662
+ name: stop.name,
15663
+ lat: stop.lat,
15664
+ lon: stop.lon,
15665
+ locationType: stop.locationType,
15666
+ platform: stop.platform,
15667
+ children: stop.children.filter((childId) => !validStops || validStops.has(childId)),
15668
+ parent: stop.parent,
15669
+ });
15657
15670
  }
15658
15671
  }
15659
15672
  return stops;
15660
- });
15673
+ };
15661
15674
  const parseGtfsLocationType = (gtfsLocationType) => {
15662
15675
  switch (gtfsLocationType) {
15663
15676
  case 0:
@@ -15680,7 +15693,7 @@ const parseGtfsLocationType = (gtfsLocationType) => {
15680
15693
  * @param stopsStream The readable stream containing the stops data.
15681
15694
  * @return A mapping of stop IDs to corresponding stop details.
15682
15695
  */
15683
- const parseTransfers = (transfersStream) => __awaiter(undefined, undefined, undefined, function* () {
15696
+ const parseTransfers = (transfersStream, stopsMap) => __awaiter(undefined, undefined, undefined, function* () {
15684
15697
  var _a, e_1, _b, _c;
15685
15698
  const transfers = new Map();
15686
15699
  try {
@@ -15708,12 +15721,16 @@ const parseTransfers = (transfersStream) => __awaiter(undefined, undefined, unde
15708
15721
  if (transferEntry.transfer_type === 2 && !transferEntry.min_transfer_time) {
15709
15722
  console.info(`Missing minimum transfer time between ${transferEntry.from_stop_id} and ${transferEntry.to_stop_id}.`);
15710
15723
  }
15711
- const transfer = Object.assign({ destination: transferEntry.to_stop_id, type: parseGtfsTransferType(transferEntry.transfer_type) }, (transferEntry.min_transfer_time && {
15724
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15725
+ const fromStop = stopsMap.get(transferEntry.from_stop_id + '');
15726
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15727
+ const toStop = stopsMap.get(transferEntry.to_stop_id + '');
15728
+ const transfer = Object.assign({ destination: toStop.id, type: parseGtfsTransferType(transferEntry.transfer_type) }, (transferEntry.min_transfer_time && {
15712
15729
  minTransferTime: Duration.fromSeconds(transferEntry.min_transfer_time),
15713
15730
  }));
15714
- const fromStopTransfers = transfers.get(transferEntry.from_stop_id) || [];
15731
+ const fromStopTransfers = transfers.get(fromStop.id) || [];
15715
15732
  fromStopTransfers.push(transfer);
15716
- transfers.set(transferEntry.from_stop_id, fromStopTransfers);
15733
+ transfers.set(fromStop.id, fromStopTransfers);
15717
15734
  }
15718
15735
  }
15719
15736
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -15804,28 +15821,52 @@ const buildStopsAdjacencyStructure = (validStops, routes, transfersMap) => {
15804
15821
  * Parses the stop_times.txt data from a GTFS feed.
15805
15822
  *
15806
15823
  * @param stopTimesStream The readable stream containing the stop times data.
15824
+ * @param stopsMap A map of parsed stops from the GTFS feed.
15807
15825
  * @param validTripIds A map of valid trip IDs to corresponding route IDs.
15808
- * @param validStopIds A map of valid stop IDs.
15809
- * @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.
15826
+ * @param validStopIds A set of valid stop IDs.
15827
+ * @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.
15810
15828
  */
15811
- const parseStopTimes = (stopTimesStream, validTripIds, validStopIds) => __awaiter(undefined, undefined, undefined, function* () {
15829
+ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) => __awaiter(undefined, undefined, undefined, function* () {
15812
15830
  var _a, e_2, _b, _c;
15813
15831
  var _d, _e;
15832
+ /**
15833
+ * Inserts a trip at the right place in the routes adjacency structure.
15834
+ */
15814
15835
  const addTrip = (currentTripId) => {
15815
15836
  const gtfsRouteId = validTripIds.get(currentTripId);
15816
15837
  if (!gtfsRouteId) {
15817
15838
  stops = [];
15818
- stopTimes = [];
15839
+ arrivalTimes = [];
15840
+ departureTimes = [];
15841
+ pickUpTypes = [];
15842
+ dropOffTypes = [];
15819
15843
  return;
15820
15844
  }
15821
- const routeId = `${gtfsRouteId}_${hash(stops.join('$'))}`;
15845
+ const routeId = `${gtfsRouteId}_${hashIds(stops)}`;
15822
15846
  let route = routes.get(routeId);
15823
15847
  if (!route) {
15848
+ const stopsCount = stops.length;
15849
+ const stopsArray = new Uint32Array(stops);
15850
+ const stopTimesArray = new Uint32Array(stopsCount * 2);
15851
+ for (let i = 0; i < stopsCount; i++) {
15852
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15853
+ stopTimesArray[i * 2] = arrivalTimes[i];
15854
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15855
+ stopTimesArray[i * 2 + 1] = departureTimes[i];
15856
+ }
15857
+ const pickUpDropOffTypesArray = new Uint8Array(stopsCount * 2);
15858
+ for (let i = 0; i < stopsCount; i++) {
15859
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15860
+ pickUpDropOffTypesArray[i * 2] = pickUpTypes[i];
15861
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15862
+ pickUpDropOffTypesArray[i * 2 + 1] = dropOffTypes[i];
15863
+ }
15824
15864
  route = {
15825
15865
  serviceRouteId: gtfsRouteId,
15826
- stops: [...stops],
15866
+ stops: stopsArray,
15827
15867
  stopIndices: new Map(stops.map((stop, i) => [stop, i])),
15828
- stopTimes: [...stopTimes],
15868
+ stopTimes: stopTimesArray,
15869
+ pickUpDropOffTypes: pickUpDropOffTypesArray,
15829
15870
  };
15830
15871
  routes.set(routeId, route);
15831
15872
  for (const stop of stops) {
@@ -15833,31 +15874,59 @@ const parseStopTimes = (stopTimesStream, validTripIds, validStopIds) => __awaite
15833
15874
  }
15834
15875
  }
15835
15876
  else {
15836
- const tripFirstStop = stopTimes[0];
15837
- if (!tripFirstStop) {
15877
+ const tripFirstStopDeparture = departureTimes[0];
15878
+ if (tripFirstStopDeparture === undefined) {
15838
15879
  throw new Error(`Empty trip ${currentTripId}`);
15839
15880
  }
15840
- // insert the stopTimes at the right position
15841
- let stopTimesIndex = 0;
15842
- for (let i = 0; i < route.stopTimes.length; i += stops.length) {
15843
- const currentDeparture = route.stopTimes[i];
15844
- if (currentDeparture &&
15845
- tripFirstStop.departure > currentDeparture.departure) {
15846
- stopTimesIndex = i + stops.length;
15881
+ // Find the correct position to insert the new trip
15882
+ const stopsCount = stops.length;
15883
+ let insertPosition = 0;
15884
+ const existingTripsCount = route.stopTimes.length / (stopsCount * 2);
15885
+ for (let tripIndex = 0; tripIndex < existingTripsCount; tripIndex++) {
15886
+ const currentDeparture = route.stopTimes[tripIndex * stopsCount * 2 + 1];
15887
+ if (currentDeparture && tripFirstStopDeparture > currentDeparture) {
15888
+ insertPosition = (tripIndex + 1) * stopsCount;
15847
15889
  }
15848
15890
  else {
15849
15891
  break;
15850
15892
  }
15851
15893
  }
15852
- route.stopTimes.splice(stopTimesIndex, 0, ...stopTimes);
15894
+ // insert data for the new trip at the right place
15895
+ const newStopTimesLength = route.stopTimes.length + stopsCount * 2;
15896
+ const newStopTimes = new Uint32Array(newStopTimesLength);
15897
+ const newPickUpDropOffTypes = new Uint8Array(newStopTimesLength);
15898
+ newStopTimes.set(route.stopTimes.slice(0, insertPosition * 2), 0);
15899
+ newPickUpDropOffTypes.set(route.pickUpDropOffTypes.slice(0, insertPosition * 2), 0);
15900
+ for (let i = 0; i < stopsCount; i++) {
15901
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15902
+ newStopTimes[(insertPosition + i) * 2] = arrivalTimes[i];
15903
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15904
+ newStopTimes[(insertPosition + i) * 2 + 1] = departureTimes[i];
15905
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15906
+ newPickUpDropOffTypes[(insertPosition + i) * 2] = pickUpTypes[i];
15907
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15908
+ newPickUpDropOffTypes[(insertPosition + i) * 2 + 1] = dropOffTypes[i];
15909
+ }
15910
+ const afterInsertionSlice = route.stopTimes.slice(insertPosition * 2);
15911
+ newStopTimes.set(afterInsertionSlice, (insertPosition + stopsCount) * 2);
15912
+ const afterInsertionTypesSlice = route.pickUpDropOffTypes.slice(insertPosition * 2);
15913
+ newPickUpDropOffTypes.set(afterInsertionTypesSlice, (insertPosition + stopsCount) * 2);
15914
+ route.stopTimes = newStopTimes;
15915
+ route.pickUpDropOffTypes = newPickUpDropOffTypes;
15853
15916
  }
15854
15917
  stops = [];
15855
- stopTimes = [];
15918
+ arrivalTimes = [];
15919
+ departureTimes = [];
15920
+ pickUpTypes = [];
15921
+ dropOffTypes = [];
15856
15922
  };
15857
15923
  const routes = new Map();
15858
15924
  let previousSeq = 0;
15859
15925
  let stops = [];
15860
- let stopTimes = [];
15926
+ let arrivalTimes = [];
15927
+ let departureTimes = [];
15928
+ let pickUpTypes = [];
15929
+ let dropOffTypes = [];
15861
15930
  let currentTripId = undefined;
15862
15931
  try {
15863
15932
  for (var _f = true, _g = __asyncValues(parseCsv(stopTimesStream)), _h; _h = yield _g.next(), _a = _h.done, !_a; _f = true) {
@@ -15876,24 +15945,20 @@ const parseStopTimes = (stopTimesStream, validTripIds, validStopIds) => __awaite
15876
15945
  if (line.pickup_type === 1 && line.drop_off_type === 1) {
15877
15946
  continue;
15878
15947
  }
15879
- if (currentTripId &&
15880
- line.trip_id !== currentTripId &&
15881
- stops.length > 0 &&
15882
- stopTimes.length > 0) {
15948
+ if (currentTripId && line.trip_id !== currentTripId && stops.length > 0) {
15883
15949
  addTrip(currentTripId);
15884
15950
  }
15885
15951
  currentTripId = line.trip_id;
15886
- stops.push(line.stop_id);
15952
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15953
+ stops.push(stopsMap.get(line.stop_id + '').id);
15887
15954
  const departure = (_d = line.departure_time) !== null && _d !== void 0 ? _d : line.arrival_time;
15888
15955
  const arrival = (_e = line.arrival_time) !== null && _e !== void 0 ? _e : line.departure_time;
15889
- stopTimes.push({
15890
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15891
- departure: toTime(departure),
15892
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15893
- arrival: toTime(arrival),
15894
- pickUpType: parsePickupDropOffType(line.pickup_type),
15895
- dropOffType: parsePickupDropOffType(line.drop_off_type),
15896
- });
15956
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15957
+ arrivalTimes.push(toTime(arrival).toSeconds());
15958
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15959
+ departureTimes.push(toTime(departure).toSeconds());
15960
+ pickUpTypes.push(parsePickupDropOffType(line.pickup_type));
15961
+ dropOffTypes.push(parsePickupDropOffType(line.drop_off_type));
15897
15962
  previousSeq = line.stop_sequence;
15898
15963
  }
15899
15964
  }
@@ -15913,15 +15978,15 @@ const parsePickupDropOffType = (gtfsType) => {
15913
15978
  switch (gtfsType) {
15914
15979
  default:
15915
15980
  console.warn(`Unknown pickup/drop-off type ${gtfsType}`);
15916
- return 'REGULAR';
15981
+ return REGULAR;
15917
15982
  case 0:
15918
- return 'REGULAR';
15983
+ return REGULAR;
15919
15984
  case 1:
15920
- return 'NOT_AVAILABLE';
15985
+ return NOT_AVAILABLE;
15921
15986
  case 2:
15922
- return 'MUST_PHONE_AGENCY';
15987
+ return MUST_PHONE_AGENCY;
15923
15988
  case 3:
15924
- return 'MUST_COORDINATE_WITH_DRIVER';
15989
+ return MUST_COORDINATE_WITH_DRIVER;
15925
15990
  }
15926
15991
  };
15927
15992
 
@@ -15953,6 +16018,10 @@ class GtfsParser {
15953
16018
  const datetime = DateTime.fromJSDate(date);
15954
16019
  const validServiceIds = new Set();
15955
16020
  const validStopIds = new Set();
16021
+ log.info(`Parsing ${STOPS_FILE}`);
16022
+ const stopsStream = yield zip.stream(STOPS_FILE);
16023
+ const parsedStops = yield parseStops(stopsStream, this.profile.platformParser);
16024
+ log.info(`${parsedStops.size} parsed stops.`);
15956
16025
  if (entries[CALENDAR_FILE]) {
15957
16026
  log.info(`Parsing ${CALENDAR_FILE}`);
15958
16027
  const calendarStream = yield zip.stream(CALENDAR_FILE);
@@ -15977,18 +16046,17 @@ class GtfsParser {
15977
16046
  if (entries[TRANSFERS_FILE]) {
15978
16047
  log.info(`Parsing ${TRANSFERS_FILE}`);
15979
16048
  const transfersStream = yield zip.stream(TRANSFERS_FILE);
15980
- transfers = yield parseTransfers(transfersStream);
16049
+ transfers = yield parseTransfers(transfersStream, parsedStops);
15981
16050
  log.info(`${transfers.size} valid transfers.`);
15982
16051
  }
15983
16052
  log.info(`Parsing ${STOP_TIMES_FILE}`);
15984
16053
  const stopTimesStream = yield zip.stream(STOP_TIMES_FILE);
15985
- const routesAdjacency = yield parseStopTimes(stopTimesStream, trips, validStopIds);
16054
+ const routesAdjacency = yield parseStopTimes(stopTimesStream, parsedStops, trips, validStopIds);
15986
16055
  const stopsAdjacency = buildStopsAdjacencyStructure(validStopIds, routesAdjacency, transfers);
15987
16056
  log.info(`${routesAdjacency.size} valid unique routes.`);
15988
- log.info(`Parsing ${STOPS_FILE}`);
15989
- const stopsStream = yield zip.stream(STOPS_FILE);
15990
- const stops = yield parseStops(stopsStream, this.profile.platformParser, validStopIds);
15991
- log.info(`${stops.size} valid stops.`);
16057
+ log.info(`Removing unused stops.`);
16058
+ const stops = indexStops(parsedStops, validStopIds);
16059
+ log.info(`${stops.size} used stop stops, ${parsedStops.size - stops.size} unused.`);
15992
16060
  yield zip.close();
15993
16061
  const timetable = new Timetable(stopsAdjacency, routesAdjacency, validGtfsRoutes);
15994
16062
  log.info(`Building stops index.`);
@@ -16009,8 +16077,8 @@ class GtfsParser {
16009
16077
  const zip = new StreamZip.async({ file: this.path });
16010
16078
  log.info(`Parsing ${STOPS_FILE}`);
16011
16079
  const stopsStream = yield zip.stream(STOPS_FILE);
16012
- const stops = yield parseStops(stopsStream, this.profile.platformParser);
16013
- log.info(`${stops.size} valid stops.`);
16080
+ const stops = indexStops(yield parseStops(stopsStream, this.profile.platformParser));
16081
+ log.info(`${stops.size} parsed stops.`);
16014
16082
  yield zip.close();
16015
16083
  return new StopsIndex(stops);
16016
16084
  });