aria-ease 2.3.0 โ 2.5.0
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.
- package/README.md +43 -20
- package/bin/cli.cjs +9 -3
- package/bin/cli.cjs.map +1 -1
- package/bin/cli.js +9 -3
- package/bin/cli.js.map +1 -1
- package/bin/cli.ts +6 -1
- package/dist/index.cjs +8 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/src/block/index.cjs +7 -6
- package/dist/src/block/index.cjs.map +1 -1
- package/dist/src/block/index.d.cts +3 -1
- package/dist/src/block/index.d.ts +3 -1
- package/dist/src/block/index.js +7 -6
- package/dist/src/block/index.js.map +1 -1
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -53,8 +53,8 @@ export default {
|
|
|
53
53
|
output: {
|
|
54
54
|
format: "html", // 'json' | 'csv' | 'html' | 'all'
|
|
55
55
|
out: "./accessibility-reports",
|
|
56
|
-
}
|
|
57
|
-
}
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
58
|
};
|
|
59
59
|
```
|
|
60
60
|
|
|
@@ -65,6 +65,7 @@ npx aria-ease audit
|
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
**Supported config formats:**
|
|
68
|
+
|
|
68
69
|
- `ariaease.config.js` (ES modules)
|
|
69
70
|
- `ariaease.config.mjs` (ES modules explicit)
|
|
70
71
|
- `ariaease.config.cjs` (CommonJS)
|
|
@@ -79,9 +80,9 @@ The CLI will automatically find and load your config file, with validation to ca
|
|
|
79
80
|
|
|
80
81
|
## ๐ Component API
|
|
81
82
|
|
|
82
|
-
### ๐ Menu (Dropdowns
|
|
83
|
+
### ๐ Menu (Dropdowns)
|
|
83
84
|
|
|
84
|
-
Creates accessible menus with focus trapping and keyboard navigation. Works for dropdowns
|
|
85
|
+
Creates accessible menus with focus trapping and keyboard navigation. Works for dropdowns that toggles display with interactive items.
|
|
85
86
|
|
|
86
87
|
**Features:**
|
|
87
88
|
|
|
@@ -95,15 +96,20 @@ import * as Menu from "aria-ease/menu";
|
|
|
95
96
|
|
|
96
97
|
// React Example
|
|
97
98
|
useEffect(() => {
|
|
98
|
-
|
|
99
|
-
menuId: "
|
|
100
|
-
menuItemsClass: "menu-
|
|
101
|
-
triggerId: "
|
|
99
|
+
menuRef.current = Menu.makeMenuAccessible({
|
|
100
|
+
menuId: "menu-div",
|
|
101
|
+
menuItemsClass: "profile-menu-items",
|
|
102
|
+
triggerId: "display-button",
|
|
102
103
|
});
|
|
103
104
|
|
|
104
|
-
return () =>
|
|
105
|
+
return () => menuRef.current.cleanup(); // Clean up on unmount
|
|
105
106
|
}, []);
|
|
106
107
|
|
|
108
|
+
// Programmatically control
|
|
109
|
+
menuRef.current.openMenu(); // Open the menu
|
|
110
|
+
menuRef.current.closeMenu(); // Close the menu
|
|
111
|
+
menuRef.current.refresh(); // Refresh the cache after dynamically adding/removing a menu item
|
|
112
|
+
|
|
107
113
|
// Vanilla JS Example
|
|
108
114
|
const menu = Menu.makeMenuAccessible({
|
|
109
115
|
menuId: "dropdown-menu",
|
|
@@ -116,22 +122,36 @@ menu.openMenu();
|
|
|
116
122
|
menu.closeMenu();
|
|
117
123
|
|
|
118
124
|
// If you dynamically add/remove menu items, refresh the cache
|
|
119
|
-
menu.refresh();
|
|
125
|
+
menu.refresh();
|
|
120
126
|
```
|
|
121
127
|
|
|
122
128
|
**Required HTML structure:**
|
|
123
129
|
|
|
124
130
|
```html
|
|
125
|
-
<button
|
|
131
|
+
<button
|
|
132
|
+
id="menu-button"
|
|
133
|
+
aria-expanded="false"
|
|
134
|
+
aria-controls="dropdown-menu"
|
|
135
|
+
aria-haspopup="true"
|
|
136
|
+
>
|
|
126
137
|
Menu
|
|
127
138
|
</button>
|
|
128
|
-
<div
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
139
|
+
<div
|
|
140
|
+
id="dropdown-menu"
|
|
141
|
+
style="display: none;"
|
|
142
|
+
aria-labelledby="menu-button"
|
|
143
|
+
role="menu"
|
|
144
|
+
>
|
|
145
|
+
<a role="menuitem" href="#" class="menu-item">Item 1</a>
|
|
146
|
+
<a role="menuitem" href="#" class="menu-item">Item 2</a>
|
|
147
|
+
<button role="menuitem" class="menu-item">Item 3</button>
|
|
132
148
|
</div>
|
|
133
149
|
```
|
|
134
150
|
|
|
151
|
+
## ๐ฎ Live Demo
|
|
152
|
+
|
|
153
|
+
- [Menu Component](https://codesandbox.io/p/sandbox/szsclq) - Dropdown with keyboard navigation
|
|
154
|
+
|
|
135
155
|
---
|
|
136
156
|
|
|
137
157
|
### ๐ช Accordion
|
|
@@ -281,7 +301,7 @@ const blockInstance = makeBlockAccessible({
|
|
|
281
301
|
});
|
|
282
302
|
|
|
283
303
|
// Clean up when done
|
|
284
|
-
blockInstance.cleanup();
|
|
304
|
+
blockInstance.current.cleanup();
|
|
285
305
|
```
|
|
286
306
|
|
|
287
307
|
---
|
|
@@ -329,6 +349,8 @@ Aria-Ease is designed to be lightweight and tree-shakable:
|
|
|
329
349
|
```javascript
|
|
330
350
|
// โ
Good - only imports menu code (~3.7KB)
|
|
331
351
|
import { makeMenuAccessible } from "aria-ease/menu";
|
|
352
|
+
//or
|
|
353
|
+
import * as Block from "aria-ease/block";
|
|
332
354
|
|
|
333
355
|
// โ Avoid - imports everything (~416KB)
|
|
334
356
|
import { makeMenuAccessible } from "aria-ease";
|
|
@@ -345,8 +367,8 @@ If using React StrictMode, be aware it intentionally calls effects twice in deve
|
|
|
345
367
|
|
|
346
368
|
```javascript
|
|
347
369
|
useEffect(() => {
|
|
348
|
-
|
|
349
|
-
return () =>
|
|
370
|
+
menuRef.current = Menu.makeMenuAccessible({...});
|
|
371
|
+
return () => menuRef.current.cleanup(); // Prevents double-initialization
|
|
350
372
|
}, []);
|
|
351
373
|
```
|
|
352
374
|
|
|
@@ -378,7 +400,7 @@ Without visible focus indicators, keyboard users cannot tell which element is ac
|
|
|
378
400
|
Aria-Ease supports all modern browsers:
|
|
379
401
|
|
|
380
402
|
| Browser | Minimum Version |
|
|
381
|
-
|
|
403
|
+
| ------- | --------------- |
|
|
382
404
|
| Chrome | Last 2 versions |
|
|
383
405
|
| Firefox | Last 2 versions |
|
|
384
406
|
| Safari | Last 2 versions |
|
|
@@ -387,6 +409,7 @@ Aria-Ease supports all modern browsers:
|
|
|
387
409
|
**Not supported:** Internet Explorer 11 and below
|
|
388
410
|
|
|
389
411
|
**Requirements:**
|
|
412
|
+
|
|
390
413
|
- ES6+ support
|
|
391
414
|
- `querySelector` and `querySelectorAll`
|
|
392
415
|
- `addEventListener` and `removeEventListener`
|
|
@@ -417,4 +440,4 @@ ISC License - see [LICENSE](LICENSE) file for details.
|
|
|
417
440
|
|
|
418
441
|
---
|
|
419
442
|
|
|
420
|
-
**Created by [Isaac Victor](https://
|
|
443
|
+
**Created by [Isaac Victor](https://github.com/Scriptkidd98)**
|
package/bin/cli.cjs
CHANGED
|
@@ -32,13 +32,15 @@ var import_fs_extra2 = __toESM(require("fs-extra"), 1);
|
|
|
32
32
|
// src/utils/audit/src/audit/audit.ts
|
|
33
33
|
var import_playwright = __toESM(require("@axe-core/playwright"), 1);
|
|
34
34
|
var import_playwright2 = require("playwright");
|
|
35
|
-
async function runAudit(url) {
|
|
35
|
+
async function runAudit(url, options) {
|
|
36
36
|
let browser;
|
|
37
|
+
const timeout = options?.timeout || 6e4;
|
|
38
|
+
const waitUntil = options?.waitUntil || "domcontentloaded";
|
|
37
39
|
try {
|
|
38
40
|
browser = await import_playwright2.chromium.launch({ headless: true });
|
|
39
41
|
const context = await browser.newContext();
|
|
40
42
|
const page = await context.newPage();
|
|
41
|
-
await page.goto(url, { waitUntil
|
|
43
|
+
await page.goto(url, { waitUntil, timeout });
|
|
42
44
|
const axe2 = new import_playwright.default({ page });
|
|
43
45
|
const axeResults = await axe2.analyze();
|
|
44
46
|
return axeResults;
|
|
@@ -421,10 +423,14 @@ program.command("audit").description("Run axe-core powered accessibility audit o
|
|
|
421
423
|
process.exit(1);
|
|
422
424
|
}
|
|
423
425
|
const allResults = [];
|
|
426
|
+
const auditOptions = {
|
|
427
|
+
timeout: config.audit?.timeout,
|
|
428
|
+
waitUntil: config.audit?.waitUntil
|
|
429
|
+
};
|
|
424
430
|
for (const url of urls) {
|
|
425
431
|
console.log(import_chalk.default.yellow(`\u{1F50E} Auditing: ${url}`));
|
|
426
432
|
try {
|
|
427
|
-
const result = await runAudit(url);
|
|
433
|
+
const result = await runAudit(url, auditOptions);
|
|
428
434
|
allResults.push({ url, result });
|
|
429
435
|
console.log(import_chalk.default.green(`\u2705 Completed audit for ${url}
|
|
430
436
|
`));
|
package/bin/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["cli.ts","../src/utils/audit/src/audit/audit.ts","../src/utils/audit/src/formatters/formatters.ts","../src/utils/test/src/test.ts","configLoader.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport path from \"path\";\nimport fs from \"fs-extra\";\nimport { AxeResult } from \"Types\";\nimport { runAudit } from \"../src/utils/audit/src/audit/audit\";\nimport { formatResults } from \"../src/utils/audit/src/formatters/formatters\";\nimport { runTest } from \"../src/utils/test/index\";\nimport { loadConfig } from \"./configLoader\";\n\nconst program = new Command();\n\nprogram.name('aria-ease').description('Run accessibility tests and audits').version('2.2.3');\n\nprogram.command('audit')\n.description('Run axe-core powered accessibility audit on webpages')\n.option('-u, --url <url>', 'Single URL to audit')\n.option('-f, --format <format>', 'Output format for the audit report: json | csv | html | all', 'all')\n.option('-o, --out <path>', 'Directory to save the audit report', './accessibility-reports/audit')\n.action(async (opts) => {\n console.log(chalk.cyanBright('๐ Starting accessibility audit...\\n'));\n\n // Load config with robust discovery and validation\n const { config, configPath, errors } = await loadConfig(process.cwd());\n \n if (configPath) {\n console.log(chalk.green(`โ
Loaded config from ${path.basename(configPath)}\\n`));\n } else if (errors.length > 0) {\n console.log(chalk.red('โ Config file errors:\\n'));\n errors.forEach(err => console.log(chalk.red(` ${err}`)));\n console.log('');\n process.exit(1);\n } else {\n console.log(chalk.yellow('โน๏ธ No config file found, using CLI options.\\n'));\n }\n\n const urls: string[] = [];\n if(opts.url) urls.push(opts.url);\n if(config.audit?.urls && Array.isArray(config.audit.urls)) urls.push(...config.audit.urls);\n\n const format: string = (config.audit?.output && (config.audit.output as { format?: string }).format) || opts.format;\n if(!['json', 'csv', 'html', 'all'].includes(format)) {\n console.log(chalk.red('โ Invalid format. Use \"json\", \"csv\", \"html\" or \"all\".'));\n process.exit(1);\n }\n\n if(urls.length === 0) {\n console.log(chalk.red('โ No URLs provided. Use --url option or add \"urls\" in config file'));\n process.exit(1);\n }\n\n const allResults: { url: string, result?: AxeResult }[] = [];\n for (const url of urls) {\n console.log(chalk.yellow(`๐ Auditing: ${url}`));\n try {\n const result: AxeResult = await runAudit(url);\n allResults.push({ url: url, result });\n console.log(chalk.green(`โ
Completed audit for ${url}\\n`));\n } catch (error: unknown) {\n if(error instanceof Error && error.message) {\n console.log(chalk.red(`โ Failed auditing ${url}: ${error.message}`));\n }\n }\n }\n\n const hasResults = allResults.some(r => r.result && r.result.violations && r.result.violations.length > 0);\n if (!hasResults) {\n const auditedCount = allResults.filter(r => r.result).length;\n if (auditedCount === 0) {\n console.log(chalk.red('โ No pages were successfully audited.'));\n process.exit(1);\n }\n console.log(chalk.green('\\n๐ Great news! No accessibility violations found!'));\n console.log(chalk.gray(` Audited ${auditedCount} page${auditedCount > 1 ? 's' : ''} successfully.\\n`));\n process.exit(0);\n }\n\n async function createReport(format: string) {\n const formatted = formatResults(allResults, format);\n\n const out = (config.audit?.output && (config.audit.output as { out?: string }).out) || opts.out;\n\n await fs.ensureDir(out);\n const d = new Date();\n const pad = (n: number) => String(n).padStart(2, '0');\n const timestamp = `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n const fileName = `ariaease-report-${timestamp}.${format}`;\n const filePath = path.join(out, fileName);\n\n await fs.writeFile(filePath, formatted, 'utf-8');\n console.log(chalk.magentaBright(`๐ Report saved to ${filePath}`));\n }\n\n if(['json', 'csv', 'html'].includes(format)) {\n await createReport(format);\n } else if(format === 'all') {\n await Promise.all(['json', 'csv', 'html'].map((format) => createReport(format)));\n }\n\n console.log(chalk.green('\\n๐ All audits completed.'));\n})\n\nprogram.command('test')\n.description('Run core a11y accessibility standard tests on UI components')\n.action(() => {\n runTest();\n})\n\nprogram.command('help')\n.description('Display help information')\n.action(() => {\n program.outputHelp();\n});\n\nprogram.parse(process.argv);","import AxeBuilder from \"@axe-core/playwright\";\nimport { chromium } from \"playwright\";\nimport type { AxeResult } from \"Types\";\n\nexport async function runAudit(url: string) {\n let browser;\n\n try{ \n browser = await chromium.launch({ headless: true });\n const context = await browser.newContext();\n const page = await context.newPage();\n await page.goto(url, { waitUntil: 'networkidle' });\n const axe = new AxeBuilder({ page });\n const axeResults: AxeResult = await axe.analyze();\n return axeResults;\n } catch(error: unknown) {\n if (error instanceof Error) {\n if (error.message.includes(\"Executable doesn't exist\")) {\n console.error('\\nโ Playwright browsers not found!\\n');\n console.log('๐ฆ First-time setup required:');\n console.log(' Run: npx playwright install chromium\\n');\n console.log('๐ก This downloads the browser needed for auditing (~200MB)');\n console.log(' You only need to do this once.\\n');\n } else if(error.message.includes(\"page.goto: net::ERR_CONNECTION_REFUSED\")) {\n console.error('\\nโ Server Not Running!\\n');\n console.log(' Make sure your server is running before auditing URL');\n console.log(' Run: npm run dev # or your start command');\n } else if(error.message.includes(\"page.goto: Protocol error (Page.navigate): Cannot navigate to invalid URL\")) {\n console.error('\\nโ Cannot audit invalid URL\\n')\n } else {\n console.error('โ Audit error:', error.message);\n console.log(' Make sure you provide a valid URL');\n }\n } else {\n console.error('โ Audit error (non-Error):', String(error));\n }\n throw error;\n } finally {\n if(browser) await browser.close(); \n }\n}","import type { AxeResult } from \"Types\";\n\nexport function formatResults(allResults: { url: string; result?: AxeResult }[], format: string): string {\n switch (format) {\n case 'json':\n return JSON.stringify(\n allResults.flatMap(({ url, result }) =>\n result\n ? result.violations.flatMap(v =>\n v.nodes.map(n => ({\n URL: url,\n Rule: v.id,\n Impact: v.impact,\n Description: v.description,\n Target: n.target,\n FailureSummary: n.failureSummary\n }))\n )\n : []\n ),\n null,\n 2\n );\n case 'csv':\n return toCSV(allResults);\n case 'html':\n return toHTML(allResults);\n default:\n return '';\n }\n}\n\nfunction toCSV(allResults: { url: string, result?: AxeResult }[]) {\n const rows = ['URL,Rule,Impact,Description,Target,FailureSummary'];\n allResults.forEach(({ url, result }: { url: string, result?: AxeResult }) => {\n if(result) {\n result.violations.forEach(v => {\n v.nodes.forEach(n => {\n rows.push(escapeCSV(url) + ',' +\n escapeCSV(v.id) + ',' +\n escapeCSV(v.impact) + ',' +\n escapeCSV(v.description) + ',' +\n escapeCSV(Array.isArray(n.target) ? n.target.join('; ') : String(n.target)) + ',' +\n escapeCSV(n.failureSummary ?? '')\n );\n });\n });\n }\n });\n return rows.join('\\n');\n}\n\nfunction escapeCSV(value: unknown): string {\n const s = String(value ?? '');\n return `\"${s.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction toHTML(allResults: { url: string, result?: AxeResult }[]) {\n const summary = {\n pagesAudited: 0,\n pagesWithViolations: 0,\n totalViolations: 0,\n distinctRules: new Set<string>(),\n impactCounts: new Map<string, number>()\n };\n\n allResults.forEach(({ result }) => {\n if (!result) return;\n summary.pagesAudited++;\n const pageViolations = result.violations.reduce((acc, v) => {\n const nodesCount = (v.nodes || []).length;\n if (nodesCount > 0) {\n summary.distinctRules.add(v.id);\n summary.totalViolations += nodesCount;\n acc += nodesCount;\n const impact = String(v.impact ?? 'unknown');\n summary.impactCounts.set(impact, (summary.impactCounts.get(impact) || 0) + nodesCount);\n }\n return acc;\n }, 0);\n if (pageViolations > 0) summary.pagesWithViolations++;\n });\n\n const rows: string[] = [];\n allResults.forEach(({ url, result }) => {\n if (!result) return;\n result.violations.forEach(v => {\n v.nodes.forEach(n => {\n const target = Array.isArray(n.target) ? n.target.join('; ') : String(n.target);\n rows.push(`\n <tr>\n <td class=\"nowrap\">${escapeHTML(url)}</td>\n <td class=\"nowrap\">${escapeHTML(v.id)}</td>\n <td class=\"impact ${escapeClass(String(v.impact ?? 'unknown'))}\">${escapeHTML(String(v.impact ?? ''))}</td>\n <td class=\"desc\">${escapeHTML(v.description ?? '')}</td>\n <td class=\"target\"><code>${escapeHTML(target)}</code></td>\n <td class=\"fail\">${escapeHTML(n.failureSummary ?? '').split(/\\r?\\n/).join('<br/>')}</td>\n </tr>\n `);\n });\n });\n });\n\n const impactSummary = Array.from(summary.impactCounts.entries()).map(([impact, count]) => `<li><strong class=\"impact ${escapeClass(impact)}\">${escapeHTML(impact)}</strong>: ${count}</li>`).join('\\n');\n const d = new Date();\n const pad = (n: number) => String(n).padStart(2, '0');\n const reportDateTime = `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n const headerSummary = `\n <section class=\"summary\">\n <h2>Report summary</h2>\n <ul>\n <li><strong>Date:</strong> ${reportDateTime}</li>\n <li><strong>Pages audited:</strong> ${summary.pagesAudited}</li>\n <li><strong>Pages with violations:</strong> ${summary.pagesWithViolations}</li>\n <li><strong>Total violations:</strong> ${summary.totalViolations}</li>\n <li><strong>Distinct rules:</strong> ${summary.distinctRules.size}</li>\n </ul>\n <div class=\"impact-summary\">\n <h3>By impact</h3>\n <ul class=\"summary-list\">\n ${impactSummary || '<li>None</li>'}\n </ul>\n </div>\n </section>\n `.trim();\n\n const html = `\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"utf-8\"/>\n <title>Aria-Ease Accessibility Audit Report</title>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n <style>\n :root{\n --bg:#ffffff; --muted:#6b7280; --border:#e6e9ee;\n --impact-critical: red; --impact-moderate:#fff4dd; --impact-serious:rgb(255, 123, 0);\n }\n body{font-family:Inter,ui-sans-serif,system-ui,Segoe UI,Roboto,Helvetica,Arial; background:var(--bg); color:#111827; padding:24px; line-height:1.4}\n h1{margin:0 0 8px}\n .summary{background:#f8fafc;border:1px solid var(--border);padding:12px 16px;border-radius:8px;margin-bottom:18px}\n .summary ul{margin:6px 0 0 0;padding:0 18px}\n .impact-summary h3{margin:12px 0 6px}\n table{width:100%; border-collapse:collapse; margin-top:12px}\n th,td{border:1px solid var(--border); padding:10px; text-align:left; vertical-align:top}\n th{background:#f3f4f6; font-weight:600; position:sticky; top:0; z-index:1}\n .nowrap{white-space:nowrap}\n .target code{font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, \"Roboto Mono\", \"Courier New\", monospace; white-space:pre-wrap}\n .desc{max-width:380px}\n tr:nth-child(even){background:#fbfbfb}\n td.fail{color:#7b1e1e}\n .impact.critical{background:var(--impact-critical); font-weight:600}\n .impact.moderate{background:var(--impact-moderate); font-weight:600}\n .impact.serious{background:var(--impact-serious); font-weight:600}\n @media (max-width:900px){\n .desc{max-width:200px}\n table, thead, tbody, th, td, tr{display:block}\n thead{display:none}\n tr{margin-bottom:10px; border: 1px solid var(--border);}\n td{border:1px solid var(--border); padding:6px}\n td::before{font-weight:600; display:inline-block; width:120px}\n }\n .summary-list strong,\n .summary-list li {\n padding: 2px 4px;\n }\n </style>\n </head>\n <body>\n <h1>Aria-Ease Accessibility Audit Report</h1>\n ${headerSummary}\n <table>\n <thead>\n <tr>\n <th>URL</th><th>Rule</th><th>Impact</th><th>Description</th><th>Target</th><th>FailureSummary</th>\n </tr>\n </thead>\n <tbody>\n ${rows.join('\\n') || '<tr><td colspan=\"6\"><em>No violations found.</em></td></tr>'}\n </tbody>\n </table>\n </body>\n </html>\n `.trim();\n\n return html;\n}\n\nfunction escapeHTML(str: unknown): string {\n return String(str ?? '')\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>')\n .replaceAll('\"', '"')\n .replaceAll(\"'\", ''');\n}\n\nfunction escapeClass(s: string): string {\n return String(s ?? '').toLowerCase().replace(/[^a-z0-9]+/g, '-');\n}","/**\n * Runs static and interactions accessibility test on UI components. \n * @param {HTMLElement} component The UI component to be tested\n * @param {string} url Optional URL to run full Playwright E2E tests (requires dev server running)\n*/\n\nimport { axe } from \"jest-axe\";\nimport type { JestAxeResult } from \"Types\";\nimport { runContractTests } from \"../contract/contractTestRunner\";\n\n\nexport async function testUiComponent(componentName: string, component: HTMLElement, url?: string): Promise<JestAxeResult> {\n const results = await axe(component);\n \n let contract;\n \n if (url) {\n console.log(`๐ญ Running Playwright E2E tests on ${url}`);\n const { runContractTestsPlaywright } = await import(\"../contract/contractTestRunnerPlaywright\");\n contract = await runContractTestsPlaywright(componentName, url);\n } else {\n console.log(`๐งช Running jsdom tests (limited event handling)`);\n contract = await runContractTests(componentName, component);\n }\n \n const result = {\n violations: results.violations,\n raw: results,\n contract\n };\n \n // Throw helpful error if there are failures (use counts from reporter, not raw arrays)\n if (contract.failures.length > 0) {\n const mode = url ? 'Playwright' : 'jsdom';\n \n throw new Error(\n `\\nโ ${contract.failures.length} assertion${contract.failures.length > 1 ? 's' : ''} failed (${mode} mode)\\n` +\n `โ
${contract.passes.length} assertion${contract.passes.length > 1 ? 's' : ''} passed\\n\\n` +\n `๐ Review the detailed test report above for specific failures.`\n );\n }\n \n if (results.violations.length > 0) {\n const violationCount = results.violations.length;\n throw new Error(\n `\\nโ ${violationCount} axe accessibility violation${violationCount > 1 ? 's' : ''} detected\\n\\n` +\n `๐ Check result.violations for details`\n );\n }\n \n return result;\n}\n\nlet runTest = async () => {}\n\nif (typeof window === \"undefined\") {\n runTest = async () => {\n console.log(`๐ Running component accessibility tests...\\n`);\n\n const { exec } = await import(\"child_process\");\n\n exec(\n `npx vitest --run --reporter verbose`,\n { cwd: process.cwd() },\n (error, stdout, stderr) => {\n // Always output stdout (test results)\n if (stdout) {\n console.log(stdout);\n }\n \n // Always output stderr (ContractReporter output)\n if (stderr) {\n console.error(stderr);\n }\n \n // Exit with proper code (error.code will be set if vitest failed)\n if (error && error.code) {\n process.exit(error.code);\n }\n }\n );\n }\n}\n\nexport { runTest }","import path from \"path\";\nimport fs from \"fs-extra\";\nimport { AriaEaseConfig } from \"Types\";\n\n/**\n * Validates the structure of an AriaEase config object\n * @param config - The config object to validate\n * @returns Validation result with errors if any\n */\nfunction validateConfig(config: unknown): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n if (!config || typeof config !== 'object') {\n errors.push('Config must be an object');\n return { valid: false, errors };\n }\n\n const cfg = config as Partial<AriaEaseConfig>;\n\n // Validate audit config if present\n if (cfg.audit !== undefined) {\n if (typeof cfg.audit !== 'object' || cfg.audit === null) {\n errors.push('audit must be an object');\n } else {\n // Validate urls\n if (cfg.audit.urls !== undefined) {\n if (!Array.isArray(cfg.audit.urls)) {\n errors.push('audit.urls must be an array');\n } else if (cfg.audit.urls.some(url => typeof url !== 'string')) {\n errors.push('audit.urls must contain only strings');\n }\n }\n\n // Validate output format\n if (cfg.audit.output !== undefined) {\n if (typeof cfg.audit.output !== 'object') {\n errors.push('audit.output must be an object');\n } else {\n const output = cfg.audit.output as { format?: string; out?: string };\n if (output.format !== undefined) {\n if (!['json', 'csv', 'html', 'all'].includes(output.format)) {\n errors.push('audit.output.format must be one of: json, csv, html, all');\n }\n }\n if (output.out !== undefined && typeof output.out !== 'string') {\n errors.push('audit.output.out must be a string');\n }\n }\n }\n }\n }\n\n // Validate test config if present\n if (cfg.test !== undefined) {\n if (typeof cfg.test !== 'object' || cfg.test === null) {\n errors.push('test must be an object');\n } else {\n if (cfg.test.components !== undefined) {\n if (!Array.isArray(cfg.test.components)) {\n errors.push('test.components must be an array');\n } else {\n cfg.test.components.forEach((comp, idx) => {\n if (typeof comp !== 'object' || comp === null) {\n errors.push(`test.components[${idx}] must be an object`);\n } else {\n if (typeof comp.name !== 'string') {\n errors.push(`test.components[${idx}].name must be a string`);\n }\n if (typeof comp.path !== 'string') {\n errors.push(`test.components[${idx}].path must be a string`);\n }\n }\n });\n }\n }\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Attempts to load and parse a config file\n * @param filePath - Absolute path to the config file\n * @returns The parsed config or null if loading fails\n */\nasync function loadConfigFile(filePath: string): Promise<AriaEaseConfig | null> {\n try {\n const ext = path.extname(filePath);\n\n if (ext === '.json') {\n // Load JSON file\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content);\n } else if (['.js', '.mjs', '.cjs', '.ts'].includes(ext)) {\n // Dynamic import for JS/TS modules\n const imported = await import(filePath);\n // Handle both default export and named exports\n return imported.default || imported;\n }\n\n return null;\n } catch {\n // Return null on any error - caller will handle\n return null;\n }\n}\n\n/**\n * Searches for and loads an AriaEase config file\n * Checks for config files in this order:\n * - ariaease.config.js\n * - ariaease.config.mjs \n * - ariaease.config.cjs\n * - ariaease.config.json\n * - ariaease.config.ts\n * \n * @param cwd - Current working directory to search in\n * @returns Object containing the config and any errors\n */\nexport async function loadConfig(cwd: string = process.cwd()): Promise<{\n config: AriaEaseConfig;\n configPath: string | null;\n errors: string[];\n}> {\n const configNames = [\n 'ariaease.config.js',\n 'ariaease.config.mjs',\n 'ariaease.config.cjs',\n 'ariaease.config.json',\n 'ariaease.config.ts'\n ];\n\n let loadedConfig: AriaEaseConfig | null = null;\n let foundPath: string | null = null;\n const errors: string[] = [];\n\n // Try to find and load config\n for (const name of configNames) {\n const configPath = path.resolve(cwd, name);\n \n if (await fs.pathExists(configPath)) {\n foundPath = configPath;\n loadedConfig = await loadConfigFile(configPath);\n \n if (loadedConfig === null) {\n errors.push(`Found config at ${name} but failed to load it. Check for syntax errors.`);\n continue;\n }\n \n // Validate the loaded config\n const validation = validateConfig(loadedConfig);\n if (!validation.valid) {\n errors.push(`Config validation failed in ${name}:`);\n errors.push(...validation.errors.map(err => ` - ${err}`));\n loadedConfig = null;\n continue;\n }\n \n // Successfully loaded and validated\n break;\n }\n }\n\n return {\n config: loadedConfig || {},\n configPath: loadedConfig ? foundPath : null,\n errors\n };\n}\n"],"mappings":"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","names":["import_path","import_fs_extra","import_playwright","axe","AxeBuilder","path","fs","chalk","path","format","fs"]}
|
|
1
|
+
{"version":3,"sources":["cli.ts","../src/utils/audit/src/audit/audit.ts","../src/utils/audit/src/formatters/formatters.ts","../src/utils/test/src/test.ts","configLoader.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport path from \"path\";\nimport fs from \"fs-extra\";\nimport { AxeResult } from \"Types\";\nimport { runAudit } from \"../src/utils/audit/src/audit/audit\";\nimport { formatResults } from \"../src/utils/audit/src/formatters/formatters\";\nimport { runTest } from \"../src/utils/test/index\";\nimport { loadConfig } from \"./configLoader\";\n\nconst program = new Command();\n\nprogram.name('aria-ease').description('Run accessibility tests and audits').version('2.2.3');\n\nprogram.command('audit')\n.description('Run axe-core powered accessibility audit on webpages')\n.option('-u, --url <url>', 'Single URL to audit')\n.option('-f, --format <format>', 'Output format for the audit report: json | csv | html | all', 'all')\n.option('-o, --out <path>', 'Directory to save the audit report', './accessibility-reports/audit')\n.action(async (opts) => {\n console.log(chalk.cyanBright('๐ Starting accessibility audit...\\n'));\n\n // Load config with robust discovery and validation\n const { config, configPath, errors } = await loadConfig(process.cwd());\n \n if (configPath) {\n console.log(chalk.green(`โ
Loaded config from ${path.basename(configPath)}\\n`));\n } else if (errors.length > 0) {\n console.log(chalk.red('โ Config file errors:\\n'));\n errors.forEach(err => console.log(chalk.red(` ${err}`)));\n console.log('');\n process.exit(1);\n } else {\n console.log(chalk.yellow('โน๏ธ No config file found, using CLI options.\\n'));\n }\n\n const urls: string[] = [];\n if(opts.url) urls.push(opts.url);\n if(config.audit?.urls && Array.isArray(config.audit.urls)) urls.push(...config.audit.urls);\n\n const format: string = (config.audit?.output && (config.audit.output as { format?: string }).format) || opts.format;\n if(!['json', 'csv', 'html', 'all'].includes(format)) {\n console.log(chalk.red('โ Invalid format. Use \"json\", \"csv\", \"html\" or \"all\".'));\n process.exit(1);\n }\n\n if(urls.length === 0) {\n console.log(chalk.red('โ No URLs provided. Use --url option or add \"urls\" in config file'));\n process.exit(1);\n }\n\n const allResults: { url: string, result?: AxeResult }[] = [];\n const auditOptions = {\n timeout: config.audit?.timeout,\n waitUntil: config.audit?.waitUntil\n };\n \n for (const url of urls) {\n console.log(chalk.yellow(`๐ Auditing: ${url}`));\n try {\n const result: AxeResult = await runAudit(url, auditOptions);\n allResults.push({ url: url, result });\n console.log(chalk.green(`โ
Completed audit for ${url}\\n`));\n } catch (error: unknown) {\n if(error instanceof Error && error.message) {\n console.log(chalk.red(`โ Failed auditing ${url}: ${error.message}`));\n }\n }\n }\n\n const hasResults = allResults.some(r => r.result && r.result.violations && r.result.violations.length > 0);\n if (!hasResults) {\n const auditedCount = allResults.filter(r => r.result).length;\n if (auditedCount === 0) {\n console.log(chalk.red('โ No pages were successfully audited.'));\n process.exit(1);\n }\n console.log(chalk.green('\\n๐ Great news! No accessibility violations found!'));\n console.log(chalk.gray(` Audited ${auditedCount} page${auditedCount > 1 ? 's' : ''} successfully.\\n`));\n process.exit(0);\n }\n\n async function createReport(format: string) {\n const formatted = formatResults(allResults, format);\n\n const out = (config.audit?.output && (config.audit.output as { out?: string }).out) || opts.out;\n\n await fs.ensureDir(out);\n const d = new Date();\n const pad = (n: number) => String(n).padStart(2, '0');\n const timestamp = `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n const fileName = `ariaease-report-${timestamp}.${format}`;\n const filePath = path.join(out, fileName);\n\n await fs.writeFile(filePath, formatted, 'utf-8');\n console.log(chalk.magentaBright(`๐ Report saved to ${filePath}`));\n }\n\n if(['json', 'csv', 'html'].includes(format)) {\n await createReport(format);\n } else if(format === 'all') {\n await Promise.all(['json', 'csv', 'html'].map((format) => createReport(format)));\n }\n\n console.log(chalk.green('\\n๐ All audits completed.'));\n})\n\nprogram.command('test')\n.description('Run core a11y accessibility standard tests on UI components')\n.action(() => {\n runTest();\n})\n\nprogram.command('help')\n.description('Display help information')\n.action(() => {\n program.outputHelp();\n});\n\nprogram.parse(process.argv);","import AxeBuilder from \"@axe-core/playwright\";\nimport { chromium } from \"playwright\";\nimport type { AxeResult } from \"Types\";\n\nexport async function runAudit(url: string, options?: { timeout?: number; waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' }) {\n let browser;\n \n // Default to 60s timeout and domcontentloaded for better reliability\n const timeout = options?.timeout || 60000;\n const waitUntil = options?.waitUntil || 'domcontentloaded';\n\n try{ \n browser = await chromium.launch({ headless: true });\n const context = await browser.newContext();\n const page = await context.newPage();\n await page.goto(url, { waitUntil, timeout });\n const axe = new AxeBuilder({ page });\n const axeResults: AxeResult = await axe.analyze();\n return axeResults;\n } catch(error: unknown) {\n if (error instanceof Error) {\n if (error.message.includes(\"Executable doesn't exist\")) {\n console.error('\\nโ Playwright browsers not found!\\n');\n console.log('๐ฆ First-time setup required:');\n console.log(' Run: npx playwright install chromium\\n');\n console.log('๐ก This downloads the browser needed for auditing (~200MB)');\n console.log(' You only need to do this once.\\n');\n } else if(error.message.includes(\"page.goto: net::ERR_CONNECTION_REFUSED\")) {\n console.error('\\nโ Server Not Running!\\n');\n console.log(' Make sure your server is running before auditing URL');\n console.log(' Run: npm run dev # or your start command');\n } else if(error.message.includes(\"page.goto: Protocol error (Page.navigate): Cannot navigate to invalid URL\")) {\n console.error('\\nโ Cannot audit invalid URL\\n')\n } else {\n console.error('โ Audit error:', error.message);\n console.log(' Make sure you provide a valid URL');\n }\n } else {\n console.error('โ Audit error (non-Error):', String(error));\n }\n throw error;\n } finally {\n if(browser) await browser.close(); \n }\n}","import type { AxeResult } from \"Types\";\n\nexport function formatResults(allResults: { url: string; result?: AxeResult }[], format: string): string {\n switch (format) {\n case 'json':\n return JSON.stringify(\n allResults.flatMap(({ url, result }) =>\n result\n ? result.violations.flatMap(v =>\n v.nodes.map(n => ({\n URL: url,\n Rule: v.id,\n Impact: v.impact,\n Description: v.description,\n Target: n.target,\n FailureSummary: n.failureSummary\n }))\n )\n : []\n ),\n null,\n 2\n );\n case 'csv':\n return toCSV(allResults);\n case 'html':\n return toHTML(allResults);\n default:\n return '';\n }\n}\n\nfunction toCSV(allResults: { url: string, result?: AxeResult }[]) {\n const rows = ['URL,Rule,Impact,Description,Target,FailureSummary'];\n allResults.forEach(({ url, result }: { url: string, result?: AxeResult }) => {\n if(result) {\n result.violations.forEach(v => {\n v.nodes.forEach(n => {\n rows.push(escapeCSV(url) + ',' +\n escapeCSV(v.id) + ',' +\n escapeCSV(v.impact) + ',' +\n escapeCSV(v.description) + ',' +\n escapeCSV(Array.isArray(n.target) ? n.target.join('; ') : String(n.target)) + ',' +\n escapeCSV(n.failureSummary ?? '')\n );\n });\n });\n }\n });\n return rows.join('\\n');\n}\n\nfunction escapeCSV(value: unknown): string {\n const s = String(value ?? '');\n return `\"${s.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction toHTML(allResults: { url: string, result?: AxeResult }[]) {\n const summary = {\n pagesAudited: 0,\n pagesWithViolations: 0,\n totalViolations: 0,\n distinctRules: new Set<string>(),\n impactCounts: new Map<string, number>()\n };\n\n allResults.forEach(({ result }) => {\n if (!result) return;\n summary.pagesAudited++;\n const pageViolations = result.violations.reduce((acc, v) => {\n const nodesCount = (v.nodes || []).length;\n if (nodesCount > 0) {\n summary.distinctRules.add(v.id);\n summary.totalViolations += nodesCount;\n acc += nodesCount;\n const impact = String(v.impact ?? 'unknown');\n summary.impactCounts.set(impact, (summary.impactCounts.get(impact) || 0) + nodesCount);\n }\n return acc;\n }, 0);\n if (pageViolations > 0) summary.pagesWithViolations++;\n });\n\n const rows: string[] = [];\n allResults.forEach(({ url, result }) => {\n if (!result) return;\n result.violations.forEach(v => {\n v.nodes.forEach(n => {\n const target = Array.isArray(n.target) ? n.target.join('; ') : String(n.target);\n rows.push(`\n <tr>\n <td class=\"nowrap\">${escapeHTML(url)}</td>\n <td class=\"nowrap\">${escapeHTML(v.id)}</td>\n <td class=\"impact ${escapeClass(String(v.impact ?? 'unknown'))}\">${escapeHTML(String(v.impact ?? ''))}</td>\n <td class=\"desc\">${escapeHTML(v.description ?? '')}</td>\n <td class=\"target\"><code>${escapeHTML(target)}</code></td>\n <td class=\"fail\">${escapeHTML(n.failureSummary ?? '').split(/\\r?\\n/).join('<br/>')}</td>\n </tr>\n `);\n });\n });\n });\n\n const impactSummary = Array.from(summary.impactCounts.entries()).map(([impact, count]) => `<li><strong class=\"impact ${escapeClass(impact)}\">${escapeHTML(impact)}</strong>: ${count}</li>`).join('\\n');\n const d = new Date();\n const pad = (n: number) => String(n).padStart(2, '0');\n const reportDateTime = `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n const headerSummary = `\n <section class=\"summary\">\n <h2>Report summary</h2>\n <ul>\n <li><strong>Date:</strong> ${reportDateTime}</li>\n <li><strong>Pages audited:</strong> ${summary.pagesAudited}</li>\n <li><strong>Pages with violations:</strong> ${summary.pagesWithViolations}</li>\n <li><strong>Total violations:</strong> ${summary.totalViolations}</li>\n <li><strong>Distinct rules:</strong> ${summary.distinctRules.size}</li>\n </ul>\n <div class=\"impact-summary\">\n <h3>By impact</h3>\n <ul class=\"summary-list\">\n ${impactSummary || '<li>None</li>'}\n </ul>\n </div>\n </section>\n `.trim();\n\n const html = `\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"utf-8\"/>\n <title>Aria-Ease Accessibility Audit Report</title>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n <style>\n :root{\n --bg:#ffffff; --muted:#6b7280; --border:#e6e9ee;\n --impact-critical: red; --impact-moderate:#fff4dd; --impact-serious:rgb(255, 123, 0);\n }\n body{font-family:Inter,ui-sans-serif,system-ui,Segoe UI,Roboto,Helvetica,Arial; background:var(--bg); color:#111827; padding:24px; line-height:1.4}\n h1{margin:0 0 8px}\n .summary{background:#f8fafc;border:1px solid var(--border);padding:12px 16px;border-radius:8px;margin-bottom:18px}\n .summary ul{margin:6px 0 0 0;padding:0 18px}\n .impact-summary h3{margin:12px 0 6px}\n table{width:100%; border-collapse:collapse; margin-top:12px}\n th,td{border:1px solid var(--border); padding:10px; text-align:left; vertical-align:top}\n th{background:#f3f4f6; font-weight:600; position:sticky; top:0; z-index:1}\n .nowrap{white-space:nowrap}\n .target code{font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, \"Roboto Mono\", \"Courier New\", monospace; white-space:pre-wrap}\n .desc{max-width:380px}\n tr:nth-child(even){background:#fbfbfb}\n td.fail{color:#7b1e1e}\n .impact.critical{background:var(--impact-critical); font-weight:600}\n .impact.moderate{background:var(--impact-moderate); font-weight:600}\n .impact.serious{background:var(--impact-serious); font-weight:600}\n @media (max-width:900px){\n .desc{max-width:200px}\n table, thead, tbody, th, td, tr{display:block}\n thead{display:none}\n tr{margin-bottom:10px; border: 1px solid var(--border);}\n td{border:1px solid var(--border); padding:6px}\n td::before{font-weight:600; display:inline-block; width:120px}\n }\n .summary-list strong,\n .summary-list li {\n padding: 2px 4px;\n }\n </style>\n </head>\n <body>\n <h1>Aria-Ease Accessibility Audit Report</h1>\n ${headerSummary}\n <table>\n <thead>\n <tr>\n <th>URL</th><th>Rule</th><th>Impact</th><th>Description</th><th>Target</th><th>FailureSummary</th>\n </tr>\n </thead>\n <tbody>\n ${rows.join('\\n') || '<tr><td colspan=\"6\"><em>No violations found.</em></td></tr>'}\n </tbody>\n </table>\n </body>\n </html>\n `.trim();\n\n return html;\n}\n\nfunction escapeHTML(str: unknown): string {\n return String(str ?? '')\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>')\n .replaceAll('\"', '"')\n .replaceAll(\"'\", ''');\n}\n\nfunction escapeClass(s: string): string {\n return String(s ?? '').toLowerCase().replace(/[^a-z0-9]+/g, '-');\n}","/**\n * Runs static and interactions accessibility test on UI components. \n * @param {HTMLElement} component The UI component to be tested\n * @param {string} url Optional URL to run full Playwright E2E tests (requires dev server running)\n*/\n\nimport { axe } from \"jest-axe\";\nimport type { JestAxeResult } from \"Types\";\nimport { runContractTests } from \"../contract/contractTestRunner\";\n\n\nexport async function testUiComponent(componentName: string, component: HTMLElement, url?: string): Promise<JestAxeResult> {\n const results = await axe(component);\n \n let contract;\n \n if (url) {\n console.log(`๐ญ Running Playwright E2E tests on ${url}`);\n const { runContractTestsPlaywright } = await import(\"../contract/contractTestRunnerPlaywright\");\n contract = await runContractTestsPlaywright(componentName, url);\n } else {\n console.log(`๐งช Running jsdom tests (limited event handling)`);\n contract = await runContractTests(componentName, component);\n }\n \n const result = {\n violations: results.violations,\n raw: results,\n contract\n };\n \n // Throw helpful error if there are failures (use counts from reporter, not raw arrays)\n if (contract.failures.length > 0) {\n const mode = url ? 'Playwright' : 'jsdom';\n \n throw new Error(\n `\\nโ ${contract.failures.length} assertion${contract.failures.length > 1 ? 's' : ''} failed (${mode} mode)\\n` +\n `โ
${contract.passes.length} assertion${contract.passes.length > 1 ? 's' : ''} passed\\n\\n` +\n `๐ Review the detailed test report above for specific failures.`\n );\n }\n \n if (results.violations.length > 0) {\n const violationCount = results.violations.length;\n throw new Error(\n `\\nโ ${violationCount} axe accessibility violation${violationCount > 1 ? 's' : ''} detected\\n\\n` +\n `๐ Check result.violations for details`\n );\n }\n \n return result;\n}\n\nlet runTest = async () => {}\n\nif (typeof window === \"undefined\") {\n runTest = async () => {\n console.log(`๐ Running component accessibility tests...\\n`);\n\n const { exec } = await import(\"child_process\");\n\n exec(\n `npx vitest --run --reporter verbose`,\n { cwd: process.cwd() },\n (error, stdout, stderr) => {\n // Always output stdout (test results)\n if (stdout) {\n console.log(stdout);\n }\n \n // Always output stderr (ContractReporter output)\n if (stderr) {\n console.error(stderr);\n }\n \n // Exit with proper code (error.code will be set if vitest failed)\n if (error && error.code) {\n process.exit(error.code);\n }\n }\n );\n }\n}\n\nexport { runTest }","import path from \"path\";\nimport fs from \"fs-extra\";\nimport { AriaEaseConfig } from \"Types\";\n\n/**\n * Validates the structure of an AriaEase config object\n * @param config - The config object to validate\n * @returns Validation result with errors if any\n */\nfunction validateConfig(config: unknown): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n if (!config || typeof config !== 'object') {\n errors.push('Config must be an object');\n return { valid: false, errors };\n }\n\n const cfg = config as Partial<AriaEaseConfig>;\n\n // Validate audit config if present\n if (cfg.audit !== undefined) {\n if (typeof cfg.audit !== 'object' || cfg.audit === null) {\n errors.push('audit must be an object');\n } else {\n // Validate urls\n if (cfg.audit.urls !== undefined) {\n if (!Array.isArray(cfg.audit.urls)) {\n errors.push('audit.urls must be an array');\n } else if (cfg.audit.urls.some(url => typeof url !== 'string')) {\n errors.push('audit.urls must contain only strings');\n }\n }\n\n // Validate output format\n if (cfg.audit.output !== undefined) {\n if (typeof cfg.audit.output !== 'object') {\n errors.push('audit.output must be an object');\n } else {\n const output = cfg.audit.output as { format?: string; out?: string };\n if (output.format !== undefined) {\n if (!['json', 'csv', 'html', 'all'].includes(output.format)) {\n errors.push('audit.output.format must be one of: json, csv, html, all');\n }\n }\n if (output.out !== undefined && typeof output.out !== 'string') {\n errors.push('audit.output.out must be a string');\n }\n }\n }\n }\n }\n\n // Validate test config if present\n if (cfg.test !== undefined) {\n if (typeof cfg.test !== 'object' || cfg.test === null) {\n errors.push('test must be an object');\n } else {\n if (cfg.test.components !== undefined) {\n if (!Array.isArray(cfg.test.components)) {\n errors.push('test.components must be an array');\n } else {\n cfg.test.components.forEach((comp, idx) => {\n if (typeof comp !== 'object' || comp === null) {\n errors.push(`test.components[${idx}] must be an object`);\n } else {\n if (typeof comp.name !== 'string') {\n errors.push(`test.components[${idx}].name must be a string`);\n }\n if (typeof comp.path !== 'string') {\n errors.push(`test.components[${idx}].path must be a string`);\n }\n }\n });\n }\n }\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Attempts to load and parse a config file\n * @param filePath - Absolute path to the config file\n * @returns The parsed config or null if loading fails\n */\nasync function loadConfigFile(filePath: string): Promise<AriaEaseConfig | null> {\n try {\n const ext = path.extname(filePath);\n\n if (ext === '.json') {\n // Load JSON file\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content);\n } else if (['.js', '.mjs', '.cjs', '.ts'].includes(ext)) {\n // Dynamic import for JS/TS modules\n const imported = await import(filePath);\n // Handle both default export and named exports\n return imported.default || imported;\n }\n\n return null;\n } catch {\n // Return null on any error - caller will handle\n return null;\n }\n}\n\n/**\n * Searches for and loads an AriaEase config file\n * Checks for config files in this order:\n * - ariaease.config.js\n * - ariaease.config.mjs \n * - ariaease.config.cjs\n * - ariaease.config.json\n * - ariaease.config.ts\n * \n * @param cwd - Current working directory to search in\n * @returns Object containing the config and any errors\n */\nexport async function loadConfig(cwd: string = process.cwd()): Promise<{\n config: AriaEaseConfig;\n configPath: string | null;\n errors: string[];\n}> {\n const configNames = [\n 'ariaease.config.js',\n 'ariaease.config.mjs',\n 'ariaease.config.cjs',\n 'ariaease.config.json',\n 'ariaease.config.ts'\n ];\n\n let loadedConfig: AriaEaseConfig | null = null;\n let foundPath: string | null = null;\n const errors: string[] = [];\n\n // Try to find and load config\n for (const name of configNames) {\n const configPath = path.resolve(cwd, name);\n \n if (await fs.pathExists(configPath)) {\n foundPath = configPath;\n loadedConfig = await loadConfigFile(configPath);\n \n if (loadedConfig === null) {\n errors.push(`Found config at ${name} but failed to load it. Check for syntax errors.`);\n continue;\n }\n \n // Validate the loaded config\n const validation = validateConfig(loadedConfig);\n if (!validation.valid) {\n errors.push(`Config validation failed in ${name}:`);\n errors.push(...validation.errors.map(err => ` - ${err}`));\n loadedConfig = null;\n continue;\n }\n \n // Successfully loaded and validated\n break;\n }\n }\n\n return {\n config: loadedConfig || {},\n configPath: loadedConfig ? foundPath : null,\n errors\n };\n}\n"],"mappings":"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","names":["import_path","import_fs_extra","import_playwright","axe","AxeBuilder","path","fs","chalk","path","format","fs"]}
|
package/bin/cli.js
CHANGED
|
@@ -9,13 +9,15 @@ import fs2 from "fs-extra";
|
|
|
9
9
|
// src/utils/audit/src/audit/audit.ts
|
|
10
10
|
import AxeBuilder from "@axe-core/playwright";
|
|
11
11
|
import { chromium } from "playwright";
|
|
12
|
-
async function runAudit(url) {
|
|
12
|
+
async function runAudit(url, options) {
|
|
13
13
|
let browser;
|
|
14
|
+
const timeout = options?.timeout || 6e4;
|
|
15
|
+
const waitUntil = options?.waitUntil || "domcontentloaded";
|
|
14
16
|
try {
|
|
15
17
|
browser = await chromium.launch({ headless: true });
|
|
16
18
|
const context = await browser.newContext();
|
|
17
19
|
const page = await context.newPage();
|
|
18
|
-
await page.goto(url, { waitUntil
|
|
20
|
+
await page.goto(url, { waitUntil, timeout });
|
|
19
21
|
const axe2 = new AxeBuilder({ page });
|
|
20
22
|
const axeResults = await axe2.analyze();
|
|
21
23
|
return axeResults;
|
|
@@ -398,10 +400,14 @@ program.command("audit").description("Run axe-core powered accessibility audit o
|
|
|
398
400
|
process.exit(1);
|
|
399
401
|
}
|
|
400
402
|
const allResults = [];
|
|
403
|
+
const auditOptions = {
|
|
404
|
+
timeout: config.audit?.timeout,
|
|
405
|
+
waitUntil: config.audit?.waitUntil
|
|
406
|
+
};
|
|
401
407
|
for (const url of urls) {
|
|
402
408
|
console.log(chalk.yellow(`\u{1F50E} Auditing: ${url}`));
|
|
403
409
|
try {
|
|
404
|
-
const result = await runAudit(url);
|
|
410
|
+
const result = await runAudit(url, auditOptions);
|
|
405
411
|
allResults.push({ url, result });
|
|
406
412
|
console.log(chalk.green(`\u2705 Completed audit for ${url}
|
|
407
413
|
`));
|
package/bin/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["cli.ts","../src/utils/audit/src/audit/audit.ts","../src/utils/audit/src/formatters/formatters.ts","../src/utils/test/src/test.ts","configLoader.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport path from \"path\";\nimport fs from \"fs-extra\";\nimport { AxeResult } from \"Types\";\nimport { runAudit } from \"../src/utils/audit/src/audit/audit\";\nimport { formatResults } from \"../src/utils/audit/src/formatters/formatters\";\nimport { runTest } from \"../src/utils/test/index\";\nimport { loadConfig } from \"./configLoader\";\n\nconst program = new Command();\n\nprogram.name('aria-ease').description('Run accessibility tests and audits').version('2.2.3');\n\nprogram.command('audit')\n.description('Run axe-core powered accessibility audit on webpages')\n.option('-u, --url <url>', 'Single URL to audit')\n.option('-f, --format <format>', 'Output format for the audit report: json | csv | html | all', 'all')\n.option('-o, --out <path>', 'Directory to save the audit report', './accessibility-reports/audit')\n.action(async (opts) => {\n console.log(chalk.cyanBright('๐ Starting accessibility audit...\\n'));\n\n // Load config with robust discovery and validation\n const { config, configPath, errors } = await loadConfig(process.cwd());\n \n if (configPath) {\n console.log(chalk.green(`โ
Loaded config from ${path.basename(configPath)}\\n`));\n } else if (errors.length > 0) {\n console.log(chalk.red('โ Config file errors:\\n'));\n errors.forEach(err => console.log(chalk.red(` ${err}`)));\n console.log('');\n process.exit(1);\n } else {\n console.log(chalk.yellow('โน๏ธ No config file found, using CLI options.\\n'));\n }\n\n const urls: string[] = [];\n if(opts.url) urls.push(opts.url);\n if(config.audit?.urls && Array.isArray(config.audit.urls)) urls.push(...config.audit.urls);\n\n const format: string = (config.audit?.output && (config.audit.output as { format?: string }).format) || opts.format;\n if(!['json', 'csv', 'html', 'all'].includes(format)) {\n console.log(chalk.red('โ Invalid format. Use \"json\", \"csv\", \"html\" or \"all\".'));\n process.exit(1);\n }\n\n if(urls.length === 0) {\n console.log(chalk.red('โ No URLs provided. Use --url option or add \"urls\" in config file'));\n process.exit(1);\n }\n\n const allResults: { url: string, result?: AxeResult }[] = [];\n for (const url of urls) {\n console.log(chalk.yellow(`๐ Auditing: ${url}`));\n try {\n const result: AxeResult = await runAudit(url);\n allResults.push({ url: url, result });\n console.log(chalk.green(`โ
Completed audit for ${url}\\n`));\n } catch (error: unknown) {\n if(error instanceof Error && error.message) {\n console.log(chalk.red(`โ Failed auditing ${url}: ${error.message}`));\n }\n }\n }\n\n const hasResults = allResults.some(r => r.result && r.result.violations && r.result.violations.length > 0);\n if (!hasResults) {\n const auditedCount = allResults.filter(r => r.result).length;\n if (auditedCount === 0) {\n console.log(chalk.red('โ No pages were successfully audited.'));\n process.exit(1);\n }\n console.log(chalk.green('\\n๐ Great news! No accessibility violations found!'));\n console.log(chalk.gray(` Audited ${auditedCount} page${auditedCount > 1 ? 's' : ''} successfully.\\n`));\n process.exit(0);\n }\n\n async function createReport(format: string) {\n const formatted = formatResults(allResults, format);\n\n const out = (config.audit?.output && (config.audit.output as { out?: string }).out) || opts.out;\n\n await fs.ensureDir(out);\n const d = new Date();\n const pad = (n: number) => String(n).padStart(2, '0');\n const timestamp = `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n const fileName = `ariaease-report-${timestamp}.${format}`;\n const filePath = path.join(out, fileName);\n\n await fs.writeFile(filePath, formatted, 'utf-8');\n console.log(chalk.magentaBright(`๐ Report saved to ${filePath}`));\n }\n\n if(['json', 'csv', 'html'].includes(format)) {\n await createReport(format);\n } else if(format === 'all') {\n await Promise.all(['json', 'csv', 'html'].map((format) => createReport(format)));\n }\n\n console.log(chalk.green('\\n๐ All audits completed.'));\n})\n\nprogram.command('test')\n.description('Run core a11y accessibility standard tests on UI components')\n.action(() => {\n runTest();\n})\n\nprogram.command('help')\n.description('Display help information')\n.action(() => {\n program.outputHelp();\n});\n\nprogram.parse(process.argv);","import AxeBuilder from \"@axe-core/playwright\";\nimport { chromium } from \"playwright\";\nimport type { AxeResult } from \"Types\";\n\nexport async function runAudit(url: string) {\n let browser;\n\n try{ \n browser = await chromium.launch({ headless: true });\n const context = await browser.newContext();\n const page = await context.newPage();\n await page.goto(url, { waitUntil: 'networkidle' });\n const axe = new AxeBuilder({ page });\n const axeResults: AxeResult = await axe.analyze();\n return axeResults;\n } catch(error: unknown) {\n if (error instanceof Error) {\n if (error.message.includes(\"Executable doesn't exist\")) {\n console.error('\\nโ Playwright browsers not found!\\n');\n console.log('๐ฆ First-time setup required:');\n console.log(' Run: npx playwright install chromium\\n');\n console.log('๐ก This downloads the browser needed for auditing (~200MB)');\n console.log(' You only need to do this once.\\n');\n } else if(error.message.includes(\"page.goto: net::ERR_CONNECTION_REFUSED\")) {\n console.error('\\nโ Server Not Running!\\n');\n console.log(' Make sure your server is running before auditing URL');\n console.log(' Run: npm run dev # or your start command');\n } else if(error.message.includes(\"page.goto: Protocol error (Page.navigate): Cannot navigate to invalid URL\")) {\n console.error('\\nโ Cannot audit invalid URL\\n')\n } else {\n console.error('โ Audit error:', error.message);\n console.log(' Make sure you provide a valid URL');\n }\n } else {\n console.error('โ Audit error (non-Error):', String(error));\n }\n throw error;\n } finally {\n if(browser) await browser.close(); \n }\n}","import type { AxeResult } from \"Types\";\n\nexport function formatResults(allResults: { url: string; result?: AxeResult }[], format: string): string {\n switch (format) {\n case 'json':\n return JSON.stringify(\n allResults.flatMap(({ url, result }) =>\n result\n ? result.violations.flatMap(v =>\n v.nodes.map(n => ({\n URL: url,\n Rule: v.id,\n Impact: v.impact,\n Description: v.description,\n Target: n.target,\n FailureSummary: n.failureSummary\n }))\n )\n : []\n ),\n null,\n 2\n );\n case 'csv':\n return toCSV(allResults);\n case 'html':\n return toHTML(allResults);\n default:\n return '';\n }\n}\n\nfunction toCSV(allResults: { url: string, result?: AxeResult }[]) {\n const rows = ['URL,Rule,Impact,Description,Target,FailureSummary'];\n allResults.forEach(({ url, result }: { url: string, result?: AxeResult }) => {\n if(result) {\n result.violations.forEach(v => {\n v.nodes.forEach(n => {\n rows.push(escapeCSV(url) + ',' +\n escapeCSV(v.id) + ',' +\n escapeCSV(v.impact) + ',' +\n escapeCSV(v.description) + ',' +\n escapeCSV(Array.isArray(n.target) ? n.target.join('; ') : String(n.target)) + ',' +\n escapeCSV(n.failureSummary ?? '')\n );\n });\n });\n }\n });\n return rows.join('\\n');\n}\n\nfunction escapeCSV(value: unknown): string {\n const s = String(value ?? '');\n return `\"${s.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction toHTML(allResults: { url: string, result?: AxeResult }[]) {\n const summary = {\n pagesAudited: 0,\n pagesWithViolations: 0,\n totalViolations: 0,\n distinctRules: new Set<string>(),\n impactCounts: new Map<string, number>()\n };\n\n allResults.forEach(({ result }) => {\n if (!result) return;\n summary.pagesAudited++;\n const pageViolations = result.violations.reduce((acc, v) => {\n const nodesCount = (v.nodes || []).length;\n if (nodesCount > 0) {\n summary.distinctRules.add(v.id);\n summary.totalViolations += nodesCount;\n acc += nodesCount;\n const impact = String(v.impact ?? 'unknown');\n summary.impactCounts.set(impact, (summary.impactCounts.get(impact) || 0) + nodesCount);\n }\n return acc;\n }, 0);\n if (pageViolations > 0) summary.pagesWithViolations++;\n });\n\n const rows: string[] = [];\n allResults.forEach(({ url, result }) => {\n if (!result) return;\n result.violations.forEach(v => {\n v.nodes.forEach(n => {\n const target = Array.isArray(n.target) ? n.target.join('; ') : String(n.target);\n rows.push(`\n <tr>\n <td class=\"nowrap\">${escapeHTML(url)}</td>\n <td class=\"nowrap\">${escapeHTML(v.id)}</td>\n <td class=\"impact ${escapeClass(String(v.impact ?? 'unknown'))}\">${escapeHTML(String(v.impact ?? ''))}</td>\n <td class=\"desc\">${escapeHTML(v.description ?? '')}</td>\n <td class=\"target\"><code>${escapeHTML(target)}</code></td>\n <td class=\"fail\">${escapeHTML(n.failureSummary ?? '').split(/\\r?\\n/).join('<br/>')}</td>\n </tr>\n `);\n });\n });\n });\n\n const impactSummary = Array.from(summary.impactCounts.entries()).map(([impact, count]) => `<li><strong class=\"impact ${escapeClass(impact)}\">${escapeHTML(impact)}</strong>: ${count}</li>`).join('\\n');\n const d = new Date();\n const pad = (n: number) => String(n).padStart(2, '0');\n const reportDateTime = `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n const headerSummary = `\n <section class=\"summary\">\n <h2>Report summary</h2>\n <ul>\n <li><strong>Date:</strong> ${reportDateTime}</li>\n <li><strong>Pages audited:</strong> ${summary.pagesAudited}</li>\n <li><strong>Pages with violations:</strong> ${summary.pagesWithViolations}</li>\n <li><strong>Total violations:</strong> ${summary.totalViolations}</li>\n <li><strong>Distinct rules:</strong> ${summary.distinctRules.size}</li>\n </ul>\n <div class=\"impact-summary\">\n <h3>By impact</h3>\n <ul class=\"summary-list\">\n ${impactSummary || '<li>None</li>'}\n </ul>\n </div>\n </section>\n `.trim();\n\n const html = `\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"utf-8\"/>\n <title>Aria-Ease Accessibility Audit Report</title>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n <style>\n :root{\n --bg:#ffffff; --muted:#6b7280; --border:#e6e9ee;\n --impact-critical: red; --impact-moderate:#fff4dd; --impact-serious:rgb(255, 123, 0);\n }\n body{font-family:Inter,ui-sans-serif,system-ui,Segoe UI,Roboto,Helvetica,Arial; background:var(--bg); color:#111827; padding:24px; line-height:1.4}\n h1{margin:0 0 8px}\n .summary{background:#f8fafc;border:1px solid var(--border);padding:12px 16px;border-radius:8px;margin-bottom:18px}\n .summary ul{margin:6px 0 0 0;padding:0 18px}\n .impact-summary h3{margin:12px 0 6px}\n table{width:100%; border-collapse:collapse; margin-top:12px}\n th,td{border:1px solid var(--border); padding:10px; text-align:left; vertical-align:top}\n th{background:#f3f4f6; font-weight:600; position:sticky; top:0; z-index:1}\n .nowrap{white-space:nowrap}\n .target code{font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, \"Roboto Mono\", \"Courier New\", monospace; white-space:pre-wrap}\n .desc{max-width:380px}\n tr:nth-child(even){background:#fbfbfb}\n td.fail{color:#7b1e1e}\n .impact.critical{background:var(--impact-critical); font-weight:600}\n .impact.moderate{background:var(--impact-moderate); font-weight:600}\n .impact.serious{background:var(--impact-serious); font-weight:600}\n @media (max-width:900px){\n .desc{max-width:200px}\n table, thead, tbody, th, td, tr{display:block}\n thead{display:none}\n tr{margin-bottom:10px; border: 1px solid var(--border);}\n td{border:1px solid var(--border); padding:6px}\n td::before{font-weight:600; display:inline-block; width:120px}\n }\n .summary-list strong,\n .summary-list li {\n padding: 2px 4px;\n }\n </style>\n </head>\n <body>\n <h1>Aria-Ease Accessibility Audit Report</h1>\n ${headerSummary}\n <table>\n <thead>\n <tr>\n <th>URL</th><th>Rule</th><th>Impact</th><th>Description</th><th>Target</th><th>FailureSummary</th>\n </tr>\n </thead>\n <tbody>\n ${rows.join('\\n') || '<tr><td colspan=\"6\"><em>No violations found.</em></td></tr>'}\n </tbody>\n </table>\n </body>\n </html>\n `.trim();\n\n return html;\n}\n\nfunction escapeHTML(str: unknown): string {\n return String(str ?? '')\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>')\n .replaceAll('\"', '"')\n .replaceAll(\"'\", ''');\n}\n\nfunction escapeClass(s: string): string {\n return String(s ?? '').toLowerCase().replace(/[^a-z0-9]+/g, '-');\n}","/**\n * Runs static and interactions accessibility test on UI components. \n * @param {HTMLElement} component The UI component to be tested\n * @param {string} url Optional URL to run full Playwright E2E tests (requires dev server running)\n*/\n\nimport { axe } from \"jest-axe\";\nimport type { JestAxeResult } from \"Types\";\nimport { runContractTests } from \"../contract/contractTestRunner\";\n\n\nexport async function testUiComponent(componentName: string, component: HTMLElement, url?: string): Promise<JestAxeResult> {\n const results = await axe(component);\n \n let contract;\n \n if (url) {\n console.log(`๐ญ Running Playwright E2E tests on ${url}`);\n const { runContractTestsPlaywright } = await import(\"../contract/contractTestRunnerPlaywright\");\n contract = await runContractTestsPlaywright(componentName, url);\n } else {\n console.log(`๐งช Running jsdom tests (limited event handling)`);\n contract = await runContractTests(componentName, component);\n }\n \n const result = {\n violations: results.violations,\n raw: results,\n contract\n };\n \n // Throw helpful error if there are failures (use counts from reporter, not raw arrays)\n if (contract.failures.length > 0) {\n const mode = url ? 'Playwright' : 'jsdom';\n \n throw new Error(\n `\\nโ ${contract.failures.length} assertion${contract.failures.length > 1 ? 's' : ''} failed (${mode} mode)\\n` +\n `โ
${contract.passes.length} assertion${contract.passes.length > 1 ? 's' : ''} passed\\n\\n` +\n `๐ Review the detailed test report above for specific failures.`\n );\n }\n \n if (results.violations.length > 0) {\n const violationCount = results.violations.length;\n throw new Error(\n `\\nโ ${violationCount} axe accessibility violation${violationCount > 1 ? 's' : ''} detected\\n\\n` +\n `๐ Check result.violations for details`\n );\n }\n \n return result;\n}\n\nlet runTest = async () => {}\n\nif (typeof window === \"undefined\") {\n runTest = async () => {\n console.log(`๐ Running component accessibility tests...\\n`);\n\n const { exec } = await import(\"child_process\");\n\n exec(\n `npx vitest --run --reporter verbose`,\n { cwd: process.cwd() },\n (error, stdout, stderr) => {\n // Always output stdout (test results)\n if (stdout) {\n console.log(stdout);\n }\n \n // Always output stderr (ContractReporter output)\n if (stderr) {\n console.error(stderr);\n }\n \n // Exit with proper code (error.code will be set if vitest failed)\n if (error && error.code) {\n process.exit(error.code);\n }\n }\n );\n }\n}\n\nexport { runTest }","import path from \"path\";\nimport fs from \"fs-extra\";\nimport { AriaEaseConfig } from \"Types\";\n\n/**\n * Validates the structure of an AriaEase config object\n * @param config - The config object to validate\n * @returns Validation result with errors if any\n */\nfunction validateConfig(config: unknown): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n if (!config || typeof config !== 'object') {\n errors.push('Config must be an object');\n return { valid: false, errors };\n }\n\n const cfg = config as Partial<AriaEaseConfig>;\n\n // Validate audit config if present\n if (cfg.audit !== undefined) {\n if (typeof cfg.audit !== 'object' || cfg.audit === null) {\n errors.push('audit must be an object');\n } else {\n // Validate urls\n if (cfg.audit.urls !== undefined) {\n if (!Array.isArray(cfg.audit.urls)) {\n errors.push('audit.urls must be an array');\n } else if (cfg.audit.urls.some(url => typeof url !== 'string')) {\n errors.push('audit.urls must contain only strings');\n }\n }\n\n // Validate output format\n if (cfg.audit.output !== undefined) {\n if (typeof cfg.audit.output !== 'object') {\n errors.push('audit.output must be an object');\n } else {\n const output = cfg.audit.output as { format?: string; out?: string };\n if (output.format !== undefined) {\n if (!['json', 'csv', 'html', 'all'].includes(output.format)) {\n errors.push('audit.output.format must be one of: json, csv, html, all');\n }\n }\n if (output.out !== undefined && typeof output.out !== 'string') {\n errors.push('audit.output.out must be a string');\n }\n }\n }\n }\n }\n\n // Validate test config if present\n if (cfg.test !== undefined) {\n if (typeof cfg.test !== 'object' || cfg.test === null) {\n errors.push('test must be an object');\n } else {\n if (cfg.test.components !== undefined) {\n if (!Array.isArray(cfg.test.components)) {\n errors.push('test.components must be an array');\n } else {\n cfg.test.components.forEach((comp, idx) => {\n if (typeof comp !== 'object' || comp === null) {\n errors.push(`test.components[${idx}] must be an object`);\n } else {\n if (typeof comp.name !== 'string') {\n errors.push(`test.components[${idx}].name must be a string`);\n }\n if (typeof comp.path !== 'string') {\n errors.push(`test.components[${idx}].path must be a string`);\n }\n }\n });\n }\n }\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Attempts to load and parse a config file\n * @param filePath - Absolute path to the config file\n * @returns The parsed config or null if loading fails\n */\nasync function loadConfigFile(filePath: string): Promise<AriaEaseConfig | null> {\n try {\n const ext = path.extname(filePath);\n\n if (ext === '.json') {\n // Load JSON file\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content);\n } else if (['.js', '.mjs', '.cjs', '.ts'].includes(ext)) {\n // Dynamic import for JS/TS modules\n const imported = await import(filePath);\n // Handle both default export and named exports\n return imported.default || imported;\n }\n\n return null;\n } catch {\n // Return null on any error - caller will handle\n return null;\n }\n}\n\n/**\n * Searches for and loads an AriaEase config file\n * Checks for config files in this order:\n * - ariaease.config.js\n * - ariaease.config.mjs \n * - ariaease.config.cjs\n * - ariaease.config.json\n * - ariaease.config.ts\n * \n * @param cwd - Current working directory to search in\n * @returns Object containing the config and any errors\n */\nexport async function loadConfig(cwd: string = process.cwd()): Promise<{\n config: AriaEaseConfig;\n configPath: string | null;\n errors: string[];\n}> {\n const configNames = [\n 'ariaease.config.js',\n 'ariaease.config.mjs',\n 'ariaease.config.cjs',\n 'ariaease.config.json',\n 'ariaease.config.ts'\n ];\n\n let loadedConfig: AriaEaseConfig | null = null;\n let foundPath: string | null = null;\n const errors: string[] = [];\n\n // Try to find and load config\n for (const name of configNames) {\n const configPath = path.resolve(cwd, name);\n \n if (await fs.pathExists(configPath)) {\n foundPath = configPath;\n loadedConfig = await loadConfigFile(configPath);\n \n if (loadedConfig === null) {\n errors.push(`Found config at ${name} but failed to load it. Check for syntax errors.`);\n continue;\n }\n \n // Validate the loaded config\n const validation = validateConfig(loadedConfig);\n if (!validation.valid) {\n errors.push(`Config validation failed in ${name}:`);\n errors.push(...validation.errors.map(err => ` - ${err}`));\n loadedConfig = null;\n continue;\n }\n \n // Successfully loaded and validated\n break;\n }\n }\n\n return {\n config: loadedConfig || {},\n configPath: loadedConfig ? foundPath : null,\n errors\n };\n}\n"],"mappings":"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","names":["path","fs","axe","path","format","fs"]}
|
|
1
|
+
{"version":3,"sources":["cli.ts","../src/utils/audit/src/audit/audit.ts","../src/utils/audit/src/formatters/formatters.ts","../src/utils/test/src/test.ts","configLoader.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport path from \"path\";\nimport fs from \"fs-extra\";\nimport { AxeResult } from \"Types\";\nimport { runAudit } from \"../src/utils/audit/src/audit/audit\";\nimport { formatResults } from \"../src/utils/audit/src/formatters/formatters\";\nimport { runTest } from \"../src/utils/test/index\";\nimport { loadConfig } from \"./configLoader\";\n\nconst program = new Command();\n\nprogram.name('aria-ease').description('Run accessibility tests and audits').version('2.2.3');\n\nprogram.command('audit')\n.description('Run axe-core powered accessibility audit on webpages')\n.option('-u, --url <url>', 'Single URL to audit')\n.option('-f, --format <format>', 'Output format for the audit report: json | csv | html | all', 'all')\n.option('-o, --out <path>', 'Directory to save the audit report', './accessibility-reports/audit')\n.action(async (opts) => {\n console.log(chalk.cyanBright('๐ Starting accessibility audit...\\n'));\n\n // Load config with robust discovery and validation\n const { config, configPath, errors } = await loadConfig(process.cwd());\n \n if (configPath) {\n console.log(chalk.green(`โ
Loaded config from ${path.basename(configPath)}\\n`));\n } else if (errors.length > 0) {\n console.log(chalk.red('โ Config file errors:\\n'));\n errors.forEach(err => console.log(chalk.red(` ${err}`)));\n console.log('');\n process.exit(1);\n } else {\n console.log(chalk.yellow('โน๏ธ No config file found, using CLI options.\\n'));\n }\n\n const urls: string[] = [];\n if(opts.url) urls.push(opts.url);\n if(config.audit?.urls && Array.isArray(config.audit.urls)) urls.push(...config.audit.urls);\n\n const format: string = (config.audit?.output && (config.audit.output as { format?: string }).format) || opts.format;\n if(!['json', 'csv', 'html', 'all'].includes(format)) {\n console.log(chalk.red('โ Invalid format. Use \"json\", \"csv\", \"html\" or \"all\".'));\n process.exit(1);\n }\n\n if(urls.length === 0) {\n console.log(chalk.red('โ No URLs provided. Use --url option or add \"urls\" in config file'));\n process.exit(1);\n }\n\n const allResults: { url: string, result?: AxeResult }[] = [];\n const auditOptions = {\n timeout: config.audit?.timeout,\n waitUntil: config.audit?.waitUntil\n };\n \n for (const url of urls) {\n console.log(chalk.yellow(`๐ Auditing: ${url}`));\n try {\n const result: AxeResult = await runAudit(url, auditOptions);\n allResults.push({ url: url, result });\n console.log(chalk.green(`โ
Completed audit for ${url}\\n`));\n } catch (error: unknown) {\n if(error instanceof Error && error.message) {\n console.log(chalk.red(`โ Failed auditing ${url}: ${error.message}`));\n }\n }\n }\n\n const hasResults = allResults.some(r => r.result && r.result.violations && r.result.violations.length > 0);\n if (!hasResults) {\n const auditedCount = allResults.filter(r => r.result).length;\n if (auditedCount === 0) {\n console.log(chalk.red('โ No pages were successfully audited.'));\n process.exit(1);\n }\n console.log(chalk.green('\\n๐ Great news! No accessibility violations found!'));\n console.log(chalk.gray(` Audited ${auditedCount} page${auditedCount > 1 ? 's' : ''} successfully.\\n`));\n process.exit(0);\n }\n\n async function createReport(format: string) {\n const formatted = formatResults(allResults, format);\n\n const out = (config.audit?.output && (config.audit.output as { out?: string }).out) || opts.out;\n\n await fs.ensureDir(out);\n const d = new Date();\n const pad = (n: number) => String(n).padStart(2, '0');\n const timestamp = `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n const fileName = `ariaease-report-${timestamp}.${format}`;\n const filePath = path.join(out, fileName);\n\n await fs.writeFile(filePath, formatted, 'utf-8');\n console.log(chalk.magentaBright(`๐ Report saved to ${filePath}`));\n }\n\n if(['json', 'csv', 'html'].includes(format)) {\n await createReport(format);\n } else if(format === 'all') {\n await Promise.all(['json', 'csv', 'html'].map((format) => createReport(format)));\n }\n\n console.log(chalk.green('\\n๐ All audits completed.'));\n})\n\nprogram.command('test')\n.description('Run core a11y accessibility standard tests on UI components')\n.action(() => {\n runTest();\n})\n\nprogram.command('help')\n.description('Display help information')\n.action(() => {\n program.outputHelp();\n});\n\nprogram.parse(process.argv);","import AxeBuilder from \"@axe-core/playwright\";\nimport { chromium } from \"playwright\";\nimport type { AxeResult } from \"Types\";\n\nexport async function runAudit(url: string, options?: { timeout?: number; waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' }) {\n let browser;\n \n // Default to 60s timeout and domcontentloaded for better reliability\n const timeout = options?.timeout || 60000;\n const waitUntil = options?.waitUntil || 'domcontentloaded';\n\n try{ \n browser = await chromium.launch({ headless: true });\n const context = await browser.newContext();\n const page = await context.newPage();\n await page.goto(url, { waitUntil, timeout });\n const axe = new AxeBuilder({ page });\n const axeResults: AxeResult = await axe.analyze();\n return axeResults;\n } catch(error: unknown) {\n if (error instanceof Error) {\n if (error.message.includes(\"Executable doesn't exist\")) {\n console.error('\\nโ Playwright browsers not found!\\n');\n console.log('๐ฆ First-time setup required:');\n console.log(' Run: npx playwright install chromium\\n');\n console.log('๐ก This downloads the browser needed for auditing (~200MB)');\n console.log(' You only need to do this once.\\n');\n } else if(error.message.includes(\"page.goto: net::ERR_CONNECTION_REFUSED\")) {\n console.error('\\nโ Server Not Running!\\n');\n console.log(' Make sure your server is running before auditing URL');\n console.log(' Run: npm run dev # or your start command');\n } else if(error.message.includes(\"page.goto: Protocol error (Page.navigate): Cannot navigate to invalid URL\")) {\n console.error('\\nโ Cannot audit invalid URL\\n')\n } else {\n console.error('โ Audit error:', error.message);\n console.log(' Make sure you provide a valid URL');\n }\n } else {\n console.error('โ Audit error (non-Error):', String(error));\n }\n throw error;\n } finally {\n if(browser) await browser.close(); \n }\n}","import type { AxeResult } from \"Types\";\n\nexport function formatResults(allResults: { url: string; result?: AxeResult }[], format: string): string {\n switch (format) {\n case 'json':\n return JSON.stringify(\n allResults.flatMap(({ url, result }) =>\n result\n ? result.violations.flatMap(v =>\n v.nodes.map(n => ({\n URL: url,\n Rule: v.id,\n Impact: v.impact,\n Description: v.description,\n Target: n.target,\n FailureSummary: n.failureSummary\n }))\n )\n : []\n ),\n null,\n 2\n );\n case 'csv':\n return toCSV(allResults);\n case 'html':\n return toHTML(allResults);\n default:\n return '';\n }\n}\n\nfunction toCSV(allResults: { url: string, result?: AxeResult }[]) {\n const rows = ['URL,Rule,Impact,Description,Target,FailureSummary'];\n allResults.forEach(({ url, result }: { url: string, result?: AxeResult }) => {\n if(result) {\n result.violations.forEach(v => {\n v.nodes.forEach(n => {\n rows.push(escapeCSV(url) + ',' +\n escapeCSV(v.id) + ',' +\n escapeCSV(v.impact) + ',' +\n escapeCSV(v.description) + ',' +\n escapeCSV(Array.isArray(n.target) ? n.target.join('; ') : String(n.target)) + ',' +\n escapeCSV(n.failureSummary ?? '')\n );\n });\n });\n }\n });\n return rows.join('\\n');\n}\n\nfunction escapeCSV(value: unknown): string {\n const s = String(value ?? '');\n return `\"${s.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction toHTML(allResults: { url: string, result?: AxeResult }[]) {\n const summary = {\n pagesAudited: 0,\n pagesWithViolations: 0,\n totalViolations: 0,\n distinctRules: new Set<string>(),\n impactCounts: new Map<string, number>()\n };\n\n allResults.forEach(({ result }) => {\n if (!result) return;\n summary.pagesAudited++;\n const pageViolations = result.violations.reduce((acc, v) => {\n const nodesCount = (v.nodes || []).length;\n if (nodesCount > 0) {\n summary.distinctRules.add(v.id);\n summary.totalViolations += nodesCount;\n acc += nodesCount;\n const impact = String(v.impact ?? 'unknown');\n summary.impactCounts.set(impact, (summary.impactCounts.get(impact) || 0) + nodesCount);\n }\n return acc;\n }, 0);\n if (pageViolations > 0) summary.pagesWithViolations++;\n });\n\n const rows: string[] = [];\n allResults.forEach(({ url, result }) => {\n if (!result) return;\n result.violations.forEach(v => {\n v.nodes.forEach(n => {\n const target = Array.isArray(n.target) ? n.target.join('; ') : String(n.target);\n rows.push(`\n <tr>\n <td class=\"nowrap\">${escapeHTML(url)}</td>\n <td class=\"nowrap\">${escapeHTML(v.id)}</td>\n <td class=\"impact ${escapeClass(String(v.impact ?? 'unknown'))}\">${escapeHTML(String(v.impact ?? ''))}</td>\n <td class=\"desc\">${escapeHTML(v.description ?? '')}</td>\n <td class=\"target\"><code>${escapeHTML(target)}</code></td>\n <td class=\"fail\">${escapeHTML(n.failureSummary ?? '').split(/\\r?\\n/).join('<br/>')}</td>\n </tr>\n `);\n });\n });\n });\n\n const impactSummary = Array.from(summary.impactCounts.entries()).map(([impact, count]) => `<li><strong class=\"impact ${escapeClass(impact)}\">${escapeHTML(impact)}</strong>: ${count}</li>`).join('\\n');\n const d = new Date();\n const pad = (n: number) => String(n).padStart(2, '0');\n const reportDateTime = `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n const headerSummary = `\n <section class=\"summary\">\n <h2>Report summary</h2>\n <ul>\n <li><strong>Date:</strong> ${reportDateTime}</li>\n <li><strong>Pages audited:</strong> ${summary.pagesAudited}</li>\n <li><strong>Pages with violations:</strong> ${summary.pagesWithViolations}</li>\n <li><strong>Total violations:</strong> ${summary.totalViolations}</li>\n <li><strong>Distinct rules:</strong> ${summary.distinctRules.size}</li>\n </ul>\n <div class=\"impact-summary\">\n <h3>By impact</h3>\n <ul class=\"summary-list\">\n ${impactSummary || '<li>None</li>'}\n </ul>\n </div>\n </section>\n `.trim();\n\n const html = `\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"utf-8\"/>\n <title>Aria-Ease Accessibility Audit Report</title>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n <style>\n :root{\n --bg:#ffffff; --muted:#6b7280; --border:#e6e9ee;\n --impact-critical: red; --impact-moderate:#fff4dd; --impact-serious:rgb(255, 123, 0);\n }\n body{font-family:Inter,ui-sans-serif,system-ui,Segoe UI,Roboto,Helvetica,Arial; background:var(--bg); color:#111827; padding:24px; line-height:1.4}\n h1{margin:0 0 8px}\n .summary{background:#f8fafc;border:1px solid var(--border);padding:12px 16px;border-radius:8px;margin-bottom:18px}\n .summary ul{margin:6px 0 0 0;padding:0 18px}\n .impact-summary h3{margin:12px 0 6px}\n table{width:100%; border-collapse:collapse; margin-top:12px}\n th,td{border:1px solid var(--border); padding:10px; text-align:left; vertical-align:top}\n th{background:#f3f4f6; font-weight:600; position:sticky; top:0; z-index:1}\n .nowrap{white-space:nowrap}\n .target code{font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, \"Roboto Mono\", \"Courier New\", monospace; white-space:pre-wrap}\n .desc{max-width:380px}\n tr:nth-child(even){background:#fbfbfb}\n td.fail{color:#7b1e1e}\n .impact.critical{background:var(--impact-critical); font-weight:600}\n .impact.moderate{background:var(--impact-moderate); font-weight:600}\n .impact.serious{background:var(--impact-serious); font-weight:600}\n @media (max-width:900px){\n .desc{max-width:200px}\n table, thead, tbody, th, td, tr{display:block}\n thead{display:none}\n tr{margin-bottom:10px; border: 1px solid var(--border);}\n td{border:1px solid var(--border); padding:6px}\n td::before{font-weight:600; display:inline-block; width:120px}\n }\n .summary-list strong,\n .summary-list li {\n padding: 2px 4px;\n }\n </style>\n </head>\n <body>\n <h1>Aria-Ease Accessibility Audit Report</h1>\n ${headerSummary}\n <table>\n <thead>\n <tr>\n <th>URL</th><th>Rule</th><th>Impact</th><th>Description</th><th>Target</th><th>FailureSummary</th>\n </tr>\n </thead>\n <tbody>\n ${rows.join('\\n') || '<tr><td colspan=\"6\"><em>No violations found.</em></td></tr>'}\n </tbody>\n </table>\n </body>\n </html>\n `.trim();\n\n return html;\n}\n\nfunction escapeHTML(str: unknown): string {\n return String(str ?? '')\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>')\n .replaceAll('\"', '"')\n .replaceAll(\"'\", ''');\n}\n\nfunction escapeClass(s: string): string {\n return String(s ?? '').toLowerCase().replace(/[^a-z0-9]+/g, '-');\n}","/**\n * Runs static and interactions accessibility test on UI components. \n * @param {HTMLElement} component The UI component to be tested\n * @param {string} url Optional URL to run full Playwright E2E tests (requires dev server running)\n*/\n\nimport { axe } from \"jest-axe\";\nimport type { JestAxeResult } from \"Types\";\nimport { runContractTests } from \"../contract/contractTestRunner\";\n\n\nexport async function testUiComponent(componentName: string, component: HTMLElement, url?: string): Promise<JestAxeResult> {\n const results = await axe(component);\n \n let contract;\n \n if (url) {\n console.log(`๐ญ Running Playwright E2E tests on ${url}`);\n const { runContractTestsPlaywright } = await import(\"../contract/contractTestRunnerPlaywright\");\n contract = await runContractTestsPlaywright(componentName, url);\n } else {\n console.log(`๐งช Running jsdom tests (limited event handling)`);\n contract = await runContractTests(componentName, component);\n }\n \n const result = {\n violations: results.violations,\n raw: results,\n contract\n };\n \n // Throw helpful error if there are failures (use counts from reporter, not raw arrays)\n if (contract.failures.length > 0) {\n const mode = url ? 'Playwright' : 'jsdom';\n \n throw new Error(\n `\\nโ ${contract.failures.length} assertion${contract.failures.length > 1 ? 's' : ''} failed (${mode} mode)\\n` +\n `โ
${contract.passes.length} assertion${contract.passes.length > 1 ? 's' : ''} passed\\n\\n` +\n `๐ Review the detailed test report above for specific failures.`\n );\n }\n \n if (results.violations.length > 0) {\n const violationCount = results.violations.length;\n throw new Error(\n `\\nโ ${violationCount} axe accessibility violation${violationCount > 1 ? 's' : ''} detected\\n\\n` +\n `๐ Check result.violations for details`\n );\n }\n \n return result;\n}\n\nlet runTest = async () => {}\n\nif (typeof window === \"undefined\") {\n runTest = async () => {\n console.log(`๐ Running component accessibility tests...\\n`);\n\n const { exec } = await import(\"child_process\");\n\n exec(\n `npx vitest --run --reporter verbose`,\n { cwd: process.cwd() },\n (error, stdout, stderr) => {\n // Always output stdout (test results)\n if (stdout) {\n console.log(stdout);\n }\n \n // Always output stderr (ContractReporter output)\n if (stderr) {\n console.error(stderr);\n }\n \n // Exit with proper code (error.code will be set if vitest failed)\n if (error && error.code) {\n process.exit(error.code);\n }\n }\n );\n }\n}\n\nexport { runTest }","import path from \"path\";\nimport fs from \"fs-extra\";\nimport { AriaEaseConfig } from \"Types\";\n\n/**\n * Validates the structure of an AriaEase config object\n * @param config - The config object to validate\n * @returns Validation result with errors if any\n */\nfunction validateConfig(config: unknown): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n if (!config || typeof config !== 'object') {\n errors.push('Config must be an object');\n return { valid: false, errors };\n }\n\n const cfg = config as Partial<AriaEaseConfig>;\n\n // Validate audit config if present\n if (cfg.audit !== undefined) {\n if (typeof cfg.audit !== 'object' || cfg.audit === null) {\n errors.push('audit must be an object');\n } else {\n // Validate urls\n if (cfg.audit.urls !== undefined) {\n if (!Array.isArray(cfg.audit.urls)) {\n errors.push('audit.urls must be an array');\n } else if (cfg.audit.urls.some(url => typeof url !== 'string')) {\n errors.push('audit.urls must contain only strings');\n }\n }\n\n // Validate output format\n if (cfg.audit.output !== undefined) {\n if (typeof cfg.audit.output !== 'object') {\n errors.push('audit.output must be an object');\n } else {\n const output = cfg.audit.output as { format?: string; out?: string };\n if (output.format !== undefined) {\n if (!['json', 'csv', 'html', 'all'].includes(output.format)) {\n errors.push('audit.output.format must be one of: json, csv, html, all');\n }\n }\n if (output.out !== undefined && typeof output.out !== 'string') {\n errors.push('audit.output.out must be a string');\n }\n }\n }\n }\n }\n\n // Validate test config if present\n if (cfg.test !== undefined) {\n if (typeof cfg.test !== 'object' || cfg.test === null) {\n errors.push('test must be an object');\n } else {\n if (cfg.test.components !== undefined) {\n if (!Array.isArray(cfg.test.components)) {\n errors.push('test.components must be an array');\n } else {\n cfg.test.components.forEach((comp, idx) => {\n if (typeof comp !== 'object' || comp === null) {\n errors.push(`test.components[${idx}] must be an object`);\n } else {\n if (typeof comp.name !== 'string') {\n errors.push(`test.components[${idx}].name must be a string`);\n }\n if (typeof comp.path !== 'string') {\n errors.push(`test.components[${idx}].path must be a string`);\n }\n }\n });\n }\n }\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Attempts to load and parse a config file\n * @param filePath - Absolute path to the config file\n * @returns The parsed config or null if loading fails\n */\nasync function loadConfigFile(filePath: string): Promise<AriaEaseConfig | null> {\n try {\n const ext = path.extname(filePath);\n\n if (ext === '.json') {\n // Load JSON file\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content);\n } else if (['.js', '.mjs', '.cjs', '.ts'].includes(ext)) {\n // Dynamic import for JS/TS modules\n const imported = await import(filePath);\n // Handle both default export and named exports\n return imported.default || imported;\n }\n\n return null;\n } catch {\n // Return null on any error - caller will handle\n return null;\n }\n}\n\n/**\n * Searches for and loads an AriaEase config file\n * Checks for config files in this order:\n * - ariaease.config.js\n * - ariaease.config.mjs \n * - ariaease.config.cjs\n * - ariaease.config.json\n * - ariaease.config.ts\n * \n * @param cwd - Current working directory to search in\n * @returns Object containing the config and any errors\n */\nexport async function loadConfig(cwd: string = process.cwd()): Promise<{\n config: AriaEaseConfig;\n configPath: string | null;\n errors: string[];\n}> {\n const configNames = [\n 'ariaease.config.js',\n 'ariaease.config.mjs',\n 'ariaease.config.cjs',\n 'ariaease.config.json',\n 'ariaease.config.ts'\n ];\n\n let loadedConfig: AriaEaseConfig | null = null;\n let foundPath: string | null = null;\n const errors: string[] = [];\n\n // Try to find and load config\n for (const name of configNames) {\n const configPath = path.resolve(cwd, name);\n \n if (await fs.pathExists(configPath)) {\n foundPath = configPath;\n loadedConfig = await loadConfigFile(configPath);\n \n if (loadedConfig === null) {\n errors.push(`Found config at ${name} but failed to load it. Check for syntax errors.`);\n continue;\n }\n \n // Validate the loaded config\n const validation = validateConfig(loadedConfig);\n if (!validation.valid) {\n errors.push(`Config validation failed in ${name}:`);\n errors.push(...validation.errors.map(err => ` - ${err}`));\n loadedConfig = null;\n continue;\n }\n \n // Successfully loaded and validated\n break;\n }\n }\n\n return {\n config: loadedConfig || {},\n configPath: loadedConfig ? foundPath : null,\n errors\n };\n}\n"],"mappings":"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","names":["path","fs","axe","path","format","fs"]}
|
package/bin/cli.ts
CHANGED
|
@@ -52,10 +52,15 @@ program.command('audit')
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
const allResults: { url: string, result?: AxeResult }[] = [];
|
|
55
|
+
const auditOptions = {
|
|
56
|
+
timeout: config.audit?.timeout,
|
|
57
|
+
waitUntil: config.audit?.waitUntil
|
|
58
|
+
};
|
|
59
|
+
|
|
55
60
|
for (const url of urls) {
|
|
56
61
|
console.log(chalk.yellow(`๐ Auditing: ${url}`));
|
|
57
62
|
try {
|
|
58
|
-
const result: AxeResult = await runAudit(url);
|
|
63
|
+
const result: AxeResult = await runAudit(url, auditOptions);
|
|
59
64
|
allResults.push({ url: url, result });
|
|
60
65
|
console.log(chalk.green(`โ
Completed audit for ${url}\n`));
|
|
61
66
|
} catch (error: unknown) {
|
package/dist/index.cjs
CHANGED
|
@@ -9816,14 +9816,14 @@ function makeBlockAccessible(blockId, blockItemsClass) {
|
|
|
9816
9816
|
const blockDiv = document.querySelector(`#${blockId}`);
|
|
9817
9817
|
if (!blockDiv) {
|
|
9818
9818
|
console.error(`[aria-ease] Element with id="${blockId}" not found. Make sure the block element exists before calling makeBlockAccessible.`);
|
|
9819
|
-
return
|
|
9820
|
-
};
|
|
9819
|
+
return { cleanup: () => {
|
|
9820
|
+
} };
|
|
9821
9821
|
}
|
|
9822
9822
|
const blockItems = blockDiv.querySelectorAll(`.${blockItemsClass}`);
|
|
9823
9823
|
if (!blockItems || blockItems.length === 0) {
|
|
9824
9824
|
console.error(`[aria-ease] Element with class="${blockItemsClass}" not found. Make sure the block items exist before calling makeBlockAccessible.`);
|
|
9825
|
-
return
|
|
9826
|
-
};
|
|
9825
|
+
return { cleanup: () => {
|
|
9826
|
+
} };
|
|
9827
9827
|
}
|
|
9828
9828
|
blockItems.forEach((blockItem) => {
|
|
9829
9829
|
if (!eventListenersMap.has(blockItem)) {
|
|
@@ -9836,7 +9836,7 @@ function makeBlockAccessible(blockId, blockItemsClass) {
|
|
|
9836
9836
|
eventListenersMap.set(blockItem, handler);
|
|
9837
9837
|
}
|
|
9838
9838
|
});
|
|
9839
|
-
|
|
9839
|
+
function cleanup() {
|
|
9840
9840
|
blockItems.forEach((blockItem) => {
|
|
9841
9841
|
const handler = eventListenersMap.get(blockItem);
|
|
9842
9842
|
if (handler) {
|
|
@@ -9844,7 +9844,9 @@ function makeBlockAccessible(blockId, blockItemsClass) {
|
|
|
9844
9844
|
eventListenersMap.delete(blockItem);
|
|
9845
9845
|
}
|
|
9846
9846
|
});
|
|
9847
|
-
}
|
|
9847
|
+
}
|
|
9848
|
+
;
|
|
9849
|
+
return { cleanup };
|
|
9848
9850
|
}
|
|
9849
9851
|
|
|
9850
9852
|
// src/checkbox/src/updateCheckboxAriaAttributes/updateCheckboxAriaAttributes.ts
|