-
Notifications
You must be signed in to change notification settings - Fork 0
/
validate-gtfs.js
executable file
·103 lines (87 loc) · 2.92 KB
/
validate-gtfs.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#!/usr/bin/env node
// usage: ./validate-gtfs.js gtfsDir wienerlinien.sql
// => gtfsDir = the directory with the unzipped GTFS data
// => wienerlinien.sql = the create statements for the database
const fs = require("fs");
const path = require("path");
const {readdir} = fs.promises;
const readline = require("readline");
const assert = require("assert");
async function getHeader(path) {
const stream = fs.createReadStream(path, "utf8");
const reader = readline.createInterface({ input: stream });
const line = await new Promise((resolve) => {
reader.on("line", (line) => {
reader.close();
resolve(line);
});
});
stream.close();
// strip the BOM
if (line.charCodeAt(0) === 0xFEFF) {
return line.slice(1);
}
return line;
}
async function getHeaders(dir) {
const fileNames = (await readdir(dir))
.filter(name => name[0] !== "." && name !== "README.md")
.sort();
assert.deepStrictEqual(fileNames, [
"agency.txt",
"calendar.txt",
"calendar_dates.txt",
"routes.txt",
"shapes.txt",
"stop_times.txt",
"stops.txt",
"trips.txt",
]);
const headers = {};
for (const fileName of fileNames) {
const fileHeader = await getHeader(path.join(dir, fileName));
headers[fileName.replace(/\.txt$/, "")] = fileHeader.split(",");
}
return headers;
}
function getTables(sqlFile) {
const tableDDL = fs.readFileSync(sqlFile, "utf8")
.split("\n")
.map(line => line.trim().replace(/^(DROP|\\copy) .*/im, "").replace(/ +/g, " "))
.filter(line => line !== "" && line !== "(" && line !== ")" && line !== ");");
const tables = {};
let currentTable = null;
for (const line of tableDDL) {
const matchCreate = line.match(/^CREATE TABLE (.+)/);
if(matchCreate !== null) {
if (matchCreate.length !== 2) {
throw new Error(`Invalid table DDL '${line}'`);
}
currentTable = matchCreate[1];
tables[currentTable] = [];
} else {
if (currentTable === null) {
throw new Error(`Invalid table DDL '${line}', current table is null!`);
}
const matchColumn = line.match(/^([a-z_]+) .+,?$/);
if (matchColumn === null || matchColumn.length !== 2) {
throw new Error(`Invalid table DDL '${line}'`);
}
tables[currentTable].push(matchColumn[1]);
}
}
return tables;
}
(async () => {
try {
const gtfsFolder = process.argv[2] || "./gtfs";
const sqlFile = process.argv[3] || "./wienerlinien.sql";
const headers = await getHeaders(gtfsFolder);
const tables = getTables(sqlFile);
assert.deepStrictEqual(headers, tables);
console.log("✅");
} catch (e) {
console.error(e);
process.exitCode = 1;
}
})();