gtfs 4.17.2 → 4.17.4

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
@@ -5,9 +5,9 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // src/lib/import-gtfs.ts
8
- import path from "node:path";
9
- import { createReadStream, existsSync, lstatSync } from "node:fs";
10
- import { cp, readdir, rename, readFile as readFile2, rm as rm2, writeFile } from "node:fs/promises";
8
+ import path2 from "path";
9
+ import { createReadStream, existsSync as existsSync2, lstatSync } from "fs";
10
+ import { cp, readdir, rename, readFile as readFile2, rm as rm2, writeFile } from "fs/promises";
11
11
  import { parse } from "csv-parse";
12
12
  import pluralize2 from "pluralize";
13
13
  import stripBomStream from "strip-bom-stream";
@@ -29,12 +29,14 @@ __export(models_exports, {
29
29
  calendarDates: () => calendarDates,
30
30
  deadheadTimes: () => deadheadTimes,
31
31
  deadheads: () => deadheads,
32
+ devices: () => devices,
32
33
  directions: () => directions,
33
34
  fareAttributes: () => fareAttributes,
34
35
  fareLegRules: () => fareLegRules,
35
36
  fareMedia: () => fareMedia,
36
37
  fareProducts: () => fareProducts,
37
38
  fareRules: () => fareRules,
39
+ fareTransactions: () => fareTransactions,
38
40
  fareTransferRules: () => fareTransferRules,
39
41
  feedInfo: () => feedInfo,
40
42
  frequencies: () => frequencies,
@@ -43,7 +45,9 @@ __export(models_exports, {
43
45
  locationGroups: () => locationGroups,
44
46
  locations: () => locations,
45
47
  networks: () => networks,
48
+ operators: () => operators,
46
49
  opsLocations: () => opsLocations,
50
+ passengerEvents: () => passengerEvents,
47
51
  pathways: () => pathways,
48
52
  rideFeedInfo: () => rideFeedInfo,
49
53
  riderCategories: () => riderCategories,
@@ -57,10 +61,12 @@ __export(models_exports, {
57
61
  serviceAlertInformedEntities: () => serviceAlertInformedEntities,
58
62
  serviceAlerts: () => serviceAlerts,
59
63
  shapes: () => shapes,
64
+ stationActivities: () => stationActivities,
60
65
  stopAreas: () => stopAreas,
61
66
  stopAttributes: () => stopAttributes,
62
67
  stopTimeUpdates: () => stopTimeUpdates,
63
68
  stopTimes: () => stopTimes,
69
+ stopVisits: () => stopVisits,
64
70
  stops: () => stops,
65
71
  timeframes: () => timeframes,
66
72
  timetableNotes: () => timetableNotes,
@@ -68,13 +74,18 @@ __export(models_exports, {
68
74
  timetablePages: () => timetablePages,
69
75
  timetableStopOrder: () => timetableStopOrder,
70
76
  timetables: () => timetables,
77
+ trainCars: () => trainCars,
71
78
  transfers: () => transfers,
72
79
  translations: () => translations,
73
80
  tripCapacity: () => tripCapacity,
74
81
  tripUpdates: () => tripUpdates,
75
82
  trips: () => trips,
76
83
  tripsDatedVehicleJourney: () => tripsDatedVehicleJourney,
77
- vehiclePositions: () => vehiclePositions
84
+ tripsPerformed: () => tripsPerformed,
85
+ vehicleLocations: () => vehicleLocations,
86
+ vehiclePositions: () => vehiclePositions,
87
+ vehicleTrainCars: () => vehicleTrainCars,
88
+ vehicles: () => vehicles
78
89
  });
79
90
 
80
91
  // src/models/gtfs/agency.ts
@@ -548,6 +559,7 @@ var fareProducts = {
548
559
  {
549
560
  name: "rider_category_id",
550
561
  type: "text",
562
+ primary: true,
551
563
  prefix: true
552
564
  },
553
565
  {
@@ -3122,143 +3134,978 @@ var runsPieces = {
3122
3134
  ]
3123
3135
  };
3124
3136
 
3125
- // src/lib/db.ts
3126
- import fs from "fs";
3127
- import Database from "better-sqlite3";
3128
- import untildify from "untildify";
3129
- var dbs = {};
3130
- function setupDb(sqlitePath) {
3131
- const db = new Database(untildify(sqlitePath));
3132
- db.pragma("journal_mode = OFF");
3133
- db.pragma("synchronous = OFF");
3134
- db.pragma("temp_store = MEMORY");
3135
- dbs[sqlitePath] = db;
3136
- return db;
3137
- }
3138
- function openDb(config = null) {
3139
- if (config) {
3140
- const { sqlitePath = ":memory:", db } = config;
3141
- if (db) {
3142
- return db;
3143
- }
3144
- if (dbs[sqlitePath]) {
3145
- return dbs[sqlitePath];
3146
- }
3147
- return setupDb(sqlitePath);
3148
- }
3149
- if (Object.keys(dbs).length === 0) {
3150
- return setupDb(":memory:");
3151
- }
3152
- if (Object.keys(dbs).length === 1) {
3153
- const filename = Object.keys(dbs)[0];
3154
- return dbs[filename];
3155
- }
3156
- if (Object.keys(dbs).length > 1) {
3157
- throw new Error(
3158
- "Multiple databases open, please specify which one to use."
3159
- );
3160
- }
3161
- throw new Error("Unable to find database connection.");
3162
- }
3163
- function closeDb(db = null) {
3164
- if (Object.keys(dbs).length === 0) {
3165
- throw new Error(
3166
- "No database connection. Call `openDb(config)` before using any methods."
3167
- );
3168
- }
3169
- if (!db) {
3170
- if (Object.keys(dbs).length > 1) {
3171
- throw new Error(
3172
- "Multiple database connections. Pass the db you want to close as a parameter to `closeDb`."
3173
- );
3174
- }
3175
- db = dbs[Object.keys(dbs)[0]];
3176
- }
3177
- db.close();
3178
- delete dbs[db.name];
3179
- }
3180
- function deleteDb(db = null) {
3181
- if (Object.keys(dbs).length === 0) {
3182
- throw new Error(
3183
- "No database connection. Call `openDb(config)` before using any methods."
3184
- );
3185
- }
3186
- if (!db) {
3187
- if (Object.keys(dbs).length > 1) {
3188
- throw new Error(
3189
- "Multiple database connections. Pass the db you want to delete as a parameter to `deleteDb`."
3190
- );
3137
+ // src/models/tides/devices.ts
3138
+ var devices = {
3139
+ filenameBase: "devices",
3140
+ filenameExtension: "txt",
3141
+ nonstandard: true,
3142
+ extension: "tides",
3143
+ schema: [
3144
+ {
3145
+ name: "device_id",
3146
+ type: "text",
3147
+ required: true,
3148
+ primary: true
3149
+ },
3150
+ {
3151
+ name: "stop_id",
3152
+ type: "text"
3153
+ },
3154
+ {
3155
+ name: "vehicle_id",
3156
+ type: "text"
3157
+ },
3158
+ {
3159
+ name: "train_car_id",
3160
+ type: "text"
3161
+ },
3162
+ {
3163
+ name: "device_type",
3164
+ type: "text"
3165
+ },
3166
+ {
3167
+ name: "device_vendor",
3168
+ type: "text"
3169
+ },
3170
+ {
3171
+ name: "device_model",
3172
+ type: "text"
3173
+ },
3174
+ {
3175
+ name: "device_location",
3176
+ type: "text"
3191
3177
  }
3192
- db = dbs[Object.keys(dbs)[0]];
3193
- }
3194
- db.close();
3195
- fs.unlinkSync(db.name);
3196
- delete dbs[db.name];
3197
- }
3198
-
3199
- // src/lib/file-utils.ts
3200
- import { mkdir, readFile, rm } from "node:fs/promises";
3201
- import { omit, snakeCase } from "lodash-es";
3202
- import sanitize from "sanitize-filename";
3203
- import untildify2 from "untildify";
3204
- import StreamZip from "node-stream-zip";
3178
+ ]
3179
+ };
3205
3180
 
3206
- // src/lib/log-utils.ts
3207
- import { clearLine, cursorTo } from "node:readline";
3208
- import { noop } from "lodash-es";
3209
- import * as colors from "yoctocolors";
3210
- function log(config) {
3211
- if (config.verbose === false) {
3212
- return noop;
3213
- }
3214
- if (config.logFunction) {
3215
- return config.logFunction;
3216
- }
3217
- return (text, overwrite = false) => {
3218
- if (overwrite && process.stdout.isTTY) {
3219
- clearLine(process.stdout, 0);
3220
- cursorTo(process.stdout, 0);
3221
- } else {
3222
- process.stdout.write("\n");
3181
+ // src/models/tides/fare-transactions.ts
3182
+ var fareTransactions = {
3183
+ filenameBase: "fare_transactions",
3184
+ filenameExtension: "txt",
3185
+ nonstandard: true,
3186
+ extension: "tides",
3187
+ schema: [
3188
+ {
3189
+ name: "transaction_id",
3190
+ type: "text",
3191
+ required: true,
3192
+ index: true
3193
+ },
3194
+ {
3195
+ name: "service_date",
3196
+ type: "date",
3197
+ required: true
3198
+ },
3199
+ {
3200
+ name: "event_timestamp",
3201
+ type: "text",
3202
+ required: true
3203
+ },
3204
+ {
3205
+ name: "location_ping_id",
3206
+ type: "text"
3207
+ },
3208
+ {
3209
+ name: "amount",
3210
+ type: "real",
3211
+ required: true
3212
+ },
3213
+ {
3214
+ name: "currency_type",
3215
+ type: "text"
3216
+ },
3217
+ {
3218
+ name: "fare_action",
3219
+ type: "text",
3220
+ required: true
3221
+ },
3222
+ {
3223
+ name: "trip_id_performed",
3224
+ type: "text"
3225
+ },
3226
+ {
3227
+ name: "trip_id_scheduled",
3228
+ type: "text"
3229
+ },
3230
+ {
3231
+ name: "pattern_id",
3232
+ type: "text"
3233
+ },
3234
+ {
3235
+ name: "trip_stop_sequence",
3236
+ type: "integer",
3237
+ min: 1
3238
+ },
3239
+ {
3240
+ name: "scheduled_stop_sequence",
3241
+ type: "integer",
3242
+ min: 0
3243
+ },
3244
+ {
3245
+ name: "vehicle_id",
3246
+ type: "text"
3247
+ },
3248
+ {
3249
+ name: "device_id",
3250
+ type: "text"
3251
+ },
3252
+ {
3253
+ name: "fare_id",
3254
+ type: "text"
3255
+ },
3256
+ {
3257
+ name: "stop_id",
3258
+ type: "text"
3259
+ },
3260
+ {
3261
+ name: "num_riders",
3262
+ type: "integer",
3263
+ min: 0
3264
+ },
3265
+ {
3266
+ name: "fare_media_id",
3267
+ type: "text"
3268
+ },
3269
+ {
3270
+ name: "rider_category",
3271
+ type: "text"
3272
+ },
3273
+ {
3274
+ name: "fare_product",
3275
+ type: "text"
3276
+ },
3277
+ {
3278
+ name: "fare_period",
3279
+ type: "text"
3280
+ },
3281
+ {
3282
+ name: "fare_capped",
3283
+ type: "text",
3284
+ required: true
3285
+ },
3286
+ {
3287
+ name: "token_id",
3288
+ type: "text"
3289
+ },
3290
+ {
3291
+ name: "balance",
3292
+ type: "real"
3223
3293
  }
3224
- process.stdout.write(text);
3225
- };
3226
- }
3227
- function logWarning(config) {
3228
- if (config.logFunction) {
3229
- return config.logFunction;
3230
- }
3231
- return (text) => {
3232
- process.stdout.write(`
3233
- ${formatWarning(text)}
3234
- `);
3235
- };
3236
- }
3237
- function logError(config) {
3238
- if (config.logFunction) {
3239
- return config.logFunction;
3240
- }
3241
- return (text) => {
3242
- process.stdout.write(`
3243
- ${formatError(text)}
3244
- `);
3245
- };
3246
- }
3247
- function formatWarning(text) {
3248
- return colors.yellow(`${colors.underline("Warning")}: ${text}`);
3249
- }
3250
- function formatError(error) {
3251
- const messageText = error instanceof Error ? error.message : error;
3252
- const cleanMessage = messageText.replace(/^Error:\s*/i, "");
3253
- return colors.red(`${colors.underline("Error")}: ${cleanMessage}`);
3254
- }
3294
+ ]
3295
+ };
3255
3296
 
3256
- // src/lib/file-utils.ts
3257
- async function prepDirectory(exportPath) {
3258
- await rm(exportPath, { recursive: true, force: true });
3259
- await mkdir(exportPath, { recursive: true });
3260
- }
3261
- async function unzip(zipfilePath, exportPath) {
3297
+ // src/models/tides/operators.ts
3298
+ var operators = {
3299
+ filenameBase: "operators",
3300
+ filenameExtension: "txt",
3301
+ nonstandard: true,
3302
+ extension: "tides",
3303
+ schema: [
3304
+ {
3305
+ name: "operator_id",
3306
+ type: "text",
3307
+ required: true,
3308
+ primary: true
3309
+ }
3310
+ ]
3311
+ };
3312
+
3313
+ // src/models/tides/passenger-events.ts
3314
+ var passengerEvents = {
3315
+ filenameBase: "passenger_events",
3316
+ filenameExtension: "txt",
3317
+ nonstandard: true,
3318
+ extension: "tides",
3319
+ schema: [
3320
+ {
3321
+ name: "passenger_event_id",
3322
+ type: "text",
3323
+ required: true,
3324
+ index: true
3325
+ },
3326
+ {
3327
+ name: "service_date",
3328
+ type: "date",
3329
+ required: true
3330
+ },
3331
+ {
3332
+ name: "event_timestamp",
3333
+ type: "text",
3334
+ required: true
3335
+ },
3336
+ {
3337
+ name: "location_ping_id",
3338
+ type: "text"
3339
+ },
3340
+ {
3341
+ name: "trip_id_performed",
3342
+ type: "text"
3343
+ },
3344
+ {
3345
+ name: "trip_id_scheduled",
3346
+ type: "text"
3347
+ },
3348
+ {
3349
+ name: "trip_stop_sequence",
3350
+ type: "integer",
3351
+ min: 1
3352
+ },
3353
+ {
3354
+ name: "scheduled_stop_sequence",
3355
+ type: "integer",
3356
+ min: 0
3357
+ },
3358
+ {
3359
+ name: "event_type",
3360
+ type: "text",
3361
+ required: true
3362
+ },
3363
+ {
3364
+ name: "vehicle_id",
3365
+ type: "text",
3366
+ required: true
3367
+ },
3368
+ {
3369
+ name: "device_id",
3370
+ type: "text"
3371
+ },
3372
+ {
3373
+ name: "train_car_id",
3374
+ type: "text"
3375
+ },
3376
+ {
3377
+ name: "stop_id",
3378
+ type: "text"
3379
+ },
3380
+ {
3381
+ name: "pattern_id",
3382
+ type: "text"
3383
+ },
3384
+ {
3385
+ name: "event_count",
3386
+ type: "integer",
3387
+ min: 0
3388
+ }
3389
+ ]
3390
+ };
3391
+
3392
+ // src/models/tides/station-activities.ts
3393
+ var stationActivities = {
3394
+ filenameBase: "station_activities",
3395
+ filenameExtension: "txt",
3396
+ nonstandard: true,
3397
+ extension: "tides",
3398
+ schema: [
3399
+ {
3400
+ name: "service_date",
3401
+ type: "date",
3402
+ required: true,
3403
+ primary: true
3404
+ },
3405
+ {
3406
+ name: "stop_id",
3407
+ type: "text",
3408
+ required: true,
3409
+ primary: true
3410
+ },
3411
+ {
3412
+ name: "time_period_start",
3413
+ type: "text",
3414
+ required: true,
3415
+ primary: true
3416
+ },
3417
+ {
3418
+ name: "time_period_end",
3419
+ type: "text",
3420
+ required: true,
3421
+ primary: true
3422
+ },
3423
+ {
3424
+ name: "time_period_category",
3425
+ type: "text"
3426
+ },
3427
+ {
3428
+ name: "total_entries",
3429
+ type: "integer",
3430
+ min: 0
3431
+ },
3432
+ {
3433
+ name: "total_exits",
3434
+ type: "integer",
3435
+ min: 0
3436
+ },
3437
+ {
3438
+ name: "number_of_transactions",
3439
+ type: "integer",
3440
+ min: 0
3441
+ },
3442
+ {
3443
+ name: "bike_entries",
3444
+ type: "integer",
3445
+ min: 0
3446
+ },
3447
+ {
3448
+ name: "bike_exits",
3449
+ type: "integer",
3450
+ min: 0
3451
+ },
3452
+ {
3453
+ name: "ramp_entries",
3454
+ type: "integer",
3455
+ min: 0
3456
+ },
3457
+ {
3458
+ name: "ramp_exits",
3459
+ type: "integer",
3460
+ min: 0
3461
+ }
3462
+ ]
3463
+ };
3464
+
3465
+ // src/models/tides/stop-visits.ts
3466
+ var stopVisits = {
3467
+ filenameBase: "stop_visits",
3468
+ filenameExtension: "txt",
3469
+ nonstandard: true,
3470
+ extension: "tides",
3471
+ schema: [
3472
+ {
3473
+ name: "service_date",
3474
+ type: "date",
3475
+ required: true,
3476
+ primary: true
3477
+ },
3478
+ {
3479
+ name: "trip_id_performed",
3480
+ type: "text",
3481
+ required: true,
3482
+ primary: true
3483
+ },
3484
+ {
3485
+ name: "trip_stop_sequence",
3486
+ type: "integer",
3487
+ min: 1,
3488
+ required: true,
3489
+ primary: true
3490
+ },
3491
+ {
3492
+ name: "scheduled_stop_sequence",
3493
+ type: "integer",
3494
+ min: 0
3495
+ },
3496
+ {
3497
+ name: "pattern_id",
3498
+ type: "text"
3499
+ },
3500
+ {
3501
+ name: "vehicle_id",
3502
+ type: "text"
3503
+ },
3504
+ {
3505
+ name: "dwell",
3506
+ type: "integer",
3507
+ min: 0
3508
+ },
3509
+ {
3510
+ name: "stop_id",
3511
+ type: "text"
3512
+ },
3513
+ {
3514
+ name: "timepoint",
3515
+ type: "text"
3516
+ },
3517
+ {
3518
+ name: "schedule_arrival_time",
3519
+ type: "text"
3520
+ },
3521
+ {
3522
+ name: "schedule_departure_time",
3523
+ type: "text"
3524
+ },
3525
+ {
3526
+ name: "actual_arrival_time",
3527
+ type: "text"
3528
+ },
3529
+ {
3530
+ name: "actual_departure_time",
3531
+ type: "text"
3532
+ },
3533
+ {
3534
+ name: "distance",
3535
+ type: "integer",
3536
+ min: 0
3537
+ },
3538
+ {
3539
+ name: "boarding_1",
3540
+ type: "integer",
3541
+ min: 0
3542
+ },
3543
+ {
3544
+ name: "alighting_1",
3545
+ type: "integer",
3546
+ min: 0
3547
+ },
3548
+ {
3549
+ name: "boarding_2",
3550
+ type: "integer",
3551
+ min: 0
3552
+ },
3553
+ {
3554
+ name: "alighting_2",
3555
+ type: "integer",
3556
+ min: 0
3557
+ },
3558
+ {
3559
+ name: "departure_load",
3560
+ type: "integer",
3561
+ min: 0
3562
+ },
3563
+ {
3564
+ name: "door_open",
3565
+ type: "text"
3566
+ },
3567
+ {
3568
+ name: "door_close",
3569
+ type: "text"
3570
+ },
3571
+ {
3572
+ name: "door_status",
3573
+ type: "text"
3574
+ },
3575
+ {
3576
+ name: "ramp_deployed_time",
3577
+ type: "text"
3578
+ },
3579
+ {
3580
+ name: "ramp_failure",
3581
+ type: "text"
3582
+ },
3583
+ {
3584
+ name: "kneel_deployed_time",
3585
+ type: "integer",
3586
+ min: 0
3587
+ },
3588
+ {
3589
+ name: "lift_deployed_time",
3590
+ type: "integer",
3591
+ min: 0
3592
+ },
3593
+ {
3594
+ name: "bike_rack_deployed",
3595
+ type: "text"
3596
+ },
3597
+ {
3598
+ name: "bike_load",
3599
+ type: "integer",
3600
+ min: 0
3601
+ },
3602
+ {
3603
+ name: "revenue",
3604
+ type: "real"
3605
+ },
3606
+ {
3607
+ name: "number_of_transactions",
3608
+ type: "integer",
3609
+ min: 0
3610
+ },
3611
+ {
3612
+ name: "schedule_relationship",
3613
+ type: "text"
3614
+ }
3615
+ ]
3616
+ };
3617
+
3618
+ // src/models/tides/train-cars.ts
3619
+ var trainCars = {
3620
+ filenameBase: "train_cars",
3621
+ filenameExtension: "txt",
3622
+ nonstandard: true,
3623
+ extension: "tides",
3624
+ schema: [
3625
+ {
3626
+ name: "train_car_id",
3627
+ type: "text",
3628
+ required: true,
3629
+ primary: true
3630
+ },
3631
+ {
3632
+ name: "model_name",
3633
+ type: "text"
3634
+ },
3635
+ {
3636
+ name: "facility_name",
3637
+ type: "text"
3638
+ },
3639
+ {
3640
+ name: "capacity_seated",
3641
+ type: "integer",
3642
+ min: 0
3643
+ },
3644
+ {
3645
+ name: "capacity_wheelchair",
3646
+ type: "integer",
3647
+ min: 0
3648
+ },
3649
+ {
3650
+ name: "capacity_bike",
3651
+ type: "integer",
3652
+ min: 0
3653
+ },
3654
+ {
3655
+ name: "bike_rack",
3656
+ type: "text"
3657
+ },
3658
+ {
3659
+ name: "capacity_standing",
3660
+ type: "integer",
3661
+ min: 0
3662
+ },
3663
+ {
3664
+ name: "train_car_type",
3665
+ type: "text"
3666
+ }
3667
+ ]
3668
+ };
3669
+
3670
+ // src/models/tides/trips-performed.ts
3671
+ var tripsPerformed = {
3672
+ filenameBase: "trips_performed",
3673
+ filenameExtension: "txt",
3674
+ nonstandard: true,
3675
+ extension: "tides",
3676
+ schema: [
3677
+ {
3678
+ name: "service_date",
3679
+ type: "date",
3680
+ required: true,
3681
+ primary: true
3682
+ },
3683
+ {
3684
+ name: "trip_id_performed",
3685
+ type: "text",
3686
+ required: true,
3687
+ primary: true
3688
+ },
3689
+ {
3690
+ name: "vehicle_id",
3691
+ type: "text",
3692
+ required: true
3693
+ },
3694
+ {
3695
+ name: "trip_id_scheduled",
3696
+ type: "text"
3697
+ },
3698
+ {
3699
+ name: "route_id",
3700
+ type: "text"
3701
+ },
3702
+ {
3703
+ name: "route_type",
3704
+ type: "text"
3705
+ },
3706
+ {
3707
+ name: "ntd_mode",
3708
+ type: "text"
3709
+ },
3710
+ {
3711
+ name: "route_type_agency",
3712
+ type: "text"
3713
+ },
3714
+ {
3715
+ name: "shape_id",
3716
+ type: "text"
3717
+ },
3718
+ {
3719
+ name: "pattern_id",
3720
+ type: "text"
3721
+ },
3722
+ {
3723
+ name: "direction_id",
3724
+ type: "integer",
3725
+ min: 0,
3726
+ max: 1
3727
+ },
3728
+ {
3729
+ name: "operator_id",
3730
+ type: "text"
3731
+ },
3732
+ {
3733
+ name: "block_id",
3734
+ type: "text"
3735
+ },
3736
+ {
3737
+ name: "trip_start_stop_id",
3738
+ type: "text"
3739
+ },
3740
+ {
3741
+ name: "trip_end_stop_id",
3742
+ type: "text"
3743
+ },
3744
+ {
3745
+ name: "schedule_trip_start",
3746
+ type: "text"
3747
+ },
3748
+ {
3749
+ name: "schedule_trip_end",
3750
+ type: "text"
3751
+ },
3752
+ {
3753
+ name: "actual_trip_start",
3754
+ type: "text"
3755
+ },
3756
+ {
3757
+ name: "actual_trip_end",
3758
+ type: "text"
3759
+ },
3760
+ {
3761
+ name: "trip_type",
3762
+ type: "text"
3763
+ },
3764
+ {
3765
+ name: "schedule_relationship",
3766
+ type: "text"
3767
+ }
3768
+ ]
3769
+ };
3770
+
3771
+ // src/models/tides/vehicle-train-cars.ts
3772
+ var vehicleTrainCars = {
3773
+ filenameBase: "vehicle_train_cars",
3774
+ filenameExtension: "txt",
3775
+ nonstandard: true,
3776
+ extension: "tides",
3777
+ schema: [
3778
+ {
3779
+ name: "vehicle_id",
3780
+ type: "text",
3781
+ required: true,
3782
+ primary: true
3783
+ },
3784
+ {
3785
+ name: "train_car_id",
3786
+ type: "text",
3787
+ required: true,
3788
+ primary: true
3789
+ },
3790
+ {
3791
+ name: "train_car_order",
3792
+ type: "integer",
3793
+ min: 0
3794
+ },
3795
+ {
3796
+ name: "operator_id",
3797
+ type: "text"
3798
+ }
3799
+ ]
3800
+ };
3801
+
3802
+ // src/models/tides/vehicle-locations.ts
3803
+ var vehicleLocations = {
3804
+ filenameBase: "vehicle_locations",
3805
+ filenameExtension: "txt",
3806
+ nonstandard: true,
3807
+ extension: "tides",
3808
+ schema: [
3809
+ {
3810
+ name: "location_ping_id",
3811
+ type: "text",
3812
+ required: true,
3813
+ primary: true
3814
+ },
3815
+ {
3816
+ name: "service_date",
3817
+ type: "date"
3818
+ },
3819
+ {
3820
+ name: "event_timestamp",
3821
+ type: "text",
3822
+ required: true
3823
+ },
3824
+ {
3825
+ name: "trip_id_performed",
3826
+ type: "text"
3827
+ },
3828
+ {
3829
+ name: "trip_id_scheduled",
3830
+ type: "text"
3831
+ },
3832
+ {
3833
+ name: "trip_stop_sequence",
3834
+ type: "integer",
3835
+ min: 1
3836
+ },
3837
+ {
3838
+ name: "scheduled_stop_sequence",
3839
+ type: "integer",
3840
+ min: 0
3841
+ },
3842
+ {
3843
+ name: "vehicle_id",
3844
+ type: "text",
3845
+ required: true
3846
+ },
3847
+ {
3848
+ name: "device_id",
3849
+ type: "text"
3850
+ },
3851
+ {
3852
+ name: "pattern_id",
3853
+ type: "text"
3854
+ },
3855
+ {
3856
+ name: "stop_id",
3857
+ type: "text"
3858
+ },
3859
+ {
3860
+ name: "current_status",
3861
+ type: "text"
3862
+ },
3863
+ {
3864
+ name: "latitude",
3865
+ type: "real",
3866
+ min: -90,
3867
+ max: 90
3868
+ },
3869
+ {
3870
+ name: "longitude",
3871
+ type: "real",
3872
+ min: -180,
3873
+ max: 180
3874
+ },
3875
+ {
3876
+ name: "gps_quality",
3877
+ type: "text"
3878
+ },
3879
+ {
3880
+ name: "heading",
3881
+ type: "real",
3882
+ min: 0,
3883
+ max: 360
3884
+ },
3885
+ {
3886
+ name: "speed",
3887
+ type: "real",
3888
+ min: 0
3889
+ },
3890
+ {
3891
+ name: "odometer",
3892
+ type: "real",
3893
+ min: 0
3894
+ },
3895
+ {
3896
+ name: "schedule_deviation",
3897
+ type: "integer"
3898
+ },
3899
+ {
3900
+ name: "headway_deviation",
3901
+ type: "integer"
3902
+ },
3903
+ {
3904
+ name: "trip_type",
3905
+ type: "text"
3906
+ },
3907
+ {
3908
+ name: "schedule_relationship",
3909
+ type: "text"
3910
+ }
3911
+ ]
3912
+ };
3913
+
3914
+ // src/models/tides/vehicles.ts
3915
+ var vehicles = {
3916
+ filenameBase: "vehicles",
3917
+ filenameExtension: "txt",
3918
+ nonstandard: true,
3919
+ extension: "tides",
3920
+ schema: [
3921
+ {
3922
+ name: "vehicle_id",
3923
+ type: "text",
3924
+ required: true,
3925
+ primary: true
3926
+ },
3927
+ {
3928
+ name: "vehicle_start",
3929
+ type: "text"
3930
+ },
3931
+ {
3932
+ name: "vehicle_end",
3933
+ type: "text"
3934
+ },
3935
+ {
3936
+ name: "model_name",
3937
+ type: "text"
3938
+ },
3939
+ {
3940
+ name: "facility_name",
3941
+ type: "text"
3942
+ },
3943
+ {
3944
+ name: "capacity_seated",
3945
+ type: "integer",
3946
+ min: 0
3947
+ },
3948
+ {
3949
+ name: "capacity_wheelchair",
3950
+ type: "integer",
3951
+ min: 0
3952
+ },
3953
+ {
3954
+ name: "capacity_bike",
3955
+ type: "integer",
3956
+ min: 0
3957
+ },
3958
+ {
3959
+ name: "bike_rack",
3960
+ type: "text"
3961
+ },
3962
+ {
3963
+ name: "capacity_standing",
3964
+ type: "integer",
3965
+ min: 0
3966
+ }
3967
+ ]
3968
+ };
3969
+
3970
+ // src/lib/db.ts
3971
+ import fs from "fs";
3972
+ import Database from "better-sqlite3";
3973
+ import untildify from "untildify";
3974
+ var dbs = {};
3975
+ function setupDb(sqlitePath) {
3976
+ const db = new Database(untildify(sqlitePath));
3977
+ db.pragma("journal_mode = OFF");
3978
+ db.pragma("synchronous = OFF");
3979
+ db.pragma("temp_store = MEMORY");
3980
+ dbs[sqlitePath] = db;
3981
+ return db;
3982
+ }
3983
+ function openDb(config = null) {
3984
+ if (config) {
3985
+ const { sqlitePath = ":memory:", db } = config;
3986
+ if (db) {
3987
+ return db;
3988
+ }
3989
+ if (dbs[sqlitePath]) {
3990
+ return dbs[sqlitePath];
3991
+ }
3992
+ return setupDb(sqlitePath);
3993
+ }
3994
+ if (Object.keys(dbs).length === 0) {
3995
+ return setupDb(":memory:");
3996
+ }
3997
+ if (Object.keys(dbs).length === 1) {
3998
+ const filename = Object.keys(dbs)[0];
3999
+ return dbs[filename];
4000
+ }
4001
+ if (Object.keys(dbs).length > 1) {
4002
+ throw new Error(
4003
+ "Multiple databases open, please specify which one to use."
4004
+ );
4005
+ }
4006
+ throw new Error("Unable to find database connection.");
4007
+ }
4008
+ function closeDb(db = null) {
4009
+ if (Object.keys(dbs).length === 0) {
4010
+ throw new Error(
4011
+ "No database connection. Call `openDb(config)` before using any methods."
4012
+ );
4013
+ }
4014
+ if (!db) {
4015
+ if (Object.keys(dbs).length > 1) {
4016
+ throw new Error(
4017
+ "Multiple database connections. Pass the db you want to close as a parameter to `closeDb`."
4018
+ );
4019
+ }
4020
+ db = dbs[Object.keys(dbs)[0]];
4021
+ }
4022
+ db.close();
4023
+ delete dbs[db.name];
4024
+ }
4025
+ function deleteDb(db = null) {
4026
+ if (Object.keys(dbs).length === 0) {
4027
+ throw new Error(
4028
+ "No database connection. Call `openDb(config)` before using any methods."
4029
+ );
4030
+ }
4031
+ if (!db) {
4032
+ if (Object.keys(dbs).length > 1) {
4033
+ throw new Error(
4034
+ "Multiple database connections. Pass the db you want to delete as a parameter to `deleteDb`."
4035
+ );
4036
+ }
4037
+ db = dbs[Object.keys(dbs)[0]];
4038
+ }
4039
+ db.close();
4040
+ fs.unlinkSync(db.name);
4041
+ delete dbs[db.name];
4042
+ }
4043
+
4044
+ // src/lib/file-utils.ts
4045
+ import path from "path";
4046
+ import { existsSync } from "fs";
4047
+ import { mkdir, readFile, rm } from "fs/promises";
4048
+ import { omit, snakeCase } from "lodash-es";
4049
+ import sanitize from "sanitize-filename";
4050
+ import untildify2 from "untildify";
4051
+ import StreamZip from "node-stream-zip";
4052
+
4053
+ // src/lib/log-utils.ts
4054
+ import { clearLine, cursorTo } from "readline";
4055
+ import { noop } from "lodash-es";
4056
+ import * as colors from "yoctocolors";
4057
+ function log(config) {
4058
+ if (config.verbose === false) {
4059
+ return noop;
4060
+ }
4061
+ if (config.logFunction) {
4062
+ return config.logFunction;
4063
+ }
4064
+ return (text, overwrite = false) => {
4065
+ if (overwrite && process.stdout.isTTY) {
4066
+ clearLine(process.stdout, 0);
4067
+ cursorTo(process.stdout, 0);
4068
+ } else {
4069
+ process.stdout.write("\n");
4070
+ }
4071
+ process.stdout.write(text);
4072
+ };
4073
+ }
4074
+ function logWarning(config) {
4075
+ if (config.logFunction) {
4076
+ return config.logFunction;
4077
+ }
4078
+ return (text) => {
4079
+ process.stdout.write(`
4080
+ ${formatWarning(text)}
4081
+ `);
4082
+ };
4083
+ }
4084
+ function logError(config) {
4085
+ if (config.logFunction) {
4086
+ return config.logFunction;
4087
+ }
4088
+ return (text) => {
4089
+ process.stdout.write(`
4090
+ ${formatError(text)}
4091
+ `);
4092
+ };
4093
+ }
4094
+ function formatWarning(text) {
4095
+ return colors.yellow(`${colors.underline("Warning")}: ${text}`);
4096
+ }
4097
+ function formatError(error) {
4098
+ const messageText = error instanceof Error ? error.message : error;
4099
+ const cleanMessage = messageText.replace(/^Error:\s*/i, "");
4100
+ return colors.red(`${colors.underline("Error")}: ${cleanMessage}`);
4101
+ }
4102
+
4103
+ // src/lib/file-utils.ts
4104
+ async function prepDirectory(exportPath) {
4105
+ await rm(exportPath, { recursive: true, force: true });
4106
+ await mkdir(exportPath, { recursive: true });
4107
+ }
4108
+ async function unzip(zipfilePath, exportPath) {
3262
4109
  try {
3263
4110
  const zip = new StreamZip.async({ file: zipfilePath });
3264
4111
  await zip.extract(null, exportPath);
@@ -3850,18 +4697,6 @@ async function updateGtfsRealtime(initialConfig) {
3850
4697
  }
3851
4698
 
3852
4699
  // src/lib/import-gtfs.ts
3853
- var timeCache = {};
3854
- var formatAndCacheTime = (value) => {
3855
- const cached = timeCache[value];
3856
- if (cached !== void 0) {
3857
- return cached;
3858
- }
3859
- const timeAsSecondsFromMidnight = calculateSecondsFromMidnight(value);
3860
- const timeAsString = padLeadingZeros(value);
3861
- const computed = [timeAsSecondsFromMidnight, timeAsString];
3862
- timeCache[value] = computed;
3863
- return computed;
3864
- };
3865
4700
  var getTextFiles = async (folderPath) => {
3866
4701
  const files = await readdir(folderPath);
3867
4702
  return files.filter((filename) => filename.slice(-3) === "txt");
@@ -3892,13 +4727,13 @@ var extractGtfsFiles = async (task) => {
3892
4727
  }
3893
4728
  const gtfsPath = untildify3(task.path);
3894
4729
  task.log(`Importing GTFS from ${task.path}\r`);
3895
- if (path.extname(gtfsPath) === ".zip") {
4730
+ if (path2.extname(gtfsPath) === ".zip") {
3896
4731
  try {
3897
4732
  await unzip(gtfsPath, task.downloadDir);
3898
4733
  const textFiles = await getTextFiles(task.downloadDir);
3899
4734
  if (textFiles.length === 0) {
3900
4735
  const files = await readdir(task.downloadDir);
3901
- const folders = files.filter((filename) => !["__MACOSX"].includes(filename)).map((filename) => path.join(task.downloadDir, filename)).filter((source) => lstatSync(source).isDirectory());
4736
+ const folders = files.filter((filename) => !["__MACOSX"].includes(filename)).map((filename) => path2.join(task.downloadDir, filename)).filter((source) => lstatSync(source).isDirectory());
3902
4737
  if (folders.length > 1) {
3903
4738
  throw new Error(
3904
4739
  `More than one subfolder found in zip file at \`${task.path}\`. Ensure that .txt files are in the top level of the zip file, or in a single subdirectory.`
@@ -3918,8 +4753,8 @@ var extractGtfsFiles = async (task) => {
3918
4753
  await Promise.all(
3919
4754
  directoryTextFiles.map(
3920
4755
  async (fileName) => rename(
3921
- path.join(subfolderName, fileName),
3922
- path.join(task.downloadDir, fileName)
4756
+ path2.join(subfolderName, fileName),
4757
+ path2.join(task.downloadDir, fileName)
3923
4758
  )
3924
4759
  )
3925
4760
  );
@@ -3973,7 +4808,16 @@ var createGtfsTables = (db) => {
3973
4808
  );
3974
4809
  if (column.type === "time") {
3975
4810
  sqlColumnCreateStatements.push(
3976
- `${getTimestampColumnName(column.name)} INTEGER`
4811
+ `${getTimestampColumnName(column.name)} INTEGER GENERATED ALWAYS AS (
4812
+ CASE
4813
+ WHEN ${column.name} IS NULL OR ${column.name} = '' THEN NULL
4814
+ ELSE CAST(
4815
+ substr(${column.name}, 1, instr(${column.name}, ':') - 1) * 3600 +
4816
+ substr(${column.name}, instr(${column.name}, ':') + 1, 2) * 60 +
4817
+ substr(${column.name}, -2) AS INTEGER
4818
+ )
4819
+ END
4820
+ ) STORED`
3977
4821
  );
3978
4822
  }
3979
4823
  }
@@ -4018,9 +4862,6 @@ var formatGtfsLine = (line, model, totalLineCount) => {
4018
4862
  let value = line[name];
4019
4863
  if (value === "" || value === void 0 || value === null) {
4020
4864
  formattedLine[name] = null;
4021
- if (type === "time") {
4022
- formattedLine[getTimestampColumnName(name)] = null;
4023
- }
4024
4865
  if (required) {
4025
4866
  throw new Error(
4026
4867
  `Missing required value in ${filenameBase}.${filenameExtension} for ${name} on line ${lineNumber}.`
@@ -4036,9 +4877,7 @@ var formatGtfsLine = (line, model, totalLineCount) => {
4036
4877
  );
4037
4878
  }
4038
4879
  } else if (type === "time") {
4039
- const [timeAsSecondsFromMidnight, timeAsString] = formatAndCacheTime(value);
4040
- value = timeAsString;
4041
- formattedLine[getTimestampColumnName(name)] = timeAsSecondsFromMidnight ?? null;
4880
+ value = padLeadingZeros(value);
4042
4881
  }
4043
4882
  if (type === "json") {
4044
4883
  value = JSON.stringify(value);
@@ -4062,8 +4901,8 @@ var importGtfsFiles = (db, task) => mapSeries2(
4062
4901
  resolve();
4063
4902
  return;
4064
4903
  }
4065
- const filepath = path.join(task.downloadDir, `${filename}`);
4066
- if (!existsSync(filepath)) {
4904
+ const filepath = path2.join(task.downloadDir, `${filename}`);
4905
+ if (!existsSync2(filepath)) {
4067
4906
  if (!model.nonstandard) {
4068
4907
  task.log(`Importing - ${filename} - No file found\r`);
4069
4908
  }
@@ -4071,19 +4910,7 @@ var importGtfsFiles = (db, task) => mapSeries2(
4071
4910
  return;
4072
4911
  }
4073
4912
  task.log(`Importing - ${filename}\r`);
4074
- const columns = model.schema.flatMap((column) => {
4075
- if (column.type === "time") {
4076
- return [
4077
- column,
4078
- {
4079
- name: getTimestampColumnName(column.name),
4080
- type: "integer",
4081
- index: true
4082
- }
4083
- ];
4084
- }
4085
- return column;
4086
- });
4913
+ const columns = model.schema;
4087
4914
  const prefixedColumns = new Set(
4088
4915
  columns.filter((column) => column.prefix).map((column) => column.name)
4089
4916
  );
@@ -4268,8 +5095,8 @@ async function importGtfs(initialConfig) {
4268
5095
  }
4269
5096
 
4270
5097
  // src/lib/export.ts
4271
- import path2 from "node:path";
4272
- import { writeFile as writeFile2 } from "node:fs/promises";
5098
+ import path3 from "path";
5099
+ import { writeFile as writeFile2 } from "fs/promises";
4273
5100
  import { without, compact as compact2 } from "lodash-es";
4274
5101
  import pluralize3 from "pluralize";
4275
5102
  import { stringify } from "csv-stringify";
@@ -4312,7 +5139,7 @@ var exportGtfs = async (initialConfig) => {
4312
5139
  )} using SQLite database at ${config.sqlitePath}`
4313
5140
  );
4314
5141
  const folderName = generateFolderName(agencies[0].agency_name);
4315
- const defaultExportPath = path2.join(process.cwd(), "gtfs-export", folderName);
5142
+ const defaultExportPath = path3.join(process.cwd(), "gtfs-export", folderName);
4316
5143
  const exportPath = untildify4(config.exportPath || defaultExportPath);
4317
5144
  await prepDirectory(exportPath);
4318
5145
  const modelsToExport = Object.values(models_exports).filter(
@@ -4321,7 +5148,7 @@ var exportGtfs = async (initialConfig) => {
4321
5148
  const exportedFiles = await mapSeries3(
4322
5149
  modelsToExport,
4323
5150
  async (model) => {
4324
- const filePath = path2.join(
5151
+ const filePath = path3.join(
4325
5152
  exportPath,
4326
5153
  `${model.filenameBase}.${model.filenameExtension}`
4327
5154
  );