gtfs-to-html 2.9.14 → 2.10.0

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 CHANGED
@@ -59,7 +59,8 @@ You can now use `gtfs-to-html` without actually downloading any code or doing an
59
59
 
60
60
  Many transit agencies use `gtfs-to-html` to generate the schedule pages used on their websites, including:
61
61
 
62
- - [Advance Transit](https://advancetransit.com)
62
+ - [Advance Transit (Vermont)](https://advancetransit.com)
63
+ - [Basin Transit (Morongo Basin, California)](https://basin-transit.com/)
63
64
  - [Brockton Area Transit Authority](https://ridebat.com)
64
65
  - [BusWay – CIRA (Aveiro, Portugal)](https://busway-cira.pt)
65
66
  - [Capital Transit (Helena, Montana)](http://www.ridethecapitalt.org)
@@ -70,6 +71,7 @@ Many transit agencies use `gtfs-to-html` to generate the schedule pages used on
70
71
  - [Greater Attleboro-Taunton Regional Transit Authority](https://www.gatra.org)
71
72
  - [Humboldt Transit Authority](http://hta.org)
72
73
  - [Kings Area Rural Transit (KART)](https://www.kartbus.org)
74
+ - [Lowell Regional Transit Authority](https://lrta.com)
73
75
  - [Madera County Connection](http://mcctransit.com)
74
76
  - [Marin Transit](https://marintransit.org)
75
77
  - [Morongo Basin Transit Authority](https://mbtabus.com)
@@ -15,7 +15,6 @@
15
15
  }
16
16
  ],
17
17
  "linkStopUrls": true,
18
- "mapboxAccessToken": "YOUR MAPBOX ACCESS TOKEN",
19
18
  "menuType": "radio",
20
19
  "noHead": false,
21
20
  "outputFormat": "html",
package/dist/app/index.js CHANGED
@@ -13,7 +13,6 @@ import yargs from "yargs";
13
13
  import { hideBin } from "yargs/helpers";
14
14
  import { openDb as openDb2 } from "gtfs";
15
15
  import express from "express";
16
- import logger from "morgan";
17
16
  import untildify2 from "untildify";
18
17
 
19
18
  // src/lib/formatters.ts
@@ -376,7 +375,7 @@ function getAgencyGeoJSON(config2) {
376
375
  }
377
376
 
378
377
  // package.json
379
- var version = "2.9.14";
378
+ var version = "2.10.0";
380
379
 
381
380
  // src/lib/utils.ts
382
381
  var isTimepoint = (stoptime) => {
@@ -430,12 +429,12 @@ var deduplicateTrips = (trips, commonStopId) => {
430
429
  }) : trip.stoptimes[0];
431
430
  const similarTrips = deduplicatedTrips.filter((trip2) => {
432
431
  const stoptime = find(trip2.stoptimes, {
433
- stop_id: selectedStoptime.stop_id
432
+ stop_id: selectedStoptime?.stop_id
434
433
  });
435
434
  if (!stoptime) {
436
435
  return false;
437
436
  }
438
- return stoptime.departure_time === selectedStoptime.departure_time;
437
+ return stoptime.departure_time === selectedStoptime?.departure_time;
439
438
  });
440
439
  const tripIsUnique = every2(similarTrips, (similarTrip) => {
441
440
  const similarTripStoptimes = similarTrip.stoptimes.map(
@@ -467,8 +466,10 @@ var sortTrips = (trips, config2) => {
467
466
  if (trip.stoptimes.length === 0) {
468
467
  continue;
469
468
  }
470
- trip.firstStoptime = timeToSeconds(first(trip.stoptimes).departure_time);
471
- trip.lastStoptime = timeToSeconds(last(trip.stoptimes).departure_time);
469
+ trip.firstStoptime = timeToSeconds(trip.stoptimes[0].departure_time);
470
+ trip.lastStoptime = timeToSeconds(
471
+ trip.stoptimes[trip.stoptimes.length - 1].departure_time
472
+ );
472
473
  }
473
474
  sortedTrips = sortBy(
474
475
  trips,
@@ -480,8 +481,10 @@ var sortTrips = (trips, config2) => {
480
481
  if (trip.stoptimes.length === 0) {
481
482
  continue;
482
483
  }
483
- trip.firstStoptime = timeToSeconds(first(trip.stoptimes).departure_time);
484
- trip.lastStoptime = timeToSeconds(last(trip.stoptimes).departure_time);
484
+ trip.firstStoptime = timeToSeconds(trip.stoptimes[0].departure_time);
485
+ trip.lastStoptime = timeToSeconds(
486
+ trip.stoptimes[trip.stoptimes.length - 1].departure_time
487
+ );
485
488
  }
486
489
  sortedTrips = sortBy(
487
490
  trips,
@@ -547,8 +550,8 @@ var getDaysFromCalendars = (calendars) => {
547
550
  sunday: 0
548
551
  };
549
552
  for (const calendar of calendars) {
550
- for (const [day, value] of Object.entries(days2)) {
551
- days2[day] = value | calendar[day];
553
+ for (const day of Object.keys(days2)) {
554
+ days2[day] = days2[day] | calendar[day];
552
555
  }
553
556
  }
554
557
  return days2;
@@ -823,20 +826,27 @@ var getStopOrder = (timetable, config2) => {
823
826
  stopGraph.push([stopId, sortedStopIds[index + 1]]);
824
827
  }
825
828
  }
826
- const stopIds2 = toposort(stopGraph);
829
+ const stopIds = toposort(stopGraph);
827
830
  return duplicateStopsForDifferentArrivalDeparture(
828
- stopIds2,
831
+ stopIds,
829
832
  timetable,
830
833
  config2
831
834
  );
832
835
  } catch {
836
+ const longestTripStoptimes = getLongestTripStoptimes(
837
+ timetable.orderedTrips,
838
+ config2
839
+ );
840
+ const stopIds = longestTripStoptimes.map((stoptime) => stoptime.stop_id);
841
+ config2.logWarning(
842
+ `Timetable ${timetable.timetable_id} stops are unable to be topologically sorted and has no \`timetable_stop_order.txt\`. Falling back to using the using the stop order from trip with most stoptimes, but this can result in timetables with some stops missing. Try manually specifying stops with \`timetable_stop_order.txt\`.`
843
+ );
844
+ return duplicateStopsForDifferentArrivalDeparture(
845
+ stopIds,
846
+ timetable,
847
+ config2
848
+ );
833
849
  }
834
- const longestTripStoptimes = getLongestTripStoptimes(
835
- timetable.orderedTrips,
836
- config2
837
- );
838
- const stopIds = longestTripStoptimes.map((stoptime) => stoptime.stop_id);
839
- return duplicateStopsForDifferentArrivalDeparture(stopIds, timetable, config2);
840
850
  };
841
851
  var getStopsForTimetable = (timetable, config2) => {
842
852
  if (timetable.orderedTrips.length === 0) {
@@ -1319,6 +1329,7 @@ function setDefaultConfig(initialConfig) {
1319
1329
  interpolatedStopText: "Estimated time of arrival",
1320
1330
  gtfsToHtmlVersion: version,
1321
1331
  linkStopUrls: false,
1332
+ mapStyleUrl: "https://tiles.openfreemap.org/styles/liberty",
1322
1333
  menuType: "jump",
1323
1334
  noDropoffSymbol: "\u2021",
1324
1335
  noDropoffText: "No drop off available",
@@ -1815,7 +1826,6 @@ var argv = yargs(hideBin(process.argv)).option("c", {
1815
1826
  type: "string"
1816
1827
  }).parseSync();
1817
1828
  var app = express();
1818
- var router = express.Router();
1819
1829
  var configPath = argv.configPath || join2(process.cwd(), "config.json");
1820
1830
  var selectedConfig = JSON.parse(readFileSync(configPath, "utf8"));
1821
1831
  var config = setDefaultConfig(selectedConfig);
@@ -1834,7 +1844,36 @@ try {
1834
1844
  }
1835
1845
  throw error;
1836
1846
  }
1837
- router.get("/", async (request, response, next) => {
1847
+ app.set("views", getPathToViewsFolder(config));
1848
+ app.set("view engine", "pug");
1849
+ app.use((req, res, next) => {
1850
+ console.log(`${req.method} ${req.url}`);
1851
+ next();
1852
+ });
1853
+ var staticAssetPath = config.templatePath === void 0 ? getPathToViewsFolder(config) : untildify2(config.templatePath);
1854
+ app.use(express.static(staticAssetPath));
1855
+ app.use(
1856
+ "/js",
1857
+ express.static(
1858
+ join2(dirname2(fileURLToPath2(import.meta.resolve("pbf"))), "dist")
1859
+ )
1860
+ );
1861
+ app.use(
1862
+ "/js",
1863
+ express.static(
1864
+ dirname2(fileURLToPath2(import.meta.resolve("gtfs-realtime-pbf-js-module")))
1865
+ )
1866
+ );
1867
+ app.use(
1868
+ "/js",
1869
+ express.static(
1870
+ join2(
1871
+ dirname2(fileURLToPath2(import.meta.resolve("anchorme"))),
1872
+ "../../dist/browser"
1873
+ )
1874
+ )
1875
+ );
1876
+ app.get("/", async (req, res, next) => {
1838
1877
  try {
1839
1878
  const timetablePages = [];
1840
1879
  const timetablePageIds = map(
@@ -1850,6 +1889,7 @@ router.get("/", async (request, response, next) => {
1850
1889
  console.error(
1851
1890
  `No timetables found for timetable_page_id=${timetablePage.timetable_page_id}`
1852
1891
  );
1892
+ continue;
1853
1893
  }
1854
1894
  timetablePage.relativePath = `/timetables/${timetablePage.timetable_page_id}`;
1855
1895
  for (const timetable of timetablePage.consolidatedTimetables) {
@@ -1858,57 +1898,66 @@ router.get("/", async (request, response, next) => {
1858
1898
  timetablePages.push(timetablePage);
1859
1899
  }
1860
1900
  const html = await generateOverviewHTML(timetablePages, config);
1861
- response.send(html);
1901
+ res.send(html);
1862
1902
  } catch (error) {
1863
- console.error(error);
1864
1903
  next(error);
1865
1904
  }
1866
1905
  });
1867
- router.get("/timetables/:timetablePageId", async (request, response, next) => {
1868
- const { timetablePageId } = request.params;
1906
+ app.get("/timetables/:timetablePageId", async (req, res, next) => {
1907
+ const { timetablePageId } = req.params;
1869
1908
  if (!timetablePageId) {
1870
- return next(new Error("No timetablePageId provided"));
1909
+ res.status(400).send("No timetablePageId provided");
1910
+ return;
1871
1911
  }
1872
1912
  try {
1873
1913
  const timetablePage = await getFormattedTimetablePage(
1874
1914
  timetablePageId,
1875
1915
  config
1876
1916
  );
1917
+ if (!timetablePage || !timetablePage.consolidatedTimetables || timetablePage.consolidatedTimetables.length === 0) {
1918
+ res.status(404).send("Timetable page not found");
1919
+ return;
1920
+ }
1877
1921
  const html = await generateTimetableHTML(timetablePage, config);
1878
- response.send(html);
1922
+ res.send(html);
1879
1923
  } catch (error) {
1924
+ if (error?.message.startsWith("No timetable found")) {
1925
+ res.status(404).send("Timetable page not found");
1926
+ return;
1927
+ }
1880
1928
  next(error);
1881
1929
  }
1882
1930
  });
1883
- app.set("views", getPathToViewsFolder(config));
1884
- app.set("view engine", "pug");
1885
- app.use(logger("dev"));
1886
- var staticAssetPath = config.templatePath === void 0 ? getPathToViewsFolder(config) : untildify2(config.templatePath);
1887
- app.use(express.static(staticAssetPath));
1888
- app.use(
1889
- "/js",
1890
- express.static(
1891
- join2(dirname2(fileURLToPath2(import.meta.resolve("pbf"))), "dist")
1892
- )
1893
- );
1894
- app.use(
1895
- "/js",
1896
- express.static(
1897
- dirname2(fileURLToPath2(import.meta.resolve("gtfs-realtime-pbf-js-module")))
1898
- )
1899
- );
1931
+ app.use((req, res) => {
1932
+ res.status(404).send("Not Found");
1933
+ });
1900
1934
  app.use(
1901
- "/js",
1902
- express.static(
1903
- join2(
1904
- dirname2(fileURLToPath2(import.meta.resolve("anchorme"))),
1905
- "../../dist/browser"
1906
- )
1907
- )
1935
+ (err, req, res, next) => {
1936
+ console.error(err.stack);
1937
+ res.status(500).send("Something broke!");
1938
+ }
1908
1939
  );
1909
- app.use("/", router);
1910
- app.set("port", process.env.PORT || 3e3);
1911
- var server = app.listen(app.get("port"), () => {
1912
- console.log(`Express server listening on port ${app.get("port")}`);
1913
- });
1940
+ var startServer = async (port2) => {
1941
+ try {
1942
+ await new Promise((resolve2, reject) => {
1943
+ const server = app.listen(port2).once("listening", () => {
1944
+ console.log(`Express server listening on port ${port2}`);
1945
+ resolve2();
1946
+ }).once("error", (err) => {
1947
+ if (err.code === "EADDRINUSE") {
1948
+ console.log(`Port ${port2} is in use, trying ${port2 + 1}`);
1949
+ server.close();
1950
+ resolve2(startServer(port2 + 1));
1951
+ } else {
1952
+ reject(err);
1953
+ }
1954
+ });
1955
+ });
1956
+ } catch (err) {
1957
+ console.error("Failed to start server:", err);
1958
+ process.exit(1);
1959
+ }
1960
+ };
1961
+ var port = process.env.PORT ? parseInt(process.env.PORT, 10) : 3e3;
1962
+ startServer(port);
1914
1963
  //# sourceMappingURL=index.js.map