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
JavaScript
;
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;