const fs = require('fs'); const path = require('path'); const vm = require('vm'); const ejs = require('ejs'); const JS_DIRS = ['server', 'public/js', 'sample-content/plugins', 'test']; const VIEW_DIR = 'views'; const CSS_DIR = 'public/css'; let jsFilesChecked = 0; let ejsFilesChecked = 0; let cssFilesChecked = 0; let errorCount = 0; // 1. JavaScript Checker function checkJsFile(filePath) { jsFilesChecked++; const code = fs.readFileSync(filePath, 'utf8'); try { new vm.Script(code, { filename: filePath }); } catch (err) { console.error(`āŒ Syntax Error in ${filePath}:\n ${err.message}`); errorCount++; return; } if (/\bdebugger\b/.test(code)) { console.error(`āš ļø Warning in ${filePath}: Found 'debugger' statement.`); errorCount++; } if (/-----BEGIN (RSA|EC|OPENSSH|PRIVATE) KEY-----/.test(code)) { console.error(`🚨 Security Alert in ${filePath}: Found private key pattern!`); errorCount++; } } // 2. EJS Template Checker function checkEjsFile(filePath) { ejsFilesChecked++; const content = fs.readFileSync(filePath, 'utf8'); // Verify EJS syntax compilation try { ejs.compile(content, { filename: filePath, client: false }); } catch (err) { console.error(`āŒ EJS Compilation Error in ${filePath}:\n ${err.message}`); errorCount++; return; } // Prevent inline style anti-patterns that break IDE CSS linters: style="... <%= ... %> ..." const styleMatch = content.match(/style="[^"]*<[%#=][\s\S]*?"/g); if (styleMatch) { console.error(`āŒ Linter Error in ${filePath}: Dynamic EJS expression inside style="" attribute causes IDE CSS linter errors. Use CSS utility classes instead:\n Matched: ${styleMatch[0]}`); errorCount++; } } // 3. CSS Checker (Brace matching) function checkCssFile(filePath) { cssFilesChecked++; const content = fs.readFileSync(filePath, 'utf8'); let openBraces = 0; for (let i = 0; i < content.length; i++) { if (content[i] === '{') openBraces++; if (content[i] === '}') openBraces--; if (openBraces < 0) { console.error(`āŒ CSS Error in ${filePath}: Unexpected closing brace '}' at char ${i}`); errorCount++; return; } } if (openBraces !== 0) { console.error(`āŒ CSS Error in ${filePath}: Unclosed brace '{' (mismatched by ${openBraces})`); errorCount++; } } function walkDir(dir, ext, handler) { if (!fs.existsSync(dir)) return; const entries = fs.readdirSync(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) { if (entry.name !== 'node_modules' && entry.name !== '.git') { walkDir(fullPath, ext, handler); } } else if (entry.isFile() && entry.name.endsWith(ext)) { handler(fullPath); } } } console.log('šŸ” Running comprehensive project linter (JS, EJS templates, CSS)...'); JS_DIRS.forEach(d => walkDir(d, '.js', checkJsFile)); walkDir(VIEW_DIR, '.ejs', checkEjsFile); walkDir(CSS_DIR, '.css', checkCssFile); if (errorCount === 0) { console.log(`āœ“ All files passed verification!`); console.log(` - ${jsFilesChecked} JavaScript files`); console.log(` - ${ejsFilesChecked} EJS templates`); console.log(` - ${cssFilesChecked} CSS stylesheets`); process.exit(0); } else { console.error(`\nāŒ Linting failed with ${errorCount} error(s).`); process.exit(1); }