gbu-accessibility-package 1.5.0 โ†’ 1.6.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 CHANGED
@@ -9,6 +9,7 @@
9
9
  ## โœจ Features
10
10
 
11
11
  - ๐Ÿ–ผ๏ธ **Smart Alt Text Generation** - Context-aware alt attributes for images
12
+ - ๐Ÿท๏ธ **Aria Label Support** - Automatic aria-label matching alt text
12
13
  - ๐ŸŒ **HTML Lang Attributes** - Automatic language attribute fixes
13
14
  - ๐ŸŽญ **Role Attributes** - WCAG-compliant role attribute management
14
15
  - ๐Ÿงน **Duplicate Cleanup** - Remove duplicate role attributes
@@ -58,6 +59,7 @@ gbu-a11y [options] [directory/file]
58
59
  Options:
59
60
  -d, --directory <path> Target directory (default: current directory)
60
61
  -l, --language <lang> Language for lang attribute (default: ja)
62
+ --backup Create backup files (default: enabled)
61
63
  --no-backup Don't create backup files
62
64
  --dry-run Preview changes without applying
63
65
  --comprehensive, --all Run all fixes including cleanup (recommended)
@@ -82,7 +84,7 @@ gbu-a11y -l en ./public
82
84
 
83
85
  # Individual fix types
84
86
  gbu-a11y --alt-only # Only fix alt attributes
85
- gbu-a11y --lang-only # Only fix lang attributes
87
+ gbu-a11y --lang-only # Only fix lang attributes
86
88
  gbu-a11y --role-only # Only fix role attributes
87
89
  gbu-a11y --cleanup-only # Only cleanup duplicates
88
90
 
@@ -90,28 +92,29 @@ gbu-a11y --cleanup-only # Only cleanup duplicates
90
92
  gbu-a11y --alt-only --dry-run ./src # Preview alt fixes only
91
93
  gbu-a11y --role-only -l en ./public # Fix roles with English lang
92
94
 
93
- # Fix without creating backups
94
- gbu-a11y --no-backup ./dist
95
+ # Backup options
96
+ gbu-a11y --backup ./dist # Explicitly enable backups (default)
97
+ gbu-a11y --no-backup ./dist # Disable backups for faster processing
95
98
  ```
96
99
 
97
100
  ## ๐Ÿ”ง Programmatic Usage
98
101
 
99
102
  ```javascript
100
- const AccessibilityFixer = require('gbu-accessibility-package');
103
+ const AccessibilityFixer = require("gbu-accessibility-package");
101
104
 
102
105
  const fixer = new AccessibilityFixer({
103
- language: 'en',
106
+ language: "en",
104
107
  backupFiles: true,
105
- dryRun: false
108
+ dryRun: false,
106
109
  });
107
110
 
108
111
  // Fix all accessibility issues
109
112
  async function fixAccessibility() {
110
113
  try {
111
- const results = await fixer.fixAllAccessibilityIssues('./src');
112
- console.log('Fixed files:', results);
114
+ const results = await fixer.fixAllAccessibilityIssues("./src");
115
+ console.log("Fixed files:", results);
113
116
  } catch (error) {
114
- console.error('Error:', error);
117
+ console.error("Error:", error);
115
118
  }
116
119
  }
117
120
 
@@ -121,14 +124,16 @@ fixAccessibility();
121
124
  ## ๐ŸŽฏ Fix Modes
122
125
 
123
126
  ### Individual Fix Options
127
+
124
128
  You can now fix specific accessibility issues individually:
125
129
 
126
130
  - `--alt-only` - Only fix alt attributes for images
127
- - `--lang-only` - Only fix HTML lang attributes
131
+ - `--lang-only` - Only fix HTML lang attributes
128
132
  - `--role-only` - Only fix role attributes
129
133
  - `--cleanup-only` - Only cleanup duplicate role attributes
130
134
 
131
135
  ### Combined Modes
136
+
132
137
  - **Standard mode** (default) - Fixes alt, lang, and role attributes
133
138
  - `--comprehensive` - All fixes including duplicate cleanup
134
139
 
@@ -152,36 +157,41 @@ gbu-a11y --comprehensive
152
157
  ## ๐Ÿ”ง What Gets Fixed
153
158
 
154
159
  ### 1. Alt Attributes
160
+
155
161
  - **Missing alt attributes** โ†’ Adds contextual alt text
156
162
  - **Empty alt attributes** โ†’ Generates meaningful descriptions
157
163
  - **Context-aware generation** โ†’ Uses surrounding text, headings, captions
158
164
 
159
165
  ```html
160
166
  <!-- Before -->
161
- <img src="logo.png">
162
- <img src="chart.jpg" alt="">
167
+ <img src="logo.png" />
168
+ <img src="chart.jpg" alt="" />
163
169
 
164
170
  <!-- After -->
165
- <img src="logo.png" alt="ใƒญใ‚ด">
166
- <img src="chart.jpg" alt="ใ‚ฐใƒฉใƒ•">
171
+ <img src="logo.png" alt="ใƒญใ‚ด" />
172
+ <img src="chart.jpg" alt="ใ‚ฐใƒฉใƒ•" />
167
173
  ```
168
174
 
169
175
  ### 2. HTML Lang Attributes
176
+
170
177
  - **Missing lang attributes** โ†’ Adds specified language
171
178
  - **Empty lang attributes** โ†’ Sets proper language code
172
179
 
173
180
  ```html
174
181
  <!-- Before -->
175
182
  <html>
176
- <html lang="">
177
-
178
- <!-- After -->
179
- <html lang="ja">
180
- <html lang="ja">
183
+ <html lang="">
184
+ <!-- After -->
185
+ <html lang="ja">
186
+ <html lang="ja"></html>
187
+ </html>
188
+ </html>
189
+ </html>
181
190
  ```
182
191
 
183
- ### 3. Role Attributes
184
- - **Images** โ†’ `role="img"`
192
+ ### 3. Role Attributes & Aria Labels
193
+
194
+ - **Images** โ†’ `role="img"` + `aria-label` (matching alt text)
185
195
  - **Picture elements** โ†’ Moves `role="img"` from `<picture>` to `<img>` inside
186
196
  - **Links** โ†’ `role="link"`
187
197
  - **Clickable elements** โ†’ `role="button"`
@@ -190,33 +200,48 @@ gbu-a11y --comprehensive
190
200
 
191
201
  ```html
192
202
  <!-- Before -->
193
- <img src="icon.png" alt="Icon">
203
+ <img src="icon.png" alt="Icon" />
194
204
  <picture role="img">
195
- <img src="photo.jpg" alt="Photo">
205
+ <img src="photo.jpg" alt="Photo" />
196
206
  </picture>
197
207
  <a href="/home">Home</a>
198
208
  <div class="btn-click">Click me</div>
199
209
 
200
210
  <!-- After -->
201
- <img src="icon.png" alt="Icon" role="img">
211
+ <img src="icon.png" alt="Icon" role="img" aria-label="Icon" />
202
212
  <picture>
203
- <img src="photo.jpg" alt="Photo" role="img">
213
+ <img src="photo.jpg" alt="Photo" role="img" aria-label="Photo" />
204
214
  </picture>
205
215
  <a href="/home" role="link">Home</a>
206
216
  <div class="btn-click" role="button">Click me</div>
207
217
  ```
208
218
 
209
- ### 4. Duplicate Cleanup
219
+ ### 4. Aria Label Enhancement
220
+
221
+ - **Automatic aria-label** โ†’ Adds `aria-label` matching `alt` text for images
222
+ - **Preserves existing** โ†’ Won't override existing `aria-label` attributes
223
+ - **Smart detection** โ†’ Only adds when `alt` text exists and is not empty
224
+
225
+ ```html
226
+ <!-- Before -->
227
+ <img src="chart.jpg" alt="Sales Chart" />
228
+
229
+ <!-- After -->
230
+ <img src="chart.jpg" alt="Sales Chart" role="img" aria-label="Sales Chart" />
231
+ ```
232
+
233
+ ### 5. Duplicate Cleanup
234
+
210
235
  - **Removes duplicate role attributes**
211
236
  - **Preserves first occurrence**
212
237
  - **Handles mixed quote styles**
213
238
 
214
239
  ```html
215
240
  <!-- Before -->
216
- <img src="test.jpg" role="img" role="img" alt="Test">
241
+ <img src="test.jpg" role="img" role="img" alt="Test" />
217
242
 
218
243
  <!-- After -->
219
- <img src="test.jpg" role="img" alt="Test">
244
+ <img src="test.jpg" role="img" alt="Test" />
220
245
  ```
221
246
 
222
247
  ## ๐ŸŒŸ Smart Alt Text Generation
@@ -224,8 +249,9 @@ gbu-a11y --comprehensive
224
249
  The package uses intelligent context analysis to generate meaningful alt text:
225
250
 
226
251
  ### Context Sources
252
+
227
253
  1. **Title attributes**
228
- 2. **Aria-label attributes**
254
+ 2. **Aria-label attributes**
229
255
  3. **Definition terms (dt elements)**
230
256
  4. **Parent link text**
231
257
  5. **Nearby headings**
@@ -233,6 +259,7 @@ The package uses intelligent context analysis to generate meaningful alt text:
233
259
  7. **Surrounding text content**
234
260
 
235
261
  ### Fallback Patterns
262
+
236
263
  - `logo.png` โ†’ "ใƒญใ‚ด" (Logo)
237
264
  - `icon.svg` โ†’ "ใ‚ขใ‚คใ‚ณใƒณ" (Icon)
238
265
  - `banner.jpg` โ†’ "ใƒใƒŠใƒผ" (Banner)
@@ -242,6 +269,7 @@ The package uses intelligent context analysis to generate meaningful alt text:
242
269
  ## ๐Ÿ“Š Output Examples
243
270
 
244
271
  ### Standard Mode
272
+
245
273
  ```
246
274
  ๐Ÿš€ Starting Accessibility Fixer...
247
275
  ๐Ÿ“ Step 1: Fixing HTML lang attributes...
@@ -250,7 +278,7 @@ The package uses intelligent context analysis to generate meaningful alt text:
250
278
  ๐Ÿ–ผ๏ธ Step 2: Fixing alt attributes...
251
279
  โœ… Fixed alt attributes in 12 files (34 issues)
252
280
 
253
- ๐ŸŽญ Step 3: Fixing role attributes...
281
+ ๐ŸŽญ Step 3: Fixing role attributes...
254
282
  โœ… Fixed role attributes in 8 files (67 issues)
255
283
 
256
284
  ๐Ÿ“Š Summary:
@@ -262,6 +290,7 @@ The package uses intelligent context analysis to generate meaningful alt text:
262
290
  ```
263
291
 
264
292
  ### Comprehensive Mode
293
+
265
294
  ```
266
295
  ๐ŸŽฏ Running comprehensive accessibility fixes...
267
296
  ๐Ÿ“ Step 1: HTML lang attributes...
@@ -272,14 +301,30 @@ The package uses intelligent context analysis to generate meaningful alt text:
272
301
  ๐ŸŽ‰ All accessibility fixes completed!
273
302
  ๐Ÿ“Š Final Summary:
274
303
  Total files scanned: 25
275
- Files fixed: 15
304
+ Files fixed: 15
276
305
  Total issues resolved: 106
277
306
  ```
278
307
 
279
308
  ## ๐Ÿ”’ Safety Features
280
309
 
281
- - **Automatic backups** with `.backup` extension
282
- - **Dry run mode** for safe previewing
310
+ ### Backup Options
311
+ - **Default behavior**: Creates `.backup` files automatically for safety
312
+ - **Disable backups**: Use `--no-backup` for faster processing
313
+ - **Explicit enable**: Use `--backup` to be explicit about backup creation
314
+
315
+ ```bash
316
+ # Safe mode (default) - creates backups
317
+ gbu-a11y --comprehensive
318
+
319
+ # Fast mode - no backups
320
+ gbu-a11y --no-backup --comprehensive
321
+
322
+ # Explicit backup mode
323
+ gbu-a11y --backup --comprehensive
324
+ ```
325
+
326
+ ### Other Safety Features
327
+ - **Dry run mode** for safe previewing with `--dry-run`
283
328
  - **Non-destructive** - only adds missing attributes
284
329
  - **Duplicate prevention** - won't add existing attributes
285
330
  - **Error handling** - continues processing on individual file errors
@@ -287,6 +332,7 @@ The package uses intelligent context analysis to generate meaningful alt text:
287
332
  ## ๐Ÿ› ๏ธ Configuration
288
333
 
289
334
  ### Package.json Scripts
335
+
290
336
  ```json
291
337
  {
292
338
  "scripts": {
@@ -295,19 +341,20 @@ The package uses intelligent context analysis to generate meaningful alt text:
295
341
  "a11y:comprehensive": "gbu-a11y --comprehensive",
296
342
  "a11y:cleanup": "gbu-a11y --cleanup-only",
297
343
  "a11y:alt": "gbu-a11y --alt-only",
298
- "a11y:lang": "gbu-a11y --lang-only",
344
+ "a11y:lang": "gbu-a11y --lang-only",
299
345
  "a11y:role": "gbu-a11y --role-only"
300
346
  }
301
347
  }
302
348
  ```
303
349
 
304
350
  ### CI/CD Integration
351
+
305
352
  ```yaml
306
353
  # GitHub Actions example
307
354
  - name: Check Accessibility
308
355
  run: npx gbu-accessibility-package --dry-run
309
356
 
310
- - name: Fix Accessibility Issues
357
+ - name: Fix Accessibility Issues
311
358
  run: npx gbu-accessibility-package --comprehensive
312
359
  ```
313
360
 
@@ -340,4 +387,4 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
340
387
 
341
388
  ---
342
389
 
343
- Made with โค๏ธ by the GBU Team
390
+ Made with โค๏ธ by the GBU Team
package/cli.js CHANGED
@@ -14,7 +14,7 @@ const args = process.argv.slice(2);
14
14
  const options = {
15
15
  directory: '.',
16
16
  language: 'ja',
17
- backupFiles: true,
17
+ backupFiles: true, // Default to true for safety
18
18
  dryRun: false,
19
19
  help: false,
20
20
  cleanupOnly: false,
@@ -41,6 +41,9 @@ for (let i = 0; i < args.length; i++) {
41
41
  case '-l':
42
42
  options.language = args[++i];
43
43
  break;
44
+ case '--backup':
45
+ options.backupFiles = true;
46
+ break;
44
47
  case '--no-backup':
45
48
  options.backupFiles = false;
46
49
  break;
@@ -80,6 +83,7 @@ Usage: node cli.js [options] [directory]
80
83
  Options:
81
84
  -d, --directory <path> Target directory (default: current directory)
82
85
  -l, --language <lang> Language for lang attribute (default: ja)
86
+ --backup Create backup files (default: enabled)
83
87
  --no-backup Don't create backup files
84
88
  --dry-run Preview changes without applying
85
89
  --comprehensive, --all Run all fixes including cleanup (recommended)
@@ -90,7 +94,7 @@ Options:
90
94
  -h, --help Show this help message
91
95
 
92
96
  Examples:
93
- node cli.js # Fix current directory (standard fixes)
97
+ node cli.js # Fix current directory (with backups)
94
98
  node cli.js --comprehensive # Run all fixes including cleanup
95
99
  node cli.js --alt-only # Only fix alt attributes
96
100
  node cli.js --lang-only # Only fix lang attributes
@@ -99,6 +103,7 @@ Examples:
99
103
  node cli.js ./src # Fix src directory
100
104
  node cli.js -l en --dry-run ./dist # Preview fixes for dist directory in English
101
105
  node cli.js --no-backup ./public # Fix without creating backups
106
+ node cli.js --backup --comprehensive # Explicitly enable backups with all fixes
102
107
 
103
108
  Features:
104
109
  โœ… Alt attributes for images
@@ -110,6 +115,22 @@ Features:
110
115
  process.exit(0);
111
116
  }
112
117
 
118
+ // Helper function to show completion message with backup info
119
+ function showCompletionMessage(options, mode = 'fixes') {
120
+ if (options.dryRun) {
121
+ console.log(chalk.cyan('\n๐Ÿ’ก This was a dry run. Use without --dry-run to apply changes.'));
122
+ } else {
123
+ console.log(chalk.green(`\n๐ŸŽ‰ ${mode} completed successfully!`));
124
+ if (options.backupFiles) {
125
+ console.log(chalk.gray(' ๐Ÿ“ Backup files created with .backup extension'));
126
+ console.log(chalk.gray(' ๐Ÿ’ก Use --no-backup to disable backups in future runs'));
127
+ } else {
128
+ console.log(chalk.yellow(' โš ๏ธ No backup files created (--no-backup was used)'));
129
+ console.log(chalk.gray(' ๐Ÿ’ก Use --backup to enable backups for safety'));
130
+ }
131
+ }
132
+ }
133
+
113
134
  // Main function
114
135
  async function main() {
115
136
  console.log(chalk.blue('๐Ÿš€ Starting Accessibility Fixer...'));
@@ -143,11 +164,7 @@ async function main() {
143
164
 
144
165
  console.log(chalk.green(`\nโœ… Cleaned duplicate roles in ${cleanupFixed} files`));
145
166
 
146
- if (options.dryRun) {
147
- console.log(chalk.cyan('\n๐Ÿ’ก This was a dry run. Use without --dry-run to apply changes.'));
148
- } else {
149
- console.log(chalk.green('\n๐ŸŽ‰ Cleanup completed successfully!'));
150
- }
167
+ showCompletionMessage(options, 'Cleanup');
151
168
  return;
152
169
 
153
170
  } else if (options.altOnly) {
@@ -159,11 +176,7 @@ async function main() {
159
176
 
160
177
  console.log(chalk.green(`\nโœ… Fixed alt attributes in ${altFixed} files (${totalAltIssues} issues)`));
161
178
 
162
- if (options.dryRun) {
163
- console.log(chalk.cyan('\n๐Ÿ’ก This was a dry run. Use without --dry-run to apply changes.'));
164
- } else {
165
- console.log(chalk.green('\n๐ŸŽ‰ Alt attribute fixes completed successfully!'));
166
- }
179
+ showCompletionMessage(options, 'Alt attribute fixes');
167
180
  return;
168
181
 
169
182
  } else if (options.langOnly) {
@@ -174,11 +187,7 @@ async function main() {
174
187
 
175
188
  console.log(chalk.green(`\nโœ… Fixed lang attributes in ${langFixed} files`));
176
189
 
177
- if (options.dryRun) {
178
- console.log(chalk.cyan('\n๐Ÿ’ก This was a dry run. Use without --dry-run to apply changes.'));
179
- } else {
180
- console.log(chalk.green('\n๐ŸŽ‰ Lang attribute fixes completed successfully!'));
181
- }
190
+ showCompletionMessage(options, 'Lang attribute fixes');
182
191
  return;
183
192
 
184
193
  } else if (options.roleOnly) {
@@ -190,11 +199,7 @@ async function main() {
190
199
 
191
200
  console.log(chalk.green(`\nโœ… Fixed role attributes in ${roleFixed} files (${totalRoleIssues} issues)`));
192
201
 
193
- if (options.dryRun) {
194
- console.log(chalk.cyan('\n๐Ÿ’ก This was a dry run. Use without --dry-run to apply changes.'));
195
- } else {
196
- console.log(chalk.green('\n๐ŸŽ‰ Role attribute fixes completed successfully!'));
197
- }
202
+ showCompletionMessage(options, 'Role attribute fixes');
198
203
  return;
199
204
  }
200
205
 
@@ -242,14 +247,7 @@ async function main() {
242
247
  console.log(chalk.green(` Files fixed: ${totalFixed}`));
243
248
  console.log(chalk.yellow(` Total issues resolved: ${totalIssues}`));
244
249
 
245
- if (options.dryRun) {
246
- console.log(chalk.cyan('\n๐Ÿ’ก This was a dry run. Use without --dry-run to apply changes.'));
247
- } else {
248
- console.log(chalk.green('\n๐ŸŽ‰ All accessibility fixes completed successfully!'));
249
- if (options.backupFiles) {
250
- console.log(chalk.gray(' Backup files created with .backup extension'));
251
- }
252
- }
250
+ showCompletionMessage(options, 'All accessibility fixes');
253
251
 
254
252
  // Suggest cleanup if not comprehensive mode
255
253
  console.log(chalk.blue('\n๐Ÿ’ก Pro tip: Use --comprehensive to include duplicate role cleanup!'));
@@ -0,0 +1,32 @@
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>Aria Label Test</title>
7
+ </head>
8
+ <body>
9
+ <h1>Aria Label Test Cases</h1>
10
+
11
+ <!-- Test case 1: Image with alt but no aria-label -->
12
+ <img src="test1.jpg" alt="Test image 1" role="img" aria-label="Test image 1">
13
+
14
+ <!-- Test case 2: Image with alt and existing aria-label (should not change) -->
15
+ <img src="test2.jpg" alt="Test image 2" aria-label="Custom label" role="img">
16
+
17
+ <!-- Test case 3: Image with empty alt (should not add aria-label) -->
18
+ <img src="test3.jpg" alt="" role="img">
19
+
20
+ <!-- Test case 4: Image without alt (should generate alt and aria-label) -->
21
+ <img src="logo.png" role="img">
22
+
23
+ <!-- Test case 5: Picture with role and img with alt -->
24
+ <picture>
25
+ <source srcset="responsive.webp" type="image/webp">
26
+ <img src="responsive.jpg" alt="Responsive image" role="img" aria-label="Responsive image">
27
+ </picture>
28
+
29
+ <!-- Test case 6: Image with role but no aria-label -->
30
+ <img src="test6.jpg" alt="Test image 6" role="img" aria-label="Test image 6">
31
+ </body>
32
+ </html>
@@ -0,0 +1,18 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Backup Test</title>
6
+ </head>
7
+ <body>
8
+ <h1>Backup Test File</h1>
9
+
10
+ <!-- This will be fixed -->
11
+ <img src="test.jpg" alt="Test image" role="img" aria-label="Test image">
12
+
13
+ <!-- This will also be fixed -->
14
+ <a href="/home" role="link">Home Link</a>
15
+
16
+ <p>This file is used to test backup functionality.</p>
17
+ </body>
18
+ </html>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>No Backup Test</title>
6
+ </head>
7
+ <body>
8
+ <h1>No Backup Test File</h1>
9
+
10
+ <img src="test2.jpg" alt="Test image 2" role="img" aria-label="Test image 2">
11
+ <a href="/about" role="link">About Link</a>
12
+ </body>
13
+ </html>
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Explicit Backup Test</title>
6
+ </head>
7
+ <body>
8
+ <h1>Explicit Backup Test File</h1>
9
+
10
+ <img src="test3.jpg" alt="Test image 3" role="img" aria-label="Test image 3">
11
+ </body>
12
+ </html>
package/lib/fixer.js CHANGED
@@ -563,7 +563,7 @@ class AccessibilityFixer {
563
563
  }
564
564
  ];
565
565
 
566
- // Check for images that need role="img"
566
+ // Check for images that need role="img" and aria-label
567
567
  const images = content.match(/<img[^>]*>/gi) || [];
568
568
  images.forEach((img, index) => {
569
569
  if (!img.includes('role=')) {
@@ -573,6 +573,18 @@ class AccessibilityFixer {
573
573
  element: img.substring(0, 100) + '...'
574
574
  });
575
575
  }
576
+
577
+ // Check for missing aria-label when alt exists
578
+ const hasAriaLabel = /aria-label\s*=/i.test(img);
579
+ const altMatch = img.match(/alt\s*=\s*["']([^"']*)["']/i);
580
+
581
+ if (!hasAriaLabel && altMatch && altMatch[1].trim()) {
582
+ issues.push({
583
+ type: '๐Ÿท๏ธ Missing aria-label',
584
+ description: `Image ${index + 1} should have aria-label matching alt text`,
585
+ element: img.substring(0, 100) + '...'
586
+ });
587
+ }
576
588
  });
577
589
 
578
590
  // Check for button elements with onclick that need role
@@ -676,7 +688,17 @@ class AccessibilityFixer {
676
688
  const pictureWithoutRole = pictureBlock.replace(/\s*role\s*=\s*["']img["']/i, '');
677
689
 
678
690
  // Add role="img" to img element
679
- const imgWithRole = imgTag.replace(/(<img[^>]*?)(\s*>)/i, '$1 role="img"$2');
691
+ let imgWithRole = imgTag.replace(/(<img[^>]*?)(\s*>)/i, '$1 role="img"$2');
692
+
693
+ // Also add aria-label if img has alt but no aria-label
694
+ const imgHasAriaLabel = /aria-label\s*=/i.test(imgWithRole);
695
+ const altMatch = imgWithRole.match(/alt\s*=\s*["']([^"']*)["']/i);
696
+
697
+ if (!imgHasAriaLabel && altMatch && altMatch[1].trim()) {
698
+ const altText = altMatch[1].trim();
699
+ imgWithRole = imgWithRole.replace(/(<img[^>]*?)(\s*>)/i, `$1 aria-label="${altText}"$2`);
700
+ console.log(chalk.yellow(` ๐Ÿท๏ธ Added aria-label="${altText}" to moved img element`));
701
+ }
680
702
 
681
703
  // Replace the img in the modified picture block
682
704
  const updatedPictureBlock = pictureWithoutRole.replace(imgTag, imgWithRole);
@@ -698,16 +720,33 @@ class AccessibilityFixer {
698
720
  // Fix picture elements with img children - move role from picture to img
699
721
  fixed = this.fixPictureImgRoles(fixed);
700
722
 
701
- // Fix all images - add role="img" (only if no role exists)
723
+ // Fix all images - add role="img" and aria-label
702
724
  fixed = fixed.replace(
703
725
  /<img([^>]*>)/gi,
704
- (match, fullTag) => {
726
+ (match) => {
727
+ let updatedImg = match;
728
+ let hasChanges = false;
729
+
705
730
  // Check if role attribute already exists
706
- if (/role\s*=/i.test(match)) {
707
- return match; // Return unchanged if role already exists
731
+ if (!/role\s*=/i.test(match)) {
732
+ updatedImg = updatedImg.replace(/(<img[^>]*?)(\s*>)/i, '$1 role="img"$2');
733
+ console.log(chalk.yellow(` ๐Ÿ–ผ๏ธ Added role="img" to image element`));
734
+ hasChanges = true;
708
735
  }
709
- console.log(chalk.yellow(` ๐Ÿ–ผ๏ธ Added role="img" to image element`));
710
- return match.replace(/(<img[^>]*?)(\s*>)/i, '$1 role="img"$2');
736
+
737
+ // Check if aria-label already exists
738
+ if (!/aria-label\s*=/i.test(match)) {
739
+ // Extract alt text to use for aria-label
740
+ const altMatch = match.match(/alt\s*=\s*["']([^"']*)["']/i);
741
+ if (altMatch && altMatch[1].trim()) {
742
+ const altText = altMatch[1].trim();
743
+ updatedImg = updatedImg.replace(/(<img[^>]*?)(\s*>)/i, `$1 aria-label="${altText}"$2`);
744
+ console.log(chalk.yellow(` ๐Ÿท๏ธ Added aria-label="${altText}" to image element`));
745
+ hasChanges = true;
746
+ }
747
+ }
748
+
749
+ return updatedImg;
711
750
  }
712
751
  );
713
752
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gbu-accessibility-package",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Automated accessibility fixes for HTML files - Alt attributes, Lang attributes, Role attributes. Smart context-aware alt text generation with individual fix options and comprehensive role attribute management.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -16,6 +16,8 @@
16
16
  "lang-only": "node cli.js --lang-only",
17
17
  "role-only": "node cli.js --role-only",
18
18
  "cleanup-only": "node cli.js --cleanup-only",
19
+ "no-backup": "node cli.js --no-backup",
20
+ "cleanup-backups": "find . -name '*.backup' -type f -delete",
19
21
  "test": "node test-package.js",
20
22
  "demo": "node cli.js --dry-run demo",
21
23
  "prepublishOnly": "npm run test"
@@ -1,45 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="ja">
3
- <head>
4
- <title>Test Duplicate Roles</title>
5
- </head>
6
- <body>
7
- <h1>Test Duplicate Role Attributes</h1>
8
-
9
- <!-- Images with duplicate roles -->
10
- <img src="logo.png" alt="Logo" role="img" role="img" role="img" role="img">
11
- <img src="banner.jpg" alt="Banner" role="img" role="img" role="img" role="img" role="img">
12
-
13
- <!-- Links with duplicate roles -->
14
- <a href="/home" role="link" role="link" role="link" role="link">Home</a>
15
- <a href="/about" role="link" role="link" role="link" role="link" role="link">About</a>
16
-
17
- <!-- Buttons with duplicate roles -->
18
- <button onclick="submit()" role="button" role="button" role="button" role="button">Submit</button>
19
- <button type="button" role="button" role="button" role="button">Click Me</button>
20
-
21
- <!-- Mixed quotes -->
22
- <div onclick="toggle()" role="button" role='button' role="button" role="button">Toggle</div>
23
- <span onclick="show()" role='button' role="button" role="button" role="button">Show</span>
24
-
25
- <!-- Navigation with duplicates -->
26
- <nav>
27
- <ul class="nav-menu" role="menubar" role="menubar" role="menubar" role="menubar">
28
- <li class="nav-item" role="menuitem" role="menuitem" role="menuitem" role="menuitem">
29
- <a href="/products" role="link" role="link" role="link" role="link">Products</a>
30
- </li>
31
- <li class="nav-item" role="menuitem" role="menuitem" role="menuitem" role="menuitem" role="menuitem">
32
- <a href="/services" role="link" role="link" role="link" role="link" role="link">Services</a>
33
- </li>
34
- </ul>
35
- </nav>
36
-
37
- <!-- Complex duplicates -->
38
- <article>
39
- <h2>Article with Issues</h2>
40
- <img src="article1.jpg" alt="Article Image" role="img" role="img" role="img" role="img">
41
- <p>Some content...</p>
42
- <a href="/read-more" role="link" role="link" role="link" role="link" role="link" role="link">Read More</a>
43
- </article>
44
- </body>
45
- </html>
@@ -1,37 +0,0 @@
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>Picture Role Test</title>
7
- </head>
8
- <body>
9
- <h1>Picture Role Test Cases</h1>
10
-
11
- <!-- Test case 1: Picture with role="img" containing img without role -->
12
- <picture>
13
- <source srcset="image.webp" type="image/webp">
14
- <img src="image.jpg" alt="Test image" role="img">
15
- </picture>
16
-
17
- <!-- Test case 2: Picture with role="img" containing img with role (should not change) -->
18
- <picture role="img">
19
- <source srcset="image2.webp" type="image/webp">
20
- <img src="image2.jpg" alt="Test image 2" role="img">
21
- </picture>
22
-
23
- <!-- Test case 3: Picture without role containing img without role (should add role to img) -->
24
- <picture>
25
- <source srcset="image3.webp" type="image/webp">
26
- <img src="image3.jpg" alt="Test image 3" role="img">
27
- </picture>
28
-
29
- <!-- Test case 4: Regular img without role (should add role) -->
30
- <img src="regular.jpg" alt="Regular image" role="img">
31
-
32
- <!-- Test case 5: Picture with role="img" but no img inside (should not change) -->
33
- <picture role="img">
34
- <source srcset="video.webp" type="image/webp">
35
- </picture>
36
- </body>
37
- </html>
@@ -1,37 +0,0 @@
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>Picture Role Test</title>
7
- </head>
8
- <body>
9
- <h1>Picture Role Test Cases</h1>
10
-
11
- <!-- Test case 1: Picture with role="img" containing img without role -->
12
- <picture role="img">
13
- <source srcset="image.webp" type="image/webp">
14
- <img src="image.jpg" alt="Test image">
15
- </picture>
16
-
17
- <!-- Test case 2: Picture with role="img" containing img with role (should not change) -->
18
- <picture role="img">
19
- <source srcset="image2.webp" type="image/webp">
20
- <img src="image2.jpg" alt="Test image 2" role="img">
21
- </picture>
22
-
23
- <!-- Test case 3: Picture without role containing img without role (should add role to img) -->
24
- <picture>
25
- <source srcset="image3.webp" type="image/webp">
26
- <img src="image3.jpg" alt="Test image 3">
27
- </picture>
28
-
29
- <!-- Test case 4: Regular img without role (should add role) -->
30
- <img src="regular.jpg" alt="Regular image">
31
-
32
- <!-- Test case 5: Picture with role="img" but no img inside (should not change) -->
33
- <picture role="img">
34
- <source srcset="video.webp" type="image/webp">
35
- </picture>
36
- </body>
37
- </html>
@@ -1,47 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="ja">
3
- <head>
4
- <title>Demo HTML for Accessibility Testing</title>
5
- </head>
6
- <body>
7
- <h1>Sample Website</h1>
8
-
9
- <!-- Images without alt or role -->
10
- <img src="logo.png" alt="Sample Website" role="img" role="img" role="img">
11
- <img src="banner.jpg" alt="Sample Website" role="img" role="img" role="img">
12
- <img src="icon.svg" alt="Home Icon" role="img" role="img" role="img">
13
-
14
- <!-- Links without role -->
15
- <a href="/home" role="link" role="link" role="link">Home</a>
16
- <a href="/about" role="link" role="link" role="link">About Us</a>
17
-
18
- <!-- Buttons without role -->
19
- <button onclick="submit()" role="button" role="button" role="button">Submit Form</button>
20
- <button type="button">Regular Button</button>
21
-
22
- <!-- Clickable elements -->
23
- <div onclick="navigate()" class="btn" role="button" role="button" role="button" role="button" role="button" role="button">Click Me</div>
24
- <span onclick="toggle()" role="button" role="button" role="button">Toggle</span>
25
-
26
- <!-- Navigation -->
27
- <nav>
28
- <ul class="nav-menu" role="menubar" role="menubar" role="menubar">
29
- <li class="nav-item"><a href="/products" role="link" role="link" role="link">Products</a></li>
30
- <li class="nav-item"><a href="/services" role="link" role="link" role="link">Services</a></li>
31
- </ul>
32
- </nav>
33
-
34
- <!-- More content -->
35
- <main>
36
- <article>
37
- <h2>Article Title</h2>
38
- <p>Some content here...</p>
39
- <img src="article-image.jpg" alt="Article Title" role="img" role="img" role="img">
40
- </article>
41
- </main>
42
-
43
- <footer>
44
- <p>&copy; 2024 Demo Company</p>
45
- </footer>
46
- </body>
47
- </html>