pmtool / src /scripts /validate-accessibility.ts
devarshia5's picture
Upload 487 files
d97b8f9 verified
Raw
History Blame Contribute Delete
7.05 kB
/**
* Simple accessibility validation script for asset management components
* This script checks for common accessibility patterns in our components
*/
import fs from 'fs';
import path from 'path';
interface AccessibilityCheck {
name: string;
pattern: RegExp;
description: string;
required: boolean;
}
const accessibilityChecks: AccessibilityCheck[] = [
{
name: 'ARIA Labels',
pattern: /aria-label(ledby)?=/g,
description: 'Components should have proper ARIA labels',
required: true
},
{
name: 'Screen Reader Text',
pattern: /sr-only|screen-reader/g,
description: 'Important information should be available to screen readers',
required: true
},
{
name: 'Keyboard Navigation',
pattern: /onKeyDown|tabIndex|role="button"/g,
description: 'Interactive elements should support keyboard navigation',
required: true
},
{
name: 'Live Regions',
pattern: /aria-live|aria-atomic/g,
description: 'Dynamic content should announce changes to screen readers',
required: true
},
{
name: 'Focus Management',
pattern: /focus\(\)|useRef.*focus|Focus/g,
description: 'Components should manage focus appropriately',
required: false
},
{
name: 'Semantic HTML',
pattern: /role="(navigation|dialog|button|searchbox|tablist|tab|tabpanel)"/g,
description: 'Components should use semantic HTML and ARIA roles',
required: true
}
];
const responsiveChecks: AccessibilityCheck[] = [
{
name: 'Mobile Breakpoints',
pattern: /(sm:|md:|lg:|xl:)/g,
description: 'Components should use responsive breakpoints',
required: true
},
{
name: 'Flexible Layouts',
pattern: /(flex|grid|w-full|min-w-0)/g,
description: 'Components should use flexible layout patterns',
required: true
},
{
name: 'Touch Targets',
pattern: /(h-8|w-8|h-10|w-10|h-12|w-12|min-h-|min-w-)/g,
description: 'Interactive elements should have adequate touch target sizes',
required: true
},
{
name: 'Text Wrapping',
pattern: /(break-words|truncate|text-wrap)/g,
description: 'Text should wrap appropriately on small screens',
required: false
}
];
function analyzeFile(filePath: string): { accessibility: number; responsive: number; issues: string[] } {
const content = fs.readFileSync(filePath, 'utf-8');
const issues: string[] = [];
let accessibilityScore = 0;
let responsiveScore = 0;
console.log(`\nπŸ“ Analyzing: ${path.relative(process.cwd(), filePath)}`);
// Check accessibility patterns
console.log('\nπŸ” Accessibility Checks:');
accessibilityChecks.forEach(check => {
const matches = content.match(check.pattern);
const count = matches ? matches.length : 0;
if (count > 0) {
console.log(` βœ… ${check.name}: ${count} instances found`);
accessibilityScore += check.required ? 2 : 1;
} else {
const severity = check.required ? '❌' : '⚠️';
console.log(` ${severity} ${check.name}: Not found`);
if (check.required) {
issues.push(`Missing ${check.name}: ${check.description}`);
}
}
});
// Check responsive patterns
console.log('\nπŸ“± Responsive Design Checks:');
responsiveChecks.forEach(check => {
const matches = content.match(check.pattern);
const count = matches ? matches.length : 0;
if (count > 0) {
console.log(` βœ… ${check.name}: ${count} instances found`);
responsiveScore += check.required ? 2 : 1;
} else {
const severity = check.required ? '❌' : '⚠️';
console.log(` ${severity} ${check.name}: Not found`);
if (check.required) {
issues.push(`Missing ${check.name}: ${check.description}`);
}
}
});
return { accessibility: accessibilityScore, responsive: responsiveScore, issues };
}
function validateAccessibility() {
console.log('πŸš€ Asset Management Accessibility Validation\n');
console.log('=' .repeat(60));
const componentDir = path.join(process.cwd(), 'src/components/asset-management');
const files = [
'AssetList.tsx',
'AssetForm.tsx',
'AssetDetail.tsx',
'shared/ConfirmDialog.tsx',
'shared/Pagination.tsx'
];
let totalAccessibilityScore = 0;
let totalResponsiveScore = 0;
let totalIssues: string[] = [];
let filesAnalyzed = 0;
files.forEach(file => {
const filePath = path.join(componentDir, file);
if (fs.existsSync(filePath)) {
const result = analyzeFile(filePath);
totalAccessibilityScore += result.accessibility;
totalResponsiveScore += result.responsive;
totalIssues.push(...result.issues);
filesAnalyzed++;
} else {
console.log(`⚠️ File not found: ${file}`);
}
});
// Calculate scores
const maxAccessibilityScore = filesAnalyzed * accessibilityChecks.filter(c => c.required).length * 2;
const maxResponsiveScore = filesAnalyzed * responsiveChecks.filter(c => c.required).length * 2;
const accessibilityPercentage = Math.round((totalAccessibilityScore / maxAccessibilityScore) * 100);
const responsivePercentage = Math.round((totalResponsiveScore / maxResponsiveScore) * 100);
// Print summary
console.log('\n' + '=' .repeat(60));
console.log('πŸ“Š SUMMARY REPORT');
console.log('=' .repeat(60));
console.log(`\nπŸ“ˆ Accessibility Score: ${accessibilityPercentage}% (${totalAccessibilityScore}/${maxAccessibilityScore})`);
console.log(`πŸ“± Responsive Score: ${responsivePercentage}% (${totalResponsiveScore}/${maxResponsiveScore})`);
console.log(`πŸ“ Files Analyzed: ${filesAnalyzed}`);
console.log(`⚠️ Total Issues: ${totalIssues.length}`);
if (totalIssues.length > 0) {
console.log('\nπŸ”§ Issues to Address:');
totalIssues.forEach((issue, index) => {
console.log(` ${index + 1}. ${issue}`);
});
}
// Grade the implementation
const overallScore = (accessibilityPercentage + responsivePercentage) / 2;
let grade = 'F';
let emoji = '❌';
if (overallScore >= 90) {
grade = 'A';
emoji = 'πŸŽ‰';
} else if (overallScore >= 80) {
grade = 'B';
emoji = 'βœ…';
} else if (overallScore >= 70) {
grade = 'C';
emoji = '⚠️';
} else if (overallScore >= 60) {
grade = 'D';
emoji = 'πŸ”Ά';
}
console.log(`\n${emoji} Overall Grade: ${grade} (${Math.round(overallScore)}%)`);
if (overallScore >= 80) {
console.log('\n🎊 Great job! Your components have excellent accessibility and responsive design.');
} else if (overallScore >= 60) {
console.log('\nπŸ‘ Good progress! Consider addressing the issues above to improve accessibility.');
} else {
console.log('\nπŸ”§ More work needed. Focus on the required accessibility patterns.');
}
console.log('\n' + '=' .repeat(60));
}
// Run the validation
validateAccessibility();