UNPKG

agentsqripts

Version:

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

238 lines (216 loc) 10.3 kB
#!/usr/bin/env node /** * @file Command-line interface for UI/UX problem analysis and usability assessment * @description Single responsibility: Provide interactive CLI for identifying user interface and experience issues * * This CLI tool serves as the UI/UX analysis interface for the AgentSqripts platform, * detecting usability problems, design inconsistencies, accessibility concerns, and * interaction pattern issues in frontend codebases. It implements category-based filtering, * effort-level prioritization, and comprehensive reporting to support UI optimization * workflows and user experience improvement initiatives. * * Design rationale: * - UX-focused analysis enables systematic user experience optimization * - Category filtering (Content, Visual Design, Forms, etc.) enables targeted improvements * - Effort-level filtering helps prioritize quick wins vs complex redesign work * - Comprehensive detection from text clarity to responsive design issues * - Human-readable output focuses on actionable UX improvements rather than technical metrics */ const fs = require('fs'); const path = require('path'); const { getProcessArgs } = require('../lib/utils/processHelpers'); const { shouldShowHelp } = require('../lib/utils/cliHelpers'); const { analyzeProjectUIProblems, analyzeFileUIProblems } = require('../lib/ui-problems/analyzeUIProblems'); const { createHelpFunction } = require('./lib/helpFormatter'); const { parseArgs: sharedParseArgs } = require('./lib/argumentParser'); const { handleAnalysisError, exitOnSeverityThreshold } = require('./lib/errorHandler'); const { formatResults } = require('./lib/commonFormatters'); const { createSummaryFormatter, createRecommendationsSection, createTopIssuesSection } = require('./lib/summaryFormatter'); const { createDetailedFormatter, formatIssueWithIcons } = require('./lib/detailedFormatter'); /** * Display help information */ const showHelp = createHelpFunction({ command: 'analyze-ui-problems.js', description: 'Analyzes UI code for user interface and user experience issues including usability problems,\ndesign inconsistencies, interaction patterns, and accessibility concerns (non-compliance focused).', options: [ { flag: '--extensions <exts>', description: 'Comma-separated list of file extensions (default: .js,.jsx,.ts,.tsx,.vue)' }, { flag: '--output-format <fmt>', description: 'Output format: json, summary, detailed (default: summary)' }, { flag: '--severity <level>', description: 'Minimum severity to report: LOW, MEDIUM, HIGH (default: LOW)' }, { flag: '--category <cat>', description: 'Filter by category: Content, "Visual Design", Feedback, Layout, Forms, Responsive (default: all)' }, { flag: '--effort <level>', description: 'Filter by effort level: 1, 2, 3 (default: all)' }, { flag: '--help', description: 'Show this help message' } ], modes: ' file Analyze a single file\n project Analyze entire project (default)', examples: [ 'node analyze-ui-problems.js .', 'node analyze-ui-problems.js --severity HIGH src/', 'node analyze-ui-problems.js --output-format json --category "Visual Design" .', 'node analyze-ui-problems.js --category Content --effort 1 components/' ], output: ' The tool identifies UI/UX problems by checking:\n - Ambiguous button and label text (clarity issues)\n - Inconsistent icon library usage (visual consistency)\n - Excessive inline styles (maintainability issues)\n - Missing loading states for async operations\n - Cluttered UI layouts (too many elements)\n - Missing error handling in UI components\n - Poor form UX patterns (labels, validation, states)\n - Responsive design issues (fixed widths, mobile unfriendly)', sections: { 'SEVERITY LEVELS': ' 🔥 HIGH: Critical usability issues that significantly impact user experience\n ⚡ MEDIUM: Moderate issues that affect consistency and maintainability\n 💡 LOW: Minor improvements for better practices', 'CATEGORIES': ' 📝 Content: Text clarity, labeling, and communication issues\n 🎨 Visual Design: Consistency, styling, and branding problems\n 🔄 Feedback: Loading states, error handling, and user communication\n 📐 Layout: Structure, spacing, and information architecture\n 📋 Forms: Form usability, validation, and interaction patterns\n 📱 Responsive: Mobile compatibility and adaptive design', 'EFFORT LEVELS': ' 1: Quick fixes (text changes, simple additions)\n 2: Moderate effort (refactoring, component changes)\n 3: Complex work (architectural changes, major redesign)', 'FIX IMPACT': ' Each issue includes specific recommendations and expected impact on user experience.' } }); // Removed duplicate formatResults - now using shared version from commonFormatters // Create custom summary formatter using shared utility const formatSummary = createSummaryFormatter({ title: '🎨 UI/UX Problem Analysis Results', scoreField: 'uiScore', gradeField: 'uiGrade', filesField: 'totalFiles', issuesField: 'totalIssues', showEffort: true, effortField: 'totalEffort', customMetrics: [ { field: 'filesWithIssues', icon: '⚠️', label: 'Files with Issues' } ], breakdowns: [ { field: 'severityBreakdown', type: 'severity', icon: '📈', title: 'Issue Breakdown' }, { field: 'categoryBreakdown', type: 'category', icon: '🏷️', title: 'Issue Categories', icons: { 'Usability': '👤', 'Visual Design': '🎨', 'Interaction': '🖱️', 'Consistency': '📐', 'Accessibility': '♿', 'Mobile Responsiveness': '📱', 'Form Issues': '📝', 'Navigation': '🧭' } } ], customSections: [ createRecommendationsSection('Top Recommendations', '💡'), createTopIssuesSection({ field: 'issues', title: 'Most Critical UI Issues', limit: 10, formatItem: (issue, i) => { const severityIcon = issue.severity === 'HIGH' ? '🔥' : issue.severity === 'MEDIUM' ? '⚡' : '💡'; const categoryIcon = issue.category === 'Content' ? '📝' : issue.category === 'Visual Design' ? '🎨' : issue.category === 'Feedback' ? '🔄' : issue.category === 'Layout' ? '📐' : issue.category === 'Forms' ? '📋' : '📱'; return ` ${i + 1}. ${severityIcon} ${categoryIcon} ${issue.summary}\n 💡 ${issue.recommendation}\n ⏱️ Effort: ${issue.effort}/3 | 🎯 Impact: ${issue.impact}`; } }) ] }); // Old formatDetailed removed - using shared detailed formatter // Replace with shared detailed formatter const formatDetailedNew = createDetailedFormatter({ title: '🔍 Detailed UI/UX Analysis', formatSummary: formatSummary, filesField: 'files', issuesField: 'issues', formatFile: (fileData) => { return `📄 ${path.relative('.', fileData.file)} (Score: ${fileData.uiScore}/100, Effort: ${fileData.metrics.totalEffort})\n`; }, formatIssue: (issue) => { const icons = { severity: { 'HIGH': '🔥', 'MEDIUM': '⚡', 'LOW': '💡' }, category: { 'Content': '📝', 'Visual Design': '🎨', 'Feedback': '🔄', 'Layout': '📐', 'Forms': '📋', 'Responsive': '📱' } }; const lines = formatIssueWithIcons(issue, icons); // Add type-specific details if (issue.examples && issue.examples.length > 0) { lines.push(` 📌 Examples: ${issue.examples.join(', ')}`); } if (issue.libraries && issue.libraries.length > 0) { lines.push(` 📚 Libraries: ${issue.libraries.join(', ')}`); } if (issue.repeatedStyles && issue.repeatedStyles.length > 0) { lines.push(' 🔁 Repeated Styles:'); issue.repeatedStyles.forEach(style => { lines.push(` - ${style.style} (${style.occurrences}x)`); }); } return lines; } }); /** * Main function */ async function main() { const args = getProcessArgs(); if (shouldShowHelp(args)) { showHelp(); return; } // Parse arguments using shared parser const { options: parsedOptions, targetPath: parsedPath, error } = sharedParseArgs(args, { defaults: { extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'], outputFormat: 'summary', severity: 'LOW', category: null, effort: null }, flags: { extensions: { type: 'list' }, outputFormat: { type: 'string' }, severity: { type: 'string', transform: (v) => v.toUpperCase() }, category: { type: 'string' }, effort: { type: 'string' } } }); if (error) { console.error(error); process.exit(1); } const { extensions, outputFormat, severity, category, effort } = parsedOptions; const targetPath = parsedPath; try { // Check if target is a file or directory const stat = await fs.promises.stat(targetPath); let results; if (stat.isFile()) { // Analyze single file results = await analyzeFileUIProblems(targetPath); } else { // Analyze project results = await analyzeProjectUIProblems(targetPath, { extensions, excludePatterns: ['node_modules', '.git', 'dist', 'build', 'coverage', 'test'] }); } // Output results const formatted = formatResults(results, outputFormat, { severity, category, effort }, formatSummary, formatDetailedNew); console.log(formatted); // Exit with error code if high-impact issues found const hasHighImpact = results.summary && results.summary.severityBreakdown ? (results.summary.severityBreakdown.HIGH || 0) > 0 : (results.issues && Array.isArray(results.issues)) ? results.issues.some(i => i.severity === 'HIGH') : false; if (hasHighImpact) { process.exit(1); } } catch (error) { handleAnalysisError(error, 'UI problems'); } } if (require.main === module) { main().catch(error => { console.error("Fatal error:", error); process.exit(1); }); }