gtfs 4.13.4 → 4.14.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/index.js CHANGED
@@ -634,11 +634,6 @@ var fareTransferRules = {
634
634
  min: -1,
635
635
  primary: true
636
636
  },
637
- {
638
- name: "transfer_id",
639
- type: "text",
640
- prefix: true
641
- },
642
637
  {
643
638
  name: "duration_limit",
644
639
  type: "integer",
@@ -3192,6 +3187,7 @@ function generateFolderName(folderName) {
3192
3187
  // src/lib/geojson-utils.ts
3193
3188
  import {
3194
3189
  cloneDeep,
3190
+ compact,
3195
3191
  filter,
3196
3192
  groupBy,
3197
3193
  last,
@@ -3220,14 +3216,14 @@ function isValidLineString(lineString) {
3220
3216
  }
3221
3217
  return true;
3222
3218
  }
3223
- function consolidateShapes(shapes2) {
3219
+ function consolidateShapes(shapeGroups) {
3224
3220
  const keys = /* @__PURE__ */ new Set();
3225
- const segmentsArray = shapes2.map(
3226
- (shape) => shape.reduce(
3221
+ const segmentsArray = shapeGroups.map(
3222
+ (shapes2) => shapes2.reduce(
3227
3223
  (memo, point, idx) => {
3228
3224
  if (idx > 0) {
3229
3225
  memo.push([
3230
- [shape[idx - 1].shape_pt_lon, shape[idx - 1].shape_pt_lat],
3226
+ [shapes2[idx - 1].shape_pt_lon, shapes2[idx - 1].shape_pt_lat],
3231
3227
  [point.shape_pt_lon, point.shape_pt_lat]
3232
3228
  ]);
3233
3229
  }
@@ -3296,15 +3292,18 @@ function shapesToGeoJSONFeature(shapes2, properties = {}) {
3296
3292
  );
3297
3293
  }
3298
3294
  function stopsToGeoJSONFeatureCollection(stops2) {
3299
- const features = stops2.map(
3300
- (stop) => feature(
3295
+ const features = compact(stops2.map((stop) => {
3296
+ if (!stop.stop_lon || !stop.stop_lat) {
3297
+ return;
3298
+ }
3299
+ return feature(
3301
3300
  {
3302
3301
  type: "Point",
3303
3302
  coordinates: [stop.stop_lon, stop.stop_lat]
3304
3303
  },
3305
3304
  formatProperties(omit2(stop, ["stop_lat", "stop_lon"]))
3306
- )
3307
- );
3305
+ );
3306
+ }));
3308
3307
  return featureCollection(features);
3309
3308
  }
3310
3309
 
@@ -3480,31 +3479,34 @@ function formatOrderByClause(orderBy2) {
3480
3479
 
3481
3480
  // src/lib/import.ts
3482
3481
  var downloadFiles = async (task) => {
3483
- task.log(`Downloading GTFS from ${task.agency_url}`);
3482
+ task.log(`Downloading GTFS from ${task.url}`);
3484
3483
  task.path = `${task.downloadDir}/gtfs.zip`;
3485
- const response = await fetch(task.agency_url, {
3484
+ const response = await fetch(task.url, {
3486
3485
  method: "GET",
3487
3486
  headers: task.headers || {},
3488
3487
  signal: task.downloadTimeout ? AbortSignal.timeout(task.downloadTimeout) : void 0
3489
3488
  });
3490
3489
  if (response.status !== 200) {
3491
- throw new Error(`Unable to download GTFS from ${task.agency_url}`);
3490
+ throw new Error(`Unable to download GTFS from ${task.url}`);
3492
3491
  }
3493
3492
  const buffer = await response.arrayBuffer();
3494
3493
  await writeFile(task.path, Buffer.from(buffer));
3495
3494
  task.log("Download successful");
3496
3495
  };
3497
- var downloadGtfsRealtimeData = async (url, task) => {
3498
- const response = await fetch(url, {
3496
+ var downloadGtfsRealtimeData = async (urlAndHeaders, task) => {
3497
+ task.log(`Downloading GTFS-Realtime from ${urlAndHeaders.url}`);
3498
+ const response = await fetch(urlAndHeaders.url, {
3499
3499
  method: "GET",
3500
3500
  headers: {
3501
- ...task.realtime_headers || {},
3501
+ ...urlAndHeaders.headers ?? {},
3502
3502
  "Accept-Encoding": "gzip"
3503
3503
  },
3504
3504
  signal: task.downloadTimeout ? AbortSignal.timeout(task.downloadTimeout) : void 0
3505
3505
  });
3506
3506
  if (response.status !== 200) {
3507
- task.logWarning(`Unable to download GTFS-Realtime from ${url}`);
3507
+ task.logWarning(
3508
+ `Unable to download GTFS-Realtime from ${urlAndHeaders.url}`
3509
+ );
3508
3510
  return null;
3509
3511
  }
3510
3512
  const buffer = await response.arrayBuffer();
@@ -3585,48 +3587,70 @@ var prepareRealtimeValue = (entity, column, task) => {
3585
3587
  );
3586
3588
  };
3587
3589
  var updateRealtimeData = async (task) => {
3588
- if (!task.realtime_urls) {
3590
+ if (task.realtimeAlerts === void 0 && task.realtimeTripUpdates === void 0 && task.realtimeVehiclePositions === void 0) {
3589
3591
  return;
3590
3592
  }
3591
3593
  const db = openDb({
3592
3594
  sqlitePath: task.sqlitePath
3593
3595
  });
3594
- task.log(
3595
- `Starting GTFS-Realtime import from ${task.realtime_urls.length} urls`
3596
- );
3597
- for (const realtimeUrl of task.realtime_urls) {
3598
- task.log(`Downloading GTFS-Realtime from ${realtimeUrl}`);
3599
- const gtfsRealtimeData = await downloadGtfsRealtimeData(realtimeUrl, task);
3600
- if (!gtfsRealtimeData?.entity) {
3601
- continue;
3602
- }
3603
- task.log(`Download successful`);
3604
- let totalLineCount = 0;
3605
- for (const entity of gtfsRealtimeData.entity) {
3606
- let model;
3607
- if (entity.vehicle) {
3608
- model = vehiclePositions;
3609
- }
3610
- if (entity.tripUpdate) {
3611
- model = tripUpdates;
3612
- }
3613
- if (entity.alert) {
3614
- model = serviceAlerts;
3615
- }
3616
- if (!model) {
3617
- break;
3618
- }
3619
- const fieldValues = model.schema.map(
3620
- (column) => prepareRealtimeValue(entity, column, task)
3621
- );
3622
- try {
3623
- db.prepare(
3624
- `REPLACE INTO ${model.filenameBase} (${model.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
3625
- ).run();
3626
- } catch (error) {
3627
- task.logWarning("Import error: " + error.message);
3596
+ if (task.realtimeAlerts?.url) {
3597
+ const gtfsRealtimeData = await downloadGtfsRealtimeData(
3598
+ task.realtimeAlerts,
3599
+ task
3600
+ );
3601
+ if (gtfsRealtimeData?.entity) {
3602
+ task.log(`Download successful`);
3603
+ let totalLineCount = 0;
3604
+ for (const entity of gtfsRealtimeData.entity) {
3605
+ const fieldValues = serviceAlerts.schema.map(
3606
+ (column) => prepareRealtimeValue(entity, column, task)
3607
+ );
3608
+ try {
3609
+ db.prepare(
3610
+ `REPLACE INTO ${serviceAlerts.filenameBase} (${serviceAlerts.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
3611
+ ).run();
3612
+ } catch (error) {
3613
+ task.logWarning("Import error: " + error.message);
3614
+ }
3615
+ const alertTargetArray = [];
3616
+ for (const informedEntity of entity.alert.informedEntity) {
3617
+ informedEntity.parent = entity;
3618
+ const subValues = serviceAlertTargets.schema.map(
3619
+ (column) => prepareRealtimeValue(informedEntity, column, task)
3620
+ );
3621
+ alertTargetArray.push(`(${subValues.join(", ")})`);
3622
+ totalLineCount++;
3623
+ }
3624
+ try {
3625
+ db.prepare(
3626
+ `REPLACE INTO ${serviceAlertTargets.filenameBase} (${serviceAlertTargets.schema.map((column) => column.name).join(", ")}) VALUES ${alertTargetArray.join(", ")}`
3627
+ ).run();
3628
+ } catch (error) {
3629
+ task.logWarning("Import error: " + error.message);
3630
+ }
3631
+ task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
3628
3632
  }
3629
- if (entity.tripUpdate) {
3633
+ }
3634
+ }
3635
+ if (task.realtimeTripUpdates?.url) {
3636
+ const gtfsRealtimeData = await downloadGtfsRealtimeData(
3637
+ task.realtimeTripUpdates,
3638
+ task
3639
+ );
3640
+ if (gtfsRealtimeData?.entity) {
3641
+ task.log(`Download successful`);
3642
+ let totalLineCount = 0;
3643
+ for (const entity of gtfsRealtimeData.entity) {
3644
+ const fieldValues = tripUpdates.schema.map(
3645
+ (column) => prepareRealtimeValue(entity, column, task)
3646
+ );
3647
+ try {
3648
+ db.prepare(
3649
+ `REPLACE INTO ${tripUpdates.filenameBase} (${tripUpdates.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
3650
+ ).run();
3651
+ } catch (error) {
3652
+ task.logWarning("Import error: " + error.message);
3653
+ }
3630
3654
  const stopTimeUpdateArray = [];
3631
3655
  for (const stopTimeUpdate of entity.tripUpdate.stopTimeUpdate) {
3632
3656
  stopTimeUpdate.parent = entity;
@@ -3643,26 +3667,31 @@ var updateRealtimeData = async (task) => {
3643
3667
  } catch (error) {
3644
3668
  task.logWarning("Import error: " + error.message);
3645
3669
  }
3670
+ task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
3646
3671
  }
3647
- if (entity.alert) {
3648
- const alertTargetArray = [];
3649
- for (const informedEntity of entity.alert.informedEntity) {
3650
- informedEntity.parent = entity;
3651
- const subValues = serviceAlertTargets.schema.map(
3652
- (column) => prepareRealtimeValue(informedEntity, column, task)
3653
- );
3654
- alertTargetArray.push(`(${subValues.join(", ")})`);
3655
- totalLineCount++;
3656
- }
3672
+ }
3673
+ }
3674
+ if (task.realtimeVehiclePositions?.url) {
3675
+ const gtfsRealtimeData = await downloadGtfsRealtimeData(
3676
+ task.realtimeVehiclePositions,
3677
+ task
3678
+ );
3679
+ if (gtfsRealtimeData?.entity) {
3680
+ task.log(`Download successful`);
3681
+ let totalLineCount = 0;
3682
+ for (const entity of gtfsRealtimeData.entity) {
3683
+ const fieldValues = tripUpdates.schema.map(
3684
+ (column) => prepareRealtimeValue(entity, column, task)
3685
+ );
3657
3686
  try {
3658
3687
  db.prepare(
3659
- `REPLACE INTO ${serviceAlertTargets.filenameBase} (${serviceAlertTargets.schema.map((column) => column.name).join(", ")}) VALUES ${alertTargetArray.join(", ")}`
3688
+ `REPLACE INTO ${tripUpdates.filenameBase} (${tripUpdates.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
3660
3689
  ).run();
3661
3690
  } catch (error) {
3662
3691
  task.logWarning("Import error: " + error.message);
3663
3692
  }
3693
+ task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
3664
3694
  }
3665
- task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
3666
3695
  }
3667
3696
  }
3668
3697
  task.log(`GTFS-Realtime data import complete`);
@@ -3974,10 +4003,11 @@ async function importGtfs(initialConfig) {
3974
4003
  const tempPath = temporaryDirectory();
3975
4004
  const task = {
3976
4005
  exclude: agency2.exclude,
3977
- agency_url: agency2.url,
4006
+ url: agency2.url,
3978
4007
  headers: agency2.headers,
3979
- realtime_headers: agency2.realtimeHeaders,
3980
- realtime_urls: agency2.realtimeUrls,
4008
+ realtimeAlerts: agency2.realtimeAlerts,
4009
+ realtimeTripUpdates: agency2.realtimeTripUpdates,
4010
+ realtimeVehiclePositions: agency2.realtimeVehiclePositions,
3981
4011
  downloadDir: tempPath,
3982
4012
  downloadTimeout: config.downloadTimeout,
3983
4013
  gtfsRealtimeExpirationSeconds: config.gtfsRealtimeExpirationSeconds,
@@ -3992,7 +4022,7 @@ async function importGtfs(initialConfig) {
3992
4022
  logError: logError2
3993
4023
  };
3994
4024
  try {
3995
- if (task.agency_url) {
4025
+ if (task.url) {
3996
4026
  await downloadFiles(task);
3997
4027
  }
3998
4028
  await readFiles(task);
@@ -4040,12 +4070,10 @@ async function updateGtfsRealtime(initialConfig) {
4040
4070
  deleteExpiredRealtimeData(config);
4041
4071
  await Promise.all(
4042
4072
  config.agencies.map(async (agency2) => {
4043
- if (agency2.realtimeUrls === void 0) {
4044
- return;
4045
- }
4046
4073
  const task = {
4047
- realtime_headers: agency2.realtimeHeaders,
4048
- realtime_urls: agency2.realtimeUrls,
4074
+ realtimeAlerts: agency2.realtimeAlerts,
4075
+ realtimeTripUpdates: agency2.realtimeTripUpdates,
4076
+ realtimeVehiclePositions: agency2.realtimeVehiclePositions,
4049
4077
  downloadTimeout: config.downloadTimeout,
4050
4078
  gtfsRealtimeExpirationSeconds: config.gtfsRealtimeExpirationSeconds,
4051
4079
  sqlitePath: config.sqlitePath,
@@ -4068,7 +4096,7 @@ async function updateGtfsRealtime(initialConfig) {
4068
4096
  } catch (error) {
4069
4097
  if (error?.code === "SQLITE_CANTOPEN") {
4070
4098
  logError2(
4071
- `Unae to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`
4099
+ `Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`
4072
4100
  );
4073
4101
  }
4074
4102
  throw error;
@@ -4078,7 +4106,7 @@ async function updateGtfsRealtime(initialConfig) {
4078
4106
  // src/lib/export.ts
4079
4107
  import path2 from "node:path";
4080
4108
  import { writeFile as writeFile2 } from "node:fs/promises";
4081
- import { without, compact } from "lodash-es";
4109
+ import { without, compact as compact2 } from "lodash-es";
4082
4110
  import pluralize2 from "pluralize";
4083
4111
  import { stringify } from "csv-stringify";
4084
4112
  import sqlString3 from "sqlstring-sqlite";
@@ -4185,7 +4213,7 @@ var exportGtfs = async (initialConfig) => {
4185
4213
  return `${model.filenameBase}.${model.filenameExtension}`;
4186
4214
  }
4187
4215
  );
4188
- if (compact(exportedFiles).length === 0) {
4216
+ if (compact2(exportedFiles).length === 0) {
4189
4217
  log2("No GTFS data exported. Be sure to first import data into SQLite.");
4190
4218
  return;
4191
4219
  }
@@ -4515,7 +4543,7 @@ function getRoutes(query = {}, fields = [], orderBy2 = [], options = {}) {
4515
4543
  }
4516
4544
 
4517
4545
  // src/lib/gtfs/shapes.ts
4518
- import { compact as compact2, omit as omit4, pick as pick2 } from "lodash-es";
4546
+ import { compact as compact3, omit as omit4, pick as pick2 } from "lodash-es";
4519
4547
  import { featureCollection as featureCollection2 } from "@turf/helpers";
4520
4548
 
4521
4549
  // src/lib/gtfs-plus/route-attributes.ts
@@ -4565,7 +4593,7 @@ function getShapesAsGeoJSON(query = {}, options = {}) {
4565
4593
  const agencies = getAgencies2({}, [], [], options);
4566
4594
  const routeQuery = pick2(query, ["route_id"]);
4567
4595
  const routes2 = getRoutes(routeQuery, [], [], options);
4568
- const features = compact2(
4596
+ const features = compact3(
4569
4597
  routes2.map((route) => {
4570
4598
  const shapeQuery = {
4571
4599
  route_id: route.route_id,
@@ -4692,14 +4720,14 @@ function getStopsAsGeoJSON(query = {}, options = {}) {
4692
4720
  const routeSubquery = "SELECT DISTINCT route_id FROM trips WHERE trip_id IN (SELECT DISTINCT trip_id FROM stop_times WHERE stop_id = ?)";
4693
4721
  const routes2 = db.prepare(`SELECT * FROM routes WHERE route_id IN (${routeSubquery})`).all(stop.stop_id);
4694
4722
  const stopAttributes2 = getStopAttributes({ stop_id: stop.stop_id });
4695
- stop.routes = orderBy(
4696
- routes2,
4697
- (route) => route?.route_short_name ? Number.parseInt(route.route_short_name, 10) : 0
4698
- );
4699
- stop.agency_name = agencies[0].agency_name;
4700
4723
  return {
4701
4724
  ...stop,
4702
- ...stopAttributes2?.[0] || []
4725
+ ...stopAttributes2?.[0] || [],
4726
+ routes: orderBy(
4727
+ routes2,
4728
+ (route) => route?.route_short_name ? Number.parseInt(route.route_short_name, 10) : 0
4729
+ ),
4730
+ agency_name: agencies[0].agency_name
4703
4731
  };
4704
4732
  });
4705
4733
  const filteredStops = preparedStops.filter((stop) => stop.routes.length > 0);