gbu-accessibility-package 3.8.5 → 3.8.7
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-vi.md +1 -1
- package/README.md +1 -1
- package/cli.js +7 -2
- package/lib/fixer.js +104 -63
- package/package.json +4 -1
package/README-vi.md
CHANGED
|
@@ -362,7 +362,7 @@ await fixer.checkFileSizes('./src');
|
|
|
362
362
|
### Tối ưu hóa dự án
|
|
363
363
|
|
|
364
364
|
- **File không sử dụng** → Phát hiện file không được tham chiếu ở đâu trong toàn bộ dự án
|
|
365
|
-
- **File types được kiểm tra**: Hình ảnh, CSS, JavaScript, JSX, TypeScript, Vue, PHP, JSON, Markdown, XML, PDF, Video, Audio files (không bao gồm HTML)
|
|
365
|
+
- **File types được kiểm tra**: Hình ảnh, CSS, SCSS/Sass, JavaScript, JSX, TypeScript, Vue, PHP, JSON, Markdown, XML, PDF, Video, Audio files (không bao gồm HTML)
|
|
366
366
|
- **Quét toàn diện**: Phân tích từ project root, không giới hạn thư mục hiện tại
|
|
367
367
|
- **Cross-reference detection**: Tìm tham chiếu từ HTML, CSS, JavaScript, JSON, và các file khác
|
|
368
368
|
- **Multiple path formats**: Hỗ trợ relative paths, absolute paths, imports, requires
|
package/README.md
CHANGED
|
@@ -349,7 +349,7 @@ await fixer.checkFileSizes('./src');
|
|
|
349
349
|
|
|
350
350
|
### Project Optimization
|
|
351
351
|
- **Unused Files** → Detect files not referenced anywhere in the project
|
|
352
|
-
- Images, CSS, JavaScript, JSX, TypeScript, Vue, PHP, JSON, Markdown, XML, PDF, Video, Audio files
|
|
352
|
+
- Images, CSS, SCSS/Sass, JavaScript, JSX, TypeScript, Vue, PHP, JSON, Markdown, XML, PDF, Video, Audio files
|
|
353
353
|
- Local file references analysis
|
|
354
354
|
- Heuristic detection with manual review recommendations
|
|
355
355
|
- **Dead Code Analysis** → Find unused CSS rules and JavaScript functions
|
package/cli.js
CHANGED
|
@@ -572,9 +572,14 @@ async function main() {
|
|
|
572
572
|
// Check unused files only (no fixes, no cleanup)
|
|
573
573
|
console.log(chalk.blue('🗂️ Running unused files check only...'));
|
|
574
574
|
const unusedResults = await fixer.checkUnusedFiles(options.directory);
|
|
575
|
-
const totalUnusedFiles = unusedResults.
|
|
575
|
+
const totalUnusedFiles = unusedResults.unusedCount;
|
|
576
576
|
|
|
577
|
-
|
|
577
|
+
if (totalUnusedFiles === 0) {
|
|
578
|
+
console.log(chalk.green(`\n✅ No unused files found! All ${unusedResults.totalFiles} files are properly referenced.`));
|
|
579
|
+
} else {
|
|
580
|
+
console.log(chalk.green(`\n✅ Analysis complete: Found ${totalUnusedFiles} unused files out of ${unusedResults.totalFiles} total files`));
|
|
581
|
+
console.log(chalk.gray(`📊 ${unusedResults.referencedFiles} files are referenced, ${totalUnusedFiles} potentially unused`));
|
|
582
|
+
}
|
|
578
583
|
console.log(chalk.gray('💡 Unused file detection is heuristic - manual review recommended'));
|
|
579
584
|
|
|
580
585
|
showCompletionMessage(options, 'Unused files check');
|
package/lib/fixer.js
CHANGED
|
@@ -5671,6 +5671,8 @@ class AccessibilityFixer {
|
|
|
5671
5671
|
const referencedFiles = await this.findReferencedFiles(scanDirectory);
|
|
5672
5672
|
console.log(chalk.gray(`🔍 Found ${referencedFiles.size} referenced files`));
|
|
5673
5673
|
|
|
5674
|
+
|
|
5675
|
+
|
|
5674
5676
|
// Find unused files
|
|
5675
5677
|
const unusedFiles = [];
|
|
5676
5678
|
|
|
@@ -5684,6 +5686,8 @@ class AccessibilityFixer {
|
|
|
5684
5686
|
const relativePath = path.relative(scanDirectory, file);
|
|
5685
5687
|
const isReferenced = this.isFileReferenced(file, relativePath, referencedFiles, scanDirectory);
|
|
5686
5688
|
|
|
5689
|
+
|
|
5690
|
+
|
|
5687
5691
|
if (!isReferenced) {
|
|
5688
5692
|
const stats = await require('fs').promises.stat(file);
|
|
5689
5693
|
const fileSize = this.formatFileSize(stats.size);
|
|
@@ -5732,7 +5736,7 @@ class AccessibilityFixer {
|
|
|
5732
5736
|
};
|
|
5733
5737
|
}
|
|
5734
5738
|
|
|
5735
|
-
// Enhanced file reference checking
|
|
5739
|
+
// Enhanced file reference checking - now works with relative paths
|
|
5736
5740
|
isFileReferenced(filePath, relativePath, referencedFiles, projectRoot) {
|
|
5737
5741
|
// Check various possible reference formats
|
|
5738
5742
|
const possibleRefs = [
|
|
@@ -5748,19 +5752,31 @@ class AccessibilityFixer {
|
|
|
5748
5752
|
relativePath.replace(/^\//, ''), // remove leading /
|
|
5749
5753
|
];
|
|
5750
5754
|
|
|
5751
|
-
// Check if any reference format exists
|
|
5755
|
+
// Check if any reference format exists in the set
|
|
5752
5756
|
for (const ref of possibleRefs) {
|
|
5753
5757
|
if (referencedFiles.has(ref)) {
|
|
5754
5758
|
return true;
|
|
5755
5759
|
}
|
|
5756
5760
|
}
|
|
5757
5761
|
|
|
5758
|
-
//
|
|
5759
|
-
const fileName = path.basename(filePath
|
|
5762
|
+
// Additional checks for path variations
|
|
5763
|
+
const fileName = path.basename(filePath);
|
|
5764
|
+
const relativeDir = path.dirname(relativePath);
|
|
5765
|
+
|
|
5766
|
+
// Check for references that might include parent directory names
|
|
5760
5767
|
for (const ref of referencedFiles) {
|
|
5761
|
-
if
|
|
5768
|
+
// If reference ends with the filename, check if path context matches
|
|
5769
|
+
if (ref.endsWith('/' + fileName) || ref === fileName) {
|
|
5762
5770
|
return true;
|
|
5763
5771
|
}
|
|
5772
|
+
|
|
5773
|
+
// Check for absolute paths that correspond to our relative path
|
|
5774
|
+
if (ref.startsWith('/') && ref.includes(fileName)) {
|
|
5775
|
+
const refWithoutLeading = ref.substring(1);
|
|
5776
|
+
if (refWithoutLeading === relativePath || refWithoutLeading.endsWith('/' + fileName)) {
|
|
5777
|
+
return true;
|
|
5778
|
+
}
|
|
5779
|
+
}
|
|
5764
5780
|
}
|
|
5765
5781
|
|
|
5766
5782
|
return false;
|
|
@@ -5768,8 +5784,8 @@ class AccessibilityFixer {
|
|
|
5768
5784
|
|
|
5769
5785
|
async findAllProjectFiles(directory) {
|
|
5770
5786
|
const files = [];
|
|
5771
|
-
//
|
|
5772
|
-
const extensions = ['.css', '.
|
|
5787
|
+
// Only check web assets: CSS, HTML, JS, and images
|
|
5788
|
+
const extensions = ['.css', '.html', '.htm', '.js', '.jsx', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.ico'];
|
|
5773
5789
|
|
|
5774
5790
|
const scan = async (dir) => {
|
|
5775
5791
|
try {
|
|
@@ -5825,7 +5841,7 @@ class AccessibilityFixer {
|
|
|
5825
5841
|
return referencedFiles;
|
|
5826
5842
|
}
|
|
5827
5843
|
|
|
5828
|
-
// Find
|
|
5844
|
+
// Find HTML and CSS/SCSS files to scan for references
|
|
5829
5845
|
async findSourceFiles(directory) {
|
|
5830
5846
|
const sourceFiles = [];
|
|
5831
5847
|
|
|
@@ -5842,10 +5858,9 @@ class AccessibilityFixer {
|
|
|
5842
5858
|
await walk(filePath);
|
|
5843
5859
|
}
|
|
5844
5860
|
} else {
|
|
5845
|
-
// Include
|
|
5861
|
+
// Include HTML (main entry) and CSS/SCSS (for background images)
|
|
5846
5862
|
const ext = path.extname(file).toLowerCase();
|
|
5847
|
-
if (['.html', '.htm', '.css', '.
|
|
5848
|
-
'.vue', '.php', '.json', '.md', '.xml', '.svg'].includes(ext)) {
|
|
5863
|
+
if (['.html', '.htm', '.css', '.scss', '.sass'].includes(ext)) {
|
|
5849
5864
|
sourceFiles.push(filePath);
|
|
5850
5865
|
}
|
|
5851
5866
|
}
|
|
@@ -5859,59 +5874,47 @@ class AccessibilityFixer {
|
|
|
5859
5874
|
return sourceFiles;
|
|
5860
5875
|
}
|
|
5861
5876
|
|
|
5862
|
-
// Enhanced reference extraction
|
|
5877
|
+
// Enhanced reference extraction from HTML and CSS files
|
|
5863
5878
|
extractAllReferences(content, baseDir, sourceFile) {
|
|
5864
|
-
const references =
|
|
5865
|
-
|
|
5866
|
-
// Get file extension to determine extraction method
|
|
5879
|
+
const references = [];
|
|
5867
5880
|
const ext = path.extname(sourceFile).toLowerCase();
|
|
5868
5881
|
|
|
5869
5882
|
if (['.html', '.htm'].includes(ext)) {
|
|
5870
|
-
// HTML
|
|
5871
|
-
const htmlRefs = this.
|
|
5872
|
-
|
|
5883
|
+
// Extract from HTML files - main entry points
|
|
5884
|
+
const htmlRefs = this.extractHtmlReferences(content, baseDir);
|
|
5885
|
+
references.push(...htmlRefs);
|
|
5873
5886
|
|
|
5874
|
-
} else if (
|
|
5875
|
-
// CSS
|
|
5887
|
+
} else if (['.css', '.scss', '.sass'].includes(ext)) {
|
|
5888
|
+
// Extract from CSS/SCSS files - background images
|
|
5876
5889
|
const cssRefs = this.extractCssReferences(content, baseDir);
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
} else if (['.js', '.jsx', '.ts', '.tsx'].includes(ext)) {
|
|
5880
|
-
// JavaScript/TypeScript references
|
|
5881
|
-
const jsRefs = this.extractJsReferences(content, baseDir);
|
|
5882
|
-
jsRefs.forEach(ref => references.add(ref));
|
|
5883
|
-
|
|
5884
|
-
// Also extract import statements
|
|
5885
|
-
const importRefs = this.extractImportReferences(content, baseDir);
|
|
5886
|
-
importRefs.forEach(ref => references.add(ref));
|
|
5887
|
-
|
|
5888
|
-
} else if (ext === '.json') {
|
|
5889
|
-
// JSON references (like package.json, config files)
|
|
5890
|
-
const jsonRefs = this.extractJsonReferences(content, baseDir);
|
|
5891
|
-
jsonRefs.forEach(ref => references.add(ref));
|
|
5892
|
-
|
|
5893
|
-
} else {
|
|
5894
|
-
// Generic file references (for .md, .xml, etc.)
|
|
5895
|
-
const genericRefs = this.extractGenericReferences(content, baseDir);
|
|
5896
|
-
genericRefs.forEach(ref => references.add(ref));
|
|
5890
|
+
references.push(...cssRefs);
|
|
5897
5891
|
}
|
|
5898
5892
|
|
|
5899
|
-
return
|
|
5893
|
+
return references;
|
|
5900
5894
|
}
|
|
5901
5895
|
|
|
5902
|
-
|
|
5896
|
+
extractHtmlReferences(content, baseDir) {
|
|
5903
5897
|
const references = [];
|
|
5904
5898
|
|
|
5905
5899
|
// HTML patterns for file references
|
|
5906
5900
|
const patterns = [
|
|
5907
5901
|
// Images
|
|
5908
5902
|
/<img[^>]*src\s*=\s*["']([^"']+)["']/gi,
|
|
5903
|
+
// Srcset (responsive images)
|
|
5904
|
+
/<img[^>]*srcset\s*=\s*["']([^"']+)["']/gi,
|
|
5905
|
+
/<source[^>]*srcset\s*=\s*["']([^"']+)["']/gi,
|
|
5906
|
+
// Data attributes (lazy loading, etc.)
|
|
5907
|
+
/data-src\s*=\s*["']([^"']+)["']/gi,
|
|
5908
|
+
/data-background\s*=\s*["']([^"']+)["']/gi,
|
|
5909
|
+
/data-image\s*=\s*["']([^"']+)["']/gi,
|
|
5910
|
+
/data-bg\s*=\s*["']([^"']+)["']/gi,
|
|
5911
|
+
/data-lazy\s*=\s*["']([^"']+)["']/gi,
|
|
5909
5912
|
// Links (CSS, other files)
|
|
5910
5913
|
/<link[^>]*href\s*=\s*["']([^"']+)["']/gi,
|
|
5911
5914
|
// Scripts
|
|
5912
5915
|
/<script[^>]*src\s*=\s*["']([^"']+)["']/gi,
|
|
5913
|
-
// Anchors
|
|
5914
|
-
/<a[^>]*href\s*=\s*["']([^"']
|
|
5916
|
+
// Anchors to other HTML files
|
|
5917
|
+
/<a[^>]*href\s*=\s*["']([^"'#]+\.html?)["']/gi,
|
|
5915
5918
|
// Video/Audio
|
|
5916
5919
|
/<(?:video|audio)[^>]*src\s*=\s*["']([^"']+)["']/gi,
|
|
5917
5920
|
// Object/Embed
|
|
@@ -5926,10 +5929,18 @@ class AccessibilityFixer {
|
|
|
5926
5929
|
let match;
|
|
5927
5930
|
while ((match = pattern.exec(content)) !== null) {
|
|
5928
5931
|
const url = match[1];
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5932
|
+
|
|
5933
|
+
// Handle srcset format: "image1.jpg 1x, image2.jpg 2x"
|
|
5934
|
+
if (pattern.source.includes('srcset')) {
|
|
5935
|
+
const srcsetUrls = url.split(',').map(item => item.trim().split(' ')[0]);
|
|
5936
|
+
srcsetUrls.forEach(srcUrl => {
|
|
5937
|
+
if (this.isLocalFile(srcUrl)) {
|
|
5938
|
+
this.addNormalizedUrl(references, srcUrl);
|
|
5939
|
+
}
|
|
5940
|
+
});
|
|
5941
|
+
} else {
|
|
5942
|
+
if (this.isLocalFile(url)) {
|
|
5943
|
+
this.addNormalizedUrl(references, url);
|
|
5933
5944
|
}
|
|
5934
5945
|
}
|
|
5935
5946
|
}
|
|
@@ -5938,15 +5949,29 @@ class AccessibilityFixer {
|
|
|
5938
5949
|
return references;
|
|
5939
5950
|
}
|
|
5940
5951
|
|
|
5952
|
+
// Helper method to add normalized URL variations
|
|
5953
|
+
addNormalizedUrl(references, url) {
|
|
5954
|
+
// Store original URL and normalized versions for matching
|
|
5955
|
+
references.push(url);
|
|
5956
|
+
if (url.startsWith('/')) {
|
|
5957
|
+
references.push(url.substring(1)); // Remove leading slash
|
|
5958
|
+
}
|
|
5959
|
+
if (!url.startsWith('./') && !url.startsWith('/')) {
|
|
5960
|
+
references.push('./' + url); // Add leading ./
|
|
5961
|
+
}
|
|
5962
|
+
}
|
|
5963
|
+
|
|
5941
5964
|
extractCssReferences(content, baseDir) {
|
|
5942
5965
|
const references = [];
|
|
5943
5966
|
|
|
5944
|
-
// CSS patterns for file references
|
|
5967
|
+
// CSS patterns for file references
|
|
5945
5968
|
const patterns = [
|
|
5946
|
-
// url() function
|
|
5969
|
+
// url() function - background images, fonts, etc.
|
|
5947
5970
|
/url\s*\(\s*["']?([^"')]+)["']?\s*\)/gi,
|
|
5948
|
-
// @import
|
|
5949
|
-
/@import\s+["']([^"']+)["']/gi
|
|
5971
|
+
// @import CSS files
|
|
5972
|
+
/@import\s+["']([^"']+)["']/gi,
|
|
5973
|
+
// CSS custom properties with URLs
|
|
5974
|
+
/--[^:]+:\s*url\s*\(\s*["']?([^"')]+)["']?\s*\)/gi
|
|
5950
5975
|
];
|
|
5951
5976
|
|
|
5952
5977
|
for (const pattern of patterns) {
|
|
@@ -5954,10 +5979,7 @@ class AccessibilityFixer {
|
|
|
5954
5979
|
while ((match = pattern.exec(content)) !== null) {
|
|
5955
5980
|
const url = match[1];
|
|
5956
5981
|
if (this.isLocalFile(url)) {
|
|
5957
|
-
|
|
5958
|
-
if (resolvedPath) {
|
|
5959
|
-
references.push(resolvedPath);
|
|
5960
|
-
}
|
|
5982
|
+
this.addNormalizedUrl(references, url);
|
|
5961
5983
|
}
|
|
5962
5984
|
}
|
|
5963
5985
|
}
|
|
@@ -5985,9 +6007,13 @@ class AccessibilityFixer {
|
|
|
5985
6007
|
while ((match = pattern.exec(content)) !== null) {
|
|
5986
6008
|
const url = match[1];
|
|
5987
6009
|
if (this.isLocalFile(url)) {
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
6010
|
+
// Store both original URL and normalized versions for matching
|
|
6011
|
+
references.push(url);
|
|
6012
|
+
if (url.startsWith('/')) {
|
|
6013
|
+
references.push(url.substring(1)); // Remove leading slash
|
|
6014
|
+
}
|
|
6015
|
+
if (!url.startsWith('./') && !url.startsWith('/')) {
|
|
6016
|
+
references.push('./' + url); // Add leading ./
|
|
5991
6017
|
}
|
|
5992
6018
|
}
|
|
5993
6019
|
}
|
|
@@ -6058,15 +6084,25 @@ class AccessibilityFixer {
|
|
|
6058
6084
|
shouldSkipUnusedCheck(filePath) {
|
|
6059
6085
|
const fileName = path.basename(filePath);
|
|
6060
6086
|
const dirName = path.basename(path.dirname(filePath));
|
|
6087
|
+
const relativePath = path.relative(process.cwd(), filePath);
|
|
6061
6088
|
|
|
6062
|
-
// Skip
|
|
6089
|
+
// Skip index files - they are main entry points
|
|
6090
|
+
if (/^index\d*\.(html?|htm)$/i.test(fileName)) {
|
|
6091
|
+
return true;
|
|
6092
|
+
}
|
|
6093
|
+
|
|
6094
|
+
// Skip OGP images - usually referenced with absolute paths in meta tags
|
|
6095
|
+
if (/^ogp\.(png|jpg|jpeg)$/i.test(fileName)) {
|
|
6096
|
+
return true;
|
|
6097
|
+
}
|
|
6098
|
+
|
|
6099
|
+
// Skip certain file types and patterns - but only in root directory
|
|
6063
6100
|
const skipPatterns = [
|
|
6064
|
-
// Common files that might not be directly referenced
|
|
6065
|
-
/^(
|
|
6101
|
+
// Common files that might not be directly referenced - only in root
|
|
6102
|
+
/^(main|app)\.(html|js|css)$/i,
|
|
6066
6103
|
/^(readme|license|changelog)/i,
|
|
6067
6104
|
/^package\.json$/i,
|
|
6068
6105
|
/^\.gitignore$/i,
|
|
6069
|
-
/^favicon\.(ico|png)$/i,
|
|
6070
6106
|
/^robots\.txt$/i,
|
|
6071
6107
|
/^sitemap\.xml$/i,
|
|
6072
6108
|
// Backup files
|
|
@@ -6075,6 +6111,11 @@ class AccessibilityFixer {
|
|
|
6075
6111
|
/test|spec|__tests__/i
|
|
6076
6112
|
];
|
|
6077
6113
|
|
|
6114
|
+
// Only skip favicon in root directory, not in assets folders
|
|
6115
|
+
if (/^favicon\.(ico|png)$/i.test(fileName) && !relativePath.includes('/')) {
|
|
6116
|
+
return true;
|
|
6117
|
+
}
|
|
6118
|
+
|
|
6078
6119
|
return skipPatterns.some(pattern =>
|
|
6079
6120
|
pattern.test(fileName) || pattern.test(dirName)
|
|
6080
6121
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gbu-accessibility-package",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.7",
|
|
4
4
|
"description": "Comprehensive accessibility fixes and project optimization for HTML files. Smart context-aware alt text generation, form labels, button names, link names, landmarks, heading analysis, WCAG-compliant role attributes, unused files detection, dead code analysis, broken external links detection, and missing local resources detection. Covers major axe DevTools issues with individual fix modes.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -35,6 +35,9 @@
|
|
|
35
35
|
"demo": "node cli.js --dry-run demo",
|
|
36
36
|
"demo-enhanced": "node cli.js --enhanced-alt --dry-run demo",
|
|
37
37
|
"demo-creative": "node cli.js --enhanced-alt --alt-creativity creative --include-emotions --dry-run demo",
|
|
38
|
+
"test-local": "./test-local-projects.sh",
|
|
39
|
+
"test-unused-files": "./test-unused-files.sh",
|
|
40
|
+
"test-pack": "npm pack && echo 'Package created. Install in test project with: npm install ./gbu-accessibility-package-$(node -p \"require('./package.json').version\").tgz'",
|
|
38
41
|
"prepublishOnly": "npm run test"
|
|
39
42
|
},
|
|
40
43
|
"keywords": [
|