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
JavaScript
#!/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); });
}