Skip to content

Commit 8433765

Browse files
committed
Add script test wild
1 parent 5fc8ac9 commit 8433765

2 files changed

Lines changed: 173 additions & 0 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ jobs:
3333
node-version: 22 # https://github.com/tree-sitter/node-tree-sitter/issues/268
3434
test-python: true
3535
test-go: true
36+
37+
- name: Run test wild
38+
run: node scripts/test_wild.mjs

‎scripts/test_wild.mjs‎

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import child_process from "node:child_process";
2+
import fs from "node:fs";
3+
import path from "node:path";
4+
5+
const repositories = [
6+
{
7+
url: "https://github.com/rescript-lang/experimental-rescript-webapi",
8+
commit: null,
9+
},
10+
{ url: "https://github.com/rescript-lang/rescript-lang.org", commit: null },
11+
{ url: "https://github.com/rescript-lang/rescript-react", commit: null },
12+
{ url: "https://github.com/enviodev/hyperindex", commit: null },
13+
{ url: "https://github.com/frontman-ai/frontman", commit: null },
14+
{ url: "https://github.com/zth/rescript-relay", commit: null },
15+
{ url: "https://github.com/glennsl/rescript-jest", commit: null },
16+
{ url: "https://github.com/cca-io/rescript-mui", commit: null },
17+
{ url: "https://github.com/DZakh/sury", commit: null },
18+
{ url: "https://github.com/DZakh/rescript-envsafe", commit: null },
19+
{ url: "https://github.com/DZakh/rescript-rest", commit: null }
20+
];
21+
22+
const TEST_WILD_DIR = path.join(process.cwd(), "test_wild");
23+
24+
if (!fs.existsSync(TEST_WILD_DIR)) {
25+
fs.mkdirSync(TEST_WILD_DIR);
26+
}
27+
28+
const signals = {
29+
SIGINT: 2,
30+
SIGQUIT: 3,
31+
SIGKILL: 9,
32+
SIGTERM: 15,
33+
};
34+
async function exec(command, args = [], cwd = process.cwd(), options = {}) {
35+
const { throwOnFail = options.stdio === "inherit" } = options;
36+
37+
const stdoutChunks = [];
38+
const stderrChunks = [];
39+
40+
const subprocess = child_process.spawn(command, args, {
41+
cwd,
42+
shell: process.platform === "win32",
43+
stdio: ["ignore", "pipe", "pipe"],
44+
...options,
45+
});
46+
47+
subprocess.stdout?.on("data", (chunk) => {
48+
stdoutChunks.push(chunk);
49+
});
50+
51+
subprocess.stderr?.on("data", (chunk) => {
52+
stderrChunks.push(chunk);
53+
});
54+
55+
return await new Promise((resolve, reject) => {
56+
subprocess.once("error", (err) => {
57+
reject(err);
58+
});
59+
60+
subprocess.once("close", (exitCode, signal) => {
61+
const stdout = Buffer.concat(stdoutChunks).toString("utf8");
62+
const stderr = Buffer.concat(stderrChunks).toString("utf8");
63+
64+
let code = exitCode ?? 1;
65+
if (signals[signal]) {
66+
// + 128 is standard POSIX practice, see also https://nodejs.org/api/process.html#exit-codes
67+
code = signals[signal] + 128;
68+
}
69+
70+
if (throwOnFail && code !== 0) {
71+
reject(
72+
new Error(`Command ${command} exited with non-zero status: ${code}`),
73+
);
74+
} else {
75+
resolve({ status: code, stdout, stderr });
76+
}
77+
});
78+
});
79+
}
80+
81+
async function cloneRepo({ url, commit }) {
82+
const baseName = url.split("/").pop();
83+
const dirName = commit ? `${baseName}-${commit}` : baseName;
84+
const repoDir = path.join(TEST_WILD_DIR, dirName);
85+
const label = commit ? `${baseName}@${commit}` : baseName;
86+
87+
if (fs.existsSync(repoDir)) {
88+
console.log(`[${label}] already cloned, skipping`);
89+
return { repoDir, dirName, label };
90+
}
91+
92+
if (commit) {
93+
console.log(`[${label}] cloning at commit ${commit}...`);
94+
await exec("git", ["clone", url, repoDir]);
95+
await exec("git", ["checkout", commit], repoDir);
96+
} else {
97+
console.log(`[${label}] cloning...`);
98+
await exec("git", ["clone", "--depth=1", url, repoDir]);
99+
}
100+
console.log(`[${label}] cloned`);
101+
return { repoDir, dirName, label };
102+
}
103+
104+
async function parseRepo(dirName, label) {
105+
const globPatternRes = `test_wild/${dirName}/**/*.res`;
106+
console.log(`[${label}] running tree-sitter parse...`);
107+
108+
const { stdout, stderr } = await exec("npx", [
109+
"tree-sitter",
110+
"parse",
111+
"--json-summary",
112+
globPatternRes,
113+
]);
114+
115+
const validJson = stdout
116+
.split("\n")
117+
.filter((line) => !line.trim().startsWith("test_wild"))
118+
.join("\n");
119+
120+
try {
121+
const result = JSON.parse(validJson);
122+
return result.parse_summaries ?? [];
123+
} catch {
124+
console.error({
125+
stdout: stdout,
126+
stderr: stderr,
127+
});
128+
throw new Error(`Failed to parse json`);
129+
}
130+
}
131+
132+
async function processRepo(repo) {
133+
const { dirName, label } = await cloneRepo(repo);
134+
135+
const summaries = await parseRepo(dirName, label);
136+
const errors = summaries.filter((s) => !s.successful);
137+
138+
console.log(
139+
`[${label}] ${summaries.length} files parsed, ${errors.length} errors`,
140+
);
141+
return { label, summaries, errors };
142+
}
143+
144+
async function main() {
145+
const results = await Promise.all(repositories.map(processRepo));
146+
147+
console.log("\n=== Parse Error Summary ===\n");
148+
let totalErrors = 0;
149+
150+
for (const { label, summaries, errors } of results) {
151+
console.log(
152+
`${label}: ${errors.length} / ${summaries.length} files with errors`,
153+
);
154+
for (const entry of errors) {
155+
console.log(` ${entry.file}`);
156+
}
157+
totalErrors += errors.length;
158+
}
159+
160+
console.log(`\nTotal files with errors: ${totalErrors}`);
161+
162+
if (totalErrors > 0) {
163+
throw new Error("Test wild failed");
164+
}
165+
}
166+
167+
main().catch((err) => {
168+
console.error(err);
169+
process.exit(1);
170+
});

0 commit comments

Comments
 (0)