gtfs-to-html 2.9.2 → 2.9.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.
@@ -11,10 +11,17 @@ import { hideBin } from "yargs/helpers";
11
11
  import PrettyError from "pretty-error";
12
12
 
13
13
  // src/lib/file-utils.ts
14
- import path from "node:path";
14
+ import { dirname, join, resolve } from "node:path";
15
15
  import { createWriteStream } from "node:fs";
16
16
  import { fileURLToPath } from "node:url";
17
- import { access, cp, copyFile, mkdir, readFile, rm } from "node:fs/promises";
17
+ import {
18
+ access,
19
+ cp,
20
+ copyFile,
21
+ mkdir,
22
+ readdir,
23
+ readFile
24
+ } from "node:fs/promises";
18
25
  import _ from "lodash-es";
19
26
  import archiver from "archiver";
20
27
  import beautify from "js-beautify";
@@ -323,7 +330,7 @@ function formatTripNameForCSV(trip, timetable) {
323
330
  }
324
331
 
325
332
  // package.json
326
- var version = "2.9.1";
333
+ var version = "2.9.3";
327
334
 
328
335
  // src/lib/utils.ts
329
336
  var isTimepoint = (stoptime) => {
@@ -1302,7 +1309,10 @@ function setDefaultConfig(initialConfig) {
1302
1309
  config.menuType = "none";
1303
1310
  }
1304
1311
  config.hasGtfsRealtime = config.agencies.some(
1305
- (agency) => agency.realtimeTripUpdates?.url || agency.realtimeVehiclePositions?.url
1312
+ (agency) => agency.realtimeTripUpdates?.url || agency.realtimeVehiclePositions?.url || agency.realtimeAlerts?.url
1313
+ );
1314
+ config.hasGtfsRealtimeAlerts = config.agencies.some(
1315
+ (agency) => agency.realtimeAlerts?.url
1306
1316
  );
1307
1317
  return config;
1308
1318
  }
@@ -1789,7 +1799,7 @@ async function getConfig(argv2) {
1789
1799
  let data;
1790
1800
  let config;
1791
1801
  try {
1792
- data = await readFile(path.resolve(untildify(argv2.configPath)), "utf8");
1802
+ data = await readFile(resolve(untildify(argv2.configPath)), "utf8");
1793
1803
  } catch (error) {
1794
1804
  throw new Error(
1795
1805
  `Cannot find configuration file at \`${argv2.configPath}\`. Use config-sample.json as a starting point, pass --configPath option`
@@ -1810,61 +1820,77 @@ async function getConfig(argv2) {
1810
1820
  }
1811
1821
  return config;
1812
1822
  }
1813
- function getTemplatePath(templateFileName, config) {
1814
- let fullTemplateFileName = templateFileName;
1815
- if (config.noHead !== true) {
1816
- fullTemplateFileName += "_full";
1823
+ function getPathToViewsFolder(config) {
1824
+ if (config.templatePath) {
1825
+ return untildify(config.templatePath);
1817
1826
  }
1818
- const templatePath = config.templatePath === void 0 ? path.join(fileURLToPath(import.meta.url), "../../../views/default") : untildify(config.templatePath);
1819
- return path.join(templatePath, `${fullTemplateFileName}.pug`);
1827
+ const __dirname = dirname(fileURLToPath(import.meta.url));
1828
+ let viewsFolderPath;
1829
+ if (__dirname.endsWith("/dist/bin") || __dirname.endsWith("/dist/app")) {
1830
+ viewsFolderPath = resolve(__dirname, "../../views/default");
1831
+ } else if (__dirname.endsWith("/dist")) {
1832
+ viewsFolderPath = resolve(__dirname, "../views/default");
1833
+ } else {
1834
+ viewsFolderPath = resolve(__dirname, "views/default");
1835
+ }
1836
+ return viewsFolderPath;
1837
+ }
1838
+ function getPathToTemplateFile(templateFileName, config) {
1839
+ const fullTemplateFileName = config.noHead !== true ? `${templateFileName}_full.pug` : `${templateFileName}.pug`;
1840
+ return join(getPathToViewsFolder(config), fullTemplateFileName);
1820
1841
  }
1821
- async function prepDirectory(exportPath) {
1822
- await rm(exportPath, { recursive: true, force: true });
1842
+ async function prepDirectory(outputPath) {
1823
1843
  try {
1824
- await mkdir(exportPath, { recursive: true });
1844
+ await access(outputPath);
1825
1845
  } catch (error) {
1826
- if (error.code === "ENOENT") {
1827
- throw new Error(
1828
- `Unable to write to ${exportPath}. Try running this command from a writable directory.`
1829
- );
1846
+ try {
1847
+ await mkdir(outputPath, { recursive: true });
1848
+ } catch (error2) {
1849
+ if (error2?.code === "ENOENT") {
1850
+ throw new Error(
1851
+ `Unable to write to ${outputPath}. Try running this command from a writable directory.`
1852
+ );
1853
+ }
1854
+ throw error2;
1830
1855
  }
1831
- throw error;
1856
+ }
1857
+ const files = await readdir(outputPath);
1858
+ if (files.length > 0) {
1859
+ throw new Error(
1860
+ `Output directory ${outputPath} is not empty. Please specify an empty directory.`
1861
+ );
1832
1862
  }
1833
1863
  }
1834
- async function copyStaticAssets(config, exportPath) {
1835
- const staticAssetPath = config.templatePath === void 0 ? path.join(fileURLToPath(import.meta.url), "../../../views/default") : untildify(config.templatePath);
1864
+ async function copyStaticAssets(config, outputPath) {
1865
+ const viewsFolderPath = getPathToViewsFolder(config);
1836
1866
  const foldersToCopy = ["css", "js", "img"];
1837
1867
  for (const folder of foldersToCopy) {
1838
- if (await access(path.join(staticAssetPath, folder)).then(() => true).catch(() => false)) {
1839
- await cp(
1840
- path.join(staticAssetPath, folder),
1841
- path.join(exportPath, folder),
1842
- {
1843
- recursive: true
1844
- }
1845
- );
1868
+ if (await access(join(viewsFolderPath, folder)).then(() => true).catch(() => false)) {
1869
+ await cp(join(viewsFolderPath, folder), join(outputPath, folder), {
1870
+ recursive: true
1871
+ });
1846
1872
  }
1847
1873
  }
1848
1874
  if (config.hasGtfsRealtime) {
1849
1875
  await copyFile(
1850
1876
  "node_modules/pbf/dist/pbf.js",
1851
- path.join(exportPath, "js/pbf.js")
1877
+ join(outputPath, "js/pbf.js")
1852
1878
  );
1853
1879
  await copyFile(
1854
1880
  "node_modules/gtfs-realtime-pbf-js-module/gtfs-realtime.browser.proto.js",
1855
- path.join(exportPath, "js/gtfs-realtime.browser.proto.js")
1881
+ join(outputPath, "js/gtfs-realtime.browser.proto.js")
1856
1882
  );
1857
1883
  }
1858
1884
  }
1859
- function zipFolder(exportPath) {
1860
- const output = createWriteStream(path.join(exportPath, "timetables.zip"));
1885
+ function zipFolder(outputPath) {
1886
+ const output = createWriteStream(join(outputPath, "timetables.zip"));
1861
1887
  const archive = archiver("zip");
1862
- return new Promise((resolve, reject) => {
1863
- output.on("close", resolve);
1888
+ return new Promise((resolve2, reject) => {
1889
+ output.on("close", resolve2);
1864
1890
  archive.on("error", reject);
1865
1891
  archive.pipe(output);
1866
1892
  archive.glob("**/*.{txt,css,js,html}", {
1867
- cwd: exportPath
1893
+ cwd: outputPath
1868
1894
  });
1869
1895
  archive.finalize();
1870
1896
  });
@@ -1888,7 +1914,7 @@ function generateFolderName(timetablePage) {
1888
1914
  return sanitize(`${timetable.start_date}-${timetable.end_date}`);
1889
1915
  }
1890
1916
  async function renderTemplate(templateFileName, templateVars, config) {
1891
- const templatePath = getTemplatePath(templateFileName, config);
1917
+ const templatePath = getPathToTemplateFile(templateFileName, config);
1892
1918
  const html = await renderFile(templatePath, {
1893
1919
  _,
1894
1920
  md: (text) => insane(marked.parseInline(text)),
@@ -2072,12 +2098,13 @@ function progressBar(formatString, barTotal, config) {
2072
2098
  }
2073
2099
 
2074
2100
  // src/lib/gtfs-to-html.ts
2075
- import path2 from "node:path";
2101
+ import path from "node:path";
2076
2102
  import { mkdir as mkdir2, writeFile } from "node:fs/promises";
2077
2103
  import { map } from "lodash-es";
2078
2104
  import { openDb as openDb2, importGtfs } from "gtfs";
2079
2105
  import sanitize2 from "sanitize-filename";
2080
2106
  import Timer from "timer-machine";
2107
+ import untildify2 from "untildify";
2081
2108
  var gtfsToHtml = async (initialConfig) => {
2082
2109
  const config = setDefaultConfig(initialConfig);
2083
2110
  const timer = new Timer();
@@ -2104,8 +2131,8 @@ var gtfsToHtml = async (initialConfig) => {
2104
2131
  const agencyKey = config.agencies.map(
2105
2132
  (agency) => agency.agencyKey ?? agency.agency_key ?? "unknown"
2106
2133
  ).join("-");
2107
- const exportPath = path2.join(process.cwd(), "html", sanitize2(agencyKey));
2108
- const outputStats = {
2134
+ const outputPath = config.outputPath ? untildify2(config.outputPath) : path.join(process.cwd(), "html", sanitize2(agencyKey));
2135
+ const stats = {
2109
2136
  timetables: 0,
2110
2137
  timetablePages: 0,
2111
2138
  calendars: 0,
@@ -2119,9 +2146,9 @@ var gtfsToHtml = async (initialConfig) => {
2119
2146
  getTimetablePagesForAgency(config),
2120
2147
  "timetable_page_id"
2121
2148
  );
2122
- await prepDirectory(exportPath);
2149
+ await prepDirectory(outputPath);
2123
2150
  if (config.noHead !== true && ["html", "pdf"].includes(config.outputFormat)) {
2124
- await copyStaticAssets(config, exportPath);
2151
+ await copyStaticAssets(config, outputPath);
2125
2152
  }
2126
2153
  const bar = progressBar(
2127
2154
  `${agencyKey}: Generating ${config.outputFormat.toUpperCase()} timetables {bar} {value}/{total}`,
@@ -2136,7 +2163,7 @@ var gtfsToHtml = async (initialConfig) => {
2136
2163
  );
2137
2164
  for (const timetable of timetablePage.timetables) {
2138
2165
  for (const warning of timetable.warnings) {
2139
- outputStats.warnings.push(warning);
2166
+ stats.warnings.push(warning);
2140
2167
  bar?.interrupt(warning);
2141
2168
  }
2142
2169
  }
@@ -2145,20 +2172,20 @@ var gtfsToHtml = async (initialConfig) => {
2145
2172
  `No timetables found for timetable_page_id=${timetablePage.timetable_page_id}`
2146
2173
  );
2147
2174
  }
2148
- outputStats.timetables += timetablePage.consolidatedTimetables.length;
2149
- outputStats.timetablePages += 1;
2175
+ stats.timetables += timetablePage.consolidatedTimetables.length;
2176
+ stats.timetablePages += 1;
2150
2177
  const datePath = generateFolderName(timetablePage);
2151
- await mkdir2(path2.join(exportPath, datePath), { recursive: true });
2178
+ await mkdir2(path.join(outputPath, datePath), { recursive: true });
2152
2179
  config.assetPath = "../";
2153
- timetablePage.relativePath = path2.join(
2180
+ timetablePage.relativePath = path.join(
2154
2181
  datePath,
2155
2182
  sanitize2(timetablePage.filename)
2156
2183
  );
2157
2184
  if (config.outputFormat === "csv") {
2158
2185
  for (const timetable of timetablePage.consolidatedTimetables) {
2159
2186
  const csv = await generateTimetableCSV(timetable);
2160
- const csvPath = path2.join(
2161
- exportPath,
2187
+ const csvPath = path.join(
2188
+ outputPath,
2162
2189
  datePath,
2163
2190
  generateFileName(timetable, config, "csv")
2164
2191
  );
@@ -2166,8 +2193,8 @@ var gtfsToHtml = async (initialConfig) => {
2166
2193
  }
2167
2194
  } else {
2168
2195
  const html = await generateTimetableHTML(timetablePage, config);
2169
- const htmlPath = path2.join(
2170
- exportPath,
2196
+ const htmlPath = path.join(
2197
+ outputPath,
2171
2198
  datePath,
2172
2199
  sanitize2(timetablePage.filename)
2173
2200
  );
@@ -2178,12 +2205,12 @@ var gtfsToHtml = async (initialConfig) => {
2178
2205
  }
2179
2206
  timetablePages.push(timetablePage);
2180
2207
  const timetableStats = generateStats(timetablePage);
2181
- outputStats.stops += timetableStats.stops;
2182
- outputStats.routes += timetableStats.routes;
2183
- outputStats.trips += timetableStats.trips;
2184
- outputStats.calendars += timetableStats.calendars;
2208
+ stats.stops += timetableStats.stops;
2209
+ stats.routes += timetableStats.routes;
2210
+ stats.trips += timetableStats.trips;
2211
+ stats.calendars += timetableStats.calendars;
2185
2212
  } catch (error) {
2186
- outputStats.warnings.push(error?.message);
2213
+ stats.warnings.push(error?.message);
2187
2214
  bar?.interrupt(error.message);
2188
2215
  }
2189
2216
  bar?.increment();
@@ -2191,26 +2218,27 @@ var gtfsToHtml = async (initialConfig) => {
2191
2218
  if (config.outputFormat === "html") {
2192
2219
  config.assetPath = "";
2193
2220
  const html = await generateOverviewHTML(timetablePages, config);
2194
- await writeFile(path2.join(exportPath, "index.html"), html);
2221
+ await writeFile(path.join(outputPath, "index.html"), html);
2195
2222
  }
2196
- const logText = generateLogText(outputStats, config);
2197
- await writeFile(path2.join(exportPath, "log.txt"), logText);
2223
+ const logText = generateLogText(stats, config);
2224
+ await writeFile(path.join(outputPath, "log.txt"), logText);
2198
2225
  if (config.zipOutput) {
2199
- await zipFolder(exportPath);
2226
+ await zipFolder(outputPath);
2200
2227
  }
2201
- const fullExportPath = path2.join(
2202
- exportPath,
2228
+ const fullOutputPath = path.join(
2229
+ outputPath,
2203
2230
  config.zipOutput ? "/timetables.zip" : ""
2204
2231
  );
2205
2232
  config.log(
2206
- `${agencyKey}: ${config.outputFormat.toUpperCase()} timetables created at ${fullExportPath}`
2233
+ `${agencyKey}: ${config.outputFormat.toUpperCase()} timetables created at ${fullOutputPath}`
2207
2234
  );
2208
- logStats(outputStats, config);
2235
+ logStats(stats, config);
2209
2236
  const seconds = Math.round(timer.time() / 1e3);
2210
2237
  config.log(
2211
2238
  `${agencyKey}: ${config.outputFormat.toUpperCase()} timetable generation required ${seconds} seconds`
2212
2239
  );
2213
2240
  timer.stop();
2241
+ return fullOutputPath;
2214
2242
  };
2215
2243
  var gtfs_to_html_default = gtfsToHtml;
2216
2244