minotor 3.0.2 → 5.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 (43) hide show
  1. package/CHANGELOG.md +9 -3
  2. package/README.md +1 -0
  3. package/dist/cli.mjs +294 -307
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/gtfs/trips.d.ts +12 -6
  6. package/dist/parser.cjs.js +290 -302
  7. package/dist/parser.cjs.js.map +1 -1
  8. package/dist/parser.esm.js +290 -302
  9. package/dist/parser.esm.js.map +1 -1
  10. package/dist/router.cjs.js +1 -1
  11. package/dist/router.cjs.js.map +1 -1
  12. package/dist/router.d.ts +2 -2
  13. package/dist/router.esm.js +1 -1
  14. package/dist/router.esm.js.map +1 -1
  15. package/dist/router.umd.js +1 -1
  16. package/dist/router.umd.js.map +1 -1
  17. package/dist/routing/route.d.ts +3 -3
  18. package/dist/timetable/io.d.ts +5 -4
  19. package/dist/timetable/proto/timetable.d.ts +7 -16
  20. package/dist/timetable/route.d.ts +7 -5
  21. package/dist/timetable/timetable.d.ts +7 -5
  22. package/package.json +1 -1
  23. package/src/__e2e__/timetable/timetable.bin +2 -2
  24. package/src/cli/repl.ts +0 -1
  25. package/src/gtfs/__tests__/parser.test.ts +2 -2
  26. package/src/gtfs/__tests__/routes.test.ts +3 -0
  27. package/src/gtfs/__tests__/trips.test.ts +123 -166
  28. package/src/gtfs/parser.ts +50 -9
  29. package/src/gtfs/routes.ts +1 -0
  30. package/src/gtfs/trips.ts +195 -112
  31. package/src/router.ts +2 -2
  32. package/src/routing/__tests__/route.test.ts +3 -3
  33. package/src/routing/__tests__/router.test.ts +186 -203
  34. package/src/routing/route.ts +3 -3
  35. package/src/routing/router.ts +1 -1
  36. package/src/timetable/__tests__/io.test.ts +52 -64
  37. package/src/timetable/__tests__/route.test.ts +25 -17
  38. package/src/timetable/__tests__/timetable.test.ts +16 -24
  39. package/src/timetable/io.ts +20 -19
  40. package/src/timetable/proto/timetable.proto +7 -9
  41. package/src/timetable/proto/timetable.ts +80 -202
  42. package/src/timetable/route.ts +27 -13
  43. package/src/timetable/timetable.ts +20 -16
@@ -148,7 +148,8 @@ export interface Route {
148
148
  * 1: NOT_AVAILABLE
149
149
  * 2: MUST_PHONE_AGENCY
150
150
  * 3: MUST_COORDINATE_WITH_DRIVER
151
- * Format: [pickupTypeStop1, dropOffTypeStop1, pickupTypeStop2, dropOffTypeStop2, etc.]
151
+ * Format: [drop_off_1][pickup_1][drop_off_0][pickup_0]
152
+ * 2 bits per value
152
153
  */
153
154
  pickUpDropOffTypes: Uint8Array;
154
155
  /**
@@ -159,15 +160,6 @@ export interface Route {
159
160
  serviceRouteId: string;
160
161
  }
161
162
 
162
- export interface RoutesAdjacency {
163
- routes: { [key: string]: Route };
164
- }
165
-
166
- export interface RoutesAdjacency_RoutesEntry {
167
- key: string;
168
- value: Route | undefined;
169
- }
170
-
171
163
  export interface Transfer {
172
164
  destination: number;
173
165
  type: TransferType;
@@ -175,22 +167,23 @@ export interface Transfer {
175
167
  }
176
168
 
177
169
  export interface StopsAdjacency {
178
- stops: { [key: string]: StopsAdjacency_StopAdjacency };
170
+ stops: { [key: number]: StopsAdjacency_StopAdjacency };
179
171
  }
180
172
 
181
173
  export interface StopsAdjacency_StopAdjacency {
182
174
  transfers: Transfer[];
183
- routes: string[];
175
+ routes: number[];
184
176
  }
185
177
 
186
178
  export interface StopsAdjacency_StopsEntry {
187
- key: string;
179
+ key: number;
188
180
  value: StopsAdjacency_StopAdjacency | undefined;
189
181
  }
190
182
 
191
183
  export interface ServiceRoute {
192
184
  type: RouteType;
193
185
  name: string;
186
+ routes: number[];
194
187
  }
195
188
 
196
189
  export interface ServiceRoutesMap {
@@ -205,7 +198,7 @@ export interface ServiceRoutesMap_RoutesEntry {
205
198
  export interface Timetable {
206
199
  version: string;
207
200
  stopsAdjacency: StopsAdjacency | undefined;
208
- routesAdjacency: RoutesAdjacency | undefined;
201
+ routesAdjacency: Route[];
209
202
  routes: ServiceRoutesMap | undefined;
210
203
  }
211
204
 
@@ -324,161 +317,6 @@ export const Route: MessageFns<Route> = {
324
317
  },
325
318
  };
326
319
 
327
- function createBaseRoutesAdjacency(): RoutesAdjacency {
328
- return { routes: {} };
329
- }
330
-
331
- export const RoutesAdjacency: MessageFns<RoutesAdjacency> = {
332
- encode(message: RoutesAdjacency, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
333
- Object.entries(message.routes).forEach(([key, value]) => {
334
- RoutesAdjacency_RoutesEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join();
335
- });
336
- return writer;
337
- },
338
-
339
- decode(input: BinaryReader | Uint8Array, length?: number): RoutesAdjacency {
340
- const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
341
- const end = length === undefined ? reader.len : reader.pos + length;
342
- const message = createBaseRoutesAdjacency();
343
- while (reader.pos < end) {
344
- const tag = reader.uint32();
345
- switch (tag >>> 3) {
346
- case 1: {
347
- if (tag !== 10) {
348
- break;
349
- }
350
-
351
- const entry1 = RoutesAdjacency_RoutesEntry.decode(reader, reader.uint32());
352
- if (entry1.value !== undefined) {
353
- message.routes[entry1.key] = entry1.value;
354
- }
355
- continue;
356
- }
357
- }
358
- if ((tag & 7) === 4 || tag === 0) {
359
- break;
360
- }
361
- reader.skip(tag & 7);
362
- }
363
- return message;
364
- },
365
-
366
- fromJSON(object: any): RoutesAdjacency {
367
- return {
368
- routes: isObject(object.routes)
369
- ? Object.entries(object.routes).reduce<{ [key: string]: Route }>((acc, [key, value]) => {
370
- acc[key] = Route.fromJSON(value);
371
- return acc;
372
- }, {})
373
- : {},
374
- };
375
- },
376
-
377
- toJSON(message: RoutesAdjacency): unknown {
378
- const obj: any = {};
379
- if (message.routes) {
380
- const entries = Object.entries(message.routes);
381
- if (entries.length > 0) {
382
- obj.routes = {};
383
- entries.forEach(([k, v]) => {
384
- obj.routes[k] = Route.toJSON(v);
385
- });
386
- }
387
- }
388
- return obj;
389
- },
390
-
391
- create<I extends Exact<DeepPartial<RoutesAdjacency>, I>>(base?: I): RoutesAdjacency {
392
- return RoutesAdjacency.fromPartial(base ?? ({} as any));
393
- },
394
- fromPartial<I extends Exact<DeepPartial<RoutesAdjacency>, I>>(object: I): RoutesAdjacency {
395
- const message = createBaseRoutesAdjacency();
396
- message.routes = Object.entries(object.routes ?? {}).reduce<{ [key: string]: Route }>((acc, [key, value]) => {
397
- if (value !== undefined) {
398
- acc[key] = Route.fromPartial(value);
399
- }
400
- return acc;
401
- }, {});
402
- return message;
403
- },
404
- };
405
-
406
- function createBaseRoutesAdjacency_RoutesEntry(): RoutesAdjacency_RoutesEntry {
407
- return { key: "", value: undefined };
408
- }
409
-
410
- export const RoutesAdjacency_RoutesEntry: MessageFns<RoutesAdjacency_RoutesEntry> = {
411
- encode(message: RoutesAdjacency_RoutesEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
412
- if (message.key !== "") {
413
- writer.uint32(10).string(message.key);
414
- }
415
- if (message.value !== undefined) {
416
- Route.encode(message.value, writer.uint32(18).fork()).join();
417
- }
418
- return writer;
419
- },
420
-
421
- decode(input: BinaryReader | Uint8Array, length?: number): RoutesAdjacency_RoutesEntry {
422
- const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
423
- const end = length === undefined ? reader.len : reader.pos + length;
424
- const message = createBaseRoutesAdjacency_RoutesEntry();
425
- while (reader.pos < end) {
426
- const tag = reader.uint32();
427
- switch (tag >>> 3) {
428
- case 1: {
429
- if (tag !== 10) {
430
- break;
431
- }
432
-
433
- message.key = reader.string();
434
- continue;
435
- }
436
- case 2: {
437
- if (tag !== 18) {
438
- break;
439
- }
440
-
441
- message.value = Route.decode(reader, reader.uint32());
442
- continue;
443
- }
444
- }
445
- if ((tag & 7) === 4 || tag === 0) {
446
- break;
447
- }
448
- reader.skip(tag & 7);
449
- }
450
- return message;
451
- },
452
-
453
- fromJSON(object: any): RoutesAdjacency_RoutesEntry {
454
- return {
455
- key: isSet(object.key) ? globalThis.String(object.key) : "",
456
- value: isSet(object.value) ? Route.fromJSON(object.value) : undefined,
457
- };
458
- },
459
-
460
- toJSON(message: RoutesAdjacency_RoutesEntry): unknown {
461
- const obj: any = {};
462
- if (message.key !== "") {
463
- obj.key = message.key;
464
- }
465
- if (message.value !== undefined) {
466
- obj.value = Route.toJSON(message.value);
467
- }
468
- return obj;
469
- },
470
-
471
- create<I extends Exact<DeepPartial<RoutesAdjacency_RoutesEntry>, I>>(base?: I): RoutesAdjacency_RoutesEntry {
472
- return RoutesAdjacency_RoutesEntry.fromPartial(base ?? ({} as any));
473
- },
474
- fromPartial<I extends Exact<DeepPartial<RoutesAdjacency_RoutesEntry>, I>>(object: I): RoutesAdjacency_RoutesEntry {
475
- const message = createBaseRoutesAdjacency_RoutesEntry();
476
- message.key = object.key ?? "";
477
- message.value = (object.value !== undefined && object.value !== null) ? Route.fromPartial(object.value) : undefined;
478
- return message;
479
- },
480
- };
481
-
482
320
  function createBaseTransfer(): Transfer {
483
321
  return { destination: 0, type: 0, minTransferTime: undefined };
484
322
  }
@@ -492,7 +330,7 @@ export const Transfer: MessageFns<Transfer> = {
492
330
  writer.uint32(16).int32(message.type);
493
331
  }
494
332
  if (message.minTransferTime !== undefined) {
495
- writer.uint32(24).int32(message.minTransferTime);
333
+ writer.uint32(24).uint32(message.minTransferTime);
496
334
  }
497
335
  return writer;
498
336
  },
@@ -525,7 +363,7 @@ export const Transfer: MessageFns<Transfer> = {
525
363
  break;
526
364
  }
527
365
 
528
- message.minTransferTime = reader.int32();
366
+ message.minTransferTime = reader.uint32();
529
367
  continue;
530
368
  }
531
369
  }
@@ -613,8 +451,8 @@ export const StopsAdjacency: MessageFns<StopsAdjacency> = {
613
451
  fromJSON(object: any): StopsAdjacency {
614
452
  return {
615
453
  stops: isObject(object.stops)
616
- ? Object.entries(object.stops).reduce<{ [key: string]: StopsAdjacency_StopAdjacency }>((acc, [key, value]) => {
617
- acc[key] = StopsAdjacency_StopAdjacency.fromJSON(value);
454
+ ? Object.entries(object.stops).reduce<{ [key: number]: StopsAdjacency_StopAdjacency }>((acc, [key, value]) => {
455
+ acc[globalThis.Number(key)] = StopsAdjacency_StopAdjacency.fromJSON(value);
618
456
  return acc;
619
457
  }, {})
620
458
  : {},
@@ -640,10 +478,10 @@ export const StopsAdjacency: MessageFns<StopsAdjacency> = {
640
478
  },
641
479
  fromPartial<I extends Exact<DeepPartial<StopsAdjacency>, I>>(object: I): StopsAdjacency {
642
480
  const message = createBaseStopsAdjacency();
643
- message.stops = Object.entries(object.stops ?? {}).reduce<{ [key: string]: StopsAdjacency_StopAdjacency }>(
481
+ message.stops = Object.entries(object.stops ?? {}).reduce<{ [key: number]: StopsAdjacency_StopAdjacency }>(
644
482
  (acc, [key, value]) => {
645
483
  if (value !== undefined) {
646
- acc[key] = StopsAdjacency_StopAdjacency.fromPartial(value);
484
+ acc[globalThis.Number(key)] = StopsAdjacency_StopAdjacency.fromPartial(value);
647
485
  }
648
486
  return acc;
649
487
  },
@@ -662,9 +500,11 @@ export const StopsAdjacency_StopAdjacency: MessageFns<StopsAdjacency_StopAdjacen
662
500
  for (const v of message.transfers) {
663
501
  Transfer.encode(v!, writer.uint32(10).fork()).join();
664
502
  }
503
+ writer.uint32(18).fork();
665
504
  for (const v of message.routes) {
666
- writer.uint32(18).string(v!);
505
+ writer.int32(v);
667
506
  }
507
+ writer.join();
668
508
  return writer;
669
509
  },
670
510
 
@@ -684,12 +524,22 @@ export const StopsAdjacency_StopAdjacency: MessageFns<StopsAdjacency_StopAdjacen
684
524
  continue;
685
525
  }
686
526
  case 2: {
687
- if (tag !== 18) {
688
- break;
527
+ if (tag === 16) {
528
+ message.routes.push(reader.int32());
529
+
530
+ continue;
689
531
  }
690
532
 
691
- message.routes.push(reader.string());
692
- continue;
533
+ if (tag === 18) {
534
+ const end2 = reader.uint32() + reader.pos;
535
+ while (reader.pos < end2) {
536
+ message.routes.push(reader.int32());
537
+ }
538
+
539
+ continue;
540
+ }
541
+
542
+ break;
693
543
  }
694
544
  }
695
545
  if ((tag & 7) === 4 || tag === 0) {
@@ -705,7 +555,7 @@ export const StopsAdjacency_StopAdjacency: MessageFns<StopsAdjacency_StopAdjacen
705
555
  transfers: globalThis.Array.isArray(object?.transfers)
706
556
  ? object.transfers.map((e: any) => Transfer.fromJSON(e))
707
557
  : [],
708
- routes: globalThis.Array.isArray(object?.routes) ? object.routes.map((e: any) => globalThis.String(e)) : [],
558
+ routes: globalThis.Array.isArray(object?.routes) ? object.routes.map((e: any) => globalThis.Number(e)) : [],
709
559
  };
710
560
  },
711
561
 
@@ -715,7 +565,7 @@ export const StopsAdjacency_StopAdjacency: MessageFns<StopsAdjacency_StopAdjacen
715
565
  obj.transfers = message.transfers.map((e) => Transfer.toJSON(e));
716
566
  }
717
567
  if (message.routes?.length) {
718
- obj.routes = message.routes;
568
+ obj.routes = message.routes.map((e) => Math.round(e));
719
569
  }
720
570
  return obj;
721
571
  },
@@ -732,13 +582,13 @@ export const StopsAdjacency_StopAdjacency: MessageFns<StopsAdjacency_StopAdjacen
732
582
  };
733
583
 
734
584
  function createBaseStopsAdjacency_StopsEntry(): StopsAdjacency_StopsEntry {
735
- return { key: "", value: undefined };
585
+ return { key: 0, value: undefined };
736
586
  }
737
587
 
738
588
  export const StopsAdjacency_StopsEntry: MessageFns<StopsAdjacency_StopsEntry> = {
739
589
  encode(message: StopsAdjacency_StopsEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
740
- if (message.key !== "") {
741
- writer.uint32(10).string(message.key);
590
+ if (message.key !== 0) {
591
+ writer.uint32(8).uint32(message.key);
742
592
  }
743
593
  if (message.value !== undefined) {
744
594
  StopsAdjacency_StopAdjacency.encode(message.value, writer.uint32(18).fork()).join();
@@ -754,11 +604,11 @@ export const StopsAdjacency_StopsEntry: MessageFns<StopsAdjacency_StopsEntry> =
754
604
  const tag = reader.uint32();
755
605
  switch (tag >>> 3) {
756
606
  case 1: {
757
- if (tag !== 10) {
607
+ if (tag !== 8) {
758
608
  break;
759
609
  }
760
610
 
761
- message.key = reader.string();
611
+ message.key = reader.uint32();
762
612
  continue;
763
613
  }
764
614
  case 2: {
@@ -780,15 +630,15 @@ export const StopsAdjacency_StopsEntry: MessageFns<StopsAdjacency_StopsEntry> =
780
630
 
781
631
  fromJSON(object: any): StopsAdjacency_StopsEntry {
782
632
  return {
783
- key: isSet(object.key) ? globalThis.String(object.key) : "",
633
+ key: isSet(object.key) ? globalThis.Number(object.key) : 0,
784
634
  value: isSet(object.value) ? StopsAdjacency_StopAdjacency.fromJSON(object.value) : undefined,
785
635
  };
786
636
  },
787
637
 
788
638
  toJSON(message: StopsAdjacency_StopsEntry): unknown {
789
639
  const obj: any = {};
790
- if (message.key !== "") {
791
- obj.key = message.key;
640
+ if (message.key !== 0) {
641
+ obj.key = Math.round(message.key);
792
642
  }
793
643
  if (message.value !== undefined) {
794
644
  obj.value = StopsAdjacency_StopAdjacency.toJSON(message.value);
@@ -801,7 +651,7 @@ export const StopsAdjacency_StopsEntry: MessageFns<StopsAdjacency_StopsEntry> =
801
651
  },
802
652
  fromPartial<I extends Exact<DeepPartial<StopsAdjacency_StopsEntry>, I>>(object: I): StopsAdjacency_StopsEntry {
803
653
  const message = createBaseStopsAdjacency_StopsEntry();
804
- message.key = object.key ?? "";
654
+ message.key = object.key ?? 0;
805
655
  message.value = (object.value !== undefined && object.value !== null)
806
656
  ? StopsAdjacency_StopAdjacency.fromPartial(object.value)
807
657
  : undefined;
@@ -810,7 +660,7 @@ export const StopsAdjacency_StopsEntry: MessageFns<StopsAdjacency_StopsEntry> =
810
660
  };
811
661
 
812
662
  function createBaseServiceRoute(): ServiceRoute {
813
- return { type: 0, name: "" };
663
+ return { type: 0, name: "", routes: [] };
814
664
  }
815
665
 
816
666
  export const ServiceRoute: MessageFns<ServiceRoute> = {
@@ -821,6 +671,11 @@ export const ServiceRoute: MessageFns<ServiceRoute> = {
821
671
  if (message.name !== "") {
822
672
  writer.uint32(18).string(message.name);
823
673
  }
674
+ writer.uint32(26).fork();
675
+ for (const v of message.routes) {
676
+ writer.int32(v);
677
+ }
678
+ writer.join();
824
679
  return writer;
825
680
  },
826
681
 
@@ -847,6 +702,24 @@ export const ServiceRoute: MessageFns<ServiceRoute> = {
847
702
  message.name = reader.string();
848
703
  continue;
849
704
  }
705
+ case 3: {
706
+ if (tag === 24) {
707
+ message.routes.push(reader.int32());
708
+
709
+ continue;
710
+ }
711
+
712
+ if (tag === 26) {
713
+ const end2 = reader.uint32() + reader.pos;
714
+ while (reader.pos < end2) {
715
+ message.routes.push(reader.int32());
716
+ }
717
+
718
+ continue;
719
+ }
720
+
721
+ break;
722
+ }
850
723
  }
851
724
  if ((tag & 7) === 4 || tag === 0) {
852
725
  break;
@@ -860,6 +733,7 @@ export const ServiceRoute: MessageFns<ServiceRoute> = {
860
733
  return {
861
734
  type: isSet(object.type) ? routeTypeFromJSON(object.type) : 0,
862
735
  name: isSet(object.name) ? globalThis.String(object.name) : "",
736
+ routes: globalThis.Array.isArray(object?.routes) ? object.routes.map((e: any) => globalThis.Number(e)) : [],
863
737
  };
864
738
  },
865
739
 
@@ -871,6 +745,9 @@ export const ServiceRoute: MessageFns<ServiceRoute> = {
871
745
  if (message.name !== "") {
872
746
  obj.name = message.name;
873
747
  }
748
+ if (message.routes?.length) {
749
+ obj.routes = message.routes.map((e) => Math.round(e));
750
+ }
874
751
  return obj;
875
752
  },
876
753
 
@@ -881,6 +758,7 @@ export const ServiceRoute: MessageFns<ServiceRoute> = {
881
758
  const message = createBaseServiceRoute();
882
759
  message.type = object.type ?? 0;
883
760
  message.name = object.name ?? "";
761
+ message.routes = object.routes?.map((e) => e) || [];
884
762
  return message;
885
763
  },
886
764
  };
@@ -1046,7 +924,7 @@ export const ServiceRoutesMap_RoutesEntry: MessageFns<ServiceRoutesMap_RoutesEnt
1046
924
  };
1047
925
 
1048
926
  function createBaseTimetable(): Timetable {
1049
- return { version: "", stopsAdjacency: undefined, routesAdjacency: undefined, routes: undefined };
927
+ return { version: "", stopsAdjacency: undefined, routesAdjacency: [], routes: undefined };
1050
928
  }
1051
929
 
1052
930
  export const Timetable: MessageFns<Timetable> = {
@@ -1057,8 +935,8 @@ export const Timetable: MessageFns<Timetable> = {
1057
935
  if (message.stopsAdjacency !== undefined) {
1058
936
  StopsAdjacency.encode(message.stopsAdjacency, writer.uint32(18).fork()).join();
1059
937
  }
1060
- if (message.routesAdjacency !== undefined) {
1061
- RoutesAdjacency.encode(message.routesAdjacency, writer.uint32(26).fork()).join();
938
+ for (const v of message.routesAdjacency) {
939
+ Route.encode(v!, writer.uint32(26).fork()).join();
1062
940
  }
1063
941
  if (message.routes !== undefined) {
1064
942
  ServiceRoutesMap.encode(message.routes, writer.uint32(34).fork()).join();
@@ -1094,7 +972,7 @@ export const Timetable: MessageFns<Timetable> = {
1094
972
  break;
1095
973
  }
1096
974
 
1097
- message.routesAdjacency = RoutesAdjacency.decode(reader, reader.uint32());
975
+ message.routesAdjacency.push(Route.decode(reader, reader.uint32()));
1098
976
  continue;
1099
977
  }
1100
978
  case 4: {
@@ -1118,7 +996,9 @@ export const Timetable: MessageFns<Timetable> = {
1118
996
  return {
1119
997
  version: isSet(object.version) ? globalThis.String(object.version) : "",
1120
998
  stopsAdjacency: isSet(object.stopsAdjacency) ? StopsAdjacency.fromJSON(object.stopsAdjacency) : undefined,
1121
- routesAdjacency: isSet(object.routesAdjacency) ? RoutesAdjacency.fromJSON(object.routesAdjacency) : undefined,
999
+ routesAdjacency: globalThis.Array.isArray(object?.routesAdjacency)
1000
+ ? object.routesAdjacency.map((e: any) => Route.fromJSON(e))
1001
+ : [],
1122
1002
  routes: isSet(object.routes) ? ServiceRoutesMap.fromJSON(object.routes) : undefined,
1123
1003
  };
1124
1004
  },
@@ -1131,8 +1011,8 @@ export const Timetable: MessageFns<Timetable> = {
1131
1011
  if (message.stopsAdjacency !== undefined) {
1132
1012
  obj.stopsAdjacency = StopsAdjacency.toJSON(message.stopsAdjacency);
1133
1013
  }
1134
- if (message.routesAdjacency !== undefined) {
1135
- obj.routesAdjacency = RoutesAdjacency.toJSON(message.routesAdjacency);
1014
+ if (message.routesAdjacency?.length) {
1015
+ obj.routesAdjacency = message.routesAdjacency.map((e) => Route.toJSON(e));
1136
1016
  }
1137
1017
  if (message.routes !== undefined) {
1138
1018
  obj.routes = ServiceRoutesMap.toJSON(message.routes);
@@ -1149,9 +1029,7 @@ export const Timetable: MessageFns<Timetable> = {
1149
1029
  message.stopsAdjacency = (object.stopsAdjacency !== undefined && object.stopsAdjacency !== null)
1150
1030
  ? StopsAdjacency.fromPartial(object.stopsAdjacency)
1151
1031
  : undefined;
1152
- message.routesAdjacency = (object.routesAdjacency !== undefined && object.routesAdjacency !== null)
1153
- ? RoutesAdjacency.fromPartial(object.routesAdjacency)
1154
- : undefined;
1032
+ message.routesAdjacency = object.routesAdjacency?.map((e) => Route.fromPartial(e)) || [];
1155
1033
  message.routes = (object.routes !== undefined && object.routes !== null)
1156
1034
  ? ServiceRoutesMap.fromPartial(object.routes)
1157
1035
  : undefined;
@@ -9,7 +9,7 @@ import { ServiceRouteId } from './timetable.js';
9
9
  * This one is used for identifying groups of trips
10
10
  * from a service route sharing the same list of stops.
11
11
  */
12
- export type RouteId = string;
12
+ export type RouteId = number;
13
13
 
14
14
  /**
15
15
  * Details about the pickup and drop-off modalities at each stop in each trip of a route.
@@ -65,14 +65,16 @@ export class Route {
65
65
  */
66
66
  private readonly stopTimes: Uint16Array;
67
67
  /**
68
- * PickUp and DropOff types represented as a binary Uint8Array.
69
- * Values:
68
+ * PickUp and DropOff types represented as a 2-bit encoded Uint8Array.
69
+ * Values (2 bits each):
70
70
  * 0: REGULAR
71
71
  * 1: NOT_AVAILABLE
72
72
  * 2: MUST_PHONE_AGENCY
73
73
  * 3: MUST_COORDINATE_WITH_DRIVER
74
- * Format: [pickupTypeStop1, dropOffTypeStop1, pickupTypeStop2, dropOffTypeStop2, etc.]
75
- * TODO: Encode 4 values instead of 1 in 8 bits.
74
+ *
75
+ * Encoding format: Each byte contains 2 pickup/drop-off pairs (4 bits each)
76
+ * Bit layout per byte: [pickup_1 (2 bits)][drop_off_1 (2 bits)][pickup_0 (2 bits)][drop_off_0 (2 bits)]
77
+ * Example: For stops 0 and 1 in a trip, one byte encodes all 4 values
76
78
  */
77
79
  private readonly pickUpDropOffTypes: Uint8Array;
78
80
  /**
@@ -225,14 +227,20 @@ export class Route {
225
227
  * @returns The pick-up type at the specified stop and trip.
226
228
  */
227
229
  pickUpTypeFrom(stopId: StopId, tripIndex: TripIndex): PickUpDropOffType {
228
- const pickUpIndex =
229
- (tripIndex * this.stops.length + this.stopIndex(stopId)) * 2;
230
- const pickUpValue = this.pickUpDropOffTypes[pickUpIndex];
231
- if (pickUpValue === undefined) {
230
+ const globalIndex = tripIndex * this.stops.length + this.stopIndex(stopId);
231
+ const byteIndex = Math.floor(globalIndex / 2);
232
+ const isSecondPair = globalIndex % 2 === 1;
233
+
234
+ const byte = this.pickUpDropOffTypes[byteIndex];
235
+ if (byte === undefined) {
232
236
  throw new Error(
233
237
  `Pick up type not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`,
234
238
  );
235
239
  }
240
+
241
+ const pickUpValue = isSecondPair
242
+ ? (byte >> 6) & 0x03 // Upper 2 bits for second pair
243
+ : (byte >> 2) & 0x03; // Bits 2-3 for first pair
236
244
  return toPickupDropOffType(pickUpValue);
237
245
  }
238
246
 
@@ -244,14 +252,20 @@ export class Route {
244
252
  * @returns The drop-off type at the specified stop and trip.
245
253
  */
246
254
  dropOffTypeAt(stopId: StopId, tripIndex: TripIndex): PickUpDropOffType {
247
- const dropOffIndex =
248
- (tripIndex * this.stops.length + this.stopIndex(stopId)) * 2 + 1;
249
- const dropOffValue = this.pickUpDropOffTypes[dropOffIndex];
250
- if (dropOffValue === undefined) {
255
+ const globalIndex = tripIndex * this.stops.length + this.stopIndex(stopId);
256
+ const byteIndex = Math.floor(globalIndex / 2);
257
+ const isSecondPair = globalIndex % 2 === 1;
258
+
259
+ const byte = this.pickUpDropOffTypes[byteIndex];
260
+ if (byte === undefined) {
251
261
  throw new Error(
252
262
  `Drop off type not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`,
253
263
  );
254
264
  }
265
+
266
+ const dropOffValue = isSecondPair
267
+ ? (byte >> 4) & 0x03 // Bits 4-5 for second pair
268
+ : byte & 0x03; // Lower 2 bits for first pair
255
269
  return toPickupDropOffType(dropOffValue);
256
270
  }
257
271
 
@@ -13,8 +13,6 @@ import {
13
13
  import { Timetable as ProtoTimetable } from './proto/timetable.js';
14
14
  import { Route, RouteId } from './route.js';
15
15
 
16
- export type RoutesAdjacency = Map<RouteId, Route>;
17
-
18
16
  export type TransferType =
19
17
  | 'RECOMMENDED'
20
18
  | 'GUARANTEED'
@@ -49,10 +47,12 @@ export type RouteType =
49
47
  | 'TROLLEYBUS'
50
48
  | 'MONORAIL';
51
49
 
52
- export type ServiceRoute = {
50
+ type ServiceRoute = {
53
51
  type: RouteType;
54
52
  name: string;
53
+ routes: RouteId[];
55
54
  };
55
+ export type ServiceRouteInfo = Omit<ServiceRoute, 'routes'>;
56
56
 
57
57
  // A service refers to a collection of trips that are displayed to riders as a single service.
58
58
  // As opposed to a route which consists of the subset of trips from a service which shares the same list of stops.
@@ -72,19 +72,19 @@ export const ALL_TRANSPORT_MODES: Set<RouteType> = new Set([
72
72
  'MONORAIL',
73
73
  ]);
74
74
 
75
- export const CURRENT_VERSION = '0.0.3';
75
+ export const CURRENT_VERSION = '0.0.5';
76
76
 
77
77
  /**
78
78
  * The internal transit timetable format.
79
79
  */
80
80
  export class Timetable {
81
81
  private readonly stopsAdjacency: StopsAdjacency;
82
- private readonly routesAdjacency: RoutesAdjacency;
82
+ private readonly routesAdjacency: Route[];
83
83
  private readonly routes: ServiceRoutesMap;
84
84
 
85
85
  constructor(
86
86
  stopsAdjacency: StopsAdjacency,
87
- routesAdjacency: RoutesAdjacency,
87
+ routesAdjacency: Route[],
88
88
  routes: ServiceRoutesMap,
89
89
  ) {
90
90
  this.stopsAdjacency = stopsAdjacency;
@@ -126,10 +126,7 @@ export class Timetable {
126
126
  return new Timetable(
127
127
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
128
128
  deserializeStopsAdjacency(protoTimetable.stopsAdjacency!),
129
- deserializeRoutesAdjacency(
130
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
131
- protoTimetable.routesAdjacency!,
132
- ),
129
+ deserializeRoutesAdjacency(protoTimetable.routesAdjacency),
133
130
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
134
131
  deserializeServiceRoutesMap(protoTimetable.routes!),
135
132
  );
@@ -143,7 +140,7 @@ export class Timetable {
143
140
  * or undefined if no such route exists.
144
141
  */
145
142
  getRoute(routeId: RouteId): Route | undefined {
146
- return this.routesAdjacency.get(routeId);
143
+ return this.routesAdjacency[routeId];
147
144
  }
148
145
 
149
146
  /**
@@ -164,9 +161,16 @@ export class Timetable {
164
161
  * @param route - The route for which the service route is to be retrieved.
165
162
  * @returns The service route corresponding to the provided route.
166
163
  */
167
- getServiceRoute(route: Route): ServiceRoute {
168
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
169
- return this.routes.get(route.serviceRoute())!;
164
+ getServiceRouteInfo(route: Route): ServiceRouteInfo {
165
+ const serviceRoute = this.routes.get(route.serviceRoute());
166
+ if (!serviceRoute) {
167
+ throw new Error(
168
+ `Service route not found for route ID: ${route.serviceRoute()}`,
169
+ );
170
+ }
171
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
172
+ const { routes, ...serviceRouteInfo } = serviceRoute;
173
+ return serviceRouteInfo;
170
174
  }
171
175
 
172
176
  /**
@@ -182,7 +186,7 @@ export class Timetable {
182
186
  }
183
187
  const routes: Route[] = [];
184
188
  for (const routeId of stopData.routes) {
185
- const route = this.routesAdjacency.get(routeId);
189
+ const route = this.routesAdjacency[routeId];
186
190
  if (route) {
187
191
  routes.push(route);
188
192
  }
@@ -207,7 +211,7 @@ export class Timetable {
207
211
  for (const originStop of fromStops) {
208
212
  const validRoutes = this.routesPassingThrough(originStop).filter(
209
213
  (route) => {
210
- const serviceRoute = this.getServiceRoute(route);
214
+ const serviceRoute = this.getServiceRouteInfo(route);
211
215
  return transportModes.has(serviceRoute.type);
212
216
  },
213
217
  );