import { spawnSync } from "node:child_process"; import { readdirSync, readFileSync, statSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const sourceFiles = collectSourceFiles(path.join(rootDir, "src")); let explicitAnyCount = 0; for (const file of sourceFiles) { const text = readFileSync(file, "utf8"); const stripped = stripComments(text); const matches = [ ...stripped.matchAll(/:\s*any\b/gu), ...stripped.matchAll(/<\s*any\s*>/gu), ...stripped.matchAll(/as\s+any\b/gu), ...stripped.matchAll(/Array\s*<\s*any\s*>/gu) ]; if (matches.length > 0) { explicitAnyCount += matches.length; console.error(` ${path.relative(rootDir, file)}: ${matches.length} explicit any usage(s)`); } } if (explicitAnyCount > 0) { console.error(`hwlab-cloud-web tsc-check: ${explicitAnyCount} explicit any usage(s) in Vue source`); process.exit(2); } const vueTscBin = path.join(rootDir, "node_modules/.bin/vue-tsc"); const result = spawnSync(vueTscBin, ["--noEmit", "--project", path.join(rootDir, "tsconfig.json")], { cwd: rootDir, encoding: "utf8" }); if (result.stdout) process.stdout.write(result.stdout); if (result.stderr) process.stderr.write(result.stderr); if (result.error) console.error(`hwlab-cloud-web tsc-check: failed to start ${vueTscBin}: ${result.error.message}`); if (result.status !== 0) { console.error(`hwlab-cloud-web tsc-check: vue-tsc failed with exit ${result.status ?? "unknown"}`); process.exit(result.status ?? 2); } console.log("hwlab-cloud-web tsc-check: passed (strict Vue TS, 0 explicit any)"); function collectSourceFiles(dir: string): string[] { const out: string[] = []; for (const entry of readdirSync(dir)) { if (entry === "node_modules" || entry === "dist" || entry.startsWith(".")) continue; const full = path.join(dir, entry); const stat = statSync(full); if (stat.isDirectory()) out.push(...collectSourceFiles(full)); else if (/\.(ts|vue)$/u.test(full)) out.push(full); } return out; } function stripComments(text: string): string { return text.replace(/\/\*[\s\S]*?\*\//gu, "").replace(/(^|[^:])\/\/.*$/gmu, "$1"); }