@tmlmobilidade/gtfs-validator 20250416.1622.36
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/scripts/postinstall.js +87 -0
- package/dist/src/index.js +26 -0
- package/dist/src/test.js +7 -0
- package/dist/src/utils.js +54 -0
- package/package.json +45 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { chmodSync, copyFileSync, createWriteStream, existsSync, mkdirSync } from 'fs';
|
|
2
|
+
import path, { dirname, join } from 'path';
|
|
3
|
+
import { Readable } from 'stream';
|
|
4
|
+
import { finished } from 'stream/promises';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
// Lookup table for all platforms and binary distribution files
|
|
9
|
+
const BINARY_DISTRIBUTIONS_FILES = {
|
|
10
|
+
'darwin-arm64': 'validator-darwin-arm64',
|
|
11
|
+
'darwin-x64': 'validator-darwin-amd64',
|
|
12
|
+
'linux-arm64': 'validator-linux-arm64',
|
|
13
|
+
'linux-x64': 'validator-linux-amd64',
|
|
14
|
+
'windows-x64': 'validator.exe',
|
|
15
|
+
};
|
|
16
|
+
const DEV_BIN_PATH = join(__dirname, '..', '..', 'bin');
|
|
17
|
+
const REMOTE_BIN_PATH = 'https://github.com/tmlmobilidade/validator/raw/refs/heads/production/bin/';
|
|
18
|
+
const LOCAL_BIN_PATH = join(__dirname, '..', 'bin');
|
|
19
|
+
// function to get the current platform
|
|
20
|
+
function getCurrentPlatform() {
|
|
21
|
+
const platform = process.platform;
|
|
22
|
+
const arch = process.arch;
|
|
23
|
+
return `${platform}-${arch}`;
|
|
24
|
+
}
|
|
25
|
+
function buildDevEnvironment() {
|
|
26
|
+
const platform = getCurrentPlatform();
|
|
27
|
+
const binaryDistributionFile = BINARY_DISTRIBUTIONS_FILES[platform];
|
|
28
|
+
if (!binaryDistributionFile) {
|
|
29
|
+
console.error(`No binary distribution file found for platform: ${platform}`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// check if local bin path exists
|
|
33
|
+
if (!existsSync(LOCAL_BIN_PATH)) {
|
|
34
|
+
mkdirSync(LOCAL_BIN_PATH);
|
|
35
|
+
}
|
|
36
|
+
copyFileSync(join(DEV_BIN_PATH, binaryDistributionFile), join(LOCAL_BIN_PATH, binaryDistributionFile));
|
|
37
|
+
}
|
|
38
|
+
async function downloadRemoteBinaries() {
|
|
39
|
+
const platform = getCurrentPlatform();
|
|
40
|
+
const binaryDistributionFile = BINARY_DISTRIBUTIONS_FILES[platform];
|
|
41
|
+
if (!binaryDistributionFile) {
|
|
42
|
+
console.error(`No binary distribution file found for platform: ${platform}`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Download the file
|
|
46
|
+
const res = await fetch(REMOTE_BIN_PATH + binaryDistributionFile);
|
|
47
|
+
if (!res.ok) {
|
|
48
|
+
throw new Error(`Error downloading remote binary: ${res.statusText}`);
|
|
49
|
+
}
|
|
50
|
+
// Create the local bin path if it doesn't exist
|
|
51
|
+
if (!existsSync(LOCAL_BIN_PATH))
|
|
52
|
+
mkdirSync(LOCAL_BIN_PATH);
|
|
53
|
+
// Download the file
|
|
54
|
+
const arrayBuffer = await res.arrayBuffer();
|
|
55
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
56
|
+
// Create the file stream
|
|
57
|
+
const fileStream = createWriteStream(path.resolve(LOCAL_BIN_PATH, binaryDistributionFile));
|
|
58
|
+
// Write the file to the local bin path
|
|
59
|
+
return await finished(Readable.from(buffer).pipe(fileStream));
|
|
60
|
+
}
|
|
61
|
+
function main() {
|
|
62
|
+
const platform = getCurrentPlatform();
|
|
63
|
+
const binaryDistributionFile = BINARY_DISTRIBUTIONS_FILES[platform];
|
|
64
|
+
if (!binaryDistributionFile) {
|
|
65
|
+
console.error(`No binary distribution file found for platform: ${platform}`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const binaryDistributionFilePath = join(DEV_BIN_PATH, binaryDistributionFile);
|
|
69
|
+
// check if the file exists
|
|
70
|
+
if (existsSync(binaryDistributionFilePath)) {
|
|
71
|
+
try {
|
|
72
|
+
buildDevEnvironment();
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
console.error(`Error building dev environment: ${error}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
console.info(`Local file not found: ${binaryDistributionFilePath}`);
|
|
80
|
+
console.info(`Downloading file from remote server...`);
|
|
81
|
+
// Download the remote binaries
|
|
82
|
+
downloadRemoteBinaries();
|
|
83
|
+
}
|
|
84
|
+
// CHMOD the file executable
|
|
85
|
+
chmodSync(join(LOCAL_BIN_PATH, binaryDistributionFile), 0o755);
|
|
86
|
+
}
|
|
87
|
+
main();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { runGoBinary } from './utils.js';
|
|
2
|
+
const BINARY_DISTRIBUTIONS_FILES = {
|
|
3
|
+
'darwin-arm64': 'validator-darwin-arm64',
|
|
4
|
+
'darwin-x64': 'validator-darwin-amd64',
|
|
5
|
+
'linux-arm64': 'validator-linux-arm64',
|
|
6
|
+
'linux-x64': 'validator-linux-amd64',
|
|
7
|
+
'windows-x64': 'validator.exe',
|
|
8
|
+
};
|
|
9
|
+
function getCurrentPlatform() {
|
|
10
|
+
const platform = process.platform;
|
|
11
|
+
const arch = process.arch;
|
|
12
|
+
return `${platform}-${arch}`;
|
|
13
|
+
}
|
|
14
|
+
export async function GTFSValidator(input) {
|
|
15
|
+
try {
|
|
16
|
+
const result = await runGoBinary(`./bin/${BINARY_DISTRIBUTIONS_FILES[getCurrentPlatform()]}`, [
|
|
17
|
+
'-input',
|
|
18
|
+
input,
|
|
19
|
+
]);
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
console.error('❌ Error:', err.message);
|
|
24
|
+
throw err;
|
|
25
|
+
}
|
|
26
|
+
}
|
package/dist/src/test.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { dirname, join } from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { GTFSValidator } from './index.js';
|
|
4
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
5
|
+
const __dirname = dirname(__filename);
|
|
6
|
+
const result = await GTFSValidator(join(__dirname, '../../data/Bom.zip'));
|
|
7
|
+
console.log(result);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Runs a Go binary and returns its JSON stdout as an object.
|
|
5
|
+
* @param binaryPath Absolute or relative path to the Go binary.
|
|
6
|
+
* @param args Arguments to pass to the binary (optional).
|
|
7
|
+
* @param timeout Timeout in milliseconds (default 1000 * 60 * 5) - 5 minutes.
|
|
8
|
+
* @returns A promise that resolves to a JSON object from the Go binary.
|
|
9
|
+
*/
|
|
10
|
+
export async function runGoBinary(binaryPath, args = [], timeout = 1000 * 60 * 5) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const fullPath = path.resolve(binaryPath);
|
|
13
|
+
const proc = spawn(fullPath, args, {
|
|
14
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
15
|
+
});
|
|
16
|
+
const stdoutChunks = [];
|
|
17
|
+
const stderrChunks = [];
|
|
18
|
+
let timedOut = false;
|
|
19
|
+
const timer = setTimeout(() => {
|
|
20
|
+
timedOut = true;
|
|
21
|
+
proc.kill();
|
|
22
|
+
reject(new Error(`Process timeout after ${timeout}ms`));
|
|
23
|
+
}, timeout);
|
|
24
|
+
proc.stdout.on('data', (chunk) => {
|
|
25
|
+
stdoutChunks.push(chunk);
|
|
26
|
+
});
|
|
27
|
+
proc.stderr.on('data', (chunk) => {
|
|
28
|
+
stderrChunks.push(chunk);
|
|
29
|
+
});
|
|
30
|
+
proc.on('error', (err) => {
|
|
31
|
+
clearTimeout(timer);
|
|
32
|
+
throw new Error(`Failed to start binary: ${err.message}`);
|
|
33
|
+
});
|
|
34
|
+
proc.on('close', (code) => {
|
|
35
|
+
clearTimeout(timer);
|
|
36
|
+
if (timedOut)
|
|
37
|
+
return;
|
|
38
|
+
const stdout = Buffer.concat(stdoutChunks).toString('utf-8').trim();
|
|
39
|
+
const stderr = Buffer.concat(stderrChunks).toString('utf-8').trim();
|
|
40
|
+
if (code !== 0) {
|
|
41
|
+
throw new Error(`Binary exited with code ${code}: ${stderr || stdout}`);
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
// Find the last line that looks like JSON
|
|
45
|
+
const lastLine = stdout.split('\n').filter(line => line.trim()).pop() || '';
|
|
46
|
+
const json = JSON.parse(lastLine);
|
|
47
|
+
resolve(json);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
throw new Error(`Failed to parse JSON output: ${e instanceof Error ? e.message : String(e)} - Output: ${stdout}`);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tmlmobilidade/gtfs-validator",
|
|
3
|
+
"version": "20250416.1622.36",
|
|
4
|
+
"author": "Jusi Monteiro & João Vasconcelos",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"gtfs",
|
|
8
|
+
"validator",
|
|
9
|
+
"gtfs-validator",
|
|
10
|
+
"tmlmobilidade",
|
|
11
|
+
"tml",
|
|
12
|
+
"cmet",
|
|
13
|
+
"carrismetropolitana"
|
|
14
|
+
],
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public",
|
|
17
|
+
"directory": "dist"
|
|
18
|
+
},
|
|
19
|
+
"type": "module",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"main": "dist/index.js",
|
|
24
|
+
"exports": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc",
|
|
30
|
+
"lint": "eslint . && tsc --noEmit",
|
|
31
|
+
"lint:fix": "eslint --fix .",
|
|
32
|
+
"postinstall": "tsx ./scripts/postinstall.ts",
|
|
33
|
+
"test": "tsx src/test.ts"
|
|
34
|
+
},
|
|
35
|
+
"description": "A GTFS Validator",
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@carrismetropolitana/eslint": "^20250325.1926.5",
|
|
38
|
+
"@dotenv-run/cli": "^1.3.6",
|
|
39
|
+
"@tmlmobilidade/tsconfig": "^20250325.1731.13",
|
|
40
|
+
"@types/node": "^22.14.1",
|
|
41
|
+
"ts-node": "^10.9.2",
|
|
42
|
+
"tsx": "^4.19.3",
|
|
43
|
+
"typescript": "^5.7.3"
|
|
44
|
+
}
|
|
45
|
+
}
|