UNPKG

@sun-asterisk/sunlint

Version:

☀️ SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards

142 lines (117 loc) 4.2 kB
/** * C029 Analyzer - Smart Pipeline Integration * * This analyzer forwards to the Smart Pipeline for superior accuracy and performance */ const fs = require('fs'); const path = require('path'); class C029Analyzer { constructor(options = {}) { this.ruleId = 'C029'; this.ruleName = 'Enhanced Catch Block Error Logging'; this.description = 'Mọi catch block phải log nguyên nhân lỗi đầy đủ và bảo toàn context (Smart Pipeline 3-stage analysis)'; this.verbose = options.verbose || false; // Load Smart Pipeline as primary analyzer this.smartPipeline = null; try { this.smartPipeline = require('./analyzer-smart-pipeline.js'); if (this.verbose) { console.log('[DEBUG] 🎯 C029: Smart Pipeline loaded (3-stage: Regex → AST → Data Flow)'); } } catch (error) { if (this.verbose) { console.warn('[DEBUG] ⚠️ C029: Smart Pipeline failed, using fallback:', error.message); } this.smartPipeline = null; } } async analyze(files, language, options = {}) { // Store verbose option for this analysis this.verbose = options.verbose || this.verbose || false; // Use Smart Pipeline as primary choice if (this.smartPipeline) { if (this.verbose) { console.log('[DEBUG] 🎯 C029: Using Smart Pipeline (3-stage analysis)...'); } return await this.smartPipeline.analyze(files, language, options); } else { if (this.verbose) { console.log('[DEBUG] 🔍 C029: Using fallback regex analysis...'); } return await this.analyzeWithRegex(files, language, options); } } async analyzeWithRegex(files, language, options = {}) { const violations = []; for (const filePath of files) { if (options.verbose) { console.log(`🔍 C029 Regex: Processing ${path.basename(filePath)}...`); } try { const content = fs.readFileSync(filePath, 'utf8'); const fileViolations = await this.analyzeFile(filePath, content, language); violations.push(...fileViolations); } catch (error) { console.warn(`⚠️ C029: Error processing ${filePath}:`, error.message); } } return violations; } async analyzeFile(filePath, content, language) { const violations = []; const lines = content.split('\n'); for (let i = 0; i < lines.length; i++) { const line = lines[i]; // Simple catch block detection if (line.includes('catch') && line.includes('(')) { const catchBlock = this.extractCatchBlock(lines, i); if (this.isCatchBlockEmpty(catchBlock.content)) { violations.push({ file: filePath, line: i + 1, column: line.indexOf('catch') + 1, message: 'Empty catch block detected', severity: 'error', ruleId: this.ruleId, type: 'empty_catch' }); } } } return violations; } extractCatchBlock(lines, startIndex) { const content = []; let braceCount = 0; let inBlock = false; for (let i = startIndex; i < lines.length; i++) { const line = lines[i]; content.push(line); for (const char of line) { if (char === '{') { braceCount++; inBlock = true; } else if (char === '}') { braceCount--; if (braceCount === 0 && inBlock) { return { content, endIndex: i }; } } } } return { content, endIndex: startIndex }; } isCatchBlockEmpty(content) { const blockContent = content.join('\n'); // Remove comments and whitespace const cleanContent = blockContent .replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments .replace(/\/\/.*$/gm, '') // Remove single-line comments .replace(/\s+/g, ' ') // Normalize whitespace .trim(); // Check if only contains catch declaration and braces const hasOnlyStructure = /^catch\s*\([^)]*\)\s*\{\s*\}$/.test(cleanContent); return hasOnlyStructure; } } module.exports = C029Analyzer;