UNPKG

@chahuadev/fix-comments

Version:

Professional Comment Standardization Tool v2.0.0 Beta - Advanced Pattern Recognition and Enhanced Context Detection for JavaScript/TypeScript projects with Smart Learning capabilities and enterprise security

1,203 lines (1,010 loc) 430 kB
#!/usr/bin/env node // ====================================================================== // Universal Comment Fixer v2.0.0/เครื่องมือแก้ไขคอมเมนต์สากล v2.0.0 // ====================================================================== // @author บริษัท ชาหัว ดีเวลลอปเมนต์ จำกัด (Chahua Development Co., Ltd.) // @version 2.0.0 // @description Professional comment standardization tool with AI-friendly format // @security_features Path Traversal Protection, File Size Limits, Symlink Protection // SECURITY FEATURES: // ┌─────────────────────────────────────────────────────────────────┐ // │ • Path Traversal Protection: Prevents ../../../etc/passwd attacks │ // │ • File Size Limits: 10MB maximum to prevent DoS attacks │ // │ • Symbolic Link Protection: Prevents infinite loop attacks │ // │ • System Directory Blacklist: Blocks access to sensitive paths │ // │ • Backup Path Validation: Secure backup creation with sanitization │ // │ • Working Directory Enforcement: All operations within project │ // └─────────────────────────────────────────────────────────────────┘ const fs = require('fs'); const path = require('path'); // ====================================================================== // Professional Logging System/ระบบบันทึกมืออาชีพ // ====================================================================== class ProfessionalLogger { constructor() { this.projectName = path.basename(process.cwd()); this.logsDir = path.join(process.cwd(), 'logs'); // สร้างโฟลเดอร์ logs หลักถ้ายังไม่มี if (!fs.existsSync(this.logsDir)) { fs.mkdirSync(this.logsDir, { recursive: true }); } // สร้างโฟลเดอร์ย่อยสำหรับโปรเจกต์นี้ this.projectLogsDir = path.join(this.logsDir, this.projectName); if (!fs.existsSync(this.projectLogsDir)) { fs.mkdirSync(this.projectLogsDir, { recursive: true }); } // สร้างโฟลเดอร์ session ตามวันเวลา const now = new Date(); const dateFolder = now.toISOString().slice(0, 10); // 2025-09-24 const timeFolder = now.toTimeString().slice(0, 8).replace(/:/g, '-'); // 03-53-12 this.sessionFolder = `${dateFolder}_${timeFolder}`; this.sessionLogsDir = path.join(this.projectLogsDir, this.sessionFolder); if (!fs.existsSync(this.sessionLogsDir)) { fs.mkdirSync(this.sessionLogsDir, { recursive: true }); } this.logFiles = { error: path.join(this.sessionLogsDir, 'error.log'), debug: path.join(this.sessionLogsDir, 'debug.log'), audit: path.join(this.sessionLogsDir, 'audit.log'), performance: path.join(this.sessionLogsDir, 'performance.log'), diagnostic: path.join(this.sessionLogsDir, 'diagnostic.log') }; // เขียน session header this.writeSessionHeader(); } writeSessionHeader() { const timestamp = new Date().toISOString(); const header = `\n${'='.repeat(80)}\nSESSION START: ${timestamp} | Project: ${this.projectName}\n${'='.repeat(80)}\n`; Object.values(this.logFiles).forEach(logFile => { fs.appendFileSync(logFile, header, 'utf8'); }); } formatLogEntry(level, category, message, data = null) { const timestamp = new Date().toISOString(); let entry = `[${timestamp}] [${level.toUpperCase()}] [${category}] ${message}`; if (data) { entry += `\n Data: ${JSON.stringify(data, null, 2)}`; } entry += '\n'; return entry; } error(category, message, error = null, data = null) { const logData = { ...data }; if (error) { logData.error = { message: error.message, stack: error.stack, name: error.name }; } const entry = this.formatLogEntry('ERROR', category, message, logData); fs.appendFileSync(this.logFiles.error, entry, 'utf8'); // แสดงใน console ด้วย console.error(`[ERROR] ${category}: ${message}`); } debug(category, message, data = null) { const entry = this.formatLogEntry('DEBUG', category, message, data); fs.appendFileSync(this.logFiles.debug, entry, 'utf8'); } audit(action, filePath, details = null) { const entry = this.formatLogEntry('AUDIT', 'FILE_OPERATION', `${action}: ${filePath}`, details); fs.appendFileSync(this.logFiles.audit, entry, 'utf8'); } performance(operation, duration, details = null) { const entry = this.formatLogEntry('PERFORMANCE', operation, `Duration: ${duration}ms`, details); fs.appendFileSync(this.logFiles.performance, entry, 'utf8'); } info(category, message, data = null) { const entry = this.formatLogEntry('INFO', category, message, data); fs.appendFileSync(this.logFiles.debug, entry, 'utf8'); } // สร้าง diagnostic report แยกต่างหาก diagnostic(category, message, data = null) { const entry = this.formatLogEntry('DIAGNOSTIC', category, message, data); // เขียนลงทั้ง audit และ debug ในโฟลเดอร์ session fs.appendFileSync(this.logFiles.audit, entry, 'utf8'); fs.appendFileSync(this.logFiles.debug, `\n=== DIAGNOSTIC REPORT ===\n${entry}=== END DIAGNOSTIC ===\n`, 'utf8'); // เขียนลงไฟล์ diagnostic ใน session folder if (!fs.existsSync(this.logFiles.diagnostic)) { const header = `DIAGNOSTIC REPORTS LOG - ${new Date().toISOString()}\nProject: ${this.projectName} | Session: ${this.sessionFolder}\n${'='.repeat(80)}\n\n`; fs.writeFileSync(this.logFiles.diagnostic, header, 'utf8'); } fs.appendFileSync(this.logFiles.diagnostic, entry, 'utf8'); } } // สร้าง logger instance const logger = new ProfessionalLogger(); // ====================================================================== // Organized Backup System/ระบบสำรองข้อมูลที่เป็นระบบ // ====================================================================== class OrganizedBackupManager { constructor() { this.projectName = path.basename(process.cwd()); this.backupsDir = path.join(process.cwd(), '.backups'); this.projectBackupDir = path.join(this.backupsDir, this.projectName); // สร้างโฟลเดอร์ backup ถ้ายังไม่มี this.ensureBackupDirectories(); } ensureBackupDirectories() { if (!fs.existsSync(this.backupsDir)) { fs.mkdirSync(this.backupsDir, { recursive: true }); logger.audit('CREATE_BACKUP_DIR', this.backupsDir); } if (!fs.existsSync(this.projectBackupDir)) { fs.mkdirSync(this.projectBackupDir, { recursive: true }); logger.audit('CREATE_PROJECT_BACKUP_DIR', this.projectBackupDir); } } createBackup(originalFilePath) { try { // ตรวจสอบว่าไฟล์ต้นฉบับมีอยู่จริง if (!fs.existsSync(originalFilePath)) { throw new Error(`Original file does not exist: ${originalFilePath}`); } // สร้างโฟลเดอร์ตามวันที่-เวลา const now = new Date(); const dateFolder = now.toISOString().slice(0, 10); // 2025-09-24 const timeFolder = now.toTimeString().slice(0, 8).replace(/:/g, '-'); // 03-40-40 const sessionFolder = `${dateFolder}_${timeFolder}`; // สร้างโฟลเดอร์ backup session const sessionBackupDir = path.join(this.projectBackupDir, sessionFolder); if (!fs.existsSync(sessionBackupDir)) { fs.mkdirSync(sessionBackupDir, { recursive: true }); logger.audit('CREATE_SESSION_BACKUP_DIR', sessionBackupDir); } // ใช้ชื่อไฟล์ต้นฉบับธรรมดา const originalFileName = path.basename(originalFilePath); const backupFilePath = path.join(sessionBackupDir, originalFileName); // คัดลอกไฟล์ต้นฉบับไป backup (เก็บไฟล์ต้นฉบับ) const originalContent = fs.readFileSync(originalFilePath, 'utf8'); fs.writeFileSync(backupFilePath, originalContent, 'utf8'); // บันทึก audit log logger.audit('BACKUP_CREATED', originalFilePath, { backupPath: backupFilePath, sessionFolder: sessionFolder, originalSize: originalContent.length, originalFileName: originalFileName }); logger.info('BACKUP', `Original file backed up to: ${sessionFolder}/${originalFileName}`); return backupFilePath; } catch (error) { logger.error('BACKUP', `Failed to create backup for ${originalFilePath}`, error); throw error; } } cleanupOldBackups(maxAge = 7) { try { const sessionFolders = fs.readdirSync(this.projectBackupDir); const cutoffTime = Date.now() - (maxAge * 24 * 60 * 60 * 1000); let cleanedCount = 0; sessionFolders.forEach(sessionFolder => { const sessionPath = path.join(this.projectBackupDir, sessionFolder); const stats = fs.statSync(sessionPath); // ถ้าเป็นโฟลเดอร์และเก่าเกินกำหนด if (stats.isDirectory() && stats.mtime.getTime() < cutoffTime) { // ลบทั้งโฟลเดอร์ fs.rmSync(sessionPath, { recursive: true, force: true }); cleanedCount++; logger.audit('BACKUP_SESSION_CLEANED', sessionPath, { sessionFolder: sessionFolder, age: maxAge }); } }); if (cleanedCount > 0) { logger.info('BACKUP', `Cleaned up ${cleanedCount} old backup sessions`); } } catch (error) { logger.error('BACKUP', 'Failed to cleanup old backups', error); } } } // ====================================================================== // File Comparison & Analysis System - ระบบเปรียบเทียบและวิเคราะห์ไฟล์ // ====================================================================== class FileComparisonAnalyzer { constructor() { this.comparisonResults = []; } // เปรียบเทียบไฟล์ก่อนและหลัง แล้วสร้าง detailed report compareAndAnalyze(originalContent, modifiedContent, filePath) { try { const comparisonId = Date.now(); logger.debug('FILE_COMPARISON', `Starting comparison analysis for: ${filePath}`, { comparisonId }); // วิเคราะห์ไฟล์ก่อน (Original) const originalAnalysis = this.analyzeFileStructures(originalContent, 'ORIGINAL'); logger.debug('FILE_ANALYSIS', `Original file analysis completed`, { filePath, structures: originalAnalysis.summary }); // วิเคราะห์ไฟล์หลัง (Modified) const modifiedAnalysis = this.analyzeFileStructures(modifiedContent, 'MODIFIED'); logger.debug('FILE_ANALYSIS', `Modified file analysis completed`, { filePath, structures: modifiedAnalysis.summary }); // เปรียบเทียบและสร้าง report const comparisonReport = this.generateComparisonReport( originalAnalysis, modifiedAnalysis, filePath ); // บันทึก detailed report ลง audit log this.logDetailedReport(comparisonReport, filePath); // บันทึก error และ skip report this.logErrorAndSkipReport(comparisonReport, filePath); this.comparisonResults.push(comparisonReport); return comparisonReport; } catch (error) { logger.error('FILE_COMPARISON', `Failed to compare files: ${filePath}`, error); return null; } } // วิเคราะห์โครงสร้างไฟล์โดยใช้ระบบที่มีอยู่ analyzeFileStructures(content, type) { try { // ใช้ SmartFileAnalyzer ที่มีอยู่แล้ว const analyzer = new SmartFileAnalyzer(content, { maxDepth: 50, maxTokens: 100000, maxParsingTime: 15000 }); const analysis = analyzer.analyzeFile(); // นับจำนวน structures แต่ละประเภท const summary = { totalFunctions: analysis.functions ? analysis.functions.length : 0, totalClasses: analysis.classes ? analysis.classes.length : 0, totalMethods: analysis.methods ? analysis.methods.length : 0, totalVariables: analysis.variables ? analysis.variables.length : 0, totalInterfaces: 0, totalTypeAliases: 0, totalAbstractClasses: 0, totalStaticMethods: 0, totalArrowFunctions: 0 }; // นับ TypeScript structures if (analysis.interfaces) summary.totalInterfaces = analysis.interfaces.length; if (analysis.typeAliases) summary.totalTypeAliases = analysis.typeAliases.length; if (analysis.abstractClasses) summary.totalAbstractClasses = analysis.abstractClasses.length; if (analysis.staticMethods) summary.totalStaticMethods = analysis.staticMethods.length; if (analysis.arrowFunctions) summary.totalArrowFunctions = analysis.arrowFunctions.length; // ตรวจสอบ functions ที่ไม่มี comment const functionsWithoutComments = this.findFunctionsWithoutComments(content, analysis.functions || []); const classesWithoutComments = this.findClassesWithoutComments(content, analysis.classes || []); return { type, analysis, summary, functionsWithoutComments, classesWithoutComments, totalStructures: Object.values(summary).reduce((a, b) => a + b, 0) }; } catch (error) { logger.error('STRUCTURE_ANALYSIS', `Failed to analyze ${type} content`, error); return { type, error: error.message, summary: {}, totalStructures: 0 }; } } // หา functions ที่ไม่มี comment findFunctionsWithoutComments(content, functions) { const withoutComments = []; const lines = content.split('\n'); functions.forEach(func => { const funcLine = func.line - 1; // 0-based index // Smart Function Detection - กรองตัวแปรและ patterns พิเศษออก if (this.isLikelyVariable(func.name, content, funcLine)) { return; // ข้ามตัวแปรที่ถูก misidentify เป็น function } // กรอง React Components ที่เป็น const assignments ออก if (this.isReactComponent(func.name, content, funcLine)) { return; // ข้าม React Components - อันนี้ควรเป็น component จริงๆ } let hasComment = false; // ตรวจสอบ 3 บรรทัดก่อนหน้า for (let i = 1; i <= 3; i++) { const checkLine = funcLine - i; if (checkLine >= 0 && lines[checkLine]) { const line = lines[checkLine].trim(); if (line.startsWith('//') || line.startsWith('/*') || line.startsWith('*')) { hasComment = true; break; } } } if (!hasComment) { withoutComments.push({ name: func.name, line: func.line, type: func.type || 'function' }); } }); return withoutComments; } // หา classes ที่ไม่มี comment (พร้อม Smart Detection) findClassesWithoutComments(content, classes) { const withoutComments = []; const lines = content.split('\n'); classes.forEach(cls => { const classLine = cls.line - 1; // 0-based index // Smart Class Detection - กรองตัวแปรออก if (this.isLikelyVariable(cls.name, content, classLine)) { return; // ข้ามตัวแปรที่ถูก misidentify } // กรอง React Components ที่เป็น const assignments ออก if (this.isReactComponent(cls.name, content, classLine)) { return; // ข้าม React Components ที่ควรเป็น functions } let hasComment = false; // ตรวจสอบ 3 บรรทัดก่อนหน้า for (let i = 1; i <= 3; i++) { const checkLine = classLine - i; if (checkLine >= 0 && lines[checkLine]) { const line = lines[checkLine].trim(); if (line.startsWith('//') || line.startsWith('/*') || line.startsWith('*')) { hasComment = true; break; } } } if (!hasComment) { withoutComments.push({ name: cls.name, line: cls.line, type: cls.type || 'class' }); } }); return withoutComments; } // Smart Detection - ตรวจสอบว่าชื่อนั้นเป็นตัวแปรหรือไม่ isLikelyVariable(name, content, lineIndex) { const lines = content.split('\n'); if (lineIndex < 0 || lineIndex >= lines.length) return false; const currentLine = lines[lineIndex].trim(); const lowerName = name.toLowerCase(); // Escape ตัวอักษรพิเศษใน name ก่อนใช้ใน RegExp const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // ตรวจสอบ patterns ที่เป็นตัวแปร const variablePatterns = [ // Variable declarations new RegExp(`\\b(const|let|var)\\s+${escapedName}\\s*=`), new RegExp(`\\b${escapedName}\\s*=\\s*`), // Function parameters new RegExp(`function\\s*\\([^)]*\\b${escapedName}\\b[^)]*\\)`), new RegExp(`\\([^)]*\\b${escapedName}\\b[^)]*\\)\\s*=>`), // Destructuring new RegExp(`{[^}]*\\b${escapedName}\\b[^}]*}`), new RegExp(`\\[[^\\]]*\\b${escapedName}\\b[^\\]]*\\]`), // Loop variables new RegExp(`for\\s*\\([^;]*\\b${escapedName}\\b`), // React Context patterns new RegExp(`\\b${escapedName}\\s*=\\s*createContext`), new RegExp(`\\bconst\\s+${escapedName}\\s*=\\s*createContext`), // React Hook patterns new RegExp(`\\b${escapedName}\\s*=\\s*use[A-Z]`), new RegExp(`\\bconst\\s+\\[.*${escapedName}.*\\]\\s*=\\s*useState`), // Arrow function assignments new RegExp(`\\bconst\\s+${escapedName}\\s*=\\s*\\(`), new RegExp(`\\bconst\\s+${escapedName}\\s*=\\s*\\w+\\s*=>`), ]; // ตรวจสอบบรรทัดปัจจุบันและใกล้เคียง (เพิ่มช่วงการตรวจสอบ) for (let i = Math.max(0, lineIndex - 3); i <= Math.min(lines.length - 1, lineIndex + 3); i++) { const line = lines[i]; if (variablePatterns.some(pattern => pattern.test(line))) { return true; } } // ตรวจสอบ common variable names const commonVariableNames = [ 'result', 'data', 'item', 'value', 'temp', 'node', 'element', 'current', 'next', 'prev', 'parent', 'child', 'left', 'right', 'count', 'index', 'length', 'size', 'max', 'min', 'sum', 'start', 'end', 'pos', 'queue', 'stack', 'list', 'array', 'map', 'set', 'key', 'val', 'obj', 'target', 'source', 'input', 'output', 'buffer', 'cache', 'config', 'options', // Algorithm-specific variables 'dp', 'memo', 'visited', 'distances', 'graph', 'matrix', 'heap', 'buckets', 'intervals', 'points', 'edges', 'vertices', // React-specific variable names 'user', 'users', 'state', 'props', 'context', 'ref', 'refs', 'handler', 'handlers', 'callback', 'callbacks', 'event', 'events', 'timeout', 'interval', 'timer', 'loading', 'error', 'success' ]; if (commonVariableNames.includes(lowerName)) { return true; } // ตรวจสอบ React Context patterns (ขึ้นต้นด้วยตัวพิมพ์ใหญ่ แต่ลงท้ายด้วย Context) if (name.endsWith('Context') && /^[A-Z][a-zA-Z]*Context$/.test(name)) { return true; } // ตรวจสอบ React Component patterns ที่เป็น const assignment if (/^[A-Z][a-zA-Z0-9]*$/.test(name)) { // ตรวจสอบว่าเป็น const component assignment หรือไม่ const componentPattern = new RegExp(`const\\s+${name}\\s*=`); for (let i = Math.max(0, lineIndex - 2); i <= Math.min(lines.length - 1, lineIndex + 2); i++) { if (componentPattern.test(lines[i])) { return true; } } } // ตรวจสอบ short variable names (มักเป็น loop counters) if (name.length <= 2 && /^[a-zA-Z][0-9]?$/.test(name)) { return true; } // ตรวจสอบ camelCase variables (ขึ้นต้นด้วยตัวพิมพ์เล็ก) if (/^[a-z][a-zA-Z0-9]*$/.test(name)) { return true; } return false; } // ตรวจสอบว่าเป็น React Component หรือไม่ isReactComponent(name, content, lineIndex) { const lines = content.split('\n'); if (lineIndex < 0 || lineIndex >= lines.length) return false; // React Component ต้องขึ้นต้นด้วยตัวพิมพ์ใหญ่ if (!/^[A-Z][a-zA-Z0-9]*$/.test(name)) return false; // ตรวจสอบ patterns ของ React Components const reactComponentPatterns = [ // const Component = () => {} new RegExp(`const\\s+${name}\\s*=\\s*\\([^)]*\\)\\s*=>`), // const Component = function() {} new RegExp(`const\\s+${name}\\s*=\\s*function`), // const Component = React.memo() new RegExp(`const\\s+${name}\\s*=\\s*React\\.memo`), // const Component = forwardRef() new RegExp(`const\\s+${name}\\s*=\\s*forwardRef`), // export const Component = new RegExp(`export\\s+const\\s+${name}\\s*=`), ]; // ตรวจสอบบรรทัดใกล้เคียง for (let i = Math.max(0, lineIndex - 2); i <= Math.min(lines.length - 1, lineIndex + 2); i++) { const line = lines[i]; if (reactComponentPatterns.some(pattern => pattern.test(line))) { return true; } } // ตรวจสอบ JSX return patterns const jsxPatterns = [ /return\s*\(/, /return\s*</, />\s*$/, /<\/[a-zA-Z]/ ]; // ตรวจสอบใน function body ว่ามี JSX หรือไม่ for (let i = lineIndex; i < Math.min(lines.length, lineIndex + 20); i++) { const line = lines[i].trim(); if (jsxPatterns.some(pattern => pattern.test(line))) { return true; } // หยุดตรวจสอบถ้าเจอปิด function if (line.includes('}') && !line.includes('{')) { break; } } return false; } // สร้าง comparison report generateComparisonReport(originalAnalysis, modifiedAnalysis, filePath) { const report = { filePath, timestamp: new Date().toISOString(), original: originalAnalysis, modified: modifiedAnalysis, changes: { functionsAdded: modifiedAnalysis.summary.totalFunctions - originalAnalysis.summary.totalFunctions, classesAdded: modifiedAnalysis.summary.totalClasses - originalAnalysis.summary.totalClasses, commentsAdded: 0, // จะคำนวณจากการเปรียบเทียบ structuresSkipped: (modifiedAnalysis.functionsWithoutComments?.length || 0) + (modifiedAnalysis.classesWithoutComments?.length || 0), errors: [] }, skippedStructures: { functions: modifiedAnalysis.functionsWithoutComments || [], classes: modifiedAnalysis.classesWithoutComments || [] } }; // คำนวณจำนวน comments ที่เพิ่ม report.changes.commentsAdded = this.calculateCommentsAdded(originalAnalysis, modifiedAnalysis); return report; } // คำนวณจำนวน comments ที่เพิ่มขึ้น calculateCommentsAdded(original, modified) { const originalCommentLines = this.countCommentLines(original.analysis?.content || ''); const modifiedCommentLines = this.countCommentLines(modified.analysis?.content || ''); return Math.max(0, modifiedCommentLines - originalCommentLines); } // นับจำนวนบรรทัดที่มี comment countCommentLines(content) { const lines = content.split('\n'); return lines.filter(line => { const trimmed = line.trim(); return trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*'); }).length; } // บันทึก detailed report ลง audit log logDetailedReport(report, filePath) { logger.audit('FILE_COMPARISON_REPORT', filePath, { summary: { totalStructuresOriginal: report.original.totalStructures, totalStructuresModified: report.modified.totalStructures, functionsAdded: report.changes.functionsAdded, classesAdded: report.changes.classesAdded, commentsAdded: report.changes.commentsAdded, structuresSkipped: report.changes.structuresSkipped }, originalStructures: report.original.summary, modifiedStructures: report.modified.summary }); } // บันทึก error และ skip report แยกต่างหาก พร้อมวิเคราะห์ละเอียดและแนะนำวิธีแก้ไข logErrorAndSkipReport(report, filePath) { if (report.changes.structuresSkipped > 0) { // วิเคราะห์รูปแบบที่ skip const analysisResult = this.analyzeSkippedPatterns(report, filePath); logger.error('STRUCTURES_SKIPPED', `${report.changes.structuresSkipped} structures were skipped in ${filePath}`, null, { skippedFunctions: report.skippedStructures.functions.map(f => `${f.name} (line ${f.line})`), skippedClasses: report.skippedStructures.classes.map(c => `${c.name} (line ${c.line})`), totalSkipped: report.changes.structuresSkipped, reasons: 'Functions/Classes without comments detected', patternAnalysis: analysisResult.patterns, suggestedSolutions: analysisResult.solutions, codeExamples: analysisResult.examples } ); // สร้าง detailed diagnostic report this.generateDetailedDiagnosticReport(report, filePath, analysisResult); } // สร้าง summary report logger.performance('FILE_PROCESSING_SUMMARY', 0, { filePath, success: true, totalStructures: report.modified.totalStructures, commentsAdded: report.changes.commentsAdded, functionsSkipped: report.skippedStructures.functions.length, classesSkipped: report.skippedStructures.classes.length, errorCount: report.changes.errors.length }); } // วิเคราะห์รูปแบบของ structures ที่ถูก skip analyzeSkippedPatterns(report, filePath) { const analysis = { patterns: { variableDeclarations: 0, shortVariableNames: 0, nestedStructures: 0, generatedCode: 0, utilityVariables: 0 }, solutions: [], examples: [] }; // วิเคราะห์ functions ที่ skip report.skippedStructures.functions.forEach(func => { if (func.name.length <= 2) { analysis.patterns.shortVariableNames++; analysis.solutions.push(`Short variable name detected: "${func.name}" - Consider using descriptive names`); } if (['i', 'j', 'k', 'x', 'y', 'z', 'n', 'm'].includes(func.name)) { analysis.patterns.utilityVariables++; analysis.solutions.push(`Loop/utility variable detected: "${func.name}" - This is likely a loop counter or temporary variable`); } }); // วิเคราะห์ classes ที่ skip report.skippedStructures.classes.forEach(cls => { if (cls.name.length <= 2) { analysis.patterns.shortVariableNames++; analysis.solutions.push(`Short variable name detected: "${cls.name}" - This appears to be a variable, not a class`); } if (['temp', 'result', 'data', 'item', 'node', 'value'].includes(cls.name.toLowerCase())) { analysis.patterns.variableDeclarations++; analysis.solutions.push(`Variable declaration detected: "${cls.name}" - This is likely a variable assignment`); } if (cls.name.match(/^[a-z][a-zA-Z]*$/)) { analysis.patterns.variableDeclarations++; analysis.solutions.push(`Camel case variable detected: "${cls.name}" - This follows variable naming convention`); } }); // สร้าง code examples สำหรับการแก้ไข if (analysis.patterns.variableDeclarations > 0) { analysis.examples.push({ type: 'Variable Declaration Fix', problem: 'const result = someFunction();', solution: '// Calculate processing result\nconst result = someFunction();' }); } if (analysis.patterns.shortVariableNames > 0) { analysis.examples.push({ type: 'Short Variable Name Fix', problem: 'let i = 0;', solution: '// Loop counter for iteration\nlet i = 0;' }); } return analysis; } // สร้าง detailed diagnostic report generateDetailedDiagnosticReport(report, filePath, analysisResult) { const diagnosticData = { filePath: filePath, timestamp: new Date().toISOString(), issuesSummary: { totalIssues: report.changes.structuresSkipped, functionIssues: report.skippedStructures.functions.length, classIssues: report.skippedStructures.classes.length, mainCauses: this.identifyMainCauses(analysisResult.patterns, report) }, detailedAnalysis: { likelyVariableDeclarations: analysisResult.patterns.variableDeclarations, shortVariableNames: analysisResult.patterns.shortVariableNames, utilityVariables: analysisResult.patterns.utilityVariables, suggestedFixes: analysisResult.solutions.length }, actionableRecommendations: this.generateActionableRecommendations(report, analysisResult), codeImprovementSuggestions: analysisResult.examples }; logger.diagnostic('STRUCTURE_ANALYSIS', `Detailed diagnostic for ${path.basename(filePath)}`, diagnosticData); } // ระบุสาเหตุหลักของปัญหา identifyMainCauses(patterns, report) { const causes = []; if (patterns.variableDeclarations > 0) { causes.push('Variable declarations misidentified as classes'); } if (patterns.shortVariableNames > 0) { causes.push('Short variable names detected'); } if (patterns.utilityVariables > 0) { causes.push('Loop counters and utility variables present'); } // เพิ่ม Advanced Pattern Analysis const advancedPatterns = this.analyzeAdvancedPatterns(report.skippedStructures); if (advancedPatterns.typeScriptPatterns > 0) { causes.push('TypeScript advanced constructs (interfaces, types, generics)'); } if (advancedPatterns.reactPatterns > 0) { causes.push('React patterns (hooks, components, context)'); } if (advancedPatterns.modernJsPatterns > 0) { causes.push('Modern JavaScript patterns (destructuring, async/await)'); } if (advancedPatterns.classMethodPatterns > 0) { causes.push('Advanced class methods and decorators'); } return causes.length > 0 ? causes : ['Unknown pattern - requires manual review']; } // วิเคราะห์ Advanced Patterns ที่ Parser ยังไม่รู้จัก analyzeAdvancedPatterns(skippedStructures) { const patterns = { typeScriptPatterns: 0, reactPatterns: 0, modernJsPatterns: 0, classMethodPatterns: 0, algorithmPatterns: 0 }; const allStructures = [ ...(skippedStructures.functions || []), ...(skippedStructures.classes || []) ]; allStructures.forEach(structure => { const name = structure.name; const lowerName = name.toLowerCase(); // TypeScript Patterns if (this.isTypeScriptPattern(name)) { patterns.typeScriptPatterns++; } // React Patterns if (this.isReactPattern(name)) { patterns.reactPatterns++; } // Modern JavaScript Patterns if (this.isModernJsPattern(name)) { patterns.modernJsPatterns++; } // Class Method Patterns if (this.isClassMethodPattern(name)) { patterns.classMethodPatterns++; } // Algorithm Patterns if (this.isAlgorithmPattern(name)) { patterns.algorithmPatterns++; } }); return patterns; } // ตรวจสอบ TypeScript Patterns isTypeScriptPattern(name) { const tsPatterns = [ /^[A-Z][a-zA-Z]*Options$/, // ConnectionOptions, QueryOptions /^[A-Z][a-zA-Z]*Config$/, // DatabaseConfig, ApiConfig /^[A-Z][a-zA-Z]*Handler$/, // EventHandler, ErrorHandler /^[A-Z][a-zA-Z]*Listener$/, // EventListener, ChangeListener /^[A-Z][a-zA-Z]*Result$/, // QueryResult, ValidationResult /^[A-Z][a-zA-Z]*Error$/, // ValidationError, ConnectionError /^[A-Z][a-zA-Z]*Stats$/, // ConnectionStats, PerformanceStats /^[A-Z][a-zA-Z]*Schema$/, // ValidationSchema, DatabaseSchema /^I[A-Z][a-zA-Z]*$/, // Interface naming (IUser, IDatabase) /^T[A-Z][a-zA-Z]*$/, // Type parameter naming ]; return tsPatterns.some(pattern => pattern.test(name)); } // ตรวจสอบ React Patterns isReactPattern(name) { const reactPatterns = [ /^use[A-Z][a-zA-Z]*$/, // Custom hooks (useApi, useLocalStorage) /^[A-Z][a-zA-Z]*Context$/, // React Context (ThemeContext, UserContext) /^[A-Z][a-zA-Z]*Provider$/, // Context Provider (NotificationProvider) /^handle[A-Z][a-zA-Z]*$/, // Event handlers (handleClick, handleSubmit) /^on[A-Z][a-zA-Z]*$/, // Event callbacks (onClick, onSubmit) /^render[A-Z][a-zA-Z]*$/, // Render methods (renderItem, renderField) /^[a-z]+Ref$/, // React refs (inputRef, containerRef) /^[A-Z][a-zA-Z]*Table$/, // React Table components (DataTable, UserTable) /^[A-Z][a-zA-Z]*Form$/, // React Form components (LoginForm, ContactForm) /^[A-Z][a-zA-Z]*Modal$/, // React Modal components (ConfirmModal, EditModal) /^[A-Z][a-zA-Z]*Button$/, // React Button components (SubmitButton, CancelButton) /^[A-Z][a-zA-Z]*Input$/, // React Input components (TextInput, DateInput) /^[A-Z][a-zA-Z]*List$/, // React List components (ItemList, UserList) /^[A-Z][a-zA-Z]*Card$/, // React Card components (ProfileCard, NewsCard) /^[A-Z][a-zA-Z]*Builder$/, // React Builder components (FormBuilder, LayoutBuilder) /^[A-Z][a-zA-Z]*Dashboard$/, // React Dashboard components /^[A-Z][a-zA-Z]*Panel$/, // React Panel components /^[A-Z][a-zA-Z]*Widget$/, // React Widget components ]; return reactPatterns.some(pattern => pattern.test(name)); } // ตรวจสอบ Modern JavaScript Patterns isModernJsPattern(name) { const modernPatterns = [ /^[a-z]+Async$/, // Async functions (fetchAsync, loadAsync) /^[a-z]+Promise$/, // Promise-based functions /^[a-z]+Generator$/, // Generator functions /^[a-z]+Iterator$/, // Iterator functions /^create[A-Z][a-zA-Z]*$/, // Factory functions (createConnection, createUser) /^build[A-Z][a-zA-Z]*$/, // Builder functions /^process[A-Z][a-zA-Z]*$/, // Processing functions ]; return modernPatterns.some(pattern => pattern.test(name)); } // ตรวจสอบ Class Method Patterns isClassMethodPattern(name) { const classPatterns = [ /^[a-z]+Connection$/, // Database connections /^[a-z]+Manager$/, // Manager classes /^[a-z]+Builder$/, // Builder classes /^[a-z]+Factory$/, // Factory classes /^[a-z]+Repository$/, // Repository pattern /^[a-z]+Service$/, // Service classes /^[a-z]+Controller$/, // Controller classes ]; return classPatterns.some(pattern => pattern.test(name)); } // ตรวจสอบ Algorithm Patterns isAlgorithmPattern(name) { const algoPatterns = [ /^[a-z]{1,3}$/, // Short algorithm variables (dp, bfs, dfs) /^[a-z]+Tree$/, // Tree structures /^[a-z]+Node$/, // Node structures /^[a-z]+Graph$/, // Graph structures /^[a-z]+Queue$/, // Queue structures /^[a-z]+Stack$/, // Stack structures ]; return algoPatterns.some(pattern => pattern.test(name)); } // สร้างคำแนะนำที่สามารถทำได้จริง generateActionableRecommendations(report, analysisResult) { const recommendations = []; if (analysisResult.patterns.variableDeclarations > 5) { recommendations.push({ priority: 'HIGH', action: 'Review variable declarations', description: 'Many variables were misidentified as classes. Consider adding comments above variable declarations.', example: '// Store calculation result\nconst result = calculate();' }); } if (analysisResult.patterns.shortVariableNames > 3) { recommendations.push({ priority: 'MEDIUM', action: 'Use descriptive variable names', description: 'Short variable names (i, j, x, y) are common and may not need comments.', example: 'for (let index = 0; index < items.length; index++)' }); } if (report.changes.structuresSkipped > 20) { recommendations.push({ priority: 'LOW', action: 'Consider code refactoring', description: 'High number of skipped structures suggests complex code that may benefit from refactoring.', example: 'Break down large functions into smaller, well-documented functions' }); } // Advanced Pattern Recommendations const advancedPatterns = this.analyzeAdvancedPatterns(report.skippedStructures); if (advancedPatterns.typeScriptPatterns > 0) { recommendations.push({ priority: 'HIGH', action: 'Add TypeScript interface/type documentation', description: 'TypeScript constructs detected. These need proper documentation for better code understanding.', example: '// Interface defining database connection options\ninterface ConnectionOptions { ... }' }); } if (advancedPatterns.reactPatterns > 0) { recommendations.push({ priority: 'HIGH', action: 'Document React components and hooks', description: 'React patterns detected. Components and custom hooks should have clear documentation.', example: '// Custom hook for managing API calls with loading state\nconst useApi = () => { ... }' }); } if (advancedPatterns.modernJsPatterns > 0) { recommendations.push({ priority: 'MEDIUM', action: 'Document async/await and modern patterns', description: 'Modern JavaScript patterns detected. Async operations need clear documentation.', example: '// Asynchronously processes user data with error handling\nasync function processUserData() { ... }' }); } if (advancedPatterns.classMethodPatterns > 0) { recommendations.push({ priority: 'MEDIUM', action: 'Add class method documentation', description: 'Advanced class methods detected. Repository/Service patterns need clear documentation.', example: '// Repository class for managing user database operations\nclass UserRepository { ... }' }); } return recommendations; } } // สร้าง file comparison analyzer instance const fileComparisonAnalyzer = new FileComparisonAnalyzer(); // สร้าง backup manager instance const backupManager = new OrganizedBackupManager(); // ====================================================================== // Helper Functions - ฟังก์ชันช่วยเหลือสำหรับการประมวลผล // ====================================================================== // ฟังก์ชันคำนวณหมายเลขบรรทัดที่จัดการ line endings ได้ถูกต้อง // @param {string} content - เนื้อหาของไฟล์ // @param {number} index - ตำแหน่งที่ต้องการหาหมายเลขบรรทัด // @returns {number} หมายเลขบรรทัด (เริ่มต้นที่ 1) function calculateLineNumber(content, index) { const normalizedContent = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); return normalizedContent.substring(0, index).split('\n').length; } // ฟังก์ชันสำหรับ normalize line endings // @param {string} content - เนื้อหาของไฟล์ // @returns {string} เนื้อหาที่ normalize แล้ว function normalizeLineEndings(content) { return content.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); } // ฟังก์ชันตรวจสอบว่าแต่ละ structure มี comment เฉพาะตัวหรือไม่ // @param {string} content - เนื้อหาของไฟล์ // @param {Array} structures - รายการ structures ที่ตรวจพบ // @returns {Map} Map ที่เก็บข้อมูล comment status ของแต่ละ structure function analyzeCommentStatus(content, structures) { const commentStatusMap = new Map(); const normalizedContent = normalizeLineEndings(content); const lines = normalizedContent.split('\n'); structures.forEach(structure => { const structureLine = structure.line - 1; // แปลงเป็น 0-based index let hasComment = false; let commentLines = []; // ตรวจสอบ 3-5 บรรทัดก่อนหน้าเฉพาะ structure นี้ for (let i = 1; i <= 5; i++) { const checkIndex = structureLine - i; if (checkIndex >= 0 && checkIndex < lines.length) { const line = lines[checkIndex]; const trimmed = line.trim(); // เจอ comment line if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.includes('*/')) { const commentContent = trimmed.toLowerCase(); const structureName = structure.name.toLowerCase(); // ตรวจสอบว่า comment นี้เกี่ยวข้องกับ structure นี้หรือไม่ // หลัก: ชื่อ structure ต้องตรงกัน หรือ comment ต้องเฉพาะเจาะจง if (commentContent.includes(structureName) || (commentContent.includes('en:') && (commentContent.includes(structureName) || (commentContent.includes('interface') && structure.type === 'interface_declaration') || (commentContent.includes('type') && structure.type === 'type_alias' && commentContent.includes('alias')) || (commentContent.includes('static') && structure.type === 'static_method') || (commentContent.includes('abstract') && structure.type === 'abstract_class'))) || (commentContent.includes('th:') && (commentContent.includes(structureName) || (commentContent.includes('interface') && structure.type === 'interface_declaration') || (commentContent.includes('type') && structure.type === 'type_alias' && commentContent.includes('alias')) || (commentContent.includes('static') && structure.type === 'static_method') || (commentContent.includes('abstract') && structure.type === 'abstract_class'))) || commentContent.includes('======')) { hasComment = true; commentLines.push(checkIndex + 1); // แปลงกลับเป็น 1-based break; } } // เจอ code line อื่นที่ไม่เกี่ยวข้อง ให้หยุดค้นหา else if (trimmed && !trimmed.startsWith('export') && !trimmed.startsWith('@') && !trimmed.startsWith('{') && !trimmed.startsWith('}')) { break; } } } commentStatusMap.set(structure.name, { hasComment, commentLines, structure: structure }); }); return commentStatusMap; } // ====================================================================== // JavaScript Tokenizer Engine/เครื่องมือ Tokenizer ของ JavaScript // ====================================================================== // Token types:ประเภทของโทเค็น const TOKEN_TYPES = { // คำหลัก - Keywords KEYWORD: 'KEYWORD', // ชื่อตัวแปร/ฟังก์ชัน - Identifiers IDENTIFIER: 'IDENTIFIER', // เครื่องหมาย - Operators and punctuation EQUALS: 'EQUALS', // = ARROW: 'ARROW', // => PAREN_OPEN: 'PAREN_OPEN', // ( PAREN_CLOSE: 'PAREN_CLOSE', // ) BRACE_OPEN: 'BRACE_OPEN', // { BRACE_CLOSE: 'BRACE_CLOSE', // } BRACKET_OPEN: 'BRACKET_OPEN', // [ BRACKET_CLOSE: 'BRACKET_CLOSE', // ] SEMICOLON: 'SEMICOLON', // ; COMMA: 'COMMA', // , // คอมเมนต์ - Comments LINE_COMMENT: 'LINE_COMMENT', // // BLOCK_COMMENT: 'BLOCK_COMMENT', // /* */ // สตริง - Strings STRING: 'STRING', // ตัวเลข - Numbers NUMBER: 'NUMBER', // ช่องว่าง - Whitespace WHITESPACE: 'WHITESPACE', NEWLINE: 'NEWLINE', // จุดสิ้นสุด - End of file EOF: 'EOF' }; // คำหลักของ JavaScript, TypeScript, JSX, TSX ครบถ้วน - Complete keywords for JS/TS/JSX/TSX const KEYWORDS = new Set([ // ═══════════════════════════════════════════════════════════════ // JavaScript Core Keywords // ═══════════════════════════════════════════════════════════════ 'function', 'const', 'let', 'var', 'async', 'await', 'class', 'constructor', 'static', 'get', 'set', 'abstract', 'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'return', 'break', 'continue', 'throw', 'try', 'catch', 'import', 'export', 'default', 'from', 'as', 'finally', 'with', 'delete', 'new', 'this', 'super', 'instanceof', 'of', 'in', 'null', 'undefined', 'true', 'false', 'yield', 'debugger', 'arguments', 'eval', // ═══════════════════════════════════════════════════════════════ // TypeScript Specific Keywords // ═══════════════════════════════════════════════════════════════ 'interface', 'type', 'enum', 'namespace', 'module', 'declare', 'readonly', 'public', 'private', 'protected', 'implements', 'extends', 'keyof', 'typeof', 'infer', 'never', 'unknown', 'any', 'void', 'string', 'number', 'boolean', 'object', 'symbol', 'bigint', 'unique', 'is', 'asserts', 'override', 'satisfies', 'out', 'in', 'const', // ═══════════════════════════════════════════════════════════════ // Advanced TypeScript Utility Types & Keywords // ═══════════════════════════════════════════════════════════════ 'Partial', 'Required', 'Pick', 'Omit', 'Exclude', 'Extract', 'NonNullable', 'Parameters', 'ReturnType', 'InstanceType', 'ThisType', 'Record', 'Readonly', 'Array', 'Promise', 'Awaited', 'ConstructorParameters', 'ThisParameterType', 'OmitThisParameter', 'Uppercase', 'Lowercase', 'Capitalize', 'Uncapitalize', // ═══════════════════════════════════════════════════════════════ // React Core Components & Hooks // ═══════════════════════════════════════════════════════════════ 'React', 'Component', 'PureComponent', 'memo', 'forwardRef', 'createContext', 'useContext', 'createRef', 'useRef', 'useState', 'useEffect', 'us