KDE Plasma Widget for displaying real time arrivals for MARTA buses.
kde
plasma
marta
transit
2.5 kB
87 lines
1export function parseCsv(text) {
2 const rows = [];
3 let fields = [];
4 let field = "";
5 let isQuoted = false;
6 let rowHasData = false;
7
8 for (let index = 0; index < text.length; index++) {
9 const character = text[index];
10 if (character === '"') {
11 if (isQuoted && text[index + 1] === '"') {
12 field += character;
13 index++;
14 } else {
15 isQuoted = !isQuoted;
16 }
17 rowHasData = true;
18 } else if (character === "," && !isQuoted) {
19 fields.push(field);
20 field = "";
21 rowHasData = true;
22 } else if ((character === "\n" || character === "\r") && !isQuoted) {
23 if (character === "\r" && text[index + 1] === "\n") index++;
24 if (rowHasData || field.length > 0) {
25 fields.push(field);
26 rows.push(fields);
27 }
28 fields = [];
29 field = "";
30 rowHasData = false;
31 } else {
32 field += character;
33 }
34 }
35
36 if (rowHasData || field.length > 0) {
37 fields.push(field);
38 rows.push(fields);
39 }
40
41 return rows;
42}
43
44export function parseCsvRow(line) {
45 return parseCsv(line)[0] || [];
46}
47
48export function createStopNames(stopsCsv) {
49 const rows = parseCsv(stopsCsv.replace(/^\uFEFF/, ""));
50 if (rows.length === 0) throw new Error("stops.txt contains no rows");
51
52 // GTFS guarantees column names, not column order.
53 const header = rows[0].map(column => column.trim());
54 const idColumn = header.indexOf("stop_id");
55 const nameColumn = header.indexOf("stop_name");
56 if (idColumn === -1 || nameColumn === -1) {
57 throw new Error("stops.txt is missing the stop_id or stop_name column");
58 }
59
60 const stopNames = {};
61 for (const row of rows.slice(1)) {
62 const stopId = row[idColumn];
63 const stopName = row[nameColumn];
64 if (stopId && stopName) stopNames[stopId] = stopName;
65 }
66
67 return stopNames;
68}
69
70export function createStopNamesModule(stopNames) {
71 const data = escapeNonAscii(JSON.stringify(stopNames, null, 4));
72 return `.pragma library
73
74// Generated from MARTA static GTFS stops.txt by update-stop-names.mjs.
75const STOP_NAMES = ${data};
76
77function nameFor(stopId) {
78 return STOP_NAMES[String(stopId)] || "";
79}
80`;
81}
82
83function escapeNonAscii(value) {
84 return value.replace(/[\u0080-\uFFFF]/g, character =>
85 "\\u" + character.charCodeAt(0).toString(16).padStart(4, "0")
86 );
87}