gtfs-to-html 2.4.4 → 2.5.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.
package/lib/utils.js CHANGED
@@ -27,7 +27,6 @@ import {
27
27
  getTimetableNotesReferences,
28
28
  getTimetableNotes,
29
29
  getRoutes,
30
- getDb,
31
30
  getCalendars,
32
31
  getTimetableStopOrders,
33
32
  getStops,
@@ -37,6 +36,7 @@ import {
37
36
  getTimetables,
38
37
  getTimetablePages,
39
38
  getAgencies,
39
+ openDb,
40
40
  } from 'gtfs';
41
41
  import { stringify } from 'csv-stringify';
42
42
  import moment from 'moment';
@@ -275,8 +275,8 @@ const sortTripsByStoptimeAtStop = (trips, stopId) =>
275
275
  /*
276
276
  * Get all calendar dates for a specific timetable.
277
277
  */
278
- const getCalendarDatesForTimetable = async (timetable, config) => {
279
- const calendarDates = await getCalendarDates(
278
+ const getCalendarDatesForTimetable = (timetable, config) => {
279
+ const calendarDates = getCalendarDates(
280
280
  {
281
281
  service_id: timetable.service_ids,
282
282
  },
@@ -334,8 +334,8 @@ const getDaysFromCalendars = (calendars) => {
334
334
  /*
335
335
  * Get the `trip_headsign` for a specific timetable.
336
336
  */
337
- const getDirectionHeadsignFromTimetable = async (timetable) => {
338
- const trips = await getTrips(
337
+ const getDirectionHeadsignFromTimetable = (timetable) => {
338
+ const trips = getTrips(
339
339
  {
340
340
  direction_id: timetable.direction_id,
341
341
  route_id: timetable.route_ids,
@@ -353,31 +353,31 @@ const getDirectionHeadsignFromTimetable = async (timetable) => {
353
353
  /*
354
354
  * Get the notes for a specific timetable.
355
355
  */
356
- const getTimetableNotesForTimetable = async (timetable, config) => {
356
+ const getTimetableNotesForTimetable = (timetable, config) => {
357
357
  const noteReferences = [
358
358
  // Get all notes for this timetable.
359
- ...(await getTimetableNotesReferences({
359
+ ...getTimetableNotesReferences({
360
360
  timetable_id: timetable.timetable_id,
361
- })),
361
+ }),
362
362
 
363
363
  // Get all notes for this route.
364
- ...(await getTimetableNotesReferences({
364
+ ...getTimetableNotesReferences({
365
365
  route_id: timetable.routes.map((route) => route.route_id),
366
366
  timetable_id: null,
367
- })),
367
+ }),
368
368
 
369
369
  // Get all notes for all trips in this timetable.
370
- ...(await getTimetableNotesReferences({
370
+ ...getTimetableNotesReferences({
371
371
  trip_id: timetable.orderedTrips.map((trip) => trip.trip_id),
372
- })),
372
+ }),
373
373
 
374
374
  // Get all notes for all stops in this timetable.
375
- ...(await getTimetableNotesReferences({
375
+ ...getTimetableNotesReferences({
376
376
  stop_id: timetable.stops.map((stop) => stop.stop_id),
377
377
  trip_id: null,
378
378
  route_id: null,
379
379
  timetable_id: null,
380
- })),
380
+ }),
381
381
  ];
382
382
 
383
383
  const usedNoteReferences = [];
@@ -416,7 +416,7 @@ const getTimetableNotesForTimetable = async (timetable, config) => {
416
416
  }
417
417
  }
418
418
 
419
- const notes = await getTimetableNotes({
419
+ const notes = getTimetableNotes({
420
420
  note_id: usedNoteReferences.map((noteReference) => noteReference.note_id),
421
421
  });
422
422
 
@@ -445,14 +445,14 @@ const getTimetableNotesForTimetable = async (timetable, config) => {
445
445
  * Create a timetable page from a single timetable. Used if no
446
446
  * `timetable_pages.txt` is present.
447
447
  */
448
- const convertTimetableToTimetablePage = async (timetable, config) => {
448
+ const convertTimetableToTimetablePage = (timetable, config) => {
449
449
  if (!timetable.routes) {
450
- timetable.routes = await getRoutes({
450
+ timetable.routes = getRoutes({
451
451
  route_id: timetable.route_ids,
452
452
  });
453
453
  }
454
454
 
455
- const filename = await generateFileName(timetable, config);
455
+ const filename = generateFileName(timetable, config);
456
456
 
457
457
  return {
458
458
  timetable_page_id: timetable.timetable_id,
@@ -517,61 +517,47 @@ const convertRouteToTimetablePage = (
517
517
  * Create timetable pages for all routes in an agency. Used if no
518
518
  * `timetables.txt` is present.
519
519
  */
520
- const convertRoutesToTimetablePages = async (config) => {
521
- const db = getDb();
522
- const routes = await getRoutes();
523
- const calendars = await getCalendars();
520
+ const convertRoutesToTimetablePages = (config) => {
521
+ const db = openDb(config);
522
+ const routes = getRoutes();
523
+ const calendars = getCalendars();
524
524
 
525
525
  // Find all calendar dates with service_ids not present in `calendar.txt`.
526
526
  const serviceIds = calendars.map((calendar) => calendar.service_id);
527
- const calendarDates = await db.all(
528
- `SELECT * FROM calendar_dates WHERE exception_type = 1 AND service_id NOT IN (${serviceIds
529
- .map((serviceId) => `'${serviceId}'`)
530
- .join(', ')})`
531
- );
527
+ const calendarDates = db
528
+ .prepare(
529
+ `SELECT * FROM calendar_dates WHERE exception_type = 1 AND service_id NOT IN (${serviceIds
530
+ .map((serviceId) => `'${serviceId}'`)
531
+ .join(', ')})`
532
+ )
533
+ .all();
534
+
535
+ const timetablePages = routes.map((route) => {
536
+ const trips = getTrips(
537
+ {
538
+ route_id: route.route_id,
539
+ },
540
+ ['trip_headsign', 'direction_id']
541
+ );
542
+ const directions = uniqBy(trips, (trip) => trip.direction_id);
543
+ const dayGroups = groupBy(calendars, calendarToCalendarCode);
544
+ const calendarDateGroups = groupBy(calendarDates, 'service_id');
532
545
 
533
- const timetablePages = await Promise.all(
534
- routes.map(async (route) => {
535
- const trips = await getTrips(
536
- {
537
- route_id: route.route_id,
538
- },
539
- ['trip_headsign', 'direction_id']
540
- );
541
- const directions = uniqBy(trips, (trip) => trip.direction_id);
542
- const dayGroups = groupBy(calendars, calendarToCalendarCode);
543
- const calendarDateGroups = groupBy(calendarDates, 'service_id');
544
-
545
- return Promise.all(
546
- directions.map((direction) =>
547
- Promise.all([
548
- Promise.all(
549
- Object.values(dayGroups).map((calendars) =>
550
- convertRouteToTimetablePage(
551
- route,
552
- direction,
553
- calendars,
554
- null,
555
- config
556
- )
557
- )
558
- ),
559
- Promise.all(
560
- Object.values(calendarDateGroups).map((calendarDates) =>
561
- convertRouteToTimetablePage(
562
- route,
563
- direction,
564
- null,
565
- calendarDates,
566
- config
567
- )
568
- )
569
- ),
570
- ])
546
+ return directions.map((direction) => [
547
+ Object.values(dayGroups).map((calendars) =>
548
+ convertRouteToTimetablePage(route, direction, calendars, null, config)
549
+ ),
550
+ Object.values(calendarDateGroups).map((calendarDates) =>
551
+ convertRouteToTimetablePage(
552
+ route,
553
+ direction,
554
+ null,
555
+ calendarDates,
556
+ config
571
557
  )
572
- );
573
- })
574
- );
558
+ ),
559
+ ]);
560
+ });
575
561
 
576
562
  return compact(flattenDeep(timetablePages));
577
563
  };
@@ -616,6 +602,10 @@ const duplicateStopsForDifferentArrivalDeparture = (
616
602
  timetable,
617
603
  config
618
604
  ) => {
605
+ if (config.showArrivalOnDifference === null) {
606
+ return stopIds;
607
+ }
608
+
619
609
  for (const trip of timetable.orderedTrips) {
620
610
  for (const stoptime of trip.stoptimes) {
621
611
  const timepointDifference = fromGTFSTime(stoptime.departure_time).diff(
@@ -623,10 +613,7 @@ const duplicateStopsForDifferentArrivalDeparture = (
623
613
  'minutes'
624
614
  );
625
615
 
626
- if (
627
- config.showArrivalOnDifference === null ||
628
- timepointDifference < config.showArrivalOnDifference
629
- ) {
616
+ if (timepointDifference < config.showArrivalOnDifference) {
630
617
  continue;
631
618
  }
632
619
 
@@ -652,9 +639,9 @@ const duplicateStopsForDifferentArrivalDeparture = (
652
639
  /*
653
640
  * Get a sorted array of stop_ids for a specific timetable.
654
641
  */
655
- const getStopOrder = async (timetable, config) => {
642
+ const getStopOrder = (timetable, config) => {
656
643
  // First, check if `timetable_stop_order.txt` for route exists
657
- const timetableStopOrders = await getTimetableStopOrders(
644
+ const timetableStopOrders = getTimetableStopOrders(
658
645
  {
659
646
  timetable_id: timetable.timetable_id,
660
647
  },
@@ -714,45 +701,43 @@ const getStopOrder = async (timetable, config) => {
714
701
  /*
715
702
  * Get an array of stops for a specific timetable.
716
703
  */
717
- const getStopsForTimetable = async (timetable, config) => {
704
+ const getStopsForTimetable = (timetable, config) => {
718
705
  if (timetable.orderedTrips.length === 0) {
719
706
  return [];
720
707
  }
721
708
 
722
- const orderedStopIds = await getStopOrder(timetable, config);
723
- const orderedStops = await Promise.all(
724
- orderedStopIds.map(async (stopId, index) => {
725
- const stops = await getStops({
726
- stop_id: stopId,
727
- });
709
+ const orderedStopIds = getStopOrder(timetable, config);
710
+ const orderedStops = orderedStopIds.map((stopId, index) => {
711
+ const stops = getStops({
712
+ stop_id: stopId,
713
+ });
728
714
 
729
- if (stops.length === 0) {
730
- throw new Error(
731
- `No stop found found for stop_id=${stopId} in timetable_id=${timetable.timetable_id}`
732
- );
733
- }
715
+ if (stops.length === 0) {
716
+ throw new Error(
717
+ `No stop found found for stop_id=${stopId} in timetable_id=${timetable.timetable_id}`
718
+ );
719
+ }
734
720
 
735
- const stop = {
736
- ...stops[0],
737
- trips: [],
738
- };
721
+ const stop = {
722
+ ...stops[0],
723
+ trips: [],
724
+ };
739
725
 
740
- if (
741
- index < orderedStopIds.length - 1 &&
742
- stopId === orderedStopIds[index + 1]
743
- ) {
744
- stop.type = 'arrival';
745
- } else if (index > 0 && stopId === orderedStopIds[index - 1]) {
746
- stop.type = 'departure';
747
- }
726
+ if (
727
+ index < orderedStopIds.length - 1 &&
728
+ stopId === orderedStopIds[index + 1]
729
+ ) {
730
+ stop.type = 'arrival';
731
+ } else if (index > 0 && stopId === orderedStopIds[index - 1]) {
732
+ stop.type = 'departure';
733
+ }
748
734
 
749
- return stop;
750
- })
751
- );
735
+ return stop;
736
+ });
752
737
 
753
738
  // If `showStopCity` is true, look up stop attributes.
754
739
  if (timetable.showStopCity) {
755
- const stopAttributes = await getStopAttributes({
740
+ const stopAttributes = getStopAttributes({
756
741
  stop_id: orderedStopIds,
757
742
  });
758
743
 
@@ -773,8 +758,8 @@ const getStopsForTimetable = async (timetable, config) => {
773
758
  /*
774
759
  * Get all calendars from a specific timetable.
775
760
  */
776
- const getCalendarsFromTimetable = async (timetable) => {
777
- const db = getDb();
761
+ const getCalendarsFromTimetable = (timetable) => {
762
+ const db = openDb();
778
763
  let whereClause = '';
779
764
  const whereClauses = [];
780
765
 
@@ -808,14 +793,14 @@ const getCalendarsFromTimetable = async (timetable) => {
808
793
  whereClause = `WHERE ${whereClauses.join(' AND ')}`;
809
794
  }
810
795
 
811
- return db.all(`SELECT * FROM calendar ${whereClause}`);
796
+ return db.prepare(`SELECT * FROM calendar ${whereClause}`).all();
812
797
  };
813
798
 
814
799
  /*
815
800
  * Get all calendar date service ids for an agency between two dates.
816
801
  */
817
- const getCalendarDatesServiceIds = async (startDate, endDate) => {
818
- const db = getDb();
802
+ const getCalendarDatesServiceIds = (startDate, endDate) => {
803
+ const db = openDb();
819
804
  const whereClauses = ['exception_type = 1'];
820
805
 
821
806
  if (endDate) {
@@ -826,11 +811,13 @@ const getCalendarDatesServiceIds = async (startDate, endDate) => {
826
811
  whereClauses.push(`date >= ${sqlString.escape(startDate)}`);
827
812
  }
828
813
 
829
- const calendarDates = await db.all(
830
- `SELECT DISTINCT service_id FROM calendar_dates WHERE ${whereClauses.join(
831
- ' AND '
832
- )}`
833
- );
814
+ const calendarDates = db
815
+ .prepare(
816
+ `SELECT DISTINCT service_id FROM calendar_dates WHERE ${whereClauses.join(
817
+ ' AND '
818
+ )}`
819
+ )
820
+ .all();
834
821
  return calendarDates.map((calendarDate) => calendarDate.service_id);
835
822
  };
836
823
 
@@ -839,8 +826,8 @@ const getCalendarDatesServiceIds = async (startDate, endDate) => {
839
826
  * and the stop_id of parent station itself. If no parent station, it returns the
840
827
  * stop_id.
841
828
  */
842
- const getAllStationStopIds = async (stopId) => {
843
- const stops = await getStops({
829
+ const getAllStationStopIds = (stopId) => {
830
+ const stops = getStops({
844
831
  stop_id: stopId,
845
832
  });
846
833
 
@@ -850,7 +837,7 @@ const getAllStationStopIds = async (stopId) => {
850
837
  return [stopId];
851
838
  }
852
839
 
853
- const stopsInParentStation = await getStops(
840
+ const stopsInParentStation = getStops(
854
841
  {
855
842
  parent_station: stop.parent_station,
856
843
  },
@@ -866,8 +853,8 @@ const getAllStationStopIds = async (stopId) => {
866
853
  /*
867
854
  * Get trips with the same `block_id`.
868
855
  */
869
- const getTripsWithSameBlock = async (trip, timetable) => {
870
- const trips = await getTrips(
856
+ const getTripsWithSameBlock = (trip, timetable) => {
857
+ const trips = getTrips(
871
858
  {
872
859
  block_id: trip.block_id,
873
860
  service_id: timetable.service_ids,
@@ -875,26 +862,24 @@ const getTripsWithSameBlock = async (trip, timetable) => {
875
862
  ['trip_id', 'route_id']
876
863
  );
877
864
 
878
- await Promise.all(
879
- trips.map(async (blockTrip) => {
880
- const stopTimes = await getStoptimes(
881
- {
882
- trip_id: blockTrip.trip_id,
883
- },
884
- [],
885
- [['stop_sequence', 'ASC']]
886
- );
865
+ for (const blockTrip of trips) {
866
+ const stopTimes = getStoptimes(
867
+ {
868
+ trip_id: blockTrip.trip_id,
869
+ },
870
+ [],
871
+ [['stop_sequence', 'ASC']]
872
+ );
887
873
 
888
- if (stopTimes.length === 0) {
889
- throw new Error(
890
- `No stoptimes found found for trip_id=${blockTrip.trip_id}`
891
- );
892
- }
874
+ if (stopTimes.length === 0) {
875
+ throw new Error(
876
+ `No stoptimes found found for trip_id=${blockTrip.trip_id}`
877
+ );
878
+ }
893
879
 
894
- blockTrip.firstStoptime = first(stopTimes);
895
- blockTrip.lastStoptime = last(stopTimes);
896
- })
897
- );
880
+ blockTrip.firstStoptime = first(stopTimes);
881
+ blockTrip.lastStoptime = last(stopTimes);
882
+ }
898
883
 
899
884
  return sortBy(trips, (trip) => trip.firstStoptime.departure_timestamp);
900
885
  };
@@ -903,7 +888,7 @@ const getTripsWithSameBlock = async (trip, timetable) => {
903
888
  * Get next trip and previous trip with the same `block_id` if it arrives or
904
889
  * departs from the same stop and is a different route.
905
890
  */
906
- const addTripContinuation = async (trip, timetable) => {
891
+ const addTripContinuation = (trip, timetable) => {
907
892
  if (!trip.block_id) {
908
893
  return;
909
894
  }
@@ -911,10 +896,10 @@ const addTripContinuation = async (trip, timetable) => {
911
896
  const maxContinuesAsWaitingTimeSeconds = 60 * 60;
912
897
 
913
898
  const firstStoptime = first(trip.stoptimes);
914
- const firstStopIds = await getAllStationStopIds(firstStoptime.stop_id);
899
+ const firstStopIds = getAllStationStopIds(firstStoptime.stop_id);
915
900
  const lastStoptime = last(trip.stoptimes);
916
- const lastStopIds = await getAllStationStopIds(lastStoptime.stop_id);
917
- const blockTrips = await getTripsWithSameBlock(trip, timetable);
901
+ const lastStopIds = getAllStationStopIds(lastStoptime.stop_id);
902
+ const blockTrips = getTripsWithSameBlock(trip, timetable);
918
903
 
919
904
  // "Continues From" trips must be the previous trip chronologically.
920
905
  const previousTrip = findLast(
@@ -937,7 +922,7 @@ const addTripContinuation = async (trip, timetable) => {
937
922
  firstStoptime.departure_timestamp - maxContinuesAsWaitingTimeSeconds &&
938
923
  firstStopIds.includes(previousTrip.lastStoptime.stop_id)
939
924
  ) {
940
- const routes = await getRoutes({
925
+ const routes = getRoutes({
941
926
  route_id: previousTrip.route_id,
942
927
  });
943
928
 
@@ -968,7 +953,7 @@ const addTripContinuation = async (trip, timetable) => {
968
953
  lastStoptime.arrival_timestamp + maxContinuesAsWaitingTimeSeconds &&
969
954
  lastStopIds.includes(nextTrip.firstStoptime.stop_id)
970
955
  ) {
971
- const routes = await getRoutes({
956
+ const routes = getRoutes({
972
957
  route_id: nextTrip.route_id,
973
958
  });
974
959
 
@@ -1021,7 +1006,9 @@ const filterTrips = (timetable) => {
1021
1006
  /*
1022
1007
  * Get all trips from a timetable.
1023
1008
  */
1024
- const getTripsForTimetable = async (timetable, calendars, config) => {
1009
+
1010
+ /* eslint-disable complexity */
1011
+ const getTripsForTimetable = (timetable, calendars, config) => {
1025
1012
  const tripQuery = {
1026
1013
  route_id: timetable.route_ids,
1027
1014
  service_id: timetable.service_ids,
@@ -1031,7 +1018,7 @@ const getTripsForTimetable = async (timetable, calendars, config) => {
1031
1018
  tripQuery.direction_id = timetable.direction_id;
1032
1019
  }
1033
1020
 
1034
- const trips = await getTrips(tripQuery);
1021
+ const trips = getTrips(tripQuery);
1035
1022
 
1036
1023
  if (trips.length === 0) {
1037
1024
  timetable.warnings.push(
@@ -1043,7 +1030,7 @@ const getTripsForTimetable = async (timetable, calendars, config) => {
1043
1030
  );
1044
1031
  }
1045
1032
 
1046
- const frequencies = await getFrequencies({
1033
+ const frequencies = getFrequencies({
1047
1034
  trip_id: trips.map((trip) => trip.trip_id),
1048
1035
  });
1049
1036
 
@@ -1051,81 +1038,78 @@ const getTripsForTimetable = async (timetable, calendars, config) => {
1051
1038
  timetable.service_ids = uniq(trips.map((trip) => trip.service_id));
1052
1039
 
1053
1040
  const formattedTrips = [];
1054
- await Promise.all(
1055
- trips.map(async (trip) => {
1056
- const formattedTrip = formatTrip(trip, timetable, calendars, config);
1057
- formattedTrip.stoptimes = await getStoptimes(
1058
- {
1059
- trip_id: formattedTrip.trip_id,
1060
- },
1061
- [],
1062
- [['stop_sequence', 'ASC']]
1063
- );
1064
1041
 
1065
- if (formattedTrip.stoptimes.length === 0) {
1066
- timetable.warnings.push(
1067
- `No stoptimes found for trip_id=${
1068
- formattedTrip.trip_id
1069
- }, route_id=${timetable.route_ids.join('_')}, timetable_id=${
1070
- timetable.timetable_id
1071
- }`
1072
- );
1073
- }
1042
+ for (const trip of trips) {
1043
+ const formattedTrip = formatTrip(trip, timetable, calendars, config);
1044
+ formattedTrip.stoptimes = getStoptimes(
1045
+ {
1046
+ trip_id: formattedTrip.trip_id,
1047
+ },
1048
+ [],
1049
+ [['stop_sequence', 'ASC']]
1050
+ );
1074
1051
 
1075
- // Exclude trips before timetable `start_timestamp`
1076
- if (
1077
- timetable.start_timestamp !== '' &&
1078
- timetable.start_timestamp !== null &&
1079
- timetable.start_timestamp !== undefined
1080
- ) {
1081
- if (trip.stoptimes[0].arrival_timestamp < timetable.start_timestamp) {
1082
- return;
1083
- }
1084
- }
1052
+ if (formattedTrip.stoptimes.length === 0) {
1053
+ timetable.warnings.push(
1054
+ `No stoptimes found for trip_id=${
1055
+ formattedTrip.trip_id
1056
+ }, route_id=${timetable.route_ids.join('_')}, timetable_id=${
1057
+ timetable.timetable_id
1058
+ }`
1059
+ );
1060
+ }
1085
1061
 
1086
- // Exclude trips after timetable `end_timestamp`
1087
- if (
1088
- timetable.end_timestamp !== '' &&
1089
- timetable.end_timestamp !== null &&
1090
- timetable.end_timestamp !== undefined
1091
- ) {
1092
- if (trip.stoptimes[0].arrival_timestamp >= timetable.end_timestamp) {
1093
- return;
1094
- }
1095
- }
1062
+ // Exclude trips before timetable `start_timestamp`
1063
+ if (
1064
+ timetable.start_timestamp !== '' &&
1065
+ timetable.start_timestamp !== null &&
1066
+ timetable.start_timestamp !== undefined &&
1067
+ trip.stoptimes[0].arrival_timestamp < timetable.start_timestamp
1068
+ ) {
1069
+ return;
1070
+ }
1096
1071
 
1097
- if (timetable.show_trip_continuation) {
1098
- await addTripContinuation(formattedTrip, timetable);
1072
+ // Exclude trips after timetable `end_timestamp`
1073
+ if (
1074
+ timetable.end_timestamp !== '' &&
1075
+ timetable.end_timestamp !== null &&
1076
+ timetable.end_timestamp !== undefined &&
1077
+ trip.stoptimes[0].arrival_timestamp >= timetable.end_timestamp
1078
+ ) {
1079
+ return;
1080
+ }
1099
1081
 
1100
- if (formattedTrip.continues_as_route) {
1101
- timetable.has_continues_as_route = true;
1102
- }
1082
+ if (timetable.show_trip_continuation) {
1083
+ addTripContinuation(formattedTrip, timetable);
1103
1084
 
1104
- if (formattedTrip.continues_from_route) {
1105
- timetable.has_continues_from_route = true;
1106
- }
1085
+ if (formattedTrip.continues_as_route) {
1086
+ timetable.has_continues_as_route = true;
1107
1087
  }
1108
1088
 
1109
- const tripFrequencies = frequencies.filter(
1110
- (frequency) => frequency.trip_id === trip.trip_id
1111
- );
1112
-
1113
- if (tripFrequencies.length === 0) {
1114
- formattedTrips.push(formattedTrip);
1115
- } else {
1116
- const frequencyTrips = generateTripsByFrequencies(
1117
- formattedTrip,
1118
- frequencies,
1119
- config
1120
- );
1121
- formattedTrips.push(...frequencyTrips);
1122
- timetable.frequencies = frequencies;
1123
- timetable.frequencyExactTimes = some(frequencies, {
1124
- exact_times: 1,
1125
- });
1089
+ if (formattedTrip.continues_from_route) {
1090
+ timetable.has_continues_from_route = true;
1126
1091
  }
1127
- })
1128
- );
1092
+ }
1093
+
1094
+ const tripFrequencies = frequencies.filter(
1095
+ (frequency) => frequency.trip_id === trip.trip_id
1096
+ );
1097
+
1098
+ if (tripFrequencies.length === 0) {
1099
+ formattedTrips.push(formattedTrip);
1100
+ } else {
1101
+ const frequencyTrips = generateTripsByFrequencies(
1102
+ formattedTrip,
1103
+ frequencies,
1104
+ config
1105
+ );
1106
+ formattedTrips.push(...frequencyTrips);
1107
+ timetable.frequencies = frequencies;
1108
+ timetable.frequencyExactTimes = some(frequencies, {
1109
+ exact_times: 1,
1110
+ });
1111
+ }
1112
+ }
1129
1113
 
1130
1114
  if (config.useParentStation) {
1131
1115
  const stopIds = [];
@@ -1136,7 +1120,7 @@ const getTripsForTimetable = async (timetable, calendars, config) => {
1136
1120
  }
1137
1121
  }
1138
1122
 
1139
- const stops = await getStops(
1123
+ const stops = getStops(
1140
1124
  {
1141
1125
  stop_id: uniq(stopIds),
1142
1126
  },
@@ -1156,73 +1140,65 @@ const getTripsForTimetable = async (timetable, calendars, config) => {
1156
1140
 
1157
1141
  return sortTrips(formattedTrips, config);
1158
1142
  };
1143
+ /* eslint-enable complexity */
1159
1144
 
1160
1145
  /*
1161
1146
  * Format timetables for display.
1162
1147
  */
1163
- const formatTimetables = async (timetables, config) => {
1164
- const formattedTimetables = await Promise.all(
1165
- timetables.map(async (timetable) => {
1166
- timetable.warnings = [];
1167
- const dayList = formatDays(timetable, config);
1168
- const calendars = await getCalendarsFromTimetable(timetable);
1169
- let serviceIds = calendars.map((calendar) => calendar.service_id);
1170
-
1171
- if (timetable.include_exceptions === 1) {
1172
- const calendarDatesServiceIds = await getCalendarDatesServiceIds(
1173
- timetable.start_date,
1174
- timetable.end_date
1175
- );
1176
- serviceIds = uniq([...serviceIds, ...calendarDatesServiceIds]);
1177
- }
1148
+ const formatTimetables = (timetables, config) => {
1149
+ const formattedTimetables = timetables.map((timetable) => {
1150
+ timetable.warnings = [];
1151
+ const dayList = formatDays(timetable, config);
1152
+ const calendars = getCalendarsFromTimetable(timetable);
1153
+ let serviceIds = calendars.map((calendar) => calendar.service_id);
1154
+
1155
+ if (timetable.include_exceptions === 1) {
1156
+ const calendarDatesServiceIds = getCalendarDatesServiceIds(
1157
+ timetable.start_date,
1158
+ timetable.end_date
1159
+ );
1160
+ serviceIds = uniq([...serviceIds, ...calendarDatesServiceIds]);
1161
+ }
1178
1162
 
1179
- Object.assign(timetable, {
1180
- noServiceSymbolUsed: false,
1181
- requestDropoffSymbolUsed: false,
1182
- noDropoffSymbolUsed: false,
1183
- requestPickupSymbolUsed: false,
1184
- noPickupSymbolUsed: false,
1185
- interpolatedStopSymbolUsed: false,
1186
- showStopCity: config.showStopCity,
1187
- showStopDescription: config.showStopDescription,
1188
- noServiceSymbol: config.noServiceSymbol,
1189
- requestDropoffSymbol: config.requestDropoffSymbol,
1190
- noDropoffSymbol: config.noDropoffSymbol,
1191
- requestPickupSymbol: config.requestPickupSymbol,
1192
- noPickupSymbol: config.noPickupSymbol,
1193
- interpolatedStopSymbol: config.interpolatedStopSymbol,
1194
- orientation: timetable.orientation || config.defaultOrientation,
1195
- service_ids: serviceIds,
1196
- dayList,
1197
- dayListLong: formatDaysLong(dayList, config),
1198
- });
1163
+ Object.assign(timetable, {
1164
+ noServiceSymbolUsed: false,
1165
+ requestDropoffSymbolUsed: false,
1166
+ noDropoffSymbolUsed: false,
1167
+ requestPickupSymbolUsed: false,
1168
+ noPickupSymbolUsed: false,
1169
+ interpolatedStopSymbolUsed: false,
1170
+ showStopCity: config.showStopCity,
1171
+ showStopDescription: config.showStopDescription,
1172
+ noServiceSymbol: config.noServiceSymbol,
1173
+ requestDropoffSymbol: config.requestDropoffSymbol,
1174
+ noDropoffSymbol: config.noDropoffSymbol,
1175
+ requestPickupSymbol: config.requestPickupSymbol,
1176
+ noPickupSymbol: config.noPickupSymbol,
1177
+ interpolatedStopSymbol: config.interpolatedStopSymbol,
1178
+ orientation: timetable.orientation || config.defaultOrientation,
1179
+ service_ids: serviceIds,
1180
+ dayList,
1181
+ dayListLong: formatDaysLong(dayList, config),
1182
+ });
1199
1183
 
1200
- timetable.orderedTrips = await getTripsForTimetable(
1201
- timetable,
1202
- calendars,
1203
- config
1204
- );
1205
- timetable.stops = await getStopsForTimetable(timetable, config);
1206
- timetable.calendarDates = await getCalendarDatesForTimetable(
1207
- timetable,
1208
- config
1209
- );
1210
- timetable.timetable_label = formatTimetableLabel(timetable);
1211
- timetable.notes = await getTimetableNotesForTimetable(timetable, config);
1184
+ timetable.orderedTrips = getTripsForTimetable(timetable, calendars, config);
1185
+ timetable.stops = getStopsForTimetable(timetable, config);
1186
+ timetable.calendarDates = getCalendarDatesForTimetable(timetable, config);
1187
+ timetable.timetable_label = formatTimetableLabel(timetable);
1188
+ timetable.notes = getTimetableNotesForTimetable(timetable, config);
1212
1189
 
1213
- if (config.showMap) {
1214
- timetable.geojson = await getTimetableGeoJSON(timetable, config);
1215
- }
1190
+ if (config.showMap) {
1191
+ timetable.geojson = getTimetableGeoJSON(timetable, config);
1192
+ }
1216
1193
 
1217
- // Filter trips after all timetable properties are assigned
1218
- timetable.orderedTrips = filterTrips(timetable);
1194
+ // Filter trips after all timetable properties are assigned
1195
+ timetable.orderedTrips = filterTrips(timetable);
1219
1196
 
1220
- // Format stops after all timetable properties are assigned
1221
- timetable.stops = formatStops(timetable, config);
1197
+ // Format stops after all timetable properties are assigned
1198
+ timetable.stops = formatStops(timetable, config);
1222
1199
 
1223
- return timetable;
1224
- })
1225
- );
1200
+ return timetable;
1201
+ });
1226
1202
 
1227
1203
  if (config.allowEmptyTimetables) {
1228
1204
  return formattedTimetables;
@@ -1236,15 +1212,15 @@ const formatTimetables = async (timetables, config) => {
1236
1212
  /*
1237
1213
  * Get all timetable pages for an agency.
1238
1214
  */
1239
- export async function getTimetablePagesForAgency(config) {
1240
- const timetables = mergeTimetablesWithSameId(await getTimetables());
1215
+ export function getTimetablePagesForAgency(config) {
1216
+ const timetables = mergeTimetablesWithSameId(getTimetables());
1241
1217
 
1242
1218
  // If no timetables, build each route and direction into a timetable.
1243
1219
  if (timetables.length === 0) {
1244
1220
  return convertRoutesToTimetablePages(config);
1245
1221
  }
1246
1222
 
1247
- const timetablePages = await getTimetablePages(
1223
+ const timetablePages = getTimetablePages(
1248
1224
  {},
1249
1225
  [],
1250
1226
  [['timetable_page_id', 'ASC']]
@@ -1253,48 +1229,44 @@ export async function getTimetablePagesForAgency(config) {
1253
1229
  // Check if there are any timetable pages defined in `timetable_pages.txt`.
1254
1230
  if (timetablePages.length === 0) {
1255
1231
  // If no timetablepages, use timetables
1256
- return Promise.all(
1257
- timetables.map((timetable) =>
1258
- convertTimetableToTimetablePage(timetable, config)
1259
- )
1232
+ return timetables.map((timetable) =>
1233
+ convertTimetableToTimetablePage(timetable, config)
1260
1234
  );
1261
1235
  }
1262
1236
 
1263
- const routes = await getRoutes();
1237
+ const routes = getRoutes();
1264
1238
 
1265
1239
  // Otherwise, use timetable pages defined in `timetable_pages.txt`.
1266
- return Promise.all(
1267
- timetablePages.map(async (timetablePage) => {
1268
- timetablePage.timetables = sortBy(
1269
- timetables.filter(
1270
- (timetable) =>
1271
- timetable.timetable_page_id === timetablePage.timetable_page_id
1272
- ),
1273
- 'timetable_sequence'
1274
- );
1240
+ return timetablePages.map((timetablePage) => {
1241
+ timetablePage.timetables = sortBy(
1242
+ timetables.filter(
1243
+ (timetable) =>
1244
+ timetable.timetable_page_id === timetablePage.timetable_page_id
1245
+ ),
1246
+ 'timetable_sequence'
1247
+ );
1275
1248
 
1276
- // Add routes for each timetable.
1277
- for (const timetable of timetablePage.timetables) {
1278
- timetable.routes = routes.filter((route) =>
1279
- timetable.route_ids.includes(route.route_id)
1280
- );
1281
- }
1249
+ // Add routes for each timetable.
1250
+ for (const timetable of timetablePage.timetables) {
1251
+ timetable.routes = routes.filter((route) =>
1252
+ timetable.route_ids.includes(route.route_id)
1253
+ );
1254
+ }
1282
1255
 
1283
- return timetablePage;
1284
- })
1285
- );
1256
+ return timetablePage;
1257
+ });
1286
1258
  }
1287
1259
 
1288
1260
  /*
1289
1261
  * Get a timetable_page by id.
1290
1262
  */
1291
- const getTimetablePageById = async (timetablePageId, config) => {
1263
+ const getTimetablePageById = (timetablePageId, config) => {
1292
1264
  // Check if there are any timetable pages defined in `timetable_pages.txt`.
1293
- const timetablePages = await getTimetablePages({
1265
+ const timetablePages = getTimetablePages({
1294
1266
  timetable_page_id: timetablePageId,
1295
1267
  });
1296
1268
 
1297
- const timetables = mergeTimetablesWithSameId(await getTimetables());
1269
+ const timetables = mergeTimetablesWithSameId(getTimetables());
1298
1270
 
1299
1271
  if (timetablePages.length > 1) {
1300
1272
  throw new Error(
@@ -1313,13 +1285,11 @@ const getTimetablePageById = async (timetablePageId, config) => {
1313
1285
  );
1314
1286
 
1315
1287
  // Add routes for each timetable
1316
- await Promise.all(
1317
- timetablePage.timetables.map(async (timetable) => {
1318
- timetable.routes = await getRoutes({
1319
- route_id: timetable.route_ids,
1320
- });
1321
- })
1322
- );
1288
+ for (const timetable of timetablePage.timetables) {
1289
+ timetable.routes = getRoutes({
1290
+ route_id: timetable.route_ids,
1291
+ });
1292
+ }
1323
1293
 
1324
1294
  return timetablePage;
1325
1295
  }
@@ -1356,11 +1326,11 @@ const getTimetablePageById = async (timetablePageId, config) => {
1356
1326
 
1357
1327
  const routeId = parts.join('|');
1358
1328
 
1359
- const routes = await getRoutes({
1329
+ const routes = getRoutes({
1360
1330
  route_id: routeId,
1361
1331
  });
1362
1332
 
1363
- const trips = await getTrips(
1333
+ const trips = getTrips(
1364
1334
  {
1365
1335
  route_id: routeId,
1366
1336
  direction_id: directionId,
@@ -1376,12 +1346,12 @@ const getTimetablePageById = async (timetablePageId, config) => {
1376
1346
  }
1377
1347
 
1378
1348
  if (/^[01]*$/.test(calendarCode)) {
1379
- calendars = await getCalendars({
1349
+ calendars = getCalendars({
1380
1350
  ...calendarCodeToCalendar(calendarCode),
1381
1351
  });
1382
1352
  } else {
1383
1353
  serviceId = calendarCode;
1384
- calendarDates = await getCalendarDates({
1354
+ calendarDates = getCalendarDates({
1385
1355
  exception_type: 1,
1386
1356
  service_id: serviceId,
1387
1357
  });
@@ -1462,10 +1432,10 @@ export function setDefaultConfig(initialConfig) {
1462
1432
  /*
1463
1433
  * Get a timetable page by id.
1464
1434
  */
1465
- export async function getFormattedTimetablePage(timetablePageId, config) {
1466
- const timetablePage = await getTimetablePageById(timetablePageId, config);
1435
+ export function getFormattedTimetablePage(timetablePageId, config) {
1436
+ const timetablePage = getTimetablePageById(timetablePageId, config);
1467
1437
 
1468
- timetablePage.consolidatedTimetables = await formatTimetables(
1438
+ timetablePage.consolidatedTimetables = formatTimetables(
1469
1439
  timetablePage.timetables,
1470
1440
  config
1471
1441
  );
@@ -1481,7 +1451,7 @@ export async function getFormattedTimetablePage(timetablePageId, config) {
1481
1451
  flatMap(timetablePage.consolidatedTimetables, 'route_ids')
1482
1452
  );
1483
1453
 
1484
- const timetableRoutes = await getRoutes(
1454
+ const timetableRoutes = getRoutes(
1485
1455
  {
1486
1456
  route_id: timetablePage.route_ids,
1487
1457
  },
@@ -1502,21 +1472,17 @@ export async function getFormattedTimetablePage(timetablePageId, config) {
1502
1472
  }
1503
1473
 
1504
1474
  // Get `direction_name` for each timetable.
1505
- await Promise.all(
1506
- timetablePage.consolidatedTimetables.map(async (timetable) => {
1507
- if (isNullOrEmpty(timetable.direction_name)) {
1508
- timetable.direction_name = await getDirectionHeadsignFromTimetable(
1509
- timetable
1510
- );
1511
- }
1475
+ for (const timetable of timetablePage.consolidatedTimetables) {
1476
+ if (isNullOrEmpty(timetable.direction_name)) {
1477
+ timetable.direction_name = getDirectionHeadsignFromTimetable(timetable);
1478
+ }
1512
1479
 
1513
- if (!timetable.routes) {
1514
- timetable.routes = await getRoutes({
1515
- route_id: timetable.route_ids,
1516
- });
1517
- }
1518
- })
1519
- );
1480
+ if (!timetable.routes) {
1481
+ timetable.routes = getRoutes({
1482
+ route_id: timetable.route_ids,
1483
+ });
1484
+ }
1485
+ }
1520
1486
 
1521
1487
  return timetablePage;
1522
1488
  }
@@ -1564,7 +1530,7 @@ export function generateTimetableHTML(timetablePage, config) {
1564
1530
  /*
1565
1531
  * Generate the CSV timetable for a timetable page.
1566
1532
  */
1567
- export async function generateTimetableCSV(timetable) {
1533
+ export function generateTimetableCSV(timetable) {
1568
1534
  // Generate horizontal orientation, then transpose if vertical is needed.
1569
1535
  const lines = [];
1570
1536
 
@@ -1606,15 +1572,15 @@ export async function generateTimetableCSV(timetable) {
1606
1572
  /*
1607
1573
  * Generate the HTML for the agency overview page.
1608
1574
  */
1609
- export async function generateOverviewHTML(timetablePages, config) {
1610
- const agencies = await getAgencies();
1575
+ export function generateOverviewHTML(timetablePages, config) {
1576
+ const agencies = getAgencies();
1611
1577
  if (agencies.length === 0) {
1612
1578
  throw new Error('No agencies found');
1613
1579
  }
1614
1580
 
1615
1581
  let geojson;
1616
1582
  if (config.showMap) {
1617
- geojson = await getAgencyGeoJSON(config);
1583
+ geojson = getAgencyGeoJSON(config);
1618
1584
  }
1619
1585
 
1620
1586
  // Sort timetables for display, first numerically then alphabetically.