@octaviaflow/accessibility-checker 1.0.0 → 1.1.2

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 CHANGED
@@ -1,94 +1,420 @@
1
- # Accessibility Checker
1
+ # @octaviaflow/accessibility-checker
2
2
 
3
- ## Overview
3
+ > **Enterprise-grade accessibility checker for OctaviaFlow Design System**
4
4
 
5
- Accessibility Checker is a JavaScript project designed to help developers ensure that their web content meets accessibility standards. This tool provides functionalities to check and validate the accessibility of web pages.
5
+ A comprehensive TypeScript-based accessibility testing tool that combines heuristic analysis with axe-core integration to provide detailed accessibility reports in multiple formats.
6
6
 
7
- ## Features
7
+ ## šŸš€ Features
8
8
 
9
- - Core functionality for accessibility checking.
10
- - Utility functions to support main functionalities.
11
- - Unit tests to ensure reliability and correctness.
9
+ - **šŸ” Dual Analysis Engine**: Combines custom heuristics with axe-core for comprehensive accessibility testing
10
+ - **šŸ“Š Multiple Output Formats**: JSON, HTML, CSV, and Excel reports
11
+ - **šŸŽØ Beautiful HTML Reports**: Responsive, styled reports with issue categorization
12
+ - **⚔ High Performance**: Built with TypeScript and optimized for speed
13
+ - **šŸ› ļø CLI & Programmatic API**: Use as command-line tool or integrate into your workflow
14
+ - **šŸ“ˆ WCAG Compliance**: Maps issues to WCAG guidelines with help URLs
15
+ - **šŸ”§ Extensible Architecture**: Easy to add custom rules and checks
12
16
 
13
- ## Installation
17
+ ## šŸ“¦ Installation
14
18
 
15
- To install the project, clone the repository and run the following command in the project directory:
19
+ ### NPM/Yarn
20
+ ```bash
21
+ npm install @octaviaflow/accessibility-checker
22
+ # or
23
+ yarn add @octaviaflow/accessibility-checker
24
+ ```
25
+
26
+ ### Bun
27
+ ```bash
28
+ bun add @octaviaflow/accessibility-checker
29
+ ```
16
30
 
31
+ ### Global Installation
32
+ ```bash
33
+ npm install -g @octaviaflow/accessibility-checker
17
34
  ```
18
- npm install
35
+
36
+ ## šŸŽÆ Quick Start
37
+
38
+ ### CLI Usage
39
+
40
+ ```bash
41
+ # Analyze an HTML file
42
+ octaviaflow-achecker --input index.html
43
+
44
+ # Generate HTML report
45
+ octaviaflow-achecker --input page.html --format html --verbose
46
+
47
+ # Test with sample HTML
48
+ octaviaflow-achecker --sample --format excel
49
+
50
+ # Custom output location
51
+ octaviaflow-achecker --input app.html --output reports/accessibility.json
19
52
  ```
20
53
 
21
- ## Usage
54
+ ### Programmatic Usage
55
+
56
+ ```typescript
57
+ import { analyze } from '@octaviaflow/accessibility-checker';
58
+ import { saveReport } from '@octaviaflow/accessibility-checker/storage';
59
+
60
+ // Analyze HTML content
61
+ const html = '<html><body><img src="logo.png"><h1>Welcome</h1></body></html>';
62
+ const result = await analyze(html);
63
+
64
+ // Save results in different formats
65
+ await saveReport(result, './report.json', 'json');
66
+ await saveReport(result, './report.html', 'html');
67
+ await saveReport(result, './report.xlsx', 'excel');
22
68
 
23
- To use the accessibility checker, you can run the main entry point:
69
+ console.log(`Found ${result.summary.totalIssues} accessibility issues`);
70
+ ```
24
71
 
72
+ ## šŸ“‹ CLI Options
73
+
74
+ | Option | Alias | Description | Default |
75
+ |--------|-------|-------------|---------|
76
+ | `--input <file>` | `-i` | HTML file to analyze | - |
77
+ | `--output <file>` | `-o` | Output file path | `./data/results.json` |
78
+ | `--format <type>` | - | Output format: `json`, `html`, `csv`, `excel` | `json` |
79
+ | `--sample` | - | Run with sample HTML for testing | `false` |
80
+ | `--verbose` | `-v` | Verbose output with detailed logging | `false` |
81
+ | `--help` | `-h` | Show help message | - |
82
+
83
+ ## šŸ“Š Output Formats
84
+
85
+ ### JSON Format
86
+ ```json
87
+ {
88
+ "summary": {
89
+ "totalIssues": 3,
90
+ "byType": {
91
+ "image-missing-alt": 1,
92
+ "link-empty": 1,
93
+ "axe:color-contrast": 1
94
+ },
95
+ "axeViolations": 1
96
+ },
97
+ "issues": [
98
+ {
99
+ "type": "image-missing-alt",
100
+ "message": "Image tag missing alt attribute",
101
+ "snippet": "<img src=\"logo.png\">",
102
+ "source": "heuristic"
103
+ }
104
+ ],
105
+ "axe": { /* Full axe-core results */ },
106
+ "meta": {
107
+ "timestamp": "2025-11-13T10:52:00.000Z",
108
+ "source": "index.html",
109
+ "version": "1.1.1"
110
+ }
111
+ }
25
112
  ```
26
- node src/index.js
113
+
114
+ ### HTML Report
115
+ - **Responsive design** with modern styling
116
+ - **Color-coded issues** by severity and type
117
+ - **Interactive elements** with expandable details
118
+ - **Summary dashboard** with metrics
119
+ - **WCAG compliance mapping**
120
+
121
+ ### Excel Report
122
+ - **Summary sheet** with overview metrics
123
+ - **Issues sheet** with detailed findings
124
+ - **Formatted tables** with proper styling
125
+ - **Multiple worksheets** for organization
126
+
127
+ ## šŸ”§ Development
128
+
129
+ ### Prerequisites
130
+ - **Node.js** ≄ 22.0.0
131
+ - **Bun** ≄ 1.3.2 (recommended)
132
+ - **TypeScript** ≄ 5.8.3
133
+
134
+ ### Setup
135
+ ```bash
136
+ # Clone the repository
137
+ git clone https://github.com/OctaviaFlow/OctaviaFlow-Design-System.git
138
+ cd OctaviaFlow-Design-System/packages/accessibility-checker
139
+
140
+ # Install dependencies
141
+ bun install
142
+
143
+ # Build the project
144
+ bun run build
145
+
146
+ # Run tests
147
+ bun run test
148
+
149
+ # Run linting
150
+ bun run lint
151
+
152
+ # Development mode
153
+ bun run dev
27
154
  ```
28
155
 
29
- ## Running Tests
156
+ ### Scripts
157
+
158
+ | Script | Description |
159
+ |--------|-------------|
160
+ | `bun run build` | Build CommonJS, ESM, and TypeScript declarations |
161
+ | `bun run test` | Run tests once and exit |
162
+ | `bun run test:watch` | Run tests in watch mode |
163
+ | `bun run lint` | Run ESLint |
164
+ | `bun run lint:fix` | Fix ESLint issues |
165
+ | `bun run format` | Format code with Prettier |
166
+ | `bun run ci-check` | Full CI pipeline (build + test + lint) |
167
+ | `bun run dev` | Build and run sample |
30
168
 
31
- To run the unit tests, use the following command:
169
+ ## šŸ—ļø Architecture
170
+
171
+ ### Core Components
32
172
 
33
173
  ```
34
- npm test
174
+ src/
175
+ ā”œā”€ā”€ checker/
176
+ │ └── index.ts # Main analysis engine
177
+ ā”œā”€ā”€ storage/
178
+ │ └── reportWriter.ts # Multi-format report generation
179
+ ā”œā”€ā”€ utils/
180
+ │ └── wcag-rules.ts # WCAG compliance mapping
181
+ └── index.ts # CLI interface
35
182
  ```
36
183
 
37
- ## Contributing
184
+ ### Analysis Engine
185
+
186
+ The accessibility checker uses a **dual-engine approach**:
187
+
188
+ 1. **Heuristic Analysis**: Fast, lightweight checks for common issues
189
+ - Missing alt attributes on images
190
+ - Empty links and headings
191
+ - Basic structural problems
192
+
193
+ 2. **Axe-Core Integration**: Comprehensive WCAG compliance testing
194
+ - Color contrast analysis
195
+ - Keyboard navigation
196
+ - ARIA compliance
197
+ - Semantic structure validation
198
+
199
+ ### Type Definitions
200
+
201
+ ```typescript
202
+ interface Issue {
203
+ type: string;
204
+ message: string;
205
+ snippet?: string;
206
+ helpUrl?: string;
207
+ source?: string;
208
+ }
209
+
210
+ interface Result {
211
+ summary: {
212
+ totalIssues: number;
213
+ byType: Record<string, number>;
214
+ axeViolations?: number;
215
+ };
216
+ issues: Issue[];
217
+ axe?: AxeResults | { error: string };
218
+ meta?: ResultMeta;
219
+ }
220
+ ```
38
221
 
39
- Contributions are welcome! Please feel free to submit a pull request or open an issue for any enhancements or bug fixes.
222
+ ## šŸŽØ Examples
223
+
224
+ ### Basic HTML Analysis
225
+
226
+ ```typescript
227
+ import { analyze } from '@octaviaflow/accessibility-checker';
228
+
229
+ const html = `
230
+ <!DOCTYPE html>
231
+ <html lang="en">
232
+ <head>
233
+ <title>Test Page</title>
234
+ </head>
235
+ <body>
236
+ <h1>Welcome</h1>
237
+ <img src="hero.jpg">
238
+ <a href="/about"></a>
239
+ <button style="color: #ccc; background: #ddd;">Click me</button>
240
+ </body>
241
+ </html>
242
+ `;
243
+
244
+ const result = await analyze(html);
245
+ console.log(`Found ${result.summary.totalIssues} issues:`);
246
+ result.issues.forEach(issue => {
247
+ console.log(`- ${issue.type}: ${issue.message}`);
248
+ });
249
+ ```
40
250
 
41
- ## License
251
+ ### CI/CD Integration
252
+
253
+ ```yaml
254
+ # GitHub Actions example
255
+ - name: Accessibility Check
256
+ run: |
257
+ octaviaflow-achecker --input dist/index.html --format json --output accessibility-report.json
258
+
259
+ - name: Upload Report
260
+ uses: actions/upload-artifact@v3
261
+ with:
262
+ name: accessibility-report
263
+ path: accessibility-report.json
264
+ ```
42
265
 
43
- This project is licensed under the MIT License. See the LICENSE file for more details.
266
+ ### Custom Report Generation
267
+
268
+ ```typescript
269
+ import { analyze, saveReport } from '@octaviaflow/accessibility-checker';
270
+
271
+ async function generateAccessibilityReport(htmlFiles: string[]) {
272
+ const results = [];
273
+
274
+ for (const file of htmlFiles) {
275
+ const html = await fs.readFile(file, 'utf8');
276
+ const result = await analyze(html);
277
+ result.meta = { ...result.meta, source: file };
278
+ results.push(result);
279
+ }
280
+
281
+ // Generate combined report
282
+ const combinedResult = {
283
+ summary: {
284
+ totalIssues: results.reduce((sum, r) => sum + r.summary.totalIssues, 0),
285
+ byType: results.reduce((acc, r) => {
286
+ Object.entries(r.summary.byType).forEach(([type, count]) => {
287
+ acc[type] = (acc[type] || 0) + count;
288
+ });
289
+ return acc;
290
+ }, {})
291
+ },
292
+ issues: results.flatMap(r => r.issues),
293
+ meta: {
294
+ timestamp: new Date().toISOString(),
295
+ source: 'batch-analysis',
296
+ fileCount: htmlFiles.length
297
+ }
298
+ };
299
+
300
+ await saveReport(combinedResult, './batch-report.html', 'html');
301
+ }
302
+ ```
44
303
 
45
- ### octaviaflow - Local Accessibility Checker
304
+ ### Integration with Testing Frameworks
305
+
306
+ ```typescript
307
+ // Jest/Vitest example
308
+ import { analyze } from '@octaviaflow/accessibility-checker';
309
+
310
+ describe('Accessibility Tests', () => {
311
+ test('homepage should be accessible', async () => {
312
+ const html = await getRenderedHTML('/');
313
+ const result = await analyze(html);
314
+
315
+ expect(result.summary.totalIssues).toBe(0);
316
+ });
317
+
318
+ test('should have no critical axe violations', async () => {
319
+ const html = await getRenderedHTML('/dashboard');
320
+ const result = await analyze(html);
321
+
322
+ if (result.axe && 'violations' in result.axe) {
323
+ const criticalViolations = result.axe.violations.filter(
324
+ v => v.impact === 'critical'
325
+ );
326
+ expect(criticalViolations).toHaveLength(0);
327
+ }
328
+ });
329
+ });
330
+ ```
46
331
 
47
- Usage:
332
+ ## šŸ”§ Configuration
333
+
334
+ ### ESLint Integration
335
+
336
+ The package uses **ESLint v9** with flat config:
337
+
338
+ ```javascript
339
+ // eslint.config.js
340
+ import typescriptEslint from '@typescript-eslint/eslint-plugin';
341
+ import tsParser from '@typescript-eslint/parser';
342
+ import js from '@eslint/js';
343
+
344
+ export default [
345
+ js.configs.recommended,
346
+ {
347
+ files: ['**/*.ts'],
348
+ languageOptions: {
349
+ parser: tsParser,
350
+ parserOptions: {
351
+ ecmaVersion: 2022,
352
+ sourceType: 'module'
353
+ }
354
+ },
355
+ plugins: {
356
+ '@typescript-eslint': typescriptEslint
357
+ },
358
+ rules: {
359
+ '@typescript-eslint/no-explicit-any': 'warn',
360
+ 'no-console': 'off'
361
+ }
362
+ }
363
+ ];
364
+ ```
48
365
 
49
- - node src/index.js --input path/to/file.html
50
- - node src/index.js --sample
51
- - Optional: --output path/to/results.json (defaults to ./data/results.json)
366
+ ### TypeScript Configuration
52
367
 
53
- Behavior:
368
+ Uses **unified OctaviaFlow TypeScript configs**:
54
369
 
55
- - Performs lightweight accessibility heuristics (images missing alt, empty links, empty headings).
56
- - Stores results as an array in the output JSON file (suitable for future import to MongoDB).
57
- - No IBM telemetry or IBM/carbon dependencies included.
370
+ ```json
371
+ {
372
+ "extends": "typescript-config-octaviaflow/base",
373
+ "compilerOptions": {
374
+ "rootDir": "src",
375
+ "outDir": "dist"
376
+ }
377
+ }
378
+ ```
58
379
 
59
- ### octaviaflow - Local Accessibility Checker (TypeScript)
380
+ ## šŸš€ Performance
60
381
 
61
- Quick start:
382
+ - **Fast Analysis**: Optimized for large HTML files
383
+ - **Memory Efficient**: Streaming analysis for large documents
384
+ - **Concurrent Processing**: Parallel heuristic and axe-core analysis
385
+ - **Minimal Dependencies**: Lightweight package with essential dependencies only
62
386
 
63
- 1. Install deps:
387
+ ## šŸ¤ Contributing
64
388
 
65
- cd accessibility-checker
66
- npm install
389
+ 1. **Fork** the repository
390
+ 2. **Create** a feature branch: `git checkout -b feature/amazing-feature`
391
+ 3. **Commit** your changes: `git commit -m 'Add amazing feature'`
392
+ 4. **Push** to the branch: `git push origin feature/amazing-feature`
393
+ 5. **Open** a Pull Request
67
394
 
68
- 2. Build:
395
+ ### Development Guidelines
69
396
 
70
- npm run build
397
+ - **TypeScript**: All code must be properly typed
398
+ - **Testing**: Maintain 100% test coverage for new features
399
+ - **Linting**: Follow ESLint configuration
400
+ - **Documentation**: Update README for new features
71
401
 
72
- 3. Run:
402
+ ## šŸ“„ License
73
403
 
74
- node ./cjs/index.js --sample
75
- or
76
- octaviaflow --input path/to/file.html --output ./data/results.json
404
+ Licensed under the **Apache-2.0** License. See [LICENSE](LICENSE) file for details.
77
405
 
78
- What changed:
406
+ ## šŸ”— Related Packages
79
407
 
80
- - Converted to TypeScript.
81
- - Uses axe-core + heuristics for more complete checks.
82
- - Stores results locally as an array in JSON (ready for importing to MongoDB).
83
- - No IBM telemetry or Carbon packages included.
408
+ - **[@octaviaflow/react](../react)** - React components with built-in accessibility
409
+ - **[@octaviaflow/styles](../styles)** - Accessible CSS framework
410
+ - **[@octaviaflow/themes](../themes)** - Accessible color themes
84
411
 
85
- Testing:
412
+ ## šŸ“ž Support
86
413
 
87
- - npm test (uses vitest)
414
+ - **Issues**: [GitHub Issues](https://github.com/OctaviaFlow/OctaviaFlow-Design-System/issues)
415
+ - **Discussions**: [GitHub Discussions](https://github.com/OctaviaFlow/OctaviaFlow-Design-System/discussions)
416
+ - **Documentation**: [OctaviaFlow Docs](https://octaviaflow.dev)
88
417
 
89
- Build outputs:
418
+ ---
90
419
 
91
- - cjs/ CommonJS build (cjs/index.js)
92
- - mjs/ ES module build (mjs/index.js)
93
- - types/ TypeScript declaration files
94
- - bin/ CLI shim (bin/octaviaflow.js)
420
+ **Made with ā¤ļø by the OctaviaFlow Team**
package/bin/achecker.js CHANGED
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
1
10
  #!/usr/bin/env node
2
11
  // simple shim that delegates to the CommonJS build
3
12
  try {
@@ -1,44 +1,11 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.analyze = analyze;
4
+ const tslib_1 = require("tslib");
37
5
  const jsdom_1 = require("jsdom");
38
- const axe = __importStar(require("axe-core"));
6
+ const axe = tslib_1.__importStar(require("axe-core"));
39
7
  function heuristicAnalyze(html) {
40
8
  const issues = [];
41
- // images without alt
42
9
  const imgRegex = /<img\b[^>]*>/gi;
43
10
  let m;
44
11
  while ((m = imgRegex.exec(html))) {
@@ -51,7 +18,6 @@ function heuristicAnalyze(html) {
51
18
  });
52
19
  }
53
20
  }
54
- // links without descriptive text (naive)
55
21
  const aRegex = /<a\b[^>]*>([\s\S]*?)<\/a>/gi;
56
22
  while ((m = aRegex.exec(html))) {
57
23
  const inner = (m[1] || '').trim();
@@ -63,7 +29,6 @@ function heuristicAnalyze(html) {
63
29
  });
64
30
  }
65
31
  }
66
- // empty headings
67
32
  const hRegex = /<h[1-6][^>]*>([\s\S]*?)<\/h[1-6]>/gi;
68
33
  while ((m = hRegex.exec(html))) {
69
34
  const content = (m[1] || '').replace(/<[^>]*>/g, '').trim();
@@ -83,10 +48,7 @@ async function runAxe(html) {
83
48
  resources: 'usable',
84
49
  });
85
50
  const { window } = dom;
86
- // axe.run expects document; pass document
87
- const result = await axe.run(window.document, {
88
- // default rules; you can customize here
89
- });
51
+ const result = await axe.run(window.document, {});
90
52
  return result;
91
53
  }
92
54
  async function analyze(html) {
@@ -96,11 +58,10 @@ async function analyze(html) {
96
58
  axeRes = await runAxe(html);
97
59
  }
98
60
  catch (e) {
99
- // If axe fails for some HTML, continue with heuristics
100
61
  axeRes = { error: String(e) };
101
62
  }
102
63
  const axeIssues = [];
103
- if (axeRes && Array.isArray(axeRes.violations)) {
64
+ if (axeRes && 'violations' in axeRes && Array.isArray(axeRes.violations)) {
104
65
  for (const v of axeRes.violations) {
105
66
  for (const node of v.nodes || []) {
106
67
  axeIssues.push({
package/cjs/index.js ADDED
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.saveReport = exports.analyze = void 0;
4
+ exports.main = main;
5
+ const tslib_1 = require("tslib");
6
+ const fs_1 = require("fs");
7
+ const path_1 = require("path");
8
+ const minimist_1 = tslib_1.__importDefault(require("minimist"));
9
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
10
+ const ora_1 = tslib_1.__importDefault(require("ora"));
11
+ const index_js_1 = require("./checker/index.js");
12
+ const reportWriter_js_1 = require("./storage/reportWriter.js");
13
+ var index_js_2 = require("./checker/index.js");
14
+ Object.defineProperty(exports, "analyze", { enumerable: true, get: function () { return index_js_2.analyze; } });
15
+ var reportWriter_js_2 = require("./storage/reportWriter.js");
16
+ Object.defineProperty(exports, "saveReport", { enumerable: true, get: function () { return reportWriter_js_2.saveReport; } });
17
+ function showHelp() {
18
+ console.log(chalk_1.default.blue.bold('OctaviaFlow Accessibility Checker'));
19
+ console.log('');
20
+ console.log(chalk_1.default.yellow('Usage:'));
21
+ console.log(' octaviaflow-achecker [options]');
22
+ console.log('');
23
+ console.log(chalk_1.default.yellow('Options:'));
24
+ console.log(' -i, --input <file> Input HTML file to analyze');
25
+ console.log(' -o, --output <file> Output file for results (default: ./data/results.json)');
26
+ console.log(' --sample Run with sample HTML for testing');
27
+ console.log(' --format <type> Output format: json, html, csv, excel (default: json)');
28
+ console.log(' -v, --verbose Verbose output');
29
+ console.log(' -h, --help Show this help message');
30
+ console.log('');
31
+ console.log(chalk_1.default.yellow('Examples:'));
32
+ console.log(' octaviaflow-achecker --input index.html');
33
+ console.log(' octaviaflow-achecker --sample --format html');
34
+ console.log(' octaviaflow-achecker -i page.html -o report.json --verbose');
35
+ }
36
+ async function main(args) {
37
+ const argv = (0, minimist_1.default)(args || process.argv.slice(2));
38
+ if (argv.help || argv.h) {
39
+ showHelp();
40
+ return;
41
+ }
42
+ const inputPath = argv.input || argv.i;
43
+ const outputPath = argv.output || argv.o || (0, path_1.join)(process.cwd(), 'data', 'results.json');
44
+ const format = argv.format || 'json';
45
+ const verbose = argv.verbose || argv.v || false;
46
+ let html = '';
47
+ let spinner = null;
48
+ try {
49
+ if (argv.sample) {
50
+ html = `<html>
51
+ <head><title>Sample Accessibility Test</title></head>
52
+ <body>
53
+ <img src="image.png">
54
+ <a href="/"></a>
55
+ <h1></h1>
56
+ <button></button>
57
+ <input type="text">
58
+ <div role="button"></div>
59
+ </body>
60
+ </html>`;
61
+ if (verbose) {
62
+ console.log(chalk_1.default.gray('Using sample HTML for testing'));
63
+ }
64
+ }
65
+ else if (inputPath) {
66
+ if (verbose) {
67
+ console.log(chalk_1.default.gray(`Reading HTML from: ${inputPath}`));
68
+ }
69
+ html = (0, fs_1.readFileSync)((0, path_1.resolve)(inputPath), 'utf8');
70
+ }
71
+ else {
72
+ console.error(chalk_1.default.red('Error: No input specified'));
73
+ showHelp();
74
+ process.exit(1);
75
+ }
76
+ spinner = (0, ora_1.default)('Analyzing accessibility...').start();
77
+ const result = await (0, index_js_1.analyze)(html);
78
+ result.meta = {
79
+ timestamp: new Date().toISOString(),
80
+ source: inputPath || 'sample',
81
+ format,
82
+ version: '1.0.0'
83
+ };
84
+ spinner.succeed('Analysis complete');
85
+ if (verbose) {
86
+ console.log(chalk_1.default.green(`Found ${result.summary.totalIssues} accessibility issues`));
87
+ console.log(chalk_1.default.gray(`Axe violations: ${result.axe && 'violations' in result.axe ? result.axe.violations?.length || 0 : 0}`));
88
+ }
89
+ await (0, reportWriter_js_1.saveReport)(result, outputPath, format);
90
+ console.log(chalk_1.default.green(`āœ“ Results saved to ${outputPath}`));
91
+ if (result.summary.totalIssues > 0) {
92
+ console.log(chalk_1.default.yellow('\nIssue Summary:'));
93
+ Object.entries(result.summary.byType).forEach(([type, count]) => {
94
+ console.log(chalk_1.default.gray(` ${type}: ${count}`));
95
+ });
96
+ }
97
+ else {
98
+ console.log(chalk_1.default.green('\nāœ“ No accessibility issues found!'));
99
+ }
100
+ }
101
+ catch (error) {
102
+ if (spinner) {
103
+ spinner.fail('Analysis failed');
104
+ }
105
+ console.error(chalk_1.default.red('Error:'), error instanceof Error ? error.message : String(error));
106
+ if (verbose && error instanceof Error) {
107
+ console.error(chalk_1.default.gray(error.stack));
108
+ }
109
+ process.exit(2);
110
+ }
111
+ }
112
+ if (require.main === module) {
113
+ main().catch(err => {
114
+ console.error(chalk_1.default.red('Fatal error:'), err);
115
+ process.exit(2);
116
+ });
117
+ }