// STATIC GUARD: prod source must pass eslint with zero errors/warnings. // Scans ALL .js/.jsx in src/ + shared/ (excl tests/mocks). Catches unused imports, // dead code, undefined vars before they hit the browser console. // Run via: npx eslint --format json -> parse -> fail on any problem. const { execSync } = require('child_process'); const path = require('path'); const fs = require('fs'); const ROOT = path.resolve(__dirname, '..', '..'); function walkJs(dir) { let out = []; for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { const full = path.join(dir, entry.name); if (entry.isDirectory()) { if (entry.name === 'node_modules' || entry.name === 'tests' || entry.name === '__mocks__') continue; out = out.concat(walkJs(full)); } else if (/\.(js|jsx)$/.test(entry.name)) { out.push(full); } } return out; } const TARGETS = [ ...walkJs(path.join(ROOT, 'src')), ...walkJs(path.join(ROOT, 'shared')), ]; function runEslint(files) { const abs = files.map(f => `"${path.join(ROOT, f)}"`).join(' '); // execSync throws on non-zero exit (eslint returns 1 when problems found). // Capture stdout regardless. let stdout; try { stdout = execSync(`npx eslint ${abs} --format json`, { encoding: 'utf8', cwd: ROOT, stdio: ['pipe', 'pipe', 'pipe'], }); } catch (err) { stdout = err.stdout || ''; } return JSON.parse(stdout || '[]'); } describe('static guard: eslint clean on prod source', () => { test('zero eslint errors or warnings', () => { const results = runEslint(TARGETS); const problems = []; let totalErrors = 0; let totalWarnings = 0; for (const file of results) { totalErrors += file.errorCount; totalWarnings += file.warningCount; for (const msg of file.messages) { problems.push(` ${path.relative(ROOT, file.filePath)}:${msg.line}:${msg.column} ${msg.ruleId} — ${msg.message}`); } } if (totalErrors + totalWarnings > 0) { const summary = `eslint found ${totalErrors} error(s), ${totalWarnings} warning(s):\n${problems.join('\n')}`; throw new Error(summary); } }, 30000); // eslint spawn can be slow });