gtfs-to-html 2.6.0 → 2.6.2

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/CHANGELOG.md CHANGED
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.6.2] - 2024-04-19
9
+
10
+ ### Updated
11
+ - Dependency updates
12
+ - Update to timetable page sorting
13
+
14
+ ### Added
15
+
16
+ - Markdown support in timetable notes
17
+
18
+ ## [2.6.1] - 2024-03-26
19
+
20
+ ### Fixed
21
+
22
+ - Fix for missing stops
23
+
24
+ ### Updated
25
+ - Dependency updates
26
+ - Day List selector label wording
27
+ - Updates to timetable map
28
+ - Filename format for CSV export files
29
+
8
30
  ## [2.6.0] - 2024-02-27
9
31
 
10
32
  ### Updated
@@ -4,4 +4,5 @@ note_id,symbol,note
4
4
  3,,"Trip is cancelled if drawbridge is up"
5
5
  4,,"This stop is sometimes underwater"
6
6
  5,,"Driver will only stop if prearranged by fax"
7
- 6,§,"Vehicle can arrive early if leap second is added during trip"
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)"
@@ -5,3 +5,4 @@ note_id,timetable_id,route_id,trip_id,stop_id,stop_sequence,show_on_stoptime
5
5
  4,,,,254514,,
6
6
  5,,,,254514,11,
7
7
  6,,,17010,235269,,
8
+ 7,131,,,,,
package/lib/file-utils.js CHANGED
@@ -11,6 +11,8 @@ import { renderFile } from 'pug';
11
11
  import puppeteer from 'puppeteer';
12
12
  import sanitize from 'sanitize-filename';
13
13
  import untildify from 'untildify';
14
+ import insane from 'insane';
15
+ import { marked } from 'marked';
14
16
 
15
17
  import {
16
18
  isNullOrEmpty,
@@ -132,7 +134,7 @@ export function zipFolder(exportPath) {
132
134
  /*
133
135
  * Generate the filename for a given timetable.
134
136
  */
135
- export function generateFileName(timetable, config) {
137
+ export function generateFileName(timetable, config, extension = 'html') {
136
138
  let filename = timetable.timetable_id;
137
139
 
138
140
  for (const route of timetable.routes) {
@@ -145,24 +147,11 @@ export function generateFileName(timetable, config) {
145
147
  filename += `_${timetable.direction_id}`;
146
148
  }
147
149
 
148
- filename += `_${formatDays(timetable, config).replace(/\s/g, '')}.html`;
150
+ filename += `_${formatDays(timetable, config).replace(/\s/g, '')}.${extension}`;
149
151
 
150
152
  return sanitize(filename).toLowerCase();
151
153
  }
152
154
 
153
- /*
154
- * Generate the filename for a CSV timetable.
155
- */
156
- export function generateCSVFileName(timetable, timetablePage) {
157
- let filename = timetablePage.filename.replace(/.html$/, '');
158
-
159
- if (timetablePage.timetables.length > 1) {
160
- filename += `_${timetable.direction_id}`;
161
- }
162
-
163
- return sanitize(`${filename}.csv`);
164
- }
165
-
166
155
  /*
167
156
  * Generates the folder name for a timetable page based on the date.
168
157
  */
@@ -182,9 +171,10 @@ export function generateFolderName(timetablePage) {
182
171
  export async function renderTemplate(templateFileName, templateVars, config) {
183
172
  const templatePath = getTemplatePath(templateFileName, config);
184
173
 
185
- // Make template functions and lodash available inside pug templates.
174
+ // Make template functions, lodash and marked available inside pug templates.
186
175
  const html = await renderFile(templatePath, {
187
176
  _,
177
+ md: (text) => insane(marked.parseInline(text)),
188
178
  ...templateFunctions,
189
179
  formatRouteColor,
190
180
  formatRouteTextColor,
@@ -12,7 +12,7 @@ import {
12
12
  generateFolderName,
13
13
  renderPdf,
14
14
  zipFolder,
15
- generateCSVFileName,
15
+ generateFileName,
16
16
  } from './file-utils.js';
17
17
  import {
18
18
  log,
@@ -139,7 +139,7 @@ const gtfsToHtml = async (initialConfig) => {
139
139
  const csvPath = path.join(
140
140
  exportPath,
141
141
  datePath,
142
- generateCSVFileName(timetable, timetablePage),
142
+ generateFileName(timetable, config, 'csv'),
143
143
  );
144
144
  await writeFile(csvPath, csv);
145
145
  }
package/lib/utils.js CHANGED
@@ -472,7 +472,7 @@ const convertTimetableToTimetablePage = (timetable, config) => {
472
472
  });
473
473
  }
474
474
 
475
- const filename = generateFileName(timetable, config);
475
+ const filename = generateFileName(timetable, config, 'html');
476
476
 
477
477
  return {
478
478
  timetable_page_id: timetable.timetable_id,
@@ -855,6 +855,10 @@ const getAllStationStopIds = (stopId) => {
855
855
  stop_id: stopId,
856
856
  });
857
857
 
858
+ if (stops.length === 0) {
859
+ throw new Error(`No stop found for stop_id=${stopId}`);
860
+ }
861
+
858
862
  const stop = stops[0];
859
863
 
860
864
  if (isNullOrEmpty(stop.parent_station)) {
@@ -1153,11 +1157,11 @@ const getTripsForTimetable = (timetable, calendars, config) => {
1153
1157
 
1154
1158
  for (const trip of formattedTrips) {
1155
1159
  for (const stoptime of trip.stoptimes) {
1156
- const parentStationStop = stops.find(
1157
- (stop) => stop.stop_id === stoptime.stop_id,
1158
- );
1159
- stoptime.stop_id =
1160
- parentStationStop.parent_station || parentStationStop.stop_id;
1160
+ const stop = stops.find((stop) => stop.stop_id === stoptime.stop_id);
1161
+
1162
+ if (stop?.parent_station) {
1163
+ stoptime.stop_id = stop.parent_station;
1164
+ }
1161
1165
  }
1162
1166
  }
1163
1167
  }
@@ -1608,17 +1612,24 @@ export function generateOverviewHTML(timetablePages, config) {
1608
1612
  // Sort timetables for display, first numerically then alphabetically.
1609
1613
  const sortedTimetablePages = sortBy(timetablePages, [
1610
1614
  (timetablePage) => {
1615
+ // First sort numerically by route_short_name, removing leading non-digits
1611
1616
  if (
1612
1617
  timetablePage.consolidatedTimetables.length > 0 &&
1613
1618
  timetablePage.consolidatedTimetables[0].routes.length > 0
1614
1619
  ) {
1615
- return Number.parseInt(
1616
- timetablePage.consolidatedTimetables[0].routes[0].route_short_name,
1617
- 10,
1620
+ return (
1621
+ Number.parseInt(
1622
+ timetablePage.consolidatedTimetables[0].routes[0].route_short_name?.replace(
1623
+ /^\D+/g,
1624
+ '',
1625
+ ),
1626
+ 10,
1627
+ ) || 0
1618
1628
  );
1619
1629
  }
1620
1630
  },
1621
1631
  (timetablePage) => {
1632
+ // Then sort by route_short_name alphabetically
1622
1633
  if (
1623
1634
  timetablePage.consolidatedTimetables.length > 0 &&
1624
1635
  timetablePage.consolidatedTimetables[0].routes.length > 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtfs-to-html",
3
- "version": "2.6.0",
3
+ "version": "2.6.2",
4
4
  "private": false,
5
5
  "description": "Build human readable transit timetables as HTML, PDF or CSV from GTFS",
6
6
  "keywords": [
@@ -37,26 +37,28 @@
37
37
  "dependencies": {
38
38
  "@turf/helpers": "^6.5.0",
39
39
  "@turf/simplify": "^6.5.0",
40
- "archiver": "^6.0.2",
40
+ "archiver": "^7.0.1",
41
41
  "cli-table": "^0.3.11",
42
42
  "copy-dir": "^1.3.0",
43
43
  "csv-stringify": "^6.4.6",
44
- "express": "^4.18.2",
45
- "gtfs": "^4.7.1",
44
+ "express": "^4.19.2",
45
+ "gtfs": "^4.10.2",
46
+ "insane": "^2.6.2",
46
47
  "js-beautify": "^1.15.1",
47
48
  "lodash-es": "^4.17.21",
49
+ "marked": "^12.0.2",
48
50
  "moment": "^2.30.1",
49
51
  "morgan": "^1.10.0",
50
52
  "pretty-error": "^4.0.0",
51
53
  "pug": "^3.0.2",
52
- "puppeteer": "^22.3.0",
54
+ "puppeteer": "^22.6.5",
53
55
  "sanitize-filename": "^1.6.3",
54
56
  "sqlstring": "^2.3.3",
55
57
  "timer-machine": "^1.1.0",
56
58
  "toposort": "^2.0.2",
57
59
  "untildify": "^5.0.0",
58
60
  "yargs": "^17.7.2",
59
- "yoctocolors": "^1.0.0"
61
+ "yoctocolors": "^2.0.0"
60
62
  },
61
63
  "devDependencies": {
62
64
  "husky": "^9.0.11",
@@ -28,6 +28,11 @@ function formatRoute(route) {
28
28
  .text(route.route_long_name || ''),
29
29
  ])
30
30
  .appendTo(html);
31
+ } else {
32
+ $('<div>')
33
+ .addClass('hover:underline')
34
+ .text(route.route_long_name || '')
35
+ .appendTo(html);
31
36
  }
32
37
 
33
38
  return html.prop('outerHTML');
@@ -48,7 +53,7 @@ function formatStopPopup(feature, routes) {
48
53
  $('<strong>').text(feature.properties.stop_code).appendTo(html);
49
54
  }
50
55
 
51
- $('<div>').addClass('text-sm').text('Routes Served:').appendTo(html);
56
+ $('<div>').addClass('text-sm mb-2').text('Routes Served:').appendTo(html);
52
57
 
53
58
  $(html).append(routeIds.map((routeId) => formatRoute(routes[routeId])));
54
59
 
@@ -42,7 +42,7 @@ if timetablePage.consolidatedTimetables.length > 1
42
42
  span= directionName
43
43
  div(hidden=timetablePage.dayLists.length <= 1)
44
44
  #day_list_selector
45
- h3.font-bold Days of Week
45
+ h3.font-bold Day of Week
46
46
  each dayList, idx in timetablePage.dayLists
47
47
  label.cursor-pointer.mb-2.w-full.flex.items-center.justify-center.px-8.py-3.border.border-transparent.text-base.rounded-md(class=idx === 0 ? 'text-white bg-blue-600': 'text-gray-600 bg-gray-300')
48
48
  input.hidden(type="radio" name="dayList" autocomplete="off" value=dayList checked=(idx === 0))
@@ -54,7 +54,10 @@ include formatting_functions.pug
54
54
  if timetable.interpolatedStopSymbolUsed
55
55
  .note(id=`note-${timetable.timetable_id}-interpolated-stop`)= `${config.interpolatedStopSymbol} = ${config.interpolatedStopText}`
56
56
  each note in _.uniqBy(timetable.notes, 'note_id')
57
- .note(id=`note-${timetable.timetable_id}-${note.note_id}`)= `${note.symbol} = ${note.note}`
57
+ .note(id=`note-${timetable.timetable_id}-${note.note_id}`)
58
+ span= note.symbol
59
+ span &nbsp;=&nbsp;
60
+ span!= md(note.note)
58
61
 
59
62
  if config.showCalendarExceptions && timetable.calendarDates.includedDates.length
60
63
  .included-dates= `${config.serviceProvidedOnText}: ${timetable.calendarDates.includedDates.join(', ')}`
@@ -13,7 +13,7 @@ By default, GTFS-to-HTML attempts to generate a timetable for each route and dir
13
13
  * [timetable_pages.txt](/docs/timetable-pages) - Specifies which HTML timetables should be grouped together into a single HTML page.
14
14
 
15
15
  ## Adding notes to timetables
16
- Notes about a specific trip, stop, stoptime, route or timetable can be added to timetables by using `timetable_notes.txt` and `timetable_notes_references.txt` in your GTFS.
16
+ Notes about a specific trip, stop, stoptime, route or timetable can be added to timetables by using `timetable_notes.txt` and `timetable_notes_references.txt` in your GTFS. These notes can include links and other formatting using Markdown syntax.
17
17
 
18
18
  * [timetable_notes.txt](/docs/timetable-notes) - Specifies notes to be used in timetables.
19
19
  * [timetable_notes_references.txt](/docs/timetable-notes-references) - Specifies where notes should be placed in timetables.
@@ -15,7 +15,7 @@ Notes can have a `symbol` specified or can be left blank and GTFS-to-HTML will a
15
15
  | ----------- | ----------- |
16
16
  | `note_id` | A unique ID for the timetable note |
17
17
  | `symbol` | The symbol used to indicate the note, such as `§`. Optional, if omitted a letter of the alphabet starting with `a` will be used. |
18
- | `note` | The text of the note, such as "This stop is sometimes underwater". |
18
+ | `note` | The text of the note, such as "This stop is sometimes underwater". [Markdown syntax](https://daringfireball.net/projects/markdown/syntax) is supported which allows including links and formatting. |
19
19
 
20
20
  ### Example
21
21
 
@@ -26,7 +26,8 @@ note_id,symbol,note
26
26
  3,,"Trip is cancelled if drawbridge is up"
27
27
  4,,"This stop is sometimes underwater"
28
28
  5,,"Driver will only stop if prearranged by fax"
29
- 6,§,"Vehicle can arrive early if leap second is added during trip"
29
+ 6,§,"Vehicle can arrive early if leap second is added during trip and *will not wait*"
30
+ 7,,"[See list of holidays](http://transitagency.org/holidays)"
30
31
  ```
31
32
 
32
33
  An example of this file is located in [examples/timetable_notes.txt](https://github.com/BlinkTagInc/gtfs-to-html/blob/master/examples/timetable_notes.txt).
package/www/package.json CHANGED
@@ -9,8 +9,8 @@
9
9
  "deploy": "docusaurus deploy"
10
10
  },
11
11
  "dependencies": {
12
- "@docusaurus/core": "^3.1.0",
13
- "@docusaurus/preset-classic": "^3.1.0",
12
+ "@docusaurus/core": "^3.2.1",
13
+ "@docusaurus/preset-classic": "^3.2.1",
14
14
  "clsx": "^2.1.0",
15
15
  "react": "^18.2.0",
16
16
  "react-dom": "^18.2.0"