@dallask/a11y-mcp-srv 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +9 -0
  3. package/README.md +1311 -0
  4. package/bin/server.js +8 -0
  5. package/dist/core/accessibility-runner.d.ts +115 -0
  6. package/dist/core/accessibility-runner.d.ts.map +1 -0
  7. package/dist/core/accessibility-runner.js +419 -0
  8. package/dist/core/accessibility-runner.js.map +1 -0
  9. package/dist/core/config.d.ts +42 -0
  10. package/dist/core/config.d.ts.map +1 -0
  11. package/dist/core/config.js +159 -0
  12. package/dist/core/config.js.map +1 -0
  13. package/dist/core/error-handler.d.ts +61 -0
  14. package/dist/core/error-handler.d.ts.map +1 -0
  15. package/dist/core/error-handler.js +264 -0
  16. package/dist/core/error-handler.js.map +1 -0
  17. package/dist/core/progress-streamer.d.ts +44 -0
  18. package/dist/core/progress-streamer.d.ts.map +1 -0
  19. package/dist/core/progress-streamer.js +160 -0
  20. package/dist/core/progress-streamer.js.map +1 -0
  21. package/dist/core/result-processor.d.ts +69 -0
  22. package/dist/core/result-processor.d.ts.map +1 -0
  23. package/dist/core/result-processor.js +461 -0
  24. package/dist/core/result-processor.js.map +1 -0
  25. package/dist/core/session-manager.d.ts +73 -0
  26. package/dist/core/session-manager.d.ts.map +1 -0
  27. package/dist/core/session-manager.js +243 -0
  28. package/dist/core/session-manager.js.map +1 -0
  29. package/dist/server.d.ts +6 -0
  30. package/dist/server.d.ts.map +1 -0
  31. package/dist/server.js +1298 -0
  32. package/dist/server.js.map +1 -0
  33. package/dist/tools/aggregate.d.ts +26 -0
  34. package/dist/tools/aggregate.d.ts.map +1 -0
  35. package/dist/tools/aggregate.js +308 -0
  36. package/dist/tools/aggregate.js.map +1 -0
  37. package/dist/tools/analysis.d.ts +68 -0
  38. package/dist/tools/analysis.d.ts.map +1 -0
  39. package/dist/tools/analysis.js +1232 -0
  40. package/dist/tools/analysis.js.map +1 -0
  41. package/dist/tools/audit.d.ts +38 -0
  42. package/dist/tools/audit.d.ts.map +1 -0
  43. package/dist/tools/audit.js +422 -0
  44. package/dist/tools/audit.js.map +1 -0
  45. package/dist/tools/comparison.d.ts +27 -0
  46. package/dist/tools/comparison.d.ts.map +1 -0
  47. package/dist/tools/comparison.js +488 -0
  48. package/dist/tools/comparison.js.map +1 -0
  49. package/dist/tools/export.d.ts +43 -0
  50. package/dist/tools/export.d.ts.map +1 -0
  51. package/dist/tools/export.js +729 -0
  52. package/dist/tools/export.js.map +1 -0
  53. package/dist/tools/filter.d.ts +26 -0
  54. package/dist/tools/filter.d.ts.map +1 -0
  55. package/dist/tools/filter.js +227 -0
  56. package/dist/tools/filter.js.map +1 -0
  57. package/dist/tools/session.d.ts +26 -0
  58. package/dist/tools/session.d.ts.map +1 -0
  59. package/dist/tools/session.js +227 -0
  60. package/dist/tools/session.js.map +1 -0
  61. package/dist/tools/visualize.d.ts +26 -0
  62. package/dist/tools/visualize.d.ts.map +1 -0
  63. package/dist/tools/visualize.js +946 -0
  64. package/dist/tools/visualize.js.map +1 -0
  65. package/dist/types/index.d.ts +755 -0
  66. package/dist/types/index.d.ts.map +1 -0
  67. package/dist/types/index.js +6 -0
  68. package/dist/types/index.js.map +1 -0
  69. package/package.json +57 -0
@@ -0,0 +1,946 @@
1
+ /**
2
+ * Visualization & dashboard tools
3
+ * Implements: generate_dashboard, generate_summary_report
4
+ */
5
+ import { auditUrl } from './audit.js';
6
+ /**
7
+ * Generate ASCII bar chart
8
+ */
9
+ function generateBarChart(data, maxWidth = 50) {
10
+ const entries = Object.entries(data).sort((a, b) => b[1] - a[1]);
11
+ const maxValue = Math.max(...entries.map(([, value]) => value), 1);
12
+ const lines = [];
13
+ entries.forEach(([label, value]) => {
14
+ const barLength = Math.round((value / maxValue) * maxWidth);
15
+ const bar = '█'.repeat(barLength);
16
+ const padding = ' '.repeat(Math.max(0, maxWidth - barLength));
17
+ lines.push(`${label.padEnd(15)} │${bar}${padding} ${value}`);
18
+ });
19
+ return lines.join('\n');
20
+ }
21
+ /**
22
+ * Generate score gauge visualization
23
+ */
24
+ function generateScoreGauge(score) {
25
+ const filled = Math.round(score / 2); // Each block represents 2 points
26
+ const empty = 50 - filled;
27
+ const bar = '█'.repeat(filled) + '░'.repeat(empty);
28
+ let status;
29
+ let emoji;
30
+ if (score >= 90) {
31
+ status = 'Excellent';
32
+ emoji = '🟢';
33
+ }
34
+ else if (score >= 75) {
35
+ status = 'Good';
36
+ emoji = '🟡';
37
+ }
38
+ else if (score >= 60) {
39
+ status = 'Needs Improvement';
40
+ emoji = '🟠';
41
+ }
42
+ else {
43
+ status = 'Critical';
44
+ emoji = '🔴';
45
+ }
46
+ return `${emoji} ${score}/100 ${status}\n${bar}`;
47
+ }
48
+ /**
49
+ * Format dashboard as markdown
50
+ */
51
+ function formatDashboardAsMarkdown(results, includeCharts) {
52
+ const resultsArray = Array.isArray(results) ? results : [results];
53
+ const isMultiple = resultsArray.length > 1;
54
+ const parts = [];
55
+ // Title
56
+ if (isMultiple) {
57
+ parts.push('# Accessibility Dashboard');
58
+ parts.push(`\n**Summary of ${resultsArray.length} audit(s)**\n`);
59
+ }
60
+ else {
61
+ const url = resultsArray[0].metadata?.url || 'Unknown URL';
62
+ parts.push(`# Accessibility Dashboard`);
63
+ parts.push(`\n**URL:** ${url}\n`);
64
+ }
65
+ // Overall metrics
66
+ if (isMultiple) {
67
+ const totalIssues = resultsArray.reduce((sum, r) => sum + r.summary.totalIssues, 0);
68
+ const avgScore = resultsArray.reduce((sum, r) => sum + r.summary.score, 0) /
69
+ resultsArray.length;
70
+ const avgWCAG = {
71
+ A: resultsArray.reduce((sum, r) => sum + r.summary.wcagCompliance.A, 0) /
72
+ resultsArray.length,
73
+ AA: resultsArray.reduce((sum, r) => sum + r.summary.wcagCompliance.AA, 0) /
74
+ resultsArray.length,
75
+ AAA: resultsArray.reduce((sum, r) => sum + r.summary.wcagCompliance.AAA, 0) / resultsArray.length,
76
+ };
77
+ parts.push('## Overall Metrics\n');
78
+ parts.push(`- **Total Issues:** ${totalIssues}`);
79
+ parts.push(`- **Average Score:** ${Math.round(avgScore)}/100`);
80
+ parts.push(`- **WCAG Compliance:** A: ${Math.round(avgWCAG.A)}%, AA: ${Math.round(avgWCAG.AA)}%, AAA: ${Math.round(avgWCAG.AAA)}%`);
81
+ if (includeCharts) {
82
+ parts.push('\n### Score Distribution\n');
83
+ parts.push('```');
84
+ parts.push(generateScoreGauge(Math.round(avgScore)));
85
+ parts.push('```');
86
+ }
87
+ }
88
+ else {
89
+ const result = resultsArray[0];
90
+ parts.push('## Overall Metrics\n');
91
+ parts.push(`- **Total Issues:** ${result.summary.totalIssues}`);
92
+ parts.push(`- **Accessibility Score:** ${result.summary.score}/100`);
93
+ parts.push(`- **WCAG Compliance:** A: ${result.summary.wcagCompliance.A}%, AA: ${result.summary.wcagCompliance.AA}%, AAA: ${result.summary.wcagCompliance.AAA}%`);
94
+ if (includeCharts) {
95
+ parts.push('\n### Score Gauge\n');
96
+ parts.push('```');
97
+ parts.push(generateScoreGauge(result.summary.score));
98
+ parts.push('```');
99
+ }
100
+ }
101
+ // Impact breakdown
102
+ if (isMultiple) {
103
+ const impactCounts = {
104
+ critical: 0,
105
+ serious: 0,
106
+ moderate: 0,
107
+ minor: 0,
108
+ };
109
+ resultsArray.forEach((result) => {
110
+ Object.entries(result.summary.byImpact).forEach(([impact, count]) => {
111
+ impactCounts[impact] = (impactCounts[impact] || 0) + count;
112
+ });
113
+ });
114
+ parts.push('\n## Issues by Impact Level\n');
115
+ if (includeCharts) {
116
+ parts.push('```');
117
+ parts.push(generateBarChart(impactCounts));
118
+ parts.push('```');
119
+ }
120
+ else {
121
+ Object.entries(impactCounts)
122
+ .sort((a, b) => b[1] - a[1])
123
+ .forEach(([impact, count]) => {
124
+ parts.push(`- **${impact}:** ${count}`);
125
+ });
126
+ }
127
+ }
128
+ else {
129
+ const result = resultsArray[0];
130
+ parts.push('\n## Issues by Impact Level\n');
131
+ if (includeCharts) {
132
+ parts.push('```');
133
+ parts.push(generateBarChart(result.summary.byImpact));
134
+ parts.push('```');
135
+ }
136
+ else {
137
+ Object.entries(result.summary.byImpact)
138
+ .sort((a, b) => b[1] - a[1])
139
+ .forEach(([impact, count]) => {
140
+ parts.push(`- **${impact}:** ${count}`);
141
+ });
142
+ }
143
+ }
144
+ // Category breakdown
145
+ if (isMultiple) {
146
+ const categoryCounts = {};
147
+ resultsArray.forEach((result) => {
148
+ Object.entries(result.summary.byCategory).forEach(([cat, count]) => {
149
+ categoryCounts[cat] = (categoryCounts[cat] || 0) + count;
150
+ });
151
+ });
152
+ parts.push('\n## Issues by Category\n');
153
+ if (includeCharts) {
154
+ parts.push('```');
155
+ parts.push(generateBarChart(categoryCounts));
156
+ parts.push('```');
157
+ }
158
+ else {
159
+ Object.entries(categoryCounts)
160
+ .sort((a, b) => b[1] - a[1])
161
+ .forEach(([category, count]) => {
162
+ parts.push(`- **${category}:** ${count}`);
163
+ });
164
+ }
165
+ }
166
+ else {
167
+ const result = resultsArray[0];
168
+ parts.push('\n## Issues by Category\n');
169
+ if (includeCharts) {
170
+ parts.push('```');
171
+ parts.push(generateBarChart(result.summary.byCategory));
172
+ parts.push('```');
173
+ }
174
+ else {
175
+ Object.entries(result.summary.byCategory)
176
+ .sort((a, b) => b[1] - a[1])
177
+ .forEach(([category, count]) => {
178
+ parts.push(`- **${category}:** ${count}`);
179
+ });
180
+ }
181
+ }
182
+ // Critical blockers and quick wins
183
+ if (!isMultiple) {
184
+ const result = resultsArray[0];
185
+ if (result.criticalBlockers.length > 0) {
186
+ parts.push('\n## 🚨 Critical Blockers\n');
187
+ parts.push(`Found ${result.criticalBlockers.length} critical blocker(s) that must be fixed before launch.\n`);
188
+ result.criticalBlockers.slice(0, 5).forEach((blocker, index) => {
189
+ parts.push(`${index + 1}. **${blocker.description}** (${blocker.affectedElements} element(s))`);
190
+ });
191
+ }
192
+ if (result.quickWins.length > 0) {
193
+ parts.push('\n## ✨ Quick Wins\n');
194
+ parts.push(`Found ${result.quickWins.length} quick win(s) - easy fixes with high impact.\n`);
195
+ result.quickWins.slice(0, 5).forEach((win, index) => {
196
+ parts.push(`${index + 1}. **${win.description}** (${win.affectedElements} element(s), ${win.estimatedTime})`);
197
+ });
198
+ }
199
+ }
200
+ // Per-URL breakdown for multiple results
201
+ if (isMultiple) {
202
+ parts.push('\n## Per-URL Breakdown\n');
203
+ parts.push('| URL | Issues | Score | WCAG A | WCAG AA | WCAG AAA |');
204
+ parts.push('|-----|--------|-------|--------|---------|----------|');
205
+ resultsArray.forEach((result) => {
206
+ const url = result.metadata?.url || 'Unknown';
207
+ const shortUrl = url.length > 50 ? url.substring(0, 47) + '...' : url;
208
+ parts.push(`| ${shortUrl} | ${result.summary.totalIssues} | ${result.summary.score}/100 | ${result.summary.wcagCompliance.A}% | ${result.summary.wcagCompliance.AA}% | ${result.summary.wcagCompliance.AAA}% |`);
209
+ });
210
+ }
211
+ return parts.join('\n');
212
+ }
213
+ /**
214
+ * Format dashboard as text
215
+ */
216
+ function formatDashboardAsText(results, includeCharts) {
217
+ const resultsArray = Array.isArray(results) ? results : [results];
218
+ const isMultiple = resultsArray.length > 1;
219
+ const parts = [];
220
+ // Title
221
+ if (isMultiple) {
222
+ parts.push('ACCESSIBILITY DASHBOARD');
223
+ parts.push(`Summary of ${resultsArray.length} audit(s)\n`);
224
+ }
225
+ else {
226
+ const url = resultsArray[0].metadata?.url || 'Unknown URL';
227
+ parts.push('ACCESSIBILITY DASHBOARD');
228
+ parts.push(`URL: ${url}\n`);
229
+ }
230
+ // Overall metrics
231
+ if (isMultiple) {
232
+ const totalIssues = resultsArray.reduce((sum, r) => sum + r.summary.totalIssues, 0);
233
+ const avgScore = resultsArray.reduce((sum, r) => sum + r.summary.score, 0) /
234
+ resultsArray.length;
235
+ const avgWCAG = {
236
+ A: resultsArray.reduce((sum, r) => sum + r.summary.wcagCompliance.A, 0) /
237
+ resultsArray.length,
238
+ AA: resultsArray.reduce((sum, r) => sum + r.summary.wcagCompliance.AA, 0) /
239
+ resultsArray.length,
240
+ AAA: resultsArray.reduce((sum, r) => sum + r.summary.wcagCompliance.AAA, 0) / resultsArray.length,
241
+ };
242
+ parts.push('OVERALL METRICS');
243
+ parts.push(`Total Issues: ${totalIssues}`);
244
+ parts.push(`Average Score: ${Math.round(avgScore)}/100`);
245
+ parts.push(`WCAG Compliance: A: ${Math.round(avgWCAG.A)}%, AA: ${Math.round(avgWCAG.AA)}%, AAA: ${Math.round(avgWCAG.AAA)}%`);
246
+ if (includeCharts) {
247
+ parts.push('\nSCORE DISTRIBUTION');
248
+ parts.push(generateScoreGauge(Math.round(avgScore)));
249
+ }
250
+ }
251
+ else {
252
+ const result = resultsArray[0];
253
+ parts.push('OVERALL METRICS');
254
+ parts.push(`Total Issues: ${result.summary.totalIssues}`);
255
+ parts.push(`Accessibility Score: ${result.summary.score}/100`);
256
+ parts.push(`WCAG Compliance: A: ${result.summary.wcagCompliance.A}%, AA: ${result.summary.wcagCompliance.AA}%, AAA: ${result.summary.wcagCompliance.AAA}%`);
257
+ if (includeCharts) {
258
+ parts.push('\nSCORE GAUGE');
259
+ parts.push(generateScoreGauge(result.summary.score));
260
+ }
261
+ }
262
+ // Impact breakdown
263
+ if (isMultiple) {
264
+ const impactCounts = {
265
+ critical: 0,
266
+ serious: 0,
267
+ moderate: 0,
268
+ minor: 0,
269
+ };
270
+ resultsArray.forEach((result) => {
271
+ Object.entries(result.summary.byImpact).forEach(([impact, count]) => {
272
+ impactCounts[impact] = (impactCounts[impact] || 0) + count;
273
+ });
274
+ });
275
+ parts.push('\nISSUES BY IMPACT LEVEL');
276
+ if (includeCharts) {
277
+ parts.push(generateBarChart(impactCounts));
278
+ }
279
+ else {
280
+ Object.entries(impactCounts)
281
+ .sort((a, b) => b[1] - a[1])
282
+ .forEach(([impact, count]) => {
283
+ parts.push(`${impact}: ${count}`);
284
+ });
285
+ }
286
+ }
287
+ else {
288
+ const result = resultsArray[0];
289
+ parts.push('\nISSUES BY IMPACT LEVEL');
290
+ if (includeCharts) {
291
+ parts.push(generateBarChart(result.summary.byImpact));
292
+ }
293
+ else {
294
+ Object.entries(result.summary.byImpact)
295
+ .sort((a, b) => b[1] - a[1])
296
+ .forEach(([impact, count]) => {
297
+ parts.push(`${impact}: ${count}`);
298
+ });
299
+ }
300
+ }
301
+ // Category breakdown
302
+ if (isMultiple) {
303
+ const categoryCounts = {};
304
+ resultsArray.forEach((result) => {
305
+ Object.entries(result.summary.byCategory).forEach(([cat, count]) => {
306
+ categoryCounts[cat] = (categoryCounts[cat] || 0) + count;
307
+ });
308
+ });
309
+ parts.push('\nISSUES BY CATEGORY');
310
+ if (includeCharts) {
311
+ parts.push(generateBarChart(categoryCounts));
312
+ }
313
+ else {
314
+ Object.entries(categoryCounts)
315
+ .sort((a, b) => b[1] - a[1])
316
+ .forEach(([category, count]) => {
317
+ parts.push(`${category}: ${count}`);
318
+ });
319
+ }
320
+ }
321
+ else {
322
+ const result = resultsArray[0];
323
+ parts.push('\nISSUES BY CATEGORY');
324
+ if (includeCharts) {
325
+ parts.push(generateBarChart(result.summary.byCategory));
326
+ }
327
+ else {
328
+ Object.entries(result.summary.byCategory)
329
+ .sort((a, b) => b[1] - a[1])
330
+ .forEach(([category, count]) => {
331
+ parts.push(`${category}: ${count}`);
332
+ });
333
+ }
334
+ }
335
+ return parts.join('\n');
336
+ }
337
+ /**
338
+ * Format dashboard as HTML
339
+ */
340
+ function formatDashboardAsHTML(results, includeCharts) {
341
+ const resultsArray = Array.isArray(results) ? results : [results];
342
+ const isMultiple = resultsArray.length > 1;
343
+ const parts = [];
344
+ parts.push(`<!DOCTYPE html>
345
+ <html lang="en">
346
+ <head>
347
+ <meta charset="UTF-8">
348
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
349
+ <title>Accessibility Dashboard</title>
350
+ <style>
351
+ body {
352
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
353
+ max-width: 1200px;
354
+ margin: 0 auto;
355
+ padding: 20px;
356
+ background: #f5f5f5;
357
+ }
358
+ .dashboard {
359
+ background: white;
360
+ border-radius: 8px;
361
+ padding: 30px;
362
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
363
+ }
364
+ h1 { color: #333; border-bottom: 3px solid #4CAF50; padding-bottom: 10px; }
365
+ h2 { color: #555; margin-top: 30px; }
366
+ .metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin: 20px 0; }
367
+ .metric-card {
368
+ background: #f9f9f9;
369
+ padding: 15px;
370
+ border-radius: 6px;
371
+ border-left: 4px solid #4CAF50;
372
+ }
373
+ .metric-value { font-size: 2em; font-weight: bold; color: #333; }
374
+ .metric-label { color: #666; font-size: 0.9em; }
375
+ .chart { background: #f9f9f9; padding: 15px; border-radius: 6px; margin: 10px 0; font-family: monospace; }
376
+ table { width: 100%; border-collapse: collapse; margin: 20px 0; }
377
+ th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
378
+ th { background: #4CAF50; color: white; }
379
+ tr:hover { background: #f5f5f5; }
380
+ .critical { color: #d32f2f; font-weight: bold; }
381
+ .serious { color: #f57c00; }
382
+ .moderate { color: #fbc02d; }
383
+ .minor { color: #388e3c; }
384
+ </style>
385
+ </head>
386
+ <body>
387
+ <div class="dashboard">`);
388
+ // Title
389
+ if (isMultiple) {
390
+ parts.push(`<h1>Accessibility Dashboard</h1>`);
391
+ parts.push(`<p><strong>Summary of ${resultsArray.length} audit(s)</strong></p>`);
392
+ }
393
+ else {
394
+ const url = resultsArray[0].metadata?.url || 'Unknown URL';
395
+ parts.push(`<h1>Accessibility Dashboard</h1>`);
396
+ parts.push(`<p><strong>URL:</strong> ${escapeHtml(url)}</p>`);
397
+ }
398
+ // Overall metrics
399
+ if (isMultiple) {
400
+ const totalIssues = resultsArray.reduce((sum, r) => sum + r.summary.totalIssues, 0);
401
+ const avgScore = resultsArray.reduce((sum, r) => sum + r.summary.score, 0) /
402
+ resultsArray.length;
403
+ const avgWCAG = {
404
+ A: resultsArray.reduce((sum, r) => sum + r.summary.wcagCompliance.A, 0) /
405
+ resultsArray.length,
406
+ AA: resultsArray.reduce((sum, r) => sum + r.summary.wcagCompliance.AA, 0) /
407
+ resultsArray.length,
408
+ AAA: resultsArray.reduce((sum, r) => sum + r.summary.wcagCompliance.AAA, 0) / resultsArray.length,
409
+ };
410
+ parts.push(`<h2>Overall Metrics</h2>`);
411
+ parts.push(`<div class="metrics">`);
412
+ parts.push(`<div class="metric-card"><div class="metric-value">${totalIssues}</div><div class="metric-label">Total Issues</div></div>`);
413
+ parts.push(`<div class="metric-card"><div class="metric-value">${Math.round(avgScore)}</div><div class="metric-label">Average Score</div></div>`);
414
+ parts.push(`<div class="metric-card"><div class="metric-value">${Math.round(avgWCAG.A)}%</div><div class="metric-label">WCAG A</div></div>`);
415
+ parts.push(`<div class="metric-card"><div class="metric-value">${Math.round(avgWCAG.AA)}%</div><div class="metric-label">WCAG AA</div></div>`);
416
+ parts.push(`</div>`);
417
+ if (includeCharts) {
418
+ parts.push(`<div class="chart"><pre>${generateScoreGauge(Math.round(avgScore))}</pre></div>`);
419
+ }
420
+ }
421
+ else {
422
+ const result = resultsArray[0];
423
+ parts.push(`<h2>Overall Metrics</h2>`);
424
+ parts.push(`<div class="metrics">`);
425
+ parts.push(`<div class="metric-card"><div class="metric-value">${result.summary.totalIssues}</div><div class="metric-label">Total Issues</div></div>`);
426
+ parts.push(`<div class="metric-card"><div class="metric-value">${result.summary.score}</div><div class="metric-label">Accessibility Score</div></div>`);
427
+ parts.push(`<div class="metric-card"><div class="metric-value">${result.summary.wcagCompliance.A}%</div><div class="metric-label">WCAG A</div></div>`);
428
+ parts.push(`<div class="metric-card"><div class="metric-value">${result.summary.wcagCompliance.AA}%</div><div class="metric-label">WCAG AA</div></div>`);
429
+ parts.push(`</div>`);
430
+ if (includeCharts) {
431
+ parts.push(`<div class="chart"><pre>${generateScoreGauge(result.summary.score)}</pre></div>`);
432
+ }
433
+ }
434
+ // Impact breakdown
435
+ if (isMultiple) {
436
+ const impactCounts = {
437
+ critical: 0,
438
+ serious: 0,
439
+ moderate: 0,
440
+ minor: 0,
441
+ };
442
+ resultsArray.forEach((result) => {
443
+ Object.entries(result.summary.byImpact).forEach(([impact, count]) => {
444
+ impactCounts[impact] = (impactCounts[impact] || 0) + count;
445
+ });
446
+ });
447
+ parts.push(`<h2>Issues by Impact Level</h2>`);
448
+ if (includeCharts) {
449
+ parts.push(`<div class="chart"><pre>${generateBarChart(impactCounts)}</pre></div>`);
450
+ }
451
+ else {
452
+ parts.push(`<ul>`);
453
+ Object.entries(impactCounts)
454
+ .sort((a, b) => b[1] - a[1])
455
+ .forEach(([impact, count]) => {
456
+ parts.push(`<li class="${impact}"><strong>${impact}:</strong> ${count}</li>`);
457
+ });
458
+ parts.push(`</ul>`);
459
+ }
460
+ }
461
+ else {
462
+ const result = resultsArray[0];
463
+ parts.push(`<h2>Issues by Impact Level</h2>`);
464
+ if (includeCharts) {
465
+ parts.push(`<div class="chart"><pre>${generateBarChart(result.summary.byImpact)}</pre></div>`);
466
+ }
467
+ else {
468
+ parts.push(`<ul>`);
469
+ Object.entries(result.summary.byImpact)
470
+ .sort((a, b) => b[1] - a[1])
471
+ .forEach(([impact, count]) => {
472
+ parts.push(`<li class="${impact}"><strong>${impact}:</strong> ${count}</li>`);
473
+ });
474
+ parts.push(`</ul>`);
475
+ }
476
+ }
477
+ // Category breakdown
478
+ if (isMultiple) {
479
+ const categoryCounts = {};
480
+ resultsArray.forEach((result) => {
481
+ Object.entries(result.summary.byCategory).forEach(([cat, count]) => {
482
+ categoryCounts[cat] = (categoryCounts[cat] || 0) + count;
483
+ });
484
+ });
485
+ parts.push(`<h2>Issues by Category</h2>`);
486
+ if (includeCharts) {
487
+ parts.push(`<div class="chart"><pre>${generateBarChart(categoryCounts)}</pre></div>`);
488
+ }
489
+ else {
490
+ parts.push(`<ul>`);
491
+ Object.entries(categoryCounts)
492
+ .sort((a, b) => b[1] - a[1])
493
+ .forEach(([category, count]) => {
494
+ parts.push(`<li><strong>${category}:</strong> ${count}</li>`);
495
+ });
496
+ parts.push(`</ul>`);
497
+ }
498
+ }
499
+ else {
500
+ const result = resultsArray[0];
501
+ parts.push(`<h2>Issues by Category</h2>`);
502
+ if (includeCharts) {
503
+ parts.push(`<div class="chart"><pre>${generateBarChart(result.summary.byCategory)}</pre></div>`);
504
+ }
505
+ else {
506
+ parts.push(`<ul>`);
507
+ Object.entries(result.summary.byCategory)
508
+ .sort((a, b) => b[1] - a[1])
509
+ .forEach(([category, count]) => {
510
+ parts.push(`<li><strong>${category}:</strong> ${count}</li>`);
511
+ });
512
+ parts.push(`</ul>`);
513
+ }
514
+ }
515
+ // Per-URL breakdown for multiple results
516
+ if (isMultiple) {
517
+ parts.push(`<h2>Per-URL Breakdown</h2>`);
518
+ parts.push(`<table>`);
519
+ parts.push(`<tr><th>URL</th><th>Issues</th><th>Score</th><th>WCAG A</th><th>WCAG AA</th><th>WCAG AAA</th></tr>`);
520
+ resultsArray.forEach((result) => {
521
+ const url = result.metadata?.url || 'Unknown';
522
+ parts.push(`<tr><td>${escapeHtml(url)}</td><td>${result.summary.totalIssues}</td><td>${result.summary.score}/100</td><td>${result.summary.wcagCompliance.A}%</td><td>${result.summary.wcagCompliance.AA}%</td><td>${result.summary.wcagCompliance.AAA}%</td></tr>`);
523
+ });
524
+ parts.push(`</table>`);
525
+ }
526
+ parts.push(` </div>
527
+ </body>
528
+ </html>`);
529
+ return parts.join('\n');
530
+ }
531
+ /**
532
+ * Escape HTML special characters
533
+ */
534
+ function escapeHtml(text) {
535
+ return text
536
+ .replace(/&/g, '&amp;')
537
+ .replace(/</g, '&lt;')
538
+ .replace(/>/g, '&gt;')
539
+ .replace(/"/g, '&quot;')
540
+ .replace(/'/g, '&#039;');
541
+ }
542
+ /**
543
+ * generate_dashboard - Create visual dashboard summary of audit results
544
+ *
545
+ * Generates a visual dashboard with key metrics, charts, and summaries
546
+ * in various formats (text, markdown, HTML, JSON).
547
+ *
548
+ * @param input - Dashboard input (results or URL/array, format, includeCharts)
549
+ * @returns Formatted dashboard with key metrics, charts, and summaries
550
+ */
551
+ export async function generateDashboard(input) {
552
+ const { results, format = 'markdown', includeCharts = true, } = input;
553
+ let auditResults;
554
+ // If input is a URL string, run an audit first
555
+ if (typeof results === 'string') {
556
+ const singleResult = await auditUrl({ url: results });
557
+ auditResults = singleResult;
558
+ }
559
+ else if (Array.isArray(results)) {
560
+ // If array contains URLs, audit them
561
+ const urlResults = await Promise.all(results.map(async (r) => {
562
+ if (typeof r === 'string') {
563
+ return await auditUrl({ url: r });
564
+ }
565
+ return r;
566
+ }));
567
+ auditResults = urlResults;
568
+ }
569
+ else {
570
+ auditResults = results;
571
+ }
572
+ // Format dashboard based on requested format
573
+ let dashboard;
574
+ switch (format) {
575
+ case 'text':
576
+ dashboard = formatDashboardAsText(auditResults, includeCharts);
577
+ break;
578
+ case 'html':
579
+ dashboard = formatDashboardAsHTML(auditResults, includeCharts);
580
+ break;
581
+ case 'json':
582
+ const resultsArray = Array.isArray(auditResults)
583
+ ? auditResults
584
+ : [auditResults];
585
+ dashboard = JSON.stringify({
586
+ summary: resultsArray.map((r) => ({
587
+ url: r.metadata?.url || 'Unknown',
588
+ totalIssues: r.summary.totalIssues,
589
+ score: r.summary.score,
590
+ wcagCompliance: r.summary.wcagCompliance,
591
+ byImpact: r.summary.byImpact,
592
+ byCategory: r.summary.byCategory,
593
+ criticalBlockers: r.criticalBlockers.length,
594
+ quickWins: r.quickWins.length,
595
+ })),
596
+ }, null, 2);
597
+ break;
598
+ case 'markdown':
599
+ default:
600
+ dashboard = formatDashboardAsMarkdown(auditResults, includeCharts);
601
+ break;
602
+ }
603
+ return {
604
+ dashboard,
605
+ format,
606
+ includeCharts,
607
+ totalResults: Array.isArray(auditResults) ? auditResults.length : 1,
608
+ };
609
+ }
610
+ /**
611
+ * Generate executive summary report
612
+ */
613
+ function generateExecutiveSummary(results, level) {
614
+ const resultsArray = Array.isArray(results) ? results : [results];
615
+ const isMultiple = resultsArray.length > 1;
616
+ const parts = [];
617
+ if (level === 'executive') {
618
+ // High-level summary for executives
619
+ if (isMultiple) {
620
+ const totalIssues = resultsArray.reduce((sum, r) => sum + r.summary.totalIssues, 0);
621
+ const avgScore = resultsArray.reduce((sum, r) => sum + r.summary.score, 0) /
622
+ resultsArray.length;
623
+ parts.push('## Executive Summary');
624
+ parts.push(`\nAn accessibility audit was conducted on ${resultsArray.length} page(s), identifying ${totalIssues} accessibility issue(s).`);
625
+ parts.push(`\n**Key Findings:**`);
626
+ parts.push(`- Average Accessibility Score: ${Math.round(avgScore)}/100`);
627
+ parts.push(`- Total Issues Found: ${totalIssues}`);
628
+ const criticalCount = resultsArray.reduce((sum, r) => sum + (r.summary.byImpact.critical || 0), 0);
629
+ if (criticalCount > 0) {
630
+ parts.push(`- Critical Issues: ${criticalCount} (must be addressed before launch)`);
631
+ }
632
+ const quickWinsCount = resultsArray.reduce((sum, r) => sum + r.quickWins.length, 0);
633
+ if (quickWinsCount > 0) {
634
+ parts.push(`- Quick Wins Available: ${quickWinsCount} (easy fixes with high impact)`);
635
+ }
636
+ parts.push(`\n**Recommendation:** ${avgScore >= 80 ? 'The site demonstrates good accessibility practices. Continue monitoring and address remaining issues.' : avgScore >= 60 ? 'The site needs improvement to meet accessibility standards. Prioritize critical issues and quick wins.' : 'The site requires significant accessibility improvements before launch. Address critical blockers immediately.'}`);
637
+ }
638
+ else {
639
+ const result = resultsArray[0];
640
+ parts.push('## Executive Summary');
641
+ parts.push(`\nAn accessibility audit was conducted, identifying ${result.summary.totalIssues} accessibility issue(s).`);
642
+ parts.push(`\n**Key Findings:**`);
643
+ parts.push(`- Accessibility Score: ${result.summary.score}/100`);
644
+ parts.push(`- Total Issues Found: ${result.summary.totalIssues}`);
645
+ if (result.criticalBlockers.length > 0) {
646
+ parts.push(`- Critical Blockers: ${result.criticalBlockers.length} (must be fixed before launch)`);
647
+ }
648
+ if (result.quickWins.length > 0) {
649
+ parts.push(`- Quick Wins Available: ${result.quickWins.length} (easy fixes with high impact)`);
650
+ }
651
+ parts.push(`\n**Recommendation:** ${result.summary.score >= 80 ? 'The page demonstrates good accessibility practices. Continue monitoring and address remaining issues.' : result.summary.score >= 60 ? 'The page needs improvement to meet accessibility standards. Prioritize critical issues and quick wins.' : 'The page requires significant accessibility improvements before launch. Address critical blockers immediately.'}`);
652
+ }
653
+ }
654
+ else if (level === 'detailed') {
655
+ // Detailed summary with more information
656
+ if (isMultiple) {
657
+ const totalIssues = resultsArray.reduce((sum, r) => sum + r.summary.totalIssues, 0);
658
+ const avgScore = resultsArray.reduce((sum, r) => sum + r.summary.score, 0) /
659
+ resultsArray.length;
660
+ const avgWCAG = {
661
+ A: resultsArray.reduce((sum, r) => sum + r.summary.wcagCompliance.A, 0) / resultsArray.length,
662
+ AA: resultsArray.reduce((sum, r) => sum + r.summary.wcagCompliance.AA, 0) / resultsArray.length,
663
+ AAA: resultsArray.reduce((sum, r) => sum + r.summary.wcagCompliance.AAA, 0) / resultsArray.length,
664
+ };
665
+ parts.push('## Detailed Summary');
666
+ parts.push(`\nAn accessibility audit was conducted on ${resultsArray.length} page(s), identifying ${totalIssues} accessibility issue(s).`);
667
+ parts.push(`\n**Overall Metrics:**`);
668
+ parts.push(`- Average Accessibility Score: ${Math.round(avgScore)}/100`);
669
+ parts.push(`- Total Issues: ${totalIssues}`);
670
+ parts.push(`- WCAG Compliance: Level A: ${Math.round(avgWCAG.A)}%, Level AA: ${Math.round(avgWCAG.AA)}%, Level AAA: ${Math.round(avgWCAG.AAA)}%`);
671
+ // Impact breakdown
672
+ const impactCounts = {
673
+ critical: 0,
674
+ serious: 0,
675
+ moderate: 0,
676
+ minor: 0,
677
+ };
678
+ resultsArray.forEach((result) => {
679
+ Object.entries(result.summary.byImpact).forEach(([impact, count]) => {
680
+ impactCounts[impact] = (impactCounts[impact] || 0) + count;
681
+ });
682
+ });
683
+ parts.push(`\n**Issues by Impact:**`);
684
+ Object.entries(impactCounts)
685
+ .sort((a, b) => b[1] - a[1])
686
+ .forEach(([impact, count]) => {
687
+ if (count > 0) {
688
+ parts.push(`- ${impact}: ${count}`);
689
+ }
690
+ });
691
+ // Category breakdown
692
+ const categoryCounts = {};
693
+ resultsArray.forEach((result) => {
694
+ Object.entries(result.summary.byCategory).forEach(([cat, count]) => {
695
+ categoryCounts[cat] = (categoryCounts[cat] || 0) + count;
696
+ });
697
+ });
698
+ parts.push(`\n**Issues by Category:**`);
699
+ Object.entries(categoryCounts)
700
+ .sort((a, b) => b[1] - a[1])
701
+ .forEach(([category, count]) => {
702
+ parts.push(`- ${category}: ${count}`);
703
+ });
704
+ const criticalCount = resultsArray.reduce((sum, r) => sum + (r.summary.byImpact.critical || 0), 0);
705
+ const quickWinsCount = resultsArray.reduce((sum, r) => sum + r.quickWins.length, 0);
706
+ parts.push(`\n**Priority Actions:**`);
707
+ if (criticalCount > 0) {
708
+ parts.push(`- Address ${criticalCount} critical issue(s) that prevent users with disabilities from accessing content`);
709
+ }
710
+ if (quickWinsCount > 0) {
711
+ parts.push(`- Implement ${quickWinsCount} quick win(s) for immediate accessibility improvements`);
712
+ }
713
+ parts.push(`\n**Next Steps:** ${avgScore >= 80 ? 'Continue monitoring accessibility and address remaining issues. Consider implementing automated accessibility testing in your CI/CD pipeline.' : avgScore >= 60 ? 'Prioritize critical issues and quick wins. Develop an accessibility remediation plan with clear timelines.' : 'Immediately address critical blockers. Conduct a comprehensive accessibility review and develop a detailed remediation plan.'}`);
714
+ }
715
+ else {
716
+ const result = resultsArray[0];
717
+ parts.push('## Detailed Summary');
718
+ parts.push(`\nAn accessibility audit was conducted, identifying ${result.summary.totalIssues} accessibility issue(s).`);
719
+ parts.push(`\n**Overall Metrics:**`);
720
+ parts.push(`- Accessibility Score: ${result.summary.score}/100`);
721
+ parts.push(`- Total Issues: ${result.summary.totalIssues}`);
722
+ parts.push(`- WCAG Compliance: Level A: ${result.summary.wcagCompliance.A}%, Level AA: ${result.summary.wcagCompliance.AA}%, Level AAA: ${result.summary.wcagCompliance.AAA}%`);
723
+ parts.push(`\n**Issues by Impact:**`);
724
+ Object.entries(result.summary.byImpact)
725
+ .sort((a, b) => b[1] - a[1])
726
+ .forEach(([impact, count]) => {
727
+ if (count > 0) {
728
+ parts.push(`- ${impact}: ${count}`);
729
+ }
730
+ });
731
+ parts.push(`\n**Issues by Category:**`);
732
+ Object.entries(result.summary.byCategory)
733
+ .sort((a, b) => b[1] - a[1])
734
+ .forEach(([category, count]) => {
735
+ parts.push(`- ${category}: ${count}`);
736
+ });
737
+ if (result.criticalBlockers.length > 0) {
738
+ parts.push(`\n**Critical Blockers:**`);
739
+ result.criticalBlockers.slice(0, 5).forEach((blocker, index) => {
740
+ parts.push(`${index + 1}. ${blocker.description} (${blocker.affectedElements} element(s))`);
741
+ });
742
+ }
743
+ if (result.quickWins.length > 0) {
744
+ parts.push(`\n**Quick Wins:**`);
745
+ result.quickWins.slice(0, 5).forEach((win, index) => {
746
+ parts.push(`${index + 1}. ${win.description} (${win.affectedElements} element(s), ${win.estimatedTime})`);
747
+ });
748
+ }
749
+ parts.push(`\n**Next Steps:** ${result.summary.score >= 80 ? 'Continue monitoring accessibility and address remaining issues. Consider implementing automated accessibility testing.' : result.summary.score >= 60 ? 'Prioritize critical issues and quick wins. Develop an accessibility remediation plan.' : 'Immediately address critical blockers. Conduct a comprehensive accessibility review and develop a detailed remediation plan.'}`);
750
+ }
751
+ }
752
+ else {
753
+ // Technical summary with detailed information
754
+ if (isMultiple) {
755
+ const totalIssues = resultsArray.reduce((sum, r) => sum + r.summary.totalIssues, 0);
756
+ const avgScore = resultsArray.reduce((sum, r) => sum + r.summary.score, 0) /
757
+ resultsArray.length;
758
+ parts.push('## Technical Summary');
759
+ parts.push(`\nAccessibility audit results for ${resultsArray.length} page(s):`);
760
+ parts.push(`\n**Statistics:**`);
761
+ parts.push(`- Total Issues: ${totalIssues}`);
762
+ parts.push(`- Average Score: ${Math.round(avgScore)}/100`);
763
+ // Per-URL breakdown
764
+ parts.push(`\n**Per-URL Breakdown:**`);
765
+ resultsArray.forEach((result, index) => {
766
+ const url = result.metadata?.url || 'Unknown';
767
+ parts.push(`\n${index + 1}. ${url}`);
768
+ parts.push(` - Issues: ${result.summary.totalIssues}`);
769
+ parts.push(` - Score: ${result.summary.score}/100`);
770
+ parts.push(` - WCAG: A: ${result.summary.wcagCompliance.A}%, AA: ${result.summary.wcagCompliance.AA}%, AAA: ${result.summary.wcagCompliance.AAA}%`);
771
+ if (result.criticalBlockers.length > 0) {
772
+ parts.push(` - Critical Blockers: ${result.criticalBlockers.length}`);
773
+ }
774
+ if (result.quickWins.length > 0) {
775
+ parts.push(` - Quick Wins: ${result.quickWins.length}`);
776
+ }
777
+ });
778
+ }
779
+ else {
780
+ const result = resultsArray[0];
781
+ const url = result.metadata?.url || 'Unknown';
782
+ parts.push('## Technical Summary');
783
+ parts.push(`\nAccessibility audit results for: ${url}`);
784
+ parts.push(`\n**Statistics:**`);
785
+ parts.push(`- Total Issues: ${result.summary.totalIssues}`);
786
+ parts.push(`- Score: ${result.summary.score}/100`);
787
+ parts.push(`- WCAG Compliance: A: ${result.summary.wcagCompliance.A}%, AA: ${result.summary.wcagCompliance.AA}%, AAA: ${result.summary.wcagCompliance.AAA}%`);
788
+ parts.push(`\n**Impact Breakdown:**`);
789
+ Object.entries(result.summary.byImpact).forEach(([impact, count]) => {
790
+ parts.push(`- ${impact}: ${count}`);
791
+ });
792
+ parts.push(`\n**Category Breakdown:**`);
793
+ Object.entries(result.summary.byCategory).forEach(([category, count]) => {
794
+ parts.push(`- ${category}: ${count}`);
795
+ });
796
+ if (result.criticalBlockers.length > 0) {
797
+ parts.push(`\n**Critical Blockers (${result.criticalBlockers.length}):**`);
798
+ result.criticalBlockers.forEach((blocker) => {
799
+ parts.push(`- ${blocker.ruleId}: ${blocker.description}`);
800
+ parts.push(` - Affected Elements: ${blocker.affectedElements}`);
801
+ parts.push(` - WCAG Level: ${blocker.wcagLevel}`);
802
+ });
803
+ }
804
+ if (result.quickWins.length > 0) {
805
+ parts.push(`\n**Quick Wins (${result.quickWins.length}):**`);
806
+ result.quickWins.forEach((win) => {
807
+ parts.push(`- ${win.ruleId}: ${win.description}`);
808
+ parts.push(` - Affected Elements: ${win.affectedElements}`);
809
+ parts.push(` - Estimated Time: ${win.estimatedTime}`);
810
+ });
811
+ }
812
+ }
813
+ }
814
+ return parts.join('\n');
815
+ }
816
+ /**
817
+ * Format summary report as markdown
818
+ */
819
+ function formatSummaryReportAsMarkdown(results, level) {
820
+ const parts = [];
821
+ parts.push('# Accessibility Summary Report');
822
+ parts.push(`\n**Report Date:** ${new Date().toISOString().split('T')[0]}`);
823
+ const summary = generateExecutiveSummary(results, level);
824
+ parts.push(summary);
825
+ return parts.join('\n');
826
+ }
827
+ /**
828
+ * Format summary report as text
829
+ */
830
+ function formatSummaryReportAsText(results, level) {
831
+ const parts = [];
832
+ parts.push('ACCESSIBILITY SUMMARY REPORT');
833
+ parts.push(`Report Date: ${new Date().toISOString().split('T')[0]}\n`);
834
+ const summary = generateExecutiveSummary(results, level);
835
+ // Convert markdown-style formatting to plain text
836
+ const textSummary = summary
837
+ .replace(/## /g, '\n')
838
+ .replace(/\*\*/g, '')
839
+ .replace(/# /g, '');
840
+ parts.push(textSummary);
841
+ return parts.join('\n');
842
+ }
843
+ /**
844
+ * Format summary report as HTML
845
+ */
846
+ function formatSummaryReportAsHTML(results, level) {
847
+ const parts = [];
848
+ parts.push(`<!DOCTYPE html>
849
+ <html lang="en">
850
+ <head>
851
+ <meta charset="UTF-8">
852
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
853
+ <title>Accessibility Summary Report</title>
854
+ <style>
855
+ body {
856
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
857
+ max-width: 900px;
858
+ margin: 0 auto;
859
+ padding: 20px;
860
+ background: #f5f5f5;
861
+ }
862
+ .report {
863
+ background: white;
864
+ border-radius: 8px;
865
+ padding: 30px;
866
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
867
+ }
868
+ h1 { color: #333; border-bottom: 3px solid #4CAF50; padding-bottom: 10px; }
869
+ h2 { color: #555; margin-top: 30px; }
870
+ p { line-height: 1.6; color: #333; }
871
+ ul { line-height: 1.8; }
872
+ .date { color: #666; font-size: 0.9em; }
873
+ </style>
874
+ </head>
875
+ <body>
876
+ <div class="report">`);
877
+ parts.push(`<h1>Accessibility Summary Report</h1>`);
878
+ parts.push(`<p class="date"><strong>Report Date:</strong> ${new Date().toISOString().split('T')[0]}</p>`);
879
+ const summary = generateExecutiveSummary(results, level);
880
+ // Convert markdown to HTML
881
+ const htmlSummary = summary
882
+ .replace(/## (.+)/g, '<h2>$1</h2>')
883
+ .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
884
+ .replace(/\n- (.+)/g, '<li>$1</li>')
885
+ .replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>')
886
+ .replace(/\n\n/g, '</p><p>')
887
+ .replace(/^/, '<p>')
888
+ .replace(/$/, '</p>');
889
+ parts.push(htmlSummary);
890
+ parts.push(` </div>
891
+ </body>
892
+ </html>`);
893
+ return parts.join('\n');
894
+ }
895
+ /**
896
+ * generate_summary_report - Generate executive summary report
897
+ *
898
+ * Generates an executive summary report with key findings and recommendations
899
+ * in various formats (text, markdown, HTML) and detail levels.
900
+ *
901
+ * @param input - Summary report input (results or URL/array, format, level)
902
+ * @returns Summary report with key findings and recommendations
903
+ */
904
+ export async function generateSummaryReport(input) {
905
+ const { results, format = 'markdown', level = 'executive', } = input;
906
+ let auditResults;
907
+ // If input is a URL string, run an audit first
908
+ if (typeof results === 'string') {
909
+ const singleResult = await auditUrl({ url: results });
910
+ auditResults = singleResult;
911
+ }
912
+ else if (Array.isArray(results)) {
913
+ // If array contains URLs, audit them
914
+ const urlResults = await Promise.all(results.map(async (r) => {
915
+ if (typeof r === 'string') {
916
+ return await auditUrl({ url: r });
917
+ }
918
+ return r;
919
+ }));
920
+ auditResults = urlResults;
921
+ }
922
+ else {
923
+ auditResults = results;
924
+ }
925
+ // Format report based on requested format
926
+ let report;
927
+ switch (format) {
928
+ case 'text':
929
+ report = formatSummaryReportAsText(auditResults, level);
930
+ break;
931
+ case 'html':
932
+ report = formatSummaryReportAsHTML(auditResults, level);
933
+ break;
934
+ case 'markdown':
935
+ default:
936
+ report = formatSummaryReportAsMarkdown(auditResults, level);
937
+ break;
938
+ }
939
+ return {
940
+ report,
941
+ format,
942
+ level,
943
+ totalResults: Array.isArray(auditResults) ? auditResults.length : 1,
944
+ };
945
+ }
946
+ //# sourceMappingURL=visualize.js.map