gtfs-to-html 2.7.2 → 2.8.1

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.
Files changed (93) hide show
  1. package/dist/app/index.d.ts +2 -0
  2. package/dist/app/index.js +1846 -0
  3. package/dist/app/index.js.map +1 -0
  4. package/dist/bin/gtfs-to-html.d.ts +1 -0
  5. package/dist/bin/gtfs-to-html.js +2222 -0
  6. package/dist/bin/gtfs-to-html.js.map +1 -0
  7. package/dist/index.d.ts +23 -0
  8. package/dist/index.js +2165 -0
  9. package/dist/index.js.map +1 -0
  10. package/package.json +23 -8
  11. package/.eslintrc.json +0 -28
  12. package/.husky/pre-commit +0 -4
  13. package/CHANGELOG.md +0 -1018
  14. package/app/index.js +0 -138
  15. package/bin/gtfs-to-html.js +0 -48
  16. package/config-sample.json +0 -59
  17. package/docker/Dockerfile +0 -14
  18. package/docker/README.md +0 -5
  19. package/docker/docker-compose.yml +0 -10
  20. package/examples/stop_attributes.txt +0 -6
  21. package/examples/timetable_notes.txt +0 -8
  22. package/examples/timetable_notes_references.txt +0 -8
  23. package/examples/timetable_pages.txt +0 -3
  24. package/examples/timetable_stop_order.txt +0 -16
  25. package/examples/timetables.txt +0 -9
  26. package/index.js +0 -1
  27. package/lib/file-utils.js +0 -202
  28. package/lib/formatters.js +0 -518
  29. package/lib/geojson-utils.js +0 -96
  30. package/lib/gtfs-to-html.js +0 -214
  31. package/lib/log-utils.js +0 -215
  32. package/lib/template-functions.js +0 -192
  33. package/lib/time-utils.js +0 -90
  34. package/lib/utils.js +0 -1702
  35. package/views/default/css/overview_styles.css +0 -197
  36. package/views/default/css/timetable_pdf_styles.css +0 -7
  37. package/views/default/css/timetable_styles.css +0 -447
  38. package/views/default/formatting_functions.pug +0 -113
  39. package/views/default/js/system-map.js +0 -594
  40. package/views/default/js/timetable-map.js +0 -358
  41. package/views/default/js/timetable-menu.js +0 -63
  42. package/views/default/layout.pug +0 -11
  43. package/views/default/overview.pug +0 -27
  44. package/views/default/overview_full.pug +0 -16
  45. package/views/default/timetable_continuation_as.pug +0 -7
  46. package/views/default/timetable_continuation_from.pug +0 -7
  47. package/views/default/timetable_horizontal.pug +0 -42
  48. package/views/default/timetable_hourly.pug +0 -30
  49. package/views/default/timetable_menu.pug +0 -48
  50. package/views/default/timetable_note_symbol.pug +0 -5
  51. package/views/default/timetable_stop_name.pug +0 -13
  52. package/views/default/timetable_stoptime.pug +0 -17
  53. package/views/default/timetable_vertical.pug +0 -67
  54. package/views/default/timetablepage.pug +0 -66
  55. package/views/default/timetablepage_full.pug +0 -22
  56. package/www/README.md +0 -33
  57. package/www/babel.config.js +0 -3
  58. package/www/blog/2020-07-07-New-Documentation.md +0 -12
  59. package/www/blog/2020-08-20-Version-1.0.0.md +0 -29
  60. package/www/blog/2021-11-06-CSV-Export.md +0 -26
  61. package/www/docs/additional-files.md +0 -24
  62. package/www/docs/configuration.md +0 -568
  63. package/www/docs/current-usage.md +0 -48
  64. package/www/docs/custom-templates.md +0 -13
  65. package/www/docs/introduction.md +0 -39
  66. package/www/docs/logging-sql-queries.md +0 -12
  67. package/www/docs/previewing-html-output.md +0 -24
  68. package/www/docs/processing-large-gtfs.md +0 -10
  69. package/www/docs/quick-start.md +0 -136
  70. package/www/docs/related-libraries.md +0 -54
  71. package/www/docs/reviewing-changes.md +0 -29
  72. package/www/docs/stop-attributes.md +0 -30
  73. package/www/docs/support.md +0 -12
  74. package/www/docs/timetable-notes-references.md +0 -44
  75. package/www/docs/timetable-notes.md +0 -33
  76. package/www/docs/timetable-pages.md +0 -37
  77. package/www/docs/timetable-stop-order.md +0 -63
  78. package/www/docs/timetables.md +0 -64
  79. package/www/docusaurus.config.js +0 -104
  80. package/www/package.json +0 -21
  81. package/www/sidebars.js +0 -10
  82. package/www/src/css/custom.css +0 -25
  83. package/www/src/pages/index.js +0 -270
  84. package/www/src/pages/styles.module.css +0 -53
  85. package/www/static/.nojekyll +0 -0
  86. package/www/static/img/favicon.ico +0 -0
  87. package/www/static/img/gtfs-to-html-logo.svg +0 -18
  88. package/www/static/img/overview-example.jpg +0 -0
  89. package/www/static/img/timetable-example.jpg +0 -0
  90. package/www/static/img/undraw_happy_music.svg +0 -1
  91. package/www/static/img/undraw_proud_coder.svg +0 -1
  92. package/www/static/img/undraw_spreadsheets.svg +0 -1
  93. package/www/yarn.lock +0 -8351
package/app/index.js DELETED
@@ -1,138 +0,0 @@
1
- import path from 'node:path';
2
- import { fileURLToPath } from 'node:url';
3
- import { readFileSync } from 'node:fs';
4
- import { map } from 'lodash-es';
5
- import yargs from 'yargs';
6
- import { openDb } from 'gtfs';
7
- import express from 'express';
8
- import logger from 'morgan';
9
- import untildify from 'untildify';
10
-
11
- import { formatTimetableLabel } from '../lib/formatters.js';
12
- import {
13
- setDefaultConfig,
14
- getTimetablePagesForAgency,
15
- getFormattedTimetablePage,
16
- generateOverviewHTML,
17
- generateTimetableHTML,
18
- } from '../lib/utils.js';
19
-
20
- const { argv } = yargs(process.argv).option('c', {
21
- alias: 'configPath',
22
- describe: 'Path to config file',
23
- default: './config.json',
24
- type: 'string',
25
- });
26
-
27
- const app = express();
28
- const router = new express.Router();
29
-
30
- const configPath =
31
- argv.configPath || new URL('../config.json', import.meta.url);
32
- const selectedConfig = JSON.parse(readFileSync(configPath));
33
-
34
- const config = setDefaultConfig(selectedConfig);
35
- // Override noHead config option so full HTML pages are generated
36
- config.noHead = false;
37
- config.assetPath = '/';
38
- config.log = console.log;
39
- config.logWarning = console.warn;
40
- config.logError = console.error;
41
-
42
- try {
43
- openDb(config);
44
- } catch (error) {
45
- if (error instanceof Error && error.code === 'SQLITE_CANTOPEN') {
46
- config.logError(
47
- `Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`,
48
- );
49
- }
50
-
51
- throw error;
52
- }
53
-
54
- /*
55
- * Show all timetable pages
56
- */
57
- router.get('/', async (request, response, next) => {
58
- try {
59
- const timetablePages = [];
60
- const timetablePageIds = map(
61
- getTimetablePagesForAgency(config),
62
- 'timetable_page_id',
63
- );
64
-
65
- for (const timetablePageId of timetablePageIds) {
66
- // eslint-disable-next-line no-await-in-loop
67
- const timetablePage = await getFormattedTimetablePage(
68
- timetablePageId,
69
- config,
70
- );
71
-
72
- if (
73
- !timetablePage.consolidatedTimetables ||
74
- timetablePage.consolidatedTimetables.length === 0
75
- ) {
76
- console.error(
77
- `No timetables found for timetable_page_id=${timetablePage.timetable_page_id}`,
78
- );
79
- }
80
-
81
- timetablePage.relativePath = `/timetables/${timetablePage.timetable_page_id}`;
82
- for (const timetable of timetablePage.consolidatedTimetables) {
83
- timetable.timetable_label = formatTimetableLabel(timetable);
84
- }
85
-
86
- timetablePages.push(timetablePage);
87
- }
88
-
89
- const html = await generateOverviewHTML(timetablePages, config);
90
- response.send(html);
91
- } catch (error) {
92
- console.error(error);
93
- next(error);
94
- }
95
- });
96
-
97
- /*
98
- * Show a specific timetable page
99
- */
100
- router.get('/timetables/:timetablePageId', async (request, response, next) => {
101
- const { timetablePageId } = request.params;
102
-
103
- if (!timetablePageId) {
104
- return next(new Error('No timetablePageId provided'));
105
- }
106
-
107
- try {
108
- const timetablePage = await getFormattedTimetablePage(
109
- timetablePageId,
110
- config,
111
- );
112
-
113
- const html = await generateTimetableHTML(timetablePage, config);
114
- response.send(html);
115
- } catch (error) {
116
- next(error);
117
- }
118
- });
119
-
120
- app.set('views', path.join(fileURLToPath(import.meta.url), '../../views'));
121
- app.set('view engine', 'pug');
122
-
123
- app.use(logger('dev'));
124
-
125
- // Serve static assets
126
- const staticAssetPath =
127
- config.templatePath === undefined
128
- ? path.join(fileURLToPath(import.meta.url), '../../views/default')
129
- : untildify(config.templatePath);
130
-
131
- app.use(express.static(staticAssetPath));
132
-
133
- app.use('/', router);
134
- app.set('port', process.env.PORT || 3000);
135
-
136
- const server = app.listen(app.get('port'), () => {
137
- console.log(`Express server listening on port ${server.address().port}`);
138
- });
@@ -1,48 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import yargs from 'yargs';
4
- import { hideBin } from 'yargs/helpers';
5
- import PrettyError from 'pretty-error';
6
-
7
- import { getConfig } from '../lib/file-utils.js';
8
- import { formatError } from '../lib/log-utils.js';
9
- import gtfsToHtml from '../index.js';
10
-
11
- const pe = new PrettyError();
12
-
13
- const { argv } = yargs(hideBin(process.argv))
14
- .usage('Usage: $0 --configPath ./config.json')
15
- .help()
16
- .option('c', {
17
- alias: 'configPath',
18
- describe: 'Path to config file',
19
- default: './config.json',
20
- type: 'string',
21
- })
22
- .option('s', {
23
- alias: 'skipImport',
24
- describe: 'Don’t import GTFS file.',
25
- type: 'boolean',
26
- })
27
- .default('skipImport', undefined)
28
- .option('t', {
29
- alias: 'showOnlyTimepoint',
30
- describe: 'Show only stops with a `timepoint` value in `stops.txt`',
31
- type: 'boolean',
32
- })
33
- .default('showOnlyTimepoint', undefined);
34
-
35
- const handleError = (error) => {
36
- const text = error || 'Unknown Error';
37
- process.stdout.write(`\n${formatError(text)}\n`);
38
- console.error(pe.render(error));
39
- process.exit(1);
40
- };
41
-
42
- const setupImport = async () => {
43
- const config = await getConfig(argv);
44
- await gtfsToHtml(config);
45
- process.exit();
46
- };
47
-
48
- setupImport().catch(handleError);
@@ -1,59 +0,0 @@
1
- {
2
- "agencies": [
3
- {
4
- "agency_key": "bart",
5
- "url": "http://www.bart.gov/dev/schedules/google_transit.zip"
6
- }
7
- ],
8
- "sqlitePath": "/tmp/gtfs",
9
- "allowEmptyTimetables": false,
10
- "beautify": false,
11
- "coordinatePrecision": 5,
12
- "dateFormat": "MMM D, YYYY",
13
- "daysShortStrings": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14
- "daysStrings": [
15
- "Monday",
16
- "Tuesday",
17
- "Wednesday",
18
- "Thursday",
19
- "Friday",
20
- "Saturday",
21
- "Sunday"
22
- ],
23
- "defaultOrientation": "vertical",
24
- "effectiveDate": "July 8, 2016",
25
- "interpolatedStopSymbol": "•",
26
- "interpolatedStopText": "Estimated time of arrival",
27
- "linkStopUrls": false,
28
- "mapboxAccessToken": "YOUR MAPBOX ACCESS TOKEN",
29
- "menuType": "jump",
30
- "noDropoffSymbol": "‡",
31
- "noDropoffText": "No drop off available",
32
- "noHead": false,
33
- "noPickupSymbol": "**",
34
- "noPickupText": "No pickup available",
35
- "noServiceSymbol": "—",
36
- "noServiceText": "No service at this stop",
37
- "outputFormat": "html",
38
- "requestDropoffSymbol": "†",
39
- "requestDropoffText": "Must request drop off",
40
- "requestPickupSymbol": "***",
41
- "requestPickupText": "Request stop - call for pickup",
42
- "serviceNotProvidedOnText": "Service not provided on",
43
- "serviceProvidedOnText": "Service provided on",
44
- "showArrivalOnDifference": 0.2,
45
- "showCalendarExceptions": true,
46
- "showMap": true,
47
- "showOnlyTimepoint": true,
48
- "showRouteTitle": true,
49
- "showStopCity": false,
50
- "showStopDescription": false,
51
- "showStoptimesForRequestStops": true,
52
- "skipImport": false,
53
- "sortingAlgorithm": "common",
54
- "templatePath": "views/default",
55
- "timeFormat": "h:mma",
56
- "useParentStation": true,
57
- "verbose": true,
58
- "zipOutput": false
59
- }
package/docker/Dockerfile DELETED
@@ -1,14 +0,0 @@
1
- # syntax=docker/dockerfile:1
2
- FROM node:20
3
-
4
- RUN apt update
5
- RUN apt install -y chromium
6
-
7
- RUN cd ~/
8
- COPY config.json ./
9
-
10
- ENV NPM_CONFIG_PREFIX=/home/node/.npm-global
11
- ENV PATH=$PATH:/home/node/.npm-global/bin
12
- RUN npm install -g gtfs-to-html
13
-
14
- CMD [ "gtfs-to-html" ]
package/docker/README.md DELETED
@@ -1,5 +0,0 @@
1
- # Docker area 🐳
2
-
3
- Use the files contained in this folder to run GTFS-to-HTML with `docker` (or `docker-compose`).
4
-
5
- Read more in the documentation.
@@ -1,10 +0,0 @@
1
- version: '3'
2
-
3
- services:
4
- gtfs-to-html:
5
- image: gtfs-to-html
6
- build:
7
- context: .
8
- volumes:
9
- - ./html:/html
10
- - ./config.json:/config.json
@@ -1,6 +0,0 @@
1
- stop_id,stop_city
2
- 1001,"Fresno, CA"
3
- 1002,"Fresno, CA"
4
- 1003,"Hanford, CA"
5
- 1004,"Hanford, CA"
6
- 1005,"Lemoore, CA"
@@ -1,8 +0,0 @@
1
- note_id,symbol,note
2
- 1,,"No service during baseball games"
3
- 2,,"No express service during a full moon"
4
- 3,,"Trip is cancelled if drawbridge is up"
5
- 4,,"This stop is sometimes underwater"
6
- 5,,"Driver will only stop if prearranged by fax"
7
- 6,§,"Vehicle can arrive early if leap second is added during trip and *will not wait*"
8
- 7,,"[See list of holidays](http://transitagency.org/holidays)"
@@ -1,8 +0,0 @@
1
- note_id,timetable_id,route_id,trip_id,stop_id,stop_sequence,show_on_stoptime
2
- 1,131,,,,,
3
- 2,,17,,,,
4
- 3,,,17010,,,1
5
- 4,,,,254514,,
6
- 5,,,,254514,11,
7
- 6,,,17010,235269,,
8
- 7,131,,,,,
@@ -1,3 +0,0 @@
1
- timetable_page_id,timetable_page_label,filename
2
- 1,"Cloverdale, Healdsburg, Windsor, Santa Rosa","60.html"
3
- 2,"Sebastopol, Rohnert Park, Cotati","26.html"
@@ -1,16 +0,0 @@
1
- timetable_id,stop_id,stop_sequence
2
- 1,757717,0
3
- 1,757722,1
4
- 1,757728,2
5
- 1,757668,3
6
- 1,757751,4
7
- 1,757683,5
8
- 1,757689,6
9
- 1,757691,7
10
- 1,757692,8
11
- 1,757700,9
12
- 1,757703,10
13
- 1,757068,11
14
- 1,757074,12
15
- 1,757080,13
16
- 1,757277,14
@@ -1,9 +0,0 @@
1
- timetable_id,route_id,direction_id,start_date,end_date,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_time,end_time,include_exceptions,timetable_label,service_notes,orientation,timetable_page_id,timetable_sequence,direction_name,show_trip_continuation
2
- 0,2034,0,20150101,20151122,1,1,1,1,1,1,0,00:00:00,13:00:00,0,101 Northbound,Mon-Sat AM,horizontal,1,0,Northbound,0
3
- 1,2034,0,20150101,20151122,1,1,1,1,1,1,0,13:00:00,24:00:00,0,101 Northbound,Mon-Sat PM,horizontal,1,1,Northbound,0
4
- 2,2035,1,20150819,20151122,1,1,0,1,1,0,0,,,0,101T Northbound,"Mon,Tue,Thur,Fri",horizontal,1,0,Northbound,0
5
- 3,2035,0,20150819,20151122,0,0,1,0,0,0,0,,,0,101T Southbound,Wednesday,horizontal,1,0,Southbound,0
6
- 4,2036,1,20150101,20151122,0,0,0,0,0,0,1,,,0,102 Eastbound,Sunday,horizontal,1,0,Eastbound,0
7
- 5,2036,0,20150101,20151122,1,1,1,1,1,0,0,,,0,102 Westbound,Mon-Fri,horizontal,1,0,Westbound,0
8
- 6,2036,1,20150101,20151122,0,0,0,0,0,1,0,,,0,102 Eastbound,Saturday,horizontal,1,0,Eastbound,0
9
- 7,2037,0,20150101,20151122,1,1,1,1,1,0,0,,,0,103 Westbound,Mon-Fri,horizontal,1,0,Westbound,0
package/index.js DELETED
@@ -1 +0,0 @@
1
- export { default } from './lib/gtfs-to-html.js';
package/lib/file-utils.js DELETED
@@ -1,202 +0,0 @@
1
- import path from 'node:path';
2
- import { createWriteStream } from 'node:fs';
3
- import { fileURLToPath } from 'node:url';
4
- import { readFile, rm, mkdir } from 'node:fs/promises';
5
-
6
- import copydir from 'copy-dir';
7
- import _ from 'lodash-es';
8
- import archiver from 'archiver';
9
- import beautify from 'js-beautify';
10
- import { renderFile } from 'pug';
11
- import puppeteer from 'puppeteer';
12
- import sanitize from 'sanitize-filename';
13
- import untildify from 'untildify';
14
- import insane from 'insane';
15
- import { marked } from 'marked';
16
-
17
- import {
18
- isNullOrEmpty,
19
- formatDays,
20
- formatRouteColor,
21
- formatRouteTextColor,
22
- } from './formatters.js';
23
- import * as templateFunctions from './template-functions.js';
24
-
25
- /*
26
- * Attempt to parse the specified config JSON file.
27
- */
28
- export async function getConfig(argv) {
29
- let data;
30
- let config;
31
-
32
- try {
33
- data = await readFile(path.resolve(untildify(argv.configPath)), 'utf8');
34
- } catch (error) {
35
- throw new Error(
36
- `Cannot find configuration file at \`${argv.configPath}\`. Use config-sample.json as a starting point, pass --configPath option`,
37
- );
38
- }
39
-
40
- try {
41
- config = JSON.parse(data);
42
- } catch (error) {
43
- throw new Error(
44
- `Cannot parse configuration file at \`${argv.configPath}\`. Check to ensure that it is valid JSON.`,
45
- );
46
- }
47
-
48
- if (argv.skipImport === true) {
49
- config.skipImport = argv.skipImport;
50
- }
51
-
52
- if (argv.showOnlyTimepoint === true) {
53
- config.showOnlyTimepoint = argv.showOnlyTimepoint;
54
- }
55
-
56
- return config;
57
- }
58
-
59
- /*
60
- * Get the full path of the template file for generating timetables based on
61
- * config.
62
- */
63
- function getTemplatePath(templateFileName, config) {
64
- let fullTemplateFileName = templateFileName;
65
- if (config.noHead !== true) {
66
- fullTemplateFileName += '_full';
67
- }
68
-
69
- const templatePath =
70
- config.templatePath === undefined
71
- ? path.join(fileURLToPath(import.meta.url), '../../views/default')
72
- : untildify(config.templatePath);
73
-
74
- return path.join(templatePath, `${fullTemplateFileName}.pug`);
75
- }
76
-
77
- /*
78
- * Prepare the specified directory for saving HTML timetables by deleting everything.
79
- */
80
- export async function prepDirectory(exportPath) {
81
- await rm(exportPath, { recursive: true, force: true });
82
- try {
83
- await mkdir(exportPath, { recursive: true });
84
- } catch (error) {
85
- if (error.code === 'ENOENT') {
86
- throw new Error(
87
- `Unable to write to ${exportPath}. Try running this command from a writable directory.`,
88
- );
89
- }
90
-
91
- throw error;
92
- }
93
- }
94
-
95
- /*
96
- * Copy needed CSS and JS to export path.
97
- */
98
- export function copyStaticAssets(config, exportPath) {
99
- const staticAssetPath =
100
- config.templatePath === undefined
101
- ? path.join(fileURLToPath(import.meta.url), '../../views/default')
102
- : untildify(config.templatePath);
103
-
104
- copydir.sync(path.join(staticAssetPath, 'css'), path.join(exportPath, 'css'));
105
- copydir.sync(path.join(staticAssetPath, 'js'), path.join(exportPath, 'js'));
106
- }
107
-
108
- /*
109
- * Zips the content of the specified folder.
110
- */
111
- export function zipFolder(exportPath) {
112
- const output = createWriteStream(path.join(exportPath, 'timetables.zip'));
113
- const archive = archiver('zip');
114
-
115
- return new Promise((resolve, reject) => {
116
- output.on('close', resolve);
117
- archive.on('error', reject);
118
- archive.pipe(output);
119
- archive.glob('**/*.{txt,css,js,html}', {
120
- cwd: exportPath,
121
- });
122
- archive.finalize();
123
- });
124
- }
125
-
126
- /*
127
- * Generate the filename for a given timetable.
128
- */
129
- export function generateFileName(timetable, config, extension = 'html') {
130
- let filename = timetable.timetable_id;
131
-
132
- for (const route of timetable.routes) {
133
- filename += isNullOrEmpty(route.route_short_name)
134
- ? `_${route.route_long_name.replace(/\s/g, '-')}`
135
- : `_${route.route_short_name.replace(/\s/g, '-')}`;
136
- }
137
-
138
- if (!isNullOrEmpty(timetable.direction_id)) {
139
- filename += `_${timetable.direction_id}`;
140
- }
141
-
142
- filename += `_${formatDays(timetable, config).replace(/\s/g, '')}.${extension}`;
143
-
144
- return sanitize(filename).toLowerCase();
145
- }
146
-
147
- /*
148
- * Generates the folder name for a timetable page based on the date.
149
- */
150
- export function generateFolderName(timetablePage) {
151
- // Use first timetable in timetable page for start date and end date
152
- const timetable = timetablePage.consolidatedTimetables[0];
153
- if (!timetable.start_date || !timetable.end_date) {
154
- return 'timetables';
155
- }
156
-
157
- return sanitize(`${timetable.start_date}-${timetable.end_date}`);
158
- }
159
-
160
- /*
161
- * Render the HTML for a timetable based on the config.
162
- */
163
- export async function renderTemplate(templateFileName, templateVars, config) {
164
- const templatePath = getTemplatePath(templateFileName, config);
165
-
166
- // Make template functions, lodash and marked available inside pug templates.
167
- const html = await renderFile(templatePath, {
168
- _,
169
- md: (text) => insane(marked.parseInline(text)),
170
- ...templateFunctions,
171
- formatRouteColor,
172
- formatRouteTextColor,
173
- ...templateVars,
174
- });
175
-
176
- // Beautify HTML if `beautify` is set in config.
177
- if (config.beautify === true) {
178
- return beautify.html_beautify(html, {
179
- indent_size: 2,
180
- });
181
- }
182
-
183
- return html;
184
- }
185
-
186
- /*
187
- * Render the PDF for a timetable based on the config.
188
- */
189
- export async function renderPdf(htmlPath) {
190
- const pdfPath = htmlPath.replace(/html$/, 'pdf');
191
- const browser = await puppeteer.launch();
192
- const page = await browser.newPage();
193
- await page.emulateMediaType('screen');
194
- await page.goto(`file://${htmlPath}`, {
195
- waitUntil: 'networkidle0',
196
- });
197
- await page.pdf({
198
- path: pdfPath,
199
- });
200
-
201
- await browser.close();
202
- }