gtfs-to-html
Version:
Build human readable transit timetables as HTML, PDF or CSV from GTFS
139 lines (137 loc) • 6.92 kB
JavaScript
import { C as logStats, D as GtfsToHtmlErrorCode, E as GtfsToHtmlErrorCategory, S as logError, T as GtfsToHtmlError, _ as setDefaultConfig, b as generateLogText, c as untildify, d as generateOverviewHTML, f as generateStats, g as getTimetablePagesForAgency, h as getFormattedTimetablePage, j as toGtfsToHtmlError, l as zipFolder, m as generateTimetableHTML, n as generateCSVFileName, o as prepDirectory, p as generateTimetableCSV, r as generateFolderName, s as renderPdf, t as copyStaticAssets, w as progressBar, x as log } from "./file-utils-CTeUEN3B.js";
import path from "node:path";
import { mkdir, writeFile } from "node:fs/promises";
import { GtfsError, GtfsErrorCategory as GtfsErrorCategory$1, GtfsErrorCode, GtfsWarningCode, closeDb, deleteDb, formatGtfsError as formatGtfsError$1, importGtfs, isGtfsError, isGtfsError as isGtfsError$1, isGtfsValidationError, openDb } from "gtfs";
import sanitize from "sanitize-filename";
//#region src/lib/gtfs-to-html.ts
const gtfsToHtml = async (initialConfig) => {
const config = setDefaultConfig(initialConfig);
const startTime = process.hrtime.bigint();
const agencyKey = config.agencies.map((agency) => agency.agencyKey ?? agency.agency_key ?? "unknown").join("-");
const outputPath = config.outputPath ? untildify(config.outputPath) : path.join(process.cwd(), "html", sanitize(agencyKey));
await prepDirectory(outputPath, config);
let db;
try {
db = openDb(config);
} catch (error) {
if (error?.code === "SQLITE_CANTOPEN") {
const dbOpenError = new GtfsToHtmlError(`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`, {
code: "GTFS_TO_HTML_DATABASE_OPEN_FAILED",
category: "database",
details: {
sqlitePath: config.sqlitePath,
dbCode: error.code
},
cause: error
});
logError(config)(dbOpenError.message);
throw dbOpenError;
}
throw toGtfsToHtmlError(error, {
message: error instanceof Error ? error.message : "Unable to open sqlite database",
code: "GTFS_TO_HTML_DATABASE_OPEN_FAILED",
category: "database",
details: { sqlitePath: config.sqlitePath }
});
}
try {
if (!config.agencies || config.agencies.length === 0) throw new GtfsToHtmlError("No agencies defined in `config.json`", {
code: "GTFS_TO_HTML_CONFIG_MISSING_AGENCIES",
category: "config",
details: { field: "agencies" }
});
if (!config.skipImport) try {
await importGtfs(config);
} catch (error) {
if (isGtfsError(error)) throw error;
throw toGtfsToHtmlError(error, {
message: error instanceof Error ? error.message : "GTFS import failed",
code: "GTFS_TO_HTML_GTFS_IMPORT_FAILED",
category: "gtfs"
});
}
const stats = {
timetables: 0,
timetablePages: 0,
calendars: 0,
routes: 0,
trips: 0,
stops: 0,
warnings: []
};
const timetablePageSummaries = [];
const timetablePageIds = getTimetablePagesForAgency(config).map((timetablePage) => timetablePage.timetable_page_id);
if (config.noHead !== true && ["html", "pdf"].includes(config.outputFormat)) await copyStaticAssets(config, outputPath);
const bar = progressBar(`${agencyKey}: Generating ${config.outputFormat.toUpperCase()} timetables {bar} {value}/{total}`, timetablePageIds.length, config);
for (const timetablePageId of timetablePageIds) {
try {
const timetablePage = await getFormattedTimetablePage(timetablePageId, config);
for (const timetable of timetablePage.consolidatedTimetables) if (timetable.warnings) for (const warning of timetable.warnings) {
stats.warnings.push(warning);
bar?.interrupt(warning);
}
if (timetablePage.consolidatedTimetables.length === 0) throw new GtfsToHtmlError(`No timetables found for timetable_page_id=${timetablePage.timetable_page_id}`, {
code: "GTFS_TO_HTML_TIMETABLE_GENERATION_FAILED",
category: "query",
details: { timetablePageId: timetablePage.timetable_page_id }
});
stats.timetables += timetablePage.consolidatedTimetables.length;
stats.timetablePages += 1;
const datePath = generateFolderName(timetablePage);
await mkdir(path.join(outputPath, datePath), { recursive: true });
config.assetPath = "../";
timetablePage.relativePath = path.join(datePath, sanitize(timetablePage.filename));
if (config.outputFormat === "csv") for (const timetable of timetablePage.consolidatedTimetables) {
const csv = await generateTimetableCSV(timetable);
await writeFile(path.join(outputPath, datePath, generateCSVFileName(timetable, config)), csv);
}
else {
const html = await generateTimetableHTML(timetablePage, config);
const htmlPath = path.join(outputPath, datePath, sanitize(timetablePage.filename));
await writeFile(htmlPath, html);
if (config.outputFormat === "pdf") await renderPdf(htmlPath);
}
timetablePageSummaries.push({
timetable_page_id: timetablePage.timetable_page_id,
relativePath: timetablePage.relativePath,
filename: timetablePage.filename,
timetable_page_label: timetablePage.timetable_page_label,
dayList: timetablePage.dayList,
route_ids: timetablePage.route_ids,
agency_ids: timetablePage.agency_ids,
consolidatedTimetables: timetablePage.consolidatedTimetables.map((timetable) => ({ routes: timetable.routes }))
});
const timetableStats = generateStats(timetablePage);
stats.stops += timetableStats.stops;
stats.routes += timetableStats.routes;
stats.trips += timetableStats.trips;
stats.calendars += timetableStats.calendars;
} catch (error) {
stats.warnings.push(error?.message);
bar?.interrupt(error.message);
}
bar?.increment();
}
if (config.outputFormat === "html") {
config.assetPath = "";
const html = await generateOverviewHTML(timetablePageSummaries, config);
await writeFile(path.join(outputPath, "index.html"), html);
}
const logText = generateLogText(stats, config);
await writeFile(path.join(outputPath, "log.txt"), logText);
if (config.zipOutput) await zipFolder(outputPath);
const fullOutputPath = path.join(outputPath, config.zipOutput ? "/timetables.zip" : "");
log(config)(`${agencyKey}: ${config.outputFormat.toUpperCase()} timetables created at ${fullOutputPath}`);
logStats(config)(stats);
const endTime = process.hrtime.bigint();
const elapsedSeconds = Number(endTime - startTime) / 1e9;
log(config)(`${agencyKey}: ${config.outputFormat.toUpperCase()} timetable generation required ${elapsedSeconds.toFixed(1)} seconds`);
return fullOutputPath;
} finally {
if (config.deleteDbAfter) deleteDb(db);
else closeDb(db);
}
};
//#endregion
export { formatGtfsError$1 as a, gtfsToHtml as c, GtfsWarningCode as i, GtfsErrorCategory$1 as n, isGtfsError$1 as o, GtfsErrorCode as r, isGtfsValidationError as s, GtfsError as t };
//# sourceMappingURL=src-CWzWo4Az.js.map