UNPKG

gtfs-to-html

Version:

Build human readable transit timetables as HTML, PDF or CSV from GTFS

139 lines (137 loc) 6.92 kB
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