gtfs-realtime
Version:
Fetch GTFS Realtime data and convert to JSON
141 lines (138 loc) • 3.91 kB
JavaScript
// src/lib/gtfs-realtime.ts
import { writeFile } from "fs/promises";
import GtfsRealtimeBindings from "gtfs-realtime-bindings";
// src/lib/utils.ts
import { dirname } from "path";
import { access, mkdir } from "fs/promises";
import { existsSync } from "fs";
import untildify from "untildify";
import { fromPairs } from "lodash-es";
async function prepDirectory(outputPath) {
if (!outputPath) {
return;
}
const folderPath = dirname(outputPath);
try {
await access(folderPath);
} catch (error) {
try {
await mkdir(folderPath, { recursive: true });
} catch (error2) {
if (error2?.code === "ENOENT") {
throw new Error(
`Unable to write to ${folderPath}. Try running this command from a writable directory.`
);
}
throw error2;
}
}
if (existsSync(outputPath)) {
throw new Error(`File already exists: ${outputPath}`);
}
}
var formatHeaders = (headers) => {
if (!headers) {
return {};
}
return fromPairs(
headers.map((header) => {
const parts = header.split(":");
if (parts.length === 1) {
return [parts[0].trim(), ""];
}
return [parts[0].trim(), parts.slice(1).join(":").trim()];
})
);
};
var formatFilename = (gtfsRealtimeType, outputPath) => {
const isoDate = (/* @__PURE__ */ new Date()).toISOString();
const filepath = outputPath ? untildify(outputPath) : `gtfs-realtime-${gtfsRealtimeType}-${isoDate}.json`;
return filepath;
};
var determineGtfsRealtimeType = (feed) => {
const hasTripUpdate = feed.entity.some((entity) => entity.tripUpdate);
if (hasTripUpdate) {
return "tripupdate";
}
const hasVehiclePosition = feed.entity.some(
(entity) => entity.vehicle && entity.vehicle.position
);
if (hasVehiclePosition) {
return "vehicleposition";
}
const hasAlert = feed.entity.some((entity) => entity.alert);
if (hasAlert) {
return "alert";
}
return "unknown";
};
// src/lib/log-utils.ts
import { clearLine, cursorTo } from "readline";
import { noop } from "lodash-es";
import * as colors from "yoctocolors";
function log(config) {
if (config.verbose === false) {
return noop;
}
if (config.logFunction) {
return config.logFunction;
}
return (text, overwrite) => {
if (overwrite === true && process.stdout.isTTY) {
clearLine(process.stdout, 0);
cursorTo(process.stdout, 0);
} else {
process.stdout.write("\n");
}
process.stdout.write(text);
};
}
function logError(config) {
if (config.logFunction) {
return config.logFunction;
}
return (text) => {
process.stdout.write(`
${formatError(text)}
`);
};
}
function formatError(error) {
const messageText = error instanceof Error ? error.message : error;
const errorMessage = `${colors.underline("Error")}: ${messageText.replace(
"Error: ",
""
)}`;
return colors.red(errorMessage);
}
// src/lib/gtfs-realtime.ts
var gtfsRealtime = async (config) => {
const log2 = log(config);
const logError2 = logError(config);
log2(`Downloading GTFS-Realtime from ${config.url}`);
const response = await fetch(config.url, {
headers: formatHeaders(config.header)
});
if (!response.ok) {
const error = new Error(
`${response.url}: ${response.status} ${response.statusText}`
);
logError2(error.message);
throw error;
}
const buffer = await response.arrayBuffer();
const feed = GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(
new Uint8Array(buffer)
);
const gtfsRealtimeType = determineGtfsRealtimeType(feed);
const filepath = formatFilename(gtfsRealtimeType, config.output);
await prepDirectory(filepath);
await writeFile(filepath, JSON.stringify(feed, null, 2));
log2(`GTFS-Realtime saved as JSON to ${filepath}
`);
};
var gtfs_realtime_default = gtfsRealtime;
export {
gtfs_realtime_default as default
};
//# sourceMappingURL=index.js.map