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.
- package/dist/app/index.d.ts +2 -0
- package/dist/app/index.js +1846 -0
- package/dist/app/index.js.map +1 -0
- package/dist/bin/gtfs-to-html.d.ts +1 -0
- package/dist/bin/gtfs-to-html.js +2222 -0
- package/dist/bin/gtfs-to-html.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +2165 -0
- package/dist/index.js.map +1 -0
- package/package.json +23 -8
- package/.eslintrc.json +0 -28
- package/.husky/pre-commit +0 -4
- package/CHANGELOG.md +0 -1018
- package/app/index.js +0 -138
- package/bin/gtfs-to-html.js +0 -48
- package/config-sample.json +0 -59
- package/docker/Dockerfile +0 -14
- package/docker/README.md +0 -5
- package/docker/docker-compose.yml +0 -10
- package/examples/stop_attributes.txt +0 -6
- package/examples/timetable_notes.txt +0 -8
- package/examples/timetable_notes_references.txt +0 -8
- package/examples/timetable_pages.txt +0 -3
- package/examples/timetable_stop_order.txt +0 -16
- package/examples/timetables.txt +0 -9
- package/index.js +0 -1
- package/lib/file-utils.js +0 -202
- package/lib/formatters.js +0 -518
- package/lib/geojson-utils.js +0 -96
- package/lib/gtfs-to-html.js +0 -214
- package/lib/log-utils.js +0 -215
- package/lib/template-functions.js +0 -192
- package/lib/time-utils.js +0 -90
- package/lib/utils.js +0 -1702
- package/views/default/css/overview_styles.css +0 -197
- package/views/default/css/timetable_pdf_styles.css +0 -7
- package/views/default/css/timetable_styles.css +0 -447
- package/views/default/formatting_functions.pug +0 -113
- package/views/default/js/system-map.js +0 -594
- package/views/default/js/timetable-map.js +0 -358
- package/views/default/js/timetable-menu.js +0 -63
- package/views/default/layout.pug +0 -11
- package/views/default/overview.pug +0 -27
- package/views/default/overview_full.pug +0 -16
- package/views/default/timetable_continuation_as.pug +0 -7
- package/views/default/timetable_continuation_from.pug +0 -7
- package/views/default/timetable_horizontal.pug +0 -42
- package/views/default/timetable_hourly.pug +0 -30
- package/views/default/timetable_menu.pug +0 -48
- package/views/default/timetable_note_symbol.pug +0 -5
- package/views/default/timetable_stop_name.pug +0 -13
- package/views/default/timetable_stoptime.pug +0 -17
- package/views/default/timetable_vertical.pug +0 -67
- package/views/default/timetablepage.pug +0 -66
- package/views/default/timetablepage_full.pug +0 -22
- package/www/README.md +0 -33
- package/www/babel.config.js +0 -3
- package/www/blog/2020-07-07-New-Documentation.md +0 -12
- package/www/blog/2020-08-20-Version-1.0.0.md +0 -29
- package/www/blog/2021-11-06-CSV-Export.md +0 -26
- package/www/docs/additional-files.md +0 -24
- package/www/docs/configuration.md +0 -568
- package/www/docs/current-usage.md +0 -48
- package/www/docs/custom-templates.md +0 -13
- package/www/docs/introduction.md +0 -39
- package/www/docs/logging-sql-queries.md +0 -12
- package/www/docs/previewing-html-output.md +0 -24
- package/www/docs/processing-large-gtfs.md +0 -10
- package/www/docs/quick-start.md +0 -136
- package/www/docs/related-libraries.md +0 -54
- package/www/docs/reviewing-changes.md +0 -29
- package/www/docs/stop-attributes.md +0 -30
- package/www/docs/support.md +0 -12
- package/www/docs/timetable-notes-references.md +0 -44
- package/www/docs/timetable-notes.md +0 -33
- package/www/docs/timetable-pages.md +0 -37
- package/www/docs/timetable-stop-order.md +0 -63
- package/www/docs/timetables.md +0 -64
- package/www/docusaurus.config.js +0 -104
- package/www/package.json +0 -21
- package/www/sidebars.js +0 -10
- package/www/src/css/custom.css +0 -25
- package/www/src/pages/index.js +0 -270
- package/www/src/pages/styles.module.css +0 -53
- package/www/static/.nojekyll +0 -0
- package/www/static/img/favicon.ico +0 -0
- package/www/static/img/gtfs-to-html-logo.svg +0 -18
- package/www/static/img/overview-example.jpg +0 -0
- package/www/static/img/timetable-example.jpg +0 -0
- package/www/static/img/undraw_happy_music.svg +0 -1
- package/www/static/img/undraw_proud_coder.svg +0 -1
- package/www/static/img/undraw_spreadsheets.svg +0 -1
- 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
|
-
});
|
package/bin/gtfs-to-html.js
DELETED
|
@@ -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);
|
package/config-sample.json
DELETED
|
@@ -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,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)"
|
package/examples/timetables.txt
DELETED
|
@@ -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
|
-
}
|