gbu-accessibility-package 1.4.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 +88 -34
- package/cli.js +28 -30
- package/demo/aria-label-test.html +32 -0
- package/demo/backup-test.html +18 -0
- package/demo/backup-test2.html +13 -0
- package/demo/backup-test3.html +12 -0
- package/lib/fixer.js +101 -7
- package/package.json +3 -1
- package/demo/duplicate-roles.html.backup +0 -45
- package/demo/sample.html.backup +0 -47
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
|
-
#
|
|
94
|
-
gbu-a11y --
|
|
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(
|
|
103
|
+
const AccessibilityFixer = require("gbu-accessibility-package");
|
|
101
104
|
|
|
102
105
|
const fixer = new AccessibilityFixer({
|
|
103
|
-
language:
|
|
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(
|
|
112
|
-
console.log(
|
|
114
|
+
const results = await fixer.fixAllAccessibilityIssues("./src");
|
|
115
|
+
console.log("Fixed files:", results);
|
|
113
116
|
} catch (error) {
|
|
114
|
-
console.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,42 @@ 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
|
-
|
|
179
|
-
<html lang="ja">
|
|
180
|
-
|
|
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
|
-
|
|
192
|
+
### 3. Role Attributes & Aria Labels
|
|
193
|
+
|
|
194
|
+
- **Images** โ `role="img"` + `aria-label` (matching alt text)
|
|
195
|
+
- **Picture elements** โ Moves `role="img"` from `<picture>` to `<img>` inside
|
|
185
196
|
- **Links** โ `role="link"`
|
|
186
197
|
- **Clickable elements** โ `role="button"`
|
|
187
198
|
- **Navigation lists** โ `role="menubar"`
|
|
@@ -189,27 +200,48 @@ gbu-a11y --comprehensive
|
|
|
189
200
|
|
|
190
201
|
```html
|
|
191
202
|
<!-- Before -->
|
|
192
|
-
<img src="icon.png" alt="Icon"
|
|
203
|
+
<img src="icon.png" alt="Icon" />
|
|
204
|
+
<picture role="img">
|
|
205
|
+
<img src="photo.jpg" alt="Photo" />
|
|
206
|
+
</picture>
|
|
193
207
|
<a href="/home">Home</a>
|
|
194
208
|
<div class="btn-click">Click me</div>
|
|
195
209
|
|
|
196
210
|
<!-- After -->
|
|
197
|
-
<img src="icon.png" alt="Icon" role="img"
|
|
211
|
+
<img src="icon.png" alt="Icon" role="img" aria-label="Icon" />
|
|
212
|
+
<picture>
|
|
213
|
+
<img src="photo.jpg" alt="Photo" role="img" aria-label="Photo" />
|
|
214
|
+
</picture>
|
|
198
215
|
<a href="/home" role="link">Home</a>
|
|
199
216
|
<div class="btn-click" role="button">Click me</div>
|
|
200
217
|
```
|
|
201
218
|
|
|
202
|
-
### 4.
|
|
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
|
+
|
|
203
235
|
- **Removes duplicate role attributes**
|
|
204
236
|
- **Preserves first occurrence**
|
|
205
237
|
- **Handles mixed quote styles**
|
|
206
238
|
|
|
207
239
|
```html
|
|
208
240
|
<!-- Before -->
|
|
209
|
-
<img src="test.jpg" role="img" role="img" alt="Test"
|
|
241
|
+
<img src="test.jpg" role="img" role="img" alt="Test" />
|
|
210
242
|
|
|
211
243
|
<!-- After -->
|
|
212
|
-
<img src="test.jpg" role="img" alt="Test"
|
|
244
|
+
<img src="test.jpg" role="img" alt="Test" />
|
|
213
245
|
```
|
|
214
246
|
|
|
215
247
|
## ๐ Smart Alt Text Generation
|
|
@@ -217,8 +249,9 @@ gbu-a11y --comprehensive
|
|
|
217
249
|
The package uses intelligent context analysis to generate meaningful alt text:
|
|
218
250
|
|
|
219
251
|
### Context Sources
|
|
252
|
+
|
|
220
253
|
1. **Title attributes**
|
|
221
|
-
2. **Aria-label attributes**
|
|
254
|
+
2. **Aria-label attributes**
|
|
222
255
|
3. **Definition terms (dt elements)**
|
|
223
256
|
4. **Parent link text**
|
|
224
257
|
5. **Nearby headings**
|
|
@@ -226,6 +259,7 @@ The package uses intelligent context analysis to generate meaningful alt text:
|
|
|
226
259
|
7. **Surrounding text content**
|
|
227
260
|
|
|
228
261
|
### Fallback Patterns
|
|
262
|
+
|
|
229
263
|
- `logo.png` โ "ใญใด" (Logo)
|
|
230
264
|
- `icon.svg` โ "ใขใคใณใณ" (Icon)
|
|
231
265
|
- `banner.jpg` โ "ใใใผ" (Banner)
|
|
@@ -235,6 +269,7 @@ The package uses intelligent context analysis to generate meaningful alt text:
|
|
|
235
269
|
## ๐ Output Examples
|
|
236
270
|
|
|
237
271
|
### Standard Mode
|
|
272
|
+
|
|
238
273
|
```
|
|
239
274
|
๐ Starting Accessibility Fixer...
|
|
240
275
|
๐ Step 1: Fixing HTML lang attributes...
|
|
@@ -243,7 +278,7 @@ The package uses intelligent context analysis to generate meaningful alt text:
|
|
|
243
278
|
๐ผ๏ธ Step 2: Fixing alt attributes...
|
|
244
279
|
โ
Fixed alt attributes in 12 files (34 issues)
|
|
245
280
|
|
|
246
|
-
๐ญ Step 3: Fixing role attributes...
|
|
281
|
+
๐ญ Step 3: Fixing role attributes...
|
|
247
282
|
โ
Fixed role attributes in 8 files (67 issues)
|
|
248
283
|
|
|
249
284
|
๐ Summary:
|
|
@@ -255,6 +290,7 @@ The package uses intelligent context analysis to generate meaningful alt text:
|
|
|
255
290
|
```
|
|
256
291
|
|
|
257
292
|
### Comprehensive Mode
|
|
293
|
+
|
|
258
294
|
```
|
|
259
295
|
๐ฏ Running comprehensive accessibility fixes...
|
|
260
296
|
๐ Step 1: HTML lang attributes...
|
|
@@ -265,14 +301,30 @@ The package uses intelligent context analysis to generate meaningful alt text:
|
|
|
265
301
|
๐ All accessibility fixes completed!
|
|
266
302
|
๐ Final Summary:
|
|
267
303
|
Total files scanned: 25
|
|
268
|
-
Files fixed: 15
|
|
304
|
+
Files fixed: 15
|
|
269
305
|
Total issues resolved: 106
|
|
270
306
|
```
|
|
271
307
|
|
|
272
308
|
## ๐ Safety Features
|
|
273
309
|
|
|
274
|
-
|
|
275
|
-
- **
|
|
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`
|
|
276
328
|
- **Non-destructive** - only adds missing attributes
|
|
277
329
|
- **Duplicate prevention** - won't add existing attributes
|
|
278
330
|
- **Error handling** - continues processing on individual file errors
|
|
@@ -280,6 +332,7 @@ The package uses intelligent context analysis to generate meaningful alt text:
|
|
|
280
332
|
## ๐ ๏ธ Configuration
|
|
281
333
|
|
|
282
334
|
### Package.json Scripts
|
|
335
|
+
|
|
283
336
|
```json
|
|
284
337
|
{
|
|
285
338
|
"scripts": {
|
|
@@ -288,19 +341,20 @@ The package uses intelligent context analysis to generate meaningful alt text:
|
|
|
288
341
|
"a11y:comprehensive": "gbu-a11y --comprehensive",
|
|
289
342
|
"a11y:cleanup": "gbu-a11y --cleanup-only",
|
|
290
343
|
"a11y:alt": "gbu-a11y --alt-only",
|
|
291
|
-
"a11y:lang": "gbu-a11y --lang-only",
|
|
344
|
+
"a11y:lang": "gbu-a11y --lang-only",
|
|
292
345
|
"a11y:role": "gbu-a11y --role-only"
|
|
293
346
|
}
|
|
294
347
|
}
|
|
295
348
|
```
|
|
296
349
|
|
|
297
350
|
### CI/CD Integration
|
|
351
|
+
|
|
298
352
|
```yaml
|
|
299
353
|
# GitHub Actions example
|
|
300
354
|
- name: Check Accessibility
|
|
301
355
|
run: npx gbu-accessibility-package --dry-run
|
|
302
356
|
|
|
303
|
-
- name: Fix Accessibility Issues
|
|
357
|
+
- name: Fix Accessibility Issues
|
|
304
358
|
run: npx gbu-accessibility-package --comprehensive
|
|
305
359
|
```
|
|
306
360
|
|
|
@@ -333,4 +387,4 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
|
333
387
|
|
|
334
388
|
---
|
|
335
389
|
|
|
336
|
-
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
@@ -637,22 +649,104 @@ class AccessibilityFixer {
|
|
|
637
649
|
}
|
|
638
650
|
});
|
|
639
651
|
|
|
652
|
+
// Check for picture elements with role="img" that contain img elements
|
|
653
|
+
const pictureWithImgPattern = /<picture[^>]*role\s*=\s*["']img["'][^>]*>[\s\S]*?<img[^>]*>[\s\S]*?<\/picture>/gi;
|
|
654
|
+
const pictureWithImgMatches = content.match(pictureWithImgPattern) || [];
|
|
655
|
+
pictureWithImgMatches.forEach((pictureBlock, index) => {
|
|
656
|
+
const imgInPicture = pictureBlock.match(/<img[^>]*>/i);
|
|
657
|
+
if (imgInPicture && !/role\s*=/i.test(imgInPicture[0])) {
|
|
658
|
+
issues.push({
|
|
659
|
+
type: '๐ผ๏ธ Role placement',
|
|
660
|
+
description: `Picture ${index + 1} has role="img" but should be on the img element inside`,
|
|
661
|
+
element: pictureBlock.substring(0, 100) + '...'
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
|
|
640
666
|
return issues;
|
|
641
667
|
}
|
|
642
668
|
|
|
669
|
+
fixPictureImgRoles(content) {
|
|
670
|
+
let fixed = content;
|
|
671
|
+
|
|
672
|
+
// Find all picture elements that contain img elements
|
|
673
|
+
const picturePattern = /<picture[^>]*role\s*=\s*["']img["'][^>]*>[\s\S]*?<\/picture>/gi;
|
|
674
|
+
const pictureMatches = content.match(picturePattern) || [];
|
|
675
|
+
|
|
676
|
+
for (const pictureBlock of pictureMatches) {
|
|
677
|
+
// Check if this picture contains an img element
|
|
678
|
+
const imgInPicture = pictureBlock.match(/<img[^>]*>/i);
|
|
679
|
+
|
|
680
|
+
if (imgInPicture) {
|
|
681
|
+
const imgTag = imgInPicture[0];
|
|
682
|
+
|
|
683
|
+
// Check if img already has role attribute
|
|
684
|
+
const imgHasRole = /role\s*=/i.test(imgTag);
|
|
685
|
+
|
|
686
|
+
if (!imgHasRole) {
|
|
687
|
+
// Remove role="img" from picture element
|
|
688
|
+
const pictureWithoutRole = pictureBlock.replace(/\s*role\s*=\s*["']img["']/i, '');
|
|
689
|
+
|
|
690
|
+
// Add role="img" to img element
|
|
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
|
+
}
|
|
702
|
+
|
|
703
|
+
// Replace the img in the modified picture block
|
|
704
|
+
const updatedPictureBlock = pictureWithoutRole.replace(imgTag, imgWithRole);
|
|
705
|
+
|
|
706
|
+
// Replace in the main content
|
|
707
|
+
fixed = fixed.replace(pictureBlock, updatedPictureBlock);
|
|
708
|
+
|
|
709
|
+
console.log(chalk.yellow(` ๐ผ๏ธ Moved role="img" from <picture> to <img> element`));
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
return fixed;
|
|
715
|
+
}
|
|
716
|
+
|
|
643
717
|
fixRoleAttributesInContent(content) {
|
|
644
718
|
let fixed = content;
|
|
645
719
|
|
|
646
|
-
// Fix
|
|
720
|
+
// Fix picture elements with img children - move role from picture to img
|
|
721
|
+
fixed = this.fixPictureImgRoles(fixed);
|
|
722
|
+
|
|
723
|
+
// Fix all images - add role="img" and aria-label
|
|
647
724
|
fixed = fixed.replace(
|
|
648
725
|
/<img([^>]*>)/gi,
|
|
649
|
-
(match
|
|
726
|
+
(match) => {
|
|
727
|
+
let updatedImg = match;
|
|
728
|
+
let hasChanges = false;
|
|
729
|
+
|
|
650
730
|
// Check if role attribute already exists
|
|
651
|
-
if (
|
|
652
|
-
|
|
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;
|
|
653
735
|
}
|
|
654
|
-
|
|
655
|
-
|
|
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;
|
|
656
750
|
}
|
|
657
751
|
);
|
|
658
752
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gbu-accessibility-package",
|
|
3
|
-
"version": "1.
|
|
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>
|
package/demo/sample.html.backup
DELETED
|
@@ -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>© 2024 Demo Company</p>
|
|
45
|
-
</footer>
|
|
46
|
-
</body>
|
|
47
|
-
</html>
|