gbu-accessibility-package 3.3.0 → 3.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/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.5.0] - 2025-01-08
9
+
10
+ ### Added
11
+ - **Enhanced Heading Structure Auto-Fix**: Automatic fixing of heading hierarchy issues with `--auto-fix-headings` option
12
+ - **Improved Nested Controls Detection**: Better detection and fixing of nested interactive controls
13
+ - **Advanced Test Cases**: New comprehensive test files for heading structure and nested controls
14
+ - **Enhanced Alt Text Quality**: Improved context-aware alt text generation with better vocabulary support
15
+
16
+ ### Enhanced
17
+ - **Heading Analysis**: More comprehensive detection of heading issues including empty headings, level skipping, and duplicates
18
+ - **Interactive Controls**: Better handling of complex nested control scenarios
19
+ - **Test Coverage**: Expanded demo files for better testing and validation
20
+ - **Performance**: Optimized processing for large files and complex HTML structures
21
+
22
+ ### Fixed
23
+ - **Heading Level Corrections**: Automatic correction of improper heading hierarchies
24
+ - **Empty Heading Detection**: Better identification and handling of empty headings
25
+ - **Control Nesting Issues**: Improved resolution of nested interactive control conflicts
26
+
8
27
  ## [3.2.0] - 2024-07-28
9
28
 
10
29
  ### Added
package/README-vi.md CHANGED
@@ -18,7 +18,8 @@
18
18
  - 🔘 **Button Names** - Sửa buttons rỗng và input buttons không có tên
19
19
  - 🔗 **Link Names** - Sửa links rỗng và phát hiện text generic
20
20
  - 🏛️ **Landmarks** - Thêm main và navigation landmarks thiếu
21
- - 📑 **Phân tích Heading** - Phân tích cấu trúc heading với gợi ý (không tự động sửa)
21
+ - 📑 **Phân tích và Sửa Heading** - Phân tích cấu trúc heading với tùy chọn tự động sửa `--auto-fix-headings`
22
+ - 🎯 **Nested Controls Detection** - Phát hiện và sửa các control tương tác lồng nhau
22
23
  - 🔍 **Broken Links Detection** - Phát hiện liên kết bị hỏng và tài nguyên 404
23
24
  - 🧹 **Dọn dẹp Duplicate** - Loại bỏ role attributes trùng lặp
24
25
 
@@ -148,7 +149,8 @@ Chế độ sửa lỗi:
148
149
  --buttons-only Sửa button names + dọn dẹp
149
150
  --links-only Sửa link names + dọn dẹp
150
151
  --landmarks-only Sửa landmarks + dọn dẹp
151
- --headings-only Phân tích cấu trúc heading (không tự động sửa)
152
+ --headings-only Phân tích cấu trúc heading với tùy chọn tự động sửa
153
+ --auto-fix-headings Bật tự động sửa lỗi heading structure
152
154
  --links-check Kiểm tra liên kết bị hỏng và tài nguyên 404
153
155
  --cleanup-only Chỉ dọn dẹp role attributes trùng lặp
154
156
 
@@ -178,6 +180,8 @@ gbu-a11y -l en ./public
178
180
  gbu-a11y --alt-only # Sửa alt attributes + dọn dẹp
179
181
  gbu-a11y --forms-only # Sửa form labels + dọn dẹp
180
182
  gbu-a11y --buttons-only # Sửa button names + dọn dẹp
183
+ gbu-a11y --headings-only # Phân tích heading structure
184
+ gbu-a11y --headings-only --auto-fix-headings # Tự động sửa heading structure
181
185
  gbu-a11y --links-check # Kiểm tra liên kết bị hỏng + dọn dẹp
182
186
 
183
187
  # Tính năng enhanced alt attribute
@@ -308,7 +312,12 @@ console.log("Hoàn thành sửa lỗi với enhanced features:", results);
308
312
 
309
313
  - **Lang attributes thiếu** → Phát hiện ngôn ngữ tự động
310
314
  - **Landmark thiếu** → Main và navigation landmarks
311
- - **Cấu trúc heading** → Phân tích và khuyến nghị
315
+ - **Cấu trúc heading** → Phân tích và tự động sửa với `--auto-fix-headings`
316
+ - Sửa multiple h1 elements
317
+ - Sửa heading level skipping (h2 → h4)
318
+ - Thêm text cho empty headings
319
+ - Sửa duplicate headings
320
+ - **Nested interactive controls** → Phát hiện và sửa controls lồng nhau
312
321
  - **Role attributes** → Gán role tuân thủ WCAG
313
322
 
314
323
  ### Kiểm tra liên kết
package/README.md CHANGED
@@ -17,7 +17,8 @@
17
17
  - 🔘 **Button Names** - Fix empty buttons and input buttons without names
18
18
  - 🔗 **Link Names** - Fix empty links and detect generic link text
19
19
  - 🏛️ **Landmarks** - Add missing main and navigation landmarks
20
- - 📑 **Heading Analysis** - Analyze heading structure with suggestions (no auto-fix)
20
+ - 📑 **Heading Analysis & Auto-Fix** - Analyze heading structure with optional auto-fix using `--auto-fix-headings`
21
+ - 🎯 **Nested Controls Detection** - Detect and fix nested interactive controls
21
22
  - 🔍 **Broken Links Detection** - Detect broken links and 404 resources
22
23
  - 🧹 **Duplicate Cleanup** - Remove duplicate role attributes
23
24
 
@@ -145,7 +146,8 @@ Fix Modes:
145
146
  --buttons-only Fix button names + cleanup
146
147
  --links-only Fix link names + cleanup
147
148
  --landmarks-only Fix landmarks + cleanup
148
- --headings-only Analyze heading structure (no auto-fix)
149
+ --headings-only Analyze heading structure with optional auto-fix
150
+ --auto-fix-headings Enable automatic heading structure fixes
149
151
  --links-check Check for broken links and 404 resources
150
152
  --cleanup-only Only cleanup duplicate role attributes
151
153
 
@@ -175,6 +177,8 @@ gbu-a11y -l en ./public
175
177
  gbu-a11y --alt-only # Fix alt attributes + cleanup
176
178
  gbu-a11y --forms-only # Fix form labels + cleanup
177
179
  gbu-a11y --buttons-only # Fix button names + cleanup
180
+ gbu-a11y --headings-only # Analyze heading structure
181
+ gbu-a11y --headings-only --auto-fix-headings # Auto-fix heading structure
178
182
  gbu-a11y --links-check # Check broken links + cleanup
179
183
 
180
184
  # Enhanced alt attribute features
@@ -298,7 +302,12 @@ console.log('Accessibility fixes completed with enhanced features:', results);
298
302
  ### Document Structure
299
303
  - **Missing lang attributes** → Automatic language detection
300
304
  - **Missing landmarks** → Main and navigation landmarks
301
- - **Heading structure** → Analysis and recommendations
305
+ - **Heading structure** → Analysis and auto-fix with `--auto-fix-headings`
306
+ - Fix multiple h1 elements
307
+ - Fix heading level skipping (h2 → h4)
308
+ - Add text to empty headings
309
+ - Fix duplicate headings
310
+ - **Nested interactive controls** → Detect and fix nested controls
302
311
  - **Role attributes** → WCAG-compliant role assignments
303
312
 
304
313
  ### Link Validation
package/cli.js CHANGED
@@ -23,16 +23,21 @@ const options = {
23
23
  langOnly: false,
24
24
  roleOnly: false,
25
25
  formsOnly: false,
26
+ nestedOnly: false,
26
27
  buttonsOnly: false,
27
28
  linksOnly: false,
28
29
  landmarksOnly: false,
29
30
  headingsOnly: false,
31
+ dlOnly: false,
30
32
  brokenLinksOnly: false,
31
33
  // Enhanced alt options
32
34
  enhancedAlt: false,
33
35
  altCreativity: 'balanced', // conservative, balanced, creative
34
36
  includeEmotions: false,
35
- strictAltChecking: false
37
+ strictAltChecking: false,
38
+ // Advanced features options
39
+ autoFixHeadings: false,
40
+ fixDescriptionLists: true
36
41
  };
37
42
 
38
43
  // Parse arguments
@@ -80,6 +85,9 @@ for (let i = 0; i < args.length; i++) {
80
85
  case '--forms-only':
81
86
  options.formsOnly = true;
82
87
  break;
88
+ case '--nested-only':
89
+ options.nestedOnly = true;
90
+ break;
83
91
  case '--buttons-only':
84
92
  options.buttonsOnly = true;
85
93
  break;
@@ -92,10 +100,19 @@ for (let i = 0; i < args.length; i++) {
92
100
  case '--headings-only':
93
101
  options.headingsOnly = true;
94
102
  break;
103
+ case '--dl-only':
104
+ options.dlOnly = true;
105
+ break;
95
106
  case '--links-check':
96
107
  case '--broken-links':
97
108
  options.brokenLinksOnly = true;
98
109
  break;
110
+ case '--auto-fix-headings':
111
+ options.autoFixHeadings = true;
112
+ break;
113
+ case '--no-fix-dl':
114
+ options.fixDescriptionLists = false;
115
+ break;
99
116
  case '--enhanced-alt':
100
117
  options.enhancedAlt = true;
101
118
  break;
@@ -221,14 +238,16 @@ async function main() {
221
238
  enhancedAltMode: options.enhancedAlt,
222
239
  altCreativity: options.altCreativity,
223
240
  includeEmotions: options.includeEmotions,
224
- strictAltChecking: options.strictAltChecking
241
+ strictAltChecking: options.strictAltChecking,
242
+ autoFixHeadings: options.autoFixHeadings,
243
+ fixDescriptionLists: options.fixDescriptionLists
225
244
  });
226
245
 
227
246
  try {
228
247
  // Handle different modes - All modes now include cleanup
229
248
  if (options.cleanupOnly || options.altOnly || options.langOnly || options.roleOnly ||
230
- options.formsOnly || options.buttonsOnly || options.linksOnly || options.landmarksOnly ||
231
- options.headingsOnly || options.brokenLinksOnly) {
249
+ options.formsOnly || options.nestedOnly || options.buttonsOnly || options.linksOnly || options.landmarksOnly ||
250
+ options.headingsOnly || options.dlOnly || options.brokenLinksOnly) {
232
251
  // Individual modes - handle each separately, then run cleanup
233
252
  } else {
234
253
  // Default mode: Run comprehensive fix (all fixes including cleanup)
@@ -333,6 +352,24 @@ async function main() {
333
352
  showCompletionMessage(options, 'Form label fixes + cleanup');
334
353
  return;
335
354
 
355
+ } else if (options.nestedOnly) {
356
+ // Fix nested interactive controls + cleanup
357
+ console.log(chalk.blue('🎯 Running nested interactive controls fixes + cleanup...'));
358
+ const nestedResults = await fixer.fixNestedInteractiveControls(options.directory);
359
+ const nestedFixed = nestedResults.filter(r => r.status === 'fixed').length;
360
+ const totalNestedIssues = nestedResults.reduce((sum, r) => sum + (r.issues || 0), 0);
361
+
362
+ console.log(chalk.green(`\n✅ Fixed nested interactive controls in ${nestedFixed} files (${totalNestedIssues} issues)`));
363
+
364
+ // Run cleanup
365
+ console.log(chalk.blue('\n🧹 Running cleanup for duplicate role attributes...'));
366
+ const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
367
+ const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
368
+ console.log(chalk.green(`✅ Cleaned duplicate roles in ${cleanupFixed} files`));
369
+
370
+ showCompletionMessage(options, 'Nested interactive controls fixes + cleanup');
371
+ return;
372
+
336
373
  } else if (options.buttonsOnly) {
337
374
  // Fix button names + cleanup
338
375
  console.log(chalk.blue('🔘 Running button name fixes + cleanup...'));
@@ -388,15 +425,45 @@ async function main() {
388
425
  return;
389
426
 
390
427
  } else if (options.headingsOnly) {
391
- // Analyze headings only (no fixes, no cleanup)
392
- console.log(chalk.blue('📑 Running heading analysis only...'));
393
- const headingResults = await fixer.analyzeHeadings(options.directory);
394
- const totalSuggestions = headingResults.reduce((sum, r) => sum + (r.issues || 0), 0);
428
+ // Fix heading structure + cleanup
429
+ console.log(chalk.blue('📑 Running heading structure fixes + cleanup...'));
430
+ const headingResults = await fixer.fixHeadingStructure(options.directory);
431
+ const headingFixed = headingResults.filter(r => r.status === 'fixed').length;
432
+ const totalHeadingIssues = headingResults.reduce((sum, r) => sum + (r.issues || 0), 0);
433
+ const totalHeadingFixes = headingResults.reduce((sum, r) => sum + (r.fixes || 0), 0);
434
+
435
+ console.log(chalk.green(`\n✅ Processed headings in ${headingResults.length} files (${totalHeadingIssues} issues found)`));
436
+ if (options.autoFixHeadings) {
437
+ console.log(chalk.green(`✅ Fixed ${totalHeadingFixes} heading issues automatically`));
438
+ } else {
439
+ console.log(chalk.gray('💡 Use --auto-fix-headings to enable automatic heading fixes'));
440
+ }
395
441
 
396
- console.log(chalk.green(`\n✅ Analyzed headings in ${headingResults.length} files (${totalSuggestions} suggestions)`));
397
- console.log(chalk.gray('💡 Heading issues require manual review and cannot be auto-fixed'));
442
+ // Run cleanup
443
+ console.log(chalk.blue('\n🧹 Running cleanup for duplicate role attributes...'));
444
+ const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
445
+ const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
446
+ console.log(chalk.green(`✅ Cleaned duplicate roles in ${cleanupFixed} files`));
447
+
448
+ showCompletionMessage(options, 'Heading structure fixes + cleanup');
449
+ return;
450
+
451
+ } else if (options.dlOnly) {
452
+ // Fix description lists + cleanup
453
+ console.log(chalk.blue('📋 Running description list fixes + cleanup...'));
454
+ const dlResults = await fixer.fixDescriptionLists(options.directory);
455
+ const dlFixed = dlResults.filter(r => r.status === 'fixed').length;
456
+ const totalDlIssues = dlResults.reduce((sum, r) => sum + (r.issues || 0), 0);
457
+
458
+ console.log(chalk.green(`\n✅ Fixed description lists in ${dlFixed} files (${totalDlIssues} issues)`));
459
+
460
+ // Run cleanup
461
+ console.log(chalk.blue('\n🧹 Running cleanup for duplicate role attributes...'));
462
+ const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
463
+ const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
464
+ console.log(chalk.green(`✅ Cleaned duplicate roles in ${cleanupFixed} files`));
398
465
 
399
- showCompletionMessage(options, 'Heading analysis');
466
+ showCompletionMessage(options, 'Description list fixes + cleanup');
400
467
  return;
401
468
 
402
469
  } else if (options.brokenLinksOnly) {
@@ -0,0 +1,60 @@
1
+ <!DOCTYPE html>
2
+ <html lang="ja">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Heading Structure Test - Accessibility Issues</title>
7
+ </head>
8
+ <body>
9
+ <h1>Heading Structure Test Cases</h1>
10
+
11
+ <!-- Test Case 1: Missing h1 (this will be converted from h2) -->
12
+ <h2>This should be h1</h2>
13
+ <p>Main content of the page</p>
14
+
15
+ <!-- Test Case 2: Multiple h1 elements -->
16
+ <h1>First h1 (should stay)</h1>
17
+ <h1>Second h1 (should become h2)</h1>
18
+ <h1>Third h1 (should become h2)</h1>
19
+
20
+ <!-- Test Case 3: Level skipping -->
21
+ <h2>Section heading</h2>
22
+ <h4>Subsection (skips h3 - should become h3)</h4>
23
+ <h6>Sub-subsection (skips h4, h5 - should become h4)</h6>
24
+
25
+ <!-- Test Case 4: Empty headings -->
26
+ <h3></h3>
27
+ <h4> </h4>
28
+ <h5><span></span></h5>
29
+
30
+ <!-- Test Case 5: Duplicate headings -->
31
+ <h2>Products</h2>
32
+ <p>Some content about products</p>
33
+ <h2>Products</h2>
34
+ <p>More content about products</p>
35
+
36
+ <!-- Test Case 6: Proper structure (should not be changed) -->
37
+ <h2>Proper Section</h2>
38
+ <h3>Proper Subsection</h3>
39
+ <h4>Proper Sub-subsection</h4>
40
+ <p>Content with proper heading hierarchy</p>
41
+
42
+ <!-- Test Case 7: Complex nesting with issues -->
43
+ <h2>Services</h2>
44
+ <h5>Service 1 (should be h3)</h5>
45
+ <h6>Details (should be h4)</h6>
46
+ <h3>Service 2 (correct)</h3>
47
+ <h5>More details (should be h4)</h5>
48
+
49
+ <!-- Test Case 8: Empty headings with context -->
50
+ <div class="section">
51
+ <h3></h3>
52
+ <p>This section talks about our company history and achievements.</p>
53
+ </div>
54
+
55
+ <div class="product-info">
56
+ <h4> </h4>
57
+ <p>Our flagship product offers innovative solutions for modern businesses.</p>
58
+ </div>
59
+ </body>
60
+ </html>
@@ -0,0 +1,92 @@
1
+ <!DOCTYPE html>
2
+ <html lang="ja">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Nested Interactive Controls Test - Accessibility Issues</title>
7
+ </head>
8
+ <body>
9
+ <h1>Nested Interactive Controls Test Cases</h1>
10
+
11
+ <!-- Test Case 1: div[role="button"] containing links (like in the axe error) -->
12
+ <div class="card-buttons" role="button">
13
+ <a href="https://business.mobile.rakuten.co.jp/solution/service/rakuten-ai-for-business/?scid=we_solution09_2504" class="btn btn-secondary" target="_blank" role="link">詳細を見る</a>
14
+ <a href="https://business.mobile.rakuten.co.jp/solution/ai/inquiry/?l=id=solution_ai_inquiry1&amp;scid=we_solution10_2504" class="btn btn-primary" target="_blank" role="link">お問い合わせ</a>
15
+ </div>
16
+
17
+ <!-- Test Case 2: Button containing links -->
18
+ <button type="button" onclick="handleClick()">
19
+ <a href="/page1">Link inside button</a>
20
+ <span>Click me</span>
21
+ </button>
22
+
23
+ <!-- Test Case 3: Link containing button -->
24
+ <a href="/page2">
25
+ <button type="button">Button inside link</button>
26
+ </a>
27
+
28
+ <!-- Test Case 4: div[role="button"] containing input -->
29
+ <div role="button" tabindex="0" onclick="submit()">
30
+ <input type="text" placeholder="Search...">
31
+ <span>Submit</span>
32
+ </div>
33
+
34
+ <!-- Test Case 5: Link containing select -->
35
+ <a href="/settings">
36
+ <select name="language">
37
+ <option value="ja">Japanese</option>
38
+ <option value="en">English</option>
39
+ </select>
40
+ Settings
41
+ </a>
42
+
43
+ <!-- Test Case 6: Button containing textarea -->
44
+ <button type="submit">
45
+ <textarea name="comment" placeholder="Enter comment"></textarea>
46
+ <span>Send</span>
47
+ </button>
48
+
49
+ <!-- Test Case 7: Multiple levels of nesting -->
50
+ <div role="button" tabindex="0">
51
+ <div class="container">
52
+ <a href="/nested">
53
+ <button type="button">Deeply nested</button>
54
+ </a>
55
+ </div>
56
+ </div>
57
+
58
+ <!-- Test Case 8: div[role="button"] with tabindex containing interactive elements -->
59
+ <div role="button" tabindex="0" onclick="handleAction()">
60
+ <input type="checkbox" id="agree">
61
+ <label for="agree">I agree</label>
62
+ <a href="/terms">Terms</a>
63
+ </div>
64
+
65
+ <!-- Test Case 9: Link containing details/summary -->
66
+ <a href="/info">
67
+ <details>
68
+ <summary>More info</summary>
69
+ <p>Details content</p>
70
+ </details>
71
+ </a>
72
+
73
+ <!-- Test Case 10: Form elements nested in buttons -->
74
+ <button type="button" class="form-button">
75
+ <input type="radio" name="choice" value="1">
76
+ <input type="radio" name="choice" value="2">
77
+ <span>Choose option</span>
78
+ </button>
79
+
80
+ <!-- Test Case 11: Correct structure (should not be flagged) -->
81
+ <div class="card-buttons">
82
+ <a href="/page1" class="btn btn-secondary">詳細を見る</a>
83
+ <a href="/page2" class="btn btn-primary">お問い合わせ</a>
84
+ </div>
85
+
86
+ <!-- Test Case 12: Another correct structure -->
87
+ <button type="button" onclick="handleClick()">
88
+ <span>Click me</span>
89
+ <i class="icon"></i>
90
+ </button>
91
+ </body>
92
+ </html>