gtfs-to-html 2.7.2 → 2.8.0
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/package.json +21 -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/lib/gtfs-to-html.js
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
-
|
|
4
|
-
import { map } from 'lodash-es';
|
|
5
|
-
import { openDb, importGtfs } from 'gtfs';
|
|
6
|
-
import sanitize from 'sanitize-filename';
|
|
7
|
-
import Timer from 'timer-machine';
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
prepDirectory,
|
|
11
|
-
copyStaticAssets,
|
|
12
|
-
generateFolderName,
|
|
13
|
-
renderPdf,
|
|
14
|
-
zipFolder,
|
|
15
|
-
generateFileName,
|
|
16
|
-
} from './file-utils.js';
|
|
17
|
-
import {
|
|
18
|
-
log,
|
|
19
|
-
logWarning,
|
|
20
|
-
logError,
|
|
21
|
-
progressBar,
|
|
22
|
-
generateLogText,
|
|
23
|
-
logStats,
|
|
24
|
-
} from './log-utils.js';
|
|
25
|
-
import {
|
|
26
|
-
setDefaultConfig,
|
|
27
|
-
getTimetablePagesForAgency,
|
|
28
|
-
getFormattedTimetablePage,
|
|
29
|
-
generateTimetableHTML,
|
|
30
|
-
generateTimetableCSV,
|
|
31
|
-
generateOverviewHTML,
|
|
32
|
-
generateStats,
|
|
33
|
-
} from './utils.js';
|
|
34
|
-
|
|
35
|
-
/*
|
|
36
|
-
* Generate HTML timetables from GTFS.
|
|
37
|
-
*/
|
|
38
|
-
/* eslint-disable complexity */
|
|
39
|
-
const gtfsToHtml = async (initialConfig) => {
|
|
40
|
-
const config = setDefaultConfig(initialConfig);
|
|
41
|
-
const timer = new Timer();
|
|
42
|
-
|
|
43
|
-
config.log = log(config);
|
|
44
|
-
config.logWarning = logWarning(config);
|
|
45
|
-
config.logError = logError(config);
|
|
46
|
-
|
|
47
|
-
timer.start();
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
openDb(config);
|
|
51
|
-
} catch (error) {
|
|
52
|
-
if (error instanceof Error && error.code === 'SQLITE_CANTOPEN') {
|
|
53
|
-
config.logError(
|
|
54
|
-
`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`,
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
throw error;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (!config.agencies || config.agencies.length === 0) {
|
|
62
|
-
throw new Error('No agencies defined in `config.json`');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (!config.skipImport) {
|
|
66
|
-
// Import GTFS
|
|
67
|
-
await importGtfs(config);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const agencyKey = config.agencies
|
|
71
|
-
.map((agency) => agency.agency_key ?? 'unknown')
|
|
72
|
-
.join('-');
|
|
73
|
-
const exportPath = path.join(process.cwd(), 'html', sanitize(agencyKey));
|
|
74
|
-
const outputStats = {
|
|
75
|
-
timetables: 0,
|
|
76
|
-
timetablePages: 0,
|
|
77
|
-
calendars: 0,
|
|
78
|
-
trips: 0,
|
|
79
|
-
routes: 0,
|
|
80
|
-
stops: 0,
|
|
81
|
-
warnings: [],
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const timetablePages = [];
|
|
85
|
-
const timetablePageIds = map(
|
|
86
|
-
getTimetablePagesForAgency(config),
|
|
87
|
-
'timetable_page_id',
|
|
88
|
-
);
|
|
89
|
-
await prepDirectory(exportPath);
|
|
90
|
-
|
|
91
|
-
if (config.noHead !== true && ['html', 'pdf'].includes(config.outputFormat)) {
|
|
92
|
-
copyStaticAssets(config, exportPath);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const bar = progressBar(
|
|
96
|
-
`${agencyKey}: Generating ${config.outputFormat.toUpperCase()} timetables {bar} {value}/{total}`,
|
|
97
|
-
timetablePageIds.length,
|
|
98
|
-
config,
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
/* eslint-disable no-await-in-loop */
|
|
102
|
-
for (const timetablePageId of timetablePageIds) {
|
|
103
|
-
try {
|
|
104
|
-
const timetablePage = await getFormattedTimetablePage(
|
|
105
|
-
timetablePageId,
|
|
106
|
-
config,
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
for (const timetable of timetablePage.timetables) {
|
|
110
|
-
for (const warning of timetable.warnings) {
|
|
111
|
-
outputStats.warnings.push(warning);
|
|
112
|
-
bar.interrupt(warning);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (timetablePage.consolidatedTimetables.length === 0) {
|
|
117
|
-
throw new Error(
|
|
118
|
-
`No timetables found for timetable_page_id=${timetablePage.timetable_page_id}`,
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
outputStats.timetables += timetablePage.consolidatedTimetables.length;
|
|
123
|
-
outputStats.timetablePages += 1;
|
|
124
|
-
|
|
125
|
-
const datePath = generateFolderName(timetablePage);
|
|
126
|
-
|
|
127
|
-
// Make directory if it doesn't exist
|
|
128
|
-
await mkdir(path.join(exportPath, datePath), { recursive: true });
|
|
129
|
-
config.assetPath = '../';
|
|
130
|
-
|
|
131
|
-
timetablePage.relativePath = path.join(
|
|
132
|
-
datePath,
|
|
133
|
-
sanitize(timetablePage.filename),
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
if (config.outputFormat === 'csv') {
|
|
137
|
-
for (const timetable of timetablePage.consolidatedTimetables) {
|
|
138
|
-
const csv = await generateTimetableCSV(timetable);
|
|
139
|
-
const csvPath = path.join(
|
|
140
|
-
exportPath,
|
|
141
|
-
datePath,
|
|
142
|
-
generateFileName(timetable, config, 'csv'),
|
|
143
|
-
);
|
|
144
|
-
await writeFile(csvPath, csv);
|
|
145
|
-
}
|
|
146
|
-
} else {
|
|
147
|
-
const html = await generateTimetableHTML(timetablePage, config);
|
|
148
|
-
const htmlPath = path.join(
|
|
149
|
-
exportPath,
|
|
150
|
-
datePath,
|
|
151
|
-
sanitize(timetablePage.filename),
|
|
152
|
-
);
|
|
153
|
-
await writeFile(htmlPath, html);
|
|
154
|
-
|
|
155
|
-
if (config.outputFormat === 'pdf') {
|
|
156
|
-
await renderPdf(htmlPath);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
timetablePages.push(timetablePage);
|
|
161
|
-
const timetableStats = generateStats(timetablePage);
|
|
162
|
-
|
|
163
|
-
for (const key of Object.keys(outputStats)) {
|
|
164
|
-
if (timetableStats[key]) {
|
|
165
|
-
outputStats[key] += timetableStats[key];
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
} catch (error) {
|
|
169
|
-
outputStats.warnings.push(error.message);
|
|
170
|
-
bar.interrupt(error.message);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
bar.increment();
|
|
174
|
-
}
|
|
175
|
-
/* eslint-enable no-await-in-loop */
|
|
176
|
-
|
|
177
|
-
if (config.outputFormat === 'html') {
|
|
178
|
-
// Generate route summary index.html
|
|
179
|
-
config.assetPath = '';
|
|
180
|
-
const html = await generateOverviewHTML(timetablePages, config);
|
|
181
|
-
await writeFile(path.join(exportPath, 'index.html'), html);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Generate output log.txt
|
|
185
|
-
const logText = generateLogText(outputStats, config);
|
|
186
|
-
await writeFile(path.join(exportPath, 'log.txt'), logText);
|
|
187
|
-
|
|
188
|
-
// Zip output, if specified
|
|
189
|
-
if (config.zipOutput) {
|
|
190
|
-
await zipFolder(exportPath);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const fullExportPath = path.join(
|
|
194
|
-
exportPath,
|
|
195
|
-
config.zipOutput ? '/timetables.zip' : '',
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
// Print stats
|
|
199
|
-
config.log(
|
|
200
|
-
`${agencyKey}: ${config.outputFormat.toUpperCase()} timetables created at ${fullExportPath}`,
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
logStats(outputStats, config);
|
|
204
|
-
|
|
205
|
-
const seconds = Math.round(timer.time() / 1000);
|
|
206
|
-
config.log(
|
|
207
|
-
`${agencyKey}: ${config.outputFormat.toUpperCase()} timetable generation required ${seconds} seconds`,
|
|
208
|
-
);
|
|
209
|
-
|
|
210
|
-
timer.stop();
|
|
211
|
-
};
|
|
212
|
-
/* eslint-enable complexity */
|
|
213
|
-
|
|
214
|
-
export default gtfsToHtml;
|
package/lib/log-utils.js
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import { clearLine, cursorTo } from 'node:readline';
|
|
2
|
-
import { noop } from 'lodash-es';
|
|
3
|
-
import * as colors from 'yoctocolors';
|
|
4
|
-
import { getFeedInfo } from 'gtfs';
|
|
5
|
-
import Table from 'cli-table';
|
|
6
|
-
|
|
7
|
-
/*
|
|
8
|
-
* Creates text for a log of output details.
|
|
9
|
-
*/
|
|
10
|
-
export function generateLogText(outputStats, config) {
|
|
11
|
-
const feedInfo = getFeedInfo();
|
|
12
|
-
const feedVersion =
|
|
13
|
-
feedInfo.length > 0 && feedInfo[0].feed_version
|
|
14
|
-
? feedInfo[0].feed_version
|
|
15
|
-
: 'Unknown';
|
|
16
|
-
|
|
17
|
-
const logText = [
|
|
18
|
-
`Feed Version: ${feedVersion}`,
|
|
19
|
-
`GTFS-to-HTML Version: ${config.gtfsToHtmlVersion}`,
|
|
20
|
-
`Date Generated: ${new Date().toISOString()}`,
|
|
21
|
-
`Timetable Page Count: ${outputStats.timetablePages}`,
|
|
22
|
-
`Timetable Count: ${outputStats.timetables}`,
|
|
23
|
-
`Calendar Service ID Count: ${outputStats.calendars}`,
|
|
24
|
-
`Route Count: ${outputStats.routes}`,
|
|
25
|
-
`Trip Count: ${outputStats.trips}`,
|
|
26
|
-
`Stop Count: ${outputStats.stops}`,
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
for (const agency of config.agencies) {
|
|
30
|
-
if (agency.url) {
|
|
31
|
-
logText.push(`Source: ${agency.url}`);
|
|
32
|
-
} else if (agency.path) {
|
|
33
|
-
logText.push(`Source: ${agency.path}`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (outputStats.warnings.length > 0) {
|
|
38
|
-
logText.push('', 'Warnings:', ...outputStats.warnings);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return logText.join('\n');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/*
|
|
45
|
-
* Returns a log function based on config settings
|
|
46
|
-
*/
|
|
47
|
-
export function log(config) {
|
|
48
|
-
if (config.verbose === false) {
|
|
49
|
-
return noop;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (config.logFunction) {
|
|
53
|
-
return config.logFunction;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return (text, overwrite) => {
|
|
57
|
-
if (overwrite === true && process.stdout.isTTY) {
|
|
58
|
-
clearLine(process.stdout, 0);
|
|
59
|
-
cursorTo(process.stdout, 0);
|
|
60
|
-
} else {
|
|
61
|
-
process.stdout.write('\n');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
process.stdout.write(text);
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/*
|
|
69
|
-
* Returns an warning log function based on config settings
|
|
70
|
-
*/
|
|
71
|
-
export function logWarning(config) {
|
|
72
|
-
if (config.logFunction) {
|
|
73
|
-
return config.logFunction;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return (text) => {
|
|
77
|
-
process.stdout.write(`\n${formatWarning(text)}\n`);
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/*
|
|
82
|
-
* Returns an error log function based on config settings
|
|
83
|
-
*/
|
|
84
|
-
export function logError(config) {
|
|
85
|
-
if (config.logFunction) {
|
|
86
|
-
return config.logFunction;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return (text) => {
|
|
90
|
-
process.stdout.write(`\n${formatError(text)}\n`);
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/*
|
|
95
|
-
* Format console warning text
|
|
96
|
-
*/
|
|
97
|
-
export function formatWarning(text) {
|
|
98
|
-
const warningMessage = `${colors.underline('Warning')}: ${text}`;
|
|
99
|
-
return colors.yellow(warningMessage);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/*
|
|
103
|
-
* Format console error text
|
|
104
|
-
*/
|
|
105
|
-
export function formatError(error) {
|
|
106
|
-
const messageText = error instanceof Error ? error.message : error;
|
|
107
|
-
const errorMessage = `${colors.underline('Error')}: ${messageText.replace(
|
|
108
|
-
'Error: ',
|
|
109
|
-
'',
|
|
110
|
-
)}`;
|
|
111
|
-
return colors.red(errorMessage);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/*
|
|
115
|
-
* Print a table of stats to the console.
|
|
116
|
-
*/
|
|
117
|
-
export function logStats(stats, config) {
|
|
118
|
-
// Hide stats table from custom log functions
|
|
119
|
-
if (config.logFunction) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const table = new Table({
|
|
124
|
-
colWidths: [40, 20],
|
|
125
|
-
head: ['Item', 'Count'],
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
table.push(
|
|
129
|
-
['📄 Timetable Pages', stats.timetablePages],
|
|
130
|
-
['🕑 Timetables', stats.timetables],
|
|
131
|
-
['📅 Calendar Service IDs', stats.calendars],
|
|
132
|
-
['🔄 Routes', stats.routes],
|
|
133
|
-
['🚍 Trips', stats.trips],
|
|
134
|
-
['🛑 Stops', stats.stops],
|
|
135
|
-
['⛔️ Warnings', stats.warnings.length],
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
config.log(table.toString());
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/*
|
|
142
|
-
* Create progress bar text string
|
|
143
|
-
*/
|
|
144
|
-
const generateProgressBarString = (barTotal, barProgress, size = 40) => {
|
|
145
|
-
const line = '-';
|
|
146
|
-
const slider = '=';
|
|
147
|
-
if (!barTotal) {
|
|
148
|
-
throw new Error('Total value is either not provided or invalid');
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (!barProgress && barProgress !== 0) {
|
|
152
|
-
throw new Error('Current value is either not provided or invalid');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (isNaN(barTotal)) {
|
|
156
|
-
throw new Error('Total value is not an integer');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (isNaN(barProgress)) {
|
|
160
|
-
throw new Error('Current value is not an integer');
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (isNaN(size)) {
|
|
164
|
-
throw new Error('Size is not an integer');
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (barProgress > barTotal) {
|
|
168
|
-
return slider.repeat(size + 2);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const percentage = barProgress / barTotal;
|
|
172
|
-
const progress = Math.round(size * percentage);
|
|
173
|
-
const emptyProgress = size - progress;
|
|
174
|
-
const progressText = slider.repeat(progress);
|
|
175
|
-
const emptyProgressText = line.repeat(emptyProgress);
|
|
176
|
-
return progressText + emptyProgressText;
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
/*
|
|
180
|
-
* Print a progress bar to the console.
|
|
181
|
-
*/
|
|
182
|
-
export function progressBar(formatString, barTotal, config) {
|
|
183
|
-
let barProgress = 0;
|
|
184
|
-
|
|
185
|
-
if (config.verbose === false) {
|
|
186
|
-
return {
|
|
187
|
-
increment: noop,
|
|
188
|
-
interrupt: noop,
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (barTotal === 0) {
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const renderProgressString = () =>
|
|
197
|
-
formatString
|
|
198
|
-
.replace('{value}', barProgress)
|
|
199
|
-
.replace('{total}', barTotal)
|
|
200
|
-
.replace('{bar}', generateProgressBarString(barTotal, barProgress));
|
|
201
|
-
|
|
202
|
-
config.log(renderProgressString(), true);
|
|
203
|
-
|
|
204
|
-
return {
|
|
205
|
-
interrupt(text) {
|
|
206
|
-
// Log two lines to avoid overwrite by progress bar
|
|
207
|
-
config.logWarning(text);
|
|
208
|
-
config.log('');
|
|
209
|
-
},
|
|
210
|
-
increment() {
|
|
211
|
-
barProgress += 1;
|
|
212
|
-
config.log(renderProgressString(), true);
|
|
213
|
-
},
|
|
214
|
-
};
|
|
215
|
-
}
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import { every } from 'lodash-es';
|
|
2
|
-
|
|
3
|
-
/*
|
|
4
|
-
* Format an id to be used as an HTML attribute.
|
|
5
|
-
*/
|
|
6
|
-
export function formatHtmlId(id) {
|
|
7
|
-
return id.replace(/([^\w[\]{}.:-])\s?/g, '');
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/*
|
|
11
|
-
* Discern if a day list should be shown for a specific timetable (if some
|
|
12
|
-
* trips happen on different days).
|
|
13
|
-
*/
|
|
14
|
-
export function timetableHasDifferentDays(timetable) {
|
|
15
|
-
return !every(timetable.orderedTrips, (trip, idx) => {
|
|
16
|
-
if (idx === 0) {
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return trip.dayList === timetable.orderedTrips[idx - 1].dayList;
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/*
|
|
25
|
-
* Discern if a day list should be shown for a specific timetable page's menu (if some
|
|
26
|
-
* timetables are for different days).
|
|
27
|
-
*/
|
|
28
|
-
export function timetablePageHasDifferentDays(timetablePage) {
|
|
29
|
-
return !every(timetablePage.consolidatedTimetables, (timetable, idx) => {
|
|
30
|
-
if (idx === 0) {
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
timetable.dayListLong ===
|
|
36
|
-
timetablePage.consolidatedTimetables[idx - 1].dayListLong
|
|
37
|
-
);
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/*
|
|
42
|
-
* Discern if individual timetable labels should be shown (if some
|
|
43
|
-
* timetables have different labels).
|
|
44
|
-
*/
|
|
45
|
-
export function timetablePageHasDifferentLabels(timetablePage) {
|
|
46
|
-
return !every(timetablePage.consolidatedTimetables, (timetable, idx) => {
|
|
47
|
-
if (idx === 0) {
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
timetable.timetable_label ===
|
|
53
|
-
timetablePage.consolidatedTimetables[idx - 1].timetable_label
|
|
54
|
-
);
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/*
|
|
59
|
-
* Discern if a timetable has any notes or notices to display.
|
|
60
|
-
*/
|
|
61
|
-
export function hasNotesOrNotices(timetable) {
|
|
62
|
-
return (
|
|
63
|
-
timetable.requestPickupSymbolUsed ||
|
|
64
|
-
timetable.noPickupSymbolUsed ||
|
|
65
|
-
timetable.requestDropoffSymbolUsed ||
|
|
66
|
-
timetable.noDropoffSymbolUsed ||
|
|
67
|
-
timetable.noServiceSymbolUsed ||
|
|
68
|
-
timetable.interpolatedStopSymbolUsed ||
|
|
69
|
-
timetable.notes.length > 0
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/*
|
|
74
|
-
* Return an array of all timetable notes that relate to the entire timetable or route.
|
|
75
|
-
*/
|
|
76
|
-
export function getNotesForTimetableLabel(notes) {
|
|
77
|
-
return notes.filter((note) => !note.stop_id && !note.trip_id);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/*
|
|
81
|
-
* Return an array of all timetable notes for a specific stop and stop_sequence.
|
|
82
|
-
*/
|
|
83
|
-
export function getNotesForStop(notes, stop) {
|
|
84
|
-
return notes.filter((note) => {
|
|
85
|
-
// Don't show if note applies only to a specific trip.
|
|
86
|
-
if (note.trip_id) {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Don't show if note applies only to a specific stop_sequence that is not found.
|
|
91
|
-
if (
|
|
92
|
-
note.stop_sequence &&
|
|
93
|
-
!stop.trips.some((trip) => trip.stop_sequence === note.stop_sequence)
|
|
94
|
-
) {
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return note.stop_id === stop.stop_id;
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/*
|
|
103
|
-
* Return an array of all timetable notes for a specific trip.
|
|
104
|
-
*/
|
|
105
|
-
export function getNotesForTrip(notes, trip) {
|
|
106
|
-
return notes.filter((note) => {
|
|
107
|
-
// Don't show if note applies only to a specific stop.
|
|
108
|
-
if (note.stop_id) {
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return note.trip_id === trip.trip_id;
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/*
|
|
117
|
-
* Return an array of all timetable notes for a specific stoptime.
|
|
118
|
-
*/
|
|
119
|
-
export function getNotesForStoptime(notes, stoptime) {
|
|
120
|
-
return notes.filter((note) => {
|
|
121
|
-
// Show notes that apply to all trips at this stop if `show_on_stoptime` is true.
|
|
122
|
-
if (
|
|
123
|
-
!note.trip_id &&
|
|
124
|
-
note.stop_id === stoptime.stop_id &&
|
|
125
|
-
note.show_on_stoptime === 1
|
|
126
|
-
) {
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Show notes that apply to all stops of this trip if `show_on_stoptime` is true.
|
|
131
|
-
if (
|
|
132
|
-
!note.stop_id &&
|
|
133
|
-
note.trip_id === stoptime.trip_id &&
|
|
134
|
-
note.show_on_stoptime === 1
|
|
135
|
-
) {
|
|
136
|
-
return true;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return (
|
|
140
|
-
note.trip_id === stoptime.trip_id && note.stop_id === stoptime.stop_id
|
|
141
|
-
);
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/*
|
|
146
|
-
* Formats a trip name.
|
|
147
|
-
*/
|
|
148
|
-
export function formatTripName(trip, index, timetable) {
|
|
149
|
-
let tripName;
|
|
150
|
-
if (timetable.routes.length > 1) {
|
|
151
|
-
tripName = trip.route_short_name;
|
|
152
|
-
} else if (timetable.orientation === 'horizontal') {
|
|
153
|
-
// Only add this to horizontal timetables.
|
|
154
|
-
if (trip.trip_short_name) {
|
|
155
|
-
tripName = trip.trip_short_name;
|
|
156
|
-
} else {
|
|
157
|
-
tripName = `Run #${index + 1}`;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (timetableHasDifferentDays(timetable)) {
|
|
162
|
-
tripName += ` ${trip.dayList}`;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return tripName;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/*
|
|
169
|
-
* Formats a trip name.
|
|
170
|
-
*/
|
|
171
|
-
export function formatTripNameForCSV(trip, timetable) {
|
|
172
|
-
let tripName = '';
|
|
173
|
-
if (timetable.routes.length > 1) {
|
|
174
|
-
tripName += `${trip.route_short_name} - `;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (trip.trip_short_name) {
|
|
178
|
-
tripName += trip.trip_short_name;
|
|
179
|
-
} else {
|
|
180
|
-
tripName += trip.trip_id;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (trip.trip_headsign) {
|
|
184
|
-
tripName += ` - ${trip.trip_headsign}`;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (timetableHasDifferentDays(timetable)) {
|
|
188
|
-
tripName += ` - ${trip.dayList}`;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return tripName;
|
|
192
|
-
}
|
package/lib/time-utils.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import moment from 'moment';
|
|
2
|
-
|
|
3
|
-
/*
|
|
4
|
-
* Convert a GTFS formatted time string into a moment less than 24 hours.
|
|
5
|
-
*/
|
|
6
|
-
export function fromGTFSTime(timeString) {
|
|
7
|
-
const duration = moment.duration(timeString);
|
|
8
|
-
|
|
9
|
-
return moment({
|
|
10
|
-
hour: duration.hours(),
|
|
11
|
-
minute: duration.minutes(),
|
|
12
|
-
second: duration.seconds(),
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/*
|
|
17
|
-
* Convert a moment into a GTFS formatted time string.
|
|
18
|
-
*/
|
|
19
|
-
export function toGTFSTime(time) {
|
|
20
|
-
return time.format('HH:mm:ss');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/*
|
|
24
|
-
* Convert a GTFS formatted date string into a moment.
|
|
25
|
-
*/
|
|
26
|
-
export function fromGTFSDate(gtfsDate) {
|
|
27
|
-
return moment(gtfsDate, 'YYYYMMDD');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/*
|
|
31
|
-
* Convert a moment date into a GTFS formatted date string.
|
|
32
|
-
*/
|
|
33
|
-
export function toGTFSDate(date) {
|
|
34
|
-
return moment(date).format('YYYYMMDD');
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/*
|
|
38
|
-
* Convert a object of weekdays into a a string containing 1s and 0s.
|
|
39
|
-
*/
|
|
40
|
-
export function calendarToCalendarCode(c) {
|
|
41
|
-
if (c.service_id) {
|
|
42
|
-
return c.service_id;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return `${c.monday}${c.tuesday}${c.wednesday}${c.thursday}${c.friday}${c.saturday}${c.sunday}`;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/*
|
|
49
|
-
* Convert a string of 1s and 0s representing a weekday to an object.
|
|
50
|
-
*/
|
|
51
|
-
export function calendarCodeToCalendar(code) {
|
|
52
|
-
const days = [
|
|
53
|
-
'monday',
|
|
54
|
-
'tuesday',
|
|
55
|
-
'wednesday',
|
|
56
|
-
'thursday',
|
|
57
|
-
'friday',
|
|
58
|
-
'saturday',
|
|
59
|
-
'sunday',
|
|
60
|
-
];
|
|
61
|
-
const calendar = {};
|
|
62
|
-
|
|
63
|
-
for (const [index, day] of days.entries()) {
|
|
64
|
-
calendar[day] = code[index];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return calendar;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/*
|
|
71
|
-
* Get number of seconds after midnight of a GTFS formatted time string.
|
|
72
|
-
*/
|
|
73
|
-
export function secondsAfterMidnight(timeString) {
|
|
74
|
-
return moment.duration(timeString).asSeconds();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/*
|
|
78
|
-
* Get number of minutes after midnight of a GTFS formatted time string.
|
|
79
|
-
*/
|
|
80
|
-
export function minutesAfterMidnight(timeString) {
|
|
81
|
-
return moment.duration(timeString).asMinutes();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/*
|
|
85
|
-
* Add specified number of seconds to a GTFS formatted time string.
|
|
86
|
-
*/
|
|
87
|
-
export function updateTimeByOffset(timeString, offsetSeconds) {
|
|
88
|
-
const newTime = fromGTFSTime(timeString);
|
|
89
|
-
return toGTFSTime(newTime.add(offsetSeconds, 'seconds'));
|
|
90
|
-
}
|