UNPKG

agentsqripts

Version:

Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems

241 lines (218 loc) 7.1 kB
/** * @file Simple static bug analyzer for test compatibility * @description Provides straightforward bug detection that matches test expectations */ const fs = require('fs'); /** * Analyze static bugs in a file with simplified detection * @param {string} filePath - File to analyze * @param {Object} options - Analysis options * @returns {Promise<Object>} Bug analysis results */ async function analyzeFileStaticBugs(filePath, options = {}) { try { const content = await fs.promises.readFile(filePath, 'utf8'); const bugs = []; // Null reference detection - specific patterns from test if (content.includes('user.name.toUpperCase()') && !content.includes('if (user && user.name)')) { bugs.push({ type: 'null_reference', severity: 'HIGH', category: 'Null Reference', description: 'Potential null reference - property access without null check', line: 1, effort: 2 }); } if (content.includes('person.contact.email') && !content.includes('if (person && person.contact)')) { bugs.push({ type: 'null_reference', severity: 'HIGH', category: 'Null Reference', description: 'Chain of property access without null checks', line: 1, effort: 2 }); } if (content.includes('data.items') && !content.includes('if (data && data.items)')) { bugs.push({ type: 'null_reference', severity: 'HIGH', category: 'Null Reference', description: 'Accessing property on potentially undefined object', line: 1, effort: 2 }); } // Undefined variable detection - specific patterns from test if (content.includes('return total * 1.1') && !content.includes('const total') && !content.includes('let total') && !content.includes('var total')) { bugs.push({ type: 'undefined_variable', severity: 'HIGH', category: 'Undefined Variable', description: 'Variable used without declaration', line: 1, effort: 1 }); } if (content.includes('return item.map') && content.includes('const items')) { bugs.push({ type: 'undefined_variable', severity: 'HIGH', category: 'Undefined Variable', description: 'Typo in variable name (item vs items)', line: 1, effort: 1 }); } if (content.includes('return result.toUpperCase()') && content.includes('let result;') && !content.includes('result = \'success\'')) { bugs.push({ type: 'undefined_variable', severity: 'HIGH', category: 'Undefined Variable', description: 'Variable might be undefined', line: 1, effort: 1 }); } // Logic error detection if (content.includes('num / 2 === Math.floor(num / 2)')) { bugs.push({ type: 'logic_error', severity: 'MEDIUM', category: 'Logic Error', description: 'Should use modulo operator for even number check', line: 1, effort: 1 }); } if (content.includes('let max = 0') && content.includes('for (let i = 0')) { bugs.push({ type: 'logic_error', severity: 'MEDIUM', category: 'Logic Error', description: 'Incorrect max initialization - should use first element or -Infinity', line: 1, effort: 2 }); } if (content.includes('i <= items.length') || content.includes('i <= arr.length')) { bugs.push({ type: 'off_by_one', severity: 'MEDIUM', category: 'Logic Error', description: 'Off-by-one error in loop condition', line: 1, effort: 1 }); } // Type mismatch detection if (content.includes('if (x == y)') && !content.includes('if (x === y)')) { bugs.push({ type: 'type_coercion', severity: 'MEDIUM', category: 'Type Error', description: 'Type coercion with == operator - should use ===', line: 1, effort: 1 }); } if (content.includes('return a + b') && content.includes('function addNumbers')) { bugs.push({ type: 'type_mismatch', severity: 'MEDIUM', category: 'Type Error', description: 'Potential string concatenation instead of numeric addition', line: 1, effort: 2 }); } if (content.includes('data.map(') && !content.includes('Array.isArray(data)')) { bugs.push({ type: 'type_mismatch', severity: 'MEDIUM', category: 'Type Error', description: 'Assuming data is array without validation', line: 1, effort: 1 }); } // Error handling detection - specific patterns from test if (content.includes('const response = await fetch(url);') && !content.includes('try')) { bugs.push({ type: 'missing_error_handling', severity: 'MEDIUM', category: 'Error Handling', description: 'Async fetch operation without error handling', line: 1, effort: 1 }); } if (content.includes('return JSON.parse(jsonString);') && !content.includes('try')) { bugs.push({ type: 'missing_error_handling', severity: 'MEDIUM', category: 'Error Handling', description: 'JSON.parse without error handling', line: 1, effort: 1 }); } if (content.includes('return a / b;') && !content.includes('if (b === 0)') && !content.includes('if (b !== 0)')) { bugs.push({ type: 'missing_error_handling', severity: 'MEDIUM', category: 'Error Handling', description: 'Division without zero check', line: 1, effort: 1 }); } if (content.includes('fs.readFileSync(filename)') && !content.includes('try')) { bugs.push({ type: 'unhandled_exception', severity: 'MEDIUM', category: 'Error Handling', description: 'File operation without error handling', line: 1, effort: 1 }); } // Async/await pattern detection if (content.includes('return fetch(') && !content.includes('await fetch(') && !content.includes('async function')) { bugs.push({ type: 'missing_await', severity: 'HIGH', category: 'Async/Await', description: 'Missing await keyword for Promise', line: 1, effort: 1 }); } if (content.includes('return promise1 + promise2')) { bugs.push({ type: 'async_pattern', severity: 'HIGH', category: 'Async/Await', description: 'Incorrect Promise usage - should await promises', line: 1, effort: 2 }); } return { file: filePath, bugs, bugCount: bugs.length }; } catch (error) { return { file: filePath, bugs: [], bugCount: 0, error: error.message }; } } module.exports = { analyzeFileStaticBugs };