gtfs 4.17.5 → 4.17.7
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/README.md +64 -8
- package/dist/bin/gtfs-export.js +18 -14
- package/dist/bin/gtfs-export.js.map +1 -1
- package/dist/bin/gtfs-import.js +90 -29
- package/dist/bin/gtfs-import.js.map +1 -1
- package/dist/bin/gtfsrealtime-update.js +17 -13
- package/dist/bin/gtfsrealtime-update.js.map +1 -1
- package/dist/index.js +185 -107
- package/dist/index.js.map +1 -1
- package/package.json +33 -37
package/README.md
CHANGED
|
@@ -151,14 +151,14 @@ Copy `config-sample.json` to `config.json` and then add your projects configurat
|
|
|
151
151
|
| option | type | description |
|
|
152
152
|
| ----------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
153
153
|
| [`agencies`](#agencies) | array | An array of GTFS files to be imported, and which files to exclude. |
|
|
154
|
-
| [`csvOptions`](#
|
|
154
|
+
| [`csvOptions`](#csvoptions) | object | Options passed to `csv-parse` for parsing GTFS CSV files. Optional. |
|
|
155
155
|
| [`db`](#db) | database instance | An existing database instance to use instead of relying on node-gtfs to connect. Optional. |
|
|
156
156
|
| [`downloadTimeout`](#downloadtimeout) | integer | The number of milliseconds to wait before throwing an error when downloading GTFS. Optional. |
|
|
157
|
-
| [`exportPath`](#
|
|
157
|
+
| [`exportPath`](#exportpath) | string | A path to a directory to put exported GTFS files. Optional, defaults to `gtfs-export/<agency_name>`. |
|
|
158
158
|
| [`gtfsRealtimeExpirationSeconds`](#gtfsrealtimeexpirationseconds) | integer | Amount of time in seconds to allow GTFS-Realtime data to be stored in database before allowing to be deleted. Optional, defaults to 0. |
|
|
159
159
|
| [`ignoreDuplicates`](#ignoreduplicates) | boolean | Whether or not to ignore unique constraints on ids when importing GTFS, such as `trip_id`, `calendar_id`. Optional, defaults to false. |
|
|
160
|
-
| [`ignoreErrors`](#ignoreerrors) | boolean | Whether or not to ignore errors during the import process. If true,
|
|
161
|
-
| [`sqlitePath`](#
|
|
160
|
+
| [`ignoreErrors`](#ignoreerrors) | boolean | Whether or not to ignore errors during the import process. If true, failed files will be skipped while the rest are processed. Optional, defaults to false. |
|
|
161
|
+
| [`sqlitePath`](#sqlitepath) | string | A path to an SQLite database. Optional, defaults to using an in-memory database. |
|
|
162
162
|
| [`verbose`](#verbose) | boolean | Whether or not to print output to the console. Optional, defaults to true. |
|
|
163
163
|
|
|
164
164
|
### agencies
|
|
@@ -431,7 +431,28 @@ importGtfs({
|
|
|
431
431
|
|
|
432
432
|
### ignoreErrors
|
|
433
433
|
|
|
434
|
-
{Boolean}
|
|
434
|
+
{Boolean} Controls error handling behavior during GTFS import. When `true`, the import process will continue even when encountering errors, logging them instead of stopping execution. Defaults to `false`.
|
|
435
|
+
|
|
436
|
+
**When enabled, `ignoreErrors` will:**
|
|
437
|
+
- Continue processing other GTFS files when one file fails
|
|
438
|
+
- Log error messages instead of throwing exceptions
|
|
439
|
+
- Skip problematic records within files while importing valid ones
|
|
440
|
+
- Handle various error types including:
|
|
441
|
+
- Invalid CSV data or malformed records
|
|
442
|
+
- JSON parsing errors (for GeoJSON files)
|
|
443
|
+
- Database constraint violations
|
|
444
|
+
- File read/write errors
|
|
445
|
+
- GTFS-Realtime API failures
|
|
446
|
+
|
|
447
|
+
**Use cases:**
|
|
448
|
+
- Importing from multiple GTFS sources where some may have data quality issues
|
|
449
|
+
- Processing large datasets where minor errors shouldn't halt the entire import
|
|
450
|
+
- Development/testing scenarios where you want to see all errors at once
|
|
451
|
+
|
|
452
|
+
**⚠️ Important considerations:**
|
|
453
|
+
- Errors are logged but not thrown, so you may miss critical data issues
|
|
454
|
+
- Partial imports may result in incomplete or inconsistent data
|
|
455
|
+
- Consider using the `exclude` config option to skip problematic files entirely instead of ignoring errors
|
|
435
456
|
|
|
436
457
|
```json
|
|
437
458
|
{
|
|
@@ -951,8 +972,8 @@ const stoptimes = getStoptimes({
|
|
|
951
972
|
});
|
|
952
973
|
|
|
953
974
|
/*
|
|
954
|
-
* `getStoptimes` allows passing a `date` in the query to return
|
|
955
|
-
*
|
|
975
|
+
* `getStoptimes` allows passing a `date` in the query to return only
|
|
976
|
+
* stoptimes for a specific service date.
|
|
956
977
|
*/
|
|
957
978
|
const stoptimes = getStoptimes({
|
|
958
979
|
stop_id: '70011',
|
|
@@ -963,7 +984,7 @@ const stoptimes = getStoptimes({
|
|
|
963
984
|
* `getStoptimes` allows passing a `start_time` and/or and
|
|
964
985
|
* `end_time` in the query to return only stoptimes after
|
|
965
986
|
* start_time and before end_time. This can be combined with the
|
|
966
|
-
* `date` parameter to get upcoming stoptimes
|
|
987
|
+
* `date` parameter to get upcoming stoptimes.
|
|
967
988
|
*/
|
|
968
989
|
const stoptimes = getStoptimes({
|
|
969
990
|
stop_id: '70011',
|
|
@@ -971,6 +992,32 @@ const stoptimes = getStoptimes({
|
|
|
971
992
|
start_time: '11:30:00',
|
|
972
993
|
end_time: '11:45:00'
|
|
973
994
|
});
|
|
995
|
+
|
|
996
|
+
/*
|
|
997
|
+
* ⚠️ By default, when using the `date` parameter in a query, it will NOT
|
|
998
|
+
* include stoptimes for trips whose service date is the previous day but
|
|
999
|
+
* whose stoptimes occur after midnight (i.e., times greater than 24:00:00
|
|
1000
|
+
* in GTFS, such as 25:15:00 for 1:15 AM the next day).
|
|
1001
|
+
*
|
|
1002
|
+
* To retrieve all stoptimes for a calendar date including those from
|
|
1003
|
+
* trips assigned to the previous service date but occurring after
|
|
1004
|
+
* midnight:
|
|
1005
|
+
* 1. Call `getStoptimes` with the target date:
|
|
1006
|
+
* 2. Call `getStoptimes` with the previous date and `start_time: '24:00:00'`:
|
|
1007
|
+
* 3. Combine both results for a complete set of stoptimes for July 5th.
|
|
1008
|
+
*
|
|
1009
|
+
* This approach ensures you include:
|
|
1010
|
+
* - All stoptimes for trips whose service date is July 4th but whose
|
|
1011
|
+
* stoptimes occur after midnight (i.e., in the early hours of July 5th)
|
|
1012
|
+
* - All stoptimes for trips whose service date is July 5th (which can
|
|
1013
|
+
* include trips with stoptimes that occur on July 6th after midnight )
|
|
1014
|
+
*/
|
|
1015
|
+
const stoptimesToday = getStoptimes({ date: 20240705 });
|
|
1016
|
+
const stoptimesYesterdayAfterMidnight = getStoptimes({ date: 20240704, start_time: '24:00:00' })
|
|
1017
|
+
const mergedStoptimes = [
|
|
1018
|
+
...stoptimesToday,
|
|
1019
|
+
...stoptimesYesterdayAfterMidnight
|
|
1020
|
+
];
|
|
974
1021
|
```
|
|
975
1022
|
|
|
976
1023
|
#### getTrips(query, fields, sortBy, options)
|
|
@@ -1001,6 +1048,15 @@ const trips = getTrips({
|
|
|
1001
1048
|
direction_id: 0,
|
|
1002
1049
|
service_id: '
|
|
1003
1050
|
});
|
|
1051
|
+
|
|
1052
|
+
/*
|
|
1053
|
+
* `getTrips` allows passing a `date` in the query to return only trips
|
|
1054
|
+
* for a specific service date.
|
|
1055
|
+
*/
|
|
1056
|
+
const trips = getTrips({
|
|
1057
|
+
route_id: 'Bu-16APR',
|
|
1058
|
+
date: 20170416
|
|
1059
|
+
});
|
|
1004
1060
|
```
|
|
1005
1061
|
|
|
1006
1062
|
#### getShapes(query, fields, sortBy, options)
|
package/dist/bin/gtfs-export.js
CHANGED
|
@@ -13,10 +13,10 @@ import PrettyError from "pretty-error";
|
|
|
13
13
|
// src/lib/file-utils.ts
|
|
14
14
|
import path from "path";
|
|
15
15
|
import { existsSync } from "fs";
|
|
16
|
+
import { homedir } from "os";
|
|
16
17
|
import { mkdir, readFile, rm } from "fs/promises";
|
|
17
18
|
import { omit, snakeCase } from "lodash-es";
|
|
18
19
|
import sanitize from "sanitize-filename";
|
|
19
|
-
import untildify from "untildify";
|
|
20
20
|
import StreamZip from "node-stream-zip";
|
|
21
21
|
|
|
22
22
|
// src/lib/log-utils.ts
|
|
@@ -60,6 +60,7 @@ function formatError(error) {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// src/lib/file-utils.ts
|
|
63
|
+
var homeDirectory = homedir();
|
|
63
64
|
async function getConfig(argv2) {
|
|
64
65
|
let config;
|
|
65
66
|
let data;
|
|
@@ -106,17 +107,17 @@ function generateFolderName(folderName) {
|
|
|
106
107
|
}
|
|
107
108
|
return snakeCase(sanitize(folderName));
|
|
108
109
|
}
|
|
110
|
+
function untildify(pathWithTilde) {
|
|
111
|
+
return homeDirectory ? pathWithTilde.replace(/^~(?=$|\/|\\)/, homeDirectory) : pathWithTilde;
|
|
112
|
+
}
|
|
109
113
|
|
|
110
114
|
// src/lib/import-gtfs.ts
|
|
111
115
|
import path2 from "path";
|
|
112
116
|
import { createReadStream, existsSync as existsSync2, lstatSync } from "fs";
|
|
113
117
|
import { cp, readdir, rename, readFile as readFile2, rm as rm2, writeFile } from "fs/promises";
|
|
114
118
|
import { parse } from "csv-parse";
|
|
115
|
-
import pluralize2 from "pluralize";
|
|
116
119
|
import stripBomStream from "strip-bom-stream";
|
|
117
120
|
import { temporaryDirectory } from "tempy";
|
|
118
|
-
import Timer from "timer-machine";
|
|
119
|
-
import untildify3 from "untildify";
|
|
120
121
|
import mapSeries2 from "promise-map-series";
|
|
121
122
|
|
|
122
123
|
// src/models/models.ts
|
|
@@ -4078,10 +4079,9 @@ var vehicles = {
|
|
|
4078
4079
|
|
|
4079
4080
|
// src/lib/db.ts
|
|
4080
4081
|
import Database from "better-sqlite3";
|
|
4081
|
-
import untildify2 from "untildify";
|
|
4082
4082
|
var dbs = {};
|
|
4083
4083
|
function setupDb(sqlitePath) {
|
|
4084
|
-
const db = new Database(
|
|
4084
|
+
const db = new Database(untildify(sqlitePath));
|
|
4085
4085
|
db.pragma("journal_mode = OFF");
|
|
4086
4086
|
db.pragma("synchronous = OFF");
|
|
4087
4087
|
db.pragma("temp_store = MEMORY");
|
|
@@ -4128,7 +4128,6 @@ import {
|
|
|
4128
4128
|
import { feature, featureCollection } from "@turf/helpers";
|
|
4129
4129
|
|
|
4130
4130
|
// src/lib/import-gtfs-realtime.ts
|
|
4131
|
-
import pluralize from "pluralize";
|
|
4132
4131
|
import GtfsRealtimeBindings from "gtfs-realtime-bindings";
|
|
4133
4132
|
import mapSeries from "promise-map-series";
|
|
4134
4133
|
import { get } from "lodash-es";
|
|
@@ -4158,16 +4157,17 @@ function formatCurrency(value, currency) {
|
|
|
4158
4157
|
const fractionPart = parts.find((part) => part.type === "fraction")?.value ?? "";
|
|
4159
4158
|
return `${integerPart}${fractionPart !== "" ? `.${fractionPart}` : ""}`;
|
|
4160
4159
|
}
|
|
4160
|
+
function pluralize(singularWord, pluralWord, count) {
|
|
4161
|
+
return count === 1 ? singularWord : pluralWord;
|
|
4162
|
+
}
|
|
4161
4163
|
|
|
4162
4164
|
// src/lib/export.ts
|
|
4163
4165
|
import path3 from "path";
|
|
4164
4166
|
import { writeFile as writeFile2 } from "fs/promises";
|
|
4165
4167
|
import { without, compact as compact2 } from "lodash-es";
|
|
4166
|
-
import pluralize3 from "pluralize";
|
|
4167
4168
|
import { stringify } from "csv-stringify";
|
|
4168
4169
|
import sqlString2 from "sqlstring-sqlite";
|
|
4169
4170
|
import mapSeries3 from "promise-map-series";
|
|
4170
|
-
import untildify4 from "untildify";
|
|
4171
4171
|
var getAgencies = (db, config) => {
|
|
4172
4172
|
try {
|
|
4173
4173
|
return db.prepare("SELECT agency_name FROM agency;").all();
|
|
@@ -4197,15 +4197,15 @@ var exportGtfs = async (initialConfig) => {
|
|
|
4197
4197
|
);
|
|
4198
4198
|
}
|
|
4199
4199
|
log(config)(
|
|
4200
|
-
`Starting GTFS export for ${
|
|
4200
|
+
`Starting GTFS export for ${pluralize(
|
|
4201
4201
|
"agency",
|
|
4202
|
-
|
|
4203
|
-
|
|
4202
|
+
"agencies",
|
|
4203
|
+
agencyCount
|
|
4204
4204
|
)} using SQLite database at ${config.sqlitePath}`
|
|
4205
4205
|
);
|
|
4206
4206
|
const folderName = generateFolderName(agencies[0].agency_name);
|
|
4207
4207
|
const defaultExportPath = path3.join(process.cwd(), "gtfs-export", folderName);
|
|
4208
|
-
const exportPath =
|
|
4208
|
+
const exportPath = untildify(config.exportPath || defaultExportPath);
|
|
4209
4209
|
await prepDirectory(exportPath);
|
|
4210
4210
|
const modelsToExport = Object.values(models_exports).filter(
|
|
4211
4211
|
(model) => model.extension !== "gtfs-realtime"
|
|
@@ -4273,7 +4273,7 @@ var exportGtfs = async (initialConfig) => {
|
|
|
4273
4273
|
}
|
|
4274
4274
|
log(config)(`Completed GTFS export to ${exportPath}`);
|
|
4275
4275
|
log(config)(
|
|
4276
|
-
`Completed GTFS export for ${
|
|
4276
|
+
`Completed GTFS export for ${pluralize("agency", "agencies", agencyCount)}
|
|
4277
4277
|
`
|
|
4278
4278
|
);
|
|
4279
4279
|
};
|
|
@@ -4295,6 +4295,10 @@ import { omit as omit5, orderBy, pick as pick3 } from "lodash-es";
|
|
|
4295
4295
|
import { omit as omit6 } from "lodash-es";
|
|
4296
4296
|
import sqlString4 from "sqlstring-sqlite";
|
|
4297
4297
|
|
|
4298
|
+
// src/lib/gtfs/trips.ts
|
|
4299
|
+
import { omit as omit7 } from "lodash-es";
|
|
4300
|
+
import sqlString5 from "sqlstring-sqlite";
|
|
4301
|
+
|
|
4298
4302
|
// src/bin/gtfs-export.ts
|
|
4299
4303
|
var pe = new PrettyError();
|
|
4300
4304
|
var argv = yargs(hideBin(process.argv)).usage("Usage: $0 --configPath ./config.json").help().option("c", {
|