gtfs 4.15.12 → 4.15.14
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.map +1 -1
- package/dist/bin/gtfs-import.js +12 -12
- package/dist/bin/gtfs-import.js.map +1 -1
- package/dist/bin/gtfsrealtime-update.js.map +1 -1
- package/dist/index.d.ts +32 -30
- package/dist/index.js +16 -13
- package/dist/index.js.map +1 -1
- package/package.json +9 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bin/gtfs-export.ts","../../src/lib/file-utils.ts","../../src/lib/log-utils.ts","../../src/lib/import-gtfs.ts","../../src/models/models.ts","../../src/models/gtfs/agency.ts","../../src/models/gtfs/areas.ts","../../src/models/gtfs/attributions.ts","../../src/models/gtfs/booking-rules.ts","../../src/models/gtfs/calendar-dates.ts","../../src/models/gtfs/calendar.ts","../../src/models/gtfs/fare-attributes.ts","../../src/models/gtfs/fare-leg-rules.ts","../../src/models/gtfs/fare-media.ts","../../src/models/gtfs/fare-products.ts","../../src/models/gtfs/fare-rules.ts","../../src/models/gtfs/fare-transfer-rules.ts","../../src/models/gtfs/feed-info.ts","../../src/models/gtfs/frequencies.ts","../../src/models/gtfs/levels.ts","../../src/models/gtfs/location-groups.ts","../../src/models/gtfs/location-group-stops.ts","../../src/models/gtfs/locations.ts","../../src/models/gtfs/networks.ts","../../src/models/gtfs/pathways.ts","../../src/models/gtfs/route-networks.ts","../../src/models/gtfs/routes.ts","../../src/models/gtfs/shapes.ts","../../src/models/gtfs/stop-areas.ts","../../src/models/gtfs/stop-times.ts","../../src/models/gtfs/stops.ts","../../src/models/gtfs/timeframes.ts","../../src/models/gtfs/transfers.ts","../../src/models/gtfs/translations.ts","../../src/models/gtfs/trips.ts","../../src/models/non-standard/timetables.ts","../../src/models/non-standard/timetable-pages.ts","../../src/models/non-standard/timetable-stop-order.ts","../../src/models/non-standard/timetable-notes.ts","../../src/models/non-standard/timetable-notes-references.ts","../../src/models/non-standard/trips-dated-vehicle-journey.ts","../../src/models/gtfs-plus/calendar-attributes.ts","../../src/models/gtfs-plus/directions.ts","../../src/models/gtfs-plus/route-attributes.ts","../../src/models/gtfs-plus/stop-attributes.ts","../../src/models/gtfs-ride/board-alight.ts","../../src/models/gtfs-ride/rider-trip.ts","../../src/models/gtfs-ride/ridership.ts","../../src/models/gtfs-ride/trip-capacity.ts","../../src/models/gtfs-ride/ride-feed-info.ts","../../src/models/gtfs-realtime/trip-updates.ts","../../src/models/gtfs-realtime/stop-time-updates.ts","../../src/models/gtfs-realtime/vehicle-positions.ts","../../src/models/gtfs-realtime/service-alerts.ts","../../src/models/gtfs-realtime/service-alert-targets.ts","../../src/models/ods/deadhead-times.ts","../../src/models/ods/deadheads.ts","../../src/models/ods/ops-locations.ts","../../src/models/ods/run-events.ts","../../src/models/ods/runs-pieces.ts","../../src/lib/db.ts","../../src/lib/geojson-utils.ts","../../src/lib/import-gtfs-realtime.ts","../../src/lib/utils.ts","../../src/lib/export.ts","../../src/lib/advancedQuery.ts","../../src/lib/gtfs/routes.ts","../../src/lib/gtfs/shapes.ts","../../src/lib/gtfs/stops.ts","../../src/lib/gtfs/stop-times.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport PrettyError from 'pretty-error';\n\nimport { getConfig } from '../lib/file-utils.ts';\nimport { formatError } from '../lib/log-utils.ts';\nimport { exportGtfs } from '../index.ts';\nimport type { Config } from '../types/global_interfaces.ts';\n\nconst pe = new PrettyError();\n\nconst argv = yargs(hideBin(process.argv))\n .usage('Usage: $0 --configPath ./config.json')\n .help()\n .option('c', {\n alias: 'configPath',\n describe: 'Path to config file',\n type: 'string',\n })\n .option('sqlitePath', {\n describe: 'Path to SQLite database',\n type: 'string',\n })\n .parseSync();\n\nconst handleError = (error = 'Unknown Error') => {\n process.stdout.write(`\\n${formatError(error)}\\n`);\n console.error(pe.render(error));\n process.exit(1);\n};\n\nconst setupExport = async () => {\n const config = await getConfig(argv);\n await exportGtfs(config as Config);\n process.exit();\n};\n\nsetupExport().catch(handleError);\n","import path from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, rm } from 'node:fs/promises';\nimport { omit, snakeCase } from 'lodash-es';\nimport sanitize from 'sanitize-filename';\nimport untildify from 'untildify';\nimport StreamZip from 'node-stream-zip';\n\nimport { log } from './log-utils.ts';\n\n/** Configuration command line arguments interface */\ninterface ConfigArgs {\n configPath?: string;\n gtfsPath?: string;\n gtfsUrl?: string;\n sqlitePath?: string;\n}\n\n/**\n * Attempts to parse and load configuration from various sources\n * Priority: 1. CLI config path 2. CLI direct args 3. ./config.json\n * @param {ConfigArgs} argv - Command line arguments\n * @throws {Error} If configuration cannot be found or parsed\n * @returns {Promise<Record<string, any>>} Parsed configuration object\n * @example\n * const config = await getConfig({ configPath: './my-config.json' });\n */\nexport async function getConfig(\n argv: ConfigArgs,\n): Promise<Record<string, any>> {\n let config;\n let data;\n\n try {\n if (argv.configPath) {\n const configPath = path.resolve(untildify(argv.configPath));\n data = await readFile(configPath, 'utf8');\n config = Object.assign(JSON.parse(data), argv);\n } else if (argv.gtfsPath || argv.gtfsUrl || argv.sqlitePath) {\n const agencies = [\n ...(argv.gtfsPath ? [{ path: argv.gtfsPath }] : []),\n ...(argv.gtfsUrl ? [{ url: argv.gtfsUrl }] : []),\n ];\n\n config = {\n agencies,\n ...omit(argv, ['path', 'url']),\n };\n } else if (existsSync(path.resolve('./config.json'))) {\n data = await readFile(path.resolve('./config.json'), 'utf8');\n config = Object.assign(JSON.parse(data), argv);\n log(config)('Using configuration from ./config.json');\n } else {\n throw new Error(\n 'Cannot find configuration file. Use config-sample.json as a starting point, pass --configPath option.',\n );\n }\n\n return config;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(\n `Cannot parse configuration file. Check to ensure that it is valid JSON. Error: ${error.message}`,\n );\n }\n throw error;\n }\n}\n\n/**\n * Prepares a directory for saving files by clearing its contents\n * @param {string} exportPath - Path to the directory to prepare\n * @returns {Promise<void>}\n * @example\n * await prepDirectory('./output');\n */\nexport async function prepDirectory(exportPath: string): Promise<void> {\n await rm(exportPath, { recursive: true, force: true });\n await mkdir(exportPath, { recursive: true });\n}\n\n/**\n * Extracts contents of a zip file to specified directory\n * @param {string} zipfilePath - Path to the zip file\n * @param {string} exportPath - Directory to extract contents to\n * @returns {Promise<void>}\n * @throws {Error} If zip file cannot be opened or extracted\n * @example\n * await unzip('./data.zip', './extracted');\n */\nexport async function unzip(\n zipfilePath: string,\n exportPath: string,\n): Promise<void> {\n try {\n const zip = new StreamZip.async({ file: zipfilePath });\n await zip.extract(null, exportPath);\n await zip.close();\n } catch (error) {\n throw new Error(\n `Failed to extract zip file: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n}\n\n/**\n * Generates a safe folder name from input string\n * Converts to snake_case and removes unsafe characters\n * @param {string} folderName - Input string to convert to folder name\n * @returns {string} Sanitized folder name\n * @example\n * generateFolderName('My Folder!') // returns 'my_folder'\n */\nexport function generateFolderName(folderName: string): string {\n if (!folderName || typeof folderName !== 'string') {\n throw new Error('Folder name must be a non-empty string');\n }\n return snakeCase(sanitize(folderName));\n}\n","import { clearLine, cursorTo } from 'node:readline';\nimport { noop } from 'lodash-es';\nimport * as colors from 'yoctocolors';\nimport { Config } from '../types/global_interfaces.ts';\n\n/** Function type for logging with optional line overwrite */\ntype LogFunction = (text: string, overwrite?: boolean) => void;\n\n/**\n * Creates a logging function based on configuration settings\n * @param {Config} config - Configuration object containing logging preferences\n * @returns {LogFunction} Logging function that writes to stdout, or noop if verbose is false\n * @example\n * const logger = log({ verbose: true });\n * logger('Processing...', true); // Overwrites current line\n * logger('Done!'); // Writes on new line\n */\nexport function log(config: Config): LogFunction {\n if (config.verbose === false) {\n return noop;\n }\n\n if (config.logFunction) {\n return config.logFunction;\n }\n\n return (text: string, overwrite = false): void => {\n if (overwrite && process.stdout.isTTY) {\n clearLine(process.stdout, 0);\n cursorTo(process.stdout, 0);\n } else {\n process.stdout.write('\\n');\n }\n\n process.stdout.write(text);\n };\n}\n\n/**\n * Creates a warning logging function\n * @param {Config} config - Configuration object containing logging preferences\n * @returns {(text: string) => void} Function that logs formatted warning messages\n * @example\n * const warnLogger = logWarning(config);\n * warnLogger('Resource not found'); // Outputs yellow warning message\n */\nexport function logWarning(config: Config): (text: string) => void {\n if (config.logFunction) {\n return config.logFunction;\n }\n\n return (text: string): void => {\n process.stdout.write(`\\n${formatWarning(text)}\\n`);\n };\n}\n\n/**\n * Creates an error logging function\n * @param {Config} config - Configuration object containing logging preferences\n * @returns {(text: string) => void} Function that logs formatted error messages\n * @example\n * const errorLogger = logError(config);\n * errorLogger('Failed to connect'); // Outputs red error message\n */\nexport function logError(config: Config): (text: string) => void {\n if (config.logFunction) {\n return config.logFunction;\n }\n\n return (text: string): void => {\n process.stdout.write(`\\n${formatError(text)}\\n`);\n };\n}\n\n/**\n * Formats warning text with yellow color and underline\n * @param {string} text - The warning message to format\n * @returns {string} Formatted warning message in yellow with underlined \"Warning\" prefix\n * @example\n * const formattedWarning = formatWarning('Resource not found');\n * console.log(formattedWarning); // Yellow \"Warning: Resource not found\"\n */\nexport function formatWarning(text: string): string {\n return colors.yellow(`${colors.underline('Warning')}: ${text}`);\n}\n\n/**\n * Formats error text with red color and underline\n * @param {Error | string} error - The error object or message to format\n * @returns {string} Formatted error message in red with underlined \"Error\" prefix\n * @example\n * const formattedError = formatError(new Error('Connection failed'));\n * console.log(formattedError); // Red \"Error: Connection failed\"\n */\nexport function formatError(error: Error | string): string {\n const messageText = error instanceof Error ? error.message : error;\n const cleanMessage = messageText.replace(/^Error:\\s*/i, '');\n\n return colors.red(`${colors.underline('Error')}: ${cleanMessage}`);\n}\n","import path from 'node:path';\nimport { createReadStream, existsSync, lstatSync } from 'node:fs';\nimport { cp, readdir, rename, readFile, rm, writeFile } from 'node:fs/promises';\nimport { parse } from 'csv-parse';\nimport pluralize from 'pluralize';\nimport stripBomStream from 'strip-bom-stream';\nimport { temporaryDirectory } from 'tempy';\nimport Timer from 'timer-machine';\nimport untildify from 'untildify';\nimport mapSeries from 'promise-map-series';\nimport Database from 'better-sqlite3';\n\nimport * as models from '../models/models.ts';\nimport { openDb } from './db.ts';\nimport { unzip } from './file-utils.ts';\nimport { isValidJSON } from './geojson-utils.ts';\nimport { updateGtfsRealtimeData } from './import-gtfs-realtime.ts';\nimport { log, logError, logWarning } from './log-utils.ts';\nimport {\n calculateSecondsFromMidnight,\n getTimestampColumnName,\n padLeadingZeros,\n setDefaultConfig,\n validateConfigForImport,\n} from './utils.ts';\n\nimport {\n Config,\n ConfigAgency,\n Model,\n ModelColumn,\n} from '../types/global_interfaces.ts';\n\ninterface GtfsImportTask {\n exclude?: string[];\n url?: string;\n headers?: Record<string, string>;\n realtimeAlerts?: {\n url: string;\n headers?: Record<string, string>;\n };\n realtimeTripUpdates?: {\n url: string;\n headers?: Record<string, string>;\n };\n realtimeVehiclePositions?: {\n url: string;\n headers?: Record<string, string>;\n };\n downloadDir: string;\n downloadTimeout?: number;\n gtfsRealtimeExpirationSeconds: number;\n path?: string;\n csvOptions: {};\n ignoreDuplicates: boolean;\n ignoreErrors: boolean;\n sqlitePath: string;\n prefix?: string;\n currentTimestamp: number;\n log: (message: string, newLine?: boolean) => void;\n logWarning: (message: string) => void;\n logError: (message: string) => void;\n}\n\ninterface Dictionary<T> {\n [key: string]: T;\n}\ntype Tuple = [seconds: number | null, date: string | null];\n\nconst timeCache: Dictionary<Tuple> = {};\n\nconst formatAndCacheTime = (value: string): Tuple => {\n const cached = timeCache[value];\n if (cached !== undefined) {\n return cached;\n }\n\n const timeAsSecondsFromMidnight = calculateSecondsFromMidnight(value);\n const timeAsString = padLeadingZeros(value);\n const computed: Tuple = [timeAsSecondsFromMidnight, timeAsString];\n timeCache[value] = computed;\n return computed;\n};\n\nconst getTextFiles = async (folderPath: string): Promise<string[]> => {\n const files = await readdir(folderPath);\n return files.filter((filename) => filename.slice(-3) === 'txt');\n};\n\nconst downloadGtfsFiles = async (task: GtfsImportTask): Promise<void> => {\n if (!task.url) {\n throw new Error('No `url` specified in config');\n }\n\n task.log(`Downloading GTFS from ${task.url}`);\n\n task.path = `${task.downloadDir}/gtfs.zip`;\n\n const response = await fetch(task.url, {\n method: 'GET',\n headers: task.headers || {},\n signal: task.downloadTimeout\n ? AbortSignal.timeout(task.downloadTimeout)\n : undefined,\n });\n\n if (response.status !== 200) {\n throw new Error(\n `Unable to download GTFS from ${task.url}. Got status ${response.status}.`,\n );\n }\n\n const buffer = await response.arrayBuffer();\n\n await writeFile(task.path, Buffer.from(buffer));\n task.log('Download successful');\n};\n\nconst extractGtfsFiles = async (task: GtfsImportTask): Promise<void> => {\n if (!task.path) {\n throw new Error('No `path` specified in config');\n }\n\n const gtfsPath = untildify(task.path);\n task.log(`Importing GTFS from ${task.path}\\r`);\n if (path.extname(gtfsPath) === '.zip') {\n try {\n await unzip(gtfsPath, task.downloadDir);\n const textFiles = await getTextFiles(task.downloadDir);\n\n // If no .txt files in this directory, check for subdirectories and copy them here\n if (textFiles.length === 0) {\n const files = await readdir(task.downloadDir);\n // Ignore system directories within zip file\n const folders = files\n .filter((filename) => !['__MACOSX'].includes(filename))\n .map((filename) => path.join(task.downloadDir, filename))\n .filter((source) => lstatSync(source).isDirectory());\n\n if (folders.length > 1) {\n throw new Error(\n `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.`,\n );\n } else if (folders.length === 0) {\n throw new Error(\n `No .txt files found in \\`${task.path}\\`. Ensure that .txt files are in the top level of the zip file, or in a single subdirectory.`,\n );\n }\n\n const subfolderName = folders[0];\n const directoryTextFiles = await getTextFiles(subfolderName);\n\n if (directoryTextFiles.length === 0) {\n throw new Error(\n `No .txt files found in \\`${task.path}\\`. Ensure that .txt files are in the top level of the zip file, or in a single subdirectory.`,\n );\n }\n\n await Promise.all(\n directoryTextFiles.map(async (fileName) =>\n rename(\n path.join(subfolderName, fileName),\n path.join(task.downloadDir, fileName),\n ),\n ),\n );\n }\n } catch (error: any) {\n task.logError(error);\n throw new Error(`Unable to unzip file ${task.path}`);\n }\n } else {\n // Local file is unzipped, just copy it from there.\n try {\n await cp(gtfsPath, task.downloadDir, { recursive: true });\n } catch {\n throw new Error(\n `Unable to load files from path \\`${gtfsPath}\\` defined in configuration. Verify that path exists and contains GTFS files.`,\n );\n }\n }\n};\n\nconst createGtfsTables = (db: Database.Database): void => {\n for (const model of Object.values(models) as Model[]) {\n if (!model.schema) {\n return;\n }\n\n const sqlColumnCreateStatements = [];\n\n for (const column of model.schema) {\n const checks = [];\n if (column.min !== undefined && column.max) {\n checks.push(\n `${column.name} >= ${column.min} AND ${column.name} <= ${column.max}`,\n );\n } else if (column.min) {\n checks.push(`${column.name} >= ${column.min}`);\n } else if (column.max) {\n checks.push(`${column.name} <= ${column.max}`);\n }\n\n if (column.type === 'integer') {\n checks.push(\n `(TYPEOF(${column.name}) = 'integer' OR ${column.name} IS NULL)`,\n );\n } else if (column.type === 'real') {\n checks.push(\n `(TYPEOF(${column.name}) = 'real' OR ${column.name} IS NULL)`,\n );\n }\n\n const required = column.required ? 'NOT NULL' : '';\n const columnDefault = column.default ? 'DEFAULT ' + column.default : '';\n const columnCollation = column.nocase ? 'COLLATE NOCASE' : '';\n const checkClause =\n checks.length > 0 ? `CHECK(${checks.join(' AND ')})` : '';\n\n sqlColumnCreateStatements.push(\n `${column.name} ${column.type} ${checkClause} ${required} ${columnDefault} ${columnCollation}`,\n );\n\n // Add an additional timestamp column for time columns\n if (column.type === 'time') {\n sqlColumnCreateStatements.push(\n `${getTimestampColumnName(column.name)} INTEGER`,\n );\n }\n }\n\n // Find Primary Key fields\n const primaryColumns = model.schema.filter((column) => column.primary);\n\n if (primaryColumns.length > 0) {\n sqlColumnCreateStatements.push(\n `PRIMARY KEY (${primaryColumns.map(({ name }) => name).join(', ')})`,\n );\n }\n\n db.prepare(`DROP TABLE IF EXISTS ${model.filenameBase};`).run();\n\n db.prepare(\n `CREATE TABLE ${model.filenameBase} (${sqlColumnCreateStatements.join(', ')});`,\n ).run();\n }\n};\n\nconst createGtfsIndexes = (db: Database.Database): void => {\n for (const model of Object.values(models) as Model[]) {\n if (!model.schema) {\n return;\n }\n for (const column of model.schema) {\n if (column.index) {\n db.prepare(\n `CREATE INDEX idx_${model.filenameBase}_${column.name} ON ${model.filenameBase} (${column.name});`,\n ).run();\n }\n\n if (column.type === 'time') {\n // Index all timestamp columns\n const timestampColumnName = getTimestampColumnName(column.name);\n db.prepare(\n `CREATE INDEX idx_${model.filenameBase}_${timestampColumnName} ON ${model.filenameBase} (${timestampColumnName});`,\n ).run();\n }\n }\n }\n};\n\nconst formatGtfsLine = (\n line: { [x: string]: any; geojson?: string },\n model: Model,\n totalLineCount: number,\n): Record<string, any> => {\n const lineNumber = totalLineCount + 1;\n const formattedLine: Record<string, any> = {};\n const filenameBase = model.filenameBase;\n const filenameExtension = model.filenameExtension;\n\n for (const { name, type, required } of model.schema) {\n let value = line[name];\n\n // Early null check\n if (value === '' || value === undefined || value === null) {\n formattedLine[name] = null;\n\n if (type === 'time') {\n formattedLine[getTimestampColumnName(name)] = null;\n }\n\n if (required) {\n throw new Error(\n `Missing required value in ${filenameBase}.${filenameExtension} for ${name} on line ${lineNumber}.`,\n );\n }\n continue;\n }\n\n if (type === 'date') {\n // Handle YYYY-MM-DD format\n value = value.replace(/-/g, '');\n if (value.length !== 8) {\n throw new Error(\n `Invalid date in ${filenameBase}.${filenameExtension} for ${name} on line ${lineNumber}.`,\n );\n }\n } else if (type === 'time') {\n // Add an additional timestamp column for time columns\n const [timeAsSecondsFromMidnight, timeAsString] =\n formatAndCacheTime(value);\n\n value = timeAsString;\n\n formattedLine[getTimestampColumnName(name)] =\n timeAsSecondsFromMidnight ?? null;\n }\n\n if (type === 'json') {\n value = JSON.stringify(value);\n }\n\n formattedLine[name] = value;\n }\n\n return formattedLine;\n};\n\nconst BATCH_SIZE = 100_000;\n\nconst importGtfsFiles = (\n db: Database.Database,\n task: GtfsImportTask,\n): Promise<void[]> =>\n mapSeries(\n Object.values(models),\n (model: Model) =>\n new Promise<void>((resolve, reject) => {\n let totalLineCount = 0;\n const filename = `${model.filenameBase}.${model.filenameExtension}`;\n\n // Filter out excluded files from config\n if (task.exclude && task.exclude.includes(model.filenameBase)) {\n task.log(`Skipping - ${filename}\\r`);\n resolve();\n return;\n }\n\n // If the model is a database/gtfs-realtime model then skip silently\n if (model.extension === 'gtfs-realtime') {\n resolve();\n return;\n }\n\n const filepath = path.join(task.downloadDir, `${filename}`);\n\n // Log missing standard GTFS files, don't log nonstandard files\n if (!existsSync(filepath)) {\n if (!model.nonstandard) {\n task.log(`Importing - ${filename} - No file found\\r`);\n }\n\n resolve();\n return;\n }\n\n task.log(`Importing - ${filename}\\r`);\n\n // Create a list of all columns\n const columns = model.schema.flatMap((column) => {\n if (column.type === 'time') {\n // Add an additional timestamp column for time columns\n return [\n column,\n {\n name: getTimestampColumnName(column.name),\n type: 'integer',\n index: true,\n } as ModelColumn,\n ];\n }\n return column;\n });\n\n // Create a map of which columns need prefixing\n const prefixedColumns = new Set(\n columns\n .filter((column) => column.prefix)\n .map((column) => column.name),\n );\n\n const prepareStatement = `INSERT ${task.ignoreDuplicates ? 'OR IGNORE' : ''} INTO ${\n model.filenameBase\n } (${columns.map(({ name }) => name).join(', ')}) VALUES (${columns\n .map(({ name }) => `@${name}`)\n .join(', ')})`;\n\n const insert = db.prepare(prepareStatement);\n\n const insertLines = db.transaction((lines) => {\n for (const [rowNumber, line] of Object.entries(lines)) {\n try {\n if (task.prefix === undefined) {\n insert.run(line);\n } else {\n const prefixedLine = Object.fromEntries(\n Object.entries(\n line as { [x: string]: any; geojson?: string },\n ).map(([columnName, value]) => [\n columnName,\n prefixedColumns.has(columnName) && value !== null\n ? `${task.prefix}${value}`\n : value,\n ]),\n );\n insert.run(prefixedLine);\n }\n } catch (error: any) {\n if (error.code === 'SQLITE_CONSTRAINT_PRIMARYKEY') {\n const primaryColumns = columns.filter(\n (column) => column.primary,\n );\n task.logWarning(\n `Duplicate values for primary key (${primaryColumns.map((column) => column.name).join(', ')}) found in ${filename}. Set the \\`ignoreDuplicates\\` option to true in config.json to ignore this error`,\n );\n }\n\n task.logWarning(\n `Check ${filename} for invalid data on line ${rowNumber + 1}.`,\n );\n throw error;\n }\n }\n });\n\n if (model.filenameExtension === 'txt') {\n const parser = parse({\n columns: true,\n relax_quotes: true,\n trim: true,\n skip_empty_lines: true,\n ...task.csvOptions,\n });\n\n let lines: { [x: string]: any; geojson?: string }[] = [];\n\n parser.on('readable', () => {\n let record;\n\n while ((record = parser.read())) {\n totalLineCount += 1;\n lines.push(formatGtfsLine(record, model, totalLineCount));\n\n if (lines.length >= BATCH_SIZE) {\n try {\n insertLines(lines);\n lines = [];\n } catch (error) {\n reject(error);\n }\n\n task.log(\n `Importing - ${filename} - ${totalLineCount} lines imported\\r`,\n true,\n );\n }\n }\n });\n\n parser.on('end', () => {\n try {\n if (lines.length > 0) {\n try {\n insertLines(lines);\n } catch (error) {\n reject(error);\n }\n }\n task.log(\n `Importing - ${filename} - ${totalLineCount} lines imported\\r`,\n true,\n );\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n\n parser.on('error', reject);\n\n createReadStream(filepath).pipe(stripBomStream()).pipe(parser);\n } else if (model.filenameExtension === 'geojson') {\n readFile(filepath, 'utf8')\n .then((data) => {\n if (isValidJSON(data) === false) {\n reject(new Error(`Invalid JSON in ${filename}`));\n }\n totalLineCount += 1;\n const line = formatGtfsLine(\n { geojson: data },\n model,\n totalLineCount,\n );\n insertLines([line]);\n task.log(\n `Importing - ${filename} - ${totalLineCount} lines imported\\r`,\n true,\n );\n resolve();\n })\n .catch(reject);\n } else {\n reject(\n new Error(`Unsupported file type: ${model.filenameExtension}`),\n );\n }\n }),\n );\n\nexport async function importGtfs(initialConfig: Config): Promise<void> {\n const timer = new Timer();\n timer.start();\n\n const config = setDefaultConfig(initialConfig);\n validateConfigForImport(config);\n\n try {\n const db = openDb(config);\n const agencyCount = config.agencies.length;\n\n log(config)(\n `Starting GTFS import for ${pluralize('file', agencyCount, true)} using SQLite database at ${config.sqlitePath}`,\n );\n\n createGtfsTables(db);\n\n await mapSeries(config.agencies, async (agency: ConfigAgency) => {\n try {\n const tempPath = temporaryDirectory();\n\n const task = {\n exclude: agency.exclude,\n url: agency.url,\n headers: agency.headers,\n realtimeAlerts: agency.realtimeAlerts,\n realtimeTripUpdates: agency.realtimeTripUpdates,\n realtimeVehiclePositions: agency.realtimeVehiclePositions,\n downloadDir: tempPath,\n downloadTimeout: config.downloadTimeout,\n gtfsRealtimeExpirationSeconds: config.gtfsRealtimeExpirationSeconds,\n path: agency.path,\n csvOptions: config.csvOptions || {},\n ignoreDuplicates: config.ignoreDuplicates,\n ignoreErrors: config.ignoreErrors,\n sqlitePath: config.sqlitePath,\n prefix: agency.prefix,\n currentTimestamp: Math.floor(Date.now() / 1000),\n log: log(config),\n logWarning: logWarning(config),\n logError: logError(config),\n };\n\n if (task.url) {\n await downloadGtfsFiles(task);\n }\n\n await extractGtfsFiles(task);\n await importGtfsFiles(db, task);\n await updateGtfsRealtimeData(task);\n\n await rm(tempPath, { recursive: true });\n } catch (error: any) {\n if (config.ignoreErrors) {\n logError(config)(error.message);\n } else {\n throw error;\n }\n }\n });\n\n log(config)(`Creating DB indexes`);\n createGtfsIndexes(db);\n\n const seconds = Math.round(timer.time() / 1000);\n timer.stop();\n\n log(config)(\n `Completed GTFS import for ${pluralize('agency', agencyCount, true)} in ${seconds} seconds\\n`,\n );\n } catch (error: any) {\n if (error?.code === 'SQLITE_CANTOPEN') {\n logError(config)(\n `Unable to open sqlite database \"${config.sqlitePath}\" defined as \\`sqlitePath\\` config.json. Ensure the parent directory exists or remove \\`sqlitePath\\` from config.json.`,\n );\n }\n throw error;\n }\n}\n","export { agency } from './gtfs/agency.ts';\nexport { areas } from './gtfs/areas.ts';\nexport { attributions } from './gtfs/attributions.ts';\nexport { bookingRules } from './gtfs/booking-rules.ts';\nexport { calendarDates } from './gtfs/calendar-dates.ts';\nexport { calendar } from './gtfs/calendar.ts';\nexport { fareAttributes } from './gtfs/fare-attributes.ts';\nexport { fareLegRules } from './gtfs/fare-leg-rules.ts';\nexport { fareMedia } from './gtfs/fare-media.ts';\nexport { fareProducts } from './gtfs/fare-products.ts';\nexport { fareRules } from './gtfs/fare-rules.ts';\nexport { fareTransferRules } from './gtfs/fare-transfer-rules.ts';\nexport { feedInfo } from './gtfs/feed-info.ts';\nexport { frequencies } from './gtfs/frequencies.ts';\nexport { levels } from './gtfs/levels.ts';\nexport { locationGroups } from './gtfs/location-groups.ts';\nexport { locationGroupStops } from './gtfs/location-group-stops.ts';\nexport { locations } from './gtfs/locations.ts';\nexport { networks } from './gtfs/networks.ts';\nexport { pathways } from './gtfs/pathways.ts';\nexport { routeNetworks } from './gtfs/route-networks.ts';\nexport { routes } from './gtfs/routes.ts';\nexport { shapes } from './gtfs/shapes.ts';\nexport { stopAreas } from './gtfs/stop-areas.ts';\nexport { stopTimes } from './gtfs/stop-times.ts';\nexport { stops } from './gtfs/stops.ts';\nexport { timeframes } from './gtfs/timeframes.ts';\nexport { transfers } from './gtfs/transfers.ts';\nexport { translations } from './gtfs/translations.ts';\nexport { trips } from './gtfs/trips.ts';\n\nexport { timetables } from './non-standard/timetables.ts';\nexport { timetablePages } from './non-standard/timetable-pages.ts';\nexport { timetableStopOrder } from './non-standard/timetable-stop-order.ts';\nexport { timetableNotes } from './non-standard/timetable-notes.ts';\nexport { timetableNotesReferences } from './non-standard/timetable-notes-references.ts';\nexport { tripsDatedVehicleJourney } from './non-standard/trips-dated-vehicle-journey.ts';\n\nexport { calendarAttributes } from './gtfs-plus/calendar-attributes.ts';\nexport { directions } from './gtfs-plus/directions.ts';\nexport { routeAttributes } from './gtfs-plus/route-attributes.ts';\nexport { stopAttributes } from './gtfs-plus/stop-attributes.ts';\n\nexport { boardAlight } from './gtfs-ride/board-alight.ts';\nexport { riderTrip } from './gtfs-ride/rider-trip.ts';\nexport { ridership } from './gtfs-ride/ridership.ts';\nexport { tripCapacity } from './gtfs-ride/trip-capacity.ts';\nexport { rideFeedInfo } from './gtfs-ride/ride-feed-info.ts';\n\nexport { tripUpdates } from './gtfs-realtime/trip-updates.ts';\nexport { stopTimeUpdates } from './gtfs-realtime/stop-time-updates.ts';\nexport { vehiclePositions } from './gtfs-realtime/vehicle-positions.ts';\nexport { serviceAlerts } from './gtfs-realtime/service-alerts.ts';\nexport { serviceAlertTargets } from './gtfs-realtime/service-alert-targets.ts';\n\nexport { deadheadTimes } from './ods/deadhead-times.ts';\nexport { deadheads } from './ods/deadheads.ts';\nexport { opsLocations } from './ods/ops-locations.ts';\nexport { runEvents } from './ods/run-events.ts';\nexport { runsPieces } from './ods/runs-pieces.ts';\n","export const agency = {\n filenameBase: 'agency',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'agency_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'agency_name',\n type: 'text',\n required: true,\n nocase: true,\n },\n {\n name: 'agency_url',\n type: 'text',\n required: true,\n },\n {\n name: 'agency_timezone',\n type: 'text',\n required: true,\n },\n {\n name: 'agency_lang',\n type: 'text',\n nocase: true,\n },\n {\n name: 'agency_phone',\n type: 'text',\n nocase: true,\n },\n {\n name: 'agency_fare_url',\n type: 'text',\n },\n {\n name: 'agency_email',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const areas = {\n filenameBase: 'areas',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'area_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'area_name',\n type: 'text',\n },\n ],\n};\n","export const attributions = {\n filenameBase: 'attributions',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'attribution_id',\n type: 'text',\n prefix: true,\n primary: true,\n },\n {\n name: 'agency_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'route_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'trip_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'organization_name',\n type: 'text',\n required: true,\n nocase: true,\n },\n {\n name: 'is_producer',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'is_operator',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'is_authority',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'attribution_url',\n type: 'text',\n },\n {\n name: 'attribution_email',\n type: 'text',\n nocase: true,\n },\n {\n name: 'attribution_phone',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const bookingRules = {\n filenameBase: 'booking_rules',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'booking_rule_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'booking_type',\n type: 'integer',\n required: true,\n min: 0,\n max: 2,\n },\n {\n name: 'prior_notice_duration_min',\n type: 'integer',\n min: 0,\n },\n {\n name: 'prior_notice_duration_max',\n type: 'integer',\n min: 0,\n },\n {\n name: 'prior_notice_last_day',\n type: 'integer',\n min: 0,\n },\n {\n name: 'prior_notice_last_time',\n type: 'time',\n },\n {\n name: 'prior_notice_start_day',\n type: 'integer',\n min: 0,\n },\n {\n name: 'prior_notice_start_time',\n type: 'time',\n },\n {\n name: 'prior_notice_service_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'message',\n type: 'text',\n nocase: true,\n },\n {\n name: 'pickup_message',\n type: 'text',\n nocase: true,\n },\n {\n name: 'drop_off_message',\n type: 'text',\n nocase: true,\n },\n {\n name: 'phone_number',\n type: 'text',\n nocase: true,\n },\n {\n name: 'info_url',\n type: 'text',\n },\n {\n name: 'booking_url',\n type: 'text',\n },\n ],\n};\n","export const calendarDates = {\n filenameBase: 'calendar_dates',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'service_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'date',\n type: 'date',\n required: true,\n primary: true,\n },\n {\n name: 'exception_type',\n type: 'integer',\n required: true,\n min: 1,\n max: 2,\n index: true,\n },\n {\n name: 'holiday_name',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const calendar = {\n filenameBase: 'calendar',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'service_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'monday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'tuesday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'wednesday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'thursday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'friday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'saturday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'sunday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'start_date',\n type: 'date',\n required: true,\n index: true,\n },\n {\n name: 'end_date',\n type: 'date',\n required: true,\n index: true,\n },\n ],\n};\n","export const fareAttributes = {\n filenameBase: 'fare_attributes',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'fare_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'price',\n type: 'real',\n required: true,\n },\n {\n name: 'currency_type',\n type: 'text',\n required: true,\n },\n {\n name: 'payment_method',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'transfers',\n type: 'integer',\n min: 0,\n max: 2,\n },\n {\n name: 'agency_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'transfer_duration',\n type: 'integer',\n min: 0,\n },\n ],\n};\n","export const fareLegRules = {\n filenameBase: 'fare_leg_rules',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'leg_group_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'network_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'from_area_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'to_area_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'from_timeframe_group_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'to_timeframe_group_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'fare_product_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'rule_priority',\n type: 'integer',\n min: 0,\n },\n ],\n};\n","export const fareMedia = {\n filenameBase: 'fare_media',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'fare_media_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'fare_media_name',\n type: 'text',\n },\n {\n name: 'fare_media_type',\n type: 'integer',\n required: true,\n min: 0,\n max: 4,\n },\n ],\n};\n","export const fareProducts = {\n filenameBase: 'fare_products',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'fare_product_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'fare_product_name',\n type: 'text',\n },\n {\n name: 'fare_media_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'amount',\n type: 'real',\n required: true,\n },\n {\n name: 'currency',\n type: 'text',\n required: true,\n },\n ],\n};\n","export const fareRules = {\n filenameBase: 'fare_rules',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'fare_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'route_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'origin_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'destination_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'contains_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n ],\n};\n","export const fareTransferRules = {\n filenameBase: 'fare_transfer_rules',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'from_leg_group_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'to_leg_group_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'transfer_count',\n type: 'integer',\n min: -1,\n primary: true,\n },\n {\n name: 'duration_limit',\n type: 'integer',\n min: 0,\n primary: true,\n },\n {\n name: 'duration_limit_type',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'fare_transfer_type',\n type: 'integer',\n min: 0,\n max: 2,\n required: true,\n },\n {\n name: 'fare_product_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n ],\n};\n","export const feedInfo = {\n filenameBase: 'feed_info',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'feed_publisher_name',\n type: 'text',\n required: true,\n nocase: true,\n },\n {\n name: 'feed_publisher_url',\n type: 'text',\n required: true,\n },\n {\n name: 'feed_lang',\n type: 'text',\n required: true,\n },\n {\n name: 'default_lang',\n type: 'text',\n nocase: true,\n },\n {\n name: 'feed_start_date',\n type: 'date',\n },\n {\n name: 'feed_end_date',\n type: 'date',\n },\n {\n name: 'feed_version',\n type: 'text',\n },\n {\n name: 'feed_contact_email',\n type: 'text',\n nocase: true,\n },\n {\n name: 'feed_contact_url',\n type: 'text',\n },\n ],\n};\n","export const frequencies = {\n filenameBase: 'frequencies',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'trip_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'start_time',\n type: 'time',\n required: true,\n primary: true,\n },\n {\n name: 'end_time',\n type: 'time',\n required: true,\n },\n {\n name: 'headway_secs',\n type: 'integer',\n required: true,\n min: 0,\n },\n {\n name: 'exact_times',\n type: 'integer',\n min: 0,\n max: 1,\n },\n ],\n};\n","export const levels = {\n filenameBase: 'levels',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'level_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'level_index',\n type: 'real',\n required: true,\n },\n {\n name: 'level_name',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const locationGroups = {\n filenameBase: 'location_groups',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'location_group_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'location_group_name',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const locationGroupStops = {\n filenameBase: 'location_group_stops',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'location_group_id',\n type: 'text',\n prefix: true,\n index: true,\n required: true,\n primary: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n required: true,\n prefix: true,\n index: true,\n primary: true,\n },\n ],\n};\n","export const locations = {\n filenameBase: 'locations',\n filenameExtension: 'geojson',\n schema: [\n {\n name: 'geojson',\n type: 'text',\n },\n ],\n};\n","export const networks = {\n filenameBase: 'networks',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'network_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'network_name',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const pathways = {\n filenameBase: 'pathways',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'pathway_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'from_stop_id',\n type: 'text',\n required: true,\n prefix: true,\n },\n {\n name: 'to_stop_id',\n type: 'text',\n required: true,\n prefix: true,\n },\n {\n name: 'pathway_mode',\n type: 'integer',\n required: true,\n min: 1,\n max: 7,\n },\n {\n name: 'is_bidirectional',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'length',\n type: 'real',\n min: 0,\n },\n {\n name: 'traversal_time',\n type: 'integer',\n min: 0,\n },\n {\n name: 'stair_count',\n type: 'integer',\n },\n {\n name: 'max_slope',\n type: 'real',\n },\n {\n name: 'min_width',\n type: 'real',\n min: 0,\n },\n {\n name: 'signposted_as',\n type: 'text',\n nocase: true,\n },\n {\n name: 'reversed_signposted_as',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const routeNetworks = {\n filenameBase: 'route_networks',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'network_id',\n type: 'text',\n required: true,\n prefix: true,\n },\n {\n name: 'route_id',\n type: 'text',\n primary: true,\n index: true,\n prefix: true,\n },\n ],\n};\n","export const routes = {\n filenameBase: 'routes',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'route_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'agency_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'route_short_name',\n type: 'text',\n nocase: true,\n },\n {\n name: 'route_long_name',\n type: 'text',\n nocase: true,\n },\n {\n name: 'route_desc',\n type: 'text',\n nocase: true,\n },\n {\n name: 'route_type',\n type: 'integer',\n required: true,\n min: 0,\n // Support extended GTFS route types with no max value\n // https://developers.google.com/transit/gtfs/reference/extended-route-types\n },\n {\n name: 'route_url',\n type: 'text',\n },\n {\n name: 'route_color',\n type: 'text',\n nocase: true,\n },\n {\n name: 'route_text_color',\n type: 'text',\n nocase: true,\n },\n {\n name: 'route_sort_order',\n type: 'integer',\n min: 0,\n },\n {\n name: 'continuous_pickup',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'continuous_drop_off',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'network_id',\n type: 'text',\n prefix: true,\n },\n ],\n};\n","export const shapes = {\n filenameBase: 'shapes',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'shape_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'shape_pt_lat',\n type: 'real',\n required: true,\n min: -90,\n max: 90,\n },\n {\n name: 'shape_pt_lon',\n type: 'real',\n required: true,\n min: -180,\n max: 180,\n },\n {\n name: 'shape_pt_sequence',\n type: 'integer',\n required: true,\n primary: true,\n min: 0,\n },\n {\n name: 'shape_dist_traveled',\n type: 'real',\n min: 0,\n },\n ],\n};\n","export const stopAreas = {\n filenameBase: 'stop_areas',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'area_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n ],\n};\n","export const stopTimes = {\n filenameBase: 'stop_times',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'trip_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'arrival_time',\n type: 'time',\n },\n {\n name: 'departure_time',\n type: 'time',\n },\n {\n name: 'location_group_id',\n type: 'text',\n prefix: true,\n index: true,\n },\n {\n name: 'location_id',\n type: 'text',\n prefix: true,\n index: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n required: true,\n prefix: true,\n index: true,\n },\n {\n name: 'stop_sequence',\n type: 'integer',\n required: true,\n primary: true,\n min: 0,\n },\n {\n name: 'stop_headsign',\n type: 'text',\n nocase: true,\n },\n {\n name: 'start_pickup_drop_off_window',\n type: 'time',\n },\n {\n name: 'pickup_type',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'drop_off_type',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'continuous_pickup',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'continuous_drop_off',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'shape_dist_traveled',\n type: 'real',\n min: 0,\n },\n {\n name: 'timepoint',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'pickup_booking_rule_id',\n type: 'text',\n prefix: true,\n index: true,\n },\n {\n name: 'drop_off_booking_rule_id',\n type: 'text',\n prefix: true,\n index: true,\n },\n ],\n};\n","export const stops = {\n filenameBase: 'stops',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'stop_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'stop_code',\n type: 'text',\n },\n {\n name: 'stop_name',\n type: 'text',\n nocase: true,\n },\n {\n name: 'tts_stop_name',\n type: 'text',\n nocase: true,\n },\n {\n name: 'stop_desc',\n type: 'text',\n nocase: true,\n },\n {\n name: 'stop_lat',\n type: 'real',\n min: -90,\n max: 90,\n },\n {\n name: 'stop_lon',\n type: 'real',\n min: -180,\n max: 180,\n },\n {\n name: 'zone_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'stop_url',\n type: 'text',\n },\n {\n name: 'location_type',\n type: 'integer',\n min: 0,\n max: 4,\n },\n {\n name: 'parent_station',\n type: 'text',\n index: true,\n },\n {\n name: 'stop_timezone',\n type: 'text',\n },\n {\n name: 'wheelchair_boarding',\n type: 'integer',\n min: 0,\n max: 2,\n },\n {\n name: 'level_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'platform_code',\n type: 'text',\n },\n ],\n};\n","export const timeframes = {\n filenameBase: 'timeframes',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'timeframe_group_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'start_time',\n type: 'time',\n primary: true,\n },\n {\n name: 'end_time',\n type: 'time',\n primary: true,\n },\n {\n name: 'service_id',\n type: 'text',\n required: true,\n primary: true,\n index: true,\n prefix: true,\n },\n ],\n};\n","export const transfers = {\n filenameBase: 'transfers',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'from_stop_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'to_stop_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'from_route_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'to_route_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'from_trip_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'to_trip_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'transfer_type',\n type: 'integer',\n min: 0,\n max: 5,\n default: 0,\n },\n {\n name: 'min_transfer_time',\n type: 'integer',\n min: 0,\n },\n ],\n};\n","export const translations = {\n filenameBase: 'translations',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'table_name',\n type: 'text',\n primary: true,\n required: true,\n },\n {\n name: 'field_name',\n type: 'text',\n primary: true,\n required: true,\n },\n {\n name: 'language',\n type: 'text',\n primary: true,\n required: true,\n },\n {\n name: 'translation',\n type: 'text',\n required: true,\n },\n {\n name: 'record_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'record_sub_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'field_value',\n type: 'text',\n primary: true,\n },\n ],\n};\n","export const trips = {\n filenameBase: 'trips',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'route_id',\n type: 'text',\n required: true,\n index: true,\n prefix: true,\n },\n {\n name: 'service_id',\n type: 'text',\n required: true,\n index: true,\n prefix: true,\n },\n {\n name: 'trip_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'trip_headsign',\n type: 'text',\n nocase: true,\n },\n {\n name: 'trip_short_name',\n type: 'text',\n nocase: true,\n },\n {\n name: 'direction_id',\n type: 'integer',\n min: 0,\n max: 1,\n index: true,\n },\n {\n name: 'block_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'shape_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'wheelchair_accessible',\n type: 'integer',\n min: 0,\n max: 2,\n },\n {\n name: 'bikes_allowed',\n type: 'integer',\n min: 0,\n max: 2,\n },\n ],\n};\n","export const timetables = {\n filenameBase: 'timetables',\n filenameExtension: 'txt',\n nonstandard: true,\n schema: [\n {\n name: 'timetable_id',\n type: 'text',\n prefix: true,\n required: true,\n primary: true,\n },\n {\n name: 'route_id',\n type: 'text',\n prefix: true,\n required: true,\n primary: true,\n },\n {\n name: 'direction_id',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'start_date',\n type: 'date',\n },\n {\n name: 'end_date',\n type: 'date',\n },\n {\n name: 'monday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'tuesday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'wednesday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'thursday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'friday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'saturday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'sunday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'start_time',\n type: 'time',\n },\n {\n name: 'end_time',\n type: 'time',\n },\n {\n name: 'timetable_label',\n type: 'text',\n nocase: true,\n },\n {\n name: 'service_notes',\n type: 'text',\n nocase: true,\n },\n {\n name: 'orientation',\n type: 'text',\n },\n {\n name: 'timetable_page_id',\n type: 'text',\n },\n {\n name: 'timetable_sequence',\n type: 'integer',\n min: 0,\n index: true,\n },\n {\n name: 'direction_name',\n type: 'text',\n },\n {\n name: 'include_exceptions',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'show_trip_continuation',\n type: 'integer',\n min: 0,\n max: 1,\n },\n ],\n};\n","export const timetablePages = {\n filenameBase: 'timetable_pages',\n filenameExtension: 'txt',\n nonstandard: true,\n schema: [\n {\n name: 'timetable_page_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'timetable_page_label',\n type: 'text',\n },\n {\n name: 'filename',\n type: 'text',\n },\n ],\n};\n","export const timetableStopOrder = {\n filenameBase: 'timetable_stop_order',\n filenameExtension: 'txt',\n nonstandard: true,\n schema: [\n {\n name: 'timetable_id',\n type: 'text',\n index: true,\n prefix: true,\n required: true,\n primary: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n prefix: true,\n required: true,\n primary: true,\n },\n {\n name: 'stop_sequence',\n type: 'integer',\n min: 0,\n index: true,\n required: true,\n primary: true,\n },\n ],\n};\n","export const timetableNotes = {\n filenameBase: 'timetable_notes',\n filenameExtension: 'txt',\n nonstandard: true,\n schema: [\n {\n name: 'note_id',\n type: 'text',\n primary: true,\n prefix: true,\n required: true,\n },\n {\n name: 'symbol',\n type: 'text',\n },\n {\n name: 'note',\n type: 'text',\n nocase: true,\n required: true,\n },\n ],\n};\n","export const timetableNotesReferences = {\n filenameBase: 'timetable_notes_references',\n filenameExtension: 'txt',\n nonstandard: true,\n schema: [\n {\n name: 'note_id',\n type: 'text',\n prefix: true,\n required: true,\n primary: true,\n },\n {\n name: 'timetable_id',\n type: 'text',\n prefix: true,\n primary: true,\n },\n {\n name: 'route_id',\n type: 'text',\n prefix: true,\n primary: true,\n },\n {\n name: 'trip_id',\n type: 'text',\n prefix: true,\n primary: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n prefix: true,\n primary: true,\n },\n {\n name: 'stop_sequence',\n type: 'integer',\n min: 0,\n primary: true,\n },\n {\n name: 'show_on_stoptime',\n type: 'integer',\n min: 0,\n max: 1,\n },\n ],\n};\n","export const tripsDatedVehicleJourney = {\n filenameBase: 'trips_dated_vehicle_journey',\n filenameExtension: 'txt',\n nonstandard: true,\n schema: [\n {\n name: 'trip_id',\n type: 'text',\n required: true,\n index: true,\n prefix: true,\n },\n {\n name: 'operating_day_date',\n type: 'text',\n index: true,\n required: true,\n },\n {\n name: 'dated_vehicle_journey_gid',\n type: 'text',\n required: true,\n },\n {\n name: 'journey_number',\n type: 'integer',\n min: 0,\n max: 65535,\n index: true,\n },\n ],\n};\n","export const calendarAttributes = {\n filenameBase: 'calendar_attributes',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-plus',\n schema: [\n {\n name: 'service_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'service_description',\n type: 'text',\n required: true,\n nocase: true,\n },\n ],\n};\n","export const directions = {\n filenameBase: 'directions',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-plus',\n schema: [\n {\n name: 'route_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'direction_id',\n type: 'integer',\n min: 0,\n max: 1,\n primary: true,\n },\n {\n name: 'direction',\n type: 'text',\n required: true,\n },\n ],\n};\n","export const routeAttributes = {\n filenameBase: 'route_attributes',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-plus',\n schema: [\n {\n name: 'route_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'category',\n type: 'integer',\n min: 0,\n required: true,\n },\n {\n name: 'subcategory',\n type: 'integer',\n min: 101,\n required: true,\n },\n {\n name: 'running_way',\n type: 'integer',\n min: 1,\n required: true,\n },\n ],\n};\n","export const stopAttributes = {\n filenameBase: 'stop_attributes',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-plus',\n schema: [\n {\n name: 'stop_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'accessibility_id',\n type: 'integer',\n min: 0,\n },\n {\n name: 'cardinal_direction',\n type: 'text',\n },\n {\n name: 'relative_position',\n type: 'text',\n },\n {\n name: 'stop_city',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const boardAlight = {\n filenameBase: 'board_alight',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-ride',\n schema: [\n {\n name: 'trip_id',\n type: 'text',\n required: true,\n index: true,\n prefix: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n required: true,\n index: true,\n prefix: true,\n },\n {\n name: 'stop_sequence',\n type: 'integer',\n required: true,\n min: 0,\n index: true,\n },\n {\n name: 'record_use',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n index: true,\n },\n {\n name: 'schedule_relationship',\n type: 'integer',\n min: 0,\n max: 8,\n },\n {\n name: 'boardings',\n type: 'integer',\n min: 0,\n },\n {\n name: 'alightings',\n type: 'integer',\n min: 0,\n },\n {\n name: 'current_load',\n type: 'integer',\n min: 0,\n },\n {\n name: 'load_count',\n type: 'integer',\n min: 0,\n },\n {\n name: 'load_type',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'rack_down',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'bike_boardings',\n type: 'integer',\n min: 0,\n },\n {\n name: 'bike_alightings',\n type: 'integer',\n min: 0,\n },\n {\n name: 'ramp_used',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'ramp_boardings',\n type: 'integer',\n min: 0,\n },\n {\n name: 'ramp_alightings',\n type: 'integer',\n min: 0,\n },\n {\n name: 'service_date',\n type: 'date',\n index: true,\n },\n {\n name: 'service_arrival_time',\n type: 'time',\n },\n {\n name: 'service_departure_time',\n type: 'time',\n },\n {\n name: 'source',\n type: 'integer',\n min: 0,\n max: 4,\n },\n ],\n};\n","export const riderTrip = {\n filenameBase: 'rider_trip',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-ride',\n schema: [\n {\n name: 'rider_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'agency_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'trip_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'boarding_stop_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'boarding_stop_sequence',\n type: 'integer',\n min: 0,\n index: true,\n },\n {\n name: 'alighting_stop_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'alighting_stop_sequence',\n type: 'integer',\n min: 0,\n index: true,\n },\n {\n name: 'service_date',\n type: 'date',\n index: true,\n },\n {\n name: 'boarding_time',\n type: 'time',\n },\n {\n name: 'alighting_time',\n type: 'time',\n },\n {\n name: 'rider_type',\n type: 'integer',\n min: 0,\n max: 13,\n },\n {\n name: 'rider_type_description',\n type: 'text',\n },\n {\n name: 'fare_paid',\n type: 'real',\n },\n {\n name: 'transaction_type',\n type: 'integer',\n min: 0,\n max: 8,\n },\n {\n name: 'fare_media',\n type: 'integer',\n min: 0,\n max: 9,\n },\n {\n name: 'accompanying_device',\n type: 'integer',\n min: 0,\n max: 6,\n },\n {\n name: 'transfer_status',\n type: 'integer',\n min: 0,\n max: 1,\n },\n ],\n};\n","export const ridership = {\n filenameBase: 'ridership',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-ride',\n schema: [\n {\n name: 'total_boardings',\n type: 'integer',\n min: 0,\n required: true,\n },\n {\n name: 'total_alightings',\n type: 'integer',\n min: 0,\n required: true,\n },\n {\n name: 'ridership_start_date',\n type: 'date',\n index: true,\n },\n {\n name: 'ridership_end_date',\n type: 'date',\n index: true,\n },\n {\n name: 'ridership_start_time',\n type: 'time',\n },\n {\n name: 'ridership_end_time',\n type: 'time',\n },\n {\n name: 'service_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'monday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'tuesday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'wednesday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'thursday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'friday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'saturday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'sunday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'agency_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'route_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'direction_id',\n type: 'integer',\n min: 0,\n max: 1,\n index: true,\n },\n {\n name: 'trip_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n prefix: true,\n },\n ],\n};\n","export const tripCapacity = {\n filenameBase: 'trip_capacity',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-ride',\n schema: [\n {\n name: 'agency_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'trip_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'service_date',\n type: 'date',\n index: true,\n },\n {\n name: 'vehicle_description',\n type: 'text',\n },\n {\n name: 'seated_capacity',\n type: 'integer',\n min: 0,\n },\n {\n name: 'standing_capacity',\n type: 'integer',\n min: 0,\n },\n {\n name: 'wheelchair_capacity',\n type: 'integer',\n min: 0,\n },\n {\n name: 'bike_capacity',\n type: 'integer',\n min: 0,\n },\n ],\n};\n","export const rideFeedInfo = {\n filenameBase: 'ride_feed_info',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-ride',\n schema: [\n {\n name: 'ride_files',\n type: 'integer',\n min: 0,\n max: 6,\n required: true,\n },\n {\n name: 'ride_start_date',\n type: 'date',\n index: true,\n },\n {\n name: 'ride_end_date',\n type: 'date',\n index: true,\n },\n {\n name: 'gtfs_feed_date',\n type: 'date',\n index: true,\n },\n {\n name: 'default_currency_type',\n type: 'text',\n },\n {\n name: 'ride_feed_version',\n type: 'text',\n },\n ],\n};\n","export const tripUpdates = {\n filenameBase: 'trip_updates',\n extension: 'gtfs-realtime',\n schema: [\n {\n name: 'id',\n type: 'text',\n required: true,\n primary: true,\n index: true,\n source: 'id',\n },\n {\n name: 'vehicle_id',\n type: 'text',\n index: true,\n source: 'tripUpdate.vehicle.id',\n default: null,\n },\n {\n name: 'trip_id',\n type: 'text',\n index: true,\n source: 'tripUpdate.trip.tripId',\n default: null,\n },\n {\n name: 'trip_start_time',\n type: 'text',\n source: 'tripUpdate.trip.startTime',\n default: null,\n },\n {\n name: 'direction_id',\n type: 'integer',\n source: 'tripUpdate.trip.directionId',\n default: null,\n },\n {\n name: 'route_id',\n type: 'text',\n index: true,\n source: 'tripUpdate.trip.routeId',\n default: null,\n },\n {\n name: 'start_date',\n type: 'text',\n source: 'tripUpdate.trip.startDate',\n default: null,\n },\n {\n name: 'timestamp',\n type: 'text',\n source: 'tripUpdate.timestamp',\n default: null,\n },\n {\n name: 'schedule_relationship',\n type: 'text',\n source: 'tripUpdate.trip.scheduleRelationship',\n default: null,\n },\n {\n name: 'created_timestamp',\n type: 'integer',\n required: true,\n },\n {\n name: 'expiration_timestamp',\n type: 'integer',\n required: true,\n },\n ],\n};\n","export const stopTimeUpdates = {\n filenameBase: 'stop_time_updates',\n extension: 'gtfs-realtime',\n schema: [\n {\n name: 'trip_id',\n type: 'text',\n index: true,\n source: 'parent.tripUpdate.trip.tripId',\n default: null,\n },\n {\n name: 'trip_start_time',\n type: 'text',\n source: 'parent.tripUpdate.trip.startTime',\n default: null,\n },\n {\n name: 'direction_id',\n type: 'integer',\n source: 'parent.tripUpdate.trip.directionId',\n default: null,\n },\n {\n name: 'route_id',\n type: 'text',\n index: true,\n source: 'parent.tripUpdate.trip.routeId',\n default: null,\n },\n {\n name: 'stop_id',\n type: 'text',\n index: true,\n source: 'stopId',\n default: null,\n },\n {\n name: 'stop_sequence',\n type: 'integer',\n source: 'stopSequence',\n default: null,\n },\n {\n name: 'arrival_delay',\n type: 'integer',\n source: 'arrival.delay',\n default: null,\n },\n {\n name: 'departure_delay',\n type: 'integer',\n source: 'departure.delay',\n default: null,\n },\n {\n name: 'departure_timestamp',\n type: 'text',\n source: 'departure.time',\n default: null,\n },\n {\n name: 'arrival_timestamp',\n type: 'text',\n source: 'arrival.time',\n default: null,\n },\n {\n name: 'schedule_relationship',\n type: 'text',\n source: 'scheduleRelationship',\n default: null,\n },\n {\n name: 'created_timestamp',\n type: 'integer',\n required: true,\n },\n {\n name: 'expiration_timestamp',\n type: 'integer',\n required: true,\n },\n ],\n};\n","export const vehiclePositions = {\n filenameBase: 'vehicle_positions',\n extension: 'gtfs-realtime',\n schema: [\n {\n name: 'id',\n type: 'text',\n required: true,\n primary: true,\n index: true,\n source: 'id',\n },\n {\n name: 'bearing',\n type: 'real',\n source: 'vehicle.position.bearing',\n default: null,\n },\n {\n name: 'latitude',\n type: 'real',\n min: -90,\n max: 90,\n source: 'vehicle.position.latitude',\n default: null,\n },\n {\n name: 'longitude',\n type: 'real',\n source: 'vehicle.position.longitude',\n min: -180,\n max: 180,\n default: null,\n },\n {\n name: 'speed',\n type: 'real',\n min: 0,\n source: 'vehicle.position.speed',\n default: null,\n },\n {\n name: 'current_stop_sequence',\n type: 'integer',\n source: 'vehicle.currentStopSequence',\n default: null,\n },\n {\n name: 'trip_id',\n type: 'text',\n index: true,\n source: 'vehicle.trip.tripId',\n default: null,\n },\n {\n name: 'trip_start_date',\n type: 'text',\n index: true,\n source: 'vehicle.trip.startDate',\n default: null,\n },\n {\n name: 'trip_start_time',\n type: 'text',\n index: true,\n source: 'vehicle.trip.startTime',\n default: null,\n },\n {\n name: 'congestion_level',\n type: 'text',\n source: 'vehicle.congestionLevel',\n default: null,\n },\n {\n name: 'occupancy_status',\n type: 'text',\n source: 'vehicle.occupancyStatus',\n default: null,\n },\n {\n name: 'occupancy_percentage',\n type: 'integer',\n source: 'vehicle.occupancyPercentage',\n default: null,\n },\n {\n name: 'vehicle_stop_status',\n type: 'text',\n source: 'vehicle.vehicleStopStatus',\n default: null,\n },\n {\n name: 'vehicle_id',\n type: 'text',\n index: true,\n source: 'vehicle.vehicle.id',\n default: null,\n },\n {\n name: 'vehicle_label',\n type: 'text',\n source: 'vehicle.vehicle.label',\n default: null,\n },\n {\n name: 'vehicle_license_plate',\n type: 'text',\n source: 'vehicle.vehicle.licensePlate',\n default: null,\n },\n {\n name: 'vehicle_wheelchair_accessible',\n type: 'text',\n source: 'vehicle.vehicle.wheelchairAccessible',\n default: null,\n },\n {\n name: 'timestamp',\n type: 'text',\n source: 'vehicle.timestamp',\n default: null,\n },\n {\n name: 'created_timestamp',\n type: 'integer',\n required: true,\n },\n {\n name: 'expiration_timestamp',\n type: 'integer',\n required: true,\n },\n ],\n};\n","export const serviceAlerts = {\n filenameBase: 'service_alerts',\n extension: 'gtfs-realtime',\n schema: [\n {\n name: 'id',\n type: 'text',\n required: true,\n primary: true,\n index: true,\n source: 'id',\n },\n {\n name: 'active_period',\n type: 'json',\n source: 'alert.activePeriod',\n },\n {\n name: 'cause',\n type: 'text',\n source: 'alert.cause',\n },\n {\n name: 'effect',\n type: 'text',\n source: 'alert.effect',\n },\n {\n name: 'url',\n type: 'text',\n source: 'alert.url.translation[0].text',\n default: '',\n },\n {\n name: 'start_time',\n type: 'text',\n required: true,\n source: 'alert.activePeriod[0].start',\n default: '',\n },\n {\n name: 'end_time',\n type: 'text',\n required: true,\n source: 'alert.activePeriod[0].end',\n default: '',\n },\n {\n name: 'header_text',\n type: 'text',\n required: true,\n source: 'alert.headerText.translation[0].text',\n default: '',\n },\n {\n name: 'description_text',\n type: 'text',\n required: true,\n source: 'alert.descriptionText.translation[0].text',\n default: '',\n },\n {\n name: 'tts_header_text',\n type: 'text',\n source: 'alert.ttsHeaderText.translation[0].text',\n },\n {\n name: 'tts_description_text',\n type: 'text',\n source: 'alert.ttsDescriptionText.translation[0].text',\n },\n {\n name: 'severity_level',\n type: 'text',\n source: 'alert.severityLevel',\n },\n {\n name: 'created_timestamp',\n type: 'integer',\n required: true,\n },\n {\n name: 'expiration_timestamp',\n type: 'integer',\n required: true,\n },\n ],\n};\n","export const serviceAlertTargets = {\n filenameBase: 'service_alert_targets',\n extension: 'gtfs-realtime',\n schema: [\n {\n name: 'alert_id',\n type: 'text',\n required: true,\n primary: true,\n source: 'parent.id',\n },\n {\n name: 'stop_id',\n type: 'text',\n index: true,\n source: 'stopId',\n default: null,\n },\n {\n name: 'route_id',\n type: 'text',\n index: true,\n source: 'routeId',\n default: null,\n },\n {\n name: 'created_timestamp',\n type: 'integer',\n required: true,\n },\n {\n name: 'expiration_timestamp',\n type: 'integer',\n required: true,\n },\n ],\n};\n","export const deadheadTimes = {\n filenameBase: 'deadhead_times',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'ods',\n schema: [\n {\n name: 'deadhead_id',\n type: 'text',\n required: true,\n index: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'arrival_time',\n type: 'time',\n required: true,\n },\n {\n name: 'departure_time',\n type: 'time',\n required: true,\n },\n {\n name: 'ops_location_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'location_sequence',\n type: 'integer',\n required: true,\n primary: true,\n min: 0,\n index: true,\n },\n {\n name: 'shape_dist_traveled',\n type: 'real',\n min: 0,\n },\n ],\n};\n","export const deadheads = {\n filenameBase: 'deadheads',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'ods',\n schema: [\n {\n name: 'deadhead_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'service_id',\n type: 'text',\n required: true,\n prefix: true,\n },\n {\n name: 'block_id',\n type: 'text',\n required: true,\n index: true,\n prefix: true,\n },\n {\n name: 'shape_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'to_trip_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'from_trip_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'to_deadhead_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'from_deadhead_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n ],\n};\n","export const opsLocations = {\n filenameBase: 'ops_locations',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'ods',\n schema: [\n {\n name: 'ops_location_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'ops_location_code',\n type: 'text',\n },\n {\n name: 'ops_location_name',\n type: 'text',\n required: true,\n nocase: true,\n },\n {\n name: 'ops_location_desc',\n type: 'text',\n nocase: true,\n },\n {\n name: 'ops_location_lat',\n type: 'real',\n required: true,\n min: -90,\n max: 90,\n },\n {\n name: 'ops_location_lon',\n type: 'real',\n required: true,\n min: -180,\n max: 180,\n },\n ],\n};\n","export const runEvents = {\n filenameBase: 'run_event',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'ods',\n schema: [\n {\n name: 'run_event_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'piece_id',\n type: 'text',\n required: true,\n prefix: true,\n },\n {\n name: 'event_type',\n type: 'integer',\n required: true,\n min: 0,\n index: true,\n },\n {\n name: 'event_name',\n type: 'text',\n nocase: true,\n },\n {\n name: 'event_time',\n type: 'text',\n required: true,\n },\n {\n name: 'event_duration',\n type: 'integer',\n required: true,\n min: 0,\n },\n {\n name: 'event_from_location_type',\n type: 'integer',\n min: 0,\n max: 1,\n index: true,\n },\n {\n name: 'event_from_location_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'event_to_location_type',\n type: 'integer',\n min: 0,\n max: 1,\n index: true,\n },\n {\n name: 'event_to_location_id',\n type: 'text',\n prefix: true,\n },\n ],\n};\n","export const runsPieces = {\n filenameBase: 'runs_pieces',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'ods',\n schema: [\n {\n name: 'run_id',\n type: 'text',\n required: true,\n },\n {\n name: 'piece_id',\n type: 'text',\n primary: true,\n required: true,\n },\n {\n name: 'start_type',\n type: 'integer',\n required: true,\n min: 0,\n max: 2,\n index: true,\n },\n {\n name: 'start_trip_id',\n type: 'text',\n required: true,\n index: true,\n },\n {\n name: 'start_trip_position',\n type: 'integer',\n min: 0,\n },\n {\n name: 'end_type',\n type: 'integer',\n required: true,\n min: 0,\n max: 2,\n index: true,\n },\n {\n name: 'end_trip_id',\n type: 'text',\n required: true,\n index: true,\n },\n {\n name: 'end_trip_position',\n type: 'integer',\n min: 0,\n },\n ],\n};\n","import fs from 'fs';\n\nimport Database from 'better-sqlite3';\nimport untildify from 'untildify';\n\nconst dbs: { [key: string]: Database.Database } = {};\n\nfunction setupDb(sqlitePath: string) {\n const db = new Database(untildify(sqlitePath));\n db.pragma('journal_mode = OFF');\n db.pragma('synchronous = OFF');\n db.pragma('temp_store = MEMORY');\n dbs[sqlitePath] = db;\n\n return db;\n}\n\nexport function openDb(\n config: { db?: Database.Database; sqlitePath?: string } | null = null,\n): Database.Database {\n // If config is passed, use that to open or return db\n if (config) {\n const { sqlitePath = ':memory:', db } = config;\n\n // If db connection is passed, use it\n if (db) {\n return db;\n }\n\n // If db connection already exists, return it\n if (dbs[sqlitePath]) {\n return dbs[sqlitePath];\n }\n\n // If no db connection exists, create it\n return setupDb(sqlitePath);\n }\n\n // If no db connection exists, create a new one in memory\n if (Object.keys(dbs).length === 0) {\n return setupDb(':memory:');\n }\n\n // If only one db connection already exists, use it\n if (Object.keys(dbs).length === 1) {\n const filename = Object.keys(dbs)[0];\n return dbs[filename];\n }\n\n if (Object.keys(dbs).length > 1) {\n throw new Error(\n 'Multiple databases open, please specify which one to use.',\n );\n }\n\n throw new Error('Unable to find database connection.');\n}\n\nexport function closeDb(db: Database.Database | null = null): void {\n if (Object.keys(dbs).length === 0) {\n throw new Error(\n 'No database connection. Call `openDb(config)` before using any methods.',\n );\n }\n\n if (!db) {\n if (Object.keys(dbs).length > 1) {\n throw new Error(\n 'Multiple database connections. Pass the db you want to close as a parameter to `closeDb`.',\n );\n }\n\n db = dbs[Object.keys(dbs)[0]];\n }\n\n db.close();\n delete dbs[db.name];\n}\n\nexport function deleteDb(db: Database.Database | null = null): void {\n if (Object.keys(dbs).length === 0) {\n throw new Error(\n 'No database connection. Call `openDb(config)` before using any methods.',\n );\n }\n\n if (!db) {\n if (Object.keys(dbs).length > 1) {\n throw new Error(\n 'Multiple database connections. Pass the db you want to delete as a parameter to `deleteDb`.',\n );\n }\n\n db = dbs[Object.keys(dbs)[0]];\n }\n\n db.close();\n\n fs.unlinkSync(db.name);\n\n delete dbs[db.name];\n}\n","import {\n cloneDeep,\n compact,\n filter,\n groupBy,\n last,\n omit,\n sortBy,\n omitBy,\n} from 'lodash-es';\nimport { feature, featureCollection } from '@turf/helpers';\nimport { Shape, Stop } from '../types/global_interfaces.ts';\n\n/** Represents a GeoJSON coordinate pair [longitude, latitude] */\ntype Position = [number, number];\n\n/**\n * Validates if a string is valid JSON\n * @param {string} string - The string to validate as JSON\n * @returns {boolean} True if string is valid JSON, false otherwise\n * @example\n * isValidJSON('{\"key\": \"value\"}') // returns true\n * isValidJSON('invalid json') // returns false\n */\nexport function isValidJSON(string: string): boolean {\n try {\n JSON.parse(string);\n return true;\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Validates if an array of positions forms a valid LineString\n * @param {Position[]} [lineString] - Array of coordinate pairs\n * @returns {boolean} True if lineString is valid, false otherwise\n */\nfunction isValidLineString(lineString?: Position[]): boolean {\n if (!lineString || lineString.length <= 1) {\n return false;\n }\n\n // Reject linestrings with two identical points\n if (lineString.length === 2) {\n const [[x1, y1], [x2, y2]] = lineString;\n return !(x1 === x2 && y1 === y2);\n }\n\n return true;\n}\n\n/**\n * Consolidates shape groups into unique line segments\n * @param {Shape[][]} shapeGroups - Array of shape point groups\n * @returns {Position[][]} Array of consolidated line strings\n */\nfunction consolidateShapes(shapeGroups: Shape[][]): Position[][] {\n const keys = new Set<string>();\n const segmentsArray = shapeGroups.map((shapes) =>\n shapes.reduce<Position[][]>((memo, point, idx) => {\n if (idx > 0) {\n const prevPoint = shapes[idx - 1];\n memo.push([\n [prevPoint.shape_pt_lon, prevPoint.shape_pt_lat],\n [point.shape_pt_lon, point.shape_pt_lat],\n ]);\n }\n return memo;\n }, []),\n );\n\n const consolidatedLineStrings: Position[][] = [];\n\n for (const segments of segmentsArray) {\n consolidatedLineStrings.push([]);\n\n for (const segment of segments) {\n const key1 = segment.flat().join(',');\n const key2 = segment.reverse().flat().join(',');\n const currentLine = last(consolidatedLineStrings);\n\n if (!currentLine || keys.has(key1) || keys.has(key2)) {\n consolidatedLineStrings.push([]);\n continue;\n }\n\n if (currentLine.length === 0) {\n currentLine.push(segment[0]);\n }\n currentLine.push(segment[1]);\n keys.add(key1);\n keys.add(key2);\n }\n }\n\n return filter(consolidatedLineStrings, isValidLineString);\n}\n\n/**\n * Formats a color string to hex format\n * @param {string | null | undefined} color - Color string to format\n * @returns {string | undefined} Formatted hex color or undefined\n * @example\n * formatHexColor('FF0000') // returns '#FF0000'\n */\nfunction formatHexColor(color: string | null | undefined): string | undefined {\n if (!color) return undefined;\n return `#${color}`;\n}\n\n/**\n * Formats properties object by cleaning null values and formatting colors\n * @param {Record<string, any>} properties - Properties object to format\n * @returns {Record<string, any>} Formatted properties object\n */\nfunction formatProperties(\n properties: Record<string, any>,\n): Record<string, any> {\n const formattedProperties = cloneDeep(\n omitBy(properties, (value) => value == null),\n );\n\n const formattedRouteColor = formatHexColor(properties.route_color);\n const formattedRouteTextColor = formatHexColor(properties.route_text_color);\n\n if (formattedRouteColor) {\n formattedProperties.route_color = formattedRouteColor;\n }\n\n if (formattedRouteTextColor) {\n formattedProperties.route_text_color = formattedRouteTextColor;\n }\n\n if (properties.routes) {\n formattedProperties.routes = properties.routes.map(\n (route: Record<string, any>) => formatProperties(route),\n );\n }\n\n return formattedProperties;\n}\n\n/**\n * Converts GTFS shapes to GeoJSON Feature\n * @param {Shape[]} shapes - Array of GTFS shapes\n * @param {Record<string, any>} [properties={}] - Properties to add to the feature\n * @returns {Feature} GeoJSON Feature with MultiLineString geometry\n */\nexport function shapesToGeoJSONFeature(\n shapes: Shape[],\n properties: Record<string, any> = {},\n) {\n const shapeGroups = Object.values(groupBy(shapes, 'shape_id')).map(\n (shapeGroup) => sortBy(shapeGroup, 'shape_pt_sequence'),\n );\n\n const lineStrings = consolidateShapes(shapeGroups);\n\n return feature(\n {\n type: 'MultiLineString',\n coordinates: lineStrings,\n },\n formatProperties(properties),\n );\n}\n\n/**\n * Converts GTFS stops to GeoJSON FeatureCollection\n * @param {Stop[]} stops - Array of GTFS stops\n * @returns {FeatureCollection} GeoJSON FeatureCollection of Point features\n */\nexport function stopsToGeoJSONFeatureCollection(stops: Stop[]) {\n const features = compact(\n stops.map((stop) => {\n if (!stop.stop_lon || !stop.stop_lat) {\n return undefined;\n }\n\n return feature(\n {\n type: 'Point',\n coordinates: [stop.stop_lon, stop.stop_lat],\n },\n formatProperties(omit(stop, ['stop_lat', 'stop_lon'])),\n );\n }),\n );\n\n return featureCollection(features);\n}\n","import pluralize from 'pluralize';\nimport GtfsRealtimeBindings from 'gtfs-realtime-bindings';\nimport sqlString from 'sqlstring-sqlite';\nimport mapSeries from 'promise-map-series';\n\nimport * as models from '../models/models.ts';\nimport { openDb } from './db.ts';\nimport { log, logError, logWarning } from './log-utils.ts';\nimport {\n convertLongTimeToDate,\n setDefaultConfig,\n validateConfigForImport,\n} from './utils.ts';\n\nimport {\n Config,\n ConfigAgency,\n ModelColumn,\n} from '../types/global_interfaces.ts';\n\ninterface GtfsRealtimeTask {\n realtimeAlerts?: {\n url: string;\n headers?: Record<string, string>;\n };\n realtimeTripUpdates?: {\n url: string;\n headers?: Record<string, string>;\n };\n realtimeVehiclePositions?: {\n url: string;\n headers?: Record<string, string>;\n };\n downloadTimeout?: number;\n gtfsRealtimeExpirationSeconds: number;\n ignoreErrors: boolean;\n sqlitePath: string;\n currentTimestamp: number;\n log: (message: string, newLine?: boolean) => void;\n logWarning: (message: string) => void;\n logError: (message: string) => void;\n}\n\nfunction getNestedProperty(obj: any, defaultValue: any, path?: string) {\n if (path === undefined) return defaultValue;\n const arr = path.split('.');\n while (arr.length) {\n const nextKey = arr.shift();\n if (nextKey === undefined) {\n return defaultValue;\n } else if (obj == null) {\n return defaultValue;\n } else if (nextKey?.includes('[')) {\n const arrayKey = nextKey.match(/(\\w*)\\[(\\d+)\\]/);\n if (arrayKey === null) {\n return defaultValue;\n }\n if (obj[arrayKey[1]] === undefined) {\n return defaultValue;\n }\n\n if (obj[arrayKey[1]][arrayKey[2]] === undefined) {\n return defaultValue;\n }\n\n obj = obj[arrayKey[1]][arrayKey[2]];\n } else {\n if (obj[nextKey] === undefined) {\n return defaultValue;\n }\n obj = obj[nextKey];\n }\n }\n\n if (obj?.__isLong__) return convertLongTimeToDate(obj);\n\n return obj;\n}\n\nasync function fetchGtfsRealtimeData(\n urlConfig: { url: string; headers?: Record<string, string> },\n task: GtfsRealtimeTask,\n) {\n task.log(`Downloading GTFS-Realtime from ${urlConfig.url}`);\n const response = await fetch(urlConfig.url, {\n method: 'GET',\n headers: {\n ...(urlConfig.headers ?? {}),\n 'Accept-Encoding': 'gzip',\n },\n signal: task.downloadTimeout\n ? AbortSignal.timeout(task.downloadTimeout)\n : undefined,\n });\n\n if (response.status !== 200) {\n task.logWarning(\n `Unable to download GTFS-Realtime from ${urlConfig.url}. Got status ${response.status}.`,\n );\n return null;\n }\n\n const buffer = await response.arrayBuffer();\n const message = GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(\n new Uint8Array(buffer),\n );\n return GtfsRealtimeBindings.transit_realtime.FeedMessage.toObject(message, {\n enums: String,\n longs: String,\n bytes: String,\n defaults: true,\n arrays: true,\n objects: true,\n oneofs: true,\n });\n}\n\nfunction removeExpiredRealtimeData(config: Config) {\n const db = openDb(config);\n\n log(config)(`Removing expired GTFS-Realtime data`);\n db.prepare(\n `DELETE FROM vehicle_positions WHERE expiration_timestamp <= strftime('%s','now')`,\n ).run();\n db.prepare(\n `DELETE FROM trip_updates WHERE expiration_timestamp <= strftime('%s','now')`,\n ).run();\n db.prepare(\n `DELETE FROM stop_time_updates WHERE expiration_timestamp <= strftime('%s','now')`,\n ).run();\n db.prepare(\n `DELETE FROM service_alerts WHERE expiration_timestamp <= strftime('%s','now')`,\n ).run();\n db.prepare(\n `DELETE FROM service_alert_targets WHERE expiration_timestamp <= strftime('%s','now')`,\n ).run();\n log(config)(`Removed expired GTFS-Realtime data\\r`, true);\n}\n\nfunction prepareRealtimeFieldValue(\n entity: any,\n column: ModelColumn,\n task: GtfsRealtimeTask,\n) {\n if (column.name === 'created_timestamp') {\n return task.currentTimestamp;\n }\n\n if (column.name === 'expiration_timestamp') {\n return task.currentTimestamp + task.gtfsRealtimeExpirationSeconds;\n }\n\n const value = getNestedProperty(entity, column.default, column.source);\n\n if (column.type === 'json') {\n return sqlString.escape(JSON.stringify(value));\n }\n\n return sqlString.escape(value);\n}\n\nasync function processRealtimeAlerts(\n db: any,\n gtfsRealtimeData: any,\n task: GtfsRealtimeTask,\n) {\n task.log(`Download successful`);\n\n let totalLineCount = 0;\n\n for (const entity of gtfsRealtimeData.entity) {\n // Do base processing\n const fieldValues = (models.serviceAlerts.schema as ModelColumn[]).map(\n (column) => prepareRealtimeFieldValue(entity, column, task),\n );\n\n try {\n db.prepare(\n `REPLACE INTO ${models.serviceAlerts.filenameBase} (${models.serviceAlerts.schema\n .map((column) => column.name)\n .join(', ')}) VALUES (${fieldValues.join(', ')})`,\n ).run();\n } catch (error: any) {\n task.logWarning(`Import error: ${error.message}`);\n }\n\n if (\n !entity.alert.informedEntity ||\n entity.alert.informedEntity.length === 0\n ) {\n task.logWarning(\n `Import error: No informed entities found for alert id=${entity.id}`,\n );\n } else {\n const alertTargetArray = [];\n for (const informedEntity of entity.alert.informedEntity) {\n informedEntity.parent = entity;\n const subValues = (\n models.serviceAlertTargets.schema as ModelColumn[]\n ).map((column) =>\n prepareRealtimeFieldValue(informedEntity, column, task),\n );\n alertTargetArray.push(`(${subValues.join(', ')})`);\n totalLineCount++;\n }\n\n try {\n db.prepare(\n `REPLACE INTO ${models.serviceAlertTargets.filenameBase} (${models.serviceAlertTargets.schema\n .map((column) => column.name)\n .join(', ')}) VALUES ${alertTargetArray.join(', ')}`,\n ).run();\n } catch (error: any) {\n task.logWarning(`Import error: ${error.message}`);\n }\n }\n\n task.log(`Importing - ${totalLineCount++} entries imported\\r`, true);\n }\n}\n\nasync function processRealtimeTripUpdates(\n db: any,\n gtfsRealtimeData: any,\n task: GtfsRealtimeTask,\n) {\n task.log(`Download successful`);\n\n let totalLineCount = 0;\n\n for (const entity of gtfsRealtimeData.entity) {\n // Do base processing\n const fieldValues = (models.tripUpdates.schema as ModelColumn[]).map(\n (column) => prepareRealtimeFieldValue(entity, column, task),\n );\n\n try {\n db.prepare(\n `REPLACE INTO ${models.tripUpdates.filenameBase} (${models.tripUpdates.schema\n .map((column) => column.name)\n .join(', ')}) VALUES (${fieldValues.join(', ')})`,\n ).run();\n } catch (error: any) {\n task.logWarning(`Import error: ${error.message}`);\n }\n\n const stopTimeUpdateArray = [];\n for (const stopTimeUpdate of entity.tripUpdate.stopTimeUpdate) {\n stopTimeUpdate.parent = entity;\n const subValues = (models.stopTimeUpdates.schema as ModelColumn[]).map(\n (column) => prepareRealtimeFieldValue(stopTimeUpdate, column, task),\n );\n stopTimeUpdateArray.push(`(${subValues.join(', ')})`);\n totalLineCount++;\n }\n\n try {\n db.prepare(\n `REPLACE INTO ${models.stopTimeUpdates.filenameBase} (${models.stopTimeUpdates.schema\n .map((column) => column.name)\n .join(', ')}) VALUES ${stopTimeUpdateArray.join(', ')}`,\n ).run();\n } catch (error: any) {\n task.logWarning(`Import error: ${error.message}`);\n }\n\n task.log(`Importing - ${totalLineCount++} entries imported\\r`, true);\n }\n}\n\nasync function processRealtimeVehiclePositions(\n db: any,\n gtfsRealtimeData: any,\n task: GtfsRealtimeTask,\n) {\n task.log(`Download successful`);\n\n let totalLineCount = 0;\n\n for (const entity of gtfsRealtimeData.entity) {\n // Do base processing\n const fieldValues = (models.vehiclePositions.schema as ModelColumn[]).map(\n (column) => prepareRealtimeFieldValue(entity, column, task),\n );\n\n try {\n db.prepare(\n `REPLACE INTO ${models.vehiclePositions.filenameBase} (${models.vehiclePositions.schema\n .map((column) => column.name)\n .join(', ')}) VALUES (${fieldValues.join(', ')})`,\n ).run();\n } catch (error: any) {\n task.logWarning(`Import error: ${error.message}`);\n }\n\n task.log(`Importing - ${totalLineCount++} entries imported\\r`, true);\n }\n}\n\nexport async function updateGtfsRealtimeData(task: GtfsRealtimeTask) {\n if (\n task.realtimeAlerts === undefined &&\n task.realtimeTripUpdates === undefined &&\n task.realtimeVehiclePositions === undefined\n ) {\n return;\n }\n\n const db = openDb({ sqlitePath: task.sqlitePath });\n\n if (task.realtimeAlerts?.url) {\n try {\n const alertsData = await fetchGtfsRealtimeData(task.realtimeAlerts, task);\n if (alertsData?.entity) {\n await processRealtimeAlerts(db, alertsData, task);\n }\n } catch (error: any) {\n if (task.ignoreErrors) {\n task.logError(error.message);\n } else {\n throw error;\n }\n }\n }\n\n if (task.realtimeTripUpdates?.url) {\n try {\n const tripUpdatesData = await fetchGtfsRealtimeData(\n task.realtimeTripUpdates,\n task,\n );\n if (tripUpdatesData?.entity) {\n await processRealtimeTripUpdates(db, tripUpdatesData, task);\n }\n } catch (error: any) {\n if (task.ignoreErrors) {\n task.logError(error.message);\n } else {\n throw error;\n }\n }\n }\n\n if (task.realtimeVehiclePositions?.url) {\n try {\n const vehiclePositionsData = await fetchGtfsRealtimeData(\n task.realtimeVehiclePositions,\n task,\n );\n if (vehiclePositionsData?.entity) {\n await processRealtimeVehiclePositions(db, vehiclePositionsData, task);\n }\n } catch (error: any) {\n if (task.ignoreErrors) {\n task.logError(error.message);\n } else {\n throw error;\n }\n }\n }\n\n task.log(`GTFS-Realtime data import complete`);\n}\n\nexport async function updateGtfsRealtime(initialConfig: Config) {\n const config = setDefaultConfig(initialConfig);\n validateConfigForImport(config);\n\n try {\n openDb(config);\n\n const agencyCount = config.agencies.length;\n log(config)(\n `Starting GTFS-Realtime refresh for ${pluralize(\n 'agencies',\n agencyCount,\n true,\n )} using SQLite database at ${config.sqlitePath}`,\n );\n\n removeExpiredRealtimeData(config);\n\n await mapSeries(config.agencies, async (agency: ConfigAgency) => {\n try {\n const task = {\n realtimeAlerts: agency.realtimeAlerts,\n realtimeTripUpdates: agency.realtimeTripUpdates,\n realtimeVehiclePositions: agency.realtimeVehiclePositions,\n downloadTimeout: config.downloadTimeout,\n gtfsRealtimeExpirationSeconds: config.gtfsRealtimeExpirationSeconds,\n ignoreErrors: config.ignoreErrors,\n sqlitePath: config.sqlitePath,\n currentTimestamp: Math.floor(Date.now() / 1000),\n log: log(config),\n logWarning: logWarning(config),\n logError: logError(config),\n };\n\n await updateGtfsRealtimeData(task);\n } catch (error: any) {\n if (config.ignoreErrors) {\n logError(config)(error.message);\n } else {\n throw error;\n }\n }\n });\n\n log(config)(\n `Completed GTFS-Realtime refresh for ${pluralize(\n 'agencies',\n agencyCount,\n true,\n )}\\n`,\n );\n } catch (error: any) {\n if (error?.code === 'SQLITE_CANTOPEN') {\n logError(config)(\n `Unable to open sqlite database \"${config.sqlitePath}\" defined as \\`sqlitePath\\` config.json. Ensure the parent directory exists or remove \\`sqlitePath\\` from config.json.`,\n );\n }\n throw error;\n }\n}\n","import sqlString from 'sqlstring-sqlite';\nimport Long from 'long';\nimport {\n Config,\n JoinOptions,\n SqlWhere,\n SqlValue,\n SqlOrderBy,\n} from '../types/global_interfaces.ts';\n\n/**\n * Validates the configuration object for GTFS import\n * @param config The configuration object to validate\n * @throws Error if agencies are missing or if agency lacks both url and path\n * @returns The validated config object\n */\nexport function validateConfigForImport(config: Config) {\n if (!config.agencies || config.agencies.length === 0) {\n throw new Error('No `agencies` specified in config');\n }\n\n for (const [index, agency] of config.agencies.entries()) {\n if (!agency.path && !agency.url) {\n throw new Error(\n `No Agency \\`url\\` or \\`path\\` specified in config for agency index ${index}.`,\n );\n }\n }\n\n return config;\n}\n\n/**\n * Initializes configuration with default values\n * @param initialConfig The user-provided configuration\n * @returns Merged configuration with defaults\n */\nexport function setDefaultConfig(initialConfig: Config) {\n const defaults = {\n sqlitePath: ':memory:',\n ignoreDuplicates: false,\n ignoreErrors: false,\n gtfsRealtimeExpirationSeconds: 0,\n verbose: true,\n };\n\n return {\n ...defaults,\n ...initialConfig,\n };\n}\n\n/**\n * Converts a Long timestamp to ISO date string\n * @param longDate Object containing high, low, and unsigned values\n * @returns ISO formatted date string\n */\nexport function convertLongTimeToDate(longDate: {\n high: number;\n low: number;\n unsigned: boolean;\n}) {\n const { high, low, unsigned } = longDate;\n return new Date(\n Long.fromBits(low, high, unsigned).toNumber() * 1000,\n ).toISOString();\n}\n\n/**\n * Converts time string in HH:mm:ss format to seconds since midnight\n * @param time Time string in HH:mm:ss format\n * @returns Number of seconds since midnight, or null if invalid format\n */\nexport function calculateSecondsFromMidnight(time: string): number | null {\n if (!time || typeof time !== 'string') {\n return null;\n }\n\n const [hours, minutes, seconds] = time.split(':').map(Number);\n\n if ([hours, minutes, seconds].some(isNaN) || minutes >= 60 || seconds >= 60) {\n return null;\n }\n\n return hours * 3600 + minutes * 60 + seconds;\n}\n\n/**\n * Ensures time components have leading zeros (e.g., \"9:5:1\" -> \"09:05:01\")\n * @param time Time string in HH:mm:ss format\n * @returns Formatted time string with leading zeros, or null if invalid format\n */\nexport function padLeadingZeros(time: string) {\n const split = time.split(':').map((d) => String(Number(d)).padStart(2, '0'));\n if (split.length !== 3) {\n return null;\n }\n\n return split.join(':');\n}\n\n/**\n * Formats SQL SELECT clause from array of field names or field mapping object\n * @param fields Array of field names or object mapping source to alias\n * @returns Formatted SELECT clause\n */\nexport function formatSelectClause(fields: string[]) {\n if (Array.isArray(fields)) {\n const selectItem =\n fields.length > 0\n ? fields.map((fieldName) => sqlString.escapeId(fieldName)).join(', ')\n : '*';\n return `SELECT ${selectItem}`;\n }\n\n const selectItem = Object.entries(fields)\n .map(\n (key) => `${sqlString.escapeId(key[0])} AS ${sqlString.escapeId(key[1])}`,\n )\n .join(', ');\n return `SELECT ${selectItem}`;\n}\n\n/**\n * Formats SQL JOIN clause from array of join configurations\n * @param joinObject Array of join options\n * @returns Formatted JOIN clause\n */\nexport function formatJoinClause(joinObject: JoinOptions[]) {\n return joinObject\n .map(\n (data) =>\n `${data.type ? data.type + ' JOIN' : 'INNER JOIN'} ${sqlString.escapeId(\n data.table,\n )} ON ${data.on}`,\n )\n .join(' ');\n}\n\n/**\n * Converts degrees to radians\n * @param angle Angle in degrees\n * @returns Angle in radians\n */\nfunction degree2radian(angle: number) {\n return (angle * Math.PI) / 180;\n}\n\n/**\n * Converts radians to degrees\n * @param angle Angle in radians\n * @returns Angle in degrees\n */\nfunction radian2degree(angle: number) {\n return (angle / Math.PI) * 180;\n}\n\nconst EARTH_RADIUS_METERS = 6371000;\n\n/**\n * Creates SQL WHERE clause for geographic bounding box search\n * @param latitudeDegree Center latitude in degrees\n * @param longitudeDegree Center longitude in degrees\n * @param boundingBoxSideMeters Size of bounding box in meters\n * @returns SQL WHERE clause for bounding box search\n */\nexport function formatWhereClauseBoundingBox(\n latitudeDegree: number | string,\n longitudeDegree: number | string,\n boundingBoxSideMeters: number,\n): string {\n const lat = Number(latitudeDegree);\n const lon = Number(longitudeDegree);\n\n if (\n isNaN(lat) ||\n isNaN(lon) ||\n lat < -90 ||\n lat > 90 ||\n lon < -180 ||\n lon > 180\n ) {\n throw new Error('Invalid latitude or longitude values');\n }\n\n const latitudeRadian = degree2radian(lat);\n const radiusFromLatitude = Math.cos(latitudeRadian) * EARTH_RADIUS_METERS;\n\n const halfSide = boundingBoxSideMeters / 2;\n const deltaLatitude = radian2degree(halfSide / EARTH_RADIUS_METERS);\n const deltaLongitude = radian2degree(halfSide / radiusFromLatitude);\n\n return [\n `stop_lat BETWEEN ${lat - deltaLatitude} AND ${lat + deltaLatitude}`,\n `stop_lon BETWEEN ${lon - deltaLongitude} AND ${lon + deltaLongitude}`,\n ].join(' AND ');\n}\n\n/**\n * Formats SQL WHERE clause for a single key-value pair\n * @param key Column name\n * @param value Single value, array of values, or null\n * @returns Formatted WHERE clause condition\n */\nexport function formatWhereClause(\n key: string,\n value: null | SqlValue | SqlValue[],\n) {\n if (Array.isArray(value)) {\n let whereClause = `${sqlString.escapeId(key)} IN (${value\n .filter((v) => v !== null)\n .map((v) => sqlString.escape(v))\n .join(', ')})`;\n\n if (value.includes(null)) {\n whereClause = `(${whereClause} OR ${sqlString.escapeId(key)} IS NULL)`;\n }\n\n return whereClause;\n }\n\n if (value === null) {\n return `${sqlString.escapeId(key)} IS NULL`;\n }\n\n return `${sqlString.escapeId(key)} = ${sqlString.escape(value)}`;\n}\n\n/**\n * Formats complete SQL WHERE clause from query object\n * @param query Object containing column-value pairs\n * @returns Formatted WHERE clause or empty string if no conditions\n */\nexport function formatWhereClauses(query: SqlWhere) {\n if (Object.keys(query).length === 0) {\n return '';\n }\n\n const whereClauses = Object.entries(query).map(([key, value]) =>\n formatWhereClause(key, value),\n );\n return `WHERE ${whereClauses.join(' AND ')}`;\n}\n\n/**\n * Formats SQL ORDER BY clause from array of sorting criteria\n * @param orderBy Array of [column, direction] tuples\n * @returns Formatted ORDER BY clause\n */\nexport function formatOrderByClause(orderBy: SqlOrderBy) {\n let orderByClause = '';\n\n if (orderBy.length > 0) {\n orderByClause += 'ORDER BY ';\n\n orderByClause += orderBy\n .map(([key, value]) => {\n const direction = value === 'DESC' ? 'DESC' : 'ASC';\n return `${sqlString.escapeId(key)} ${direction}`;\n })\n .join(', ');\n }\n\n return orderByClause;\n}\n\n/**\n * Gets day of week name from YYYYMMDD date number\n * @param date Date in YYYYMMDD format\n * @returns Lowercase day name (sunday-saturday)\n */\nexport function getDayOfWeekFromDate(date: number): string {\n const DAYS_OF_WEEK = [\n 'sunday',\n 'monday',\n 'tuesday',\n 'wednesday',\n 'thursday',\n 'friday',\n 'saturday',\n ] as const;\n\n if (!Number.isInteger(date) || date.toString().length !== 8) {\n throw new Error('Date must be in YYYYMMDD format');\n }\n\n const year = Math.floor(date / 10000);\n const month = Math.floor((date % 10000) / 100);\n const day = date % 100;\n\n const dateObj = new Date(year, month - 1, day);\n\n if (dateObj.toString() === 'Invalid Date') {\n throw new Error('Invalid date');\n }\n\n return DAYS_OF_WEEK[dateObj.getDay()];\n}\n\n/**\n * Formats a numeric value according to the decimal precision rules of the specified currency,\n * without any currency symbols or separators.\n * @param value The numeric value to format (e.g., 10.5)\n * @param currency The ISO 4217 currency code (e.g., 'USD', 'JPY', 'EUR')\n * @returns The formatted string with appropriate decimal places\n * Examples:\n * - formatCurrency(10.5, 'USD') => '10.50' // USD uses 2 decimal places\n * - formatCurrency(10.5, 'JPY') => '10' // JPY uses 0 decimal places\n * - formatCurrency(10.523, 'BHD') => '10.523' // BHD uses 3 decimal places\n */\nexport function formatCurrency(value: number, currency: string) {\n const parts = new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency,\n }).formatToParts(value);\n\n const integerPart =\n parts.find((part) => part.type === 'integer')?.value ?? '0';\n const fractionPart =\n parts.find((part) => part.type === 'fraction')?.value ?? '';\n\n return `${integerPart}${fractionPart !== '' ? `.${fractionPart}` : ''}`;\n}\n\n/**\n * Gets the timestamp column name for a given column name\n * @param columnName The column name\n * @returns The timestamp column name\n */\nexport function getTimestampColumnName(columnName: string) {\n return columnName.endsWith('time')\n ? `${columnName}stamp`\n : `${columnName}_timestamp`;\n}\n","import path from 'node:path';\nimport { writeFile } from 'node:fs/promises';\n\nimport { without, compact } from 'lodash-es';\nimport pluralize from 'pluralize';\nimport { stringify } from 'csv-stringify';\nimport sqlString from 'sqlstring-sqlite';\nimport Database from 'better-sqlite3';\nimport mapSeries from 'promise-map-series';\nimport untildify from 'untildify';\n\nimport * as models from '../models/models.ts';\nimport { openDb } from './db.ts';\nimport { prepDirectory, generateFolderName } from './file-utils.ts';\nimport { log, logWarning } from './log-utils.ts';\nimport { formatCurrency, setDefaultConfig } from './utils.ts';\n\nimport { Config, Model } from '../types/global_interfaces.ts';\n\nconst getAgencies = (db: Database.Database, config: Config) => {\n try {\n return db.prepare('SELECT agency_name FROM agency;').all() as {\n agency_name: string;\n }[];\n } catch (error) {\n if (config.sqlitePath === ':memory:') {\n throw new Error(\n 'No agencies found in SQLite. You are using an in-memory database - if running this from command line be sure to specify a value for `sqlitePath` in config.json other than \":memory:\".',\n );\n }\n\n throw new Error(\n 'No agencies found in SQLite. Be sure to first import data into SQLite using `gtfs-import` or `importGtfs(config);`',\n );\n }\n};\n\nexport const exportGtfs = async (initialConfig: Config) => {\n const config = setDefaultConfig(initialConfig);\n const db = openDb(config);\n\n // Get agency name for export folder from first line of agency.txt\n\n const agencies = getAgencies(db, config);\n const agencyCount = agencies.length;\n if (agencyCount === 0) {\n throw new Error(\n 'No agencies found in SQLite. Be sure to first import data into SQLite using `gtfs-import` or `importGtfs(config);`',\n );\n } else if (agencyCount > 1) {\n logWarning(config)(\n 'More than one agency is defined in config.json. Export will merge all into one GTFS file.',\n );\n }\n\n log(config)(\n `Starting GTFS export for ${pluralize(\n 'agency',\n agencyCount,\n true,\n )} using SQLite database at ${config.sqlitePath}`,\n );\n\n const folderName = generateFolderName(agencies[0].agency_name);\n const defaultExportPath = path.join(process.cwd(), 'gtfs-export', folderName);\n const exportPath = untildify(config.exportPath || defaultExportPath);\n\n await prepDirectory(exportPath);\n\n // Loop through each GTFS file\n const modelsToExport = (Object.values(models) as Model[]).filter(\n (model) => model.extension !== 'gtfs-realtime',\n );\n const exportedFiles = await mapSeries(\n modelsToExport,\n async (model: Model) => {\n const filePath = path.join(\n exportPath,\n `${model.filenameBase}.${model.filenameExtension}`,\n );\n const tableName = sqlString.escapeId(model.filenameBase);\n const lines = db.prepare(`SELECT * FROM ${tableName};`).all() as Array<\n Record<string, any>\n >;\n\n if (!lines || lines.length === 0) {\n if (!model.nonstandard) {\n log(config)(\n `Skipping (no data) - ${model.filenameBase}.${model.filenameExtension}\\r`,\n );\n }\n\n return;\n }\n\n if (model.filenameExtension === 'txt') {\n const excludeColumns = [];\n\n // If no routes have values for agency_id, add it to the excludeColumns list\n if (model.filenameBase === 'routes') {\n const routesWithAgencyId = db\n .prepare(\n 'SELECT agency_id FROM routes WHERE agency_id IS NOT NULL;',\n )\n .all();\n if (!routesWithAgencyId || routesWithAgencyId.length === 0) {\n excludeColumns.push('agency_id');\n }\n } else if (model.filenameBase === 'fare_attributes') {\n for (const line of lines) {\n line.price = formatCurrency(line.price, line.currency_type);\n }\n } else if (model.filenameBase === 'fare_products') {\n for (const line of lines) {\n line.amount = formatCurrency(line.amount, line.currency);\n }\n }\n\n const columns = without(\n model.schema.map((column) => column.name),\n ...excludeColumns,\n );\n const fileText = await stringify(lines, { columns, header: true });\n await writeFile(filePath, fileText);\n } else if (model.filenameExtension === 'geojson') {\n const fileText = lines?.[0].geojson ?? '';\n await writeFile(filePath, fileText);\n } else {\n throw new Error(\n `Unexpected filename extension: ${model.filenameExtension}`,\n );\n }\n\n log(config)(\n `Exporting - ${model.filenameBase}.${model.filenameExtension}\\r`,\n );\n\n return `${model.filenameBase}.${model.filenameExtension}`;\n },\n );\n\n if (compact(exportedFiles).length === 0) {\n log(config)(\n 'No GTFS data exported. Be sure to first import data into SQLite.',\n );\n return;\n }\n\n log(config)(`Completed GTFS export to ${exportPath}`);\n\n log(config)(\n `Completed GTFS export for ${pluralize('agency', agencyCount, true)}\\n`,\n );\n};\n","import sqlString from 'sqlstring-sqlite';\nimport Database from 'better-sqlite3';\n\nimport { openDb } from './db.ts';\n\nimport {\n formatOrderByClause,\n formatSelectClause,\n formatWhereClauses,\n formatJoinClause,\n} from './utils.ts';\n\nimport type {\n JoinOptions,\n QueryOptions,\n SqlOrderBy,\n SqlWhere,\n} from '../types/global_interfaces.ts';\n\n/*\n * Returns an array of all agencies that match the query parameters.\n */\nexport function advancedQuery(\n table: string,\n advancedQueryOptions: {\n db?: Database.Database;\n query?: SqlWhere;\n fields?: string[];\n orderBy?: SqlOrderBy;\n join?: JoinOptions[];\n options?: QueryOptions;\n },\n) {\n const defaultOptions: {\n query: SqlWhere;\n fields: string[];\n orderBy: SqlOrderBy;\n join: JoinOptions[];\n options: QueryOptions;\n } = {\n query: {},\n fields: [],\n orderBy: [],\n join: [],\n options: {},\n };\n const queryOptions = { ...defaultOptions, ...advancedQueryOptions };\n\n const db = queryOptions.options.db ?? openDb();\n const tableName = sqlString.escapeId(table);\n const selectClause = formatSelectClause(queryOptions.fields);\n const whereClause = formatWhereClauses(queryOptions.query);\n const joinClause = formatJoinClause(queryOptions.join);\n const orderByClause = formatOrderByClause(queryOptions.orderBy);\n return db\n .prepare(\n `${selectClause} FROM ${tableName} ${joinClause} ${whereClause} ${orderByClause};`,\n )\n .all() as Array<Record<string, any>>;\n}\n","import { omit, pick } from 'lodash-es';\n\nimport type {\n QueryOptions,\n Route,\n SqlOrderBy,\n QueryResult,\n SqlWhere,\n} from '../../types/global_interfaces.ts';\nimport { openDb } from '../db.ts';\nimport {\n formatOrderByClause,\n formatSelectClause,\n formatWhereClause,\n formatWhereClauses,\n} from '../utils.ts';\n\nfunction buildStoptimeSubquery(query: { [key: string]: string }) {\n const whereClause = formatWhereClauses(query);\n return `SELECT DISTINCT trip_id FROM stop_times ${whereClause}`;\n}\n\nfunction buildTripSubquery(query: { service_id?: string; stop_id?: string }) {\n let whereClause = '';\n const tripQuery = omit(query, ['stop_id']);\n const stoptimeQuery = pick(query, ['stop_id']);\n\n const whereClauses = Object.entries(tripQuery).map(([key, value]) =>\n formatWhereClause(key, value),\n );\n\n if (Object.values(stoptimeQuery).length > 0) {\n whereClauses.push(`trip_id IN (${buildStoptimeSubquery(stoptimeQuery)})`);\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n return `SELECT DISTINCT route_id FROM trips ${whereClause}`;\n}\n\n/*\n * Returns an array of routes that match the query parameters. A `stop_id`\n * query parameter may be passed to find all routes that contain that stop.\n * A `service_id` query parameter may be passed to limit routes to specific\n * calendars.\n */\nexport function getRoutes<Fields extends keyof Route>(\n query: SqlWhere = {},\n fields: Fields[] = [],\n orderBy: SqlOrderBy = [],\n options: QueryOptions = {},\n) {\n const db = options.db ?? openDb();\n const tableName = 'routes';\n const selectClause = formatSelectClause(fields);\n let whereClause = '';\n const orderByClause = formatOrderByClause(orderBy);\n\n const routeQuery = omit(query, ['stop_id', 'service_id']);\n const tripQuery: { stop_id?: any; service_id?: any } = pick(query, [\n 'stop_id',\n 'service_id',\n ]);\n\n const whereClauses = Object.entries(routeQuery).map(([key, value]) =>\n formatWhereClause(key, value),\n );\n\n if (Object.values(tripQuery).length > 0) {\n whereClauses.push(`route_id IN (${buildTripSubquery(tripQuery)})`);\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n return db\n .prepare(\n `${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`,\n )\n .all() as QueryResult<Route, Fields>[];\n}\n","import { compact, omit, pick } from 'lodash-es';\nimport { FeatureCollection } from 'geojson';\nimport { featureCollection } from '@turf/helpers';\n\nimport type {\n QueryOptions,\n Shape,\n SqlOrderBy,\n QueryResult,\n SqlWhere,\n} from '../../types/global_interfaces.ts';\nimport { openDb } from '../db.ts';\nimport {\n formatOrderByClause,\n formatSelectClause,\n formatWhereClause,\n formatWhereClauses,\n} from '../utils.ts';\nimport { shapesToGeoJSONFeature } from '../geojson-utils.ts';\nimport { getAgencies } from './agencies.ts';\nimport { getRoutes } from './routes.ts';\nimport { getRouteAttributes } from '../gtfs-plus/route-attributes.ts';\n\nfunction buildTripSubquery(query: { [key: string]: string }) {\n const whereClause = formatWhereClauses(query);\n return `SELECT DISTINCT shape_id FROM trips ${whereClause}`;\n}\n\n/*\n * Returns array of shapes that match the query parameters. A `route_id` query\n * parameter may be passed to find all shapes for a route. A `trip_id` query\n * parameter may be passed to find all shapes for a trip. A `direction_id`\n * query parameter may be passed to find all shapes for a direction.\n */\nexport function getShapes<Fields extends keyof Shape>(\n query: SqlWhere = {},\n fields: Fields[] = [],\n orderBy: SqlOrderBy = [],\n options: QueryOptions = {},\n) {\n const db = options.db ?? openDb();\n const tableName = 'shapes';\n const selectClause = formatSelectClause(fields);\n let whereClause = '';\n const orderByClause = formatOrderByClause(orderBy);\n\n const shapeQuery = omit(query, [\n 'route_id',\n 'trip_id',\n 'service_id',\n 'direction_id',\n ]);\n const tripQuery: {\n route_id?: any;\n trip_id?: any;\n service_id?: any;\n direction_id?: any;\n } = pick(query, ['route_id', 'trip_id', 'service_id', 'direction_id']);\n\n const whereClauses = Object.entries(shapeQuery).map(([key, value]) =>\n formatWhereClause(key, value),\n );\n\n if (Object.values(tripQuery).length > 0) {\n whereClauses.push(`shape_id IN (${buildTripSubquery(tripQuery)})`);\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n return db\n .prepare(\n `${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`,\n )\n .all() as QueryResult<Shape, Fields>[];\n}\n\n/*\n * Returns geoJSON of the shapes that match the query parameters. A `route_id`\n * query parameter may be passed to find all shapes for a route. A `trip_id`\n * query parameter may be passed to find all shapes for a trip. A\n * `direction_id` query parameter may be passed to find all shapes for a direction.\n */\nexport function getShapesAsGeoJSON(\n query: SqlWhere = {},\n options: QueryOptions = {},\n): FeatureCollection {\n const agencies = getAgencies({}, [], [], options);\n const routeQuery = pick(query, ['route_id']);\n const routes = getRoutes(routeQuery, [], [], options);\n const features = compact(\n routes.map((route) => {\n const shapeQuery = {\n route_id: route.route_id,\n ...omit(query, 'route_id'),\n };\n const shapes = getShapes(\n shapeQuery,\n ['shape_id', 'shape_pt_sequence', 'shape_pt_lon', 'shape_pt_lat'],\n [],\n options,\n );\n\n if (shapes.length === 0) {\n return;\n }\n\n const routeAttributes = getRouteAttributes(\n { route_id: route.route_id },\n [],\n [],\n options,\n );\n\n const agency = agencies.find(\n (agency) => agency.agency_id === route.agency_id,\n );\n\n const geojsonProperties = {\n agency_name: agency ? agency.agency_name : undefined,\n shape_id: query.shape_id,\n ...route,\n ...(routeAttributes?.[0] || []),\n };\n return shapesToGeoJSONFeature(shapes, geojsonProperties);\n }),\n );\n\n return featureCollection(features);\n}\n","import { omit, orderBy, pick } from 'lodash-es';\nimport { FeatureCollection } from 'geojson';\n\nimport type {\n QueryOptions,\n SqlOrderBy,\n QueryResult,\n SqlWhere,\n Stop,\n} from '../../types/global_interfaces.ts';\nimport { openDb } from '../db.ts';\nimport {\n formatOrderByClause,\n formatSelectClause,\n formatWhereClause,\n formatWhereClauseBoundingBox,\n formatWhereClauses,\n} from '../utils.ts';\nimport { stopsToGeoJSONFeatureCollection } from '../geojson-utils.ts';\nimport { getAgencies } from './agencies.ts';\nimport { getStopAttributes } from '../gtfs-plus/stop-attributes.ts';\n\nfunction buildTripSubquery(query: { [key: string]: string }) {\n const whereClause = formatWhereClauses(query);\n return `SELECT trip_id FROM trips ${whereClause}`;\n}\n\nfunction buildStoptimeSubquery(query: { [key: string]: string }) {\n return `SELECT DISTINCT stop_id FROM stop_times WHERE trip_id IN (${buildTripSubquery(\n query,\n )})`;\n}\n\n/*\n * Returns an array of stops that match the query parameters. A `route_id`\n * query parameter may be passed to find all shapes for a route. A `trip_id`\n * query parameter may be passed to find all shapes for a trip. A\n * `direction_id` query parameter may be passed to find all shapes for a\n * direction.\n */\nexport function getStops<Fields extends keyof Stop>(\n query: SqlWhere = {},\n fields: Fields[] = [],\n orderBy: SqlOrderBy = [],\n options: QueryOptions = {},\n) {\n const db = options.db ?? openDb();\n const tableName = 'stops';\n const selectClause = formatSelectClause(fields);\n let whereClause = '';\n const orderByClause = formatOrderByClause(orderBy);\n\n const stopQueryOmitKeys = [\n 'route_id',\n 'trip_id',\n 'service_id',\n 'direction_id',\n 'shape_id',\n ];\n\n // If bounding_box_side_m is defined, search for stops inside a bounding box so omit `stop_lat` and `stop_lon`.\n if (options.bounding_box_side_m !== undefined) {\n stopQueryOmitKeys.push('stop_lat', 'stop_lon');\n }\n\n let stopQuery = omit(query, stopQueryOmitKeys);\n\n const tripQuery: {\n route_id?: any;\n trip_id?: any;\n service_id?: any;\n direction_id?: any;\n shape_id?: any;\n } = pick(query, [\n 'route_id',\n 'trip_id',\n 'service_id',\n 'direction_id',\n 'shape_id',\n ]);\n\n const whereClauses = Object.entries(stopQuery).map(\n ([key, value]: [string, any]) => formatWhereClause(key, value),\n );\n\n if (\n options.bounding_box_side_m !== undefined &&\n query.stop_lat !== undefined &&\n query.stop_lon !== undefined\n ) {\n whereClauses.push(\n formatWhereClauseBoundingBox(\n query.stop_lat as number | string,\n query.stop_lon as number | string,\n options.bounding_box_side_m,\n ),\n );\n }\n\n if (Object.values(tripQuery).length > 0) {\n whereClauses.push(`stop_id IN (${buildStoptimeSubquery(tripQuery)})`);\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n return db\n .prepare(\n `${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`,\n )\n .all() as QueryResult<Stop, Fields>[];\n}\n\n/*\n * Returns geoJSON with stops. A `route_id` query parameter may be passed to\n * find all shapes for a route. A `trip_id` query parameter may be passed to\n * find all shapes for a trip. A `direction_id` query parameter may be passed\n * to find all shapes for a direction.\n */\nexport function getStopsAsGeoJSON(\n query: SqlWhere = {},\n options: QueryOptions = {},\n): FeatureCollection {\n const db = options.db ?? openDb();\n const stops = getStops(query, [], [], options);\n\n // Get all agencies for reference\n const agencies = getAgencies({}, [], [], options);\n\n const preparedStops = stops.map((stop) => {\n const routeSubquery =\n 'SELECT DISTINCT route_id FROM trips WHERE trip_id IN (SELECT DISTINCT trip_id FROM stop_times WHERE stop_id = ?)';\n const routes = db\n .prepare(`SELECT * FROM routes WHERE route_id IN (${routeSubquery})`)\n .all(stop.stop_id);\n\n const stopAttributes = getStopAttributes({ stop_id: stop.stop_id });\n\n return {\n ...stop,\n ...(stopAttributes?.[0] || []),\n routes: orderBy(routes, (route: { route_short_name?: string }) =>\n route?.route_short_name\n ? Number.parseInt(route.route_short_name, 10)\n : 0,\n ),\n agency_name: agencies[0].agency_name,\n };\n });\n\n // Exclude stops not part of any route\n const filteredStops = preparedStops.filter((stop) => stop.routes.length > 0);\n\n return stopsToGeoJSONFeatureCollection(filteredStops);\n}\n","import { omit } from 'lodash-es';\nimport sqlString from 'sqlstring-sqlite';\nimport type {\n QueryOptions,\n SqlOrderBy,\n QueryResult,\n SqlWhere,\n StopTime,\n} from '../../types/global_interfaces.ts';\nimport { openDb } from '../db.ts';\nimport {\n calculateSecondsFromMidnight,\n formatOrderByClause,\n formatSelectClause,\n formatWhereClause,\n} from '../utils.ts';\nimport { getServiceIdsByDate } from './calendars.ts';\n\n/*\n * Returns an array of stoptimes that match the query parameters.\n */\nexport function getStoptimes<Fields extends keyof StopTime>(\n query: SqlWhere = {},\n fields: Fields[] = [],\n orderBy: SqlOrderBy = [],\n options: QueryOptions = {},\n) {\n const db = options.db ?? openDb();\n const tableName = 'stop_times';\n const selectClause = formatSelectClause(fields);\n let whereClause = '';\n const orderByClause = formatOrderByClause(orderBy);\n\n const stoptimeQueryOmitKeys = ['date', 'start_time', 'end_time'];\n\n let stoptimeQuery = omit(query, stoptimeQueryOmitKeys);\n\n const whereClauses = Object.entries(stoptimeQuery).map(\n ([key, value]: [string, any]) => formatWhereClause(key, value),\n );\n\n if (query.date) {\n if (typeof query.date !== 'number') {\n throw new Error('`date` must be a number in yyyymmdd format');\n }\n\n const serviceIds = getServiceIdsByDate(query.date);\n\n const tripSubquery = `SELECT DISTINCT trip_id FROM trips WHERE service_id IN (${serviceIds.map((id) => sqlString.escape(id)).join(',')})`;\n\n whereClauses.push(`trip_id IN (${tripSubquery})`);\n }\n\n if (query.start_time) {\n if (typeof query.start_time !== 'string') {\n throw new Error('`start_time` must be a string in HH:mm:ss format');\n }\n\n whereClauses.push(\n `arrival_timestamp >= ${calculateSecondsFromMidnight(query.start_time)}`,\n );\n }\n\n if (query.end_time) {\n if (typeof query.end_time !== 'string') {\n throw new Error('`end_time` must be a string in HH:mm:ss format');\n }\n\n whereClauses.push(\n `departure_timestamp <= ${calculateSecondsFromMidnight(query.end_time)}`,\n );\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n return db\n .prepare(\n `${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`,\n )\n .all() as QueryResult<StopTime, Fields>[];\n}\n"],"mappings":"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","names":["argv","pluralize","untildify","mapSeries","untildify","omit","sqlString","path","compact","pluralize","sqlString","mapSeries","untildify","pluralize","path","untildify","mapSeries","sqlString","compact","sqlString","omit","compact","omit","pick","featureCollection","omit","pick","omit","sqlString"]}
|
|
1
|
+
{"version":3,"sources":["../../src/bin/gtfs-export.ts","../../src/lib/file-utils.ts","../../src/lib/log-utils.ts","../../src/lib/import-gtfs.ts","../../src/models/models.ts","../../src/models/gtfs/agency.ts","../../src/models/gtfs/areas.ts","../../src/models/gtfs/attributions.ts","../../src/models/gtfs/booking-rules.ts","../../src/models/gtfs/calendar-dates.ts","../../src/models/gtfs/calendar.ts","../../src/models/gtfs/fare-attributes.ts","../../src/models/gtfs/fare-leg-rules.ts","../../src/models/gtfs/fare-media.ts","../../src/models/gtfs/fare-products.ts","../../src/models/gtfs/fare-rules.ts","../../src/models/gtfs/fare-transfer-rules.ts","../../src/models/gtfs/feed-info.ts","../../src/models/gtfs/frequencies.ts","../../src/models/gtfs/levels.ts","../../src/models/gtfs/location-groups.ts","../../src/models/gtfs/location-group-stops.ts","../../src/models/gtfs/locations.ts","../../src/models/gtfs/networks.ts","../../src/models/gtfs/pathways.ts","../../src/models/gtfs/route-networks.ts","../../src/models/gtfs/routes.ts","../../src/models/gtfs/shapes.ts","../../src/models/gtfs/stop-areas.ts","../../src/models/gtfs/stop-times.ts","../../src/models/gtfs/stops.ts","../../src/models/gtfs/timeframes.ts","../../src/models/gtfs/transfers.ts","../../src/models/gtfs/translations.ts","../../src/models/gtfs/trips.ts","../../src/models/non-standard/timetables.ts","../../src/models/non-standard/timetable-pages.ts","../../src/models/non-standard/timetable-stop-order.ts","../../src/models/non-standard/timetable-notes.ts","../../src/models/non-standard/timetable-notes-references.ts","../../src/models/non-standard/trips-dated-vehicle-journey.ts","../../src/models/gtfs-plus/calendar-attributes.ts","../../src/models/gtfs-plus/directions.ts","../../src/models/gtfs-plus/route-attributes.ts","../../src/models/gtfs-plus/stop-attributes.ts","../../src/models/gtfs-ride/board-alight.ts","../../src/models/gtfs-ride/rider-trip.ts","../../src/models/gtfs-ride/ridership.ts","../../src/models/gtfs-ride/trip-capacity.ts","../../src/models/gtfs-ride/ride-feed-info.ts","../../src/models/gtfs-realtime/trip-updates.ts","../../src/models/gtfs-realtime/stop-time-updates.ts","../../src/models/gtfs-realtime/vehicle-positions.ts","../../src/models/gtfs-realtime/service-alerts.ts","../../src/models/gtfs-realtime/service-alert-targets.ts","../../src/models/ods/deadhead-times.ts","../../src/models/ods/deadheads.ts","../../src/models/ods/ops-locations.ts","../../src/models/ods/run-events.ts","../../src/models/ods/runs-pieces.ts","../../src/lib/db.ts","../../src/lib/geojson-utils.ts","../../src/lib/import-gtfs-realtime.ts","../../src/lib/utils.ts","../../src/lib/export.ts","../../src/lib/advancedQuery.ts","../../src/lib/gtfs/routes.ts","../../src/lib/gtfs/shapes.ts","../../src/lib/gtfs/stops.ts","../../src/lib/gtfs/stop-times.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport PrettyError from 'pretty-error';\n\nimport { getConfig } from '../lib/file-utils.ts';\nimport { formatError } from '../lib/log-utils.ts';\nimport { exportGtfs } from '../index.ts';\nimport type { Config } from '../types/global_interfaces.ts';\n\nconst pe = new PrettyError();\n\nconst argv = yargs(hideBin(process.argv))\n .usage('Usage: $0 --configPath ./config.json')\n .help()\n .option('c', {\n alias: 'configPath',\n describe: 'Path to config file',\n type: 'string',\n })\n .option('sqlitePath', {\n describe: 'Path to SQLite database',\n type: 'string',\n })\n .parseSync();\n\nconst handleError = (error = 'Unknown Error') => {\n process.stdout.write(`\\n${formatError(error)}\\n`);\n console.error(pe.render(error));\n process.exit(1);\n};\n\nconst setupExport = async () => {\n const config = await getConfig(argv);\n await exportGtfs(config as Config);\n process.exit();\n};\n\nsetupExport().catch(handleError);\n","import path from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, rm } from 'node:fs/promises';\nimport { omit, snakeCase } from 'lodash-es';\nimport sanitize from 'sanitize-filename';\nimport untildify from 'untildify';\nimport StreamZip from 'node-stream-zip';\n\nimport { log } from './log-utils.ts';\n\n/** Configuration command line arguments interface */\ninterface ConfigArgs {\n configPath?: string;\n gtfsPath?: string;\n gtfsUrl?: string;\n sqlitePath?: string;\n}\n\n/**\n * Attempts to parse and load configuration from various sources\n * Priority: 1. CLI config path 2. CLI direct args 3. ./config.json\n * @param {ConfigArgs} argv - Command line arguments\n * @throws {Error} If configuration cannot be found or parsed\n * @returns {Promise<Record<string, any>>} Parsed configuration object\n * @example\n * const config = await getConfig({ configPath: './my-config.json' });\n */\nexport async function getConfig(\n argv: ConfigArgs,\n): Promise<Record<string, any>> {\n let config;\n let data;\n\n try {\n if (argv.configPath) {\n const configPath = path.resolve(untildify(argv.configPath));\n data = await readFile(configPath, 'utf8');\n config = Object.assign(JSON.parse(data), argv);\n } else if (argv.gtfsPath || argv.gtfsUrl || argv.sqlitePath) {\n const agencies = [\n ...(argv.gtfsPath ? [{ path: argv.gtfsPath }] : []),\n ...(argv.gtfsUrl ? [{ url: argv.gtfsUrl }] : []),\n ];\n\n config = {\n agencies,\n ...omit(argv, ['path', 'url']),\n };\n } else if (existsSync(path.resolve('./config.json'))) {\n data = await readFile(path.resolve('./config.json'), 'utf8');\n config = Object.assign(JSON.parse(data), argv);\n log(config)('Using configuration from ./config.json');\n } else {\n throw new Error(\n 'Cannot find configuration file. Use config-sample.json as a starting point, pass --configPath option.',\n );\n }\n\n return config;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(\n `Cannot parse configuration file. Check to ensure that it is valid JSON. Error: ${error.message}`,\n );\n }\n throw error;\n }\n}\n\n/**\n * Prepares a directory for saving files by clearing its contents\n * @param {string} exportPath - Path to the directory to prepare\n * @returns {Promise<void>}\n * @example\n * await prepDirectory('./output');\n */\nexport async function prepDirectory(exportPath: string): Promise<void> {\n await rm(exportPath, { recursive: true, force: true });\n await mkdir(exportPath, { recursive: true });\n}\n\n/**\n * Extracts contents of a zip file to specified directory\n * @param {string} zipfilePath - Path to the zip file\n * @param {string} exportPath - Directory to extract contents to\n * @returns {Promise<void>}\n * @throws {Error} If zip file cannot be opened or extracted\n * @example\n * await unzip('./data.zip', './extracted');\n */\nexport async function unzip(\n zipfilePath: string,\n exportPath: string,\n): Promise<void> {\n try {\n const zip = new StreamZip.async({ file: zipfilePath });\n await zip.extract(null, exportPath);\n await zip.close();\n } catch (error) {\n throw new Error(\n `Failed to extract zip file: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n}\n\n/**\n * Generates a safe folder name from input string\n * Converts to snake_case and removes unsafe characters\n * @param {string} folderName - Input string to convert to folder name\n * @returns {string} Sanitized folder name\n * @example\n * generateFolderName('My Folder!') // returns 'my_folder'\n */\nexport function generateFolderName(folderName: string): string {\n if (!folderName || typeof folderName !== 'string') {\n throw new Error('Folder name must be a non-empty string');\n }\n return snakeCase(sanitize(folderName));\n}\n","import { clearLine, cursorTo } from 'node:readline';\nimport { noop } from 'lodash-es';\nimport * as colors from 'yoctocolors';\nimport { Config } from '../types/global_interfaces.ts';\n\n/** Function type for logging with optional line overwrite */\ntype LogFunction = (text: string, overwrite?: boolean) => void;\n\n/**\n * Creates a logging function based on configuration settings\n * @param {Config} config - Configuration object containing logging preferences\n * @returns {LogFunction} Logging function that writes to stdout, or noop if verbose is false\n * @example\n * const logger = log({ verbose: true });\n * logger('Processing...', true); // Overwrites current line\n * logger('Done!'); // Writes on new line\n */\nexport function log(config: Config): LogFunction {\n if (config.verbose === false) {\n return noop;\n }\n\n if (config.logFunction) {\n return config.logFunction;\n }\n\n return (text: string, overwrite = false): void => {\n if (overwrite && process.stdout.isTTY) {\n clearLine(process.stdout, 0);\n cursorTo(process.stdout, 0);\n } else {\n process.stdout.write('\\n');\n }\n\n process.stdout.write(text);\n };\n}\n\n/**\n * Creates a warning logging function\n * @param {Config} config - Configuration object containing logging preferences\n * @returns {(text: string) => void} Function that logs formatted warning messages\n * @example\n * const warnLogger = logWarning(config);\n * warnLogger('Resource not found'); // Outputs yellow warning message\n */\nexport function logWarning(config: Config): (text: string) => void {\n if (config.logFunction) {\n return config.logFunction;\n }\n\n return (text: string): void => {\n process.stdout.write(`\\n${formatWarning(text)}\\n`);\n };\n}\n\n/**\n * Creates an error logging function\n * @param {Config} config - Configuration object containing logging preferences\n * @returns {(text: string) => void} Function that logs formatted error messages\n * @example\n * const errorLogger = logError(config);\n * errorLogger('Failed to connect'); // Outputs red error message\n */\nexport function logError(config: Config): (text: string) => void {\n if (config.logFunction) {\n return config.logFunction;\n }\n\n return (text: string): void => {\n process.stdout.write(`\\n${formatError(text)}\\n`);\n };\n}\n\n/**\n * Formats warning text with yellow color and underline\n * @param {string} text - The warning message to format\n * @returns {string} Formatted warning message in yellow with underlined \"Warning\" prefix\n * @example\n * const formattedWarning = formatWarning('Resource not found');\n * console.log(formattedWarning); // Yellow \"Warning: Resource not found\"\n */\nexport function formatWarning(text: string): string {\n return colors.yellow(`${colors.underline('Warning')}: ${text}`);\n}\n\n/**\n * Formats error text with red color and underline\n * @param {Error | string} error - The error object or message to format\n * @returns {string} Formatted error message in red with underlined \"Error\" prefix\n * @example\n * const formattedError = formatError(new Error('Connection failed'));\n * console.log(formattedError); // Red \"Error: Connection failed\"\n */\nexport function formatError(error: Error | string): string {\n const messageText = error instanceof Error ? error.message : error;\n const cleanMessage = messageText.replace(/^Error:\\s*/i, '');\n\n return colors.red(`${colors.underline('Error')}: ${cleanMessage}`);\n}\n","import path from 'node:path';\nimport { createReadStream, existsSync, lstatSync } from 'node:fs';\nimport { cp, readdir, rename, readFile, rm, writeFile } from 'node:fs/promises';\nimport { parse } from 'csv-parse';\nimport pluralize from 'pluralize';\nimport stripBomStream from 'strip-bom-stream';\nimport { temporaryDirectory } from 'tempy';\nimport Timer from 'timer-machine';\nimport untildify from 'untildify';\nimport mapSeries from 'promise-map-series';\nimport Database from 'better-sqlite3';\n\nimport * as models from '../models/models.ts';\nimport { openDb } from './db.ts';\nimport { unzip } from './file-utils.ts';\nimport { isValidJSON } from './geojson-utils.ts';\nimport { updateGtfsRealtimeData } from './import-gtfs-realtime.ts';\nimport { log, logError, logWarning } from './log-utils.ts';\nimport {\n calculateSecondsFromMidnight,\n getTimestampColumnName,\n padLeadingZeros,\n setDefaultConfig,\n validateConfigForImport,\n} from './utils.ts';\n\nimport {\n Config,\n ConfigAgency,\n Model,\n ModelColumn,\n} from '../types/global_interfaces.ts';\n\ninterface GtfsImportTask {\n exclude?: string[];\n url?: string;\n headers?: Record<string, string>;\n realtimeAlerts?: {\n url: string;\n headers?: Record<string, string>;\n };\n realtimeTripUpdates?: {\n url: string;\n headers?: Record<string, string>;\n };\n realtimeVehiclePositions?: {\n url: string;\n headers?: Record<string, string>;\n };\n downloadDir: string;\n downloadTimeout?: number;\n gtfsRealtimeExpirationSeconds: number;\n path?: string;\n csvOptions: {};\n ignoreDuplicates: boolean;\n ignoreErrors: boolean;\n sqlitePath: string;\n prefix?: string;\n currentTimestamp: number;\n log: (message: string, newLine?: boolean) => void;\n logWarning: (message: string) => void;\n logError: (message: string) => void;\n}\n\ninterface Dictionary<T> {\n [key: string]: T;\n}\ntype Tuple = [seconds: number | null, date: string | null];\n\nconst timeCache: Dictionary<Tuple> = {};\n\nconst formatAndCacheTime = (value: string): Tuple => {\n const cached = timeCache[value];\n if (cached !== undefined) {\n return cached;\n }\n\n const timeAsSecondsFromMidnight = calculateSecondsFromMidnight(value);\n const timeAsString = padLeadingZeros(value);\n const computed: Tuple = [timeAsSecondsFromMidnight, timeAsString];\n timeCache[value] = computed;\n return computed;\n};\n\nconst getTextFiles = async (folderPath: string): Promise<string[]> => {\n const files = await readdir(folderPath);\n return files.filter((filename) => filename.slice(-3) === 'txt');\n};\n\nconst downloadGtfsFiles = async (task: GtfsImportTask): Promise<void> => {\n if (!task.url) {\n throw new Error('No `url` specified in config');\n }\n\n task.log(`Downloading GTFS from ${task.url}`);\n\n task.path = `${task.downloadDir}/gtfs.zip`;\n\n const response = await fetch(task.url, {\n method: 'GET',\n headers: task.headers || {},\n signal: task.downloadTimeout\n ? AbortSignal.timeout(task.downloadTimeout)\n : undefined,\n });\n\n if (response.status !== 200) {\n throw new Error(\n `Unable to download GTFS from ${task.url}. Got status ${response.status}.`,\n );\n }\n\n const buffer = await response.arrayBuffer();\n\n await writeFile(task.path, Buffer.from(buffer));\n task.log('Download successful');\n};\n\nconst extractGtfsFiles = async (task: GtfsImportTask): Promise<void> => {\n if (!task.path) {\n throw new Error('No `path` specified in config');\n }\n\n const gtfsPath = untildify(task.path);\n task.log(`Importing GTFS from ${task.path}\\r`);\n if (path.extname(gtfsPath) === '.zip') {\n try {\n await unzip(gtfsPath, task.downloadDir);\n const textFiles = await getTextFiles(task.downloadDir);\n\n // If no .txt files in this directory, check for subdirectories and copy them here\n if (textFiles.length === 0) {\n const files = await readdir(task.downloadDir);\n // Ignore system directories within zip file\n const folders = files\n .filter((filename) => !['__MACOSX'].includes(filename))\n .map((filename) => path.join(task.downloadDir, filename))\n .filter((source) => lstatSync(source).isDirectory());\n\n if (folders.length > 1) {\n throw new Error(\n `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.`,\n );\n } else if (folders.length === 0) {\n throw new Error(\n `No .txt files found in \\`${task.path}\\`. Ensure that .txt files are in the top level of the zip file, or in a single subdirectory.`,\n );\n }\n\n const subfolderName = folders[0];\n const directoryTextFiles = await getTextFiles(subfolderName);\n\n if (directoryTextFiles.length === 0) {\n throw new Error(\n `No .txt files found in \\`${task.path}\\`. Ensure that .txt files are in the top level of the zip file, or in a single subdirectory.`,\n );\n }\n\n await Promise.all(\n directoryTextFiles.map(async (fileName) =>\n rename(\n path.join(subfolderName, fileName),\n path.join(task.downloadDir, fileName),\n ),\n ),\n );\n }\n } catch (error: any) {\n task.logError(error);\n throw new Error(`Unable to unzip file ${task.path}`);\n }\n } else {\n // Local file is unzipped, just copy it from there.\n try {\n await cp(gtfsPath, task.downloadDir, { recursive: true });\n } catch {\n throw new Error(\n `Unable to load files from path \\`${gtfsPath}\\` defined in configuration. Verify that path exists and contains GTFS files.`,\n );\n }\n }\n};\n\nconst createGtfsTables = (db: Database.Database): void => {\n for (const model of Object.values(models) as Model[]) {\n if (!model.schema) {\n return;\n }\n\n const sqlColumnCreateStatements = [];\n\n for (const column of model.schema) {\n const checks = [];\n if (column.min !== undefined && column.max) {\n checks.push(\n `${column.name} >= ${column.min} AND ${column.name} <= ${column.max}`,\n );\n } else if (column.min) {\n checks.push(`${column.name} >= ${column.min}`);\n } else if (column.max) {\n checks.push(`${column.name} <= ${column.max}`);\n }\n\n if (column.type === 'integer') {\n checks.push(\n `(TYPEOF(${column.name}) = 'integer' OR ${column.name} IS NULL)`,\n );\n } else if (column.type === 'real') {\n checks.push(\n `(TYPEOF(${column.name}) = 'real' OR ${column.name} IS NULL)`,\n );\n }\n\n const required = column.required ? 'NOT NULL' : '';\n const columnDefault = column.default ? 'DEFAULT ' + column.default : '';\n const columnCollation = column.nocase ? 'COLLATE NOCASE' : '';\n const checkClause =\n checks.length > 0 ? `CHECK(${checks.join(' AND ')})` : '';\n\n sqlColumnCreateStatements.push(\n `${column.name} ${column.type} ${checkClause} ${required} ${columnDefault} ${columnCollation}`,\n );\n\n // Add an additional timestamp column for time columns\n if (column.type === 'time') {\n sqlColumnCreateStatements.push(\n `${getTimestampColumnName(column.name)} INTEGER`,\n );\n }\n }\n\n // Find Primary Key fields\n const primaryColumns = model.schema.filter((column) => column.primary);\n\n if (primaryColumns.length > 0) {\n sqlColumnCreateStatements.push(\n `PRIMARY KEY (${primaryColumns.map(({ name }) => name).join(', ')})`,\n );\n }\n\n db.prepare(`DROP TABLE IF EXISTS ${model.filenameBase};`).run();\n\n db.prepare(\n `CREATE TABLE ${model.filenameBase} (${sqlColumnCreateStatements.join(', ')});`,\n ).run();\n }\n};\n\nconst createGtfsIndexes = (db: Database.Database): void => {\n for (const model of Object.values(models) as Model[]) {\n if (!model.schema) {\n return;\n }\n for (const column of model.schema) {\n if (column.index) {\n db.prepare(\n `CREATE INDEX idx_${model.filenameBase}_${column.name} ON ${model.filenameBase} (${column.name});`,\n ).run();\n }\n\n if (column.type === 'time') {\n // Index all timestamp columns\n const timestampColumnName = getTimestampColumnName(column.name);\n db.prepare(\n `CREATE INDEX idx_${model.filenameBase}_${timestampColumnName} ON ${model.filenameBase} (${timestampColumnName});`,\n ).run();\n }\n }\n }\n};\n\nconst formatGtfsLine = (\n line: { [x: string]: any; geojson?: string },\n model: Model,\n totalLineCount: number,\n): Record<string, any> => {\n const lineNumber = totalLineCount + 1;\n const formattedLine: Record<string, any> = {};\n const filenameBase = model.filenameBase;\n const filenameExtension = model.filenameExtension;\n\n for (const { name, type, required } of model.schema) {\n let value = line[name];\n\n // Early null check\n if (value === '' || value === undefined || value === null) {\n formattedLine[name] = null;\n\n if (type === 'time') {\n formattedLine[getTimestampColumnName(name)] = null;\n }\n\n if (required) {\n throw new Error(\n `Missing required value in ${filenameBase}.${filenameExtension} for ${name} on line ${lineNumber}.`,\n );\n }\n continue;\n }\n\n if (type === 'date') {\n // Handle YYYY-MM-DD format\n value = value.replace(/-/g, '');\n if (value.length !== 8) {\n throw new Error(\n `Invalid date in ${filenameBase}.${filenameExtension} for ${name} on line ${lineNumber}.`,\n );\n }\n } else if (type === 'time') {\n // Add an additional timestamp column for time columns\n const [timeAsSecondsFromMidnight, timeAsString] =\n formatAndCacheTime(value);\n\n value = timeAsString;\n\n formattedLine[getTimestampColumnName(name)] =\n timeAsSecondsFromMidnight ?? null;\n }\n\n if (type === 'json') {\n value = JSON.stringify(value);\n }\n\n formattedLine[name] = value;\n }\n\n return formattedLine;\n};\n\nconst BATCH_SIZE = 100_000;\n\nconst importGtfsFiles = (\n db: Database.Database,\n task: GtfsImportTask,\n): Promise<void[]> =>\n mapSeries(\n Object.values(models),\n (model: Model) =>\n new Promise<void>((resolve, reject) => {\n let totalLineCount = 0;\n const filename = `${model.filenameBase}.${model.filenameExtension}`;\n\n // Filter out excluded files from config\n if (task.exclude && task.exclude.includes(model.filenameBase)) {\n task.log(`Skipping - ${filename}\\r`);\n resolve();\n return;\n }\n\n // If the model is a database/gtfs-realtime model then skip silently\n if (model.extension === 'gtfs-realtime') {\n resolve();\n return;\n }\n\n const filepath = path.join(task.downloadDir, `${filename}`);\n\n // Log missing standard GTFS files, don't log nonstandard files\n if (!existsSync(filepath)) {\n if (!model.nonstandard) {\n task.log(`Importing - ${filename} - No file found\\r`);\n }\n\n resolve();\n return;\n }\n\n task.log(`Importing - ${filename}\\r`);\n\n // Create a list of all columns\n const columns = model.schema.flatMap((column) => {\n if (column.type === 'time') {\n // Add an additional timestamp column for time columns\n return [\n column,\n {\n name: getTimestampColumnName(column.name),\n type: 'integer',\n index: true,\n } as ModelColumn,\n ];\n }\n return column;\n });\n\n // Create a map of which columns need prefixing\n const prefixedColumns = new Set(\n columns\n .filter((column) => column.prefix)\n .map((column) => column.name),\n );\n\n const prepareStatement = `INSERT ${task.ignoreDuplicates ? 'OR IGNORE' : ''} INTO ${\n model.filenameBase\n } (${columns.map(({ name }) => name).join(', ')}) VALUES (${columns\n .map(({ name }) => `@${name}`)\n .join(', ')})`;\n\n const insert = db.prepare(prepareStatement);\n\n const insertLines = db.transaction((lines) => {\n for (const [rowNumber, line] of Object.entries(lines)) {\n try {\n if (task.prefix === undefined) {\n insert.run(line);\n } else {\n const prefixedLine = Object.fromEntries(\n Object.entries(\n line as { [x: string]: any; geojson?: string },\n ).map(([columnName, value]) => [\n columnName,\n prefixedColumns.has(columnName) && value !== null\n ? `${task.prefix}${value}`\n : value,\n ]),\n );\n insert.run(prefixedLine);\n }\n } catch (error: any) {\n if (error.code === 'SQLITE_CONSTRAINT_PRIMARYKEY') {\n const primaryColumns = columns.filter(\n (column) => column.primary,\n );\n task.logWarning(\n `Duplicate values for primary key (${primaryColumns.map((column) => column.name).join(', ')}) found in ${filename}. Set the \\`ignoreDuplicates\\` option to true in config.json to ignore this error`,\n );\n }\n\n task.logWarning(\n `Check ${filename} for invalid data on line ${rowNumber + 1}.`,\n );\n throw error;\n }\n }\n });\n\n if (model.filenameExtension === 'txt') {\n const parser = parse({\n columns: true,\n relax_quotes: true,\n trim: true,\n skip_empty_lines: true,\n ...task.csvOptions,\n });\n\n let lines: { [x: string]: any; geojson?: string }[] = [];\n\n parser.on('readable', () => {\n try {\n let record;\n\n while ((record = parser.read())) {\n totalLineCount += 1;\n lines.push(formatGtfsLine(record, model, totalLineCount));\n\n if (lines.length >= BATCH_SIZE) {\n insertLines(lines);\n lines = [];\n\n task.log(\n `Importing - ${filename} - ${totalLineCount} lines imported\\r`,\n true,\n );\n }\n }\n } catch (error) {\n reject(error);\n }\n });\n\n parser.on('end', () => {\n try {\n if (lines.length > 0) {\n try {\n insertLines(lines);\n } catch (error) {\n reject(error);\n }\n }\n task.log(\n `Importing - ${filename} - ${totalLineCount} lines imported\\r`,\n true,\n );\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n\n parser.on('error', reject);\n\n createReadStream(filepath).pipe(stripBomStream()).pipe(parser);\n } else if (model.filenameExtension === 'geojson') {\n readFile(filepath, 'utf8')\n .then((data) => {\n if (isValidJSON(data) === false) {\n reject(new Error(`Invalid JSON in ${filename}`));\n }\n totalLineCount += 1;\n const line = formatGtfsLine(\n { geojson: data },\n model,\n totalLineCount,\n );\n insertLines([line]);\n task.log(\n `Importing - ${filename} - ${totalLineCount} lines imported\\r`,\n true,\n );\n resolve();\n })\n .catch(reject);\n } else {\n reject(\n new Error(`Unsupported file type: ${model.filenameExtension}`),\n );\n }\n }),\n );\n\nexport async function importGtfs(initialConfig: Config): Promise<void> {\n const timer = new Timer();\n timer.start();\n\n const config = setDefaultConfig(initialConfig);\n validateConfigForImport(config);\n\n try {\n const db = openDb(config);\n const agencyCount = config.agencies.length;\n\n log(config)(\n `Starting GTFS import for ${pluralize('file', agencyCount, true)} using SQLite database at ${config.sqlitePath}`,\n );\n\n createGtfsTables(db);\n\n await mapSeries(config.agencies, async (agency: ConfigAgency) => {\n try {\n const tempPath = temporaryDirectory();\n\n const task = {\n exclude: agency.exclude,\n url: agency.url,\n headers: agency.headers,\n realtimeAlerts: agency.realtimeAlerts,\n realtimeTripUpdates: agency.realtimeTripUpdates,\n realtimeVehiclePositions: agency.realtimeVehiclePositions,\n downloadDir: tempPath,\n downloadTimeout: config.downloadTimeout,\n gtfsRealtimeExpirationSeconds: config.gtfsRealtimeExpirationSeconds,\n path: agency.path,\n csvOptions: config.csvOptions || {},\n ignoreDuplicates: config.ignoreDuplicates,\n ignoreErrors: config.ignoreErrors,\n sqlitePath: config.sqlitePath,\n prefix: agency.prefix,\n currentTimestamp: Math.floor(Date.now() / 1000),\n log: log(config),\n logWarning: logWarning(config),\n logError: logError(config),\n };\n\n if (task.url) {\n await downloadGtfsFiles(task);\n }\n\n await extractGtfsFiles(task);\n await importGtfsFiles(db, task);\n await updateGtfsRealtimeData(task);\n\n await rm(tempPath, { recursive: true });\n } catch (error: any) {\n if (config.ignoreErrors) {\n logError(config)(error.message);\n } else {\n throw error;\n }\n }\n });\n\n log(config)(`Creating DB indexes`);\n createGtfsIndexes(db);\n\n const seconds = Math.round(timer.time() / 1000);\n timer.stop();\n\n log(config)(\n `Completed GTFS import for ${pluralize('agency', agencyCount, true)} in ${seconds} seconds\\n`,\n );\n } catch (error: any) {\n if (error?.code === 'SQLITE_CANTOPEN') {\n logError(config)(\n `Unable to open sqlite database \"${config.sqlitePath}\" defined as \\`sqlitePath\\` config.json. Ensure the parent directory exists or remove \\`sqlitePath\\` from config.json.`,\n );\n }\n throw error;\n }\n}\n","export { agency } from './gtfs/agency.ts';\nexport { areas } from './gtfs/areas.ts';\nexport { attributions } from './gtfs/attributions.ts';\nexport { bookingRules } from './gtfs/booking-rules.ts';\nexport { calendarDates } from './gtfs/calendar-dates.ts';\nexport { calendar } from './gtfs/calendar.ts';\nexport { fareAttributes } from './gtfs/fare-attributes.ts';\nexport { fareLegRules } from './gtfs/fare-leg-rules.ts';\nexport { fareMedia } from './gtfs/fare-media.ts';\nexport { fareProducts } from './gtfs/fare-products.ts';\nexport { fareRules } from './gtfs/fare-rules.ts';\nexport { fareTransferRules } from './gtfs/fare-transfer-rules.ts';\nexport { feedInfo } from './gtfs/feed-info.ts';\nexport { frequencies } from './gtfs/frequencies.ts';\nexport { levels } from './gtfs/levels.ts';\nexport { locationGroups } from './gtfs/location-groups.ts';\nexport { locationGroupStops } from './gtfs/location-group-stops.ts';\nexport { locations } from './gtfs/locations.ts';\nexport { networks } from './gtfs/networks.ts';\nexport { pathways } from './gtfs/pathways.ts';\nexport { routeNetworks } from './gtfs/route-networks.ts';\nexport { routes } from './gtfs/routes.ts';\nexport { shapes } from './gtfs/shapes.ts';\nexport { stopAreas } from './gtfs/stop-areas.ts';\nexport { stopTimes } from './gtfs/stop-times.ts';\nexport { stops } from './gtfs/stops.ts';\nexport { timeframes } from './gtfs/timeframes.ts';\nexport { transfers } from './gtfs/transfers.ts';\nexport { translations } from './gtfs/translations.ts';\nexport { trips } from './gtfs/trips.ts';\n\nexport { timetables } from './non-standard/timetables.ts';\nexport { timetablePages } from './non-standard/timetable-pages.ts';\nexport { timetableStopOrder } from './non-standard/timetable-stop-order.ts';\nexport { timetableNotes } from './non-standard/timetable-notes.ts';\nexport { timetableNotesReferences } from './non-standard/timetable-notes-references.ts';\nexport { tripsDatedVehicleJourney } from './non-standard/trips-dated-vehicle-journey.ts';\n\nexport { calendarAttributes } from './gtfs-plus/calendar-attributes.ts';\nexport { directions } from './gtfs-plus/directions.ts';\nexport { routeAttributes } from './gtfs-plus/route-attributes.ts';\nexport { stopAttributes } from './gtfs-plus/stop-attributes.ts';\n\nexport { boardAlight } from './gtfs-ride/board-alight.ts';\nexport { riderTrip } from './gtfs-ride/rider-trip.ts';\nexport { ridership } from './gtfs-ride/ridership.ts';\nexport { tripCapacity } from './gtfs-ride/trip-capacity.ts';\nexport { rideFeedInfo } from './gtfs-ride/ride-feed-info.ts';\n\nexport { tripUpdates } from './gtfs-realtime/trip-updates.ts';\nexport { stopTimeUpdates } from './gtfs-realtime/stop-time-updates.ts';\nexport { vehiclePositions } from './gtfs-realtime/vehicle-positions.ts';\nexport { serviceAlerts } from './gtfs-realtime/service-alerts.ts';\nexport { serviceAlertTargets } from './gtfs-realtime/service-alert-targets.ts';\n\nexport { deadheadTimes } from './ods/deadhead-times.ts';\nexport { deadheads } from './ods/deadheads.ts';\nexport { opsLocations } from './ods/ops-locations.ts';\nexport { runEvents } from './ods/run-events.ts';\nexport { runsPieces } from './ods/runs-pieces.ts';\n","export const agency = {\n filenameBase: 'agency',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'agency_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'agency_name',\n type: 'text',\n required: true,\n nocase: true,\n },\n {\n name: 'agency_url',\n type: 'text',\n required: true,\n },\n {\n name: 'agency_timezone',\n type: 'text',\n required: true,\n },\n {\n name: 'agency_lang',\n type: 'text',\n nocase: true,\n },\n {\n name: 'agency_phone',\n type: 'text',\n nocase: true,\n },\n {\n name: 'agency_fare_url',\n type: 'text',\n },\n {\n name: 'agency_email',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const areas = {\n filenameBase: 'areas',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'area_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'area_name',\n type: 'text',\n },\n ],\n};\n","export const attributions = {\n filenameBase: 'attributions',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'attribution_id',\n type: 'text',\n prefix: true,\n primary: true,\n },\n {\n name: 'agency_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'route_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'trip_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'organization_name',\n type: 'text',\n required: true,\n nocase: true,\n },\n {\n name: 'is_producer',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'is_operator',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'is_authority',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'attribution_url',\n type: 'text',\n },\n {\n name: 'attribution_email',\n type: 'text',\n nocase: true,\n },\n {\n name: 'attribution_phone',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const bookingRules = {\n filenameBase: 'booking_rules',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'booking_rule_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'booking_type',\n type: 'integer',\n required: true,\n min: 0,\n max: 2,\n },\n {\n name: 'prior_notice_duration_min',\n type: 'integer',\n min: 0,\n },\n {\n name: 'prior_notice_duration_max',\n type: 'integer',\n min: 0,\n },\n {\n name: 'prior_notice_last_day',\n type: 'integer',\n min: 0,\n },\n {\n name: 'prior_notice_last_time',\n type: 'time',\n },\n {\n name: 'prior_notice_start_day',\n type: 'integer',\n min: 0,\n },\n {\n name: 'prior_notice_start_time',\n type: 'time',\n },\n {\n name: 'prior_notice_service_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'message',\n type: 'text',\n nocase: true,\n },\n {\n name: 'pickup_message',\n type: 'text',\n nocase: true,\n },\n {\n name: 'drop_off_message',\n type: 'text',\n nocase: true,\n },\n {\n name: 'phone_number',\n type: 'text',\n nocase: true,\n },\n {\n name: 'info_url',\n type: 'text',\n },\n {\n name: 'booking_url',\n type: 'text',\n },\n ],\n};\n","export const calendarDates = {\n filenameBase: 'calendar_dates',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'service_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'date',\n type: 'date',\n required: true,\n primary: true,\n },\n {\n name: 'exception_type',\n type: 'integer',\n required: true,\n min: 1,\n max: 2,\n index: true,\n },\n {\n name: 'holiday_name',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const calendar = {\n filenameBase: 'calendar',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'service_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'monday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'tuesday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'wednesday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'thursday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'friday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'saturday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'sunday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'start_date',\n type: 'date',\n required: true,\n index: true,\n },\n {\n name: 'end_date',\n type: 'date',\n required: true,\n index: true,\n },\n ],\n};\n","export const fareAttributes = {\n filenameBase: 'fare_attributes',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'fare_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'price',\n type: 'real',\n required: true,\n },\n {\n name: 'currency_type',\n type: 'text',\n required: true,\n },\n {\n name: 'payment_method',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'transfers',\n type: 'integer',\n min: 0,\n max: 2,\n },\n {\n name: 'agency_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'transfer_duration',\n type: 'integer',\n min: 0,\n },\n ],\n};\n","export const fareLegRules = {\n filenameBase: 'fare_leg_rules',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'leg_group_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'network_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'from_area_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'to_area_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'from_timeframe_group_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'to_timeframe_group_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'fare_product_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'rule_priority',\n type: 'integer',\n min: 0,\n },\n ],\n};\n","export const fareMedia = {\n filenameBase: 'fare_media',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'fare_media_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'fare_media_name',\n type: 'text',\n },\n {\n name: 'fare_media_type',\n type: 'integer',\n required: true,\n min: 0,\n max: 4,\n },\n ],\n};\n","export const fareProducts = {\n filenameBase: 'fare_products',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'fare_product_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'fare_product_name',\n type: 'text',\n },\n {\n name: 'fare_media_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'amount',\n type: 'real',\n required: true,\n },\n {\n name: 'currency',\n type: 'text',\n required: true,\n },\n ],\n};\n","export const fareRules = {\n filenameBase: 'fare_rules',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'fare_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'route_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'origin_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'destination_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'contains_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n ],\n};\n","export const fareTransferRules = {\n filenameBase: 'fare_transfer_rules',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'from_leg_group_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'to_leg_group_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'transfer_count',\n type: 'integer',\n min: -1,\n primary: true,\n },\n {\n name: 'duration_limit',\n type: 'integer',\n min: 0,\n primary: true,\n },\n {\n name: 'duration_limit_type',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'fare_transfer_type',\n type: 'integer',\n min: 0,\n max: 2,\n required: true,\n },\n {\n name: 'fare_product_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n ],\n};\n","export const feedInfo = {\n filenameBase: 'feed_info',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'feed_publisher_name',\n type: 'text',\n required: true,\n nocase: true,\n },\n {\n name: 'feed_publisher_url',\n type: 'text',\n required: true,\n },\n {\n name: 'feed_lang',\n type: 'text',\n required: true,\n },\n {\n name: 'default_lang',\n type: 'text',\n nocase: true,\n },\n {\n name: 'feed_start_date',\n type: 'date',\n },\n {\n name: 'feed_end_date',\n type: 'date',\n },\n {\n name: 'feed_version',\n type: 'text',\n },\n {\n name: 'feed_contact_email',\n type: 'text',\n nocase: true,\n },\n {\n name: 'feed_contact_url',\n type: 'text',\n },\n ],\n};\n","export const frequencies = {\n filenameBase: 'frequencies',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'trip_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'start_time',\n type: 'time',\n required: true,\n primary: true,\n },\n {\n name: 'end_time',\n type: 'time',\n required: true,\n },\n {\n name: 'headway_secs',\n type: 'integer',\n required: true,\n min: 0,\n },\n {\n name: 'exact_times',\n type: 'integer',\n min: 0,\n max: 1,\n },\n ],\n};\n","export const levels = {\n filenameBase: 'levels',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'level_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'level_index',\n type: 'real',\n required: true,\n },\n {\n name: 'level_name',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const locationGroups = {\n filenameBase: 'location_groups',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'location_group_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'location_group_name',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const locationGroupStops = {\n filenameBase: 'location_group_stops',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'location_group_id',\n type: 'text',\n prefix: true,\n index: true,\n required: true,\n primary: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n required: true,\n prefix: true,\n index: true,\n primary: true,\n },\n ],\n};\n","export const locations = {\n filenameBase: 'locations',\n filenameExtension: 'geojson',\n schema: [\n {\n name: 'geojson',\n type: 'text',\n },\n ],\n};\n","export const networks = {\n filenameBase: 'networks',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'network_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'network_name',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const pathways = {\n filenameBase: 'pathways',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'pathway_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'from_stop_id',\n type: 'text',\n required: true,\n prefix: true,\n },\n {\n name: 'to_stop_id',\n type: 'text',\n required: true,\n prefix: true,\n },\n {\n name: 'pathway_mode',\n type: 'integer',\n required: true,\n min: 1,\n max: 7,\n },\n {\n name: 'is_bidirectional',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'length',\n type: 'real',\n min: 0,\n },\n {\n name: 'traversal_time',\n type: 'integer',\n min: 0,\n },\n {\n name: 'stair_count',\n type: 'integer',\n },\n {\n name: 'max_slope',\n type: 'real',\n },\n {\n name: 'min_width',\n type: 'real',\n min: 0,\n },\n {\n name: 'signposted_as',\n type: 'text',\n nocase: true,\n },\n {\n name: 'reversed_signposted_as',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const routeNetworks = {\n filenameBase: 'route_networks',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'network_id',\n type: 'text',\n required: true,\n prefix: true,\n },\n {\n name: 'route_id',\n type: 'text',\n primary: true,\n index: true,\n prefix: true,\n },\n ],\n};\n","export const routes = {\n filenameBase: 'routes',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'route_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'agency_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'route_short_name',\n type: 'text',\n nocase: true,\n },\n {\n name: 'route_long_name',\n type: 'text',\n nocase: true,\n },\n {\n name: 'route_desc',\n type: 'text',\n nocase: true,\n },\n {\n name: 'route_type',\n type: 'integer',\n required: true,\n min: 0,\n // Support extended GTFS route types with no max value\n // https://developers.google.com/transit/gtfs/reference/extended-route-types\n },\n {\n name: 'route_url',\n type: 'text',\n },\n {\n name: 'route_color',\n type: 'text',\n nocase: true,\n },\n {\n name: 'route_text_color',\n type: 'text',\n nocase: true,\n },\n {\n name: 'route_sort_order',\n type: 'integer',\n min: 0,\n },\n {\n name: 'continuous_pickup',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'continuous_drop_off',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'network_id',\n type: 'text',\n prefix: true,\n },\n ],\n};\n","export const shapes = {\n filenameBase: 'shapes',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'shape_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'shape_pt_lat',\n type: 'real',\n required: true,\n min: -90,\n max: 90,\n },\n {\n name: 'shape_pt_lon',\n type: 'real',\n required: true,\n min: -180,\n max: 180,\n },\n {\n name: 'shape_pt_sequence',\n type: 'integer',\n required: true,\n primary: true,\n min: 0,\n },\n {\n name: 'shape_dist_traveled',\n type: 'real',\n min: 0,\n },\n ],\n};\n","export const stopAreas = {\n filenameBase: 'stop_areas',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'area_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n ],\n};\n","export const stopTimes = {\n filenameBase: 'stop_times',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'trip_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'arrival_time',\n type: 'time',\n },\n {\n name: 'departure_time',\n type: 'time',\n },\n {\n name: 'location_group_id',\n type: 'text',\n prefix: true,\n index: true,\n },\n {\n name: 'location_id',\n type: 'text',\n prefix: true,\n index: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n required: true,\n prefix: true,\n index: true,\n },\n {\n name: 'stop_sequence',\n type: 'integer',\n required: true,\n primary: true,\n min: 0,\n },\n {\n name: 'stop_headsign',\n type: 'text',\n nocase: true,\n },\n {\n name: 'start_pickup_drop_off_window',\n type: 'time',\n },\n {\n name: 'pickup_type',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'drop_off_type',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'continuous_pickup',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'continuous_drop_off',\n type: 'integer',\n min: 0,\n max: 3,\n },\n {\n name: 'shape_dist_traveled',\n type: 'real',\n min: 0,\n },\n {\n name: 'timepoint',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'pickup_booking_rule_id',\n type: 'text',\n prefix: true,\n index: true,\n },\n {\n name: 'drop_off_booking_rule_id',\n type: 'text',\n prefix: true,\n index: true,\n },\n ],\n};\n","export const stops = {\n filenameBase: 'stops',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'stop_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'stop_code',\n type: 'text',\n },\n {\n name: 'stop_name',\n type: 'text',\n nocase: true,\n },\n {\n name: 'tts_stop_name',\n type: 'text',\n nocase: true,\n },\n {\n name: 'stop_desc',\n type: 'text',\n nocase: true,\n },\n {\n name: 'stop_lat',\n type: 'real',\n min: -90,\n max: 90,\n },\n {\n name: 'stop_lon',\n type: 'real',\n min: -180,\n max: 180,\n },\n {\n name: 'zone_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'stop_url',\n type: 'text',\n },\n {\n name: 'location_type',\n type: 'integer',\n min: 0,\n max: 4,\n },\n {\n name: 'parent_station',\n type: 'text',\n index: true,\n },\n {\n name: 'stop_timezone',\n type: 'text',\n },\n {\n name: 'wheelchair_boarding',\n type: 'integer',\n min: 0,\n max: 2,\n },\n {\n name: 'level_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'platform_code',\n type: 'text',\n },\n ],\n};\n","export const timeframes = {\n filenameBase: 'timeframes',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'timeframe_group_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'start_time',\n type: 'time',\n primary: true,\n },\n {\n name: 'end_time',\n type: 'time',\n primary: true,\n },\n {\n name: 'service_id',\n type: 'text',\n required: true,\n primary: true,\n index: true,\n prefix: true,\n },\n ],\n};\n","export const transfers = {\n filenameBase: 'transfers',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'from_stop_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'to_stop_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'from_route_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'to_route_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'from_trip_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'to_trip_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'transfer_type',\n type: 'integer',\n min: 0,\n max: 5,\n default: 0,\n },\n {\n name: 'min_transfer_time',\n type: 'integer',\n min: 0,\n },\n ],\n};\n","export const translations = {\n filenameBase: 'translations',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'table_name',\n type: 'text',\n primary: true,\n required: true,\n },\n {\n name: 'field_name',\n type: 'text',\n primary: true,\n required: true,\n },\n {\n name: 'language',\n type: 'text',\n primary: true,\n required: true,\n },\n {\n name: 'translation',\n type: 'text',\n required: true,\n },\n {\n name: 'record_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'record_sub_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'field_value',\n type: 'text',\n primary: true,\n },\n ],\n};\n","export const trips = {\n filenameBase: 'trips',\n filenameExtension: 'txt',\n schema: [\n {\n name: 'route_id',\n type: 'text',\n required: true,\n index: true,\n prefix: true,\n },\n {\n name: 'service_id',\n type: 'text',\n required: true,\n index: true,\n prefix: true,\n },\n {\n name: 'trip_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'trip_headsign',\n type: 'text',\n nocase: true,\n },\n {\n name: 'trip_short_name',\n type: 'text',\n nocase: true,\n },\n {\n name: 'direction_id',\n type: 'integer',\n min: 0,\n max: 1,\n index: true,\n },\n {\n name: 'block_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'shape_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'wheelchair_accessible',\n type: 'integer',\n min: 0,\n max: 2,\n },\n {\n name: 'bikes_allowed',\n type: 'integer',\n min: 0,\n max: 2,\n },\n ],\n};\n","export const timetables = {\n filenameBase: 'timetables',\n filenameExtension: 'txt',\n nonstandard: true,\n schema: [\n {\n name: 'timetable_id',\n type: 'text',\n prefix: true,\n required: true,\n primary: true,\n },\n {\n name: 'route_id',\n type: 'text',\n prefix: true,\n required: true,\n primary: true,\n },\n {\n name: 'direction_id',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'start_date',\n type: 'date',\n },\n {\n name: 'end_date',\n type: 'date',\n },\n {\n name: 'monday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'tuesday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'wednesday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'thursday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'friday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'saturday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'sunday',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n },\n {\n name: 'start_time',\n type: 'time',\n },\n {\n name: 'end_time',\n type: 'time',\n },\n {\n name: 'timetable_label',\n type: 'text',\n nocase: true,\n },\n {\n name: 'service_notes',\n type: 'text',\n nocase: true,\n },\n {\n name: 'orientation',\n type: 'text',\n },\n {\n name: 'timetable_page_id',\n type: 'text',\n },\n {\n name: 'timetable_sequence',\n type: 'integer',\n min: 0,\n index: true,\n },\n {\n name: 'direction_name',\n type: 'text',\n },\n {\n name: 'include_exceptions',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'show_trip_continuation',\n type: 'integer',\n min: 0,\n max: 1,\n },\n ],\n};\n","export const timetablePages = {\n filenameBase: 'timetable_pages',\n filenameExtension: 'txt',\n nonstandard: true,\n schema: [\n {\n name: 'timetable_page_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'timetable_page_label',\n type: 'text',\n },\n {\n name: 'filename',\n type: 'text',\n },\n ],\n};\n","export const timetableStopOrder = {\n filenameBase: 'timetable_stop_order',\n filenameExtension: 'txt',\n nonstandard: true,\n schema: [\n {\n name: 'timetable_id',\n type: 'text',\n index: true,\n prefix: true,\n required: true,\n primary: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n prefix: true,\n required: true,\n primary: true,\n },\n {\n name: 'stop_sequence',\n type: 'integer',\n min: 0,\n index: true,\n required: true,\n primary: true,\n },\n ],\n};\n","export const timetableNotes = {\n filenameBase: 'timetable_notes',\n filenameExtension: 'txt',\n nonstandard: true,\n schema: [\n {\n name: 'note_id',\n type: 'text',\n primary: true,\n prefix: true,\n required: true,\n },\n {\n name: 'symbol',\n type: 'text',\n },\n {\n name: 'note',\n type: 'text',\n nocase: true,\n required: true,\n },\n ],\n};\n","export const timetableNotesReferences = {\n filenameBase: 'timetable_notes_references',\n filenameExtension: 'txt',\n nonstandard: true,\n schema: [\n {\n name: 'note_id',\n type: 'text',\n prefix: true,\n required: true,\n primary: true,\n },\n {\n name: 'timetable_id',\n type: 'text',\n prefix: true,\n primary: true,\n },\n {\n name: 'route_id',\n type: 'text',\n prefix: true,\n primary: true,\n },\n {\n name: 'trip_id',\n type: 'text',\n prefix: true,\n primary: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n prefix: true,\n primary: true,\n },\n {\n name: 'stop_sequence',\n type: 'integer',\n min: 0,\n primary: true,\n },\n {\n name: 'show_on_stoptime',\n type: 'integer',\n min: 0,\n max: 1,\n },\n ],\n};\n","export const tripsDatedVehicleJourney = {\n filenameBase: 'trips_dated_vehicle_journey',\n filenameExtension: 'txt',\n nonstandard: true,\n schema: [\n {\n name: 'trip_id',\n type: 'text',\n required: true,\n index: true,\n prefix: true,\n },\n {\n name: 'operating_day_date',\n type: 'text',\n index: true,\n required: true,\n },\n {\n name: 'dated_vehicle_journey_gid',\n type: 'text',\n required: true,\n },\n {\n name: 'journey_number',\n type: 'integer',\n min: 0,\n max: 65535,\n index: true,\n },\n ],\n};\n","export const calendarAttributes = {\n filenameBase: 'calendar_attributes',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-plus',\n schema: [\n {\n name: 'service_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'service_description',\n type: 'text',\n required: true,\n nocase: true,\n },\n ],\n};\n","export const directions = {\n filenameBase: 'directions',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-plus',\n schema: [\n {\n name: 'route_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'direction_id',\n type: 'integer',\n min: 0,\n max: 1,\n primary: true,\n },\n {\n name: 'direction',\n type: 'text',\n required: true,\n },\n ],\n};\n","export const routeAttributes = {\n filenameBase: 'route_attributes',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-plus',\n schema: [\n {\n name: 'route_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'category',\n type: 'integer',\n min: 0,\n required: true,\n },\n {\n name: 'subcategory',\n type: 'integer',\n min: 101,\n required: true,\n },\n {\n name: 'running_way',\n type: 'integer',\n min: 1,\n required: true,\n },\n ],\n};\n","export const stopAttributes = {\n filenameBase: 'stop_attributes',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-plus',\n schema: [\n {\n name: 'stop_id',\n type: 'text',\n required: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'accessibility_id',\n type: 'integer',\n min: 0,\n },\n {\n name: 'cardinal_direction',\n type: 'text',\n },\n {\n name: 'relative_position',\n type: 'text',\n },\n {\n name: 'stop_city',\n type: 'text',\n nocase: true,\n },\n ],\n};\n","export const boardAlight = {\n filenameBase: 'board_alight',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-ride',\n schema: [\n {\n name: 'trip_id',\n type: 'text',\n required: true,\n index: true,\n prefix: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n required: true,\n index: true,\n prefix: true,\n },\n {\n name: 'stop_sequence',\n type: 'integer',\n required: true,\n min: 0,\n index: true,\n },\n {\n name: 'record_use',\n type: 'integer',\n required: true,\n min: 0,\n max: 1,\n index: true,\n },\n {\n name: 'schedule_relationship',\n type: 'integer',\n min: 0,\n max: 8,\n },\n {\n name: 'boardings',\n type: 'integer',\n min: 0,\n },\n {\n name: 'alightings',\n type: 'integer',\n min: 0,\n },\n {\n name: 'current_load',\n type: 'integer',\n min: 0,\n },\n {\n name: 'load_count',\n type: 'integer',\n min: 0,\n },\n {\n name: 'load_type',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'rack_down',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'bike_boardings',\n type: 'integer',\n min: 0,\n },\n {\n name: 'bike_alightings',\n type: 'integer',\n min: 0,\n },\n {\n name: 'ramp_used',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'ramp_boardings',\n type: 'integer',\n min: 0,\n },\n {\n name: 'ramp_alightings',\n type: 'integer',\n min: 0,\n },\n {\n name: 'service_date',\n type: 'date',\n index: true,\n },\n {\n name: 'service_arrival_time',\n type: 'time',\n },\n {\n name: 'service_departure_time',\n type: 'time',\n },\n {\n name: 'source',\n type: 'integer',\n min: 0,\n max: 4,\n },\n ],\n};\n","export const riderTrip = {\n filenameBase: 'rider_trip',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-ride',\n schema: [\n {\n name: 'rider_id',\n type: 'text',\n primary: true,\n prefix: true,\n },\n {\n name: 'agency_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'trip_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'boarding_stop_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'boarding_stop_sequence',\n type: 'integer',\n min: 0,\n index: true,\n },\n {\n name: 'alighting_stop_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'alighting_stop_sequence',\n type: 'integer',\n min: 0,\n index: true,\n },\n {\n name: 'service_date',\n type: 'date',\n index: true,\n },\n {\n name: 'boarding_time',\n type: 'time',\n },\n {\n name: 'alighting_time',\n type: 'time',\n },\n {\n name: 'rider_type',\n type: 'integer',\n min: 0,\n max: 13,\n },\n {\n name: 'rider_type_description',\n type: 'text',\n },\n {\n name: 'fare_paid',\n type: 'real',\n },\n {\n name: 'transaction_type',\n type: 'integer',\n min: 0,\n max: 8,\n },\n {\n name: 'fare_media',\n type: 'integer',\n min: 0,\n max: 9,\n },\n {\n name: 'accompanying_device',\n type: 'integer',\n min: 0,\n max: 6,\n },\n {\n name: 'transfer_status',\n type: 'integer',\n min: 0,\n max: 1,\n },\n ],\n};\n","export const ridership = {\n filenameBase: 'ridership',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-ride',\n schema: [\n {\n name: 'total_boardings',\n type: 'integer',\n min: 0,\n required: true,\n },\n {\n name: 'total_alightings',\n type: 'integer',\n min: 0,\n required: true,\n },\n {\n name: 'ridership_start_date',\n type: 'date',\n index: true,\n },\n {\n name: 'ridership_end_date',\n type: 'date',\n index: true,\n },\n {\n name: 'ridership_start_time',\n type: 'time',\n },\n {\n name: 'ridership_end_time',\n type: 'time',\n },\n {\n name: 'service_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'monday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'tuesday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'wednesday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'thursday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'friday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'saturday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'sunday',\n type: 'integer',\n min: 0,\n max: 1,\n },\n {\n name: 'agency_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'route_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'direction_id',\n type: 'integer',\n min: 0,\n max: 1,\n index: true,\n },\n {\n name: 'trip_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n prefix: true,\n },\n ],\n};\n","export const tripCapacity = {\n filenameBase: 'trip_capacity',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-ride',\n schema: [\n {\n name: 'agency_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'trip_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'service_date',\n type: 'date',\n index: true,\n },\n {\n name: 'vehicle_description',\n type: 'text',\n },\n {\n name: 'seated_capacity',\n type: 'integer',\n min: 0,\n },\n {\n name: 'standing_capacity',\n type: 'integer',\n min: 0,\n },\n {\n name: 'wheelchair_capacity',\n type: 'integer',\n min: 0,\n },\n {\n name: 'bike_capacity',\n type: 'integer',\n min: 0,\n },\n ],\n};\n","export const rideFeedInfo = {\n filenameBase: 'ride_feed_info',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'gtfs-ride',\n schema: [\n {\n name: 'ride_files',\n type: 'integer',\n min: 0,\n max: 6,\n required: true,\n },\n {\n name: 'ride_start_date',\n type: 'date',\n index: true,\n },\n {\n name: 'ride_end_date',\n type: 'date',\n index: true,\n },\n {\n name: 'gtfs_feed_date',\n type: 'date',\n index: true,\n },\n {\n name: 'default_currency_type',\n type: 'text',\n },\n {\n name: 'ride_feed_version',\n type: 'text',\n },\n ],\n};\n","export const tripUpdates = {\n filenameBase: 'trip_updates',\n extension: 'gtfs-realtime',\n schema: [\n {\n name: 'id',\n type: 'text',\n required: true,\n primary: true,\n index: true,\n source: 'id',\n },\n {\n name: 'vehicle_id',\n type: 'text',\n index: true,\n source: 'tripUpdate.vehicle.id',\n default: null,\n },\n {\n name: 'trip_id',\n type: 'text',\n index: true,\n source: 'tripUpdate.trip.tripId',\n default: null,\n },\n {\n name: 'trip_start_time',\n type: 'text',\n source: 'tripUpdate.trip.startTime',\n default: null,\n },\n {\n name: 'direction_id',\n type: 'integer',\n source: 'tripUpdate.trip.directionId',\n default: null,\n },\n {\n name: 'route_id',\n type: 'text',\n index: true,\n source: 'tripUpdate.trip.routeId',\n default: null,\n },\n {\n name: 'start_date',\n type: 'text',\n source: 'tripUpdate.trip.startDate',\n default: null,\n },\n {\n name: 'timestamp',\n type: 'text',\n source: 'tripUpdate.timestamp',\n default: null,\n },\n {\n name: 'schedule_relationship',\n type: 'text',\n source: 'tripUpdate.trip.scheduleRelationship',\n default: null,\n },\n {\n name: 'created_timestamp',\n type: 'integer',\n required: true,\n },\n {\n name: 'expiration_timestamp',\n type: 'integer',\n required: true,\n },\n ],\n};\n","export const stopTimeUpdates = {\n filenameBase: 'stop_time_updates',\n extension: 'gtfs-realtime',\n schema: [\n {\n name: 'trip_id',\n type: 'text',\n index: true,\n source: 'parent.tripUpdate.trip.tripId',\n default: null,\n },\n {\n name: 'trip_start_time',\n type: 'text',\n source: 'parent.tripUpdate.trip.startTime',\n default: null,\n },\n {\n name: 'direction_id',\n type: 'integer',\n source: 'parent.tripUpdate.trip.directionId',\n default: null,\n },\n {\n name: 'route_id',\n type: 'text',\n index: true,\n source: 'parent.tripUpdate.trip.routeId',\n default: null,\n },\n {\n name: 'stop_id',\n type: 'text',\n index: true,\n source: 'stopId',\n default: null,\n },\n {\n name: 'stop_sequence',\n type: 'integer',\n source: 'stopSequence',\n default: null,\n },\n {\n name: 'arrival_delay',\n type: 'integer',\n source: 'arrival.delay',\n default: null,\n },\n {\n name: 'departure_delay',\n type: 'integer',\n source: 'departure.delay',\n default: null,\n },\n {\n name: 'departure_timestamp',\n type: 'text',\n source: 'departure.time',\n default: null,\n },\n {\n name: 'arrival_timestamp',\n type: 'text',\n source: 'arrival.time',\n default: null,\n },\n {\n name: 'schedule_relationship',\n type: 'text',\n source: 'scheduleRelationship',\n default: null,\n },\n {\n name: 'created_timestamp',\n type: 'integer',\n required: true,\n },\n {\n name: 'expiration_timestamp',\n type: 'integer',\n required: true,\n },\n ],\n};\n","export const vehiclePositions = {\n filenameBase: 'vehicle_positions',\n extension: 'gtfs-realtime',\n schema: [\n {\n name: 'id',\n type: 'text',\n required: true,\n primary: true,\n index: true,\n source: 'id',\n },\n {\n name: 'bearing',\n type: 'real',\n source: 'vehicle.position.bearing',\n default: null,\n },\n {\n name: 'latitude',\n type: 'real',\n min: -90,\n max: 90,\n source: 'vehicle.position.latitude',\n default: null,\n },\n {\n name: 'longitude',\n type: 'real',\n source: 'vehicle.position.longitude',\n min: -180,\n max: 180,\n default: null,\n },\n {\n name: 'speed',\n type: 'real',\n min: 0,\n source: 'vehicle.position.speed',\n default: null,\n },\n {\n name: 'current_stop_sequence',\n type: 'integer',\n source: 'vehicle.currentStopSequence',\n default: null,\n },\n {\n name: 'trip_id',\n type: 'text',\n index: true,\n source: 'vehicle.trip.tripId',\n default: null,\n },\n {\n name: 'trip_start_date',\n type: 'text',\n index: true,\n source: 'vehicle.trip.startDate',\n default: null,\n },\n {\n name: 'trip_start_time',\n type: 'text',\n index: true,\n source: 'vehicle.trip.startTime',\n default: null,\n },\n {\n name: 'congestion_level',\n type: 'text',\n source: 'vehicle.congestionLevel',\n default: null,\n },\n {\n name: 'occupancy_status',\n type: 'text',\n source: 'vehicle.occupancyStatus',\n default: null,\n },\n {\n name: 'occupancy_percentage',\n type: 'integer',\n source: 'vehicle.occupancyPercentage',\n default: null,\n },\n {\n name: 'vehicle_stop_status',\n type: 'text',\n source: 'vehicle.vehicleStopStatus',\n default: null,\n },\n {\n name: 'vehicle_id',\n type: 'text',\n index: true,\n source: 'vehicle.vehicle.id',\n default: null,\n },\n {\n name: 'vehicle_label',\n type: 'text',\n source: 'vehicle.vehicle.label',\n default: null,\n },\n {\n name: 'vehicle_license_plate',\n type: 'text',\n source: 'vehicle.vehicle.licensePlate',\n default: null,\n },\n {\n name: 'vehicle_wheelchair_accessible',\n type: 'text',\n source: 'vehicle.vehicle.wheelchairAccessible',\n default: null,\n },\n {\n name: 'timestamp',\n type: 'text',\n source: 'vehicle.timestamp',\n default: null,\n },\n {\n name: 'created_timestamp',\n type: 'integer',\n required: true,\n },\n {\n name: 'expiration_timestamp',\n type: 'integer',\n required: true,\n },\n ],\n};\n","export const serviceAlerts = {\n filenameBase: 'service_alerts',\n extension: 'gtfs-realtime',\n schema: [\n {\n name: 'id',\n type: 'text',\n required: true,\n primary: true,\n index: true,\n source: 'id',\n },\n {\n name: 'active_period',\n type: 'json',\n source: 'alert.activePeriod',\n },\n {\n name: 'cause',\n type: 'text',\n source: 'alert.cause',\n },\n {\n name: 'effect',\n type: 'text',\n source: 'alert.effect',\n },\n {\n name: 'url',\n type: 'text',\n source: 'alert.url.translation[0].text',\n default: '',\n },\n {\n name: 'start_time',\n type: 'text',\n required: true,\n source: 'alert.activePeriod[0].start',\n default: '',\n },\n {\n name: 'end_time',\n type: 'text',\n required: true,\n source: 'alert.activePeriod[0].end',\n default: '',\n },\n {\n name: 'header_text',\n type: 'text',\n required: true,\n source: 'alert.headerText.translation[0].text',\n default: '',\n },\n {\n name: 'description_text',\n type: 'text',\n required: true,\n source: 'alert.descriptionText.translation[0].text',\n default: '',\n },\n {\n name: 'tts_header_text',\n type: 'text',\n source: 'alert.ttsHeaderText.translation[0].text',\n },\n {\n name: 'tts_description_text',\n type: 'text',\n source: 'alert.ttsDescriptionText.translation[0].text',\n },\n {\n name: 'severity_level',\n type: 'text',\n source: 'alert.severityLevel',\n },\n {\n name: 'created_timestamp',\n type: 'integer',\n required: true,\n },\n {\n name: 'expiration_timestamp',\n type: 'integer',\n required: true,\n },\n ],\n};\n","export const serviceAlertTargets = {\n filenameBase: 'service_alert_targets',\n extension: 'gtfs-realtime',\n schema: [\n {\n name: 'alert_id',\n type: 'text',\n required: true,\n primary: true,\n source: 'parent.id',\n },\n {\n name: 'stop_id',\n type: 'text',\n index: true,\n source: 'stopId',\n default: null,\n },\n {\n name: 'route_id',\n type: 'text',\n index: true,\n source: 'routeId',\n default: null,\n },\n {\n name: 'created_timestamp',\n type: 'integer',\n required: true,\n },\n {\n name: 'expiration_timestamp',\n type: 'integer',\n required: true,\n },\n ],\n};\n","export const deadheadTimes = {\n filenameBase: 'deadhead_times',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'ods',\n schema: [\n {\n name: 'deadhead_id',\n type: 'text',\n required: true,\n index: true,\n primary: true,\n prefix: true,\n },\n {\n name: 'arrival_time',\n type: 'time',\n required: true,\n },\n {\n name: 'departure_time',\n type: 'time',\n required: true,\n },\n {\n name: 'ops_location_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'stop_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'location_sequence',\n type: 'integer',\n required: true,\n primary: true,\n min: 0,\n index: true,\n },\n {\n name: 'shape_dist_traveled',\n type: 'real',\n min: 0,\n },\n ],\n};\n","export const deadheads = {\n filenameBase: 'deadheads',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'ods',\n schema: [\n {\n name: 'deadhead_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'service_id',\n type: 'text',\n required: true,\n prefix: true,\n },\n {\n name: 'block_id',\n type: 'text',\n required: true,\n index: true,\n prefix: true,\n },\n {\n name: 'shape_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'to_trip_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'from_trip_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'to_deadhead_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n {\n name: 'from_deadhead_id',\n type: 'text',\n index: true,\n prefix: true,\n },\n ],\n};\n","export const opsLocations = {\n filenameBase: 'ops_locations',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'ods',\n schema: [\n {\n name: 'ops_location_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'ops_location_code',\n type: 'text',\n },\n {\n name: 'ops_location_name',\n type: 'text',\n required: true,\n nocase: true,\n },\n {\n name: 'ops_location_desc',\n type: 'text',\n nocase: true,\n },\n {\n name: 'ops_location_lat',\n type: 'real',\n required: true,\n min: -90,\n max: 90,\n },\n {\n name: 'ops_location_lon',\n type: 'real',\n required: true,\n min: -180,\n max: 180,\n },\n ],\n};\n","export const runEvents = {\n filenameBase: 'run_event',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'ods',\n schema: [\n {\n name: 'run_event_id',\n type: 'text',\n primary: true,\n required: true,\n prefix: true,\n },\n {\n name: 'piece_id',\n type: 'text',\n required: true,\n prefix: true,\n },\n {\n name: 'event_type',\n type: 'integer',\n required: true,\n min: 0,\n index: true,\n },\n {\n name: 'event_name',\n type: 'text',\n nocase: true,\n },\n {\n name: 'event_time',\n type: 'text',\n required: true,\n },\n {\n name: 'event_duration',\n type: 'integer',\n required: true,\n min: 0,\n },\n {\n name: 'event_from_location_type',\n type: 'integer',\n min: 0,\n max: 1,\n index: true,\n },\n {\n name: 'event_from_location_id',\n type: 'text',\n prefix: true,\n },\n {\n name: 'event_to_location_type',\n type: 'integer',\n min: 0,\n max: 1,\n index: true,\n },\n {\n name: 'event_to_location_id',\n type: 'text',\n prefix: true,\n },\n ],\n};\n","export const runsPieces = {\n filenameBase: 'runs_pieces',\n filenameExtension: 'txt',\n nonstandard: true,\n extension: 'ods',\n schema: [\n {\n name: 'run_id',\n type: 'text',\n required: true,\n },\n {\n name: 'piece_id',\n type: 'text',\n primary: true,\n required: true,\n },\n {\n name: 'start_type',\n type: 'integer',\n required: true,\n min: 0,\n max: 2,\n index: true,\n },\n {\n name: 'start_trip_id',\n type: 'text',\n required: true,\n index: true,\n },\n {\n name: 'start_trip_position',\n type: 'integer',\n min: 0,\n },\n {\n name: 'end_type',\n type: 'integer',\n required: true,\n min: 0,\n max: 2,\n index: true,\n },\n {\n name: 'end_trip_id',\n type: 'text',\n required: true,\n index: true,\n },\n {\n name: 'end_trip_position',\n type: 'integer',\n min: 0,\n },\n ],\n};\n","import fs from 'fs';\n\nimport Database from 'better-sqlite3';\nimport untildify from 'untildify';\n\nconst dbs: { [key: string]: Database.Database } = {};\n\nfunction setupDb(sqlitePath: string) {\n const db = new Database(untildify(sqlitePath));\n db.pragma('journal_mode = OFF');\n db.pragma('synchronous = OFF');\n db.pragma('temp_store = MEMORY');\n dbs[sqlitePath] = db;\n\n return db;\n}\n\nexport function openDb(\n config: { db?: Database.Database; sqlitePath?: string } | null = null,\n): Database.Database {\n // If config is passed, use that to open or return db\n if (config) {\n const { sqlitePath = ':memory:', db } = config;\n\n // If db connection is passed, use it\n if (db) {\n return db;\n }\n\n // If db connection already exists, return it\n if (dbs[sqlitePath]) {\n return dbs[sqlitePath];\n }\n\n // If no db connection exists, create it\n return setupDb(sqlitePath);\n }\n\n // If no db connection exists, create a new one in memory\n if (Object.keys(dbs).length === 0) {\n return setupDb(':memory:');\n }\n\n // If only one db connection already exists, use it\n if (Object.keys(dbs).length === 1) {\n const filename = Object.keys(dbs)[0];\n return dbs[filename];\n }\n\n if (Object.keys(dbs).length > 1) {\n throw new Error(\n 'Multiple databases open, please specify which one to use.',\n );\n }\n\n throw new Error('Unable to find database connection.');\n}\n\nexport function closeDb(db: Database.Database | null = null): void {\n if (Object.keys(dbs).length === 0) {\n throw new Error(\n 'No database connection. Call `openDb(config)` before using any methods.',\n );\n }\n\n if (!db) {\n if (Object.keys(dbs).length > 1) {\n throw new Error(\n 'Multiple database connections. Pass the db you want to close as a parameter to `closeDb`.',\n );\n }\n\n db = dbs[Object.keys(dbs)[0]];\n }\n\n db.close();\n delete dbs[db.name];\n}\n\nexport function deleteDb(db: Database.Database | null = null): void {\n if (Object.keys(dbs).length === 0) {\n throw new Error(\n 'No database connection. Call `openDb(config)` before using any methods.',\n );\n }\n\n if (!db) {\n if (Object.keys(dbs).length > 1) {\n throw new Error(\n 'Multiple database connections. Pass the db you want to delete as a parameter to `deleteDb`.',\n );\n }\n\n db = dbs[Object.keys(dbs)[0]];\n }\n\n db.close();\n\n fs.unlinkSync(db.name);\n\n delete dbs[db.name];\n}\n","import {\n cloneDeep,\n compact,\n filter,\n groupBy,\n last,\n omit,\n sortBy,\n omitBy,\n} from 'lodash-es';\nimport { feature, featureCollection } from '@turf/helpers';\nimport { Shape, Stop } from '../types/global_interfaces.ts';\n\n/** Represents a GeoJSON coordinate pair [longitude, latitude] */\ntype Position = [number, number];\n\n/**\n * Validates if a string is valid JSON\n * @param {string} string - The string to validate as JSON\n * @returns {boolean} True if string is valid JSON, false otherwise\n * @example\n * isValidJSON('{\"key\": \"value\"}') // returns true\n * isValidJSON('invalid json') // returns false\n */\nexport function isValidJSON(string: string): boolean {\n try {\n JSON.parse(string);\n return true;\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Validates if an array of positions forms a valid LineString\n * @param {Position[]} [lineString] - Array of coordinate pairs\n * @returns {boolean} True if lineString is valid, false otherwise\n */\nfunction isValidLineString(lineString?: Position[]): boolean {\n if (!lineString || lineString.length <= 1) {\n return false;\n }\n\n // Reject linestrings with two identical points\n if (lineString.length === 2) {\n const [[x1, y1], [x2, y2]] = lineString;\n return !(x1 === x2 && y1 === y2);\n }\n\n return true;\n}\n\n/**\n * Consolidates shape groups into unique line segments\n * @param {Shape[][]} shapeGroups - Array of shape point groups\n * @returns {Position[][]} Array of consolidated line strings\n */\nfunction consolidateShapes(shapeGroups: Shape[][]): Position[][] {\n const keys = new Set<string>();\n const segmentsArray = shapeGroups.map((shapes) =>\n shapes.reduce<Position[][]>((memo, point, idx) => {\n if (idx > 0) {\n const prevPoint = shapes[idx - 1];\n memo.push([\n [prevPoint.shape_pt_lon, prevPoint.shape_pt_lat],\n [point.shape_pt_lon, point.shape_pt_lat],\n ]);\n }\n return memo;\n }, []),\n );\n\n const consolidatedLineStrings: Position[][] = [];\n\n for (const segments of segmentsArray) {\n consolidatedLineStrings.push([]);\n\n for (const segment of segments) {\n const key1 = segment.flat().join(',');\n const key2 = segment.reverse().flat().join(',');\n const currentLine = last(consolidatedLineStrings);\n\n if (!currentLine || keys.has(key1) || keys.has(key2)) {\n consolidatedLineStrings.push([]);\n continue;\n }\n\n if (currentLine.length === 0) {\n currentLine.push(segment[0]);\n }\n currentLine.push(segment[1]);\n keys.add(key1);\n keys.add(key2);\n }\n }\n\n return filter(consolidatedLineStrings, isValidLineString);\n}\n\n/**\n * Formats a color string to hex format\n * @param {string | null | undefined} color - Color string to format\n * @returns {string | undefined} Formatted hex color or undefined\n * @example\n * formatHexColor('FF0000') // returns '#FF0000'\n */\nfunction formatHexColor(color: string | null | undefined): string | undefined {\n if (!color) return undefined;\n return `#${color}`;\n}\n\n/**\n * Formats properties object by cleaning null values and formatting colors\n * @param {Record<string, any>} properties - Properties object to format\n * @returns {Record<string, any>} Formatted properties object\n */\nfunction formatProperties(\n properties: Record<string, any>,\n): Record<string, any> {\n const formattedProperties = cloneDeep(\n omitBy(properties, (value) => value == null),\n );\n\n const formattedRouteColor = formatHexColor(properties.route_color);\n const formattedRouteTextColor = formatHexColor(properties.route_text_color);\n\n if (formattedRouteColor) {\n formattedProperties.route_color = formattedRouteColor;\n }\n\n if (formattedRouteTextColor) {\n formattedProperties.route_text_color = formattedRouteTextColor;\n }\n\n if (properties.routes) {\n formattedProperties.routes = properties.routes.map(\n (route: Record<string, any>) => formatProperties(route),\n );\n }\n\n return formattedProperties;\n}\n\n/**\n * Converts GTFS shapes to GeoJSON Feature\n * @param {Shape[]} shapes - Array of GTFS shapes\n * @param {Record<string, any>} [properties={}] - Properties to add to the feature\n * @returns {Feature} GeoJSON Feature with MultiLineString geometry\n */\nexport function shapesToGeoJSONFeature(\n shapes: Shape[],\n properties: Record<string, any> = {},\n) {\n const shapeGroups = Object.values(groupBy(shapes, 'shape_id')).map(\n (shapeGroup) => sortBy(shapeGroup, 'shape_pt_sequence'),\n );\n\n const lineStrings = consolidateShapes(shapeGroups);\n\n return feature(\n {\n type: 'MultiLineString',\n coordinates: lineStrings,\n },\n formatProperties(properties),\n );\n}\n\n/**\n * Converts GTFS stops to GeoJSON FeatureCollection\n * @param {Stop[]} stops - Array of GTFS stops\n * @returns {FeatureCollection} GeoJSON FeatureCollection of Point features\n */\nexport function stopsToGeoJSONFeatureCollection(stops: Stop[]) {\n const features = compact(\n stops.map((stop) => {\n if (!stop.stop_lon || !stop.stop_lat) {\n return undefined;\n }\n\n return feature(\n {\n type: 'Point',\n coordinates: [stop.stop_lon, stop.stop_lat],\n },\n formatProperties(omit(stop, ['stop_lat', 'stop_lon'])),\n );\n }),\n );\n\n return featureCollection(features);\n}\n","import pluralize from 'pluralize';\nimport GtfsRealtimeBindings from 'gtfs-realtime-bindings';\nimport sqlString from 'sqlstring-sqlite';\nimport mapSeries from 'promise-map-series';\n\nimport * as models from '../models/models.ts';\nimport { openDb } from './db.ts';\nimport { log, logError, logWarning } from './log-utils.ts';\nimport {\n convertLongTimeToDate,\n setDefaultConfig,\n validateConfigForImport,\n} from './utils.ts';\n\nimport {\n Config,\n ConfigAgency,\n ModelColumn,\n} from '../types/global_interfaces.ts';\n\ninterface GtfsRealtimeTask {\n realtimeAlerts?: {\n url: string;\n headers?: Record<string, string>;\n };\n realtimeTripUpdates?: {\n url: string;\n headers?: Record<string, string>;\n };\n realtimeVehiclePositions?: {\n url: string;\n headers?: Record<string, string>;\n };\n downloadTimeout?: number;\n gtfsRealtimeExpirationSeconds: number;\n ignoreErrors: boolean;\n sqlitePath: string;\n currentTimestamp: number;\n log: (message: string, newLine?: boolean) => void;\n logWarning: (message: string) => void;\n logError: (message: string) => void;\n}\n\nfunction getNestedProperty(obj: any, defaultValue: any, path?: string) {\n if (path === undefined) return defaultValue;\n const arr = path.split('.');\n while (arr.length) {\n const nextKey = arr.shift();\n if (nextKey === undefined) {\n return defaultValue;\n } else if (obj == null) {\n return defaultValue;\n } else if (nextKey?.includes('[')) {\n const arrayKey = nextKey.match(/(\\w*)\\[(\\d+)\\]/);\n if (arrayKey === null) {\n return defaultValue;\n }\n if (obj[arrayKey[1]] === undefined) {\n return defaultValue;\n }\n\n if (obj[arrayKey[1]][arrayKey[2]] === undefined) {\n return defaultValue;\n }\n\n obj = obj[arrayKey[1]][arrayKey[2]];\n } else {\n if (obj[nextKey] === undefined) {\n return defaultValue;\n }\n obj = obj[nextKey];\n }\n }\n\n if (obj?.__isLong__) return convertLongTimeToDate(obj);\n\n return obj;\n}\n\nasync function fetchGtfsRealtimeData(\n urlConfig: { url: string; headers?: Record<string, string> },\n task: GtfsRealtimeTask,\n) {\n task.log(`Downloading GTFS-Realtime from ${urlConfig.url}`);\n const response = await fetch(urlConfig.url, {\n method: 'GET',\n headers: {\n ...(urlConfig.headers ?? {}),\n 'Accept-Encoding': 'gzip',\n },\n signal: task.downloadTimeout\n ? AbortSignal.timeout(task.downloadTimeout)\n : undefined,\n });\n\n if (response.status !== 200) {\n task.logWarning(\n `Unable to download GTFS-Realtime from ${urlConfig.url}. Got status ${response.status}.`,\n );\n return null;\n }\n\n const buffer = await response.arrayBuffer();\n const message = GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(\n new Uint8Array(buffer),\n );\n return GtfsRealtimeBindings.transit_realtime.FeedMessage.toObject(message, {\n enums: String,\n longs: String,\n bytes: String,\n defaults: true,\n arrays: true,\n objects: true,\n oneofs: true,\n });\n}\n\nfunction removeExpiredRealtimeData(config: Config) {\n const db = openDb(config);\n\n log(config)(`Removing expired GTFS-Realtime data`);\n db.prepare(\n `DELETE FROM vehicle_positions WHERE expiration_timestamp <= strftime('%s','now')`,\n ).run();\n db.prepare(\n `DELETE FROM trip_updates WHERE expiration_timestamp <= strftime('%s','now')`,\n ).run();\n db.prepare(\n `DELETE FROM stop_time_updates WHERE expiration_timestamp <= strftime('%s','now')`,\n ).run();\n db.prepare(\n `DELETE FROM service_alerts WHERE expiration_timestamp <= strftime('%s','now')`,\n ).run();\n db.prepare(\n `DELETE FROM service_alert_targets WHERE expiration_timestamp <= strftime('%s','now')`,\n ).run();\n log(config)(`Removed expired GTFS-Realtime data\\r`, true);\n}\n\nfunction prepareRealtimeFieldValue(\n entity: any,\n column: ModelColumn,\n task: GtfsRealtimeTask,\n) {\n if (column.name === 'created_timestamp') {\n return task.currentTimestamp;\n }\n\n if (column.name === 'expiration_timestamp') {\n return task.currentTimestamp + task.gtfsRealtimeExpirationSeconds;\n }\n\n const value = getNestedProperty(entity, column.default, column.source);\n\n if (column.type === 'json') {\n return sqlString.escape(JSON.stringify(value));\n }\n\n return sqlString.escape(value);\n}\n\nasync function processRealtimeAlerts(\n db: any,\n gtfsRealtimeData: any,\n task: GtfsRealtimeTask,\n) {\n task.log(`Download successful`);\n\n let totalLineCount = 0;\n\n for (const entity of gtfsRealtimeData.entity) {\n // Do base processing\n const fieldValues = (models.serviceAlerts.schema as ModelColumn[]).map(\n (column) => prepareRealtimeFieldValue(entity, column, task),\n );\n\n try {\n db.prepare(\n `REPLACE INTO ${models.serviceAlerts.filenameBase} (${models.serviceAlerts.schema\n .map((column) => column.name)\n .join(', ')}) VALUES (${fieldValues.join(', ')})`,\n ).run();\n } catch (error: any) {\n task.logWarning(`Import error: ${error.message}`);\n }\n\n if (\n !entity.alert.informedEntity ||\n entity.alert.informedEntity.length === 0\n ) {\n task.logWarning(\n `Import error: No informed entities found for alert id=${entity.id}`,\n );\n } else {\n const alertTargetArray = [];\n for (const informedEntity of entity.alert.informedEntity) {\n informedEntity.parent = entity;\n const subValues = (\n models.serviceAlertTargets.schema as ModelColumn[]\n ).map((column) =>\n prepareRealtimeFieldValue(informedEntity, column, task),\n );\n alertTargetArray.push(`(${subValues.join(', ')})`);\n totalLineCount++;\n }\n\n try {\n db.prepare(\n `REPLACE INTO ${models.serviceAlertTargets.filenameBase} (${models.serviceAlertTargets.schema\n .map((column) => column.name)\n .join(', ')}) VALUES ${alertTargetArray.join(', ')}`,\n ).run();\n } catch (error: any) {\n task.logWarning(`Import error: ${error.message}`);\n }\n }\n\n task.log(`Importing - ${totalLineCount++} entries imported\\r`, true);\n }\n}\n\nasync function processRealtimeTripUpdates(\n db: any,\n gtfsRealtimeData: any,\n task: GtfsRealtimeTask,\n) {\n task.log(`Download successful`);\n\n let totalLineCount = 0;\n\n for (const entity of gtfsRealtimeData.entity) {\n // Do base processing\n const fieldValues = (models.tripUpdates.schema as ModelColumn[]).map(\n (column) => prepareRealtimeFieldValue(entity, column, task),\n );\n\n try {\n db.prepare(\n `REPLACE INTO ${models.tripUpdates.filenameBase} (${models.tripUpdates.schema\n .map((column) => column.name)\n .join(', ')}) VALUES (${fieldValues.join(', ')})`,\n ).run();\n } catch (error: any) {\n task.logWarning(`Import error: ${error.message}`);\n }\n\n const stopTimeUpdateArray = [];\n for (const stopTimeUpdate of entity.tripUpdate.stopTimeUpdate) {\n stopTimeUpdate.parent = entity;\n const subValues = (models.stopTimeUpdates.schema as ModelColumn[]).map(\n (column) => prepareRealtimeFieldValue(stopTimeUpdate, column, task),\n );\n stopTimeUpdateArray.push(`(${subValues.join(', ')})`);\n totalLineCount++;\n }\n\n try {\n db.prepare(\n `REPLACE INTO ${models.stopTimeUpdates.filenameBase} (${models.stopTimeUpdates.schema\n .map((column) => column.name)\n .join(', ')}) VALUES ${stopTimeUpdateArray.join(', ')}`,\n ).run();\n } catch (error: any) {\n task.logWarning(`Import error: ${error.message}`);\n }\n\n task.log(`Importing - ${totalLineCount++} entries imported\\r`, true);\n }\n}\n\nasync function processRealtimeVehiclePositions(\n db: any,\n gtfsRealtimeData: any,\n task: GtfsRealtimeTask,\n) {\n task.log(`Download successful`);\n\n let totalLineCount = 0;\n\n for (const entity of gtfsRealtimeData.entity) {\n // Do base processing\n const fieldValues = (models.vehiclePositions.schema as ModelColumn[]).map(\n (column) => prepareRealtimeFieldValue(entity, column, task),\n );\n\n try {\n db.prepare(\n `REPLACE INTO ${models.vehiclePositions.filenameBase} (${models.vehiclePositions.schema\n .map((column) => column.name)\n .join(', ')}) VALUES (${fieldValues.join(', ')})`,\n ).run();\n } catch (error: any) {\n task.logWarning(`Import error: ${error.message}`);\n }\n\n task.log(`Importing - ${totalLineCount++} entries imported\\r`, true);\n }\n}\n\nexport async function updateGtfsRealtimeData(task: GtfsRealtimeTask) {\n if (\n task.realtimeAlerts === undefined &&\n task.realtimeTripUpdates === undefined &&\n task.realtimeVehiclePositions === undefined\n ) {\n return;\n }\n\n const db = openDb({ sqlitePath: task.sqlitePath });\n\n if (task.realtimeAlerts?.url) {\n try {\n const alertsData = await fetchGtfsRealtimeData(task.realtimeAlerts, task);\n if (alertsData?.entity) {\n await processRealtimeAlerts(db, alertsData, task);\n }\n } catch (error: any) {\n if (task.ignoreErrors) {\n task.logError(error.message);\n } else {\n throw error;\n }\n }\n }\n\n if (task.realtimeTripUpdates?.url) {\n try {\n const tripUpdatesData = await fetchGtfsRealtimeData(\n task.realtimeTripUpdates,\n task,\n );\n if (tripUpdatesData?.entity) {\n await processRealtimeTripUpdates(db, tripUpdatesData, task);\n }\n } catch (error: any) {\n if (task.ignoreErrors) {\n task.logError(error.message);\n } else {\n throw error;\n }\n }\n }\n\n if (task.realtimeVehiclePositions?.url) {\n try {\n const vehiclePositionsData = await fetchGtfsRealtimeData(\n task.realtimeVehiclePositions,\n task,\n );\n if (vehiclePositionsData?.entity) {\n await processRealtimeVehiclePositions(db, vehiclePositionsData, task);\n }\n } catch (error: any) {\n if (task.ignoreErrors) {\n task.logError(error.message);\n } else {\n throw error;\n }\n }\n }\n\n task.log(`GTFS-Realtime data import complete`);\n}\n\nexport async function updateGtfsRealtime(initialConfig: Config) {\n const config = setDefaultConfig(initialConfig);\n validateConfigForImport(config);\n\n try {\n openDb(config);\n\n const agencyCount = config.agencies.length;\n log(config)(\n `Starting GTFS-Realtime refresh for ${pluralize(\n 'agencies',\n agencyCount,\n true,\n )} using SQLite database at ${config.sqlitePath}`,\n );\n\n removeExpiredRealtimeData(config);\n\n await mapSeries(config.agencies, async (agency: ConfigAgency) => {\n try {\n const task = {\n realtimeAlerts: agency.realtimeAlerts,\n realtimeTripUpdates: agency.realtimeTripUpdates,\n realtimeVehiclePositions: agency.realtimeVehiclePositions,\n downloadTimeout: config.downloadTimeout,\n gtfsRealtimeExpirationSeconds: config.gtfsRealtimeExpirationSeconds,\n ignoreErrors: config.ignoreErrors,\n sqlitePath: config.sqlitePath,\n currentTimestamp: Math.floor(Date.now() / 1000),\n log: log(config),\n logWarning: logWarning(config),\n logError: logError(config),\n };\n\n await updateGtfsRealtimeData(task);\n } catch (error: any) {\n if (config.ignoreErrors) {\n logError(config)(error.message);\n } else {\n throw error;\n }\n }\n });\n\n log(config)(\n `Completed GTFS-Realtime refresh for ${pluralize(\n 'agencies',\n agencyCount,\n true,\n )}\\n`,\n );\n } catch (error: any) {\n if (error?.code === 'SQLITE_CANTOPEN') {\n logError(config)(\n `Unable to open sqlite database \"${config.sqlitePath}\" defined as \\`sqlitePath\\` config.json. Ensure the parent directory exists or remove \\`sqlitePath\\` from config.json.`,\n );\n }\n throw error;\n }\n}\n","import sqlString from 'sqlstring-sqlite';\nimport Long from 'long';\nimport {\n Config,\n JoinOptions,\n SqlWhere,\n SqlValue,\n SqlOrderBy,\n} from '../types/global_interfaces.ts';\n\n/**\n * Validates the configuration object for GTFS import\n * @param config The configuration object to validate\n * @throws Error if agencies are missing or if agency lacks both url and path\n * @returns The validated config object\n */\nexport function validateConfigForImport(config: Config) {\n if (!config.agencies || config.agencies.length === 0) {\n throw new Error('No `agencies` specified in config');\n }\n\n for (const [index, agency] of config.agencies.entries()) {\n if (!agency.path && !agency.url) {\n throw new Error(\n `No Agency \\`url\\` or \\`path\\` specified in config for agency index ${index}.`,\n );\n }\n }\n\n return config;\n}\n\n/**\n * Initializes configuration with default values\n * @param initialConfig The user-provided configuration\n * @returns Merged configuration with defaults\n */\nexport function setDefaultConfig(initialConfig: Config) {\n const defaults = {\n sqlitePath: ':memory:',\n ignoreDuplicates: false,\n ignoreErrors: false,\n gtfsRealtimeExpirationSeconds: 0,\n verbose: true,\n };\n\n return {\n ...defaults,\n ...initialConfig,\n };\n}\n\n/**\n * Converts a Long timestamp to ISO date string\n * @param longDate Object containing high, low, and unsigned values\n * @returns ISO formatted date string\n */\nexport function convertLongTimeToDate(longDate: {\n high: number;\n low: number;\n unsigned: boolean;\n}) {\n const { high, low, unsigned } = longDate;\n return new Date(\n Long.fromBits(low, high, unsigned).toNumber() * 1000,\n ).toISOString();\n}\n\n/**\n * Converts time string in HH:mm:ss format to seconds since midnight\n * @param time Time string in HH:mm:ss format\n * @returns Number of seconds since midnight, or null if invalid format\n */\nexport function calculateSecondsFromMidnight(time: string): number | null {\n if (!time || typeof time !== 'string') {\n return null;\n }\n\n const [hours, minutes, seconds] = time.split(':').map(Number);\n\n if ([hours, minutes, seconds].some(isNaN) || minutes >= 60 || seconds >= 60) {\n return null;\n }\n\n return hours * 3600 + minutes * 60 + seconds;\n}\n\n/**\n * Ensures time components have leading zeros (e.g., \"9:5:1\" -> \"09:05:01\")\n * @param time Time string in HH:mm:ss format\n * @returns Formatted time string with leading zeros, or null if invalid format\n */\nexport function padLeadingZeros(time: string) {\n const split = time.split(':').map((d) => String(Number(d)).padStart(2, '0'));\n if (split.length !== 3) {\n return null;\n }\n\n return split.join(':');\n}\n\n/**\n * Formats SQL SELECT clause from array of field names or field mapping object\n * @param fields Array of field names or object mapping source to alias\n * @returns Formatted SELECT clause\n */\nexport function formatSelectClause(fields: string[]) {\n if (Array.isArray(fields)) {\n const selectItem =\n fields.length > 0\n ? fields.map((fieldName) => sqlString.escapeId(fieldName)).join(', ')\n : '*';\n return `SELECT ${selectItem}`;\n }\n\n const selectItem = Object.entries(fields)\n .map(\n (key) => `${sqlString.escapeId(key[0])} AS ${sqlString.escapeId(key[1])}`,\n )\n .join(', ');\n return `SELECT ${selectItem}`;\n}\n\n/**\n * Formats SQL JOIN clause from array of join configurations\n * @param joinObject Array of join options\n * @returns Formatted JOIN clause\n */\nexport function formatJoinClause(joinObject: JoinOptions[]) {\n return joinObject\n .map(\n (data) =>\n `${data.type ? data.type + ' JOIN' : 'INNER JOIN'} ${sqlString.escapeId(\n data.table,\n )} ON ${data.on}`,\n )\n .join(' ');\n}\n\n/**\n * Converts degrees to radians\n * @param angle Angle in degrees\n * @returns Angle in radians\n */\nfunction degree2radian(angle: number) {\n return (angle * Math.PI) / 180;\n}\n\n/**\n * Converts radians to degrees\n * @param angle Angle in radians\n * @returns Angle in degrees\n */\nfunction radian2degree(angle: number) {\n return (angle / Math.PI) * 180;\n}\n\nconst EARTH_RADIUS_METERS = 6371000;\n\n/**\n * Creates SQL WHERE clause for geographic bounding box search\n * @param latitudeDegree Center latitude in degrees\n * @param longitudeDegree Center longitude in degrees\n * @param boundingBoxSideMeters Size of bounding box in meters\n * @returns SQL WHERE clause for bounding box search\n */\nexport function formatWhereClauseBoundingBox(\n latitudeDegree: number | string,\n longitudeDegree: number | string,\n boundingBoxSideMeters: number,\n): string {\n const lat = Number(latitudeDegree);\n const lon = Number(longitudeDegree);\n\n if (\n isNaN(lat) ||\n isNaN(lon) ||\n lat < -90 ||\n lat > 90 ||\n lon < -180 ||\n lon > 180\n ) {\n throw new Error('Invalid latitude or longitude values');\n }\n\n const latitudeRadian = degree2radian(lat);\n const radiusFromLatitude = Math.cos(latitudeRadian) * EARTH_RADIUS_METERS;\n\n const halfSide = boundingBoxSideMeters / 2;\n const deltaLatitude = radian2degree(halfSide / EARTH_RADIUS_METERS);\n const deltaLongitude = radian2degree(halfSide / radiusFromLatitude);\n\n return [\n `stop_lat BETWEEN ${lat - deltaLatitude} AND ${lat + deltaLatitude}`,\n `stop_lon BETWEEN ${lon - deltaLongitude} AND ${lon + deltaLongitude}`,\n ].join(' AND ');\n}\n\n/**\n * Formats SQL WHERE clause for a single key-value pair\n * @param key Column name\n * @param value Single value, array of values, or null\n * @returns Formatted WHERE clause condition\n */\nexport function formatWhereClause(\n key: string,\n value: null | SqlValue | SqlValue[],\n) {\n if (Array.isArray(value)) {\n let whereClause = `${sqlString.escapeId(key)} IN (${value\n .filter((v) => v !== null)\n .map((v) => sqlString.escape(v))\n .join(', ')})`;\n\n if (value.includes(null)) {\n whereClause = `(${whereClause} OR ${sqlString.escapeId(key)} IS NULL)`;\n }\n\n return whereClause;\n }\n\n if (value === null) {\n return `${sqlString.escapeId(key)} IS NULL`;\n }\n\n return `${sqlString.escapeId(key)} = ${sqlString.escape(value)}`;\n}\n\n/**\n * Formats complete SQL WHERE clause from query object\n * @param query Object containing column-value pairs\n * @returns Formatted WHERE clause or empty string if no conditions\n */\nexport function formatWhereClauses(query: SqlWhere) {\n if (Object.keys(query).length === 0) {\n return '';\n }\n\n const whereClauses = Object.entries(query).map(([key, value]) =>\n formatWhereClause(key, value),\n );\n return `WHERE ${whereClauses.join(' AND ')}`;\n}\n\n/**\n * Formats SQL ORDER BY clause from array of sorting criteria\n * @param orderBy Array of [column, direction] tuples\n * @returns Formatted ORDER BY clause\n */\nexport function formatOrderByClause(orderBy: SqlOrderBy) {\n let orderByClause = '';\n\n if (orderBy.length > 0) {\n orderByClause += 'ORDER BY ';\n\n orderByClause += orderBy\n .map(([key, value]) => {\n const direction = value === 'DESC' ? 'DESC' : 'ASC';\n return `${sqlString.escapeId(key)} ${direction}`;\n })\n .join(', ');\n }\n\n return orderByClause;\n}\n\n/**\n * Gets day of week name from YYYYMMDD date number\n * @param date Date in YYYYMMDD format\n * @returns Lowercase day name (sunday-saturday)\n */\nexport function getDayOfWeekFromDate(date: number): string {\n const DAYS_OF_WEEK = [\n 'sunday',\n 'monday',\n 'tuesday',\n 'wednesday',\n 'thursday',\n 'friday',\n 'saturday',\n ] as const;\n\n if (!Number.isInteger(date) || date.toString().length !== 8) {\n throw new Error('Date must be in YYYYMMDD format');\n }\n\n const year = Math.floor(date / 10000);\n const month = Math.floor((date % 10000) / 100);\n const day = date % 100;\n\n const dateObj = new Date(year, month - 1, day);\n\n if (dateObj.toString() === 'Invalid Date') {\n throw new Error('Invalid date');\n }\n\n return DAYS_OF_WEEK[dateObj.getDay()];\n}\n\n/**\n * Formats a numeric value according to the decimal precision rules of the specified currency,\n * without any currency symbols or separators.\n * @param value The numeric value to format (e.g., 10.5)\n * @param currency The ISO 4217 currency code (e.g., 'USD', 'JPY', 'EUR')\n * @returns The formatted string with appropriate decimal places\n * Examples:\n * - formatCurrency(10.5, 'USD') => '10.50' // USD uses 2 decimal places\n * - formatCurrency(10.5, 'JPY') => '10' // JPY uses 0 decimal places\n * - formatCurrency(10.523, 'BHD') => '10.523' // BHD uses 3 decimal places\n */\nexport function formatCurrency(value: number, currency: string) {\n const parts = new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency,\n }).formatToParts(value);\n\n const integerPart =\n parts.find((part) => part.type === 'integer')?.value ?? '0';\n const fractionPart =\n parts.find((part) => part.type === 'fraction')?.value ?? '';\n\n return `${integerPart}${fractionPart !== '' ? `.${fractionPart}` : ''}`;\n}\n\n/**\n * Gets the timestamp column name for a given column name\n * @param columnName The column name\n * @returns The timestamp column name\n */\nexport function getTimestampColumnName(columnName: string) {\n return columnName.endsWith('time')\n ? `${columnName}stamp`\n : `${columnName}_timestamp`;\n}\n","import path from 'node:path';\nimport { writeFile } from 'node:fs/promises';\n\nimport { without, compact } from 'lodash-es';\nimport pluralize from 'pluralize';\nimport { stringify } from 'csv-stringify';\nimport sqlString from 'sqlstring-sqlite';\nimport Database from 'better-sqlite3';\nimport mapSeries from 'promise-map-series';\nimport untildify from 'untildify';\n\nimport * as models from '../models/models.ts';\nimport { openDb } from './db.ts';\nimport { prepDirectory, generateFolderName } from './file-utils.ts';\nimport { log, logWarning } from './log-utils.ts';\nimport { formatCurrency, setDefaultConfig } from './utils.ts';\n\nimport { Config, Model } from '../types/global_interfaces.ts';\n\nconst getAgencies = (db: Database.Database, config: Config) => {\n try {\n return db.prepare('SELECT agency_name FROM agency;').all() as {\n agency_name: string;\n }[];\n } catch (error) {\n if (config.sqlitePath === ':memory:') {\n throw new Error(\n 'No agencies found in SQLite. You are using an in-memory database - if running this from command line be sure to specify a value for `sqlitePath` in config.json other than \":memory:\".',\n );\n }\n\n throw new Error(\n 'No agencies found in SQLite. Be sure to first import data into SQLite using `gtfs-import` or `importGtfs(config);`',\n );\n }\n};\n\nexport const exportGtfs = async (initialConfig: Config) => {\n const config = setDefaultConfig(initialConfig);\n const db = openDb(config);\n\n // Get agency name for export folder from first line of agency.txt\n\n const agencies = getAgencies(db, config);\n const agencyCount = agencies.length;\n if (agencyCount === 0) {\n throw new Error(\n 'No agencies found in SQLite. Be sure to first import data into SQLite using `gtfs-import` or `importGtfs(config);`',\n );\n } else if (agencyCount > 1) {\n logWarning(config)(\n 'More than one agency is defined in config.json. Export will merge all into one GTFS file.',\n );\n }\n\n log(config)(\n `Starting GTFS export for ${pluralize(\n 'agency',\n agencyCount,\n true,\n )} using SQLite database at ${config.sqlitePath}`,\n );\n\n const folderName = generateFolderName(agencies[0].agency_name);\n const defaultExportPath = path.join(process.cwd(), 'gtfs-export', folderName);\n const exportPath = untildify(config.exportPath || defaultExportPath);\n\n await prepDirectory(exportPath);\n\n // Loop through each GTFS file\n const modelsToExport = (Object.values(models) as Model[]).filter(\n (model) => model.extension !== 'gtfs-realtime',\n );\n const exportedFiles = await mapSeries(\n modelsToExport,\n async (model: Model) => {\n const filePath = path.join(\n exportPath,\n `${model.filenameBase}.${model.filenameExtension}`,\n );\n const tableName = sqlString.escapeId(model.filenameBase);\n const lines = db.prepare(`SELECT * FROM ${tableName};`).all() as Array<\n Record<string, any>\n >;\n\n if (!lines || lines.length === 0) {\n if (!model.nonstandard) {\n log(config)(\n `Skipping (no data) - ${model.filenameBase}.${model.filenameExtension}\\r`,\n );\n }\n\n return;\n }\n\n if (model.filenameExtension === 'txt') {\n const excludeColumns = [];\n\n // If no routes have values for agency_id, add it to the excludeColumns list\n if (model.filenameBase === 'routes') {\n const routesWithAgencyId = db\n .prepare(\n 'SELECT agency_id FROM routes WHERE agency_id IS NOT NULL;',\n )\n .all();\n if (!routesWithAgencyId || routesWithAgencyId.length === 0) {\n excludeColumns.push('agency_id');\n }\n } else if (model.filenameBase === 'fare_attributes') {\n for (const line of lines) {\n line.price = formatCurrency(line.price, line.currency_type);\n }\n } else if (model.filenameBase === 'fare_products') {\n for (const line of lines) {\n line.amount = formatCurrency(line.amount, line.currency);\n }\n }\n\n const columns = without(\n model.schema.map((column) => column.name),\n ...excludeColumns,\n );\n const fileText = await stringify(lines, { columns, header: true });\n await writeFile(filePath, fileText);\n } else if (model.filenameExtension === 'geojson') {\n const fileText = lines?.[0].geojson ?? '';\n await writeFile(filePath, fileText);\n } else {\n throw new Error(\n `Unexpected filename extension: ${model.filenameExtension}`,\n );\n }\n\n log(config)(\n `Exporting - ${model.filenameBase}.${model.filenameExtension}\\r`,\n );\n\n return `${model.filenameBase}.${model.filenameExtension}`;\n },\n );\n\n if (compact(exportedFiles).length === 0) {\n log(config)(\n 'No GTFS data exported. Be sure to first import data into SQLite.',\n );\n return;\n }\n\n log(config)(`Completed GTFS export to ${exportPath}`);\n\n log(config)(\n `Completed GTFS export for ${pluralize('agency', agencyCount, true)}\\n`,\n );\n};\n","import sqlString from 'sqlstring-sqlite';\nimport Database from 'better-sqlite3';\n\nimport { openDb } from './db.ts';\n\nimport {\n formatOrderByClause,\n formatSelectClause,\n formatWhereClauses,\n formatJoinClause,\n} from './utils.ts';\n\nimport type {\n JoinOptions,\n QueryOptions,\n SqlOrderBy,\n SqlWhere,\n} from '../types/global_interfaces.ts';\n\n/*\n * Returns an array of all agencies that match the query parameters.\n */\nexport function advancedQuery(\n table: string,\n advancedQueryOptions: {\n db?: Database.Database;\n query?: SqlWhere;\n fields?: string[];\n orderBy?: SqlOrderBy;\n join?: JoinOptions[];\n options?: QueryOptions;\n },\n) {\n const defaultOptions: {\n query: SqlWhere;\n fields: string[];\n orderBy: SqlOrderBy;\n join: JoinOptions[];\n options: QueryOptions;\n } = {\n query: {},\n fields: [],\n orderBy: [],\n join: [],\n options: {},\n };\n const queryOptions = { ...defaultOptions, ...advancedQueryOptions };\n\n const db = queryOptions.options.db ?? openDb();\n const tableName = sqlString.escapeId(table);\n const selectClause = formatSelectClause(queryOptions.fields);\n const whereClause = formatWhereClauses(queryOptions.query);\n const joinClause = formatJoinClause(queryOptions.join);\n const orderByClause = formatOrderByClause(queryOptions.orderBy);\n return db\n .prepare(\n `${selectClause} FROM ${tableName} ${joinClause} ${whereClause} ${orderByClause};`,\n )\n .all() as Array<Record<string, any>>;\n}\n","import { omit, pick } from 'lodash-es';\n\nimport type {\n QueryOptions,\n Route,\n SqlOrderBy,\n QueryResult,\n SqlWhere,\n} from '../../types/global_interfaces.ts';\nimport { openDb } from '../db.ts';\nimport {\n formatOrderByClause,\n formatSelectClause,\n formatWhereClause,\n formatWhereClauses,\n} from '../utils.ts';\n\nfunction buildStoptimeSubquery(query: { [key: string]: string }) {\n const whereClause = formatWhereClauses(query);\n return `SELECT DISTINCT trip_id FROM stop_times ${whereClause}`;\n}\n\nfunction buildTripSubquery(query: { service_id?: string; stop_id?: string }) {\n let whereClause = '';\n const tripQuery = omit(query, ['stop_id']);\n const stoptimeQuery = pick(query, ['stop_id']);\n\n const whereClauses = Object.entries(tripQuery).map(([key, value]) =>\n formatWhereClause(key, value),\n );\n\n if (Object.values(stoptimeQuery).length > 0) {\n whereClauses.push(`trip_id IN (${buildStoptimeSubquery(stoptimeQuery)})`);\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n return `SELECT DISTINCT route_id FROM trips ${whereClause}`;\n}\n\n/*\n * Returns an array of routes that match the query parameters. A `stop_id`\n * query parameter may be passed to find all routes that contain that stop.\n * A `service_id` query parameter may be passed to limit routes to specific\n * calendars.\n */\nexport function getRoutes<Fields extends keyof Route>(\n query: SqlWhere = {},\n fields: Fields[] = [],\n orderBy: SqlOrderBy = [],\n options: QueryOptions = {},\n) {\n const db = options.db ?? openDb();\n const tableName = 'routes';\n const selectClause = formatSelectClause(fields);\n let whereClause = '';\n const orderByClause = formatOrderByClause(orderBy);\n\n const routeQuery = omit(query, ['stop_id', 'service_id']);\n const tripQuery: { stop_id?: any; service_id?: any } = pick(query, [\n 'stop_id',\n 'service_id',\n ]);\n\n const whereClauses = Object.entries(routeQuery).map(([key, value]) =>\n formatWhereClause(key, value),\n );\n\n if (Object.values(tripQuery).length > 0) {\n whereClauses.push(`route_id IN (${buildTripSubquery(tripQuery)})`);\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n return db\n .prepare(\n `${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`,\n )\n .all() as QueryResult<Route, Fields>[];\n}\n","import { compact, omit, pick } from 'lodash-es';\nimport { FeatureCollection } from 'geojson';\nimport { featureCollection } from '@turf/helpers';\n\nimport type {\n QueryOptions,\n Shape,\n SqlOrderBy,\n QueryResult,\n SqlWhere,\n} from '../../types/global_interfaces.ts';\nimport { openDb } from '../db.ts';\nimport {\n formatOrderByClause,\n formatSelectClause,\n formatWhereClause,\n formatWhereClauses,\n} from '../utils.ts';\nimport { shapesToGeoJSONFeature } from '../geojson-utils.ts';\nimport { getAgencies } from './agencies.ts';\nimport { getRoutes } from './routes.ts';\nimport { getRouteAttributes } from '../gtfs-plus/route-attributes.ts';\n\nfunction buildTripSubquery(query: { [key: string]: string }) {\n const whereClause = formatWhereClauses(query);\n return `SELECT DISTINCT shape_id FROM trips ${whereClause}`;\n}\n\n/*\n * Returns array of shapes that match the query parameters. A `route_id` query\n * parameter may be passed to find all shapes for a route. A `trip_id` query\n * parameter may be passed to find all shapes for a trip. A `direction_id`\n * query parameter may be passed to find all shapes for a direction.\n */\nexport function getShapes<Fields extends keyof Shape>(\n query: SqlWhere = {},\n fields: Fields[] = [],\n orderBy: SqlOrderBy = [],\n options: QueryOptions = {},\n) {\n const db = options.db ?? openDb();\n const tableName = 'shapes';\n const selectClause = formatSelectClause(fields);\n let whereClause = '';\n const orderByClause = formatOrderByClause(orderBy);\n\n const shapeQuery = omit(query, [\n 'route_id',\n 'trip_id',\n 'service_id',\n 'direction_id',\n ]);\n const tripQuery: {\n route_id?: any;\n trip_id?: any;\n service_id?: any;\n direction_id?: any;\n } = pick(query, ['route_id', 'trip_id', 'service_id', 'direction_id']);\n\n const whereClauses = Object.entries(shapeQuery).map(([key, value]) =>\n formatWhereClause(key, value),\n );\n\n if (Object.values(tripQuery).length > 0) {\n whereClauses.push(`shape_id IN (${buildTripSubquery(tripQuery)})`);\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n return db\n .prepare(\n `${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`,\n )\n .all() as QueryResult<Shape, Fields>[];\n}\n\n/*\n * Returns geoJSON of the shapes that match the query parameters. A `route_id`\n * query parameter may be passed to find all shapes for a route. A `trip_id`\n * query parameter may be passed to find all shapes for a trip. A\n * `direction_id` query parameter may be passed to find all shapes for a direction.\n */\nexport function getShapesAsGeoJSON(\n query: SqlWhere = {},\n options: QueryOptions = {},\n): FeatureCollection {\n const agencies = getAgencies({}, [], [], options);\n const routeQuery = pick(query, ['route_id']);\n const routes = getRoutes(routeQuery, [], [], options);\n const features = compact(\n routes.map((route) => {\n const shapeQuery = {\n route_id: route.route_id,\n ...omit(query, 'route_id'),\n };\n const shapes = getShapes(\n shapeQuery,\n ['shape_id', 'shape_pt_sequence', 'shape_pt_lon', 'shape_pt_lat'],\n [],\n options,\n );\n\n if (shapes.length === 0) {\n return;\n }\n\n const routeAttributes = getRouteAttributes(\n { route_id: route.route_id },\n [],\n [],\n options,\n );\n\n const agency = agencies.find(\n (agency) => agency.agency_id === route.agency_id,\n );\n\n const geojsonProperties = {\n agency_name: agency ? agency.agency_name : undefined,\n shape_id: query.shape_id,\n ...route,\n ...(routeAttributes?.[0] || []),\n };\n return shapesToGeoJSONFeature(shapes, geojsonProperties);\n }),\n );\n\n return featureCollection(features);\n}\n","import { omit, orderBy, pick } from 'lodash-es';\nimport { FeatureCollection } from 'geojson';\n\nimport type {\n QueryOptions,\n SqlOrderBy,\n QueryResult,\n SqlWhere,\n Stop,\n} from '../../types/global_interfaces.ts';\nimport { openDb } from '../db.ts';\nimport {\n formatOrderByClause,\n formatSelectClause,\n formatWhereClause,\n formatWhereClauseBoundingBox,\n formatWhereClauses,\n} from '../utils.ts';\nimport { stopsToGeoJSONFeatureCollection } from '../geojson-utils.ts';\nimport { getAgencies } from './agencies.ts';\nimport { getStopAttributes } from '../gtfs-plus/stop-attributes.ts';\n\nfunction buildTripSubquery(query: { [key: string]: string }) {\n const whereClause = formatWhereClauses(query);\n return `SELECT trip_id FROM trips ${whereClause}`;\n}\n\nfunction buildStoptimeSubquery(query: { [key: string]: string }) {\n return `SELECT DISTINCT stop_id FROM stop_times WHERE trip_id IN (${buildTripSubquery(\n query,\n )})`;\n}\n\n/*\n * Returns an array of stops that match the query parameters. A `route_id`\n * query parameter may be passed to find all shapes for a route. A `trip_id`\n * query parameter may be passed to find all shapes for a trip. A\n * `direction_id` query parameter may be passed to find all shapes for a\n * direction.\n */\nexport function getStops<Fields extends keyof Stop>(\n query: SqlWhere = {},\n fields: Fields[] = [],\n orderBy: SqlOrderBy = [],\n options: QueryOptions = {},\n) {\n const db = options.db ?? openDb();\n const tableName = 'stops';\n const selectClause = formatSelectClause(fields);\n let whereClause = '';\n let orderByClause = formatOrderByClause(orderBy);\n\n const stopQueryOmitKeys = [\n 'route_id',\n 'trip_id',\n 'service_id',\n 'direction_id',\n 'shape_id',\n ];\n\n // If bounding_box_side_m is defined, search for stops inside a bounding box so omit `stop_lat` and `stop_lon`.\n if (options.bounding_box_side_m !== undefined) {\n stopQueryOmitKeys.push('stop_lat', 'stop_lon');\n }\n\n let stopQuery = omit(query, stopQueryOmitKeys);\n\n const tripQuery: {\n route_id?: any;\n trip_id?: any;\n service_id?: any;\n direction_id?: any;\n shape_id?: any;\n } = pick(query, [\n 'route_id',\n 'trip_id',\n 'service_id',\n 'direction_id',\n 'shape_id',\n ]);\n\n const whereClauses = Object.entries(stopQuery).map(\n ([key, value]: [string, any]) => formatWhereClause(key, value),\n );\n\n if (\n options.bounding_box_side_m !== undefined &&\n query.stop_lat !== undefined &&\n query.stop_lon !== undefined\n ) {\n whereClauses.push(\n formatWhereClauseBoundingBox(\n query.stop_lat as number | string,\n query.stop_lon as number | string,\n options.bounding_box_side_m,\n ),\n );\n\n // Add distance-based sorting if bounding_box_side_m is set and no other orderBy is set\n if (orderBy.length === 0) {\n orderByClause = `ORDER BY (((stop_lat - ${query.stop_lat}) * (stop_lat - ${query.stop_lat})) + ((stop_lon - ${query.stop_lon}) * (stop_lon - ${query.stop_lon}))) ASC`;\n }\n }\n\n if (Object.values(tripQuery).length > 0) {\n whereClauses.push(`stop_id IN (${buildStoptimeSubquery(tripQuery)})`);\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n return db\n .prepare(\n `${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`,\n )\n .all() as QueryResult<Stop, Fields>[];\n}\n\n/*\n * Returns geoJSON with stops. A `route_id` query parameter may be passed to\n * find all shapes for a route. A `trip_id` query parameter may be passed to\n * find all shapes for a trip. A `direction_id` query parameter may be passed\n * to find all shapes for a direction.\n */\nexport function getStopsAsGeoJSON(\n query: SqlWhere = {},\n options: QueryOptions = {},\n): FeatureCollection {\n const db = options.db ?? openDb();\n const stops = getStops(query, [], [], options);\n\n // Get all agencies for reference\n const agencies = getAgencies({}, [], [], options);\n\n const preparedStops = stops.map((stop) => {\n const routeSubquery =\n 'SELECT DISTINCT route_id FROM trips WHERE trip_id IN (SELECT DISTINCT trip_id FROM stop_times WHERE stop_id = ?)';\n const routes = db\n .prepare(`SELECT * FROM routes WHERE route_id IN (${routeSubquery})`)\n .all(stop.stop_id);\n\n const stopAttributes = getStopAttributes({ stop_id: stop.stop_id });\n\n return {\n ...stop,\n ...(stopAttributes?.[0] || []),\n routes: orderBy(routes, (route: { route_short_name?: string }) =>\n route?.route_short_name\n ? Number.parseInt(route.route_short_name, 10)\n : 0,\n ),\n agency_name: agencies[0].agency_name,\n };\n });\n\n // Exclude stops not part of any route\n const filteredStops = preparedStops.filter((stop) => stop.routes.length > 0);\n\n return stopsToGeoJSONFeatureCollection(filteredStops);\n}\n","import { omit } from 'lodash-es';\nimport sqlString from 'sqlstring-sqlite';\nimport type {\n QueryOptions,\n SqlOrderBy,\n QueryResult,\n SqlWhere,\n StopTime,\n} from '../../types/global_interfaces.ts';\nimport { openDb } from '../db.ts';\nimport {\n calculateSecondsFromMidnight,\n formatOrderByClause,\n formatSelectClause,\n formatWhereClause,\n} from '../utils.ts';\nimport { getServiceIdsByDate } from './calendars.ts';\n\n/*\n * Returns an array of stoptimes that match the query parameters.\n */\nexport function getStoptimes<Fields extends keyof StopTime>(\n query: SqlWhere = {},\n fields: Fields[] = [],\n orderBy: SqlOrderBy = [],\n options: QueryOptions = {},\n) {\n const db = options.db ?? openDb();\n const tableName = 'stop_times';\n const selectClause = formatSelectClause(fields);\n let whereClause = '';\n const orderByClause = formatOrderByClause(orderBy);\n\n const stoptimeQueryOmitKeys = ['date', 'start_time', 'end_time'];\n\n let stoptimeQuery = omit(query, stoptimeQueryOmitKeys);\n\n const whereClauses = Object.entries(stoptimeQuery).map(\n ([key, value]: [string, any]) => formatWhereClause(key, value),\n );\n\n if (query.date) {\n if (typeof query.date !== 'number') {\n throw new Error('`date` must be a number in yyyymmdd format');\n }\n\n const serviceIds = getServiceIdsByDate(query.date);\n\n const tripSubquery = `SELECT DISTINCT trip_id FROM trips WHERE service_id IN (${serviceIds.map((id) => sqlString.escape(id)).join(',')})`;\n\n whereClauses.push(`trip_id IN (${tripSubquery})`);\n }\n\n if (query.start_time) {\n if (typeof query.start_time !== 'string') {\n throw new Error('`start_time` must be a string in HH:mm:ss format');\n }\n\n whereClauses.push(\n `arrival_timestamp >= ${calculateSecondsFromMidnight(query.start_time)}`,\n );\n }\n\n if (query.end_time) {\n if (typeof query.end_time !== 'string') {\n throw new Error('`end_time` must be a string in HH:mm:ss format');\n }\n\n whereClauses.push(\n `departure_timestamp <= ${calculateSecondsFromMidnight(query.end_time)}`,\n );\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n return db\n .prepare(\n `${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`,\n )\n .all() as QueryResult<StopTime, Fields>[];\n}\n"],"mappings":"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","names":["argv","pluralize","untildify","mapSeries","untildify","omit","sqlString","path","compact","pluralize","sqlString","mapSeries","untildify","pluralize","path","untildify","mapSeries","sqlString","compact","sqlString","omit","compact","omit","pick","featureCollection","omit","pick","omit","sqlString"]}
|