gbu-accessibility-package 3.12.1 → 3.13.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 +9 -4
- package/QUICK_START.md +14 -157
- package/README-vi.md +104 -678
- package/README.md +105 -658
- package/bin/fix.js +1 -138
- package/cli.js +289 -578
- package/index.js +5 -2
- package/lib/checker.js +233 -0
- package/lib/fixer.js +109 -125
- package/package.json +13 -14
package/cli.js
CHANGED
|
@@ -1,28 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
* Accessibility Fixer CLI
|
|
5
|
-
* Command line interface for the accessibility fixer tool
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const AccessibilityFixer = require('./lib/fixer.js');
|
|
3
|
+
const { AccessibilityChecker } = require('./index.js');
|
|
9
4
|
const chalk = require('chalk');
|
|
10
|
-
const path = require('path');
|
|
11
5
|
|
|
12
|
-
// Parse command line arguments
|
|
13
6
|
const args = process.argv.slice(2);
|
|
14
7
|
const options = {
|
|
15
8
|
directory: '.',
|
|
16
9
|
language: 'ja',
|
|
17
|
-
backupFiles: false, // Default to false for faster processing
|
|
18
|
-
dryRun: false,
|
|
19
10
|
help: false,
|
|
20
11
|
version: false,
|
|
21
|
-
|
|
22
|
-
comprehensive: false,
|
|
12
|
+
dryRun: false,
|
|
13
|
+
comprehensive: false,
|
|
23
14
|
altOnly: false,
|
|
24
15
|
langOnly: false,
|
|
25
16
|
roleOnly: false,
|
|
17
|
+
ariaLabelOnly: false,
|
|
26
18
|
formsOnly: false,
|
|
27
19
|
nestedOnly: false,
|
|
28
20
|
buttonsOnly: false,
|
|
@@ -30,27 +22,42 @@ const options = {
|
|
|
30
22
|
landmarksOnly: false,
|
|
31
23
|
headingsOnly: false,
|
|
32
24
|
dlOnly: false,
|
|
25
|
+
linksCheckOnly: false,
|
|
33
26
|
brokenLinksOnly: false,
|
|
27
|
+
missingResourcesOnly: false,
|
|
28
|
+
gtmCheckOnly: false,
|
|
29
|
+
checkMetaOnly: false,
|
|
30
|
+
fullReport: false,
|
|
34
31
|
unusedFilesOnly: false,
|
|
35
32
|
unusedFilesListOnly: false,
|
|
36
|
-
deleteUnusedFilesFromList: false,
|
|
37
33
|
deadCodeOnly: false,
|
|
38
34
|
fileSizeOnly: false,
|
|
39
35
|
listFile: 'unused-files-list.txt',
|
|
40
|
-
|
|
36
|
+
reportOutput: null,
|
|
41
37
|
enhancedAlt: false,
|
|
42
|
-
altCreativity: 'balanced',
|
|
38
|
+
altCreativity: 'balanced',
|
|
43
39
|
includeEmotions: false,
|
|
44
|
-
strictAltChecking: false
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
strictAltChecking: false
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const removedFlags = {
|
|
44
|
+
'--backup': 'Source file backups were removed because the package no longer edits files.',
|
|
45
|
+
'--no-backup': 'Backups are no longer needed because the package is check/report-only.',
|
|
46
|
+
'--cleanup-only': 'Cleanup mode was removed because it modified source files.',
|
|
47
|
+
'--fix-meta': 'Meta auto-fix was removed. Use --check-meta to review issues.',
|
|
48
|
+
'--meta-fix': 'Meta auto-fix was removed. Use --check-meta to review issues.',
|
|
49
|
+
'--delete-unused-files': 'File deletion was removed. Use --unused-files-list to export a review list instead.',
|
|
50
|
+
'--auto-fix-headings': 'Heading auto-fix was removed. Use --headings-only to review issues instead.'
|
|
48
51
|
};
|
|
49
52
|
|
|
50
|
-
|
|
51
|
-
for (let i = 0; i < args.length; i++) {
|
|
53
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
52
54
|
const arg = args[i];
|
|
53
|
-
|
|
55
|
+
|
|
56
|
+
if (removedFlags[arg]) {
|
|
57
|
+
console.error(chalk.red(`❌ ${removedFlags[arg]}`));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
54
61
|
switch (arg) {
|
|
55
62
|
case '--help':
|
|
56
63
|
case '-h':
|
|
@@ -62,27 +69,20 @@ for (let i = 0; i < args.length; i++) {
|
|
|
62
69
|
break;
|
|
63
70
|
case '--directory':
|
|
64
71
|
case '-d':
|
|
65
|
-
options.directory = args[
|
|
72
|
+
options.directory = args[i + 1];
|
|
73
|
+
i += 1;
|
|
66
74
|
break;
|
|
67
75
|
case '--language':
|
|
68
76
|
case '-l':
|
|
69
|
-
options.language = args[
|
|
70
|
-
|
|
71
|
-
case '--backup':
|
|
72
|
-
options.backupFiles = true;
|
|
73
|
-
break;
|
|
74
|
-
case '--no-backup':
|
|
75
|
-
options.backupFiles = false;
|
|
77
|
+
options.language = args[i + 1];
|
|
78
|
+
i += 1;
|
|
76
79
|
break;
|
|
77
80
|
case '--dry-run':
|
|
78
81
|
options.dryRun = true;
|
|
79
82
|
break;
|
|
80
|
-
case '--cleanup-only':
|
|
81
|
-
options.cleanupOnly = true;
|
|
82
|
-
break;
|
|
83
83
|
case '--comprehensive':
|
|
84
84
|
case '--all':
|
|
85
|
-
options.comprehensive = true;
|
|
85
|
+
options.comprehensive = true;
|
|
86
86
|
break;
|
|
87
87
|
case '--alt-only':
|
|
88
88
|
options.altOnly = true;
|
|
@@ -136,10 +136,6 @@ for (let i = 0; i < args.length; i++) {
|
|
|
136
136
|
case '--meta-check':
|
|
137
137
|
options.checkMetaOnly = true;
|
|
138
138
|
break;
|
|
139
|
-
case '--fix-meta':
|
|
140
|
-
case '--meta-fix':
|
|
141
|
-
options.fixMetaOnly = true;
|
|
142
|
-
break;
|
|
143
139
|
case '--full-report':
|
|
144
140
|
case '--report':
|
|
145
141
|
case '--excel-report':
|
|
@@ -147,7 +143,8 @@ for (let i = 0; i < args.length; i++) {
|
|
|
147
143
|
break;
|
|
148
144
|
case '-o':
|
|
149
145
|
case '--output':
|
|
150
|
-
options.reportOutput = args[
|
|
146
|
+
options.reportOutput = args[i + 1];
|
|
147
|
+
i += 1;
|
|
151
148
|
break;
|
|
152
149
|
case '--unused-files':
|
|
153
150
|
options.unusedFilesOnly = true;
|
|
@@ -155,11 +152,9 @@ for (let i = 0; i < args.length; i++) {
|
|
|
155
152
|
case '--unused-files-list':
|
|
156
153
|
options.unusedFilesListOnly = true;
|
|
157
154
|
break;
|
|
158
|
-
case '--delete-unused-files':
|
|
159
|
-
options.deleteUnusedFilesFromList = true;
|
|
160
|
-
break;
|
|
161
155
|
case '--list-file':
|
|
162
|
-
options.listFile = args[
|
|
156
|
+
options.listFile = args[i + 1];
|
|
157
|
+
i += 1;
|
|
163
158
|
break;
|
|
164
159
|
case '--dead-code':
|
|
165
160
|
options.deadCodeOnly = true;
|
|
@@ -168,17 +163,12 @@ for (let i = 0; i < args.length; i++) {
|
|
|
168
163
|
case '--size-check':
|
|
169
164
|
options.fileSizeOnly = true;
|
|
170
165
|
break;
|
|
171
|
-
case '--auto-fix-headings':
|
|
172
|
-
options.autoFixHeadings = true;
|
|
173
|
-
break;
|
|
174
|
-
case '--no-fix-dl':
|
|
175
|
-
options.fixDescriptionLists = false;
|
|
176
|
-
break;
|
|
177
166
|
case '--enhanced-alt':
|
|
178
167
|
options.enhancedAlt = true;
|
|
179
168
|
break;
|
|
180
169
|
case '--alt-creativity':
|
|
181
|
-
options.altCreativity = args[
|
|
170
|
+
options.altCreativity = args[i + 1];
|
|
171
|
+
i += 1;
|
|
182
172
|
break;
|
|
183
173
|
case '--include-emotions':
|
|
184
174
|
options.includeEmotions = true;
|
|
@@ -189,555 +179,276 @@ for (let i = 0; i < args.length; i++) {
|
|
|
189
179
|
default:
|
|
190
180
|
if (!arg.startsWith('-')) {
|
|
191
181
|
options.directory = arg;
|
|
182
|
+
} else {
|
|
183
|
+
console.error(chalk.red(`❌ Unknown option: ${arg}`));
|
|
184
|
+
process.exit(1);
|
|
192
185
|
}
|
|
193
186
|
}
|
|
194
187
|
}
|
|
195
188
|
|
|
196
|
-
|
|
189
|
+
function showHelp() {
|
|
190
|
+
console.log(chalk.blue(`
|
|
191
|
+
GBU Accessibility Checker
|
|
192
|
+
|
|
193
|
+
Usage: gbu-a11y [options] [directory]
|
|
194
|
+
|
|
195
|
+
This package now runs in check/report-only mode.
|
|
196
|
+
Source files are never modified.
|
|
197
|
+
|
|
198
|
+
Core options:
|
|
199
|
+
-d, --directory <path> Target directory (default: current directory)
|
|
200
|
+
-l, --language <lang> Language context for checks (default: ja)
|
|
201
|
+
--dry-run Optional legacy flag; check-only mode is always enabled
|
|
202
|
+
-h, --help Show this help message
|
|
203
|
+
-v, --version Show version number
|
|
204
|
+
|
|
205
|
+
Check modes:
|
|
206
|
+
--comprehensive, --all Run the default comprehensive check set
|
|
207
|
+
--alt-only Check alt text issues only
|
|
208
|
+
--lang-only Check HTML lang issues only
|
|
209
|
+
--role-only Check role attribute issues only
|
|
210
|
+
--aria-label-only Check aria-label issues only
|
|
211
|
+
--forms-only Check form label issues only
|
|
212
|
+
--nested-only Check nested interactive controls only
|
|
213
|
+
--buttons-only Check button naming issues only
|
|
214
|
+
--links-only Check accessible link name issues only
|
|
215
|
+
--landmarks-only Check landmark issues only
|
|
216
|
+
--headings-only Check heading structure only
|
|
217
|
+
--dl-only Check description list structure only
|
|
218
|
+
--links-check Check external links and local missing resources
|
|
219
|
+
--broken-links Check broken external links only
|
|
220
|
+
--404-resources Check missing local resources only
|
|
221
|
+
--gtm-check Check Google Tag Manager installation only
|
|
222
|
+
--check-meta Check meta tags and OGP issues only
|
|
223
|
+
--unused-files Check unused files only
|
|
224
|
+
--unused-files-list Export unused files to a text report
|
|
225
|
+
--dead-code Check dead CSS and JavaScript only
|
|
226
|
+
--file-size Check file sizes only
|
|
227
|
+
--full-report Generate the comprehensive Excel report
|
|
228
|
+
-o, --output <file> Custom output path for --full-report
|
|
229
|
+
--list-file <file> Custom output path/name for --unused-files-list
|
|
230
|
+
|
|
231
|
+
Enhanced alt checks:
|
|
232
|
+
--enhanced-alt Enable deeper alt text analysis
|
|
233
|
+
--alt-creativity <mode> conservative | balanced | creative
|
|
234
|
+
--include-emotions Include emotional/contextual alt suggestions
|
|
235
|
+
--strict-alt Enable stricter alt quality rules
|
|
236
|
+
|
|
237
|
+
Removed editing features:
|
|
238
|
+
--backup, --no-backup
|
|
239
|
+
--cleanup-only
|
|
240
|
+
--fix-meta, --meta-fix
|
|
241
|
+
--delete-unused-files
|
|
242
|
+
--auto-fix-headings
|
|
243
|
+
|
|
244
|
+
Examples:
|
|
245
|
+
gbu-a11y
|
|
246
|
+
gbu-a11y --alt-only ./src
|
|
247
|
+
gbu-a11y --links-check ./public
|
|
248
|
+
gbu-a11y --unused-files-list --list-file reports/unused-files.txt
|
|
249
|
+
gbu-a11y --full-report -o reports/accessibility-report.xlsx
|
|
250
|
+
`));
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function printSummary(label, result) {
|
|
254
|
+
if (!result) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (Array.isArray(result)) {
|
|
259
|
+
const issueCount = result.filter((item) => (
|
|
260
|
+
item.status === 'issue-found'
|
|
261
|
+
|| item.status === 'fixed'
|
|
262
|
+
|| (typeof item.issues === 'number' && item.issues > 0)
|
|
263
|
+
)).length;
|
|
264
|
+
const cleanCount = result.filter((item) => item.status === 'clean' || item.status === 'no-change').length;
|
|
265
|
+
const errorCount = result.filter((item) => item.status === 'error').length;
|
|
266
|
+
|
|
267
|
+
console.log(chalk.blue(`\n📌 ${label}`));
|
|
268
|
+
console.log(` Files with findings: ${issueCount}`);
|
|
269
|
+
console.log(` Clean files: ${cleanCount}`);
|
|
270
|
+
console.log(` Errors: ${errorCount}`);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (result.filePath) {
|
|
275
|
+
console.log(chalk.blue(`\n📌 ${label}`));
|
|
276
|
+
console.log(` Report: ${result.filePath}`);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (typeof result.unusedCount === 'number') {
|
|
281
|
+
console.log(chalk.blue(`\n📌 ${label}`));
|
|
282
|
+
console.log(` Unused files found: ${result.unusedCount}`);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (typeof result.deletedCount === 'number') {
|
|
287
|
+
console.log(chalk.blue(`\n📌 ${label}`));
|
|
288
|
+
console.log(` Files flagged from list: ${result.deletedCount}`);
|
|
289
|
+
console.log(' Note: preview only, no files were deleted.');
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (result.brokenLinks || result.missingResources) {
|
|
294
|
+
printSummary(`${label} - Broken Links`, result.brokenLinks);
|
|
295
|
+
printSummary(`${label} - Missing Resources`, result.missingResources);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const nestedEntries = Object.entries(result).filter(([, value]) => Array.isArray(value));
|
|
300
|
+
if (nestedEntries.length > 0) {
|
|
301
|
+
console.log(chalk.blue(`\n📌 ${label}`));
|
|
302
|
+
|
|
303
|
+
for (const [key, value] of nestedEntries) {
|
|
304
|
+
const issueCount = value.filter((item) => (
|
|
305
|
+
item.status === 'issue-found'
|
|
306
|
+
|| item.status === 'fixed'
|
|
307
|
+
|| (typeof item.issues === 'number' && item.issues > 0)
|
|
308
|
+
)).length;
|
|
309
|
+
const errorCount = value.filter((item) => item.status === 'error').length;
|
|
310
|
+
console.log(` ${key}: ${issueCount} files with findings, ${errorCount} errors`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
197
315
|
if (options.version) {
|
|
198
316
|
const packageJson = require('./package.json');
|
|
199
|
-
console.log(
|
|
317
|
+
console.log(`GBU Accessibility Checker v${packageJson.version}`);
|
|
200
318
|
process.exit(0);
|
|
201
319
|
}
|
|
202
320
|
|
|
203
321
|
if (options.help) {
|
|
204
|
-
|
|
205
|
-
🔧 Accessibility Fixer CLI
|
|
206
|
-
|
|
207
|
-
Usage: node cli.js [options] [directory]
|
|
208
|
-
|
|
209
|
-
Options:
|
|
210
|
-
-d, --directory <path> Target directory (default: current directory)
|
|
211
|
-
-l, --language <lang> Language for lang attribute (default: ja)
|
|
212
|
-
--backup Create backup files
|
|
213
|
-
--no-backup Don't create backup files (default)
|
|
214
|
-
--dry-run Preview changes without applying
|
|
215
|
-
--comprehensive, --all Run comprehensive fixes (same as default)
|
|
216
|
-
--cleanup-only Only cleanup duplicate role attributes
|
|
217
|
-
--alt-only Fix alt attributes + cleanup
|
|
218
|
-
--lang-only Fix HTML lang attributes + cleanup
|
|
219
|
-
--role-only Fix role attributes + cleanup
|
|
220
|
-
--aria-label-only Fix aria-label attributes + cleanup
|
|
221
|
-
--forms-only Fix form labels + cleanup
|
|
222
|
-
--buttons-only Fix button names + cleanup
|
|
223
|
-
--links-only Fix link names + cleanup
|
|
224
|
-
--landmarks-only Fix landmarks + cleanup
|
|
225
|
-
--headings-only Analyze heading structure (no auto-fix)
|
|
226
|
-
--links-check Check for broken links and 404 resources (no auto-fix)
|
|
227
|
-
--broken-links Check for broken external links only (no auto-fix)
|
|
228
|
-
--404-resources Check for missing local resources only (no auto-fix)
|
|
229
|
-
--gtm-check Check Google Tag Manager installation (no auto-fix)
|
|
230
|
-
--check-meta Check meta tags and Open Graph Protocol (no auto-fix)
|
|
231
|
-
--fix-meta Auto-fix missing meta tags and OGP tags
|
|
232
|
-
--full-report Generate comprehensive Excel report (all checks)
|
|
233
|
-
-o, --output <file> Output path for Excel report (use with --full-report)
|
|
234
|
-
--unused-files Check for unused files in project (no auto-fix)
|
|
235
|
-
--unused-files-list Create unused-files-list.txt from detected unused files
|
|
236
|
-
--delete-unused-files Delete all files listed in unused-files-list.txt
|
|
237
|
-
--list-file <file> Custom list file name/path inside target directory
|
|
238
|
-
--dead-code Check for dead code in CSS and JavaScript (no auto-fix)
|
|
239
|
-
--file-size, --size-check Check file sizes and suggest optimizations (no auto-fix)
|
|
240
|
-
--enhanced-alt Use enhanced alt attribute analysis and generation
|
|
241
|
-
--alt-creativity <mode> Alt text creativity: conservative, balanced, creative (default: balanced)
|
|
242
|
-
--include-emotions Include emotional descriptors in alt text
|
|
243
|
-
--strict-alt Enable strict alt attribute quality checking
|
|
244
|
-
-h, --help Show this help message
|
|
245
|
-
-v, --version Show version number
|
|
246
|
-
|
|
247
|
-
Enhanced Alt Features:
|
|
248
|
-
--enhanced-alt Comprehensive alt attribute analysis with:
|
|
249
|
-
• Image type classification (decorative, functional, complex, etc.)
|
|
250
|
-
• Content quality checking (length, redundancy, generic text)
|
|
251
|
-
• Context-aware alt text generation
|
|
252
|
-
• Multi-language vocabulary support
|
|
253
|
-
• Brand and emotional context integration
|
|
254
|
-
• Technical image description (charts, graphs)
|
|
255
|
-
|
|
256
|
-
Alt Creativity Modes:
|
|
257
|
-
conservative Simple, factual descriptions
|
|
258
|
-
balanced Context-aware with moderate creativity (default)
|
|
259
|
-
creative Rich descriptions with emotions and brand context
|
|
260
|
-
|
|
261
|
-
Examples:
|
|
262
|
-
node cli.js # Comprehensive fixes (no backup by default)
|
|
263
|
-
node cli.js --comprehensive # Comprehensive fixes (same as default)
|
|
264
|
-
node cli.js --alt-only # Fix alt attributes + cleanup
|
|
265
|
-
node cli.js --forms-only # Fix form labels + cleanup
|
|
266
|
-
node cli.js --buttons-only # Fix button names + cleanup
|
|
267
|
-
node cli.js --links-only # Fix link names + cleanup
|
|
268
|
-
node cli.js --landmarks-only # Fix landmarks + cleanup
|
|
269
|
-
node cli.js --headings-only # Analyze heading structure only
|
|
270
|
-
node cli.js --links-check # Check for broken links and 404s
|
|
271
|
-
node cli.js --broken-links # Check for broken external links only
|
|
272
|
-
node cli.js --404-resources # Check for missing local resources only
|
|
273
|
-
node cli.js --gtm-check # Check Google Tag Manager installation
|
|
274
|
-
node cli.js --check-meta # Check meta tags and Open Graph Protocol
|
|
275
|
-
node cli.js --fix-meta # Auto-fix missing meta tags and OGP
|
|
276
|
-
node cli.js --fix-meta --dry-run # Preview meta tag fixes
|
|
277
|
-
node cli.js --full-report # Generate comprehensive Excel report
|
|
278
|
-
node cli.js --full-report ./project -o report.xlsx # Custom output path
|
|
279
|
-
node cli.js --unused-files # Check for unused files in project
|
|
280
|
-
node cli.js --unused-files-list # Create ./unused-files-list.txt
|
|
281
|
-
node cli.js --delete-unused-files # Delete files listed in ./unused-files-list.txt
|
|
282
|
-
node cli.js --delete-unused-files --dry-run # Preview files that would be deleted
|
|
283
|
-
node cli.js --dead-code # Check for dead CSS and JavaScript code
|
|
284
|
-
node cli.js --file-size # Check file sizes and suggest optimizations
|
|
285
|
-
node cli.js --cleanup-only # Only cleanup duplicate roles
|
|
286
|
-
node cli.js ./src # Fix src directory (comprehensive)
|
|
287
|
-
node cli.js -l en --dry-run ./dist # Preview comprehensive fixes in English
|
|
288
|
-
node cli.js --backup ./public # Comprehensive fixes with backups
|
|
289
|
-
node cli.js --enhanced-alt # Use enhanced alt attribute analysis
|
|
290
|
-
node cli.js --enhanced-alt --alt-creativity creative # Creative alt text generation
|
|
291
|
-
node cli.js --enhanced-alt --include-emotions # Include emotional context
|
|
292
|
-
node cli.js --strict-alt --enhanced-alt # Strict quality checking
|
|
293
|
-
|
|
294
|
-
Features:
|
|
295
|
-
✅ Alt attributes for images
|
|
296
|
-
✅ Lang attributes for HTML
|
|
297
|
-
✅ Role attributes for accessibility
|
|
298
|
-
✅ Context-aware text generation
|
|
299
|
-
✅ Automatic backups
|
|
300
|
-
`));
|
|
322
|
+
showHelp();
|
|
301
323
|
process.exit(0);
|
|
302
324
|
}
|
|
303
325
|
|
|
326
|
+
const selectedModes = [
|
|
327
|
+
'comprehensive',
|
|
328
|
+
'altOnly',
|
|
329
|
+
'langOnly',
|
|
330
|
+
'roleOnly',
|
|
331
|
+
'ariaLabelOnly',
|
|
332
|
+
'formsOnly',
|
|
333
|
+
'nestedOnly',
|
|
334
|
+
'buttonsOnly',
|
|
335
|
+
'linksOnly',
|
|
336
|
+
'landmarksOnly',
|
|
337
|
+
'headingsOnly',
|
|
338
|
+
'dlOnly',
|
|
339
|
+
'linksCheckOnly',
|
|
340
|
+
'brokenLinksOnly',
|
|
341
|
+
'missingResourcesOnly',
|
|
342
|
+
'gtmCheckOnly',
|
|
343
|
+
'checkMetaOnly',
|
|
344
|
+
'fullReport',
|
|
345
|
+
'unusedFilesOnly',
|
|
346
|
+
'unusedFilesListOnly',
|
|
347
|
+
'deadCodeOnly',
|
|
348
|
+
'fileSizeOnly'
|
|
349
|
+
].filter((key) => options[key]);
|
|
350
|
+
|
|
351
|
+
if (selectedModes.length > 1) {
|
|
352
|
+
console.error(chalk.red('❌ Please select only one check mode at a time.'));
|
|
353
|
+
process.exit(1);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const checker = new AccessibilityChecker({
|
|
357
|
+
language: options.language,
|
|
358
|
+
enhancedAltMode: options.enhancedAlt,
|
|
359
|
+
altCreativity: options.altCreativity,
|
|
360
|
+
includeEmotions: options.includeEmotions,
|
|
361
|
+
strictAltChecking: options.strictAltChecking
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
async function run() {
|
|
365
|
+
console.log(chalk.blue('🔍 GBU Accessibility Checker'));
|
|
366
|
+
console.log(chalk.gray(`Target: ${options.directory}`));
|
|
367
|
+
console.log(chalk.gray('Mode: check/report only (source files remain unchanged)'));
|
|
304
368
|
|
|
305
|
-
// Helper function to show completion message with backup info
|
|
306
|
-
function showCompletionMessage(options, mode = 'sửa lỗi') {
|
|
307
369
|
if (options.dryRun) {
|
|
308
|
-
console.log(chalk.
|
|
309
|
-
} else {
|
|
310
|
-
console.log(chalk.green(`\n🎉 ${mode} hoàn tất thành công!`));
|
|
311
|
-
if (options.backupFiles) {
|
|
312
|
-
console.log(chalk.gray(' 📁 Đã tạo file backup với đuôi .backup'));
|
|
313
|
-
console.log(chalk.gray(' 💡 Sử dụng --no-backup để tắt backup trong các lần chạy sau'));
|
|
314
|
-
} else {
|
|
315
|
-
console.log(chalk.blue(' ⚡ Không tạo file backup (mặc định để xử lý nhanh hơn)'));
|
|
316
|
-
console.log(chalk.gray(' 💡 Sử dụng --backup để bật tính năng backup để an toàn'));
|
|
317
|
-
}
|
|
370
|
+
console.log(chalk.gray('Note: --dry-run is now redundant because check-only mode is always enabled.'));
|
|
318
371
|
}
|
|
319
|
-
}
|
|
320
372
|
|
|
321
|
-
// Main function
|
|
322
|
-
async function main() {
|
|
323
|
-
console.log(chalk.blue('🚀 Đang khởi động Accessibility Fixer...'));
|
|
324
|
-
console.log(chalk.gray(`Thư mục: ${path.resolve(options.directory)}`));
|
|
325
|
-
console.log(chalk.gray(`Ngôn ngữ: ${options.language}`));
|
|
326
|
-
console.log(chalk.gray(`Backup: ${options.backupFiles ? 'Có' : 'Không'}`));
|
|
327
|
-
console.log(chalk.gray(`Chế độ: ${options.dryRun ? 'Xem trước (Preview)' : 'Áp dụng thay đổi'}`));
|
|
328
373
|
console.log('');
|
|
329
374
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
backupFiles: options.backupFiles,
|
|
333
|
-
dryRun: options.dryRun,
|
|
334
|
-
enhancedAltMode: options.enhancedAlt,
|
|
335
|
-
altCreativity: options.altCreativity,
|
|
336
|
-
includeEmotions: options.includeEmotions,
|
|
337
|
-
strictAltChecking: options.strictAltChecking,
|
|
338
|
-
autoFixHeadings: options.autoFixHeadings,
|
|
339
|
-
fixDescriptionLists: options.fixDescriptionLists
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
try {
|
|
343
|
-
// Handle Full Report mode first
|
|
344
|
-
if (options.fullReport) {
|
|
345
|
-
console.log(chalk.blue('📊 Đang tạo báo cáo toàn diện...'));
|
|
346
|
-
await fixer.generateFullReport(options.directory, options.reportOutput);
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Handle different modes - All modes now include cleanup
|
|
351
|
-
if (options.cleanupOnly || options.altOnly || options.langOnly || options.roleOnly || options.ariaLabelOnly ||
|
|
352
|
-
options.formsOnly || options.nestedOnly || options.buttonsOnly || options.linksOnly || options.landmarksOnly ||
|
|
353
|
-
options.headingsOnly || options.dlOnly || options.linksCheckOnly || options.brokenLinksOnly || options.missingResourcesOnly || options.gtmCheckOnly || options.checkMetaOnly || options.fixMetaOnly || options.unusedFilesOnly || options.unusedFilesListOnly || options.deleteUnusedFilesFromList || options.deadCodeOnly || options.fileSizeOnly) {
|
|
354
|
-
// Individual modes - handle each separately, then run cleanup
|
|
355
|
-
} else {
|
|
356
|
-
// Default mode: Run comprehensive fix (all fixes including cleanup)
|
|
357
|
-
console.log(chalk.blue('🎯 Đang chạy sửa lỗi accessibility toàn diện...'));
|
|
358
|
-
const results = await fixer.fixAllAccessibilityIssues(options.directory);
|
|
359
|
-
|
|
360
|
-
// Results already logged in the method
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// Individual modes
|
|
365
|
-
if (options.cleanupOnly) {
|
|
366
|
-
// Only cleanup duplicate roles
|
|
367
|
-
console.log(chalk.blue('🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
368
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
369
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
370
|
-
|
|
371
|
-
console.log(chalk.green(`\n✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
372
|
-
|
|
373
|
-
showCompletionMessage(options, 'Dọn dẹp');
|
|
374
|
-
return;
|
|
375
|
-
|
|
376
|
-
} else if (options.cleanupOnly) {
|
|
377
|
-
// Only cleanup duplicate roles
|
|
378
|
-
console.log(chalk.blue('🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
379
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
380
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
381
|
-
|
|
382
|
-
console.log(chalk.green(`\n✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
383
|
-
|
|
384
|
-
showCompletionMessage(options, 'Dọn dẹp');
|
|
385
|
-
return;
|
|
386
|
-
|
|
387
|
-
} else if (options.altOnly) {
|
|
388
|
-
// Fix alt attributes + cleanup
|
|
389
|
-
console.log(chalk.blue('🖼️ Đang sửa thuộc tính alt + dọn dẹp...'));
|
|
390
|
-
const altResults = await fixer.fixEmptyAltAttributes(options.directory);
|
|
391
|
-
const altFixed = altResults.filter(r => r.status === 'fixed').length;
|
|
392
|
-
const totalAltIssues = altResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
393
|
-
|
|
394
|
-
console.log(chalk.green(`\n✅ Đã sửa thuộc tính alt trong ${altFixed} file (${totalAltIssues} vấn đề)`));
|
|
395
|
-
|
|
396
|
-
// Run cleanup
|
|
397
|
-
console.log(chalk.blue('\n🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
398
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
399
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
400
|
-
console.log(chalk.green(`✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
401
|
-
|
|
402
|
-
showCompletionMessage(options, 'Sửa thuộc tính alt + dọn dẹp');
|
|
403
|
-
return;
|
|
404
|
-
|
|
405
|
-
} else if (options.langOnly) {
|
|
406
|
-
// Fix lang attributes + cleanup
|
|
407
|
-
console.log(chalk.blue('📝 Đang sửa thuộc tính HTML lang + dọn dẹp...'));
|
|
408
|
-
const langResults = await fixer.fixHtmlLang(options.directory);
|
|
409
|
-
const langFixed = langResults.filter(r => r.status === 'fixed').length;
|
|
410
|
-
|
|
411
|
-
console.log(chalk.green(`\n✅ Đã sửa thuộc tính lang trong ${langFixed} file`));
|
|
412
|
-
|
|
413
|
-
// Run cleanup
|
|
414
|
-
console.log(chalk.blue('\n🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
415
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
416
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
417
|
-
console.log(chalk.green(`✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
418
|
-
|
|
419
|
-
showCompletionMessage(options, 'Sửa thuộc tính lang + dọn dẹp');
|
|
420
|
-
return;
|
|
421
|
-
|
|
422
|
-
} else if (options.roleOnly) {
|
|
423
|
-
// Fix role attributes + cleanup
|
|
424
|
-
console.log(chalk.blue('🎭 Đang sửa thuộc tính role + dọn dẹp...'));
|
|
425
|
-
const roleResults = await fixer.fixRoleAttributes(options.directory);
|
|
426
|
-
const roleFixed = roleResults.filter(r => r.status === 'fixed').length;
|
|
427
|
-
const totalRoleIssues = roleResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
428
|
-
|
|
429
|
-
console.log(chalk.green(`\n✅ Đã sửa thuộc tính role trong ${roleFixed} file (${totalRoleIssues} vấn đề)`));
|
|
430
|
-
|
|
431
|
-
// Run cleanup
|
|
432
|
-
console.log(chalk.blue('\n🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
433
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
434
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
435
|
-
console.log(chalk.green(`✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
436
|
-
|
|
437
|
-
showCompletionMessage(options, 'Sửa thuộc tính role + dọn dẹp');
|
|
438
|
-
return;
|
|
439
|
-
|
|
440
|
-
} else if (options.ariaLabelOnly) {
|
|
441
|
-
// Fix aria-label attributes + cleanup
|
|
442
|
-
console.log(chalk.blue('🏷️ Đang sửa thuộc tính aria-label + dọn dẹp...'));
|
|
443
|
-
const ariaResults = await fixer.fixAriaLabels(options.directory);
|
|
444
|
-
const ariaFixed = ariaResults.filter(r => r.status === 'processed' && r.changes > 0).length;
|
|
445
|
-
const totalAriaIssues = ariaResults.reduce((sum, r) => sum + (r.changes || 0), 0);
|
|
446
|
-
|
|
447
|
-
console.log(chalk.green(`\n✅ Đã sửa thuộc tính aria-label trong ${ariaFixed} file (${totalAriaIssues} vấn đề)`));
|
|
448
|
-
|
|
449
|
-
// Run cleanup
|
|
450
|
-
console.log(chalk.blue('\n🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
451
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
452
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
453
|
-
console.log(chalk.green(`✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
454
|
-
|
|
455
|
-
showCompletionMessage(options, 'Sửa thuộc tính aria-label + dọn dẹp');
|
|
456
|
-
return;
|
|
457
|
-
|
|
458
|
-
} else if (options.formsOnly) {
|
|
459
|
-
// Fix form labels + cleanup
|
|
460
|
-
console.log(chalk.blue('📋 Đang sửa nhãn form + dọn dẹp...'));
|
|
461
|
-
const formResults = await fixer.fixFormLabels(options.directory);
|
|
462
|
-
const formFixed = formResults.filter(r => r.status === 'fixed').length;
|
|
463
|
-
const totalFormIssues = formResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
464
|
-
|
|
465
|
-
console.log(chalk.green(`\n✅ Đã sửa nhãn form trong ${formFixed} file (${totalFormIssues} vấn đề)`));
|
|
466
|
-
|
|
467
|
-
// Run cleanup
|
|
468
|
-
console.log(chalk.blue('\n🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
469
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
470
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
471
|
-
console.log(chalk.green(`✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
472
|
-
|
|
473
|
-
showCompletionMessage(options, 'Sửa nhãn form + dọn dẹp');
|
|
474
|
-
return;
|
|
475
|
-
|
|
476
|
-
} else if (options.nestedOnly) {
|
|
477
|
-
// Fix nested interactive controls + cleanup
|
|
478
|
-
console.log(chalk.blue('🎯 Đang sửa các control tương tác lồng nhau + dọn dẹp...'));
|
|
479
|
-
const nestedResults = await fixer.fixNestedInteractiveControls(options.directory);
|
|
480
|
-
const nestedFixed = nestedResults.filter(r => r.status === 'fixed').length;
|
|
481
|
-
const totalNestedIssues = nestedResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
482
|
-
|
|
483
|
-
console.log(chalk.green(`\n✅ Đã sửa các control tương tác lồng nhau trong ${nestedFixed} file (${totalNestedIssues} vấn đề)`));
|
|
484
|
-
|
|
485
|
-
// Run cleanup
|
|
486
|
-
console.log(chalk.blue('\n🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
487
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
488
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
489
|
-
console.log(chalk.green(`✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
490
|
-
|
|
491
|
-
showCompletionMessage(options, 'Sửa các control tương tác lồng nhau + dọn dẹp');
|
|
492
|
-
return;
|
|
493
|
-
|
|
494
|
-
} else if (options.buttonsOnly) {
|
|
495
|
-
// Fix button names + cleanup
|
|
496
|
-
console.log(chalk.blue('🔘 Đang sửa tên button + dọn dẹp...'));
|
|
497
|
-
const buttonResults = await fixer.fixButtonNames(options.directory);
|
|
498
|
-
const buttonFixed = buttonResults.filter(r => r.status === 'fixed').length;
|
|
499
|
-
const totalButtonIssues = buttonResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
500
|
-
|
|
501
|
-
console.log(chalk.green(`\n✅ Đã sửa tên button trong ${buttonFixed} file (${totalButtonIssues} vấn đề)`));
|
|
502
|
-
|
|
503
|
-
// Run cleanup
|
|
504
|
-
console.log(chalk.blue('\n🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
505
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
506
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
507
|
-
console.log(chalk.green(`✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
508
|
-
|
|
509
|
-
showCompletionMessage(options, 'Sửa tên button + dọn dẹp');
|
|
510
|
-
return;
|
|
511
|
-
|
|
512
|
-
} else if (options.linksOnly) {
|
|
513
|
-
// Fix link names + cleanup
|
|
514
|
-
console.log(chalk.blue('🔗 Đang sửa tên link + dọn dẹp...'));
|
|
515
|
-
const linkResults = await fixer.fixLinkNames(options.directory);
|
|
516
|
-
const linkFixed = linkResults.filter(r => r.status === 'fixed').length;
|
|
517
|
-
const totalLinkIssues = linkResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
518
|
-
|
|
519
|
-
console.log(chalk.green(`\n✅ Đã sửa tên link trong ${linkFixed} file (${totalLinkIssues} vấn đề)`));
|
|
520
|
-
|
|
521
|
-
// Run cleanup
|
|
522
|
-
console.log(chalk.blue('\n🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
523
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
524
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
525
|
-
console.log(chalk.green(`✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
526
|
-
|
|
527
|
-
showCompletionMessage(options, 'Sửa tên link + dọn dẹp');
|
|
528
|
-
return;
|
|
529
|
-
|
|
530
|
-
} else if (options.landmarksOnly) {
|
|
531
|
-
// Fix landmarks + cleanup
|
|
532
|
-
console.log(chalk.blue('🏛️ Đang sửa landmark + dọn dẹp...'));
|
|
533
|
-
const landmarkResults = await fixer.fixLandmarks(options.directory);
|
|
534
|
-
const landmarkFixed = landmarkResults.filter(r => r.status === 'fixed').length;
|
|
535
|
-
const totalLandmarkIssues = landmarkResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
536
|
-
|
|
537
|
-
console.log(chalk.green(`\n✅ Đã sửa landmark trong ${landmarkFixed} file (${totalLandmarkIssues} vấn đề)`));
|
|
538
|
-
|
|
539
|
-
// Run cleanup
|
|
540
|
-
console.log(chalk.blue('\n🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
541
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
542
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
543
|
-
console.log(chalk.green(`✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
544
|
-
|
|
545
|
-
showCompletionMessage(options, 'Sửa landmark + dọn dẹp');
|
|
546
|
-
return;
|
|
547
|
-
|
|
548
|
-
} else if (options.headingsOnly) {
|
|
549
|
-
// Fix heading structure + cleanup
|
|
550
|
-
console.log(chalk.blue('📑 Đang sửa cấu trúc heading + dọn dẹp...'));
|
|
551
|
-
const headingResults = await fixer.fixHeadingStructure(options.directory);
|
|
552
|
-
const headingFixed = headingResults.filter(r => r.status === 'fixed').length;
|
|
553
|
-
const totalHeadingIssues = headingResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
554
|
-
const totalHeadingFixes = headingResults.reduce((sum, r) => sum + (r.fixes || 0), 0);
|
|
555
|
-
|
|
556
|
-
console.log(chalk.green(`\n✅ Đã xử lý heading trong ${headingResults.length} file (${totalHeadingIssues} vấn đề tìm thấy)`));
|
|
557
|
-
if (options.autoFixHeadings) {
|
|
558
|
-
console.log(chalk.green(`✅ Đã sửa ${totalHeadingFixes} vấn đề heading tự động`));
|
|
559
|
-
} else {
|
|
560
|
-
console.log(chalk.gray('💡 Sử dụng --auto-fix-headings để bật tính năng tự động sửa heading'));
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// Run cleanup
|
|
564
|
-
console.log(chalk.blue('\n🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
565
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
566
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
567
|
-
console.log(chalk.green(`✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
568
|
-
|
|
569
|
-
showCompletionMessage(options, 'Sửa cấu trúc heading + dọn dẹp');
|
|
570
|
-
return;
|
|
571
|
-
|
|
572
|
-
} else if (options.dlOnly) {
|
|
573
|
-
// Fix description lists + cleanup
|
|
574
|
-
console.log(chalk.blue('📋 Đang sửa danh sách mô tả + dọn dẹp...'));
|
|
575
|
-
const dlResults = await fixer.fixDescriptionLists(options.directory);
|
|
576
|
-
const dlFixed = dlResults.filter(r => r.status === 'fixed').length;
|
|
577
|
-
const totalDlIssues = dlResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
578
|
-
|
|
579
|
-
console.log(chalk.green(`\n✅ Đã sửa danh sách mô tả trong ${dlFixed} file (${totalDlIssues} vấn đề)`));
|
|
580
|
-
|
|
581
|
-
// Run cleanup
|
|
582
|
-
console.log(chalk.blue('\n🧹 Đang dọn dẹp các thuộc tính role trùng lặp...'));
|
|
583
|
-
const cleanupResults = await fixer.cleanupDuplicateRoles(options.directory);
|
|
584
|
-
const cleanupFixed = cleanupResults.filter(r => r.status === 'fixed').length;
|
|
585
|
-
console.log(chalk.green(`✅ Đã dọn dẹp role trùng lặp trong ${cleanupFixed} file`));
|
|
586
|
-
|
|
587
|
-
showCompletionMessage(options, 'Sửa danh sách mô tả + dọn dẹp');
|
|
588
|
-
return;
|
|
589
|
-
|
|
590
|
-
} else if (options.linksCheckOnly) {
|
|
591
|
-
// Check broken links and 404 resources (backward compatibility)
|
|
592
|
-
console.log(chalk.blue('🔗 Đang kiểm tra link và tài nguyên toàn diện...'));
|
|
593
|
-
const linkResults = await fixer.checkBrokenLinks(options.directory);
|
|
594
|
-
const resourceResults = await fixer.check404Resources(options.directory);
|
|
595
|
-
const totalLinkIssues = linkResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
596
|
-
const totalResourceIssues = resourceResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
597
|
-
|
|
598
|
-
console.log(chalk.green(`\n✅ Đã kiểm tra link trong ${linkResults.length} file (${totalLinkIssues} vấn đề link)`));
|
|
599
|
-
console.log(chalk.green(`✅ Đã kiểm tra tài nguyên trong ${resourceResults.length} file (${totalResourceIssues} vấn đề tài nguyên)`));
|
|
600
|
-
console.log(chalk.gray('💡 Vấn đề về link và tài nguyên cần xem xét thủ công và không thể tự động sửa'));
|
|
601
|
-
|
|
602
|
-
showCompletionMessage(options, 'Kiểm tra link và tài nguyên');
|
|
603
|
-
return;
|
|
604
|
-
|
|
605
|
-
} else if (options.brokenLinksOnly) {
|
|
606
|
-
// Check broken external links only
|
|
607
|
-
console.log(chalk.blue('🔗 Đang kiểm tra link bên ngoài bị lỗi...'));
|
|
608
|
-
const linkResults = await fixer.checkBrokenLinks(options.directory);
|
|
609
|
-
const totalBrokenLinks = linkResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
610
|
-
|
|
611
|
-
console.log(chalk.green(`\n✅ Đã kiểm tra link bên ngoài trong ${linkResults.length} file (${totalBrokenLinks} vấn đề)`));
|
|
612
|
-
console.log(chalk.gray('💡 Vấn đề link bị lỗi cần xem xét thủ công và không thể tự động sửa'));
|
|
613
|
-
|
|
614
|
-
showCompletionMessage(options, 'Kiểm tra link bị lỗi');
|
|
615
|
-
return;
|
|
616
|
-
|
|
617
|
-
} else if (options.missingResourcesOnly) {
|
|
618
|
-
// Check 404 resources only (missing local files)
|
|
619
|
-
console.log(chalk.blue('📁 Đang kiểm tra tài nguyên thiếu...'));
|
|
620
|
-
const resourceResults = await fixer.check404Resources(options.directory);
|
|
621
|
-
const totalMissingResources = resourceResults.reduce((sum, r) => sum + (r.issues || 0), 0);
|
|
622
|
-
|
|
623
|
-
console.log(chalk.green(`\n✅ Đã kiểm tra tài nguyên cục bộ trong ${resourceResults.length} file (${totalMissingResources} vấn đề)`));
|
|
624
|
-
console.log(chalk.gray('💡 Vấn đề tài nguyên thiếu cần xem xét thủ công và không thể tự động sửa'));
|
|
625
|
-
|
|
626
|
-
showCompletionMessage(options, 'Kiểm tra tài nguyên thiếu');
|
|
627
|
-
return;
|
|
628
|
-
|
|
629
|
-
} else if (options.gtmCheckOnly) {
|
|
630
|
-
// Check Google Tag Manager installation only (no fixes)
|
|
631
|
-
console.log(chalk.blue('🏷️ Đang kiểm tra Google Tag Manager...'));
|
|
632
|
-
const gtmResults = await fixer.checkGoogleTagManager(options.directory);
|
|
633
|
-
const filesWithGTM = gtmResults.filter(r => r.gtmAnalysis?.hasGTM).length;
|
|
634
|
-
const filesWithIssues = gtmResults.filter(r => r.gtmAnalysis?.issues?.length > 0).length;
|
|
635
|
-
|
|
636
|
-
console.log(chalk.green(`\n✅ Phân tích hoàn tất: Tìm thấy ${filesWithGTM} file có GTM`));
|
|
637
|
-
if (filesWithIssues > 0) {
|
|
638
|
-
console.log(chalk.yellow(`⚠️ ${filesWithIssues} file có vấn đề về cài đặt GTM`));
|
|
639
|
-
}
|
|
640
|
-
console.log(chalk.gray('💡 GTM cần có cả <script> trong <head> và <noscript> sau <body>'));
|
|
641
|
-
|
|
642
|
-
showCompletionMessage(options, 'Kiểm tra GTM');
|
|
643
|
-
return;
|
|
644
|
-
|
|
645
|
-
} else if (options.checkMetaOnly) {
|
|
646
|
-
// Check meta tags only (no fixes)
|
|
647
|
-
console.log(chalk.blue('🏷️ Đang kiểm tra meta tags và Open Graph Protocol...'));
|
|
648
|
-
await fixer.checkMetaTags(options.directory);
|
|
649
|
-
|
|
650
|
-
showCompletionMessage(options, 'Kiểm tra meta tags');
|
|
651
|
-
return;
|
|
652
|
-
|
|
653
|
-
} else if (options.fixMetaOnly) {
|
|
654
|
-
// Fix meta tags
|
|
655
|
-
console.log(chalk.blue('🔧 Đang tự động sửa meta tags...'));
|
|
656
|
-
await fixer.fixMetaTags(options.directory, { dryRun: options.dryRun, backup: options.backupFiles });
|
|
657
|
-
|
|
658
|
-
showCompletionMessage(options, 'Sửa meta tags');
|
|
659
|
-
return;
|
|
660
|
-
|
|
661
|
-
} else if (options.unusedFilesOnly) {
|
|
662
|
-
// Check unused files only (no fixes, no cleanup)
|
|
663
|
-
console.log(chalk.blue('🗂️ Đang kiểm tra file không sử dụng...'));
|
|
664
|
-
const unusedResults = await fixer.checkUnusedFiles(options.directory);
|
|
665
|
-
const totalUnusedFiles = unusedResults.unusedCount;
|
|
666
|
-
|
|
667
|
-
if (totalUnusedFiles === 0) {
|
|
668
|
-
console.log(chalk.green(`\n✅ Không tìm thấy file không sử dụng! Tất cả ${unusedResults.totalFiles} file đều được tham chiếu đúng cách.`));
|
|
669
|
-
} else {
|
|
670
|
-
console.log(chalk.green(`\n✅ Phân tích hoàn tất: Tìm thấy ${totalUnusedFiles} file không sử dụng trong tổng số ${unusedResults.totalFiles} file`));
|
|
671
|
-
console.log(chalk.gray(`📊 ${unusedResults.referencedFiles} file được tham chiếu, ${totalUnusedFiles} file có thể không sử dụng`));
|
|
672
|
-
}
|
|
673
|
-
console.log(chalk.gray('💡 Phát hiện file không sử dụng dựa trên heuristic - khuyến nghị xem xét thủ công'));
|
|
674
|
-
|
|
675
|
-
showCompletionMessage(options, 'Kiểm tra file không sử dụng');
|
|
676
|
-
return;
|
|
677
|
-
|
|
678
|
-
} else if (options.unusedFilesListOnly) {
|
|
679
|
-
console.log(chalk.blue('📝 Đang tạo danh sách file không sử dụng...'));
|
|
680
|
-
const listResults = await fixer.generateUnusedFilesList(options.directory, options.listFile);
|
|
681
|
-
|
|
682
|
-
console.log(chalk.green(`\n✅ Đã tạo file list: ${listResults.outputPath}`));
|
|
683
|
-
console.log(chalk.gray(`📊 ${listResults.unusedCount} path đã được ghi vào list`));
|
|
684
|
-
console.log(chalk.gray('💡 Danh sách dùng path tương đối so với thư mục target và có thể dùng lại với --delete-unused-files'));
|
|
685
|
-
return;
|
|
686
|
-
|
|
687
|
-
} else if (options.deleteUnusedFilesFromList) {
|
|
688
|
-
console.log(chalk.blue('🗑️ Đang xóa file theo danh sách unused files...'));
|
|
689
|
-
const deleteResults = await fixer.deleteUnusedFilesFromList(options.directory, options.listFile, {
|
|
690
|
-
dryRun: options.dryRun
|
|
691
|
-
});
|
|
692
|
-
|
|
693
|
-
console.log(chalk.green(`\n✅ ${options.dryRun ? 'Đã mô phỏng xóa' : 'Đã xử lý xóa'} ${deleteResults.deletedCount} file từ list`));
|
|
694
|
-
console.log(chalk.gray(`📄 File list: ${deleteResults.listPath}`));
|
|
695
|
-
|
|
696
|
-
if (deleteResults.missingCount > 0) {
|
|
697
|
-
console.log(chalk.yellow(`⚠️ ${deleteResults.missingCount} file trong list không còn tồn tại`));
|
|
698
|
-
}
|
|
375
|
+
let result;
|
|
376
|
+
let label;
|
|
699
377
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
378
|
+
if (options.altOnly) {
|
|
379
|
+
label = 'Alt Text Check';
|
|
380
|
+
result = await checker.checkAltText(options.directory);
|
|
381
|
+
} else if (options.langOnly) {
|
|
382
|
+
label = 'Lang Check';
|
|
383
|
+
result = await checker.checkLang(options.directory);
|
|
384
|
+
} else if (options.roleOnly) {
|
|
385
|
+
label = 'Role Check';
|
|
386
|
+
result = await checker.checkRoles(options.directory);
|
|
387
|
+
} else if (options.ariaLabelOnly) {
|
|
388
|
+
label = 'Aria Label Check';
|
|
389
|
+
result = await checker.checkAriaLabels(options.directory);
|
|
390
|
+
} else if (options.formsOnly) {
|
|
391
|
+
label = 'Form Label Check';
|
|
392
|
+
result = await checker.checkForms(options.directory);
|
|
393
|
+
} else if (options.nestedOnly) {
|
|
394
|
+
label = 'Nested Control Check';
|
|
395
|
+
result = await checker.checkNestedControls(options.directory);
|
|
396
|
+
} else if (options.buttonsOnly) {
|
|
397
|
+
label = 'Button Check';
|
|
398
|
+
result = await checker.checkButtons(options.directory);
|
|
399
|
+
} else if (options.linksOnly) {
|
|
400
|
+
label = 'Accessible Link Name Check';
|
|
401
|
+
result = await checker.checkLinks(options.directory);
|
|
402
|
+
} else if (options.landmarksOnly) {
|
|
403
|
+
label = 'Landmark Check';
|
|
404
|
+
result = await checker.checkLandmarks(options.directory);
|
|
405
|
+
} else if (options.headingsOnly) {
|
|
406
|
+
label = 'Heading Check';
|
|
407
|
+
result = await checker.checkHeadings(options.directory);
|
|
408
|
+
} else if (options.dlOnly) {
|
|
409
|
+
label = 'Description List Check';
|
|
410
|
+
result = await checker.checkDescriptionLists(options.directory);
|
|
411
|
+
} else if (options.linksCheckOnly) {
|
|
412
|
+
label = 'Link and Resource Check';
|
|
413
|
+
result = await checker.checkLinksAndResources(options.directory);
|
|
414
|
+
} else if (options.brokenLinksOnly) {
|
|
415
|
+
label = 'Broken External Link Check';
|
|
416
|
+
result = await checker.checkBrokenLinks(options.directory);
|
|
417
|
+
} else if (options.missingResourcesOnly) {
|
|
418
|
+
label = 'Missing Resource Check';
|
|
419
|
+
result = await checker.check404Resources(options.directory);
|
|
420
|
+
} else if (options.gtmCheckOnly) {
|
|
421
|
+
label = 'GTM Check';
|
|
422
|
+
result = await checker.checkGoogleTagManager(options.directory);
|
|
423
|
+
} else if (options.checkMetaOnly) {
|
|
424
|
+
label = 'Meta Tag Check';
|
|
425
|
+
result = await checker.checkMetaTags(options.directory);
|
|
426
|
+
} else if (options.fullReport) {
|
|
427
|
+
label = 'Full Report';
|
|
428
|
+
result = await checker.generateFullReport(options.directory, options.reportOutput);
|
|
429
|
+
} else if (options.unusedFilesOnly) {
|
|
430
|
+
label = 'Unused File Check';
|
|
431
|
+
result = await checker.checkUnusedFiles(options.directory);
|
|
432
|
+
} else if (options.unusedFilesListOnly) {
|
|
433
|
+
label = 'Unused File List Export';
|
|
434
|
+
result = await checker.generateUnusedFilesList(options.directory, options.listFile);
|
|
435
|
+
} else if (options.deadCodeOnly) {
|
|
436
|
+
label = 'Dead Code Check';
|
|
437
|
+
result = await checker.checkDeadCode(options.directory);
|
|
438
|
+
} else if (options.fileSizeOnly) {
|
|
439
|
+
label = 'File Size Check';
|
|
440
|
+
result = await checker.checkFileSizes(options.directory);
|
|
441
|
+
} else {
|
|
442
|
+
label = 'Comprehensive Check';
|
|
443
|
+
result = await checker.runComprehensiveChecks(options.directory);
|
|
444
|
+
}
|
|
703
445
|
|
|
704
|
-
|
|
705
|
-
console.log(chalk.cyan('\n💡 Đây là chế độ xem trước. Chạy lại không kèm --dry-run để xóa thật.'));
|
|
706
|
-
} else {
|
|
707
|
-
console.log(chalk.gray('💡 File list được giữ nguyên để bạn có thể đối chiếu sau khi xóa'));
|
|
708
|
-
}
|
|
709
|
-
return;
|
|
710
|
-
|
|
711
|
-
} else if (options.deadCodeOnly) {
|
|
712
|
-
// Check dead code only (no fixes, no cleanup)
|
|
713
|
-
console.log(chalk.blue('☠️ Đang kiểm tra mã không sử dụng...'));
|
|
714
|
-
const deadCodeResults = await fixer.checkDeadCode(options.directory);
|
|
715
|
-
const totalDeadCode = deadCodeResults.length;
|
|
716
|
-
|
|
717
|
-
console.log(chalk.green(`\n✅ Đã kiểm tra mã không sử dụng (${totalDeadCode} vấn đề tiềm ẩn)`));
|
|
718
|
-
console.log(chalk.gray('💡 Phân tích mã không sử dụng dựa trên heuristic - khuyến nghị xem xét thủ công'));
|
|
719
|
-
|
|
720
|
-
showCompletionMessage(options, 'Kiểm tra mã không sử dụng');
|
|
721
|
-
return;
|
|
722
|
-
|
|
723
|
-
} else if (options.fileSizeOnly) {
|
|
724
|
-
// Check file sizes only (no fixes, no cleanup)
|
|
725
|
-
console.log(chalk.blue('📏 Đang phân tích kích thước file...'));
|
|
726
|
-
const sizeResults = await fixer.checkFileSizes(options.directory);
|
|
727
|
-
const totalLargeFiles = sizeResults.largeFiles.length;
|
|
728
|
-
|
|
729
|
-
console.log(chalk.green(`\n✅ Đã phân tích ${sizeResults.totalFiles} file (${totalLargeFiles} file có kích thước lớn)`));
|
|
730
|
-
console.log(chalk.gray('💡 Phân tích kích thước file dựa trên best practices phổ biến'));
|
|
731
|
-
|
|
732
|
-
showCompletionMessage(options, 'Phân tích kích thước file');
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
446
|
+
printSummary(label, result);
|
|
735
447
|
|
|
736
|
-
|
|
737
|
-
console.error(chalk.red('❌ Đã xảy ra lỗi:'), error.message);
|
|
738
|
-
process.exit(1);
|
|
739
|
-
}
|
|
448
|
+
console.log(chalk.green('\n✅ Check completed.'));
|
|
740
449
|
}
|
|
741
450
|
|
|
742
|
-
|
|
743
|
-
|
|
451
|
+
run().catch((error) => {
|
|
452
|
+
console.error(chalk.red(`\n❌ ${error.message}`));
|
|
453
|
+
process.exit(1);
|
|
454
|
+
});
|