gtfs 4.14.4 → 4.15.0
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/bin/gtfs-export.js +29 -10
- package/dist/bin/gtfs-export.js.map +1 -1
- package/dist/bin/gtfs-import.js +293 -277
- package/dist/bin/gtfs-import.js.map +1 -1
- package/dist/bin/gtfsrealtime-update.js +171 -145
- package/dist/bin/gtfsrealtime-update.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +356 -337
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
|
@@ -125,15 +125,13 @@ function formatError(error) {
|
|
|
125
125
|
return colors.red(errorMessage);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
// src/lib/import.ts
|
|
128
|
+
// src/lib/import-gtfs.ts
|
|
129
129
|
import { parse } from "csv-parse";
|
|
130
|
-
import
|
|
130
|
+
import pluralize2 from "pluralize";
|
|
131
131
|
import stripBomStream from "strip-bom-stream";
|
|
132
132
|
import { temporaryDirectory } from "tempy";
|
|
133
133
|
import untildify3 from "untildify";
|
|
134
|
-
import
|
|
135
|
-
import GtfsRealtimeBindings from "gtfs-realtime-bindings";
|
|
136
|
-
import sqlString2 from "sqlstring-sqlite";
|
|
134
|
+
import mapSeries2 from "promise-map-series";
|
|
137
135
|
|
|
138
136
|
// src/models/gtfs-realtime/trip-updates.ts
|
|
139
137
|
var tripUpdates = {
|
|
@@ -588,6 +586,12 @@ import {
|
|
|
588
586
|
} from "lodash-es";
|
|
589
587
|
import { feature, featureCollection } from "@turf/helpers";
|
|
590
588
|
|
|
589
|
+
// src/lib/import-gtfs-realtime.ts
|
|
590
|
+
import pluralize from "pluralize";
|
|
591
|
+
import GtfsRealtimeBindings from "gtfs-realtime-bindings";
|
|
592
|
+
import sqlString2 from "sqlstring-sqlite";
|
|
593
|
+
import mapSeries from "promise-map-series";
|
|
594
|
+
|
|
591
595
|
// src/lib/utils.ts
|
|
592
596
|
import sqlString from "sqlstring-sqlite";
|
|
593
597
|
import Long from "long";
|
|
@@ -621,40 +625,10 @@ function convertLongTimeToDate(longDate) {
|
|
|
621
625
|
return new Date(new Long(low, high, unsigned).toInt() * 1e3).toISOString();
|
|
622
626
|
}
|
|
623
627
|
|
|
624
|
-
// src/lib/import.ts
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
const
|
|
628
|
-
method: "GET",
|
|
629
|
-
headers: {
|
|
630
|
-
...urlAndHeaders.headers ?? {},
|
|
631
|
-
"Accept-Encoding": "gzip"
|
|
632
|
-
},
|
|
633
|
-
signal: task.downloadTimeout ? AbortSignal.timeout(task.downloadTimeout) : void 0
|
|
634
|
-
});
|
|
635
|
-
if (response.status !== 200) {
|
|
636
|
-
task.logWarning(
|
|
637
|
-
`Unable to download GTFS-Realtime from ${urlAndHeaders.url}. Got status ${response.status}.`
|
|
638
|
-
);
|
|
639
|
-
return null;
|
|
640
|
-
}
|
|
641
|
-
const buffer = await response.arrayBuffer();
|
|
642
|
-
const message = GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(
|
|
643
|
-
new Uint8Array(buffer)
|
|
644
|
-
);
|
|
645
|
-
return GtfsRealtimeBindings.transit_realtime.FeedMessage.toObject(message, {
|
|
646
|
-
enums: String,
|
|
647
|
-
longs: String,
|
|
648
|
-
bytes: String,
|
|
649
|
-
defaults: true,
|
|
650
|
-
arrays: true,
|
|
651
|
-
objects: true,
|
|
652
|
-
oneofs: true
|
|
653
|
-
});
|
|
654
|
-
};
|
|
655
|
-
function getDescendantProp(obj, defaultValue, source) {
|
|
656
|
-
if (source === void 0) return defaultValue;
|
|
657
|
-
const arr = source.split(".");
|
|
628
|
+
// src/lib/import-gtfs-realtime.ts
|
|
629
|
+
function getNestedProperty(obj, defaultValue, path2) {
|
|
630
|
+
if (path2 === void 0) return defaultValue;
|
|
631
|
+
const arr = path2.split(".");
|
|
658
632
|
while (arr.length) {
|
|
659
633
|
const nextKey = arr.shift();
|
|
660
634
|
if (nextKey === void 0) {
|
|
@@ -683,7 +657,37 @@ function getDescendantProp(obj, defaultValue, source) {
|
|
|
683
657
|
if (obj.__isLong__) return convertLongTimeToDate(obj);
|
|
684
658
|
return obj;
|
|
685
659
|
}
|
|
686
|
-
|
|
660
|
+
async function fetchGtfsRealtimeData(urlConfig, task) {
|
|
661
|
+
task.log(`Downloading GTFS-Realtime from ${urlConfig.url}`);
|
|
662
|
+
const response = await fetch(urlConfig.url, {
|
|
663
|
+
method: "GET",
|
|
664
|
+
headers: {
|
|
665
|
+
...urlConfig.headers ?? {},
|
|
666
|
+
"Accept-Encoding": "gzip"
|
|
667
|
+
},
|
|
668
|
+
signal: task.downloadTimeout ? AbortSignal.timeout(task.downloadTimeout) : void 0
|
|
669
|
+
});
|
|
670
|
+
if (response.status !== 200) {
|
|
671
|
+
task.logWarning(
|
|
672
|
+
`Unable to download GTFS-Realtime from ${urlConfig.url}. Got status ${response.status}.`
|
|
673
|
+
);
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
676
|
+
const buffer = await response.arrayBuffer();
|
|
677
|
+
const message = GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(
|
|
678
|
+
new Uint8Array(buffer)
|
|
679
|
+
);
|
|
680
|
+
return GtfsRealtimeBindings.transit_realtime.FeedMessage.toObject(message, {
|
|
681
|
+
enums: String,
|
|
682
|
+
longs: String,
|
|
683
|
+
bytes: String,
|
|
684
|
+
defaults: true,
|
|
685
|
+
arrays: true,
|
|
686
|
+
objects: true,
|
|
687
|
+
oneofs: true
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
function removeExpiredRealtimeData(config) {
|
|
687
691
|
const log2 = log(config);
|
|
688
692
|
const db = openDb(config);
|
|
689
693
|
log2(`Removing expired GTFS-Realtime data`);
|
|
@@ -703,8 +707,8 @@ var deleteExpiredRealtimeData = (config) => {
|
|
|
703
707
|
`DELETE FROM service_alert_targets WHERE expiration_timestamp <= strftime('%s','now')`
|
|
704
708
|
).run();
|
|
705
709
|
log2(`Removed expired GTFS-Realtime data\r`, true);
|
|
706
|
-
}
|
|
707
|
-
|
|
710
|
+
}
|
|
711
|
+
function prepareRealtimeFieldValue(entity, column, task) {
|
|
708
712
|
if (column.name === "created_timestamp") {
|
|
709
713
|
return task.currentTimestamp;
|
|
710
714
|
}
|
|
@@ -712,54 +716,102 @@ var prepareRealtimeValue = (entity, column, task) => {
|
|
|
712
716
|
return task.currentTimestamp + task.gtfsRealtimeExpirationSeconds;
|
|
713
717
|
}
|
|
714
718
|
return sqlString2.escape(
|
|
715
|
-
|
|
719
|
+
getNestedProperty(entity, column.default, column.source)
|
|
716
720
|
);
|
|
717
|
-
}
|
|
718
|
-
|
|
721
|
+
}
|
|
722
|
+
async function processRealtimeAlerts(db, gtfsRealtimeData, task) {
|
|
723
|
+
task.log(`Download successful`);
|
|
724
|
+
let totalLineCount = 0;
|
|
725
|
+
for (const entity of gtfsRealtimeData.entity) {
|
|
726
|
+
const fieldValues = serviceAlerts.schema.map(
|
|
727
|
+
(column) => prepareRealtimeFieldValue(entity, column, task)
|
|
728
|
+
);
|
|
729
|
+
try {
|
|
730
|
+
db.prepare(
|
|
731
|
+
`REPLACE INTO ${serviceAlerts.filenameBase} (${serviceAlerts.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
|
|
732
|
+
).run();
|
|
733
|
+
} catch (error) {
|
|
734
|
+
task.logWarning("Import error: " + error.message);
|
|
735
|
+
}
|
|
736
|
+
const alertTargetArray = [];
|
|
737
|
+
for (const informedEntity of entity.alert.informedEntity) {
|
|
738
|
+
informedEntity.parent = entity;
|
|
739
|
+
const subValues = serviceAlertTargets.schema.map(
|
|
740
|
+
(column) => prepareRealtimeFieldValue(informedEntity, column, task)
|
|
741
|
+
);
|
|
742
|
+
alertTargetArray.push(`(${subValues.join(", ")})`);
|
|
743
|
+
totalLineCount++;
|
|
744
|
+
}
|
|
745
|
+
try {
|
|
746
|
+
db.prepare(
|
|
747
|
+
`REPLACE INTO ${serviceAlertTargets.filenameBase} (${serviceAlertTargets.schema.map((column) => column.name).join(", ")}) VALUES ${alertTargetArray.join(", ")}`
|
|
748
|
+
).run();
|
|
749
|
+
} catch (error) {
|
|
750
|
+
task.logWarning("Import error: " + error.message);
|
|
751
|
+
}
|
|
752
|
+
task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
async function processRealtimeTripUpdates(db, gtfsRealtimeData, task) {
|
|
756
|
+
task.log(`Download successful`);
|
|
757
|
+
let totalLineCount = 0;
|
|
758
|
+
for (const entity of gtfsRealtimeData.entity) {
|
|
759
|
+
const fieldValues = tripUpdates.schema.map(
|
|
760
|
+
(column) => prepareRealtimeFieldValue(entity, column, task)
|
|
761
|
+
);
|
|
762
|
+
try {
|
|
763
|
+
db.prepare(
|
|
764
|
+
`REPLACE INTO ${tripUpdates.filenameBase} (${tripUpdates.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
|
|
765
|
+
).run();
|
|
766
|
+
} catch (error) {
|
|
767
|
+
task.logWarning("Import error: " + error.message);
|
|
768
|
+
}
|
|
769
|
+
const stopTimeUpdateArray = [];
|
|
770
|
+
for (const stopTimeUpdate of entity.tripUpdate.stopTimeUpdate) {
|
|
771
|
+
stopTimeUpdate.parent = entity;
|
|
772
|
+
const subValues = stopTimeUpdates.schema.map(
|
|
773
|
+
(column) => prepareRealtimeFieldValue(stopTimeUpdate, column, task)
|
|
774
|
+
);
|
|
775
|
+
stopTimeUpdateArray.push(`(${subValues.join(", ")})`);
|
|
776
|
+
totalLineCount++;
|
|
777
|
+
}
|
|
778
|
+
try {
|
|
779
|
+
db.prepare(
|
|
780
|
+
`REPLACE INTO ${stopTimeUpdates.filenameBase} (${stopTimeUpdates.schema.map((column) => column.name).join(", ")}) VALUES ${stopTimeUpdateArray.join(", ")}`
|
|
781
|
+
).run();
|
|
782
|
+
} catch (error) {
|
|
783
|
+
task.logWarning("Import error: " + error.message);
|
|
784
|
+
}
|
|
785
|
+
task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
async function processRealtimeVehiclePositions(db, gtfsRealtimeData, task) {
|
|
789
|
+
task.log(`Download successful`);
|
|
790
|
+
let totalLineCount = 0;
|
|
791
|
+
for (const entity of gtfsRealtimeData.entity) {
|
|
792
|
+
const fieldValues = vehiclePositions.schema.map(
|
|
793
|
+
(column) => prepareRealtimeFieldValue(entity, column, task)
|
|
794
|
+
);
|
|
795
|
+
try {
|
|
796
|
+
db.prepare(
|
|
797
|
+
`REPLACE INTO ${vehiclePositions.filenameBase} (${vehiclePositions.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
|
|
798
|
+
).run();
|
|
799
|
+
} catch (error) {
|
|
800
|
+
task.logWarning("Import error: " + error.message);
|
|
801
|
+
}
|
|
802
|
+
task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
async function updateGtfsRealtimeData(task) {
|
|
719
806
|
if (task.realtimeAlerts === void 0 && task.realtimeTripUpdates === void 0 && task.realtimeVehiclePositions === void 0) {
|
|
720
807
|
return;
|
|
721
808
|
}
|
|
722
|
-
const db = openDb({
|
|
723
|
-
sqlitePath: task.sqlitePath
|
|
724
|
-
});
|
|
809
|
+
const db = openDb({ sqlitePath: task.sqlitePath });
|
|
725
810
|
if (task.realtimeAlerts?.url) {
|
|
726
811
|
try {
|
|
727
|
-
const
|
|
728
|
-
|
|
729
|
-
task
|
|
730
|
-
);
|
|
731
|
-
if (gtfsRealtimeData?.entity) {
|
|
732
|
-
task.log(`Download successful`);
|
|
733
|
-
let totalLineCount = 0;
|
|
734
|
-
for (const entity of gtfsRealtimeData.entity) {
|
|
735
|
-
const fieldValues = serviceAlerts.schema.map(
|
|
736
|
-
(column) => prepareRealtimeValue(entity, column, task)
|
|
737
|
-
);
|
|
738
|
-
try {
|
|
739
|
-
db.prepare(
|
|
740
|
-
`REPLACE INTO ${serviceAlerts.filenameBase} (${serviceAlerts.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
|
|
741
|
-
).run();
|
|
742
|
-
} catch (error) {
|
|
743
|
-
task.logWarning("Import error: " + error.message);
|
|
744
|
-
}
|
|
745
|
-
const alertTargetArray = [];
|
|
746
|
-
for (const informedEntity of entity.alert.informedEntity) {
|
|
747
|
-
informedEntity.parent = entity;
|
|
748
|
-
const subValues = serviceAlertTargets.schema.map(
|
|
749
|
-
(column) => prepareRealtimeValue(informedEntity, column, task)
|
|
750
|
-
);
|
|
751
|
-
alertTargetArray.push(`(${subValues.join(", ")})`);
|
|
752
|
-
totalLineCount++;
|
|
753
|
-
}
|
|
754
|
-
try {
|
|
755
|
-
db.prepare(
|
|
756
|
-
`REPLACE INTO ${serviceAlertTargets.filenameBase} (${serviceAlertTargets.schema.map((column) => column.name).join(", ")}) VALUES ${alertTargetArray.join(", ")}`
|
|
757
|
-
).run();
|
|
758
|
-
} catch (error) {
|
|
759
|
-
task.logWarning("Import error: " + error.message);
|
|
760
|
-
}
|
|
761
|
-
task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
|
|
762
|
-
}
|
|
812
|
+
const alertsData = await fetchGtfsRealtimeData(task.realtimeAlerts, task);
|
|
813
|
+
if (alertsData?.entity) {
|
|
814
|
+
await processRealtimeAlerts(db, alertsData, task);
|
|
763
815
|
}
|
|
764
816
|
} catch (error) {
|
|
765
817
|
if (task.ignoreErrors) {
|
|
@@ -771,42 +823,12 @@ var updateRealtimeData = async (task) => {
|
|
|
771
823
|
}
|
|
772
824
|
if (task.realtimeTripUpdates?.url) {
|
|
773
825
|
try {
|
|
774
|
-
const
|
|
826
|
+
const tripUpdatesData = await fetchGtfsRealtimeData(
|
|
775
827
|
task.realtimeTripUpdates,
|
|
776
828
|
task
|
|
777
829
|
);
|
|
778
|
-
if (
|
|
779
|
-
|
|
780
|
-
let totalLineCount = 0;
|
|
781
|
-
for (const entity of gtfsRealtimeData.entity) {
|
|
782
|
-
const fieldValues = tripUpdates.schema.map(
|
|
783
|
-
(column) => prepareRealtimeValue(entity, column, task)
|
|
784
|
-
);
|
|
785
|
-
try {
|
|
786
|
-
db.prepare(
|
|
787
|
-
`REPLACE INTO ${tripUpdates.filenameBase} (${tripUpdates.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
|
|
788
|
-
).run();
|
|
789
|
-
} catch (error) {
|
|
790
|
-
task.logWarning("Import error: " + error.message);
|
|
791
|
-
}
|
|
792
|
-
const stopTimeUpdateArray = [];
|
|
793
|
-
for (const stopTimeUpdate of entity.tripUpdate.stopTimeUpdate) {
|
|
794
|
-
stopTimeUpdate.parent = entity;
|
|
795
|
-
const subValues = stopTimeUpdates.schema.map(
|
|
796
|
-
(column) => prepareRealtimeValue(stopTimeUpdate, column, task)
|
|
797
|
-
);
|
|
798
|
-
stopTimeUpdateArray.push(`(${subValues.join(", ")})`);
|
|
799
|
-
totalLineCount++;
|
|
800
|
-
}
|
|
801
|
-
try {
|
|
802
|
-
db.prepare(
|
|
803
|
-
`REPLACE INTO ${stopTimeUpdates.filenameBase} (${stopTimeUpdates.schema.map((column) => column.name).join(", ")}) VALUES ${stopTimeUpdateArray.join(", ")}`
|
|
804
|
-
).run();
|
|
805
|
-
} catch (error) {
|
|
806
|
-
task.logWarning("Import error: " + error.message);
|
|
807
|
-
}
|
|
808
|
-
task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
|
|
809
|
-
}
|
|
830
|
+
if (tripUpdatesData?.entity) {
|
|
831
|
+
await processRealtimeTripUpdates(db, tripUpdatesData, task);
|
|
810
832
|
}
|
|
811
833
|
} catch (error) {
|
|
812
834
|
if (task.ignoreErrors) {
|
|
@@ -818,26 +840,12 @@ var updateRealtimeData = async (task) => {
|
|
|
818
840
|
}
|
|
819
841
|
if (task.realtimeVehiclePositions?.url) {
|
|
820
842
|
try {
|
|
821
|
-
const
|
|
843
|
+
const vehiclePositionsData = await fetchGtfsRealtimeData(
|
|
822
844
|
task.realtimeVehiclePositions,
|
|
823
845
|
task
|
|
824
846
|
);
|
|
825
|
-
if (
|
|
826
|
-
|
|
827
|
-
let totalLineCount = 0;
|
|
828
|
-
for (const entity of gtfsRealtimeData.entity) {
|
|
829
|
-
const fieldValues = vehiclePositions.schema.map(
|
|
830
|
-
(column) => prepareRealtimeValue(entity, column, task)
|
|
831
|
-
);
|
|
832
|
-
try {
|
|
833
|
-
db.prepare(
|
|
834
|
-
`REPLACE INTO ${vehiclePositions.filenameBase} (${vehiclePositions.schema.map((column) => column.name).join(", ")}) VALUES (${fieldValues.join(", ")})`
|
|
835
|
-
).run();
|
|
836
|
-
} catch (error) {
|
|
837
|
-
task.logWarning("Import error: " + error.message);
|
|
838
|
-
}
|
|
839
|
-
task.log(`Importing - ${totalLineCount++} entries imported\r`, true);
|
|
840
|
-
}
|
|
847
|
+
if (vehiclePositionsData?.entity) {
|
|
848
|
+
await processRealtimeVehiclePositions(db, vehiclePositionsData, task);
|
|
841
849
|
}
|
|
842
850
|
} catch (error) {
|
|
843
851
|
if (task.ignoreErrors) {
|
|
@@ -848,7 +856,7 @@ var updateRealtimeData = async (task) => {
|
|
|
848
856
|
}
|
|
849
857
|
}
|
|
850
858
|
task.log(`GTFS-Realtime data import complete`);
|
|
851
|
-
}
|
|
859
|
+
}
|
|
852
860
|
async function updateGtfsRealtime(initialConfig) {
|
|
853
861
|
const config = setDefaultConfig(initialConfig);
|
|
854
862
|
validateConfigForImport(config);
|
|
@@ -865,7 +873,7 @@ async function updateGtfsRealtime(initialConfig) {
|
|
|
865
873
|
true
|
|
866
874
|
)} using SQLite database at ${config.sqlitePath}`
|
|
867
875
|
);
|
|
868
|
-
|
|
876
|
+
removeExpiredRealtimeData(config);
|
|
869
877
|
await mapSeries(config.agencies, async (agency2) => {
|
|
870
878
|
try {
|
|
871
879
|
const task = {
|
|
@@ -881,7 +889,7 @@ async function updateGtfsRealtime(initialConfig) {
|
|
|
881
889
|
logWarning: logWarning2,
|
|
882
890
|
logError: logError2
|
|
883
891
|
};
|
|
884
|
-
await
|
|
892
|
+
await updateGtfsRealtimeData(task);
|
|
885
893
|
} catch (error) {
|
|
886
894
|
if (config.ignoreErrors) {
|
|
887
895
|
logError2(error.message);
|
|
@@ -899,21 +907,39 @@ async function updateGtfsRealtime(initialConfig) {
|
|
|
899
907
|
`
|
|
900
908
|
);
|
|
901
909
|
} catch (error) {
|
|
902
|
-
|
|
903
|
-
logError2(
|
|
904
|
-
`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`
|
|
905
|
-
);
|
|
906
|
-
}
|
|
907
|
-
throw error;
|
|
910
|
+
handleDatabaseError(error, config, logError2);
|
|
908
911
|
}
|
|
909
912
|
}
|
|
913
|
+
function handleDatabaseError(error, config, logError2) {
|
|
914
|
+
if (error?.code === "SQLITE_CANTOPEN") {
|
|
915
|
+
logError2(
|
|
916
|
+
`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
throw error;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// src/lib/import-gtfs.ts
|
|
923
|
+
var TIME_COLUMN_NAMES = [
|
|
924
|
+
"start_time",
|
|
925
|
+
"end_time",
|
|
926
|
+
"arrival_time",
|
|
927
|
+
"departure_time",
|
|
928
|
+
"prior_notice_last_time",
|
|
929
|
+
"prior_notice_start_time",
|
|
930
|
+
"start_pickup_drop_off_window"
|
|
931
|
+
];
|
|
932
|
+
var TIME_COLUMN_PAIRS = TIME_COLUMN_NAMES.map((name) => [
|
|
933
|
+
name,
|
|
934
|
+
name.endsWith("time") ? `${name}stamp` : `${name}_timestamp`
|
|
935
|
+
]);
|
|
910
936
|
|
|
911
937
|
// src/lib/export.ts
|
|
912
938
|
import { without, compact as compact2 } from "lodash-es";
|
|
913
|
-
import
|
|
939
|
+
import pluralize3 from "pluralize";
|
|
914
940
|
import { stringify } from "csv-stringify";
|
|
915
941
|
import sqlString3 from "sqlstring-sqlite";
|
|
916
|
-
import
|
|
942
|
+
import mapSeries3 from "promise-map-series";
|
|
917
943
|
import untildify4 from "untildify";
|
|
918
944
|
|
|
919
945
|
// src/lib/advancedQuery.ts
|