import { execSync } from 'child_process'; import fs from 'fs/promises'; import { Command } from 'commander'; export interface LintAgentOptions {} export interface LintAgentResult { passed: boolean; /** * Statistiques globales issues de ESLint */ metrics?: { errors: number; warnings: number; /** Nombre de fichiers analysés */ files: number; /** Nombre total de problèmes (errors + warnings) */ total: number; /** Nombre de problèmes fixables */ fixable: number; }; /** Chemin vers le rapport JSON détaillé */ detailPath?: string; /** Contenu brut en cas d'erreur JSON */ output?: string; /** Synthèse des fichiers et règles les plus problématiques */ summary?: { topFiles: Array<{ filePath: string; errors: number; warnings: number; total: number; fixable: number }>; topRules: Array<{ ruleId: string; count: number }>; }; } /** * Lance ESLint et renvoie le résultat. */ export async function lintAgent( _opts?: LintAgentOptions, ): Promise { const detailPath = 'eslint-report.json'; try { // Run ESLint and output JSON to stdout // Use npx to invoke the local ESLint binary (works with npm, pnpm, yarn) const cmd = 'npx eslint . --ext .ts,.js --format json'; const stdout = execSync(cmd, { encoding: 'utf-8' }); const results = JSON.parse(stdout); await fs.writeFile(detailPath, stdout, 'utf-8'); let errors = 0; let warnings = 0; let fixable = 0; // Détails par fichier pour synthèse const fileStats: Array<{ filePath: string; errors: number; warnings: number; total: number; fixable: number }> = []; const ruleCounts: Record = {}; results.forEach((file: any) => { let fe = 0; let fw = 0; let ff = 0; file.messages.forEach((m: any) => { if (m.severity === 2) { errors++; fe++; } if (m.severity === 1) { warnings++; fw++; } if (m.fix) { fixable++; ff++; } if (m.ruleId) { ruleCounts[m.ruleId] = (ruleCounts[m.ruleId] || 0) + 1; } }); const total = fe + fw; fileStats.push({ filePath: file.filePath, errors: fe, warnings: fw, total, fixable: ff }); }); const files = results.length; const total = errors + warnings; // Top 5 fichiers et règles const topFiles = fileStats .filter(f => f.total > 0) .sort((a, b) => b.total - a.total) .slice(0, 5); const topRules = Object.entries(ruleCounts) .map(([ruleId, count]) => ({ ruleId, count })) .sort((a, b) => b.count - a.count) .slice(0, 5); return { passed: errors === 0, metrics: { errors, warnings, files, total, fixable }, detailPath, summary: { topFiles, topRules } }; } catch (err: any) { // On errors, attempt to parse output in stdout let raw = ''; if (err.stdout) raw = err.stdout as string; if (!raw && err.stderr) raw = err.stderr as string; await fs.writeFile(detailPath, raw, 'utf-8'); let results: any[] = []; try { results = JSON.parse(raw); } catch {} let errors = 0; let warnings = 0; let fixable = 0; const fileStats: Array<{ filePath: string; errors: number; warnings: number; total: number; fixable: number }> = []; const ruleCounts: Record = {}; results.forEach((file: any) => { let fe = 0; let fw = 0; let ff = 0; file.messages.forEach((m: any) => { if (m.severity === 2) { errors++; fe++; } if (m.severity === 1) { warnings++; fw++; } if (m.fix) { fixable++; ff++; } if (m.ruleId) { ruleCounts[m.ruleId] = (ruleCounts[m.ruleId] || 0) + 1; } }); const totalErr = fe + fw; fileStats.push({ filePath: file.filePath, errors: fe, warnings: fw, total: totalErr, fixable: ff }); }); const files = results.length; const total = errors + warnings; const topFiles = fileStats .filter(f => f.total > 0) .sort((a, b) => b.total - a.total) .slice(0, 5); const topRules = Object.entries(ruleCounts) .map(([ruleId, count]) => ({ ruleId, count })) .sort((a, b) => b.count - a.count) .slice(0, 5); return { passed: false, metrics: { errors, warnings, files, total, fixable }, detailPath, output: raw, summary: { topFiles, topRules } }; } } export const cli = { command: 'qualimetrie:lint', description: 'Vérifie la qualité du code avec ESLint', builder: (cmd: Command) => cmd, handler: async (_opts: unknown) => { // eslint-disable-next-line @typescript-eslint/no-var-requires const { lintAgent: run } = require('./lintAgent'); const res = await run(); console.log(res); }, };