gtfs-to-html 2.12.5 → 2.12.7
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/dist/app/index.js +155 -43
- package/dist/app/index.js.map +1 -1
- package/dist/bin/gtfs-to-html.js +298 -70
- package/dist/bin/gtfs-to-html.js.map +1 -1
- package/dist/index.d.ts +56 -2
- package/dist/index.js +320 -63
- package/dist/index.js.map +1 -1
- package/package.json +10 -12
- package/views/default/css/timetable_styles.css +1 -2
- package/views/default/js/timetable-map.js +3 -2
- package/dist/frontend_libraries/anchorme.min.js +0 -1
- package/dist/frontend_libraries/gtfs-realtime.browser.proto.js +0 -0
- package/dist/frontend_libraries/maplibre-gl-geocoder.css +0 -284
- package/dist/frontend_libraries/maplibre-gl-geocoder.js +0 -2786
- package/dist/frontend_libraries/maplibre-gl.css +0 -1
- package/dist/frontend_libraries/maplibre-gl.js +0 -59
- package/dist/frontend_libraries/pbf.js +0 -1
package/dist/app/index.js
CHANGED
|
@@ -306,6 +306,30 @@ function formatTripNameForCSV(trip, timetable) {
|
|
|
306
306
|
return tripName;
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
+
// src/lib/errors.ts
|
|
310
|
+
import { GtfsErrorCategory, isGtfsError } from "gtfs";
|
|
311
|
+
var GtfsToHtmlError = class extends Error {
|
|
312
|
+
code;
|
|
313
|
+
category;
|
|
314
|
+
isOperational;
|
|
315
|
+
details;
|
|
316
|
+
constructor(message, options) {
|
|
317
|
+
super(message, { cause: options.cause });
|
|
318
|
+
this.name = "GtfsToHtmlError";
|
|
319
|
+
this.code = options.code;
|
|
320
|
+
this.category = options.category;
|
|
321
|
+
this.isOperational = options.isOperational ?? true;
|
|
322
|
+
this.details = options.details;
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
function isGtfsToHtmlError(error) {
|
|
326
|
+
if (!error || typeof error !== "object") {
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
const candidate = error;
|
|
330
|
+
return candidate.name === "GtfsToHtmlError" && typeof candidate.message === "string" && typeof candidate.code === "string" && typeof candidate.category === "string" && typeof candidate.isOperational === "boolean";
|
|
331
|
+
}
|
|
332
|
+
|
|
309
333
|
// src/lib/file-utils.ts
|
|
310
334
|
var homeDirectory = homedir();
|
|
311
335
|
function getPathToThisModuleFolder() {
|
|
@@ -385,7 +409,7 @@ import { featureCollection, round } from "@turf/helpers";
|
|
|
385
409
|
import { clearLine, cursorTo } from "readline";
|
|
386
410
|
import { noop } from "lodash-es";
|
|
387
411
|
import * as colors from "yoctocolors";
|
|
388
|
-
import { getAgencies, getFeedInfo } from "gtfs";
|
|
412
|
+
import { getAgencies, getFeedInfo, isGtfsError as isGtfsError2, formatGtfsError } from "gtfs";
|
|
389
413
|
import Table from "cli-table";
|
|
390
414
|
function logWarning(config2) {
|
|
391
415
|
if (config2.logFunction) {
|
|
@@ -402,6 +426,10 @@ function formatWarning(text) {
|
|
|
402
426
|
return colors.yellow(warningMessage);
|
|
403
427
|
}
|
|
404
428
|
|
|
429
|
+
// src/lib/trip-id-utils.ts
|
|
430
|
+
var getBaseTripId = (tripId) => tripId.replace(/_freq_\d+$/, "");
|
|
431
|
+
var getBaseTripIds = (trips) => Array.from(new Set(trips.map((trip) => getBaseTripId(trip.trip_id))));
|
|
432
|
+
|
|
405
433
|
// src/lib/geojson-utils.ts
|
|
406
434
|
var mergeGeojson = (...geojsons) => featureCollection(geojsons.flatMap((geojson) => geojson.features));
|
|
407
435
|
var truncateGeoJSONDecimals = (geojson, config2) => {
|
|
@@ -431,18 +459,19 @@ var truncateGeoJSONDecimals = (geojson, config2) => {
|
|
|
431
459
|
return geojson;
|
|
432
460
|
};
|
|
433
461
|
function getTimetableGeoJSON(timetable, config2) {
|
|
462
|
+
const tripIds = getBaseTripIds(timetable.orderedTrips);
|
|
434
463
|
const shapesGeojsons = timetable.route_ids.map(
|
|
435
464
|
(routeId) => getShapesAsGeoJSON({
|
|
436
465
|
route_id: routeId,
|
|
437
466
|
direction_id: timetable.direction_id,
|
|
438
|
-
trip_id:
|
|
467
|
+
trip_id: tripIds
|
|
439
468
|
})
|
|
440
469
|
);
|
|
441
470
|
const stopsGeojsons = timetable.route_ids.map(
|
|
442
471
|
(routeId) => getStopsAsGeoJSON({
|
|
443
472
|
route_id: routeId,
|
|
444
473
|
direction_id: timetable.direction_id,
|
|
445
|
-
trip_id:
|
|
474
|
+
trip_id: tripIds
|
|
446
475
|
})
|
|
447
476
|
);
|
|
448
477
|
const geojson = mergeGeojson(...shapesGeojsons, ...stopsGeojsons);
|
|
@@ -480,7 +509,7 @@ function getAgencyGeoJSON(config2) {
|
|
|
480
509
|
// package.json
|
|
481
510
|
var package_default = {
|
|
482
511
|
name: "gtfs-to-html",
|
|
483
|
-
version: "2.12.
|
|
512
|
+
version: "2.12.7",
|
|
484
513
|
private: false,
|
|
485
514
|
description: "Build human readable transit timetables as HTML, PDF or CSV from GTFS",
|
|
486
515
|
keywords: [
|
|
@@ -537,21 +566,21 @@ var package_default = {
|
|
|
537
566
|
archiver: "^7.0.1",
|
|
538
567
|
"cli-table": "^0.3.11",
|
|
539
568
|
"css.escape": "^1.5.1",
|
|
540
|
-
"csv-stringify": "^6.
|
|
569
|
+
"csv-stringify": "^6.7.0",
|
|
541
570
|
express: "^5.2.1",
|
|
542
|
-
gtfs: "^4.18.
|
|
571
|
+
gtfs: "^4.18.5",
|
|
543
572
|
"gtfs-realtime-pbf-js-module": "^1.0.0",
|
|
544
573
|
"js-beautify": "^1.15.4",
|
|
545
|
-
"lodash-es": "^4.
|
|
546
|
-
"maplibre-gl": "^5.
|
|
547
|
-
marked: "^17.0.
|
|
574
|
+
"lodash-es": "^4.18.1",
|
|
575
|
+
"maplibre-gl": "^5.21.1",
|
|
576
|
+
marked: "^17.0.5",
|
|
548
577
|
moment: "^2.30.1",
|
|
549
578
|
pbf: "^4.0.1",
|
|
550
579
|
"pretty-error": "^4.0.0",
|
|
551
580
|
pug: "^3.0.4",
|
|
552
|
-
puppeteer: "^24.
|
|
553
|
-
"sanitize-filename": "^1.6.
|
|
554
|
-
"sanitize-html": "^2.17.
|
|
581
|
+
puppeteer: "^24.40.0",
|
|
582
|
+
"sanitize-filename": "^1.6.4",
|
|
583
|
+
"sanitize-html": "^2.17.2",
|
|
555
584
|
sqlstring: "^2.3.3",
|
|
556
585
|
toposort: "^2.0.2",
|
|
557
586
|
yargs: "^18.0.0",
|
|
@@ -561,10 +590,8 @@ var package_default = {
|
|
|
561
590
|
"@types/archiver": "^7.0.0",
|
|
562
591
|
"@types/cli-table": "^0.3.4",
|
|
563
592
|
"@types/express": "^5.0.6",
|
|
564
|
-
"@types/insane": "^1.0.0",
|
|
565
593
|
"@types/js-beautify": "^1.14.3",
|
|
566
594
|
"@types/lodash-es": "^4.17.12",
|
|
567
|
-
"@types/morgan": "^1.9.10",
|
|
568
595
|
"@types/node": "^25",
|
|
569
596
|
"@types/pug": "^2.0.10",
|
|
570
597
|
"@types/sanitize-html": "^2.16.1",
|
|
@@ -575,7 +602,7 @@ var package_default = {
|
|
|
575
602
|
"lint-staged": "^16.4.0",
|
|
576
603
|
prettier: "^3.8.1",
|
|
577
604
|
tsup: "^8.5.1",
|
|
578
|
-
typescript: "^
|
|
605
|
+
typescript: "^6.0.2"
|
|
579
606
|
},
|
|
580
607
|
engines: {
|
|
581
608
|
node: ">= 22"
|
|
@@ -805,7 +832,7 @@ var getTimetableNotesForTimetable = (timetable, config2) => {
|
|
|
805
832
|
}),
|
|
806
833
|
// Get all notes for all trips in this timetable.
|
|
807
834
|
...getTimetableNotesReferences({
|
|
808
|
-
trip_id: timetable.orderedTrips
|
|
835
|
+
trip_id: getBaseTripIds(timetable.orderedTrips)
|
|
809
836
|
}),
|
|
810
837
|
// Get all notes for all stops in this timetable.
|
|
811
838
|
...getTimetableNotesReferences({
|
|
@@ -999,7 +1026,7 @@ var convertRoutesToTimetablePages = (config2) => {
|
|
|
999
1026
|
if (config2.groupTimetablesIntoPages === true) {
|
|
1000
1027
|
timetablePages.push(
|
|
1001
1028
|
createTimetablePage({
|
|
1002
|
-
timetablePageId: `route_${route.
|
|
1029
|
+
timetablePageId: `route_${route.route_id}`,
|
|
1003
1030
|
timetables,
|
|
1004
1031
|
config: config2
|
|
1005
1032
|
})
|
|
@@ -1146,8 +1173,17 @@ var getStopsForTimetable = (timetable, config2) => {
|
|
|
1146
1173
|
stop_id: stopId
|
|
1147
1174
|
});
|
|
1148
1175
|
if (stops.length === 0) {
|
|
1149
|
-
throw new
|
|
1150
|
-
`No stop found found for stop_id=${stopId} in timetable_id=${timetable.timetable_id}
|
|
1176
|
+
throw new GtfsToHtmlError(
|
|
1177
|
+
`No stop found found for stop_id=${stopId} in timetable_id=${timetable.timetable_id}`,
|
|
1178
|
+
{
|
|
1179
|
+
code: "GTFS_TO_HTML_QUERY_RESULT_NOT_FOUND" /* QUERY_RESULT_NOT_FOUND */,
|
|
1180
|
+
category: "query" /* QUERY */,
|
|
1181
|
+
details: {
|
|
1182
|
+
entity: "stop",
|
|
1183
|
+
stopId,
|
|
1184
|
+
timetableId: timetable.timetable_id
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1151
1187
|
);
|
|
1152
1188
|
}
|
|
1153
1189
|
const stop = {
|
|
@@ -1182,7 +1218,14 @@ var getCalendarsFromConfig = (config2) => {
|
|
|
1182
1218
|
const whereClauses = [];
|
|
1183
1219
|
if (config2.endDate) {
|
|
1184
1220
|
if (!moment2(config2.endDate).isValid()) {
|
|
1185
|
-
throw new
|
|
1221
|
+
throw new GtfsToHtmlError(
|
|
1222
|
+
`Invalid endDate=${config2.endDate} in config.json`,
|
|
1223
|
+
{
|
|
1224
|
+
code: "GTFS_TO_HTML_CONFIG_DATE_INVALID" /* CONFIG_DATE_INVALID */,
|
|
1225
|
+
category: "config" /* CONFIG */,
|
|
1226
|
+
details: { field: "endDate", value: config2.endDate }
|
|
1227
|
+
}
|
|
1228
|
+
);
|
|
1186
1229
|
}
|
|
1187
1230
|
whereClauses.push(
|
|
1188
1231
|
`start_date <= ${sqlString.escape(moment2(config2.endDate).format("YYYYMMDD"))}`
|
|
@@ -1190,7 +1233,14 @@ var getCalendarsFromConfig = (config2) => {
|
|
|
1190
1233
|
}
|
|
1191
1234
|
if (config2.startDate) {
|
|
1192
1235
|
if (!moment2(config2.startDate).isValid()) {
|
|
1193
|
-
throw new
|
|
1236
|
+
throw new GtfsToHtmlError(
|
|
1237
|
+
`Invalid startDate=${config2.startDate} in config.json`,
|
|
1238
|
+
{
|
|
1239
|
+
code: "GTFS_TO_HTML_CONFIG_DATE_INVALID" /* CONFIG_DATE_INVALID */,
|
|
1240
|
+
category: "config" /* CONFIG */,
|
|
1241
|
+
details: { field: "startDate", value: config2.startDate }
|
|
1242
|
+
}
|
|
1243
|
+
);
|
|
1194
1244
|
}
|
|
1195
1245
|
whereClauses.push(
|
|
1196
1246
|
`end_date >= ${sqlString.escape(moment2(config2.startDate).format("YYYYMMDD"))}`
|
|
@@ -1215,16 +1265,34 @@ var getCalendarsFromTimetable = (timetable) => {
|
|
|
1215
1265
|
const whereClauses = [];
|
|
1216
1266
|
if (timetable.end_date) {
|
|
1217
1267
|
if (!moment2(timetable.end_date, "YYYYMMDD", true).isValid()) {
|
|
1218
|
-
throw new
|
|
1219
|
-
`Invalid end_date=${timetable.end_date} for timetable_id=${timetable.timetable_id}
|
|
1268
|
+
throw new GtfsToHtmlError(
|
|
1269
|
+
`Invalid end_date=${timetable.end_date} for timetable_id=${timetable.timetable_id}`,
|
|
1270
|
+
{
|
|
1271
|
+
code: "GTFS_TO_HTML_QUERY_INVALID" /* QUERY_INVALID */,
|
|
1272
|
+
category: "validation" /* VALIDATION */,
|
|
1273
|
+
details: {
|
|
1274
|
+
field: "end_date",
|
|
1275
|
+
value: timetable.end_date,
|
|
1276
|
+
timetableId: timetable.timetable_id
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1220
1279
|
);
|
|
1221
1280
|
}
|
|
1222
1281
|
whereClauses.push(`start_date <= ${sqlString.escape(timetable.end_date)}`);
|
|
1223
1282
|
}
|
|
1224
1283
|
if (timetable.start_date) {
|
|
1225
1284
|
if (!moment2(timetable.start_date, "YYYYMMDD", true).isValid()) {
|
|
1226
|
-
throw new
|
|
1227
|
-
`Invalid start_date=${timetable.start_date} for timetable_id=${timetable.timetable_id}
|
|
1285
|
+
throw new GtfsToHtmlError(
|
|
1286
|
+
`Invalid start_date=${timetable.start_date} for timetable_id=${timetable.timetable_id}`,
|
|
1287
|
+
{
|
|
1288
|
+
code: "GTFS_TO_HTML_QUERY_INVALID" /* QUERY_INVALID */,
|
|
1289
|
+
category: "validation" /* VALIDATION */,
|
|
1290
|
+
details: {
|
|
1291
|
+
field: "start_date",
|
|
1292
|
+
value: timetable.start_date,
|
|
1293
|
+
timetableId: timetable.timetable_id
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1228
1296
|
);
|
|
1229
1297
|
}
|
|
1230
1298
|
whereClauses.push(`end_date >= ${sqlString.escape(timetable.start_date)}`);
|
|
@@ -1269,7 +1337,11 @@ var getAllStationStopIds = (stopId) => {
|
|
|
1269
1337
|
stop_id: stopId
|
|
1270
1338
|
});
|
|
1271
1339
|
if (stops.length === 0) {
|
|
1272
|
-
throw new
|
|
1340
|
+
throw new GtfsToHtmlError(`No stop found for stop_id=${stopId}`, {
|
|
1341
|
+
code: "GTFS_TO_HTML_QUERY_RESULT_NOT_FOUND" /* QUERY_RESULT_NOT_FOUND */,
|
|
1342
|
+
category: "query" /* QUERY */,
|
|
1343
|
+
details: { entity: "stop", stopId }
|
|
1344
|
+
});
|
|
1273
1345
|
}
|
|
1274
1346
|
const stop = stops[0];
|
|
1275
1347
|
if (isNullOrEmpty(stop.parent_station)) {
|
|
@@ -1303,8 +1375,13 @@ var getTripsWithSameBlock = (trip, timetable) => {
|
|
|
1303
1375
|
[["stop_sequence", "ASC"]]
|
|
1304
1376
|
);
|
|
1305
1377
|
if (stopTimes.length === 0) {
|
|
1306
|
-
throw new
|
|
1307
|
-
`No stoptimes found found for trip_id=${blockTrip.trip_id}
|
|
1378
|
+
throw new GtfsToHtmlError(
|
|
1379
|
+
`No stoptimes found found for trip_id=${blockTrip.trip_id}`,
|
|
1380
|
+
{
|
|
1381
|
+
code: "GTFS_TO_HTML_QUERY_RESULT_NOT_FOUND" /* QUERY_RESULT_NOT_FOUND */,
|
|
1382
|
+
category: "query" /* QUERY */,
|
|
1383
|
+
details: { entity: "stoptime", tripId: blockTrip.trip_id }
|
|
1384
|
+
}
|
|
1308
1385
|
);
|
|
1309
1386
|
}
|
|
1310
1387
|
blockTrip.firstStoptime = first(stopTimes);
|
|
@@ -1564,9 +1641,7 @@ var formatTimetables = (timetables, config2) => {
|
|
|
1564
1641
|
if (config2.showMap) {
|
|
1565
1642
|
timetable.geojson = getTimetableGeoJSON(timetable, config2);
|
|
1566
1643
|
}
|
|
1567
|
-
timetable.trip_ids = uniq(
|
|
1568
|
-
timetable.orderedTrips.map((trip) => trip.trip_id)
|
|
1569
|
-
);
|
|
1644
|
+
timetable.trip_ids = uniq(getBaseTripIds(timetable.orderedTrips));
|
|
1570
1645
|
timetable.orderedTrips = filterTrips(timetable, calendars, config2);
|
|
1571
1646
|
timetable.stops = formatStops(timetable, config2);
|
|
1572
1647
|
return timetable;
|
|
@@ -1645,8 +1720,18 @@ var getDataForTimetablePageById = (timetablePageId) => {
|
|
|
1645
1720
|
);
|
|
1646
1721
|
const uniqueTripDirections = uniqBy2(trips, (trip) => trip.direction_id);
|
|
1647
1722
|
if (uniqueTripDirections.length === 0) {
|
|
1648
|
-
throw new
|
|
1649
|
-
`No trips found for timetable_page_id=${timetablePageId} route_id=${routeId} direction_id=${directionId}
|
|
1723
|
+
throw new GtfsToHtmlError(
|
|
1724
|
+
`No trips found for timetable_page_id=${timetablePageId} route_id=${routeId} direction_id=${directionId}`,
|
|
1725
|
+
{
|
|
1726
|
+
code: "GTFS_TO_HTML_QUERY_RESULT_NOT_FOUND" /* QUERY_RESULT_NOT_FOUND */,
|
|
1727
|
+
category: "query" /* QUERY */,
|
|
1728
|
+
details: {
|
|
1729
|
+
entity: "trip",
|
|
1730
|
+
timetablePageId,
|
|
1731
|
+
routeId,
|
|
1732
|
+
directionId
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1650
1735
|
);
|
|
1651
1736
|
}
|
|
1652
1737
|
if (/^[01]*$/.test(calendarCode ?? "")) {
|
|
@@ -1676,8 +1761,13 @@ var getTimetablePageById = (timetablePageId, config2) => {
|
|
|
1676
1761
|
getTimetables()
|
|
1677
1762
|
);
|
|
1678
1763
|
if (timetablePages.length > 1) {
|
|
1679
|
-
throw new
|
|
1680
|
-
`Multiple timetable_pages found for timetable_page_id=${timetablePageId}
|
|
1764
|
+
throw new GtfsToHtmlError(
|
|
1765
|
+
`Multiple timetable_pages found for timetable_page_id=${timetablePageId}`,
|
|
1766
|
+
{
|
|
1767
|
+
code: "GTFS_TO_HTML_QUERY_RESULT_AMBIGUOUS" /* QUERY_RESULT_AMBIGUOUS */,
|
|
1768
|
+
category: "query" /* QUERY */,
|
|
1769
|
+
details: { entity: "timetable_page", timetablePageId }
|
|
1770
|
+
}
|
|
1681
1771
|
);
|
|
1682
1772
|
}
|
|
1683
1773
|
if (timetablePages.length === 1) {
|
|
@@ -1700,8 +1790,13 @@ var getTimetablePageById = (timetablePageId, config2) => {
|
|
|
1700
1790
|
(timetable2) => timetable2.timetable_id === timetablePageId
|
|
1701
1791
|
);
|
|
1702
1792
|
if (timetablePageTimetables.length === 0) {
|
|
1703
|
-
throw new
|
|
1704
|
-
`No timetable found for timetable_page_id=${timetablePageId}
|
|
1793
|
+
throw new GtfsToHtmlError(
|
|
1794
|
+
`No timetable found for timetable_page_id=${timetablePageId}`,
|
|
1795
|
+
{
|
|
1796
|
+
code: "GTFS_TO_HTML_QUERY_RESULT_NOT_FOUND" /* QUERY_RESULT_NOT_FOUND */,
|
|
1797
|
+
category: "query" /* QUERY */,
|
|
1798
|
+
details: { entity: "timetable", timetablePageId }
|
|
1799
|
+
}
|
|
1705
1800
|
);
|
|
1706
1801
|
}
|
|
1707
1802
|
return createTimetablePage({
|
|
@@ -1712,11 +1807,16 @@ var getTimetablePageById = (timetablePageId, config2) => {
|
|
|
1712
1807
|
}
|
|
1713
1808
|
if (timetablePageId.startsWith("route_")) {
|
|
1714
1809
|
const routes = getRoutes({
|
|
1715
|
-
|
|
1810
|
+
route_id: timetablePageId.split("_")[1]
|
|
1716
1811
|
});
|
|
1717
1812
|
if (routes.length === 0) {
|
|
1718
|
-
throw new
|
|
1719
|
-
`No route found for timetable_page_id=${timetablePageId}
|
|
1813
|
+
throw new GtfsToHtmlError(
|
|
1814
|
+
`No route found for timetable_page_id=${timetablePageId}`,
|
|
1815
|
+
{
|
|
1816
|
+
code: "GTFS_TO_HTML_QUERY_RESULT_NOT_FOUND" /* QUERY_RESULT_NOT_FOUND */,
|
|
1817
|
+
category: "query" /* QUERY */,
|
|
1818
|
+
details: { entity: "route", timetablePageId }
|
|
1819
|
+
}
|
|
1720
1820
|
);
|
|
1721
1821
|
}
|
|
1722
1822
|
const { calendars: calendars2, calendarDates: calendarDates2 } = getCalendarsFromConfig(config2);
|
|
@@ -1907,7 +2007,11 @@ function generateTimetableHTML(timetablePage, config2) {
|
|
|
1907
2007
|
function generateOverviewHTML(timetablePages, config2) {
|
|
1908
2008
|
const agencies = getAgencies2();
|
|
1909
2009
|
if (agencies.length === 0) {
|
|
1910
|
-
throw new
|
|
2010
|
+
throw new GtfsToHtmlError("No agencies found", {
|
|
2011
|
+
code: "GTFS_TO_HTML_QUERY_RESULT_NOT_FOUND" /* QUERY_RESULT_NOT_FOUND */,
|
|
2012
|
+
category: "query" /* QUERY */,
|
|
2013
|
+
details: { entity: "agency" }
|
|
2014
|
+
});
|
|
1911
2015
|
}
|
|
1912
2016
|
const geojson = config2.showMap ? getAgencyGeoJSON(config2) : void 0;
|
|
1913
2017
|
const templateVars = {
|
|
@@ -2287,7 +2391,15 @@ try {
|
|
|
2287
2391
|
console.error(
|
|
2288
2392
|
`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists and run gtfs-to-html to import GTFS before running this app.`
|
|
2289
2393
|
);
|
|
2290
|
-
throw
|
|
2394
|
+
throw new GtfsToHtmlError(
|
|
2395
|
+
`Unable to open sqlite database "${config.sqlitePath}"`,
|
|
2396
|
+
{
|
|
2397
|
+
code: "GTFS_TO_HTML_DATABASE_OPEN_FAILED" /* DATABASE_OPEN_FAILED */,
|
|
2398
|
+
category: "database" /* DATABASE */,
|
|
2399
|
+
details: { sqlitePath: config.sqlitePath, dbCode: error?.code },
|
|
2400
|
+
cause: error
|
|
2401
|
+
}
|
|
2402
|
+
);
|
|
2291
2403
|
}
|
|
2292
2404
|
app.set("views", getPathToViewsFolder(config));
|
|
2293
2405
|
app.set("view engine", "pug");
|
|
@@ -2371,7 +2483,7 @@ app.get("/timetables/:timetablePageId", async (req, res, next) => {
|
|
|
2371
2483
|
const html = await generateTimetableHTML(timetablePage, config);
|
|
2372
2484
|
res.send(html);
|
|
2373
2485
|
} catch (error) {
|
|
2374
|
-
if (error
|
|
2486
|
+
if (isGtfsToHtmlError(error) && error.code === "GTFS_TO_HTML_QUERY_RESULT_NOT_FOUND" /* QUERY_RESULT_NOT_FOUND */) {
|
|
2375
2487
|
res.status(404).send("Timetable page not found");
|
|
2376
2488
|
return;
|
|
2377
2489
|
}
|