import { spawn } from "child_process"; import fs from "fs"; import path from "path"; export interface ValidationResult { success: boolean; installLog: string; buildLog: string; error?: string; duration: number; // milliseconds } /** * Run a command with timeout and capture stdout/stderr */ function runCommand( cmd: string, args: string[], cwd: string, timeout: number = 300000 // 5 minutes default ): Promise<{ stdout: string; stderr: string; code: number | null }> { return new Promise((resolve) => { const child = spawn(cmd, args, { cwd, shell: true }); let stdout = ""; let stderr = ""; child.stdout.on("data", (data) => { stdout += data.toString(); }); child.stderr.on("data", (data) => { stderr += data.toString(); }); const timer = setTimeout(() => { child.kill("SIGTERM"); resolve({ stdout, stderr: stderr + "\n[ERROR] Command timed out after " + timeout + "ms", code: null, }); }, timeout); child.on("close", (code) => { clearTimeout(timer); resolve({ stdout, stderr, code }); }); child.on("error", (err) => { clearTimeout(timer); resolve({ stdout, stderr: stderr + "\n" + err.message, code: null, }); }); }); } export async function validateProject( projectDir: string, options: { installTimeout?: number; buildTimeout?: number } = {} ): Promise { const start = Date.now(); const installTimeout = options.installTimeout || 300000; const buildTimeout = options.buildTimeout || 300000; // Check if project directory exists if (!fs.existsSync(projectDir)) { return { success: false, installLog: "", buildLog: "", error: `Project directory not found: ${projectDir}`, duration: 0, }; } // Check for package.json const pkgPath = path.join(projectDir, "package.json"); if (!fs.existsSync(pkgPath)) { return { success: false, installLog: "", buildLog: "", error: "No package.json found in project directory", duration: 0, }; } // Step 1: npm install const installResult = await runCommand( "npm", ["install", "--no-audit", "--no-fund", "--loglevel=error", "--include=dev"], projectDir, installTimeout ); const installLog = installResult.stdout + "\n" + installResult.stderr; if (installResult.code !== 0) { return { success: false, installLog, buildLog: "", error: `npm install failed with code ${installResult.code}`, duration: Date.now() - start, }; } // Step 2: npm run build const buildResult = await runCommand( "npm", ["run", "build"], projectDir, buildTimeout ); const buildLog = buildResult.stdout + "\n" + buildResult.stderr; if (buildResult.code !== 0 && buildResult.code !== null) { return { success: false, installLog, buildLog, error: `npm run build failed with code ${buildResult.code}`, duration: Date.now() - start, }; } return { success: true, installLog, buildLog, duration: Date.now() - start, }; } /** * Validate the project and write a JSON report inside the project directory */ export async function validateAndSave( projectDir: string, options?: { installTimeout?: number; buildTimeout?: number } ): Promise { const result = await validateProject(projectDir, options); const reportPath = path.join(projectDir, ".validation.json"); fs.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8"); return result; }