minotor 3.0.2 → 4.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.
@@ -5,8 +5,13 @@ import { ParsedStopsMap } from './stops.js';
5
5
  import { TransfersMap } from './transfers.js';
6
6
  export type TripId = string;
7
7
  export type TripIdsMap = Map<TripId, ServiceRouteId>;
8
- export type GtfsPickupDropOffType = '' | 0 | 1 | 2 | 3;
8
+ export type GtfsPickupDropOffType = '' | '0' | '1' | '2' | '3';
9
9
  export type SerializedPickUpDropOffType = 0 | 1 | 2 | 3;
10
+ /**
11
+ * Encodes pickup/drop-off types into a Uint8Array using 2 bits per value.
12
+ * Layout per byte: [drop_off_1][pickup_1][drop_off_0][pickup_0] for stops 0 and 1
13
+ */
14
+ export declare const encodePickUpDropOffTypes: (pickUpTypes: SerializedPickUpDropOffType[], dropOffTypes: SerializedPickUpDropOffType[]) => Uint8Array;
10
15
  /**
11
16
  * Parses the trips.txt file from a GTFS feed
12
17
  *
@@ -13444,11 +13444,16 @@ class Route {
13444
13444
  * @returns The pick-up type at the specified stop and trip.
13445
13445
  */
13446
13446
  pickUpTypeFrom(stopId, tripIndex) {
13447
- const pickUpIndex = (tripIndex * this.stops.length + this.stopIndex(stopId)) * 2;
13448
- const pickUpValue = this.pickUpDropOffTypes[pickUpIndex];
13449
- if (pickUpValue === undefined) {
13447
+ const globalIndex = tripIndex * this.stops.length + this.stopIndex(stopId);
13448
+ const byteIndex = Math.floor(globalIndex / 2);
13449
+ const isSecondPair = globalIndex % 2 === 1;
13450
+ const byte = this.pickUpDropOffTypes[byteIndex];
13451
+ if (byte === undefined) {
13450
13452
  throw new Error(`Pick up type not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13451
13453
  }
13454
+ const pickUpValue = isSecondPair
13455
+ ? (byte >> 6) & 0x03 // Upper 2 bits for second pair
13456
+ : (byte >> 2) & 0x03; // Bits 2-3 for first pair
13452
13457
  return toPickupDropOffType(pickUpValue);
13453
13458
  }
13454
13459
  /**
@@ -13459,11 +13464,16 @@ class Route {
13459
13464
  * @returns The drop-off type at the specified stop and trip.
13460
13465
  */
13461
13466
  dropOffTypeAt(stopId, tripIndex) {
13462
- const dropOffIndex = (tripIndex * this.stops.length + this.stopIndex(stopId)) * 2 + 1;
13463
- const dropOffValue = this.pickUpDropOffTypes[dropOffIndex];
13464
- if (dropOffValue === undefined) {
13467
+ const globalIndex = tripIndex * this.stops.length + this.stopIndex(stopId);
13468
+ const byteIndex = Math.floor(globalIndex / 2);
13469
+ const isSecondPair = globalIndex % 2 === 1;
13470
+ const byte = this.pickUpDropOffTypes[byteIndex];
13471
+ if (byte === undefined) {
13465
13472
  throw new Error(`Drop off type not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
13466
13473
  }
13474
+ const dropOffValue = isSecondPair
13475
+ ? (byte >> 4) & 0x03 // Bits 4-5 for second pair
13476
+ : byte & 0x03; // Lower 2 bits for first pair
13467
13477
  return toPickupDropOffType(dropOffValue);
13468
13478
  }
13469
13479
  /**
@@ -13765,7 +13775,7 @@ const ALL_TRANSPORT_MODES = new Set([
13765
13775
  'TROLLEYBUS',
13766
13776
  'MONORAIL',
13767
13777
  ]);
13768
- const CURRENT_VERSION = '0.0.3';
13778
+ const CURRENT_VERSION = '0.0.4';
13769
13779
  /**
13770
13780
  * The internal transit timetable format.
13771
13781
  */
@@ -16196,6 +16206,86 @@ const parseGtfsTransferType = (gtfsTransferType) => {
16196
16206
  }
16197
16207
  };
16198
16208
 
16209
+ /**
16210
+ * Encodes pickup/drop-off types into a Uint8Array using 2 bits per value.
16211
+ * Layout per byte: [drop_off_1][pickup_1][drop_off_0][pickup_0] for stops 0 and 1
16212
+ */
16213
+ const encodePickUpDropOffTypes = (pickUpTypes, dropOffTypes) => {
16214
+ const stopsCount = pickUpTypes.length;
16215
+ // Each byte stores 2 pickup/drop-off pairs (4 bits each)
16216
+ const arraySize = Math.ceil(stopsCount / 2);
16217
+ const encoded = new Uint8Array(arraySize);
16218
+ for (let i = 0; i < stopsCount; i++) {
16219
+ const byteIndex = Math.floor(i / 2);
16220
+ const isSecondPair = i % 2 === 1;
16221
+ const dropOffType = dropOffTypes[i];
16222
+ const pickUpType = pickUpTypes[i];
16223
+ if (dropOffType !== undefined &&
16224
+ pickUpType !== undefined &&
16225
+ byteIndex < encoded.length) {
16226
+ if (isSecondPair) {
16227
+ // Second pair: upper 4 bits
16228
+ const currentByte = encoded[byteIndex];
16229
+ if (currentByte !== undefined) {
16230
+ encoded[byteIndex] =
16231
+ currentByte | (dropOffType << 4) | (pickUpType << 6);
16232
+ }
16233
+ }
16234
+ else {
16235
+ // First pair: lower 4 bits
16236
+ const currentByte = encoded[byteIndex];
16237
+ if (currentByte !== undefined) {
16238
+ encoded[byteIndex] = currentByte | dropOffType | (pickUpType << 2);
16239
+ }
16240
+ }
16241
+ }
16242
+ }
16243
+ return encoded;
16244
+ };
16245
+ /**
16246
+ * Sorts trips by departure time and creates optimized typed arrays
16247
+ */
16248
+ const finalizeRouteFromBuilder = (builder) => {
16249
+ builder.trips.sort((a, b) => a.firstDeparture - b.firstDeparture);
16250
+ const stopsCount = builder.stops.length;
16251
+ const tripsCount = builder.trips.length;
16252
+ const stopsArray = new Uint32Array(builder.stops);
16253
+ const stopTimesArray = new Uint16Array(stopsCount * tripsCount * 2);
16254
+ const allPickUpTypes = [];
16255
+ const allDropOffTypes = [];
16256
+ for (let tripIndex = 0; tripIndex < tripsCount; tripIndex++) {
16257
+ const trip = builder.trips[tripIndex];
16258
+ if (!trip) {
16259
+ throw new Error(`Missing trip data at index ${tripIndex}`);
16260
+ }
16261
+ const baseIndex = tripIndex * stopsCount * 2;
16262
+ for (let stopIndex = 0; stopIndex < stopsCount; stopIndex++) {
16263
+ const timeIndex = baseIndex + stopIndex * 2;
16264
+ const arrivalTime = trip.arrivalTimes[stopIndex];
16265
+ const departureTime = trip.departureTimes[stopIndex];
16266
+ const pickUpType = trip.pickUpTypes[stopIndex];
16267
+ const dropOffType = trip.dropOffTypes[stopIndex];
16268
+ if (arrivalTime === undefined ||
16269
+ departureTime === undefined ||
16270
+ pickUpType === undefined ||
16271
+ dropOffType === undefined) {
16272
+ throw new Error(`Missing trip data for trip ${tripIndex} at stop ${stopIndex}`);
16273
+ }
16274
+ stopTimesArray[timeIndex] = arrivalTime;
16275
+ stopTimesArray[timeIndex + 1] = departureTime;
16276
+ allDropOffTypes.push(dropOffType);
16277
+ allPickUpTypes.push(pickUpType);
16278
+ }
16279
+ }
16280
+ // Use 2-bit encoding for pickup/drop-off types
16281
+ const pickUpDropOffTypesArray = encodePickUpDropOffTypes(allPickUpTypes, allDropOffTypes);
16282
+ return {
16283
+ serviceRouteId: builder.serviceRouteId,
16284
+ stops: stopsArray,
16285
+ stopTimes: stopTimesArray,
16286
+ pickUpDropOffTypes: pickUpDropOffTypesArray,
16287
+ };
16288
+ };
16199
16289
  /**
16200
16290
  * Parses the trips.txt file from a GTFS feed
16201
16291
  *
@@ -16273,11 +16363,11 @@ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) =
16273
16363
  var _a, e_2, _b, _c;
16274
16364
  var _d, _e;
16275
16365
  /**
16276
- * Inserts a trip at the right place in the routes adjacency structure.
16366
+ * Adds a trip to the appropriate route builder
16277
16367
  */
16278
16368
  const addTrip = (currentTripId) => {
16279
16369
  const gtfsRouteId = validTripIds.get(currentTripId);
16280
- if (!gtfsRouteId) {
16370
+ if (!gtfsRouteId || stops.length === 0) {
16281
16371
  stops = [];
16282
16372
  arrivalTimes = [];
16283
16373
  departureTimes = [];
@@ -16286,83 +16376,42 @@ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) =
16286
16376
  return;
16287
16377
  }
16288
16378
  const routeId = `${gtfsRouteId}_${hashIds(stops)}`;
16289
- let route = routes.get(routeId);
16290
- if (!route) {
16291
- const stopsCount = stops.length;
16292
- const stopsArray = new Uint32Array(stops);
16293
- const stopTimesArray = new Uint16Array(stopsCount * 2);
16294
- for (let i = 0; i < stopsCount; i++) {
16295
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16296
- stopTimesArray[i * 2] = arrivalTimes[i];
16297
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16298
- stopTimesArray[i * 2 + 1] = departureTimes[i];
16299
- }
16300
- const pickUpDropOffTypesArray = new Uint8Array(stopsCount * 2);
16301
- for (let i = 0; i < stopsCount; i++) {
16302
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16303
- pickUpDropOffTypesArray[i * 2] = pickUpTypes[i];
16304
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16305
- pickUpDropOffTypesArray[i * 2 + 1] = dropOffTypes[i];
16306
- }
16307
- route = {
16379
+ const firstDeparture = departureTimes[0];
16380
+ if (firstDeparture === undefined) {
16381
+ console.warn(`Empty trip ${currentTripId}`);
16382
+ stops = [];
16383
+ arrivalTimes = [];
16384
+ departureTimes = [];
16385
+ pickUpTypes = [];
16386
+ dropOffTypes = [];
16387
+ return;
16388
+ }
16389
+ let routeBuilder = routeBuilders.get(routeId);
16390
+ if (!routeBuilder) {
16391
+ routeBuilder = {
16308
16392
  serviceRouteId: gtfsRouteId,
16309
- stops: stopsArray,
16310
- stopTimes: stopTimesArray,
16311
- pickUpDropOffTypes: pickUpDropOffTypesArray,
16393
+ stops: [...stops],
16394
+ trips: [],
16312
16395
  };
16313
- routes.set(routeId, route);
16396
+ routeBuilders.set(routeId, routeBuilder);
16314
16397
  for (const stop of stops) {
16315
16398
  validStopIds.add(stop);
16316
16399
  }
16317
16400
  }
16318
- else {
16319
- const tripFirstStopDeparture = departureTimes[0];
16320
- if (tripFirstStopDeparture === undefined) {
16321
- throw new Error(`Empty trip ${currentTripId}`);
16322
- }
16323
- // Find the correct position to insert the new trip
16324
- const stopsCount = stops.length;
16325
- let insertPosition = 0;
16326
- const existingTripsCount = route.stopTimes.length / (stopsCount * 2);
16327
- for (let tripIndex = 0; tripIndex < existingTripsCount; tripIndex++) {
16328
- const currentDeparture = route.stopTimes[tripIndex * stopsCount * 2 + 1];
16329
- if (currentDeparture && tripFirstStopDeparture > currentDeparture) {
16330
- insertPosition = (tripIndex + 1) * stopsCount;
16331
- }
16332
- else {
16333
- break;
16334
- }
16335
- }
16336
- // insert data for the new trip at the right place
16337
- const newStopTimesLength = route.stopTimes.length + stopsCount * 2;
16338
- const newStopTimes = new Uint16Array(newStopTimesLength);
16339
- const newPickUpDropOffTypes = new Uint8Array(newStopTimesLength);
16340
- newStopTimes.set(route.stopTimes.slice(0, insertPosition * 2), 0);
16341
- newPickUpDropOffTypes.set(route.pickUpDropOffTypes.slice(0, insertPosition * 2), 0);
16342
- for (let i = 0; i < stopsCount; i++) {
16343
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16344
- newStopTimes[(insertPosition + i) * 2] = arrivalTimes[i];
16345
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16346
- newStopTimes[(insertPosition + i) * 2 + 1] = departureTimes[i];
16347
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16348
- newPickUpDropOffTypes[(insertPosition + i) * 2] = pickUpTypes[i];
16349
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16350
- newPickUpDropOffTypes[(insertPosition + i) * 2 + 1] = dropOffTypes[i];
16351
- }
16352
- const afterInsertionSlice = route.stopTimes.slice(insertPosition * 2);
16353
- newStopTimes.set(afterInsertionSlice, (insertPosition + stopsCount) * 2);
16354
- const afterInsertionTypesSlice = route.pickUpDropOffTypes.slice(insertPosition * 2);
16355
- newPickUpDropOffTypes.set(afterInsertionTypesSlice, (insertPosition + stopsCount) * 2);
16356
- route.stopTimes = newStopTimes;
16357
- route.pickUpDropOffTypes = newPickUpDropOffTypes;
16358
- }
16401
+ routeBuilder.trips.push({
16402
+ firstDeparture,
16403
+ arrivalTimes: [...arrivalTimes],
16404
+ departureTimes: [...departureTimes],
16405
+ pickUpTypes: [...pickUpTypes],
16406
+ dropOffTypes: [...dropOffTypes],
16407
+ });
16359
16408
  stops = [];
16360
16409
  arrivalTimes = [];
16361
16410
  departureTimes = [];
16362
16411
  pickUpTypes = [];
16363
16412
  dropOffTypes = [];
16364
16413
  };
16365
- const routes = new Map();
16414
+ const routeBuilders = new Map();
16366
16415
  let previousSeq = 0;
16367
16416
  let stops = [];
16368
16417
  let arrivalTimes = [];
@@ -16377,27 +16426,33 @@ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) =
16377
16426
  const rawLine = _c;
16378
16427
  const line = rawLine;
16379
16428
  if (line.trip_id === currentTripId && line.stop_sequence <= previousSeq) {
16380
- console.warn(`Stop sequences not increasing for trip ${line.trip_id}.`);
16429
+ console.warn(`Stop sequences not increasing for trip ${line.trip_id}: ${line.stop_sequence} > ${previousSeq}.`);
16381
16430
  continue;
16382
16431
  }
16383
16432
  if (!line.arrival_time && !line.departure_time) {
16384
16433
  console.warn(`Missing arrival or departure time for ${line.trip_id} at stop ${line.stop_id}.`);
16385
16434
  continue;
16386
16435
  }
16387
- if (line.pickup_type === 1 && line.drop_off_type === 1) {
16436
+ if (line.pickup_type === '1' && line.drop_off_type === '1') {
16388
16437
  continue;
16389
16438
  }
16390
16439
  if (currentTripId && line.trip_id !== currentTripId && stops.length > 0) {
16391
16440
  addTrip(currentTripId);
16392
16441
  }
16393
16442
  currentTripId = line.trip_id;
16394
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16395
- stops.push(stopsMap.get(line.stop_id).id);
16443
+ const stopData = stopsMap.get(line.stop_id);
16444
+ if (!stopData) {
16445
+ console.warn(`Unknown stop ID: ${line.stop_id}`);
16446
+ continue;
16447
+ }
16448
+ stops.push(stopData.id);
16396
16449
  const departure = (_d = line.departure_time) !== null && _d !== void 0 ? _d : line.arrival_time;
16397
16450
  const arrival = (_e = line.arrival_time) !== null && _e !== void 0 ? _e : line.departure_time;
16398
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16451
+ if (!arrival || !departure) {
16452
+ console.warn(`Missing time data for ${line.trip_id} at stop ${line.stop_id}`);
16453
+ continue;
16454
+ }
16399
16455
  arrivalTimes.push(toTime(arrival).toMinutes());
16400
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16401
16456
  departureTimes.push(toTime(departure).toMinutes());
16402
16457
  pickUpTypes.push(parsePickupDropOffType(line.pickup_type));
16403
16458
  dropOffTypes.push(parsePickupDropOffType(line.drop_off_type));
@@ -16415,7 +16470,8 @@ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) =
16415
16470
  addTrip(currentTripId);
16416
16471
  }
16417
16472
  const routesAdjacency = new Map();
16418
- for (const [routeId, routeData] of routes) {
16473
+ for (const [routeId, routeBuilder] of routeBuilders) {
16474
+ const routeData = finalizeRouteFromBuilder(routeBuilder);
16419
16475
  routesAdjacency.set(routeId, new Route(routeData.stopTimes, routeData.pickUpDropOffTypes, routeData.stops, routeData.serviceRouteId));
16420
16476
  }
16421
16477
  return routesAdjacency;
@@ -16424,13 +16480,13 @@ const parsePickupDropOffType = (gtfsType) => {
16424
16480
  switch (gtfsType) {
16425
16481
  default:
16426
16482
  return REGULAR;
16427
- case 0:
16483
+ case '0':
16428
16484
  return REGULAR;
16429
- case 1:
16485
+ case '1':
16430
16486
  return NOT_AVAILABLE;
16431
- case 2:
16487
+ case '2':
16432
16488
  return MUST_PHONE_AGENCY;
16433
- case 3:
16489
+ case '3':
16434
16490
  return MUST_COORDINATE_WITH_DRIVER;
16435
16491
  }
16436
16492
  };
@@ -16458,54 +16514,74 @@ class GtfsParser {
16458
16514
  */
16459
16515
  parse(date) {
16460
16516
  return __awaiter(this, void 0, void 0, function* () {
16517
+ log.setLevel('INFO');
16461
16518
  const zip = new StreamZip.async({ file: this.path });
16462
16519
  const entries = yield zip.entries();
16463
16520
  const datetime = DateTime.fromJSDate(date);
16464
16521
  const validServiceIds = new Set();
16465
16522
  const validStopIds = new Set();
16466
16523
  log.info(`Parsing ${STOPS_FILE}`);
16524
+ const stopsStart = performance.now();
16467
16525
  const stopsStream = yield zip.stream(STOPS_FILE);
16468
16526
  const parsedStops = yield parseStops(stopsStream, this.profile.platformParser);
16469
- log.info(`${parsedStops.size} parsed stops.`);
16527
+ const stopsEnd = performance.now();
16528
+ log.info(`${parsedStops.size} parsed stops. (${(stopsEnd - stopsStart).toFixed(2)}ms)`);
16470
16529
  if (entries[CALENDAR_FILE]) {
16471
16530
  log.info(`Parsing ${CALENDAR_FILE}`);
16531
+ const calendarStart = performance.now();
16472
16532
  const calendarStream = yield zip.stream(CALENDAR_FILE);
16473
16533
  yield parseCalendar(calendarStream, validServiceIds, datetime);
16474
- log.info(`${validServiceIds.size} valid services.`);
16534
+ const calendarEnd = performance.now();
16535
+ log.info(`${validServiceIds.size} valid services. (${(calendarEnd - calendarStart).toFixed(2)}ms)`);
16475
16536
  }
16476
16537
  if (entries[CALENDAR_DATES_FILE]) {
16477
16538
  log.info(`Parsing ${CALENDAR_DATES_FILE}`);
16539
+ const calendarDatesStart = performance.now();
16478
16540
  const calendarDatesStream = yield zip.stream(CALENDAR_DATES_FILE);
16479
16541
  yield parseCalendarDates(calendarDatesStream, validServiceIds, datetime);
16480
- log.info(`${validServiceIds.size} valid services.`);
16542
+ const calendarDatesEnd = performance.now();
16543
+ log.info(`${validServiceIds.size} valid services. (${(calendarDatesEnd - calendarDatesStart).toFixed(2)}ms)`);
16481
16544
  }
16482
16545
  log.info(`Parsing ${ROUTES_FILE}`);
16546
+ const routesStart = performance.now();
16483
16547
  const routesStream = yield zip.stream(ROUTES_FILE);
16484
16548
  const validGtfsRoutes = yield parseRoutes(routesStream, this.profile);
16485
- log.info(`${validGtfsRoutes.size} valid GTFS routes.`);
16549
+ const routesEnd = performance.now();
16550
+ log.info(`${validGtfsRoutes.size} valid GTFS routes. (${(routesEnd - routesStart).toFixed(2)}ms)`);
16486
16551
  log.info(`Parsing ${TRIPS_FILE}`);
16552
+ const tripsStart = performance.now();
16487
16553
  const tripsStream = yield zip.stream(TRIPS_FILE);
16488
16554
  const trips = yield parseTrips(tripsStream, validServiceIds, validGtfsRoutes);
16489
- log.info(`${trips.size} valid trips.`);
16555
+ const tripsEnd = performance.now();
16556
+ log.info(`${trips.size} valid trips. (${(tripsEnd - tripsStart).toFixed(2)}ms)`);
16490
16557
  let transfers = new Map();
16491
16558
  if (entries[TRANSFERS_FILE]) {
16492
16559
  log.info(`Parsing ${TRANSFERS_FILE}`);
16560
+ const transfersStart = performance.now();
16493
16561
  const transfersStream = yield zip.stream(TRANSFERS_FILE);
16494
16562
  transfers = yield parseTransfers(transfersStream, parsedStops);
16495
- log.info(`${transfers.size} valid transfers.`);
16563
+ const transfersEnd = performance.now();
16564
+ log.info(`${transfers.size} valid transfers. (${(transfersEnd - transfersStart).toFixed(2)}ms)`);
16496
16565
  }
16497
16566
  log.info(`Parsing ${STOP_TIMES_FILE}`);
16567
+ const stopTimesStart = performance.now();
16498
16568
  const stopTimesStream = yield zip.stream(STOP_TIMES_FILE);
16499
16569
  const routesAdjacency = yield parseStopTimes(stopTimesStream, parsedStops, trips, validStopIds);
16500
16570
  const stopsAdjacency = buildStopsAdjacencyStructure(validStopIds, routesAdjacency, transfers);
16501
- log.info(`${routesAdjacency.size} valid unique routes.`);
16571
+ const stopTimesEnd = performance.now();
16572
+ log.info(`${routesAdjacency.size} valid unique routes. (${(stopTimesEnd - stopTimesStart).toFixed(2)}ms)`);
16502
16573
  log.info(`Removing unused stops.`);
16574
+ const indexStopsStart = performance.now();
16503
16575
  const stops = indexStops(parsedStops, validStopIds);
16504
- log.info(`${stops.size} used stop stops, ${parsedStops.size - stops.size} unused.`);
16576
+ const indexStopsEnd = performance.now();
16577
+ log.info(`${stops.size} used stop stops, ${parsedStops.size - stops.size} unused. (${(indexStopsEnd - indexStopsStart).toFixed(2)}ms)`);
16505
16578
  yield zip.close();
16506
16579
  const timetable = new Timetable(stopsAdjacency, routesAdjacency, validGtfsRoutes);
16507
16580
  log.info(`Building stops index.`);
16581
+ const stopsIndexStart = performance.now();
16508
16582
  const stopsIndex = new StopsIndex(stops);
16583
+ const stopsIndexEnd = performance.now();
16584
+ log.info(`Stops index built. (${(stopsIndexEnd - stopsIndexStart).toFixed(2)}ms)`);
16509
16585
  log.info('Parsing complete.');
16510
16586
  return { timetable, stopsIndex };
16511
16587
  });
@@ -16521,9 +16597,11 @@ class GtfsParser {
16521
16597
  return __awaiter(this, void 0, void 0, function* () {
16522
16598
  const zip = new StreamZip.async({ file: this.path });
16523
16599
  log.info(`Parsing ${STOPS_FILE}`);
16600
+ const stopsStart = performance.now();
16524
16601
  const stopsStream = yield zip.stream(STOPS_FILE);
16525
16602
  const stops = indexStops(yield parseStops(stopsStream, this.profile.platformParser));
16526
- log.info(`${stops.size} parsed stops.`);
16603
+ const stopsEnd = performance.now();
16604
+ log.info(`${stops.size} parsed stops. (${(stopsEnd - stopsStart).toFixed(2)}ms)`);
16527
16605
  yield zip.close();
16528
16606
  return new StopsIndex(stops);
16529
16607
  });