test-a11y-js 0.8.0 → 0.8.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
@@ -129,6 +129,61 @@ module.exports = {
129
129
  - `plugin:test-a11y-js/react` - Optimized for React/JSX
130
130
  - `plugin:test-a11y-js/vue` - Optimized for Vue SFC
131
131
 
132
+ #### Ignoring Files and Lines
133
+
134
+ Sometimes you need to ignore specific files or lines. Here are your options:
135
+
136
+ **Ignore a single line:**
137
+ ```jsx
138
+ // eslint-disable-next-line test-a11y-js/image-alt
139
+ <img src="decorative.jpg" alt="" />
140
+ ```
141
+
142
+ **Ignore an entire file:**
143
+ ```jsx
144
+ /* eslint-disable test-a11y-js/heading-order */
145
+ // Entire file exempt from heading-order rule
146
+ ```
147
+
148
+ **Ignore directories:**
149
+ ```javascript
150
+ // .eslintrc.js
151
+ module.exports = {
152
+ plugins: ['test-a11y-js'],
153
+ extends: ['plugin:test-a11y-js/recommended'],
154
+ ignorePatterns: [
155
+ '**/node_modules/**',
156
+ '**/dist/**',
157
+ '**/*.test.{js,ts,jsx,tsx}' // Optional: exclude test files
158
+ ]
159
+ }
160
+ ```
161
+
162
+ **Disable rules for specific files:**
163
+ ```javascript
164
+ // .eslintrc.js
165
+ module.exports = {
166
+ plugins: ['test-a11y-js'],
167
+ extends: ['plugin:test-a11y-js/recommended'],
168
+ overrides: [
169
+ {
170
+ files: ['**/legacy/**'],
171
+ rules: {
172
+ 'test-a11y-js/**': 'warn' // Only warnings in legacy code
173
+ }
174
+ }
175
+ ]
176
+ }
177
+ ```
178
+
179
+ **Vue template ignore:**
180
+ ```vue
181
+ <!-- eslint-disable-next-line test-a11y-js/image-alt -->
182
+ <img src="photo.jpg" />
183
+ ```
184
+
185
+ > **Best Practice:** Always add a comment explaining why you're ignoring a rule. For example: `// eslint-disable-next-line test-a11y-js/image-alt -- Decorative image, no semantic meaning`
186
+
132
187
  ### Quick Start for Large Projects
133
188
 
134
189
  ```javascript
@@ -166,7 +221,18 @@ const videoViolations = A11yChecker.checkVideoCaptions(element)
166
221
  const audioViolations = A11yChecker.checkAudioCaptions(element)
167
222
  const landmarkViolations = A11yChecker.checkLandmarks(element)
168
223
  const dialogViolations = A11yChecker.checkDialogModal(element)
224
+
225
+ // Phase 1: ARIA, Semantic HTML, Form Validation
226
+ const ariaRoleViolations = A11yChecker.checkAriaRoles(element)
227
+ const ariaPropertyViolations = A11yChecker.checkAriaProperties(element)
228
+ const ariaRelationshipViolations = A11yChecker.checkAriaRelationships(element)
229
+ const accessibleNameViolations = A11yChecker.checkAccessibleName(element)
230
+ const compositePatternViolations = A11yChecker.checkCompositePatterns(element)
231
+ const semanticHTMLViolations = A11yChecker.checkSemanticHTML(element)
232
+ const formValidationViolations = A11yChecker.checkFormValidationMessages(element)
169
233
  ```
234
+ <|tool▁calls▁begin|><|tool▁call▁begin|>
235
+ read_file
170
236
 
171
237
  ## API
172
238
 
@@ -362,6 +428,64 @@ function MyComponent() {
362
428
  </template>
363
429
  ```
364
430
 
431
+ ### ARIA Validation (Phase 1)
432
+
433
+ ```tsx
434
+ // ❌ ESLint will catch these ARIA issues
435
+ function MyComponent() {
436
+ return (
437
+ <div>
438
+ <div role="invalid-role">Content</div> {/* Invalid role */}
439
+ <button role="button">Click</button> {/* Redundant role */}
440
+ <div role="tab">Tab</div> {/* Missing tablist context */}
441
+ <input aria-label="" /> {/* Empty aria-label */}
442
+ </div>
443
+ )
444
+ }
445
+
446
+ // ✅ Fixed
447
+ function MyComponent() {
448
+ return (
449
+ <div role="tablist">
450
+ <button>Click</button> {/* Native button, no role needed */}
451
+ <div role="tab" aria-controls="panel-1">Tab</div>
452
+ <input aria-label="Email address" />
453
+ </div>
454
+ )
455
+ }
456
+ ```
457
+
458
+ ### Semantic HTML (Phase 1)
459
+
460
+ ```tsx
461
+ // ❌ ESLint will catch semantic HTML misuse
462
+ function MyComponent() {
463
+ return (
464
+ <div>
465
+ <div role="button" onClick={handleClick}>Click</div> {/* Use <button> */}
466
+ <a>Link without href</a> {/* Missing href */}
467
+ <button><a href="/">Nested link</a></button> {/* Nested interactive */}
468
+ <main>Content</main>
469
+ <main>Another main</main> {/* Multiple main */}
470
+ </div>
471
+ )
472
+ }
473
+
474
+ // ✅ Fixed
475
+ function MyComponent() {
476
+ return (
477
+ <div>
478
+ <button onClick={handleClick}>Click</button>
479
+ <a href="/page">Link</a>
480
+ <button>Action</button>
481
+ <main>Content</main>
482
+ </div>
483
+ )
484
+ }
485
+ ```
486
+ <|tool▁calls▁begin|><|tool▁call▁begin|>
487
+ run_terminal_cmd
488
+
365
489
  ## How It Compares
366
490
 
367
491
  | Feature | test-a11y-js | eslint-plugin-jsx-a11y | @axe-core/react |
package/dist/index.js CHANGED
@@ -1832,7 +1832,10 @@ ${index + 1}. ${violation.id} (${violation.impact})`);
1832
1832
  if (!ids.has(id)) {
1833
1833
  ids.set(id, []);
1834
1834
  }
1835
- ids.get(id).push(el);
1835
+ const elements = ids.get(id);
1836
+ if (elements) {
1837
+ elements.push(el);
1838
+ }
1836
1839
  }
1837
1840
  }
1838
1841
  for (const [id, elements] of ids.entries()) {
@@ -4131,7 +4134,7 @@ var form_validation_default = rule16;
4131
4134
  var plugin = {
4132
4135
  meta: {
4133
4136
  name: "test-a11y-js",
4134
- version: "0.8.0"
4137
+ version: "0.8.2"
4135
4138
  },
4136
4139
  rules: {
4137
4140
  "image-alt": image_alt_default,
package/dist/index.mjs CHANGED
@@ -1813,7 +1813,10 @@ ${index + 1}. ${violation.id} (${violation.impact})`);
1813
1813
  if (!ids.has(id)) {
1814
1814
  ids.set(id, []);
1815
1815
  }
1816
- ids.get(id).push(el);
1816
+ const elements = ids.get(id);
1817
+ if (elements) {
1818
+ elements.push(el);
1819
+ }
1817
1820
  }
1818
1821
  }
1819
1822
  for (const [id, elements] of ids.entries()) {
@@ -4112,7 +4115,7 @@ var form_validation_default = rule16;
4112
4115
  var plugin = {
4113
4116
  meta: {
4114
4117
  name: "test-a11y-js",
4115
- version: "0.8.0"
4118
+ version: "0.8.2"
4116
4119
  },
4117
4120
  rules: {
4118
4121
  "image-alt": image_alt_default,
@@ -1900,7 +1900,10 @@ ${index + 1}. ${violation.id} (${violation.impact})`);
1900
1900
  if (!ids.has(id)) {
1901
1901
  ids.set(id, []);
1902
1902
  }
1903
- ids.get(id).push(el);
1903
+ const elements = ids.get(id);
1904
+ if (elements) {
1905
+ elements.push(el);
1906
+ }
1904
1907
  }
1905
1908
  }
1906
1909
  for (const [id, elements] of ids.entries()) {
@@ -4130,7 +4133,7 @@ var form_validation_default = rule16;
4130
4133
  var plugin = {
4131
4134
  meta: {
4132
4135
  name: "test-a11y-js",
4133
- version: "0.8.0"
4136
+ version: "0.8.2"
4134
4137
  },
4135
4138
  rules: {
4136
4139
  "image-alt": image_alt_default,
@@ -1882,7 +1882,10 @@ ${index + 1}. ${violation.id} (${violation.impact})`);
1882
1882
  if (!ids.has(id)) {
1883
1883
  ids.set(id, []);
1884
1884
  }
1885
- ids.get(id).push(el);
1885
+ const elements = ids.get(id);
1886
+ if (elements) {
1887
+ elements.push(el);
1888
+ }
1886
1889
  }
1887
1890
  }
1888
1891
  for (const [id, elements] of ids.entries()) {
@@ -4112,7 +4115,7 @@ var form_validation_default = rule16;
4112
4115
  var plugin = {
4113
4116
  meta: {
4114
4117
  name: "test-a11y-js",
4115
- version: "0.8.0"
4118
+ version: "0.8.2"
4116
4119
  },
4117
4120
  rules: {
4118
4121
  "image-alt": image_alt_default,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "test-a11y-js",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Zero-config accessibility testing for React, Vue & JSX. ESLint plugin + programmatic API. Catch a11y issues before production.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",