minotor 1.0.7 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/README.md +3 -2
  3. package/dist/cli.mjs +604 -531
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/gtfs/stops.d.ts +19 -5
  6. package/dist/gtfs/transfers.d.ts +5 -4
  7. package/dist/gtfs/trips.d.ts +7 -5
  8. package/dist/gtfs/utils.d.ts +7 -8
  9. package/dist/parser.cjs.js +569 -501
  10. package/dist/parser.cjs.js.map +1 -1
  11. package/dist/parser.esm.js +569 -501
  12. package/dist/parser.esm.js.map +1 -1
  13. package/dist/router.cjs.js +1 -1
  14. package/dist/router.cjs.js.map +1 -1
  15. package/dist/router.d.ts +3 -3
  16. package/dist/router.esm.js +1 -1
  17. package/dist/router.esm.js.map +1 -1
  18. package/dist/router.umd.js +1 -1
  19. package/dist/router.umd.js.map +1 -1
  20. package/dist/routing/__tests__/route.test.d.ts +1 -0
  21. package/dist/routing/query.d.ts +7 -7
  22. package/dist/routing/result.d.ts +3 -3
  23. package/dist/routing/route.d.ts +1 -0
  24. package/dist/stops/proto/stops.d.ts +5 -4
  25. package/dist/stops/stops.d.ts +10 -1
  26. package/dist/stops/stopsIndex.d.ts +21 -4
  27. package/dist/timetable/proto/timetable.d.ts +21 -18
  28. package/dist/timetable/timetable.d.ts +38 -14
  29. package/package.json +4 -3
  30. package/src/cli/repl.ts +13 -10
  31. package/src/gtfs/__tests__/parser.test.ts +50 -579
  32. package/src/gtfs/__tests__/stops.test.ts +181 -112
  33. package/src/gtfs/__tests__/transfers.test.ts +170 -12
  34. package/src/gtfs/__tests__/trips.test.ts +212 -141
  35. package/src/gtfs/__tests__/utils.test.ts +4 -4
  36. package/src/gtfs/parser.ts +22 -13
  37. package/src/gtfs/stops.ts +63 -28
  38. package/src/gtfs/transfers.ts +14 -6
  39. package/src/gtfs/trips.ts +110 -47
  40. package/src/gtfs/utils.ts +11 -11
  41. package/src/router.ts +2 -3
  42. package/src/routing/__tests__/route.test.ts +112 -0
  43. package/src/routing/__tests__/router.test.ts +234 -244
  44. package/src/routing/query.ts +7 -7
  45. package/src/routing/result.ts +9 -6
  46. package/src/routing/route.ts +11 -0
  47. package/src/routing/router.ts +26 -24
  48. package/src/stops/__tests__/io.test.ts +9 -8
  49. package/src/stops/__tests__/stopFinder.test.ts +45 -36
  50. package/src/stops/io.ts +8 -5
  51. package/src/stops/proto/stops.proto +8 -7
  52. package/src/stops/proto/stops.ts +68 -38
  53. package/src/stops/stops.ts +13 -1
  54. package/src/stops/stopsIndex.ts +50 -7
  55. package/src/timetable/__tests__/io.test.ts +40 -49
  56. package/src/timetable/__tests__/timetable.test.ts +50 -58
  57. package/src/timetable/io.ts +69 -56
  58. package/src/timetable/proto/timetable.proto +22 -17
  59. package/src/timetable/proto/timetable.ts +94 -184
  60. package/src/timetable/timetable.ts +62 -29
@@ -9,45 +9,6 @@ import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
9
9
 
10
10
  export const protobufPackage = "minotor.timetable";
11
11
 
12
- export enum PickUpDropOffType {
13
- NOT_AVAILABLE = 0,
14
- MUST_PHONE_AGENCY = 1,
15
- MUST_COORDINATE_WITH_DRIVER = 2,
16
- UNRECOGNIZED = -1,
17
- }
18
-
19
- export function pickUpDropOffTypeFromJSON(object: any): PickUpDropOffType {
20
- switch (object) {
21
- case 0:
22
- case "NOT_AVAILABLE":
23
- return PickUpDropOffType.NOT_AVAILABLE;
24
- case 1:
25
- case "MUST_PHONE_AGENCY":
26
- return PickUpDropOffType.MUST_PHONE_AGENCY;
27
- case 2:
28
- case "MUST_COORDINATE_WITH_DRIVER":
29
- return PickUpDropOffType.MUST_COORDINATE_WITH_DRIVER;
30
- case -1:
31
- case "UNRECOGNIZED":
32
- default:
33
- return PickUpDropOffType.UNRECOGNIZED;
34
- }
35
- }
36
-
37
- export function pickUpDropOffTypeToJSON(object: PickUpDropOffType): string {
38
- switch (object) {
39
- case PickUpDropOffType.NOT_AVAILABLE:
40
- return "NOT_AVAILABLE";
41
- case PickUpDropOffType.MUST_PHONE_AGENCY:
42
- return "MUST_PHONE_AGENCY";
43
- case PickUpDropOffType.MUST_COORDINATE_WITH_DRIVER:
44
- return "MUST_COORDINATE_WITH_DRIVER";
45
- case PickUpDropOffType.UNRECOGNIZED:
46
- default:
47
- return "UNRECOGNIZED";
48
- }
49
- }
50
-
51
12
  export enum TransferType {
52
13
  RECOMMENDED_TRANSFER_POINT = 0,
53
14
  TIMED_TRANSFER = 1,
@@ -174,16 +135,27 @@ export function routeTypeToJSON(object: RouteType): string {
174
135
  }
175
136
  }
176
137
 
177
- export interface StopTimes {
178
- arrival: number;
179
- departure: number;
180
- pickUpType?: PickUpDropOffType | undefined;
181
- dropOffType?: PickUpDropOffType | undefined;
182
- }
183
-
184
138
  export interface Route {
185
- stopTimes: StopTimes[];
186
- stops: string[];
139
+ /**
140
+ * Arrivals and departures encoded as a 32 bit uint array.
141
+ * Format: [arrival1, departure1, arrival2, departure2, etc.]
142
+ */
143
+ stopTimes: Uint8Array;
144
+ /**
145
+ * PickUp and DropOff types represented as an 8 bit uint array.
146
+ * Values:
147
+ * 0: REGULAR
148
+ * 1: NOT_AVAILABLE
149
+ * 2: MUST_PHONE_AGENCY
150
+ * 3: MUST_COORDINATE_WITH_DRIVER
151
+ * Format: [pickupTypeStop1, dropOffTypeStop1, pickupTypeStop2, dropOffTypeStop2, etc.]
152
+ */
153
+ pickUpDropOffTypes: Uint8Array;
154
+ /**
155
+ * Stops encoded as a 32 bit uint array.
156
+ * Format: [stop1, stop2, stop3, etc.]
157
+ */
158
+ stops: Uint8Array;
187
159
  serviceRouteId: string;
188
160
  }
189
161
 
@@ -197,7 +169,7 @@ export interface RoutesAdjacency_RoutesEntry {
197
169
  }
198
170
 
199
171
  export interface Transfer {
200
- destination: string;
172
+ destination: number;
201
173
  type: TransferType;
202
174
  minTransferTime?: number | undefined;
203
175
  }
@@ -237,128 +209,28 @@ export interface Timetable {
237
209
  routes: ServiceRoutesMap | undefined;
238
210
  }
239
211
 
240
- function createBaseStopTimes(): StopTimes {
241
- return { arrival: 0, departure: 0, pickUpType: undefined, dropOffType: undefined };
242
- }
243
-
244
- export const StopTimes: MessageFns<StopTimes> = {
245
- encode(message: StopTimes, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
246
- if (message.arrival !== 0) {
247
- writer.uint32(8).int32(message.arrival);
248
- }
249
- if (message.departure !== 0) {
250
- writer.uint32(16).int32(message.departure);
251
- }
252
- if (message.pickUpType !== undefined) {
253
- writer.uint32(24).int32(message.pickUpType);
254
- }
255
- if (message.dropOffType !== undefined) {
256
- writer.uint32(32).int32(message.dropOffType);
257
- }
258
- return writer;
259
- },
260
-
261
- decode(input: BinaryReader | Uint8Array, length?: number): StopTimes {
262
- const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
263
- let end = length === undefined ? reader.len : reader.pos + length;
264
- const message = createBaseStopTimes();
265
- while (reader.pos < end) {
266
- const tag = reader.uint32();
267
- switch (tag >>> 3) {
268
- case 1: {
269
- if (tag !== 8) {
270
- break;
271
- }
272
-
273
- message.arrival = reader.int32();
274
- continue;
275
- }
276
- case 2: {
277
- if (tag !== 16) {
278
- break;
279
- }
280
-
281
- message.departure = reader.int32();
282
- continue;
283
- }
284
- case 3: {
285
- if (tag !== 24) {
286
- break;
287
- }
288
-
289
- message.pickUpType = reader.int32() as any;
290
- continue;
291
- }
292
- case 4: {
293
- if (tag !== 32) {
294
- break;
295
- }
296
-
297
- message.dropOffType = reader.int32() as any;
298
- continue;
299
- }
300
- }
301
- if ((tag & 7) === 4 || tag === 0) {
302
- break;
303
- }
304
- reader.skip(tag & 7);
305
- }
306
- return message;
307
- },
308
-
309
- fromJSON(object: any): StopTimes {
310
- return {
311
- arrival: isSet(object.arrival) ? globalThis.Number(object.arrival) : 0,
312
- departure: isSet(object.departure) ? globalThis.Number(object.departure) : 0,
313
- pickUpType: isSet(object.pickUpType) ? pickUpDropOffTypeFromJSON(object.pickUpType) : undefined,
314
- dropOffType: isSet(object.dropOffType) ? pickUpDropOffTypeFromJSON(object.dropOffType) : undefined,
315
- };
316
- },
317
-
318
- toJSON(message: StopTimes): unknown {
319
- const obj: any = {};
320
- if (message.arrival !== 0) {
321
- obj.arrival = Math.round(message.arrival);
322
- }
323
- if (message.departure !== 0) {
324
- obj.departure = Math.round(message.departure);
325
- }
326
- if (message.pickUpType !== undefined) {
327
- obj.pickUpType = pickUpDropOffTypeToJSON(message.pickUpType);
328
- }
329
- if (message.dropOffType !== undefined) {
330
- obj.dropOffType = pickUpDropOffTypeToJSON(message.dropOffType);
331
- }
332
- return obj;
333
- },
334
-
335
- create<I extends Exact<DeepPartial<StopTimes>, I>>(base?: I): StopTimes {
336
- return StopTimes.fromPartial(base ?? ({} as any));
337
- },
338
- fromPartial<I extends Exact<DeepPartial<StopTimes>, I>>(object: I): StopTimes {
339
- const message = createBaseStopTimes();
340
- message.arrival = object.arrival ?? 0;
341
- message.departure = object.departure ?? 0;
342
- message.pickUpType = object.pickUpType ?? undefined;
343
- message.dropOffType = object.dropOffType ?? undefined;
344
- return message;
345
- },
346
- };
347
-
348
212
  function createBaseRoute(): Route {
349
- return { stopTimes: [], stops: [], serviceRouteId: "" };
213
+ return {
214
+ stopTimes: new Uint8Array(0),
215
+ pickUpDropOffTypes: new Uint8Array(0),
216
+ stops: new Uint8Array(0),
217
+ serviceRouteId: "",
218
+ };
350
219
  }
351
220
 
352
221
  export const Route: MessageFns<Route> = {
353
222
  encode(message: Route, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
354
- for (const v of message.stopTimes) {
355
- StopTimes.encode(v!, writer.uint32(10).fork()).join();
223
+ if (message.stopTimes.length !== 0) {
224
+ writer.uint32(10).bytes(message.stopTimes);
356
225
  }
357
- for (const v of message.stops) {
358
- writer.uint32(18).string(v!);
226
+ if (message.pickUpDropOffTypes.length !== 0) {
227
+ writer.uint32(18).bytes(message.pickUpDropOffTypes);
228
+ }
229
+ if (message.stops.length !== 0) {
230
+ writer.uint32(26).bytes(message.stops);
359
231
  }
360
232
  if (message.serviceRouteId !== "") {
361
- writer.uint32(26).string(message.serviceRouteId);
233
+ writer.uint32(34).string(message.serviceRouteId);
362
234
  }
363
235
  return writer;
364
236
  },
@@ -375,7 +247,7 @@ export const Route: MessageFns<Route> = {
375
247
  break;
376
248
  }
377
249
 
378
- message.stopTimes.push(StopTimes.decode(reader, reader.uint32()));
250
+ message.stopTimes = reader.bytes();
379
251
  continue;
380
252
  }
381
253
  case 2: {
@@ -383,7 +255,7 @@ export const Route: MessageFns<Route> = {
383
255
  break;
384
256
  }
385
257
 
386
- message.stops.push(reader.string());
258
+ message.pickUpDropOffTypes = reader.bytes();
387
259
  continue;
388
260
  }
389
261
  case 3: {
@@ -391,6 +263,14 @@ export const Route: MessageFns<Route> = {
391
263
  break;
392
264
  }
393
265
 
266
+ message.stops = reader.bytes();
267
+ continue;
268
+ }
269
+ case 4: {
270
+ if (tag !== 34) {
271
+ break;
272
+ }
273
+
394
274
  message.serviceRouteId = reader.string();
395
275
  continue;
396
276
  }
@@ -405,21 +285,25 @@ export const Route: MessageFns<Route> = {
405
285
 
406
286
  fromJSON(object: any): Route {
407
287
  return {
408
- stopTimes: globalThis.Array.isArray(object?.stopTimes)
409
- ? object.stopTimes.map((e: any) => StopTimes.fromJSON(e))
410
- : [],
411
- stops: globalThis.Array.isArray(object?.stops) ? object.stops.map((e: any) => globalThis.String(e)) : [],
288
+ stopTimes: isSet(object.stopTimes) ? bytesFromBase64(object.stopTimes) : new Uint8Array(0),
289
+ pickUpDropOffTypes: isSet(object.pickUpDropOffTypes)
290
+ ? bytesFromBase64(object.pickUpDropOffTypes)
291
+ : new Uint8Array(0),
292
+ stops: isSet(object.stops) ? bytesFromBase64(object.stops) : new Uint8Array(0),
412
293
  serviceRouteId: isSet(object.serviceRouteId) ? globalThis.String(object.serviceRouteId) : "",
413
294
  };
414
295
  },
415
296
 
416
297
  toJSON(message: Route): unknown {
417
298
  const obj: any = {};
418
- if (message.stopTimes?.length) {
419
- obj.stopTimes = message.stopTimes.map((e) => StopTimes.toJSON(e));
299
+ if (message.stopTimes.length !== 0) {
300
+ obj.stopTimes = base64FromBytes(message.stopTimes);
420
301
  }
421
- if (message.stops?.length) {
422
- obj.stops = message.stops;
302
+ if (message.pickUpDropOffTypes.length !== 0) {
303
+ obj.pickUpDropOffTypes = base64FromBytes(message.pickUpDropOffTypes);
304
+ }
305
+ if (message.stops.length !== 0) {
306
+ obj.stops = base64FromBytes(message.stops);
423
307
  }
424
308
  if (message.serviceRouteId !== "") {
425
309
  obj.serviceRouteId = message.serviceRouteId;
@@ -432,8 +316,9 @@ export const Route: MessageFns<Route> = {
432
316
  },
433
317
  fromPartial<I extends Exact<DeepPartial<Route>, I>>(object: I): Route {
434
318
  const message = createBaseRoute();
435
- message.stopTimes = object.stopTimes?.map((e) => StopTimes.fromPartial(e)) || [];
436
- message.stops = object.stops?.map((e) => e) || [];
319
+ message.stopTimes = object.stopTimes ?? new Uint8Array(0);
320
+ message.pickUpDropOffTypes = object.pickUpDropOffTypes ?? new Uint8Array(0);
321
+ message.stops = object.stops ?? new Uint8Array(0);
437
322
  message.serviceRouteId = object.serviceRouteId ?? "";
438
323
  return message;
439
324
  },
@@ -595,13 +480,13 @@ export const RoutesAdjacency_RoutesEntry: MessageFns<RoutesAdjacency_RoutesEntry
595
480
  };
596
481
 
597
482
  function createBaseTransfer(): Transfer {
598
- return { destination: "", type: 0, minTransferTime: undefined };
483
+ return { destination: 0, type: 0, minTransferTime: undefined };
599
484
  }
600
485
 
601
486
  export const Transfer: MessageFns<Transfer> = {
602
487
  encode(message: Transfer, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
603
- if (message.destination !== "") {
604
- writer.uint32(10).string(message.destination);
488
+ if (message.destination !== 0) {
489
+ writer.uint32(8).uint32(message.destination);
605
490
  }
606
491
  if (message.type !== 0) {
607
492
  writer.uint32(16).int32(message.type);
@@ -620,11 +505,11 @@ export const Transfer: MessageFns<Transfer> = {
620
505
  const tag = reader.uint32();
621
506
  switch (tag >>> 3) {
622
507
  case 1: {
623
- if (tag !== 10) {
508
+ if (tag !== 8) {
624
509
  break;
625
510
  }
626
511
 
627
- message.destination = reader.string();
512
+ message.destination = reader.uint32();
628
513
  continue;
629
514
  }
630
515
  case 2: {
@@ -654,7 +539,7 @@ export const Transfer: MessageFns<Transfer> = {
654
539
 
655
540
  fromJSON(object: any): Transfer {
656
541
  return {
657
- destination: isSet(object.destination) ? globalThis.String(object.destination) : "",
542
+ destination: isSet(object.destination) ? globalThis.Number(object.destination) : 0,
658
543
  type: isSet(object.type) ? transferTypeFromJSON(object.type) : 0,
659
544
  minTransferTime: isSet(object.minTransferTime) ? globalThis.Number(object.minTransferTime) : undefined,
660
545
  };
@@ -662,8 +547,8 @@ export const Transfer: MessageFns<Transfer> = {
662
547
 
663
548
  toJSON(message: Transfer): unknown {
664
549
  const obj: any = {};
665
- if (message.destination !== "") {
666
- obj.destination = message.destination;
550
+ if (message.destination !== 0) {
551
+ obj.destination = Math.round(message.destination);
667
552
  }
668
553
  if (message.type !== 0) {
669
554
  obj.type = transferTypeToJSON(message.type);
@@ -679,7 +564,7 @@ export const Transfer: MessageFns<Transfer> = {
679
564
  },
680
565
  fromPartial<I extends Exact<DeepPartial<Transfer>, I>>(object: I): Transfer {
681
566
  const message = createBaseTransfer();
682
- message.destination = object.destination ?? "";
567
+ message.destination = object.destination ?? 0;
683
568
  message.type = object.type ?? 0;
684
569
  message.minTransferTime = object.minTransferTime ?? undefined;
685
570
  return message;
@@ -1274,6 +1159,31 @@ export const Timetable: MessageFns<Timetable> = {
1274
1159
  },
1275
1160
  };
1276
1161
 
1162
+ function bytesFromBase64(b64: string): Uint8Array {
1163
+ if ((globalThis as any).Buffer) {
1164
+ return Uint8Array.from(globalThis.Buffer.from(b64, "base64"));
1165
+ } else {
1166
+ const bin = globalThis.atob(b64);
1167
+ const arr = new Uint8Array(bin.length);
1168
+ for (let i = 0; i < bin.length; ++i) {
1169
+ arr[i] = bin.charCodeAt(i);
1170
+ }
1171
+ return arr;
1172
+ }
1173
+ }
1174
+
1175
+ function base64FromBytes(arr: Uint8Array): string {
1176
+ if ((globalThis as any).Buffer) {
1177
+ return globalThis.Buffer.from(arr).toString("base64");
1178
+ } else {
1179
+ const bin: string[] = [];
1180
+ arr.forEach((byte) => {
1181
+ bin.push(globalThis.String.fromCharCode(byte));
1182
+ });
1183
+ return globalThis.btoa(bin.join(""));
1184
+ }
1185
+ }
1186
+
1277
1187
  type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
1278
1188
 
1279
1189
  export type DeepPartial<T> = T extends Builtin ? T
@@ -13,29 +13,55 @@ import {
13
13
  import { Timetable as ProtoTimetable } from './proto/timetable.js';
14
14
  import { Time } from './time.js';
15
15
 
16
- export type PickUpDropOffType =
17
- | 'REGULAR'
18
- | 'NOT_AVAILABLE'
19
- | 'MUST_PHONE_AGENCY'
20
- | 'MUST_COORDINATE_WITH_DRIVER';
21
-
22
- export type StopTimes = {
23
- arrival: Time;
24
- departure: Time;
25
- pickUpType: PickUpDropOffType;
26
- dropOffType: PickUpDropOffType;
27
- };
16
+ // Identifies all trips of a given service route sharing the same list of stops.
28
17
  export type RouteId = string;
29
18
 
30
- export type IndexedStopId = {
31
- stopId: StopId;
32
- index: number;
33
- };
19
+ export const REGULAR = 0;
20
+ export const NOT_AVAILABLE = 1;
21
+ export const MUST_PHONE_AGENCY = 2;
22
+ export const MUST_COORDINATE_WITH_DRIVER = 3;
23
+
24
+ export type PickUpDropOffType =
25
+ | 0 // REGULAR
26
+ | 1 // NOT_AVAILABLE
27
+ | 2 // MUST_PHONE_AGENCY
28
+ | 3; // MUST_COORDINATE_WITH_DRIVER
29
+
34
30
  export type Route = {
35
- stopTimes: StopTimes[];
36
- stops: StopId[];
31
+ /**
32
+ * Arrivals and departures encoded as a binary array.
33
+ * Format: [arrival1, departure1, arrival2, departure2, etc.]
34
+ */
35
+ stopTimes: Uint32Array;
36
+ /**
37
+ * PickUp and DropOff types represented as a binary Uint8Array.
38
+ * Values:
39
+ * 0: REGULAR
40
+ * 1: NOT_AVAILABLE
41
+ * 2: MUST_PHONE_AGENCY
42
+ * 3: MUST_COORDINATE_WITH_DRIVER
43
+ * Format: [pickupTypeStop1, dropOffTypeStop1, pickupTypeStop2, dropOffTypeStop2, etc.]
44
+ */
45
+ pickUpDropOffTypes: Uint8Array;
46
+ /**
47
+ * A binary array of stopIds in the route.
48
+ * [stop1, stop2, stop3,...]
49
+ */
50
+ stops: Uint32Array;
51
+ /**
52
+ * A reverse mapping of each stop with their index in the route:
53
+ * {
54
+ * 4: 0,
55
+ * 5: 1,
56
+ * ...
57
+ * }
58
+ */
37
59
  stopIndices: Map<StopId, number>;
60
+ /**
61
+ * The identifier of the route as a service shown to users.
62
+ */
38
63
  serviceRouteId: ServiceRouteId;
64
+ // TODO Add tripIds for real-time support
39
65
  };
40
66
  export type RoutesAdjacency = Map<RouteId, Route>;
41
67
 
@@ -101,7 +127,7 @@ export const ALL_TRANSPORT_MODES: RouteType[] = [
101
127
  'MONORAIL',
102
128
  ];
103
129
 
104
- export const CURRENT_VERSION = '0.0.1';
130
+ export const CURRENT_VERSION = '0.0.2';
105
131
 
106
132
  /**
107
133
  * The internal transit timetable format
@@ -165,6 +191,14 @@ export class Timetable {
165
191
  );
166
192
  }
167
193
 
194
+ getRoutesThroughStop(stopId: StopId): RouteId[] {
195
+ const stopAdjacency = this.stopsAdjacency.get(stopId);
196
+ if (!stopAdjacency) {
197
+ return [];
198
+ }
199
+ return stopAdjacency.routes;
200
+ }
201
+
168
202
  getRoute(routeId: RouteId): Route | undefined {
169
203
  return this.routesAdjacency.get(routeId);
170
204
  }
@@ -249,11 +283,9 @@ export class Timetable {
249
283
  tripIndex++
250
284
  ) {
251
285
  const stopTimeIndex = tripIndex * stopsNumber + stopIndex;
252
- const stopTime = route.stopTimes[stopTimeIndex]!;
253
- if (
254
- stopTime.departure >= after &&
255
- stopTime.pickUpType !== 'NOT_AVAILABLE'
256
- ) {
286
+ const departure = route.stopTimes[stopTimeIndex * 2 + 1]!;
287
+ const pickUpType = route.pickUpDropOffTypes[stopTimeIndex * 2]!;
288
+ if (departure >= after.toSeconds() && pickUpType !== NOT_AVAILABLE) {
257
289
  return tripIndex;
258
290
  }
259
291
  }
@@ -267,17 +299,18 @@ export class Timetable {
267
299
  tripIndex--
268
300
  ) {
269
301
  const stopTimeIndex = tripIndex * stopsNumber + stopIndex;
270
- const stopTime = route.stopTimes[stopTimeIndex]!;
271
- if (stopTime.departure < after) {
302
+ const departure = route.stopTimes[stopTimeIndex * 2 + 1]!;
303
+ const pickUpType = route.pickUpDropOffTypes[stopTimeIndex * 2]!;
304
+ if (departure < after.toSeconds()) {
272
305
  break;
273
306
  }
274
307
  if (
275
- stopTime.pickUpType !== 'NOT_AVAILABLE' &&
308
+ pickUpType !== NOT_AVAILABLE &&
276
309
  (earliestDeparture === undefined ||
277
- stopTime.departure < earliestDeparture)
310
+ departure < earliestDeparture.toSeconds())
278
311
  ) {
279
312
  earliestTripIndex = tripIndex;
280
- earliestDeparture = stopTime.departure;
313
+ earliestDeparture = Time.fromSeconds(departure);
281
314
  }
282
315
  }
283
316
  return earliestTripIndex;