gtfs 3.1.3 → 3.2.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/.eslintrc.json +14 -19
- package/.husky/pre-commit +4 -0
- package/@types/index.d.ts +269 -0
- package/@types/tests.ts +26 -0
- package/@types/tsconfig.json +17 -0
- package/CHANGELOG.md +181 -0
- package/README.md +168 -149
- package/bin/gtfs-export.js +4 -5
- package/bin/gtfs-import.js +6 -7
- package/config-sample-full.json +2 -7
- package/docs/images/node-gtfs-logo.svg +18 -0
- package/lib/db.js +64 -13
- package/lib/export.js +27 -13
- package/lib/file-utils.js +26 -9
- package/lib/geojson-utils.js +51 -38
- package/lib/gtfs/agencies.js +15 -4
- package/lib/gtfs/attributions.js +15 -4
- package/lib/gtfs/calendar-dates.js +15 -4
- package/lib/gtfs/calendars.js +15 -4
- package/lib/gtfs/fare-attributes.js +15 -4
- package/lib/gtfs/fare-rules.js +15 -4
- package/lib/gtfs/feed-info.js +15 -4
- package/lib/gtfs/frequencies.js +15 -4
- package/lib/gtfs/levels.js +15 -4
- package/lib/gtfs/pathways.js +15 -4
- package/lib/gtfs/routes.js +22 -6
- package/lib/gtfs/shapes.js +59 -23
- package/lib/gtfs/stop-times.js +15 -4
- package/lib/gtfs/stops.js +57 -23
- package/lib/gtfs/transfers.js +15 -4
- package/lib/gtfs/translations.js +15 -4
- package/lib/gtfs/trips.js +15 -4
- package/lib/gtfs-ride/board-alights.js +15 -4
- package/lib/gtfs-ride/ride-feed-infos.js +15 -4
- package/lib/gtfs-ride/rider-trips.js +15 -4
- package/lib/gtfs-ride/riderships.js +15 -4
- package/lib/gtfs-ride/trip-capacities.js +15 -4
- package/lib/import.js +201 -126
- package/lib/log-utils.js +8 -4
- package/lib/non-standard/directions.js +15 -4
- package/lib/non-standard/stop-attributes.js +15 -4
- package/lib/non-standard/timetable-notes-references.js +15 -4
- package/lib/non-standard/timetable-notes.js +15 -4
- package/lib/non-standard/timetable-pages.js +15 -4
- package/lib/non-standard/timetable-stop-order.js +15 -4
- package/lib/non-standard/timetables.js +15 -4
- package/lib/utils.js +26 -12
- package/models/gtfs/agency.js +11 -11
- package/models/gtfs/attributions.js +14 -14
- package/models/gtfs/calendar-dates.js +7 -7
- package/models/gtfs/calendar.js +12 -12
- package/models/gtfs/fare-attributes.js +9 -9
- package/models/gtfs/fare-rules.js +8 -8
- package/models/gtfs/feed-info.js +12 -12
- package/models/gtfs/frequencies.js +10 -10
- package/models/gtfs/levels.js +5 -5
- package/models/gtfs/pathways.js +14 -14
- package/models/gtfs/routes.js +14 -14
- package/models/gtfs/shapes.js +8 -8
- package/models/gtfs/stop-times.js +17 -17
- package/models/gtfs/stops.js +17 -17
- package/models/gtfs/transfers.js +7 -7
- package/models/gtfs/translations.js +10 -10
- package/models/gtfs/trips.js +12 -12
- package/models/gtfs-ride/board-alight.js +24 -24
- package/models/gtfs-ride/ride-feed-info.js +8 -8
- package/models/gtfs-ride/rider-trip.js +21 -21
- package/models/gtfs-ride/ridership.js +23 -23
- package/models/gtfs-ride/trip-capacity.js +10 -10
- package/models/models.js +1 -1
- package/models/non-standard/directions.js +6 -6
- package/models/non-standard/stop-attributes.js +5 -5
- package/models/non-standard/timetable-notes-references.js +9 -9
- package/models/non-standard/timetable-notes.js +5 -5
- package/models/non-standard/timetable-pages.js +5 -5
- package/models/non-standard/timetable-stop-order.js +6 -6
- package/models/non-standard/timetables.js +27 -27
- package/package.json +23 -11
- package/test/mocha/export-gtfs.js +74 -44
- package/test/mocha/get-agencies.js +20 -14
- package/test/mocha/get-attributions.js +10 -4
- package/test/mocha/get-board-alights.js +10 -4
- package/test/mocha/get-calendar-dates.js +31 -24
- package/test/mocha/get-calendars.js +17 -11
- package/test/mocha/get-db.js +71 -5
- package/test/mocha/get-directions.js +10 -4
- package/test/mocha/get-fare-attributes.js +12 -6
- package/test/mocha/get-fare-rules.js +17 -13
- package/test/mocha/get-feed-info.js +10 -4
- package/test/mocha/get-frequencies.js +10 -4
- package/test/mocha/get-levels.js +4 -4
- package/test/mocha/get-pathways.js +10 -4
- package/test/mocha/get-ride-feed-infos.js +9 -3
- package/test/mocha/get-rider-trips.js +10 -4
- package/test/mocha/get-riderships.js +10 -4
- package/test/mocha/get-routes.js +12 -16
- package/test/mocha/get-shapes-as-geojson.js +12 -6
- package/test/mocha/get-shapes.js +31 -39
- package/test/mocha/get-stop-attributes.js +10 -4
- package/test/mocha/get-stops-as-geojson.js +11 -5
- package/test/mocha/get-stops.js +62 -51
- package/test/mocha/get-stoptimes.js +18 -10
- package/test/mocha/get-timetable-pages.js +10 -4
- package/test/mocha/get-timetable-stop-orders.js +10 -4
- package/test/mocha/get-timetables.js +10 -4
- package/test/mocha/get-transfers.js +10 -4
- package/test/mocha/get-translations.js +10 -4
- package/test/mocha/get-trip-capacities.js +10 -4
- package/test/mocha/get-trips.js +6 -6
- package/test/mocha/import-gtfs.js +63 -46
- package/test/test-config.js +9 -4
package/bin/gtfs-export.js
CHANGED
|
@@ -13,15 +13,15 @@ const { argv } = yargs(hideBin(process.argv))
|
|
|
13
13
|
.option('c', {
|
|
14
14
|
alias: 'configPath',
|
|
15
15
|
describe: 'Path to config file',
|
|
16
|
-
type: 'string'
|
|
16
|
+
type: 'string',
|
|
17
17
|
})
|
|
18
18
|
.option('sqlitePath', {
|
|
19
19
|
describe: 'Path to SQLite database',
|
|
20
|
-
type: 'string'
|
|
20
|
+
type: 'string',
|
|
21
21
|
})
|
|
22
22
|
.option('exportPath', {
|
|
23
23
|
describe: 'Path where GTFS export should go',
|
|
24
|
-
type: 'string'
|
|
24
|
+
type: 'string',
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
const handleError = (error = 'Unknown Error') => {
|
|
@@ -35,5 +35,4 @@ const setupExport = async () => {
|
|
|
35
35
|
process.exit();
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
setupExport()
|
|
39
|
-
.catch(handleError);
|
|
38
|
+
setupExport().catch(handleError);
|
package/bin/gtfs-import.js
CHANGED
|
@@ -13,22 +13,22 @@ const { argv } = yargs(hideBin(process.argv))
|
|
|
13
13
|
.option('c', {
|
|
14
14
|
alias: 'configPath',
|
|
15
15
|
describe: 'Path to config file',
|
|
16
|
-
type: 'string'
|
|
16
|
+
type: 'string',
|
|
17
17
|
})
|
|
18
18
|
.option('gtfsPath', {
|
|
19
19
|
describe: 'Path to gtfs (zipped or unzipped)',
|
|
20
|
-
type: 'string'
|
|
20
|
+
type: 'string',
|
|
21
21
|
})
|
|
22
22
|
.option('gtfsUrl', {
|
|
23
23
|
describe: 'URL of gtfs file',
|
|
24
|
-
type: 'string'
|
|
24
|
+
type: 'string',
|
|
25
25
|
})
|
|
26
26
|
.option('sqlitePath', {
|
|
27
27
|
describe: 'Path to SQLite database',
|
|
28
|
-
type: 'string'
|
|
28
|
+
type: 'string',
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
const handleError = error => {
|
|
31
|
+
const handleError = (error) => {
|
|
32
32
|
const text = error || 'Unknown Error';
|
|
33
33
|
process.stdout.write(`\n${formatError(text)}\n`);
|
|
34
34
|
console.error(error);
|
|
@@ -41,5 +41,4 @@ const setupImport = async () => {
|
|
|
41
41
|
process.exit();
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
setupImport()
|
|
45
|
-
.catch(handleError);
|
|
44
|
+
setupImport().catch(handleError);
|
package/config-sample-full.json
CHANGED
|
@@ -2,16 +2,11 @@
|
|
|
2
2
|
"agencies": [
|
|
3
3
|
{
|
|
4
4
|
"url": "http://www.bart.gov/dev/schedules/google_transit.zip",
|
|
5
|
-
"exclude": [
|
|
6
|
-
"shapes"
|
|
7
|
-
]
|
|
5
|
+
"exclude": ["shapes"]
|
|
8
6
|
},
|
|
9
7
|
{
|
|
10
8
|
"path": "/path/to/gtfs.zip",
|
|
11
|
-
"exclude": [
|
|
12
|
-
"stop_times",
|
|
13
|
-
"shapes"
|
|
14
|
-
]
|
|
9
|
+
"exclude": ["stop_times", "shapes"]
|
|
15
10
|
}
|
|
16
11
|
],
|
|
17
12
|
"csvOptions": {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<svg width="280" height="311" viewBox="0 0 280 311" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M279.142 216.458V95.0263C279.142 82.9559 272.684 71.822 262.162 65.7868L156.951 5.01874C146.43 -1.01645 133.617 -1.01645 123.096 5.01874L17.8843 65.6828C7.36316 71.718 0.904633 82.8518 0.904633 95.0263V216.458C0.904633 228.529 7.36316 239.663 17.8843 245.698L123.096 306.362C133.617 312.397 146.43 312.397 156.951 306.362L262.267 245.594C272.684 239.663 279.142 228.529 279.142 216.458Z" fill="#B43052"/>
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M140.075 292.21C137.471 292.21 134.867 291.482 132.471 290.233L27.2596 229.465C22.5719 226.76 19.6552 221.765 19.6552 216.354V95.0263C19.6552 89.6154 22.5719 84.6208 27.1554 81.9154L132.471 21.1473C134.763 19.7945 137.367 19.1702 140.075 19.1702C142.784 19.1702 145.284 19.8986 147.68 21.1473L252.995 81.9154C257.683 84.6208 260.6 89.6154 260.6 95.0263V216.458C260.6 221.869 257.683 226.864 252.995 229.569L147.68 290.337C145.284 291.482 142.68 292.21 140.075 292.21Z" fill="#FCC761"/>
|
|
4
|
+
<mask id="mask0_4_20" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="10" y="133" width="259" height="61">
|
|
5
|
+
<path d="M10.6457 133.301H268.646V193.301H10.6457V133.301Z" fill="white"/>
|
|
6
|
+
</mask>
|
|
7
|
+
<g mask="url(#mask0_4_20)">
|
|
8
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.6457 34.2317H268.646V292.232H10.6457V34.2317Z" fill="#B43052"/>
|
|
9
|
+
</g>
|
|
10
|
+
<mask id="mask1_4_20" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="122" y="244" width="36" height="35">
|
|
11
|
+
<path d="M122 244H157.139V278.037H122V244Z" fill="white"/>
|
|
12
|
+
</mask>
|
|
13
|
+
<g mask="url(#mask1_4_20)">
|
|
14
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M144.917 255.167L157.139 256.912L148.335 265.657L150.471 277.948L139.523 272.186L128.621 278.037L130.658 265.73L121.785 257.056L133.992 255.212L139.41 244L144.917 255.167Z" fill="white"/>
|
|
15
|
+
</g>
|
|
16
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M178.87 65.8803C178.87 64.6713 178.312 63.7413 177.289 63.0903C177.103 62.9973 176.824 62.8113 176.638 62.7183C176.638 59.6494 176.545 56.4875 176.359 53.3256C175.987 46.0718 172.174 42.5378 165.013 42.4448C158.782 42.4448 152.551 42.4448 146.32 42.4448C136.183 42.4448 126.139 42.3518 116.002 42.5378C106.702 42.7238 102.982 46.6297 102.982 55.9295C102.982 58.1614 102.982 60.3934 102.982 62.7183C102.424 62.9043 101.959 63.3693 101.587 63.8343C100.936 64.3923 100.75 65.2293 100.75 66.1592C100.75 70.4371 100.75 74.715 100.75 79.0859C100.75 80.3879 101.215 81.4109 102.331 82.0618C102.61 82.2478 102.796 82.3408 103.075 82.4338C103.075 91.6406 103.075 100.754 103.075 109.961C103.075 111.263 102.889 112.751 103.54 113.867C104.935 116.099 104.656 118.517 104.749 120.935C104.842 123.911 106.795 125.957 109.771 126.05C111.91 126.143 114.049 126.143 116.188 126.05C119.257 125.957 121.21 124.19 121.303 121.121C121.396 119.819 121.582 119.354 123.07 119.354C134.23 119.447 145.483 119.447 156.643 119.354C158.038 119.354 158.41 119.726 158.41 121.121C158.503 124.376 160.456 126.05 163.711 126.05C165.571 126.05 167.431 126.05 169.291 126.05C173.104 126.05 174.964 124.097 175.057 120.284C175.057 118.796 174.592 117.122 175.429 115.727C176.452 113.867 176.731 112.007 176.731 109.961C176.731 101.312 176.731 92.6636 176.731 82.4338C177.382 82.3408 177.94 81.7829 178.312 81.2249C178.777 80.6669 178.963 79.9229 178.963 79.1789C178.87 74.808 178.87 70.3441 178.87 65.8803ZM124.279 49.1407C129.859 49.1407 135.439 49.1407 140.926 49.1407C146.32 49.1407 151.714 49.1407 157.201 49.1407C159.619 49.1407 159.898 49.5127 159.991 52.3026C159.991 55.3715 159.712 55.8365 157.387 55.8365C146.32 55.8365 135.253 55.8365 124.279 55.8365C121.861 55.8365 121.396 55.2785 121.396 52.4886C121.303 49.6987 121.768 49.1407 124.279 49.1407ZM117.304 111.077C114.049 111.077 111.352 108.38 111.352 105.125C111.445 101.963 114.142 99.3594 117.211 99.3594C120.466 99.3594 122.884 101.87 122.884 105.218C122.977 108.473 120.466 111.077 117.304 111.077ZM116.467 90.9896C112.933 90.9896 111.352 89.3157 111.352 85.6888C111.352 79.1789 111.352 72.6691 111.352 66.1592C111.352 62.5323 112.84 61.0444 116.467 61.0444C124.279 61.0444 131.998 61.0444 139.81 61.0444C147.436 61.0444 155.062 61.0444 162.688 61.0444C166.78 61.0444 168.175 62.4393 168.175 66.4382C168.175 72.6691 168.175 78.8999 168.175 85.1308C168.175 88.8507 166.129 90.8966 162.409 90.9896C147.157 90.9896 131.812 90.9896 116.467 90.9896ZM162.409 111.077C159.247 111.077 156.736 108.566 156.643 105.311C156.643 101.963 159.061 99.4524 162.316 99.4524C165.571 99.4524 168.268 102.149 168.268 105.404C168.175 108.38 165.571 111.077 162.409 111.077Z" fill="white"/>
|
|
17
|
+
<path d="M69.2254 147.5H75.4354L80.2504 166.355H80.3404V147.5H84.7504V179H79.6654L73.7254 156.005H73.6354V179H69.2254V147.5ZM95.5845 179.45C93.1545 179.45 91.2945 178.76 90.0045 177.38C88.7145 176 88.0695 174.05 88.0695 171.53V154.97C88.0695 152.45 88.7145 150.5 90.0045 149.12C91.2945 147.74 93.1545 147.05 95.5845 147.05C98.0145 147.05 99.8745 147.74 101.164 149.12C102.454 150.5 103.099 152.45 103.099 154.97V171.53C103.099 174.05 102.454 176 101.164 177.38C99.8745 178.76 98.0145 179.45 95.5845 179.45ZM95.5845 174.95C97.2945 174.95 98.1495 173.915 98.1495 171.845V154.655C98.1495 152.585 97.2945 151.55 95.5845 151.55C93.8745 151.55 93.0195 152.585 93.0195 154.655V171.845C93.0195 173.915 93.8745 174.95 95.5845 174.95ZM106.447 147.5H114.007C116.467 147.5 118.312 148.16 119.542 149.48C120.772 150.8 121.387 152.735 121.387 155.285V171.215C121.387 173.765 120.772 175.7 119.542 177.02C118.312 178.34 116.467 179 114.007 179H106.447V147.5ZM113.917 174.5C114.727 174.5 115.342 174.26 115.762 173.78C116.212 173.3 116.437 172.52 116.437 171.44V155.06C116.437 153.98 116.212 153.2 115.762 152.72C115.342 152.24 114.727 152 113.917 152H111.397V174.5H113.917ZM124.728 147.5H138.228V152H129.678V160.325H136.473V164.825H129.678V174.5H138.228V179H124.728V147.5ZM155.303 179.45C152.903 179.45 151.073 178.775 149.813 177.425C148.553 176.045 147.923 174.08 147.923 171.53V154.97C147.923 152.42 148.553 150.47 149.813 149.12C151.073 147.74 152.903 147.05 155.303 147.05C157.703 147.05 159.533 147.74 160.793 149.12C162.053 150.47 162.683 152.42 162.683 154.97V157.67H158.003V154.655C158.003 152.585 157.148 151.55 155.438 151.55C153.728 151.55 152.873 152.585 152.873 154.655V171.89C152.873 173.93 153.728 174.95 155.438 174.95C157.148 174.95 158.003 173.93 158.003 171.89V165.725H155.528V161.225H162.683V171.53C162.683 174.08 162.053 176.045 160.793 177.425C159.533 178.775 157.703 179.45 155.303 179.45ZM169.731 152H164.556V147.5H179.856V152H174.681V179H169.731V152ZM182.253 147.5H195.348V152H187.203V160.775H193.593V165.275H187.203V179H182.253V147.5ZM204.156 179.45C201.756 179.45 199.941 178.775 198.711 177.425C197.481 176.045 196.866 174.08 196.866 171.53V169.73H201.546V171.89C201.546 173.93 202.401 174.95 204.111 174.95C204.951 174.95 205.581 174.71 206.001 174.23C206.451 173.72 206.676 172.91 206.676 171.8C206.676 170.48 206.376 169.325 205.776 168.335C205.176 167.315 204.066 166.1 202.446 164.69C200.406 162.89 198.981 161.27 198.171 159.83C197.361 158.36 196.956 156.71 196.956 154.88C196.956 152.39 197.586 150.47 198.846 149.12C200.106 147.74 201.936 147.05 204.336 147.05C206.706 147.05 208.491 147.74 209.691 149.12C210.921 150.47 211.536 152.42 211.536 154.97V156.275H206.856V154.655C206.856 153.575 206.646 152.795 206.226 152.315C205.806 151.805 205.191 151.55 204.381 151.55C202.731 151.55 201.906 152.555 201.906 154.565C201.906 155.705 202.206 156.77 202.806 157.76C203.436 158.75 204.561 159.95 206.181 161.36C208.251 163.16 209.676 164.795 210.456 166.265C211.236 167.735 211.626 169.46 211.626 171.44C211.626 174.02 210.981 176 209.691 177.38C208.431 178.76 206.586 179.45 204.156 179.45Z" fill="white"/>
|
|
18
|
+
</svg>
|
package/lib/db.js
CHANGED
|
@@ -1,21 +1,38 @@
|
|
|
1
|
-
import sqlite3 from 'sqlite3';
|
|
1
|
+
import sqlite3 from '@vscode/sqlite3';
|
|
2
2
|
import { open } from 'sqlite';
|
|
3
3
|
import { setDefaultConfig } from './utils.js';
|
|
4
|
-
|
|
4
|
+
const dbs = {};
|
|
5
5
|
|
|
6
6
|
export async function openDb(initialConfig) {
|
|
7
7
|
const config = setDefaultConfig(initialConfig);
|
|
8
|
-
if (!
|
|
9
|
-
|
|
8
|
+
if (!dbs[config.sqlitePath]) {
|
|
9
|
+
dbs[config.sqlitePath] = await open({
|
|
10
10
|
filename: config.sqlitePath,
|
|
11
|
-
driver: sqlite3.Database
|
|
11
|
+
driver: sqlite3.Database,
|
|
12
12
|
});
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
return
|
|
15
|
+
return dbs[config.sqlitePath];
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export async function setupDb() {
|
|
18
|
+
export async function setupDb(db) {
|
|
19
|
+
if (Object.keys(dbs).length === 0) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
'No database connection. Call `openDb(config)` before using any methods.'
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!db) {
|
|
26
|
+
if (Object.keys(dbs).length > 1) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
'Multiple database connections. Pass the db you want to close as a parameter to `setupDb`.'
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const filename = Object.keys(dbs)[0];
|
|
33
|
+
db = dbs[filename];
|
|
34
|
+
}
|
|
35
|
+
|
|
19
36
|
await db.run('PRAGMA journal_mode = OFF;');
|
|
20
37
|
await db.run('PRAGMA synchronous = 0;');
|
|
21
38
|
await db.run('PRAGMA locking_mode = EXCLUSIVE;');
|
|
@@ -23,15 +40,49 @@ export async function setupDb() {
|
|
|
23
40
|
await db.run('VACUUM;');
|
|
24
41
|
}
|
|
25
42
|
|
|
26
|
-
export async function closeDb() {
|
|
43
|
+
export async function closeDb(db) {
|
|
44
|
+
if (Object.keys(dbs).length === 0) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
'No database connection. Call `openDb(config)` before using any methods.'
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!db) {
|
|
51
|
+
if (Object.keys(dbs).length > 1) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
'Multiple database connections. Pass the db you want to close as a parameter to `closeDb`.'
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
db = dbs[Object.keys(dbs)[0]];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const { filename } = db.config;
|
|
61
|
+
|
|
27
62
|
await db.close();
|
|
28
|
-
|
|
63
|
+
delete dbs[filename];
|
|
29
64
|
}
|
|
30
65
|
|
|
31
|
-
export function getDb() {
|
|
32
|
-
if (
|
|
33
|
-
|
|
66
|
+
export function getDb(initialConfig) {
|
|
67
|
+
if (Object.keys(dbs).length === 0) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
'No database connection. Call `openDb(config)` before using any methods.'
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const config = setDefaultConfig(initialConfig);
|
|
74
|
+
if (dbs[config.sqlitePath]) {
|
|
75
|
+
return dbs[config.sqlitePath];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/*
|
|
79
|
+
* Fall back to using the only open database connection if only
|
|
80
|
+
* one exists for backwards compatibility
|
|
81
|
+
*/
|
|
82
|
+
if (Object.keys(dbs).length === 1) {
|
|
83
|
+
const filename = Object.keys(dbs)[0];
|
|
84
|
+
return dbs[filename];
|
|
34
85
|
}
|
|
35
86
|
|
|
36
|
-
throw new Error('
|
|
87
|
+
throw new Error('Unable to find database connection.');
|
|
37
88
|
}
|
package/lib/export.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { writeFile } from 'node:fs/promises';
|
|
3
|
-
import { promisify } from 'node:util';
|
|
4
3
|
|
|
5
4
|
import { without, compact } from 'lodash-es';
|
|
6
5
|
import pluralize from 'pluralize';
|
|
7
|
-
import
|
|
6
|
+
import { stringify } from 'csv-stringify';
|
|
8
7
|
import sqlString from 'sqlstring-sqlite';
|
|
9
8
|
import mapSeries from 'promise-map-series';
|
|
10
9
|
import untildify from 'untildify';
|
|
@@ -15,9 +14,7 @@ import { prepDirectory, generateFolderName } from './file-utils.js';
|
|
|
15
14
|
import { log as _log, logWarning as _logWarning } from './log-utils.js';
|
|
16
15
|
import { setDefaultConfig } from './utils.js';
|
|
17
16
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
const exportGtfs = async initialConfig => {
|
|
17
|
+
const exportGtfs = async (initialConfig) => {
|
|
21
18
|
const config = setDefaultConfig(initialConfig);
|
|
22
19
|
const log = _log(config);
|
|
23
20
|
const logWarning = _logWarning(config);
|
|
@@ -26,20 +23,34 @@ const exportGtfs = async initialConfig => {
|
|
|
26
23
|
// Get agency name for export folder from first line of agency.txt
|
|
27
24
|
const agencies = await db.all('SELECT agency_name FROM agency;').catch(() => {
|
|
28
25
|
if (config.sqlitePath === ':memory:') {
|
|
29
|
-
throw new Error(
|
|
26
|
+
throw new Error(
|
|
27
|
+
'No agencies found in SQLite. You are using an in-memory database - if running this from command line be sure to specify a value for `sqlitePath` in config.json other than ":memory:".'
|
|
28
|
+
);
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
throw new Error(
|
|
31
|
+
throw new Error(
|
|
32
|
+
'No agencies found in SQLite. Be sure to first import data into SQLite using `gtfs-import` or `importGtfs(config);`'
|
|
33
|
+
);
|
|
33
34
|
});
|
|
34
35
|
|
|
35
36
|
const agencyCount = agencies.length;
|
|
36
37
|
if (agencyCount === 0) {
|
|
37
|
-
throw new Error(
|
|
38
|
+
throw new Error(
|
|
39
|
+
'No agencies found in SQLite. Be sure to first import data into SQLite using `gtfs-import` or `importGtfs(config);`'
|
|
40
|
+
);
|
|
38
41
|
} else if (agencyCount > 1) {
|
|
39
|
-
logWarning(
|
|
42
|
+
logWarning(
|
|
43
|
+
'More than one agency is defined in config.json. Export will merge all into one GTFS file.'
|
|
44
|
+
);
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
log(
|
|
47
|
+
log(
|
|
48
|
+
`Starting GTFS export for ${pluralize(
|
|
49
|
+
'agency',
|
|
50
|
+
agencyCount,
|
|
51
|
+
true
|
|
52
|
+
)} using SQLite database at ${config.sqlitePath}`
|
|
53
|
+
);
|
|
43
54
|
|
|
44
55
|
const folderName = generateFolderName(agencies[0].agency_name);
|
|
45
56
|
const defaultExportPath = path.join(process.cwd(), 'gtfs-export', folderName);
|
|
@@ -48,7 +59,7 @@ const exportGtfs = async initialConfig => {
|
|
|
48
59
|
await prepDirectory(exportPath);
|
|
49
60
|
|
|
50
61
|
// Loop through each GTFS file
|
|
51
|
-
const exportedFiles = await mapSeries(models, async model => {
|
|
62
|
+
const exportedFiles = await mapSeries(models, async (model) => {
|
|
52
63
|
const filepath = path.join(exportPath, `${model.filenameBase}.txt`);
|
|
53
64
|
const tableName = sqlString.escapeId(model.filenameBase);
|
|
54
65
|
const lines = await db.all(`SELECT * FROM ${tableName};`);
|
|
@@ -72,10 +83,13 @@ const exportGtfs = async initialConfig => {
|
|
|
72
83
|
'boarding_timestamp',
|
|
73
84
|
'alighting_timestamp',
|
|
74
85
|
'ridership_start_timestamp',
|
|
75
|
-
'ridership_end_timestamp'
|
|
86
|
+
'ridership_end_timestamp',
|
|
76
87
|
];
|
|
77
88
|
|
|
78
|
-
const columns = without(
|
|
89
|
+
const columns = without(
|
|
90
|
+
model.schema.map((column) => column.name),
|
|
91
|
+
...excludeColumns
|
|
92
|
+
);
|
|
79
93
|
const fileText = await stringify(lines, { columns, header: true });
|
|
80
94
|
await writeFile(filepath, fileText);
|
|
81
95
|
|
package/lib/file-utils.js
CHANGED
|
@@ -15,13 +15,24 @@ export async function getConfig(argv) {
|
|
|
15
15
|
if (argv.configPath) {
|
|
16
16
|
// If a `configPath` is specified, try to read it and throw error if it doesn't exist
|
|
17
17
|
try {
|
|
18
|
-
const data = await readFile(
|
|
19
|
-
|
|
18
|
+
const data = await readFile(
|
|
19
|
+
path.resolve(untildify(argv.configPath)),
|
|
20
|
+
'utf8'
|
|
21
|
+
).catch((error) => {
|
|
22
|
+
console.error(
|
|
23
|
+
new Error(
|
|
24
|
+
`Cannot find configuration file at \`${argv.configPath}\`. Use config-sample.json as a starting point, pass --configPath option.`
|
|
25
|
+
)
|
|
26
|
+
);
|
|
20
27
|
throw error;
|
|
21
28
|
});
|
|
22
29
|
config = Object.assign(JSON.parse(data), argv);
|
|
23
30
|
} catch (error) {
|
|
24
|
-
console.error(
|
|
31
|
+
console.error(
|
|
32
|
+
new Error(
|
|
33
|
+
`Cannot parse configuration file at \`${argv.configPath}\`. Check to ensure that it is valid JSON.`
|
|
34
|
+
)
|
|
35
|
+
);
|
|
25
36
|
throw error;
|
|
26
37
|
}
|
|
27
38
|
} else if (existsSync(path.resolve('./config.json'))) {
|
|
@@ -31,7 +42,11 @@ export async function getConfig(argv) {
|
|
|
31
42
|
config = Object.assign(JSON.parse(data), argv);
|
|
32
43
|
console.log('Using configuration from ./config.json');
|
|
33
44
|
} catch (error) {
|
|
34
|
-
console.error(
|
|
45
|
+
console.error(
|
|
46
|
+
new Error(
|
|
47
|
+
'Cannot parse configuration file at `./config.json`. Check to ensure that it is valid JSON.'
|
|
48
|
+
)
|
|
49
|
+
);
|
|
35
50
|
throw error;
|
|
36
51
|
}
|
|
37
52
|
} else if (argv.gtfsPath || argv.gtfsUrl) {
|
|
@@ -39,22 +54,24 @@ export async function getConfig(argv) {
|
|
|
39
54
|
const agencies = [];
|
|
40
55
|
if (argv.gtfsPath) {
|
|
41
56
|
agencies.push({
|
|
42
|
-
path: argv.gtfsPath
|
|
57
|
+
path: argv.gtfsPath,
|
|
43
58
|
});
|
|
44
59
|
}
|
|
45
60
|
|
|
46
61
|
if (argv.gtfsUrl) {
|
|
47
62
|
agencies.push({
|
|
48
|
-
url: argv.gtfsUrl
|
|
63
|
+
url: argv.gtfsUrl,
|
|
49
64
|
});
|
|
50
65
|
}
|
|
51
66
|
|
|
52
67
|
config = {
|
|
53
68
|
agencies,
|
|
54
|
-
...omit(argv, ['path', 'url'])
|
|
69
|
+
...omit(argv, ['path', 'url']),
|
|
55
70
|
};
|
|
56
71
|
} else {
|
|
57
|
-
const error = new Error(
|
|
72
|
+
const error = new Error(
|
|
73
|
+
'Cannot find configuration file. Use config-sample.json as a starting point, pass --configPath option.'
|
|
74
|
+
);
|
|
58
75
|
console.error(error);
|
|
59
76
|
throw error;
|
|
60
77
|
}
|
|
@@ -78,7 +95,7 @@ export function unzip(zipfilePath, exportPath) {
|
|
|
78
95
|
/* eslint-disable new-cap */
|
|
79
96
|
return createReadStream(zipfilePath)
|
|
80
97
|
.pipe(Extract({ path: exportPath }))
|
|
81
|
-
.on('entry', entry => entry.autodrain())
|
|
98
|
+
.on('entry', (entry) => entry.autodrain())
|
|
82
99
|
.promise();
|
|
83
100
|
/* eslint-enable new-cap */
|
|
84
101
|
}
|
package/lib/geojson-utils.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
cloneDeep,
|
|
3
|
+
filter,
|
|
4
|
+
groupBy,
|
|
5
|
+
last,
|
|
6
|
+
omit,
|
|
7
|
+
sortBy,
|
|
8
|
+
omitBy,
|
|
9
|
+
} from 'lodash-es';
|
|
2
10
|
import { feature, featureCollection } from '@turf/helpers';
|
|
3
11
|
|
|
4
12
|
function isValidLineString(lineString) {
|
|
@@ -11,7 +19,11 @@ function isValidLineString(lineString) {
|
|
|
11
19
|
}
|
|
12
20
|
|
|
13
21
|
// Reject linestrings with two identical points
|
|
14
|
-
if (
|
|
22
|
+
if (
|
|
23
|
+
lineString.length === 2 &&
|
|
24
|
+
lineString[0][0] === lineString[1][0] &&
|
|
25
|
+
lineString[0][1] === lineString[1][1]
|
|
26
|
+
) {
|
|
15
27
|
return false;
|
|
16
28
|
}
|
|
17
29
|
|
|
@@ -20,22 +32,18 @@ function isValidLineString(lineString) {
|
|
|
20
32
|
|
|
21
33
|
function consolidateShapes(shapes) {
|
|
22
34
|
const keys = new Set();
|
|
23
|
-
const segmentsArray = shapes.map(shape
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
[
|
|
27
|
-
shape[idx - 1].shape_pt_lon,
|
|
28
|
-
|
|
29
|
-
]
|
|
30
|
-
|
|
31
|
-
point.shape_pt_lon,
|
|
32
|
-
point.shape_pt_lat
|
|
33
|
-
]
|
|
34
|
-
]);
|
|
35
|
-
}
|
|
35
|
+
const segmentsArray = shapes.map((shape) =>
|
|
36
|
+
shape.reduce((memo, point, idx) => {
|
|
37
|
+
if (idx > 0) {
|
|
38
|
+
memo.push([
|
|
39
|
+
[shape[idx - 1].shape_pt_lon, shape[idx - 1].shape_pt_lat],
|
|
40
|
+
[point.shape_pt_lon, point.shape_pt_lat],
|
|
41
|
+
]);
|
|
42
|
+
}
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
|
|
44
|
+
return memo;
|
|
45
|
+
}, [])
|
|
46
|
+
);
|
|
39
47
|
|
|
40
48
|
const consolidatedLineStrings = [];
|
|
41
49
|
|
|
@@ -75,42 +83,47 @@ function formatHexColor(color) {
|
|
|
75
83
|
|
|
76
84
|
function formatProperties(properties) {
|
|
77
85
|
const formattedProperties = {
|
|
78
|
-
...cloneDeep(omitBy(properties, value => value === null)),
|
|
86
|
+
...cloneDeep(omitBy(properties, (value) => value === null)),
|
|
79
87
|
route_color: formatHexColor(properties.route_color),
|
|
80
|
-
route_text_color: formatHexColor(properties.route_text_color)
|
|
88
|
+
route_text_color: formatHexColor(properties.route_text_color),
|
|
81
89
|
};
|
|
82
90
|
|
|
83
91
|
if (properties.routes) {
|
|
84
|
-
formattedProperties.routes = properties.routes.map(route =>
|
|
92
|
+
formattedProperties.routes = properties.routes.map((route) =>
|
|
93
|
+
formatProperties(route)
|
|
94
|
+
);
|
|
85
95
|
}
|
|
86
96
|
|
|
87
97
|
return formattedProperties;
|
|
88
98
|
}
|
|
89
99
|
|
|
90
100
|
export function shapesToGeoJSONFeatures(shapes, properties = {}) {
|
|
91
|
-
const shapeGroups = Object.values(groupBy(shapes, 'shape_id')).map(
|
|
101
|
+
const shapeGroups = Object.values(groupBy(shapes, 'shape_id')).map(
|
|
102
|
+
(shapeGroup) => sortBy(shapeGroup, 'shape_pt_sequence')
|
|
103
|
+
);
|
|
92
104
|
const lineStrings = consolidateShapes(shapeGroups);
|
|
93
105
|
|
|
94
|
-
return lineStrings.map(lineString =>
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
return lineStrings.map((lineString) =>
|
|
107
|
+
feature(
|
|
108
|
+
{
|
|
109
|
+
type: 'LineString',
|
|
110
|
+
coordinates: lineString,
|
|
111
|
+
},
|
|
112
|
+
formatProperties(properties)
|
|
113
|
+
)
|
|
114
|
+
);
|
|
101
115
|
}
|
|
102
116
|
|
|
103
117
|
export function stopsToGeoJSON(stops) {
|
|
104
|
-
const features = stops.map(stop =>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
stop.stop_lon,
|
|
109
|
-
|
|
110
|
-
]
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
));
|
|
118
|
+
const features = stops.map((stop) =>
|
|
119
|
+
feature(
|
|
120
|
+
{
|
|
121
|
+
type: 'Point',
|
|
122
|
+
coordinates: [stop.stop_lon, stop.stop_lat],
|
|
123
|
+
},
|
|
124
|
+
formatProperties(omit(stop, ['stop_lat', 'stop_lon']))
|
|
125
|
+
)
|
|
126
|
+
);
|
|
114
127
|
|
|
115
128
|
return featureCollection(features);
|
|
116
129
|
}
|
package/lib/gtfs/agencies.js
CHANGED
|
@@ -2,18 +2,29 @@ import sqlString from 'sqlstring-sqlite';
|
|
|
2
2
|
|
|
3
3
|
import { getDb } from '../db.js';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
formatOrderByClause,
|
|
7
|
+
formatSelectClause,
|
|
8
|
+
formatWhereClauses,
|
|
9
|
+
} from '../utils.js';
|
|
6
10
|
import agency from '../../models/gtfs/agency.js';
|
|
7
11
|
|
|
8
12
|
/*
|
|
9
13
|
* Returns an array of all agencies that match the query parameters.
|
|
10
14
|
*/
|
|
11
|
-
export async function getAgencies(
|
|
12
|
-
|
|
15
|
+
export async function getAgencies(
|
|
16
|
+
query = {},
|
|
17
|
+
fields = [],
|
|
18
|
+
orderBy = [],
|
|
19
|
+
options = {}
|
|
20
|
+
) {
|
|
21
|
+
const db = options.db ?? (await getDb());
|
|
13
22
|
const tableName = sqlString.escapeId(agency.filenameBase);
|
|
14
23
|
const selectClause = formatSelectClause(fields);
|
|
15
24
|
const whereClause = formatWhereClauses(query);
|
|
16
25
|
const orderByClause = formatOrderByClause(orderBy);
|
|
17
26
|
|
|
18
|
-
return db.all(
|
|
27
|
+
return db.all(
|
|
28
|
+
`${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`
|
|
29
|
+
);
|
|
19
30
|
}
|
package/lib/gtfs/attributions.js
CHANGED
|
@@ -2,18 +2,29 @@ import sqlString from 'sqlstring-sqlite';
|
|
|
2
2
|
|
|
3
3
|
import { getDb } from '../db.js';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
formatOrderByClause,
|
|
7
|
+
formatSelectClause,
|
|
8
|
+
formatWhereClauses,
|
|
9
|
+
} from '../utils.js';
|
|
6
10
|
import attributions from '../../models/gtfs/attributions.js';
|
|
7
11
|
|
|
8
12
|
/*
|
|
9
13
|
* Returns an array of all attributions that match the query parameters.
|
|
10
14
|
*/
|
|
11
|
-
export async function getAttributions(
|
|
12
|
-
|
|
15
|
+
export async function getAttributions(
|
|
16
|
+
query = {},
|
|
17
|
+
fields = [],
|
|
18
|
+
orderBy = [],
|
|
19
|
+
options = {}
|
|
20
|
+
) {
|
|
21
|
+
const db = options.db ?? (await getDb());
|
|
13
22
|
const tableName = sqlString.escapeId(attributions.filenameBase);
|
|
14
23
|
const selectClause = formatSelectClause(fields);
|
|
15
24
|
const whereClause = formatWhereClauses(query);
|
|
16
25
|
const orderByClause = formatOrderByClause(orderBy);
|
|
17
26
|
|
|
18
|
-
return db.all(
|
|
27
|
+
return db.all(
|
|
28
|
+
`${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`
|
|
29
|
+
);
|
|
19
30
|
}
|
|
@@ -2,18 +2,29 @@ import sqlString from 'sqlstring-sqlite';
|
|
|
2
2
|
|
|
3
3
|
import { getDb } from '../db.js';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
formatOrderByClause,
|
|
7
|
+
formatSelectClause,
|
|
8
|
+
formatWhereClauses,
|
|
9
|
+
} from '../utils.js';
|
|
6
10
|
import calendarDates from '../../models/gtfs/calendar-dates.js';
|
|
7
11
|
|
|
8
12
|
/*
|
|
9
13
|
* Returns an array of calendarDates that match the query parameters.
|
|
10
14
|
*/
|
|
11
|
-
export async function getCalendarDates(
|
|
12
|
-
|
|
15
|
+
export async function getCalendarDates(
|
|
16
|
+
query = {},
|
|
17
|
+
fields = [],
|
|
18
|
+
orderBy = [],
|
|
19
|
+
options = {}
|
|
20
|
+
) {
|
|
21
|
+
const db = options.db ?? (await getDb());
|
|
13
22
|
const tableName = sqlString.escapeId(calendarDates.filenameBase);
|
|
14
23
|
const selectClause = formatSelectClause(fields);
|
|
15
24
|
const whereClause = formatWhereClauses(query);
|
|
16
25
|
const orderByClause = formatOrderByClause(orderBy);
|
|
17
26
|
|
|
18
|
-
return db.all(
|
|
27
|
+
return db.all(
|
|
28
|
+
`${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`
|
|
29
|
+
);
|
|
19
30
|
}
|
package/lib/gtfs/calendars.js
CHANGED
|
@@ -2,18 +2,29 @@ import sqlString from 'sqlstring-sqlite';
|
|
|
2
2
|
|
|
3
3
|
import { getDb } from '../db.js';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
formatOrderByClause,
|
|
7
|
+
formatSelectClause,
|
|
8
|
+
formatWhereClauses,
|
|
9
|
+
} from '../utils.js';
|
|
6
10
|
import calendars from '../../models/gtfs/calendar.js';
|
|
7
11
|
|
|
8
12
|
/*
|
|
9
13
|
* Returns an array of calendars that match the query parameters.
|
|
10
14
|
*/
|
|
11
|
-
export async function getCalendars(
|
|
12
|
-
|
|
15
|
+
export async function getCalendars(
|
|
16
|
+
query = {},
|
|
17
|
+
fields = [],
|
|
18
|
+
orderBy = [],
|
|
19
|
+
options = {}
|
|
20
|
+
) {
|
|
21
|
+
const db = options.db ?? (await getDb());
|
|
13
22
|
const tableName = sqlString.escapeId(calendars.filenameBase);
|
|
14
23
|
const selectClause = formatSelectClause(fields);
|
|
15
24
|
const whereClause = formatWhereClauses(query);
|
|
16
25
|
const orderByClause = formatOrderByClause(orderBy);
|
|
17
26
|
|
|
18
|
-
return db.all(
|
|
27
|
+
return db.all(
|
|
28
|
+
`${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`
|
|
29
|
+
);
|
|
19
30
|
}
|