/** * Static Analysis Module * Runs deterministic static analysis before LLM review * Uses enhanced regex-based checks for syntax errors * Injects findings into LLM prompt for context */ interface StaticAnalysisFinding { line?: number severity: 'error' | 'warning' message: string rule?: string } interface StaticAnalysisResult { filename: string findings: StaticAnalysisFinding[] } /** * Analyze Python for basic syntax issues */ function analyzePythonBasic(content: string): StaticAnalysisFinding[] { const findings: StaticAnalysisFinding[] = [] const lines = content.split('\n') // Check for common Python issues lines.forEach((line, idx) => { const lineNum = idx + 1 // Check for unmatched parentheses const openBrackets = (line.match(/\(/g) || []).length const closeBrackets = (line.match(/\)/g) || []).length if (openBrackets !== closeBrackets) { findings.push({ line: lineNum, severity: 'error', message: 'Unmatched parentheses detected', rule: 'syntax-balance' }) } // Check for unmatched braces const openBraces = (line.match(/\{/g) || []).length const closeBraces = (line.match(/\}/g) || []).length if (openBraces !== closeBraces) { findings.push({ line: lineNum, severity: 'error', message: 'Unmatched braces detected', rule: 'syntax-balance' }) } // Check for unmatched square brackets const openSquare = (line.match(/\[/g) || []).length const closeSquare = (line.match(/\]/g) || []).length if (openSquare !== closeSquare) { findings.push({ line: lineNum, severity: 'error', message: 'Unmatched square brackets detected', rule: 'syntax-balance' }) } }) return findings } /** * Analyze JavaScript/TypeScript for basic syntax issues */ function analyzeJavaScriptBasic(_content: string): StaticAnalysisFinding[] { return [] } function analyzeTypeScriptEnhanced(content: string): StaticAnalysisFinding[] { const findings: StaticAnalysisFinding[] = [] const lines = content.split('\n') lines.forEach((line, idx) => { const lineNum = idx + 1 const trimmed = line.trim() // Check for TypeScript syntax issues if (trimmed.includes('interface') && !trimmed.includes('{')) { findings.push({ line: lineNum, severity: 'error', message: 'Interface declaration missing opening brace', rule: 'ts-syntax' }) } // Check for type assertion issues if (trimmed.match(/<[^>]+>\s*[^=]/) && !trimmed.includes('extends')) { findings.push({ line: lineNum, severity: 'warning', message: 'Potential type assertion - consider using as keyword', rule: 'ts-style' }) } // Check for async/await without error handling if ( trimmed.includes('await') && !trimmed.includes('try') && !trimmed.includes('catch') && !line.includes('.catch(') && !line.includes('await Promise.') ) { findings.push({ line: lineNum, severity: 'warning', message: 'Await without error handling', rule: 'async-error' }) } // Check for console.log in production code if ( trimmed.includes('console.log') || trimmed.includes('console.warn') || trimmed.includes('console.error') ) { findings.push({ line: lineNum, severity: 'warning', message: 'Console statement detected', rule: 'no-console' }) } // Check for any type usage (warning) if ( trimmed.includes(': any') || trimmed.includes('any[]') || trimmed.includes('any>') ) { findings.push({ line: lineNum, severity: 'warning', message: 'Using any type reduces type safety', rule: 'no-any' }) } }) return findings } /** * Main static analysis function * Analyzes file content and returns findings */ export async function analyzeStatic( content: string, filename: string ): Promise { const ext = filename.split('.').pop()?.toLowerCase() let findings: StaticAnalysisFinding[] = [] switch (ext) { case 'py': findings = analyzePythonBasic(content) break case 'js': case 'jsx': case 'ts': case 'tsx': findings = analyzeTypeScriptEnhanced(content) break default: // No static analysis for other file types break } return { filename, findings } } /** * Format static analysis findings for injection into LLM prompt * Bug Fix #2: Always return content so LLM knows analysis was performed */ export function formatStaticAnalysisFindings( findings: StaticAnalysisFinding[] ): string { if (findings.length === 0) { return 'Static analysis: No syntax errors or common issues detected.' } const formatted = findings .map(f => { const line = f.line ? ` line ${f.line}` : '' const rule = f.rule ? ` [${f.rule}]` : '' return `- ${f.severity.toUpperCase()}${line}${rule}: ${f.message}` }) .join('\n') return `Static analysis detected:\n${formatted}` }