gtfs-to-html
Version:
Build human readable transit timetables as HTML, PDF or CSV from GTFS
121 lines (119 loc) • 4.66 kB
JavaScript
import { A as isGtfsToHtmlError, D as GtfsToHtmlErrorCode, E as GtfsToHtmlErrorCategory, T as GtfsToHtmlError, _ as setDefaultConfig, a as getPathToViewsFolder, c as untildify, d as generateOverviewHTML, g as getTimetablePagesForAgency, h as getFormattedTimetablePage, m as generateTimetableHTML, u as formatTimetableLabel } from "../file-utils-CTeUEN3B.js";
import { dirname, join } from "node:path";
import { openDb } from "gtfs";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import express from "express";
//#region src/app/index.ts
const argv = yargs(hideBin(process.argv)).option("c", {
alias: "configPath",
describe: "Path to config file",
default: "./config.json",
type: "string"
}).parseSync();
const app = express();
const configPath = argv.configPath || join(process.cwd(), "config.json");
const config = setDefaultConfig(JSON.parse(readFileSync(configPath, "utf8")));
config.noHead = false;
config.assetPath = "/";
config.logFunction = console.log;
try {
openDb(config);
} catch (error) {
console.error(`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.`);
throw new GtfsToHtmlError(`Unable to open sqlite database "${config.sqlitePath}"`, {
code: "GTFS_TO_HTML_DATABASE_OPEN_FAILED",
category: "database",
details: {
sqlitePath: config.sqlitePath,
dbCode: error?.code
},
cause: error
});
}
app.set("views", getPathToViewsFolder(config));
app.set("view engine", "pug");
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
const staticAssetPath = config.templatePath === void 0 ? getPathToViewsFolder(config) : untildify(config.templatePath);
app.use(express.static(staticAssetPath));
const browserAssetsPath = join(dirname(fileURLToPath(import.meta.url)), "../browser");
app.use("/js", express.static(browserAssetsPath));
app.use("/css", express.static(browserAssetsPath));
app.get("/", async (req, res, next) => {
try {
const timetablePages = [];
const timetablePageIds = getTimetablePagesForAgency(config).map((timetablePage) => timetablePage.timetable_page_id);
for (const timetablePageId of timetablePageIds) {
if (!timetablePageId) continue;
const timetablePage = await getFormattedTimetablePage(timetablePageId, config);
if (!timetablePage.consolidatedTimetables || timetablePage.consolidatedTimetables.length === 0) {
console.error(`No timetables found for timetable_page_id=${timetablePage.timetable_page_id}`);
continue;
}
timetablePage.relativePath = `/timetables/${timetablePage.timetable_page_id}`;
for (const timetable of timetablePage.consolidatedTimetables) timetable.timetable_label = formatTimetableLabel(timetable);
timetablePages.push(timetablePage);
}
const html = await generateOverviewHTML(timetablePages, config);
res.send(html);
} catch (error) {
next(error);
}
});
app.get("/timetables/:timetablePageId", async (req, res, next) => {
const { timetablePageId } = req.params;
if (!timetablePageId) {
res.status(400).send("No timetablePageId provided");
return;
}
try {
const timetablePage = await getFormattedTimetablePage(timetablePageId, config);
if (!timetablePage || !timetablePage.consolidatedTimetables || timetablePage.consolidatedTimetables.length === 0) {
res.status(404).send("Timetable page not found");
return;
}
const html = await generateTimetableHTML(timetablePage, config);
res.send(html);
} catch (error) {
if (isGtfsToHtmlError(error) && error.code === "GTFS_TO_HTML_QUERY_RESULT_NOT_FOUND") {
res.status(404).send("Timetable page not found");
return;
}
next(error);
}
});
app.use((req, res) => {
res.status(404).send("Not Found");
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send("Something broke!");
});
const startServer = async (port) => {
try {
await new Promise((resolve, reject) => {
const server = app.listen(port).once("listening", () => {
console.log(`Express server listening on port ${port}`);
resolve();
}).once("error", (err) => {
if (err.code === "EADDRINUSE") {
console.log(`Port ${port} is in use, trying ${port + 1}`);
server.close();
resolve(startServer(port + 1));
} else reject(err);
});
});
} catch (err) {
console.error("Failed to start server:", err);
process.exit(1);
}
};
startServer(process.env.PORT ? parseInt(process.env.PORT, 10) : 3e3);
//#endregion
export { };
//# sourceMappingURL=index.js.map