/* 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('')) {
indent = Math.max(0, indent - 1);
result += '\n' + ' '.repeat(indent) + tag;
} else if (
tag.endsWith('/>') ||
['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 '
${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.nodes && violation.nodes.length > 0
? this.generateCollapsibleCode(violation.nodes, 'problem')
: ''
}
${
violation.aiExplanation
? `
AI Explanation
${this.markdownToHtml(violation.aiExplanation)}
`
: ''
}
${
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 '
${
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
? `
`
: ''
}
`
)
.join('')}
`
: `
`
}
${
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('');
}
}