gtfs-to-html 2.2.0 → 2.3.2

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/formatters.js CHANGED
@@ -1,14 +1,32 @@
1
- import { clone, find, first, flatMap, groupBy, last, omit, sortBy, uniqBy, zipObject } from 'lodash-es';
1
+ import {
2
+ clone,
3
+ find,
4
+ first,
5
+ flatMap,
6
+ groupBy,
7
+ last,
8
+ omit,
9
+ sortBy,
10
+ uniqBy,
11
+ zipObject,
12
+ } from 'lodash-es';
2
13
  import moment from 'moment';
3
14
 
4
- import { fromGTFSTime, minutesAfterMidnight, calendarToCalendarCode, secondsAfterMidnight, toGTFSTime, updateTimeByOffset } from './time-utils.js';
15
+ import {
16
+ fromGTFSTime,
17
+ minutesAfterMidnight,
18
+ calendarToCalendarCode,
19
+ secondsAfterMidnight,
20
+ toGTFSTime,
21
+ updateTimeByOffset,
22
+ } from './time-utils.js';
5
23
 
6
24
  /*
7
25
  * Replace all instances in a string with items from an object.
8
26
  */
9
27
  function replaceAll(string, mapObject) {
10
28
  const re = new RegExp(Object.keys(mapObject).join('|'), 'gi');
11
- return string.replace(re, matched => mapObject[matched]);
29
+ return string.replace(re, (matched) => mapObject[matched]);
12
30
  }
13
31
 
14
32
  /*
@@ -120,13 +138,17 @@ function filterHourlyTimes(stops) {
120
138
  // Sort stoptimes by minutes for first stop.
121
139
  const firstStopTimesAndIndex = firstStopTimes.map((time, idx) => ({
122
140
  idx,
123
- time
141
+ time,
124
142
  }));
125
- const sortedFirstStopTimesAndIndex = sortBy(firstStopTimesAndIndex, item => Number.parseInt(item.time.format('m'), 10));
143
+ const sortedFirstStopTimesAndIndex = sortBy(firstStopTimesAndIndex, (item) =>
144
+ Number.parseInt(item.time.format('m'), 10)
145
+ );
126
146
 
127
147
  // Filter and arrange stoptimes for all stops based on sort.
128
- return stops.map(stop => {
129
- stop.hourlyTimes = sortedFirstStopTimesAndIndex.map(item => fromGTFSTime(stop.trips[item.idx].arrival_time).format(':mm'));
148
+ return stops.map((stop) => {
149
+ stop.hourlyTimes = sortedFirstStopTimesAndIndex.map((item) =>
150
+ fromGTFSTime(stop.trips[item.idx].arrival_time).format(':mm')
151
+ );
130
152
 
131
153
  return stop;
132
154
  });
@@ -135,7 +157,15 @@ function filterHourlyTimes(stops) {
135
157
  /*
136
158
  * Format a calendar's list of days for display using abbreviated day names.
137
159
  */
138
- const days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
160
+ const days = [
161
+ 'monday',
162
+ 'tuesday',
163
+ 'wednesday',
164
+ 'thursday',
165
+ 'friday',
166
+ 'saturday',
167
+ 'sunday',
168
+ ];
139
169
  export function formatDays(calendar, config) {
140
170
  const daysShort = config.daysShortStrings;
141
171
  let daysInARow = 0;
@@ -146,9 +176,9 @@ export function formatDays(calendar, config) {
146
176
  }
147
177
 
148
178
  for (let i = 0; i <= 6; i += 1) {
149
- const currentDayOperating = (calendar[days[i]] === 1);
150
- const previousDayOperating = (i > 0) ? (calendar[days[i - 1]] === 1) : false;
151
- const nextDayOperating = (i < 6) ? (calendar[days[i + 1]] === 1) : false;
179
+ const currentDayOperating = calendar[days[i]] === 1;
180
+ const previousDayOperating = i > 0 ? calendar[days[i - 1]] === 1 : false;
181
+ const nextDayOperating = i < 6 ? calendar[days[i + 1]] === 1 : false;
152
182
 
153
183
  if (currentDayOperating) {
154
184
  if (dayString.length > 0) {
@@ -161,7 +191,12 @@ export function formatDays(calendar, config) {
161
191
 
162
192
  daysInARow += 1;
163
193
 
164
- if (dayString.length === 0 || !nextDayOperating || i === 6 || !previousDayOperating) {
194
+ if (
195
+ dayString.length === 0 ||
196
+ !nextDayOperating ||
197
+ i === 6 ||
198
+ !previousDayOperating
199
+ ) {
165
200
  dayString += daysShort[i];
166
201
  }
167
202
  } else {
@@ -190,7 +225,7 @@ export function formatDaysLong(dayList, config) {
190
225
  */
191
226
  export function formatTrip(trip, timetable, calendars, config) {
192
227
  trip.calendar = find(calendars, {
193
- service_id: trip.service_id
228
+ service_id: trip.service_id,
194
229
  });
195
230
  trip.dayList = formatDays(trip.calendar, config);
196
231
  trip.dayListLong = formatDaysLong(trip.dayList, config);
@@ -198,7 +233,9 @@ export function formatTrip(trip, timetable, calendars, config) {
198
233
  if (timetable.routes.length === 1) {
199
234
  trip.route_short_name = timetable.routes[0].route_short_name;
200
235
  } else {
201
- const route = timetable.routes.find(route => route.route_id === trip.route_id);
236
+ const route = timetable.routes.find(
237
+ (route) => route.route_id === trip.route_id
238
+ );
202
239
  trip.route_short_name = route.route_short_name;
203
240
  }
204
241
 
@@ -236,7 +273,9 @@ export function formatFrequency(frequency, config) {
236
273
  * Generate a timetable id.
237
274
  */
238
275
  export function formatTimetableId(timetable) {
239
- let timetableId = `${timetable.route_ids.join('_')}|${calendarToCalendarCode(timetable)}`;
276
+ let timetableId = `${timetable.route_ids.join('_')}|${calendarToCalendarCode(
277
+ timetable
278
+ )}`;
240
279
  if (!isNullOrEmpty(timetable.direction_id)) {
241
280
  timetableId += `|${timetable.direction_id}`;
242
281
  }
@@ -258,7 +297,7 @@ function createEmptyStoptime(stopId, tripId) {
258
297
  continuous_pickup: null,
259
298
  continuous_drop_off: null,
260
299
  shape_dist_traveled: null,
261
- timepoint: null
300
+ timepoint: null,
262
301
  };
263
302
  }
264
303
 
@@ -288,7 +327,9 @@ export function formatStops(timetable, config) {
288
327
  if (stop.type === 'arrival' && idx < trip.stoptimes.length - 1) {
289
328
  const departureStoptime = clone(stoptime);
290
329
  departureStoptime.type = 'departure';
291
- timetable.stops[stopIndex + 1].trips.push(formatStopTime(departureStoptime, timetable, config));
330
+ timetable.stops[stopIndex + 1].trips.push(
331
+ formatStopTime(departureStoptime, timetable, config)
332
+ );
292
333
  }
293
334
 
294
335
  // Show times if it is an arrival stop and is the first stoptime for the trip.
@@ -315,16 +356,53 @@ export function formatStops(timetable, config) {
315
356
  return timetable.stops;
316
357
  }
317
358
 
359
+ /*
360
+ * Formats a stop name.
361
+ */
362
+ export function formatStopName(stop) {
363
+ return `${stop.stop_name}${
364
+ stop.type === 'arrival'
365
+ ? ' (Arrival)'
366
+ : stop.type === 'departure'
367
+ ? ' (Departure)'
368
+ : ''
369
+ }`;
370
+ }
371
+
372
+ /*
373
+ * Formats trip "Contines from".
374
+ */
375
+ export function formatTripContinuesFrom(trip) {
376
+ return trip.continues_from_route
377
+ ? trip.continues_from_route.route.route_short_name
378
+ : '';
379
+ }
380
+
381
+ /*
382
+ * Formats trip "Contines as".
383
+ */
384
+ export function formatTripContinuesAs(trip) {
385
+ return trip.continues_as_route
386
+ ? trip.continues_as_route.route.route_short_name
387
+ : '';
388
+ }
389
+
318
390
  /*
319
391
  * Change all stoptimes of a trip so the first trip starts at midnight. Useful
320
392
  * for hourly schedules.
321
393
  */
322
394
  export function resetStoptimesToMidnight(trip) {
323
- const offsetSeconds = secondsAfterMidnight(first(trip.stoptimes).departure_time);
395
+ const offsetSeconds = secondsAfterMidnight(
396
+ first(trip.stoptimes).departure_time
397
+ );
324
398
  if (offsetSeconds > 0) {
325
399
  for (const stoptime of trip.stoptimes) {
326
- stoptime.departure_time = toGTFSTime(fromGTFSTime(stoptime.departure_time).subtract(offsetSeconds, 'seconds'));
327
- stoptime.arrival_time = toGTFSTime(fromGTFSTime(stoptime.arrival_time).subtract(offsetSeconds, 'seconds'));
400
+ stoptime.departure_time = toGTFSTime(
401
+ fromGTFSTime(stoptime.departure_time).subtract(offsetSeconds, 'seconds')
402
+ );
403
+ stoptime.arrival_time = toGTFSTime(
404
+ fromGTFSTime(stoptime.arrival_time).subtract(offsetSeconds, 'seconds')
405
+ );
328
406
  }
329
407
  }
330
408
 
@@ -336,10 +414,16 @@ export function resetStoptimesToMidnight(trip) {
336
414
  * hourly schedules.
337
415
  */
338
416
  export function updateStoptimesByOffset(trip, offsetSeconds) {
339
- return trip.stoptimes.map(stoptime => {
417
+ return trip.stoptimes.map((stoptime) => {
340
418
  delete stoptime._id;
341
- stoptime.departure_time = updateTimeByOffset(stoptime.departure_time, offsetSeconds);
342
- stoptime.arrival_time = updateTimeByOffset(stoptime.arrival_time, offsetSeconds);
419
+ stoptime.departure_time = updateTimeByOffset(
420
+ stoptime.departure_time,
421
+ offsetSeconds
422
+ );
423
+ stoptime.arrival_time = updateTimeByOffset(
424
+ stoptime.arrival_time,
425
+ offsetSeconds
426
+ );
343
427
  stoptime.trip_id = trip.trip_id;
344
428
  return stoptime;
345
429
  });
@@ -392,9 +476,18 @@ export function formatTimetablePageLabel(timetablePage) {
392
476
  }
393
477
 
394
478
  // Get label from first timetable.
395
- if (timetablePage.consolidatedTimetables && timetablePage.consolidatedTimetables.length > 0) {
396
- const routes = uniqBy(flatMap(timetablePage.consolidatedTimetables, timetable => timetable.routes), 'route_id');
397
- const timetablePageLabel = routes.map(route => formatRouteName(route));
479
+ if (
480
+ timetablePage.consolidatedTimetables &&
481
+ timetablePage.consolidatedTimetables.length > 0
482
+ ) {
483
+ const routes = uniqBy(
484
+ flatMap(
485
+ timetablePage.consolidatedTimetables,
486
+ (timetable) => timetable.routes
487
+ ),
488
+ 'route_id'
489
+ );
490
+ const timetablePageLabel = routes.map((route) => formatRouteName(route));
398
491
 
399
492
  return timetablePageLabel.join(' and ');
400
493
  }
@@ -412,10 +505,12 @@ export function mergeTimetablesWithSameId(timetables) {
412
505
 
413
506
  const mergedTimetables = groupBy(timetables, 'timetable_id');
414
507
 
415
- return Object.values(mergedTimetables).map(timetableGroup => {
508
+ return Object.values(mergedTimetables).map((timetableGroup) => {
416
509
  const mergedTimetable = omit(timetableGroup[0], 'route_id');
417
510
 
418
- mergedTimetable.route_ids = timetableGroup.map(timetable => timetable.route_id);
511
+ mergedTimetable.route_ids = timetableGroup.map(
512
+ (timetable) => timetable.route_id
513
+ );
419
514
 
420
515
  return mergedTimetable;
421
516
  });
@@ -6,14 +6,15 @@ import { featureCollection } from '@turf/helpers';
6
6
  /*
7
7
  * Merge any number of geojson objects into one. Only works for `FeatureCollection`.
8
8
  */
9
- const mergeGeojson = (...geojsons) => featureCollection(flatMap(geojsons, geojson => geojson.features));
9
+ const mergeGeojson = (...geojsons) =>
10
+ featureCollection(flatMap(geojsons, (geojson) => geojson.features));
10
11
 
11
12
  /*
12
13
  * Truncate a coordinate to a specific number of decimal places.
13
14
  */
14
15
  const truncateCoordinate = (coordinate, precision) => [
15
- Math.round(coordinate[0] * (10 ** precision)) / (10 ** precision),
16
- Math.round(coordinate[1] * (10 ** precision)) / (10 ** precision)
16
+ Math.round(coordinate[0] * 10 ** precision) / 10 ** precision,
17
+ Math.round(coordinate[1] * 10 ** precision) / 10 ** precision,
17
18
  ];
18
19
 
19
20
  /*
@@ -23,9 +24,15 @@ const truncateGeoJSONDecimals = (geojson, config) => {
23
24
  for (const feature of geojson.features) {
24
25
  if (feature.geometry.coordinates) {
25
26
  if (feature.geometry.type.toLowerCase() === 'point') {
26
- feature.geometry.coordinates = truncateCoordinate(feature.geometry.coordinates, config.coordinatePrecision);
27
+ feature.geometry.coordinates = truncateCoordinate(
28
+ feature.geometry.coordinates,
29
+ config.coordinatePrecision
30
+ );
27
31
  } else if (feature.geometry.type.toLowerCase() === 'linestring') {
28
- feature.geometry.coordinates = feature.geometry.coordinates.map(coordinate => truncateCoordinate(coordinate, config.coordinatePrecision));
32
+ feature.geometry.coordinates = feature.geometry.coordinates.map(
33
+ (coordinate) =>
34
+ truncateCoordinate(coordinate, config.coordinatePrecision)
35
+ );
29
36
  }
30
37
  }
31
38
  }
@@ -39,8 +46,8 @@ const truncateGeoJSONDecimals = (geojson, config) => {
39
46
  const simplifyGeoJSON = (geojson, config) => {
40
47
  try {
41
48
  const simplifiedGeojson = simplify(geojson, {
42
- tolerance: 1 / (10 ** config.coordinatePrecision),
43
- highQuality: true
49
+ tolerance: 1 / 10 ** config.coordinatePrecision,
50
+ highQuality: true,
44
51
  });
45
52
 
46
53
  return truncateGeoJSONDecimals(simplifiedGeojson, config);
@@ -56,16 +63,24 @@ const simplifyGeoJSON = (geojson, config) => {
56
63
  */
57
64
  export async function getTimetableGeoJSON(timetable, config) {
58
65
  const [shapesGeojsons, stopsGeojsons] = await Promise.all([
59
- await Promise.all(timetable.route_ids.map(routeId => getShapesAsGeoJSON({
60
- route_id: routeId,
61
- direction_id: timetable.direction_id,
62
- trip_id: timetable.orderedTrips.map(trip => trip.trip_id)
63
- }))),
64
- await Promise.all(timetable.route_ids.map(routeId => getStopsAsGeoJSON({
65
- route_id: routeId,
66
- direction_id: timetable.direction_id,
67
- trip_id: timetable.orderedTrips.map(trip => trip.trip_id)
68
- })))
66
+ await Promise.all(
67
+ timetable.route_ids.map((routeId) =>
68
+ getShapesAsGeoJSON({
69
+ route_id: routeId,
70
+ direction_id: timetable.direction_id,
71
+ trip_id: timetable.orderedTrips.map((trip) => trip.trip_id),
72
+ })
73
+ )
74
+ ),
75
+ await Promise.all(
76
+ timetable.route_ids.map((routeId) =>
77
+ getStopsAsGeoJSON({
78
+ route_id: routeId,
79
+ direction_id: timetable.direction_id,
80
+ trip_id: timetable.orderedTrips.map((trip) => trip.trip_id),
81
+ })
82
+ )
83
+ ),
69
84
  ]);
70
85
 
71
86
  const geojson = mergeGeojson(...shapesGeojsons, ...stopsGeojsons);
@@ -1,19 +1,41 @@
1
1
  import path from 'node:path';
2
2
  import { mkdir, writeFile } from 'node:fs/promises';
3
3
 
4
- import { each, map } from 'lodash-es';
4
+ import { map } from 'lodash-es';
5
5
  import { openDb, getDb, importGtfs } from 'gtfs';
6
6
  import sanitize from 'sanitize-filename';
7
7
  import Timer from 'timer-machine';
8
8
 
9
- import { prepDirectory, copyStaticAssets, generateFolderName, renderPdf, zipFolder } from './file-utils.js';
10
- import { log, logWarning, logError, progressBar, generateLogText, logStats } from './log-utils.js';
11
- import { setDefaultConfig, getTimetablePagesForAgency, getFormattedTimetablePage, generateHTML, generateOverviewHTML } from './utils.js';
9
+ import {
10
+ prepDirectory,
11
+ copyStaticAssets,
12
+ generateFolderName,
13
+ renderPdf,
14
+ zipFolder,
15
+ generateCSVFileName,
16
+ } from './file-utils.js';
17
+ import {
18
+ log,
19
+ logWarning,
20
+ logError,
21
+ progressBar,
22
+ generateLogText,
23
+ logStats,
24
+ } from './log-utils.js';
25
+ import {
26
+ setDefaultConfig,
27
+ getTimetablePagesForAgency,
28
+ getFormattedTimetablePage,
29
+ generateTimetableHTML,
30
+ generateTimetableCSV,
31
+ generateOverviewHTML,
32
+ generateStats,
33
+ } from './utils.js';
12
34
 
13
35
  /*
14
36
  * Generate HTML timetables from GTFS.
15
37
  */
16
- const gtfsToHtml = async initialConfig => {
38
+ const gtfsToHtml = async (initialConfig) => {
17
39
  const config = setDefaultConfig(initialConfig);
18
40
  const timer = new Timer();
19
41
 
@@ -23,9 +45,11 @@ const gtfsToHtml = async initialConfig => {
23
45
 
24
46
  timer.start();
25
47
 
26
- await openDb(config).catch(error => {
48
+ await openDb(config).catch((error) => {
27
49
  if (error instanceof Error && error.code === 'SQLITE_CANTOPEN') {
28
- config.logError(`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`);
50
+ config.logError(
51
+ `Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`
52
+ );
29
53
  }
30
54
 
31
55
  throw error;
@@ -51,7 +75,9 @@ const gtfsToHtml = async initialConfig => {
51
75
  await importGtfs(config);
52
76
  }
53
77
 
54
- const agencyKey = config.agencies.map(agency => agency.agency_key).join('-');
78
+ const agencyKey = config.agencies
79
+ .map((agency) => agency.agency_key)
80
+ .join('-');
55
81
  const exportPath = path.join(process.cwd(), 'html', sanitize(agencyKey));
56
82
  const outputStats = {
57
83
  timetables: 0,
@@ -60,14 +86,17 @@ const gtfsToHtml = async initialConfig => {
60
86
  trips: 0,
61
87
  routes: 0,
62
88
  stops: 0,
63
- warnings: []
89
+ warnings: [],
64
90
  };
65
91
 
66
92
  const timetablePages = [];
67
- const timetablePageIds = map(await getTimetablePagesForAgency(config), 'timetable_page_id');
93
+ const timetablePageIds = map(
94
+ await getTimetablePagesForAgency(config),
95
+ 'timetable_page_id'
96
+ );
68
97
  await prepDirectory(exportPath);
69
98
 
70
- if (config.noHead !== true) {
99
+ if (config.noHead !== true && ['html', 'pdf'].includes(config.outputFormat)) {
71
100
  copyStaticAssets(exportPath);
72
101
  }
73
102
 
@@ -80,10 +109,15 @@ const gtfsToHtml = async initialConfig => {
80
109
  /* eslint-disable no-await-in-loop */
81
110
  for (const timetablePageId of timetablePageIds) {
82
111
  try {
83
- const timetablePage = await getFormattedTimetablePage(timetablePageId, config);
112
+ const timetablePage = await getFormattedTimetablePage(
113
+ timetablePageId,
114
+ config
115
+ );
84
116
 
85
117
  if (timetablePage.consolidatedTimetables.length === 0) {
86
- throw new Error(`No timetables found for timetable_page_id=${timetablePage.timetable_page_id}`);
118
+ throw new Error(
119
+ `No timetables found for timetable_page_id=${timetablePage.timetable_page_id}`
120
+ );
87
121
  }
88
122
 
89
123
  for (const timetable of timetablePage.timetables) {
@@ -102,24 +136,43 @@ const gtfsToHtml = async initialConfig => {
102
136
  await mkdir(path.join(exportPath, datePath), { recursive: true });
103
137
  config.assetPath = '../';
104
138
 
105
- timetablePage.relativePath = path.join(datePath, sanitize(timetablePage.filename));
106
-
107
- const results = await generateHTML(timetablePage, config);
108
-
109
- each(outputStats, (stat, key) => {
110
- if (results.stats[key]) {
111
- outputStats[key] += results.stats[key];
139
+ timetablePage.relativePath = path.join(
140
+ datePath,
141
+ sanitize(timetablePage.filename)
142
+ );
143
+
144
+ if (config.outputFormat === 'csv') {
145
+ for (const timetable of timetablePage.timetables) {
146
+ const csv = await generateTimetableCSV(timetable);
147
+ const csvPath = path.join(
148
+ exportPath,
149
+ datePath,
150
+ generateCSVFileName(timetable, timetablePage)
151
+ );
152
+ await writeFile(csvPath, csv);
153
+ }
154
+ } else {
155
+ const html = await generateTimetableHTML(timetablePage, config);
156
+ const htmlPath = path.join(
157
+ exportPath,
158
+ datePath,
159
+ sanitize(timetablePage.filename)
160
+ );
161
+ await writeFile(htmlPath, html);
162
+
163
+ if (config.outputFormat === 'pdf') {
164
+ await renderPdf(htmlPath);
112
165
  }
113
- });
114
-
115
- const htmlPath = path.join(exportPath, datePath, sanitize(timetablePage.filename));
116
- await writeFile(htmlPath, results.html);
117
-
118
- if (config.outputFormat === 'pdf') {
119
- await renderPdf(htmlPath);
120
166
  }
121
167
 
122
168
  timetablePages.push(timetablePage);
169
+ const timetableStats = generateStats(timetablePage);
170
+
171
+ for (const key of Object.keys(outputStats)) {
172
+ if (timetableStats[key]) {
173
+ outputStats[key] += timetableStats[key];
174
+ }
175
+ }
123
176
  } catch (error) {
124
177
  outputStats.warnings.push(error.message);
125
178
  bar.interrupt(error.message);
@@ -129,10 +182,12 @@ const gtfsToHtml = async initialConfig => {
129
182
  }
130
183
  /* eslint-enable no-await-in-loop */
131
184
 
132
- // Generate route summary index.html
133
- config.assetPath = '';
134
- const html = await generateOverviewHTML(timetablePages, config);
135
- await writeFile(path.join(exportPath, 'index.html'), html);
185
+ if (config.outputFormat === 'html') {
186
+ // Generate route summary index.html
187
+ config.assetPath = '';
188
+ const html = await generateOverviewHTML(timetablePages, config);
189
+ await writeFile(path.join(exportPath, 'index.html'), html);
190
+ }
136
191
 
137
192
  // Generate output log.txt
138
193
  const logText = await generateLogText(outputStats, config);
@@ -143,15 +198,22 @@ const gtfsToHtml = async initialConfig => {
143
198
  await zipFolder(exportPath);
144
199
  }
145
200
 
146
- const fullExportPath = path.join(exportPath, config.zipOutput ? '/timetables.zip' : '');
201
+ const fullExportPath = path.join(
202
+ exportPath,
203
+ config.zipOutput ? '/timetables.zip' : ''
204
+ );
147
205
 
148
206
  // Print stats
149
- config.log(`${agencyKey}: ${config.outputFormat.toUpperCase()} timetables created at ${fullExportPath}`);
207
+ config.log(
208
+ `${agencyKey}: ${config.outputFormat.toUpperCase()} timetables created at ${fullExportPath}`
209
+ );
150
210
 
151
211
  logStats(outputStats, config);
152
212
 
153
213
  const seconds = Math.round(timer.time() / 1000);
154
- config.log(`${agencyKey}: ${config.outputFormat.toUpperCase()} timetable generation required ${seconds} seconds`);
214
+ config.log(
215
+ `${agencyKey}: ${config.outputFormat.toUpperCase()} timetable generation required ${seconds} seconds`
216
+ );
155
217
 
156
218
  timer.stop();
157
219
  };
package/lib/log-utils.js CHANGED
@@ -13,7 +13,10 @@ pe.start();
13
13
  */
14
14
  export async function generateLogText(outputStats, config) {
15
15
  const feedInfo = await getFeedInfo();
16
- const feedVersion = (feedInfo.length > 0 && feedInfo[0].feed_version) ? feedInfo[0].feed_version : 'Unknown';
16
+ const feedVersion =
17
+ feedInfo.length > 0 && feedInfo[0].feed_version
18
+ ? feedInfo[0].feed_version
19
+ : 'Unknown';
17
20
 
18
21
  const logText = [
19
22
  `Feed Version: ${feedVersion}`,
@@ -24,7 +27,7 @@ export async function generateLogText(outputStats, config) {
24
27
  `Calendar Service ID Count: ${outputStats.calendars}`,
25
28
  `Route Count: ${outputStats.routes}`,
26
29
  `Trip Count: ${outputStats.trips}`,
27
- `Stop Count: ${outputStats.stops}`
30
+ `Stop Count: ${outputStats.stops}`,
28
31
  ];
29
32
 
30
33
  for (const agency of config.agencies) {
@@ -74,7 +77,7 @@ export function logWarning(config) {
74
77
  return config.logFunction;
75
78
  }
76
79
 
77
- return text => {
80
+ return (text) => {
78
81
  process.stdout.write(`\n${formatWarning(text)}\n`);
79
82
  };
80
83
  }
@@ -87,7 +90,7 @@ export function logError(config) {
87
90
  return config.logFunction;
88
91
  }
89
92
 
90
- return text => {
93
+ return (text) => {
91
94
  process.stdout.write(`\n${formatError(text)}\n`);
92
95
  };
93
96
  }
@@ -96,7 +99,9 @@ export function logError(config) {
96
99
  * Format console warning text
97
100
  */
98
101
  export function formatWarning(text) {
99
- return `${chalk.yellow.underline('Warning')}${chalk.yellow(':')} ${chalk.yellow(text)}`;
102
+ return `${chalk.yellow.underline('Warning')}${chalk.yellow(
103
+ ':'
104
+ )} ${chalk.yellow(text)}`;
100
105
  }
101
106
 
102
107
  /*
@@ -104,7 +109,9 @@ export function formatWarning(text) {
104
109
  */
105
110
  export function formatError(error) {
106
111
  const message = error instanceof Error ? error.message : error;
107
- return `${chalk.red.underline('Error')}${chalk.red(':')} ${chalk.red(message.replace('Error: ', ''))}`;
112
+ return `${chalk.red.underline('Error')}${chalk.red(':')} ${chalk.red(
113
+ message.replace('Error: ', '')
114
+ )}`;
108
115
  }
109
116
 
110
117
  /*
@@ -118,7 +125,7 @@ export function logStats(stats, config) {
118
125
 
119
126
  const table = new Table({
120
127
  colWidths: [40, 20],
121
- head: ['Item', 'Count']
128
+ head: ['Item', 'Count'],
122
129
  });
123
130
 
124
131
  table.push(
@@ -165,7 +172,7 @@ const generateProgressBarString = (barTotal, barProgress, size = 40) => {
165
172
  }
166
173
 
167
174
  const percentage = barProgress / barTotal;
168
- const progress = Math.round((size * percentage));
175
+ const progress = Math.round(size * percentage);
169
176
  const emptyProgress = size - progress;
170
177
  const progressText = slider.repeat(progress);
171
178
  const emptyProgressText = line.repeat(emptyProgress);
@@ -181,7 +188,7 @@ export function progressBar(formatString, barTotal, config) {
181
188
  if (config.verbose === false) {
182
189
  return {
183
190
  increment: noop,
184
- interrupt: noop
191
+ interrupt: noop,
185
192
  };
186
193
  }
187
194
 
@@ -189,15 +196,16 @@ export function progressBar(formatString, barTotal, config) {
189
196
  return null;
190
197
  }
191
198
 
192
- const renderProgressString = () => formatString
193
- .replace('{value}', barProgress)
194
- .replace('{total}', barTotal)
195
- .replace('{bar}', generateProgressBarString(barTotal, barProgress));
199
+ const renderProgressString = () =>
200
+ formatString
201
+ .replace('{value}', barProgress)
202
+ .replace('{total}', barTotal)
203
+ .replace('{bar}', generateProgressBarString(barTotal, barProgress));
196
204
 
197
205
  config.log(renderProgressString(), true);
198
206
 
199
207
  return {
200
- interrupt: text => {
208
+ interrupt: (text) => {
201
209
  // Log two lines to avoid overwrite by progress bar
202
210
  config.logWarning(text);
203
211
  config.logWarning('');
@@ -205,6 +213,6 @@ export function progressBar(formatString, barTotal, config) {
205
213
  increment: () => {
206
214
  barProgress += 1;
207
215
  config.log(renderProgressString(), true);
208
- }
216
+ },
209
217
  };
210
218
  }