/* eslint-disable @typescript-eslint/no-explicit-any */ import Handlebars from 'handlebars'; import marked from 'marked'; export class HtmlGeneratorService { private static escapeHtml(text: string): string { return Handlebars.escapeExpression(text); } private static formatHtml(htmlString: string): string { if (!htmlString) return ''; const formatted = htmlString.trim(); let indent = 0; let result = ''; let i = 0; while (i < formatted.length) { const char = formatted[i]; if (char === '<') { const tagEnd = formatted.indexOf('>', i); if (tagEnd === -1) break; const tag = formatted.substring(i, tagEnd + 1); const tagName = tag.match(/<\/?(\w+)/)?.[1] || ''; if (tag.startsWith('') || ['img', 'br', 'hr', 'input', 'meta', 'link'].includes(tagName) ) { result += '\n' + ' '.repeat(indent) + tag; } else if (tag.startsWith(' ${icon} ${title}
${nodes .map( (node: any, idx: number) => `
${node.target ? `
Target: ${this.escapeHtml(node.target.join(' > '))}
` : ''}
${this.escapeHtml(this.formatHtml(node.html))}
${node.failureSummary ? `
${this.escapeHtml(node.failureSummary)}
` : ''}
` ) .join('')}
`; } static generateCrawlTableRows(pages: any[]): string { if (!pages || pages.length === 0) { return 'No pages found'; } return pages .map( (page, index) => ` ${index + 1} ${page.url} ${page.title || '-'} ${page.description || '-'} ${page.statusCode || '-'} ${new Date(page.timestamp).toLocaleString()} ` ) .join(''); } static generateViolationsSection(results: any[]): string { const allViolations: any[] = []; results.forEach((result) => { if (result.violations) { result.violations.forEach((violation: any) => { allViolations.push({ ...violation, url: result.url, }); }); } }); if (allViolations.length === 0) { return `
🎉

No violations found!

Great job! Your website passed all accessibility checks.

`; } return allViolations .map( (violation) => `

${violation.id}

${violation.description}

${violation.impact || 'unknown'} impact
${ violation.nodes && violation.nodes.length > 0 ? this.generateCollapsibleCode(violation.nodes, 'problem') : '' } ${ violation.userStory ? `
User Story
${this.escapeHtml(violation.userStory)}
` : '' } ${ violation.aiExplanation ? `
AI Explanation
${this.markdownToHtml(violation.aiExplanation)}
` : '' } ${ violation.aiRemediation ? `
Solution
${this.markdownToHtml(violation.aiRemediation)}
` : '' }
` ) .join(''); } static generateTestViolationsSection(violations: any[]): string { if (!violations || violations.length === 0) { return `
🎉

No violations found!

Great job! This page passed all accessibility checks.

`; } return violations .map( (violation) => `

${violation.id}

${violation.description}

${violation.impact || 'unknown'} impact
${ violation.nodes && violation.nodes.length > 0 ? this.generateCollapsibleCode(violation.nodes, 'problem') : '' } ${ violation.userStory ? `
User Story
${this.escapeHtml(violation.userStory)}
` : '' } ${ violation.aiExplanation ? `
AI Explanation
${this.markdownToHtml(violation.aiExplanation)}
` : '' } ${ violation.aiRemediation ? `
Solution
${this.markdownToHtml(violation.aiRemediation)}
` : '' }
` ) .join(''); } static extractScreenshotPath(screenshotUrl: string): string { if (!screenshotUrl) return ''; if ( screenshotUrl.startsWith('http://') || screenshotUrl.startsWith('https://') ) { return screenshotUrl; } if (screenshotUrl.startsWith('gs://')) { const parts = screenshotUrl.split('/'); return `/storage/screenshots/${parts[parts.length - 1]}`; } if (screenshotUrl.includes('screenshots/')) { const parts = screenshotUrl.split('screenshots/'); const fileName = parts[parts.length - 1]; if (fileName && fileName !== screenshotUrl) { return `/storage/screenshots/${fileName}`; } } if (screenshotUrl.includes('screenshots\\')) { const parts = screenshotUrl.split('screenshots\\'); const fileName = parts[parts.length - 1]; if (fileName && fileName !== screenshotUrl) { return `/storage/screenshots/${fileName}`; } } const fileName = screenshotUrl.split(/[/\\]/).pop() || screenshotUrl; if (fileName && fileName.endsWith('.png')) { return `/storage/screenshots/${fileName}`; } return `/storage/screenshots/${screenshotUrl}`; } private static generateScreenshotSection( imgPath: string, url: string ): string { return `

Screenshot

Screenshot of ${this.escapeHtml(url)}
`; } static generatePageResultsForScan(results: any[]): string { if (!results || results.length === 0) { return '
No accessibility results found
'; } return results .map((result, index) => { const imgPath = result.screenshot ? this.extractScreenshotPath(result.screenshot) : null; return `

Page ${index + 1}

${this.escapeHtml(result.url)}
Violations: ${result.violations?.length || 0}
Passed: ${result.passes?.length || 0}
${imgPath ? this.generateScreenshotSection(imgPath, result.url) : ''} ${ result.violations && result.violations.length > 0 ? `

Violations (${result.violations.length})

${result.violations .map( (violation: any) => `
${this.escapeHtml(violation.id)}

${this.escapeHtml(violation.description)}

${violation.impact || 'unknown'} impact Help: ${this.escapeHtml(violation.help)}
${ violation.nodes && violation.nodes.length > 0 ? this.generateCollapsibleCode(violation.nodes, 'problem') : '' } ${ violation.aiExplanation ? `
AI Explanation
${this.markdownToHtml(violation.aiExplanation)}
` : '' } ${ violation.aiRemediation ? `
Solution
${this.markdownToHtml(violation.aiRemediation)}
` : '' }
` ) .join('')}
` : '' } ${ result.passes && result.passes.length > 0 ? `

Passed Checks (${result.passes.length})

${result.passes .slice(0, 12) .map( (pass: any) => `
${this.escapeHtml(pass.id)}
${this.escapeHtml(pass.description || '')}
` ) .join('')} ${ result.passes.length > 12 ? `
+${result.passes.length - 12} more
` : '' }
` : '' }
`; }) .join(''); } static generatePassedChecksSection(results: any[]): string { const allPassed: any[] = []; results.forEach((result) => { if (result.passes) { result.passes.forEach((pass: any) => { allPassed.push(pass); }); } }); if (allPassed.length === 0) { return '
'; } return `
${allPassed .map( (pass) => `

${pass.id}

${pass.description}

` ) .join('')}
`; } static generateTestPassedChecksSection(passes: any[]): string { if (!passes || passes.length === 0) { return '
'; } return `
${passes .map( (pass) => `

${pass.id}

${pass.description}

` ) .join('')}
`; } static generatePageResults(results: any[]): string { if (!results || results.length === 0) { return '

No test results found

'; } return results .map( (result, index) => `
${ result.screenshot ? (() => { const imgPath = this.extractScreenshotPath(result.screenshot); return this.generateScreenshotSection(imgPath, result.url); })() : '' } ${ result.violations && result.violations.length > 0 ? `

Violations (${result.violations.length})

${result.violations .map( (violation: any) => `
${violation.id}

${violation.description}

${violation.impact || 'unknown'} impact
${ violation.nodes && violation.nodes.length > 0 ? this.generateCollapsibleCode(violation.nodes, 'problem') : '' } ${ violation.userStory ? `
User Story
${this.escapeHtml(violation.userStory)}
` : '' } ${ violation.aiExplanation ? `
AI Explanation
${this.markdownToHtml(violation.aiExplanation)}
` : '' } ${ violation.aiRemediation ? `
Solution
${this.markdownToHtml(violation.aiRemediation)}
` : '' }
` ) .join('')}
` : `

No violations found

` } ${ result.passes && result.passes.length > 0 ? `

Passed Checks (${result.passes.length})

${result.passes .slice(0, 8) .map( (pass: any) => `
${pass.id}
` ) .join('')} ${ result.passes.length > 8 ? `
+${result.passes.length - 8} more
` : '' }
` : '' }
` ) .join(''); } }