gtfs-to-html 2.12.1 → 2.12.3
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/README.md +1 -0
- package/dist/app/index.js +102 -32
- package/dist/app/index.js.map +1 -1
- package/dist/bin/gtfs-to-html.js +113 -69
- package/dist/bin/gtfs-to-html.js.map +1 -1
- package/dist/frontend_libraries/anchorme.min.js +1 -0
- package/dist/frontend_libraries/gtfs-realtime.browser.proto.js +0 -0
- package/dist/frontend_libraries/maplibre-gl-geocoder.css +284 -0
- package/dist/frontend_libraries/maplibre-gl-geocoder.js +2790 -0
- package/dist/frontend_libraries/maplibre-gl.css +1 -0
- package/dist/frontend_libraries/maplibre-gl.js +59 -0
- package/dist/frontend_libraries/pbf.js +1 -0
- package/dist/index.js +113 -69
- package/dist/index.js.map +1 -1
- package/package.json +14 -11
- package/scripts/postinstall.js +115 -0
package/README.md
CHANGED
|
@@ -62,6 +62,7 @@ Many transit agencies use `gtfs-to-html` to generate the schedule pages used on
|
|
|
62
62
|
| Agency | Location |
|
|
63
63
|
| ----------------------------------------------------------------------------- | ----------------------------------- |
|
|
64
64
|
| [Basin Transit](https://basin-transit.com) | Morongo Basin, California |
|
|
65
|
+
| [Bayway Transit](https://www.baywaytransit.org) | Panama City, Florida |
|
|
65
66
|
| [Brockton Area Transit Authority](https://ridebat.com) | Brockton, Massachusetts |
|
|
66
67
|
| [Cape Ann Transportation Authority](https://canntran.com) | Gloucester, Massachusetts |
|
|
67
68
|
| [Capital Transit](https://juneaucapitaltransit.org) | Juneau, Alaska |
|
package/dist/app/index.js
CHANGED
|
@@ -39,11 +39,11 @@ function fromGTFSTime(timeString) {
|
|
|
39
39
|
function toGTFSTime(time) {
|
|
40
40
|
return time.format("HH:mm:ss");
|
|
41
41
|
}
|
|
42
|
-
function calendarToCalendarCode(
|
|
43
|
-
if (Object.values(
|
|
42
|
+
function calendarToCalendarCode(calendar) {
|
|
43
|
+
if (Object.values(calendar).every((value) => value === null)) {
|
|
44
44
|
return "";
|
|
45
45
|
}
|
|
46
|
-
return `${
|
|
46
|
+
return `${calendar.monday ?? "0"}${calendar.tuesday ?? "0"}${calendar.wednesday ?? "0"}${calendar.thursday ?? "0"}${calendar.friday ?? "0"}${calendar.saturday ?? "0"}${calendar.sunday ?? "0"}`;
|
|
47
47
|
}
|
|
48
48
|
function calendarCodeToCalendar(code) {
|
|
49
49
|
const days2 = [
|
|
@@ -61,6 +61,35 @@ function calendarCodeToCalendar(code) {
|
|
|
61
61
|
}
|
|
62
62
|
return calendar;
|
|
63
63
|
}
|
|
64
|
+
function calendarToDateList(calendar, startDate, endDate) {
|
|
65
|
+
if (!startDate || !endDate) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
const activeWeekdays = [
|
|
69
|
+
calendar.monday === 1 ? 1 : null,
|
|
70
|
+
calendar.tuesday === 1 ? 2 : null,
|
|
71
|
+
calendar.wednesday === 1 ? 3 : null,
|
|
72
|
+
calendar.thursday === 1 ? 4 : null,
|
|
73
|
+
calendar.friday === 1 ? 5 : null,
|
|
74
|
+
calendar.saturday === 1 ? 6 : null,
|
|
75
|
+
calendar.sunday === 1 ? 7 : null
|
|
76
|
+
].filter((weekday) => weekday !== null);
|
|
77
|
+
if (activeWeekdays.length === 0) {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
const activeWeekdaySet = new Set(activeWeekdays);
|
|
81
|
+
const dates = /* @__PURE__ */ new Set();
|
|
82
|
+
const date = moment(startDate.toString(), "YYYYMMDD");
|
|
83
|
+
const endDateMoment = moment(endDate.toString(), "YYYYMMDD");
|
|
84
|
+
while (date.isSameOrBefore(endDateMoment)) {
|
|
85
|
+
const isoWeekday = date.isoWeekday();
|
|
86
|
+
if (activeWeekdaySet.has(isoWeekday)) {
|
|
87
|
+
dates.add(parseInt(date.format("YYYYMMDD"), 10));
|
|
88
|
+
}
|
|
89
|
+
date.add(1, "day");
|
|
90
|
+
}
|
|
91
|
+
return Array.from(dates);
|
|
92
|
+
}
|
|
64
93
|
function secondsAfterMidnight(timeString) {
|
|
65
94
|
return moment.duration(timeString).asSeconds();
|
|
66
95
|
}
|
|
@@ -136,7 +165,6 @@ import {
|
|
|
136
165
|
rm
|
|
137
166
|
} from "fs/promises";
|
|
138
167
|
import { homedir } from "os";
|
|
139
|
-
import { findPackageJSON } from "module";
|
|
140
168
|
import * as _ from "lodash-es";
|
|
141
169
|
import { uniqBy } from "lodash-es";
|
|
142
170
|
import archiver from "archiver";
|
|
@@ -259,20 +287,23 @@ function formatTripNameForCSV(trip, timetable) {
|
|
|
259
287
|
|
|
260
288
|
// src/lib/file-utils.ts
|
|
261
289
|
var homeDirectory = homedir();
|
|
262
|
-
function
|
|
263
|
-
if (config2.templatePath) {
|
|
264
|
-
return untildify(config2.templatePath);
|
|
265
|
-
}
|
|
290
|
+
function getPathToThisModuleFolder() {
|
|
266
291
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
267
|
-
let
|
|
292
|
+
let distFolderPath;
|
|
268
293
|
if (__dirname.endsWith("/dist/bin") || __dirname.endsWith("/dist/app")) {
|
|
269
|
-
|
|
294
|
+
distFolderPath = resolve(__dirname, "../../");
|
|
270
295
|
} else if (__dirname.endsWith("/dist")) {
|
|
271
|
-
|
|
296
|
+
distFolderPath = resolve(__dirname, "../");
|
|
272
297
|
} else {
|
|
273
|
-
|
|
298
|
+
distFolderPath = resolve(__dirname, "../../");
|
|
299
|
+
}
|
|
300
|
+
return distFolderPath;
|
|
301
|
+
}
|
|
302
|
+
function getPathToViewsFolder(config2) {
|
|
303
|
+
if (config2.templatePath) {
|
|
304
|
+
return untildify(config2.templatePath);
|
|
274
305
|
}
|
|
275
|
-
return
|
|
306
|
+
return join(getPathToThisModuleFolder(), "views/default");
|
|
276
307
|
}
|
|
277
308
|
function getPathToTemplateFile(templateFileName, config2) {
|
|
278
309
|
const fullTemplateFileName = config2.noHead !== true ? `${templateFileName}_full.pug` : `${templateFileName}.pug`;
|
|
@@ -428,7 +459,7 @@ function getAgencyGeoJSON(config2) {
|
|
|
428
459
|
// package.json
|
|
429
460
|
var package_default = {
|
|
430
461
|
name: "gtfs-to-html",
|
|
431
|
-
version: "2.12.
|
|
462
|
+
version: "2.12.3",
|
|
432
463
|
private: false,
|
|
433
464
|
description: "Build human readable transit timetables as HTML, PDF or CSV from GTFS",
|
|
434
465
|
keywords: [
|
|
@@ -463,6 +494,7 @@ var package_default = {
|
|
|
463
494
|
"dist",
|
|
464
495
|
"docker",
|
|
465
496
|
"examples",
|
|
497
|
+
"scripts",
|
|
466
498
|
"views/default",
|
|
467
499
|
"config-sample.json"
|
|
468
500
|
],
|
|
@@ -471,30 +503,32 @@ var package_default = {
|
|
|
471
503
|
},
|
|
472
504
|
scripts: {
|
|
473
505
|
build: "tsup",
|
|
506
|
+
postbuild: "node scripts/postinstall.js",
|
|
474
507
|
start: "node ./dist/app",
|
|
475
|
-
prepare: "husky"
|
|
508
|
+
prepare: "husky && npm run build",
|
|
509
|
+
postinstall: "node scripts/postinstall.js"
|
|
476
510
|
},
|
|
477
511
|
dependencies: {
|
|
478
512
|
"@maplibre/maplibre-gl-geocoder": "^1.9.1",
|
|
479
|
-
"@turf/helpers": "^7.3.
|
|
480
|
-
"@turf/simplify": "^7.3.
|
|
513
|
+
"@turf/helpers": "^7.3.1",
|
|
514
|
+
"@turf/simplify": "^7.3.1",
|
|
481
515
|
anchorme: "^3.0.8",
|
|
482
516
|
archiver: "^7.0.1",
|
|
483
517
|
"cli-table": "^0.3.11",
|
|
484
518
|
"css.escape": "^1.5.1",
|
|
485
519
|
"csv-stringify": "^6.6.0",
|
|
486
|
-
express: "^5.1
|
|
487
|
-
gtfs: "^4.18.
|
|
520
|
+
express: "^5.2.1",
|
|
521
|
+
gtfs: "^4.18.2",
|
|
488
522
|
"gtfs-realtime-pbf-js-module": "^1.0.0",
|
|
489
523
|
"js-beautify": "^1.15.4",
|
|
490
524
|
"lodash-es": "^4.17.21",
|
|
491
|
-
"maplibre-gl": "^5.
|
|
492
|
-
marked: "^17.0.
|
|
525
|
+
"maplibre-gl": "^5.14.0",
|
|
526
|
+
marked: "^17.0.1",
|
|
493
527
|
moment: "^2.30.1",
|
|
494
528
|
pbf: "^4.0.1",
|
|
495
529
|
"pretty-error": "^4.0.0",
|
|
496
530
|
pug: "^3.0.3",
|
|
497
|
-
puppeteer: "^24.
|
|
531
|
+
puppeteer: "^24.32.0",
|
|
498
532
|
"sanitize-filename": "^1.6.3",
|
|
499
533
|
"sanitize-html": "^2.17.0",
|
|
500
534
|
sqlstring: "^2.3.3",
|
|
@@ -505,7 +539,7 @@ var package_default = {
|
|
|
505
539
|
devDependencies: {
|
|
506
540
|
"@types/archiver": "^7.0.0",
|
|
507
541
|
"@types/cli-table": "^0.3.4",
|
|
508
|
-
"@types/express": "^5.0.
|
|
542
|
+
"@types/express": "^5.0.6",
|
|
509
543
|
"@types/insane": "^1.0.0",
|
|
510
544
|
"@types/js-beautify": "^1.14.3",
|
|
511
545
|
"@types/lodash-es": "^4.17.12",
|
|
@@ -518,7 +552,7 @@ var package_default = {
|
|
|
518
552
|
"@types/yargs": "^17.0.35",
|
|
519
553
|
husky: "^9.1.7",
|
|
520
554
|
"lint-staged": "^16.2.7",
|
|
521
|
-
prettier: "^3.
|
|
555
|
+
prettier: "^3.7.4",
|
|
522
556
|
tsup: "^8.5.1",
|
|
523
557
|
typescript: "^5.9.3"
|
|
524
558
|
},
|
|
@@ -1183,9 +1217,9 @@ var getCalendarsFromTimetable = (timetable) => {
|
|
|
1183
1217
|
}
|
|
1184
1218
|
return db.prepare(`SELECT * FROM calendar ${whereClause}`).all();
|
|
1185
1219
|
};
|
|
1186
|
-
var
|
|
1220
|
+
var getCalendarDatesForDateRange = (startDate, endDate) => {
|
|
1187
1221
|
const db = openDb();
|
|
1188
|
-
const whereClauses = [
|
|
1222
|
+
const whereClauses = [];
|
|
1189
1223
|
if (endDate) {
|
|
1190
1224
|
whereClauses.push(`date <= ${sqlString.escape(endDate)}`);
|
|
1191
1225
|
}
|
|
@@ -1193,11 +1227,11 @@ var getCalendarDatesServiceIds = (startDate, endDate) => {
|
|
|
1193
1227
|
whereClauses.push(`date >= ${sqlString.escape(startDate)}`);
|
|
1194
1228
|
}
|
|
1195
1229
|
const calendarDates = db.prepare(
|
|
1196
|
-
`SELECT
|
|
1230
|
+
`SELECT service_id, date, exception_type FROM calendar_dates WHERE ${whereClauses.join(
|
|
1197
1231
|
" AND "
|
|
1198
1232
|
)}`
|
|
1199
1233
|
).all();
|
|
1200
|
-
return calendarDates
|
|
1234
|
+
return calendarDates;
|
|
1201
1235
|
};
|
|
1202
1236
|
var getAllStationStopIds = (stopId) => {
|
|
1203
1237
|
const stops = getStops({
|
|
@@ -1408,13 +1442,49 @@ var formatTimetables = (timetables, config2) => {
|
|
|
1408
1442
|
timetable.warnings = [];
|
|
1409
1443
|
const dayList = formatDays(timetable, config2);
|
|
1410
1444
|
const calendars = getCalendarsFromTimetable(timetable);
|
|
1411
|
-
|
|
1445
|
+
const serviceIds = /* @__PURE__ */ new Set();
|
|
1446
|
+
for (const calendar of calendars) {
|
|
1447
|
+
serviceIds.add(calendar.service_id);
|
|
1448
|
+
}
|
|
1412
1449
|
if (timetable.include_exceptions === 1) {
|
|
1413
|
-
const
|
|
1450
|
+
const calendarDates = getCalendarDatesForDateRange(
|
|
1414
1451
|
timetable.start_date,
|
|
1415
1452
|
timetable.end_date
|
|
1416
1453
|
);
|
|
1417
|
-
|
|
1454
|
+
const calendarDateGroups = groupBy(calendarDates, "service_id");
|
|
1455
|
+
for (const [serviceId, calendarDateGroup] of Object.entries(
|
|
1456
|
+
calendarDateGroups
|
|
1457
|
+
)) {
|
|
1458
|
+
const calendar = calendars.find(
|
|
1459
|
+
(c) => c.service_id === serviceId
|
|
1460
|
+
);
|
|
1461
|
+
if (calendarDateGroup.some(
|
|
1462
|
+
(calendarDate) => calendarDate.exception_type === 1
|
|
1463
|
+
)) {
|
|
1464
|
+
serviceIds.add(serviceId);
|
|
1465
|
+
}
|
|
1466
|
+
const calendarDateGroupExceptionType2 = calendarDateGroup.filter(
|
|
1467
|
+
(calendarDate) => calendarDate.exception_type === 2
|
|
1468
|
+
);
|
|
1469
|
+
if (timetable.start_date && timetable.end_date && calendar && calendarDateGroupExceptionType2.length > 0) {
|
|
1470
|
+
const datesDuringDateRange = calendarToDateList(
|
|
1471
|
+
calendar,
|
|
1472
|
+
timetable.start_date,
|
|
1473
|
+
timetable.end_date
|
|
1474
|
+
);
|
|
1475
|
+
if (datesDuringDateRange.length === 0) {
|
|
1476
|
+
serviceIds.delete(serviceId);
|
|
1477
|
+
}
|
|
1478
|
+
const everyDateIsExcluded = datesDuringDateRange.every(
|
|
1479
|
+
(dateDuringDateRange) => calendarDateGroupExceptionType2.some(
|
|
1480
|
+
(calendarDate) => calendarDate.date === dateDuringDateRange
|
|
1481
|
+
)
|
|
1482
|
+
);
|
|
1483
|
+
if (everyDateIsExcluded) {
|
|
1484
|
+
serviceIds.delete(serviceId);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1418
1488
|
}
|
|
1419
1489
|
Object.assign(timetable, {
|
|
1420
1490
|
noServiceSymbolUsed: false,
|
|
@@ -1432,7 +1502,7 @@ var formatTimetables = (timetables, config2) => {
|
|
|
1432
1502
|
noPickupSymbol: config2.noPickupSymbol,
|
|
1433
1503
|
interpolatedStopSymbol: config2.interpolatedStopSymbol,
|
|
1434
1504
|
orientation: timetable.orientation || config2.defaultOrientation,
|
|
1435
|
-
service_ids: serviceIds,
|
|
1505
|
+
service_ids: Array.from(serviceIds),
|
|
1436
1506
|
dayList,
|
|
1437
1507
|
dayListLong: formatDaysLong(dayList, config2)
|
|
1438
1508
|
});
|