UNPKG

n8n-nodes-pdf-accessibility

Version:

AI-powered PDF accessibility automation for N8N - comprehensive WCAG compliance analysis, intelligent remediation, and professional audit reporting with 5 integrated accessibility tools

249 lines (248 loc) 10.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AccessibilityToolsManager = void 0; const ImageAltTextTool_1 = require("./ImageAltTextTool"); const HeadingStructureTool_1 = require("./HeadingStructureTool"); const TableAccessibilityTool_1 = require("./TableAccessibilityTool"); const LinkTextTool_1 = require("./LinkTextTool"); const MetadataEnhancerTool_1 = require("./MetadataEnhancerTool"); class AccessibilityToolsManager { constructor() { this.tools = new Map(); this.executionLog = []; this.initializeTools(); } initializeTools() { // Initialize and register all accessibility tools this.registerTool(new ImageAltTextTool_1.ImageAltTextTool()); this.registerTool(new HeadingStructureTool_1.HeadingStructureTool()); this.registerTool(new TableAccessibilityTool_1.TableAccessibilityTool()); this.registerTool(new LinkTextTool_1.LinkTextTool()); this.registerTool(new MetadataEnhancerTool_1.MetadataEnhancerTool()); console.log(`AccessibilityToolsManager: ${this.tools.size} accessibility tools initialized and ready`); } registerTool(tool) { this.tools.set(tool.getName(), tool); } getAvailableTools() { return Array.from(this.tools.keys()); } getToolDescription(toolName) { const tool = this.tools.get(toolName); return tool ? tool.getDescription() : null; } /** * Analyze PDF and determine which tools should be executed based on content */ async analyzeAndRecommendTools(context) { const recommended = []; const reasoning = []; // Check each registered tool to see if it can process this context this.tools.forEach((tool, toolName) => { if (tool.canProcess(context)) { recommended.push(toolName); reasoning.push(`${tool.getDescription()}`); } }); // Metadata enhancement is always recommended if (!recommended.includes('metadata_enhancer')) { recommended.push('metadata_enhancer'); reasoning.push('Metadata enhancement improves document accessibility and discoverability'); } // Heading structure for documents with substantial text if (context.textContent.length > 1000 && !recommended.includes('heading_structure')) { recommended.push('heading_structure'); reasoning.push('Substantial text content benefits from heading structure optimization'); } // Determine complexity based on content and WCAG level let complexity = 'simple'; if (context.wcagLevel === 'AAA' || recommended.length > 5) { complexity = 'complex'; } else if (context.wcagLevel === 'AA' || recommended.length > 3) { complexity = 'moderate'; } return { recommendedTools: recommended, reasoning, estimatedComplexity: complexity, }; } /** * Execute specific tools in optimized order */ async executeTools(toolNames, context, llmProvider) { const results = []; const startTime = Date.now(); let totalIssues = 0; let totalFixes = 0; let overallSuccess = true; // Execute tools in optimal order const orderedTools = this.optimizeToolOrder(toolNames); for (const toolName of orderedTools) { const tool = this.tools.get(toolName); if (!tool) { results.push({ toolName, success: false, issuesFound: [], fixesApplied: [], processing_time_ms: 0, error: `Tool '${toolName}' not found`, }); overallSuccess = false; continue; } // Check if tool can process this context if (!tool.canProcess(context)) { results.push({ toolName, success: false, issuesFound: [], fixesApplied: [], processing_time_ms: 0, error: `Tool '${toolName}' cannot process this document type`, }); continue; } try { const result = await tool.execute(context, llmProvider); results.push(result); totalIssues += result.issuesFound.length; totalFixes += result.fixesApplied.length; if (!result.success) { overallSuccess = false; } } catch (error) { const errorResult = { toolName, success: false, issuesFound: [], fixesApplied: [], processing_time_ms: 0, error: error instanceof Error ? error.message : String(error), }; results.push(errorResult); overallSuccess = false; } } // Store execution log this.executionLog.push(...results); return { results, summary: { totalIssues, totalFixes, processingTime: Date.now() - startTime, success: overallSuccess, }, }; } /** * Optimize tool execution order for best results */ optimizeToolOrder(toolNames) { // Define optimal execution order const orderPriority = { 'metadata_enhancer': 1, // Core document properties 'heading_structure': 2, // Document hierarchy 'image_alttext': 3, // Content descriptions 'table_accessibility': 4, // Tabular data 'link_text': 5, // Navigation elements }; return toolNames.sort((a, b) => { const priorityA = orderPriority[a] || 999; const priorityB = orderPriority[b] || 999; return priorityA - priorityB; }); } /** * Get execution statistics */ getExecutionStats() { if (this.executionLog.length === 0) { return { totalExecutions: 0, successRate: 0, averageProcessingTime: 0, mostUsedTools: [], }; } const successful = this.executionLog.filter(result => result.success).length; const successRate = (successful / this.executionLog.length) * 100; const averageTime = this.executionLog.reduce((sum, result) => sum + result.processing_time_ms, 0) / this.executionLog.length; // Count tool usage const toolUsage = new Map(); this.executionLog.forEach(result => { const count = toolUsage.get(result.toolName) || 0; toolUsage.set(result.toolName, count + 1); }); const mostUsedTools = Array.from(toolUsage.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map(([toolName]) => toolName); return { totalExecutions: this.executionLog.length, successRate, averageProcessingTime: averageTime, mostUsedTools, }; } /** * Generate comprehensive accessibility report */ generateAccessibilityReport(results, wcagLevel) { const allIssues = results.flatMap(result => result.issuesFound); const allFixes = results.flatMap(result => result.fixesApplied); // Calculate compliance score based on issues resolved const criticalIssues = allIssues.filter(issue => issue.severity === 'critical').length; const highIssues = allIssues.filter(issue => issue.severity === 'high').length; const mediumIssues = allIssues.filter(issue => issue.severity === 'medium').length; const lowIssues = allIssues.filter(issue => issue.severity === 'low').length; const appliedFixes = allFixes.filter(fix => fix.applied).length; const totalIssues = allIssues.length; // Weighted scoring: critical = 4 points, high = 3, medium = 2, low = 1 const maxScore = (criticalIssues * 4) + (highIssues * 3) + (mediumIssues * 2) + lowIssues; const achievedScore = Math.max(0, maxScore - (criticalIssues * 4) - (highIssues * 3) - (mediumIssues * 2) - lowIssues + (appliedFixes * 2)); const complianceScore = maxScore > 0 ? Math.round((achievedScore / maxScore) * 100) : 100; const recommendations = [ `${totalIssues} accessibility issues identified across ${results.length} analysis tools`, `${appliedFixes} improvements successfully applied`, `Target WCAG ${wcagLevel} compliance level`, criticalIssues > 0 ? `${criticalIssues} critical issues require immediate attention` : null, highIssues > 0 ? `${highIssues} high-priority issues should be addressed soon` : null, ].filter(Boolean); return { summary: `Accessibility analysis complete. Compliance score: ${complianceScore}% for WCAG ${wcagLevel}`, detailedFindings: { issuesByType: this.groupIssuesByType(allIssues), fixesBySeverity: this.groupFixesBySeverity(allFixes), toolPerformance: results.map(r => ({ tool: r.toolName, success: r.success, issuesFound: r.issuesFound.length, fixesApplied: r.fixesApplied.length, processingTime: r.processing_time_ms, })), }, complianceScore, recommendations, }; } groupIssuesByType(issues) { const grouped = {}; issues.forEach(issue => { grouped[issue.type] = (grouped[issue.type] || 0) + 1; }); return grouped; } groupFixesBySeverity(fixes) { const grouped = { applied: fixes.filter(f => f.applied).length, pending: fixes.filter(f => !f.applied).length, }; return grouped; } } exports.AccessibilityToolsManager = AccessibilityToolsManager;