gtfs-to-html 2.12.2 → 2.12.4
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 +140 -41
- package/dist/app/index.js.map +1 -1
- package/dist/bin/gtfs-to-html.js +140 -41
- package/dist/bin/gtfs-to-html.js.map +1 -1
- package/dist/frontend_libraries/maplibre-gl-geocoder.js +99 -103
- package/dist/frontend_libraries/maplibre-gl.js +4 -4
- package/dist/index.js +140 -41
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/views/default/css/timetable_styles.css +1 -1
- package/views/default/formatting_functions.pug +1 -1
package/dist/index.js
CHANGED
|
@@ -61,11 +61,11 @@ function fromGTFSTime(timeString) {
|
|
|
61
61
|
function toGTFSTime(time) {
|
|
62
62
|
return time.format("HH:mm:ss");
|
|
63
63
|
}
|
|
64
|
-
function calendarToCalendarCode(
|
|
65
|
-
if (Object.values(
|
|
64
|
+
function calendarToCalendarCode(calendar) {
|
|
65
|
+
if (Object.values(calendar).every((value) => value === null)) {
|
|
66
66
|
return "";
|
|
67
67
|
}
|
|
68
|
-
return `${
|
|
68
|
+
return `${calendar.monday ?? "0"}${calendar.tuesday ?? "0"}${calendar.wednesday ?? "0"}${calendar.thursday ?? "0"}${calendar.friday ?? "0"}${calendar.saturday ?? "0"}${calendar.sunday ?? "0"}`;
|
|
69
69
|
}
|
|
70
70
|
function calendarCodeToCalendar(code) {
|
|
71
71
|
const days2 = [
|
|
@@ -83,6 +83,56 @@ function calendarCodeToCalendar(code) {
|
|
|
83
83
|
}
|
|
84
84
|
return calendar;
|
|
85
85
|
}
|
|
86
|
+
function calendarToDateList(calendar, startDate, endDate) {
|
|
87
|
+
if (!startDate || !endDate) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
const activeWeekdays = [
|
|
91
|
+
calendar.monday === 1 ? 1 : null,
|
|
92
|
+
calendar.tuesday === 1 ? 2 : null,
|
|
93
|
+
calendar.wednesday === 1 ? 3 : null,
|
|
94
|
+
calendar.thursday === 1 ? 4 : null,
|
|
95
|
+
calendar.friday === 1 ? 5 : null,
|
|
96
|
+
calendar.saturday === 1 ? 6 : null,
|
|
97
|
+
calendar.sunday === 1 ? 7 : null
|
|
98
|
+
].filter((weekday) => weekday !== null);
|
|
99
|
+
if (activeWeekdays.length === 0) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
const activeWeekdaySet = new Set(activeWeekdays);
|
|
103
|
+
const dates = /* @__PURE__ */ new Set();
|
|
104
|
+
const date = moment(startDate.toString(), "YYYYMMDD");
|
|
105
|
+
const endDateMoment = moment(endDate.toString(), "YYYYMMDD");
|
|
106
|
+
while (date.isSameOrBefore(endDateMoment)) {
|
|
107
|
+
const isoWeekday = date.isoWeekday();
|
|
108
|
+
if (activeWeekdaySet.has(isoWeekday)) {
|
|
109
|
+
dates.add(parseInt(date.format("YYYYMMDD"), 10));
|
|
110
|
+
}
|
|
111
|
+
date.add(1, "day");
|
|
112
|
+
}
|
|
113
|
+
return Array.from(dates);
|
|
114
|
+
}
|
|
115
|
+
function combineCalendars(calendars) {
|
|
116
|
+
const combinedCalendar = {
|
|
117
|
+
monday: 0,
|
|
118
|
+
tuesday: 0,
|
|
119
|
+
wednesday: 0,
|
|
120
|
+
thursday: 0,
|
|
121
|
+
friday: 0,
|
|
122
|
+
saturday: 0,
|
|
123
|
+
sunday: 0
|
|
124
|
+
};
|
|
125
|
+
for (const calendar of calendars) {
|
|
126
|
+
for (const day of Object.keys(
|
|
127
|
+
combinedCalendar
|
|
128
|
+
)) {
|
|
129
|
+
if (calendar[day] === 1) {
|
|
130
|
+
combinedCalendar[day] = 1;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return combinedCalendar;
|
|
135
|
+
}
|
|
86
136
|
function secondsAfterMidnight(timeString) {
|
|
87
137
|
return moment.duration(timeString).asSeconds();
|
|
88
138
|
}
|
|
@@ -493,7 +543,7 @@ function formatTripNameForCSV(trip, timetable) {
|
|
|
493
543
|
// package.json
|
|
494
544
|
var package_default = {
|
|
495
545
|
name: "gtfs-to-html",
|
|
496
|
-
version: "2.12.
|
|
546
|
+
version: "2.12.4",
|
|
497
547
|
private: false,
|
|
498
548
|
description: "Build human readable transit timetables as HTML, PDF or CSV from GTFS",
|
|
499
549
|
keywords: [
|
|
@@ -543,26 +593,26 @@ var package_default = {
|
|
|
543
593
|
postinstall: "node scripts/postinstall.js"
|
|
544
594
|
},
|
|
545
595
|
dependencies: {
|
|
546
|
-
"@maplibre/maplibre-gl-geocoder": "^1.9.
|
|
547
|
-
"@turf/helpers": "^7.3.
|
|
548
|
-
"@turf/simplify": "^7.3.
|
|
596
|
+
"@maplibre/maplibre-gl-geocoder": "^1.9.4",
|
|
597
|
+
"@turf/helpers": "^7.3.2",
|
|
598
|
+
"@turf/simplify": "^7.3.2",
|
|
549
599
|
anchorme: "^3.0.8",
|
|
550
600
|
archiver: "^7.0.1",
|
|
551
601
|
"cli-table": "^0.3.11",
|
|
552
602
|
"css.escape": "^1.5.1",
|
|
553
603
|
"csv-stringify": "^6.6.0",
|
|
554
604
|
express: "^5.2.1",
|
|
555
|
-
gtfs: "^4.18.
|
|
605
|
+
gtfs: "^4.18.3",
|
|
556
606
|
"gtfs-realtime-pbf-js-module": "^1.0.0",
|
|
557
607
|
"js-beautify": "^1.15.4",
|
|
558
|
-
"lodash-es": "^4.17.
|
|
559
|
-
"maplibre-gl": "^5.
|
|
608
|
+
"lodash-es": "^4.17.23",
|
|
609
|
+
"maplibre-gl": "^5.16.0",
|
|
560
610
|
marked: "^17.0.1",
|
|
561
611
|
moment: "^2.30.1",
|
|
562
612
|
pbf: "^4.0.1",
|
|
563
613
|
"pretty-error": "^4.0.0",
|
|
564
614
|
pug: "^3.0.3",
|
|
565
|
-
puppeteer: "^24.
|
|
615
|
+
puppeteer: "^24.35.0",
|
|
566
616
|
"sanitize-filename": "^1.6.3",
|
|
567
617
|
"sanitize-html": "^2.17.0",
|
|
568
618
|
sqlstring: "^2.3.3",
|
|
@@ -578,7 +628,7 @@ var package_default = {
|
|
|
578
628
|
"@types/js-beautify": "^1.14.3",
|
|
579
629
|
"@types/lodash-es": "^4.17.12",
|
|
580
630
|
"@types/morgan": "^1.9.10",
|
|
581
|
-
"@types/node": "^
|
|
631
|
+
"@types/node": "^25",
|
|
582
632
|
"@types/pug": "^2.0.10",
|
|
583
633
|
"@types/sanitize-html": "^2.16.0",
|
|
584
634
|
"@types/sqlstring": "^2.3.2",
|
|
@@ -586,7 +636,7 @@ var package_default = {
|
|
|
586
636
|
"@types/yargs": "^17.0.35",
|
|
587
637
|
husky: "^9.1.7",
|
|
588
638
|
"lint-staged": "^16.2.7",
|
|
589
|
-
prettier: "^3.
|
|
639
|
+
prettier: "^3.8.1",
|
|
590
640
|
tsup: "^8.5.1",
|
|
591
641
|
typescript: "^5.9.3"
|
|
592
642
|
},
|
|
@@ -667,6 +717,16 @@ var deduplicateTrips = (trips) => {
|
|
|
667
717
|
).join("|");
|
|
668
718
|
if (!uniqueTrips.has(tripSignature)) {
|
|
669
719
|
uniqueTrips.set(tripSignature, trip);
|
|
720
|
+
} else {
|
|
721
|
+
const existingTrip = uniqueTrips.get(tripSignature);
|
|
722
|
+
if (!existingTrip) {
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
if (!existingTrip.additional_service_ids) {
|
|
726
|
+
existingTrip.additional_service_ids = [];
|
|
727
|
+
}
|
|
728
|
+
existingTrip.additional_service_ids.push(trip.service_id);
|
|
729
|
+
uniqueTrips.set(tripSignature, existingTrip);
|
|
670
730
|
}
|
|
671
731
|
}
|
|
672
732
|
return Array.from(uniqueTrips.values());
|
|
@@ -1251,9 +1311,9 @@ var getCalendarsFromTimetable = (timetable) => {
|
|
|
1251
1311
|
}
|
|
1252
1312
|
return db.prepare(`SELECT * FROM calendar ${whereClause}`).all();
|
|
1253
1313
|
};
|
|
1254
|
-
var
|
|
1314
|
+
var getCalendarDatesForDateRange = (startDate, endDate) => {
|
|
1255
1315
|
const db = openDb();
|
|
1256
|
-
const whereClauses = [
|
|
1316
|
+
const whereClauses = [];
|
|
1257
1317
|
if (endDate) {
|
|
1258
1318
|
whereClauses.push(`date <= ${sqlString.escape(endDate)}`);
|
|
1259
1319
|
}
|
|
@@ -1261,11 +1321,11 @@ var getCalendarDatesServiceIds = (startDate, endDate) => {
|
|
|
1261
1321
|
whereClauses.push(`date >= ${sqlString.escape(startDate)}`);
|
|
1262
1322
|
}
|
|
1263
1323
|
const calendarDates = db.prepare(
|
|
1264
|
-
`SELECT
|
|
1324
|
+
`SELECT service_id, date, exception_type FROM calendar_dates WHERE ${whereClauses.join(
|
|
1265
1325
|
" AND "
|
|
1266
1326
|
)}`
|
|
1267
1327
|
).all();
|
|
1268
|
-
return calendarDates
|
|
1328
|
+
return calendarDates;
|
|
1269
1329
|
};
|
|
1270
1330
|
var getAllStationStopIds = (stopId) => {
|
|
1271
1331
|
const stops = getStops({
|
|
@@ -1348,7 +1408,7 @@ var addTripContinuation = (trip, timetable) => {
|
|
|
1348
1408
|
trip.continues_as_route = nextTrip;
|
|
1349
1409
|
}
|
|
1350
1410
|
};
|
|
1351
|
-
var filterTrips = (timetable, config) => {
|
|
1411
|
+
var filterTrips = (timetable, calendars, config) => {
|
|
1352
1412
|
let filteredTrips = timetable.orderedTrips;
|
|
1353
1413
|
for (const trip of filteredTrips) {
|
|
1354
1414
|
const combinedStoptimes = [];
|
|
@@ -1375,7 +1435,26 @@ var filterTrips = (timetable, config) => {
|
|
|
1375
1435
|
if (config.showDuplicateTrips === false) {
|
|
1376
1436
|
filteredTrips = deduplicateTrips(filteredTrips);
|
|
1377
1437
|
}
|
|
1378
|
-
|
|
1438
|
+
const formattedTrips = filteredTrips.map((trip) => {
|
|
1439
|
+
const tripCalendars = calendars.filter((calendar) => {
|
|
1440
|
+
return [
|
|
1441
|
+
trip.service_id,
|
|
1442
|
+
...trip.additional_service_ids || []
|
|
1443
|
+
].includes(calendar.service_id);
|
|
1444
|
+
}) ?? [];
|
|
1445
|
+
trip.dayList = formatDays(combineCalendars(tripCalendars), config);
|
|
1446
|
+
trip.dayListLong = formatDaysLong(trip.dayList, config);
|
|
1447
|
+
if (timetable.routes.length === 1) {
|
|
1448
|
+
trip.route_short_name = timetable.routes[0].route_short_name;
|
|
1449
|
+
} else {
|
|
1450
|
+
const route = timetable.routes.find(
|
|
1451
|
+
(route2) => route2.route_id === trip.route_id
|
|
1452
|
+
);
|
|
1453
|
+
trip.route_short_name = route?.route_short_name;
|
|
1454
|
+
}
|
|
1455
|
+
return trip;
|
|
1456
|
+
});
|
|
1457
|
+
return formattedTrips;
|
|
1379
1458
|
};
|
|
1380
1459
|
var getTripsForTimetable = (timetable, calendars, config) => {
|
|
1381
1460
|
const tripQuery = {
|
|
@@ -1401,7 +1480,7 @@ var getTripsForTimetable = (timetable, calendars, config) => {
|
|
|
1401
1480
|
timetable.service_ids = uniq(trips.map((trip) => trip.service_id));
|
|
1402
1481
|
const formattedTrips = [];
|
|
1403
1482
|
for (const trip of trips) {
|
|
1404
|
-
const formattedTrip =
|
|
1483
|
+
const formattedTrip = trip;
|
|
1405
1484
|
formattedTrip.stoptimes = getStoptimes(
|
|
1406
1485
|
{
|
|
1407
1486
|
trip_id: formattedTrip.trip_id
|
|
@@ -1476,13 +1555,49 @@ var formatTimetables = (timetables, config) => {
|
|
|
1476
1555
|
timetable.warnings = [];
|
|
1477
1556
|
const dayList = formatDays(timetable, config);
|
|
1478
1557
|
const calendars = getCalendarsFromTimetable(timetable);
|
|
1479
|
-
|
|
1558
|
+
const serviceIds = /* @__PURE__ */ new Set();
|
|
1559
|
+
for (const calendar of calendars) {
|
|
1560
|
+
serviceIds.add(calendar.service_id);
|
|
1561
|
+
}
|
|
1480
1562
|
if (timetable.include_exceptions === 1) {
|
|
1481
|
-
const
|
|
1563
|
+
const calendarDates = getCalendarDatesForDateRange(
|
|
1482
1564
|
timetable.start_date,
|
|
1483
1565
|
timetable.end_date
|
|
1484
1566
|
);
|
|
1485
|
-
|
|
1567
|
+
const calendarDateGroups = groupBy(calendarDates, "service_id");
|
|
1568
|
+
for (const [serviceId, calendarDateGroup] of Object.entries(
|
|
1569
|
+
calendarDateGroups
|
|
1570
|
+
)) {
|
|
1571
|
+
const calendar = calendars.find(
|
|
1572
|
+
(c) => c.service_id === serviceId
|
|
1573
|
+
);
|
|
1574
|
+
if (calendarDateGroup.some(
|
|
1575
|
+
(calendarDate) => calendarDate.exception_type === 1
|
|
1576
|
+
)) {
|
|
1577
|
+
serviceIds.add(serviceId);
|
|
1578
|
+
}
|
|
1579
|
+
const calendarDateGroupExceptionType2 = calendarDateGroup.filter(
|
|
1580
|
+
(calendarDate) => calendarDate.exception_type === 2
|
|
1581
|
+
);
|
|
1582
|
+
if (timetable.start_date && timetable.end_date && calendar && calendarDateGroupExceptionType2.length > 0) {
|
|
1583
|
+
const datesDuringDateRange = calendarToDateList(
|
|
1584
|
+
calendar,
|
|
1585
|
+
timetable.start_date,
|
|
1586
|
+
timetable.end_date
|
|
1587
|
+
);
|
|
1588
|
+
if (datesDuringDateRange.length === 0) {
|
|
1589
|
+
serviceIds.delete(serviceId);
|
|
1590
|
+
}
|
|
1591
|
+
const everyDateIsExcluded = datesDuringDateRange.every(
|
|
1592
|
+
(dateDuringDateRange) => calendarDateGroupExceptionType2.some(
|
|
1593
|
+
(calendarDate) => calendarDate.date === dateDuringDateRange
|
|
1594
|
+
)
|
|
1595
|
+
);
|
|
1596
|
+
if (everyDateIsExcluded) {
|
|
1597
|
+
serviceIds.delete(serviceId);
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1486
1601
|
}
|
|
1487
1602
|
Object.assign(timetable, {
|
|
1488
1603
|
noServiceSymbolUsed: false,
|
|
@@ -1500,7 +1615,7 @@ var formatTimetables = (timetables, config) => {
|
|
|
1500
1615
|
noPickupSymbol: config.noPickupSymbol,
|
|
1501
1616
|
interpolatedStopSymbol: config.interpolatedStopSymbol,
|
|
1502
1617
|
orientation: timetable.orientation || config.defaultOrientation,
|
|
1503
|
-
service_ids: serviceIds,
|
|
1618
|
+
service_ids: Array.from(serviceIds),
|
|
1504
1619
|
dayList,
|
|
1505
1620
|
dayListLong: formatDaysLong(dayList, config)
|
|
1506
1621
|
});
|
|
@@ -1515,7 +1630,7 @@ var formatTimetables = (timetables, config) => {
|
|
|
1515
1630
|
timetable.trip_ids = uniq(
|
|
1516
1631
|
timetable.orderedTrips.map((trip) => trip.trip_id)
|
|
1517
1632
|
);
|
|
1518
|
-
timetable.orderedTrips = filterTrips(timetable, config);
|
|
1633
|
+
timetable.orderedTrips = filterTrips(timetable, calendars, config);
|
|
1519
1634
|
timetable.stops = formatStops(timetable, config);
|
|
1520
1635
|
return timetable;
|
|
1521
1636
|
});
|
|
@@ -2070,22 +2185,6 @@ function formatDaysLong(dayList, config) {
|
|
|
2070
2185
|
const mapObject = zipObject(config.daysShortStrings, config.daysStrings);
|
|
2071
2186
|
return replaceAll(dayList, mapObject);
|
|
2072
2187
|
}
|
|
2073
|
-
function formatTrip(trip, timetable, calendars, config) {
|
|
2074
|
-
trip.calendar = find2(calendars, {
|
|
2075
|
-
service_id: trip.service_id
|
|
2076
|
-
});
|
|
2077
|
-
trip.dayList = formatDays(trip.calendar, config);
|
|
2078
|
-
trip.dayListLong = formatDaysLong(trip.dayList, config);
|
|
2079
|
-
if (timetable.routes.length === 1) {
|
|
2080
|
-
trip.route_short_name = timetable.routes[0].route_short_name;
|
|
2081
|
-
} else {
|
|
2082
|
-
const route = timetable.routes.find(
|
|
2083
|
-
(route2) => route2.route_id === trip.route_id
|
|
2084
|
-
);
|
|
2085
|
-
trip.route_short_name = route.route_short_name;
|
|
2086
|
-
}
|
|
2087
|
-
return trip;
|
|
2088
|
-
}
|
|
2089
2188
|
function formatFrequency(frequency, config) {
|
|
2090
2189
|
const startTime = fromGTFSTime(frequency.start_time);
|
|
2091
2190
|
const endTime = fromGTFSTime(frequency.end_time);
|