gbu-accessibility-package 3.8.6 → 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.
Files changed (2) hide show
  1. package/lib/fixer.js +91 -69
  2. package/package.json +4 -1
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
 
@@ -5734,7 +5736,7 @@ class AccessibilityFixer {
5734
5736
  };
5735
5737
  }
5736
5738
 
5737
- // Enhanced file reference checking
5739
+ // Enhanced file reference checking - now works with relative paths
5738
5740
  isFileReferenced(filePath, relativePath, referencedFiles, projectRoot) {
5739
5741
  // Check various possible reference formats
5740
5742
  const possibleRefs = [
@@ -5750,30 +5752,30 @@ class AccessibilityFixer {
5750
5752
  relativePath.replace(/^\//, ''), // remove leading /
5751
5753
  ];
5752
5754
 
5753
- // Check if any reference format exists
5755
+ // Check if any reference format exists in the set
5754
5756
  for (const ref of possibleRefs) {
5755
5757
  if (referencedFiles.has(ref)) {
5756
5758
  return true;
5757
5759
  }
5758
5760
  }
5759
5761
 
5760
- // Check for partial matches (for dynamic imports) - match only specific patterns
5761
- const fullFileName = path.basename(filePath);
5762
+ // Additional checks for path variations
5763
+ const fileName = path.basename(filePath);
5764
+ const relativeDir = path.dirname(relativePath);
5762
5765
 
5766
+ // Check for references that might include parent directory names
5763
5767
  for (const ref of referencedFiles) {
5764
- // Match full relative path first (most accurate)
5765
- if (ref === relativePath || ref === './' + relativePath || ref === '/' + relativePath) {
5768
+ // If reference ends with the filename, check if path context matches
5769
+ if (ref.endsWith('/' + fileName) || ref === fileName) {
5766
5770
  return true;
5767
5771
  }
5768
5772
 
5769
- // Match filename only if it appears in a relative path context (not absolute paths)
5770
- if (ref.includes('/') && ref.endsWith('/' + fullFileName) && !path.isAbsolute(ref)) {
5771
- return true;
5772
- }
5773
-
5774
- // Match filename only if it's the exact reference (not just substring)
5775
- if (ref === fullFileName) {
5776
- return true;
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
+ }
5777
5779
  }
5778
5780
  }
5779
5781
 
@@ -5782,8 +5784,8 @@ class AccessibilityFixer {
5782
5784
 
5783
5785
  async findAllProjectFiles(directory) {
5784
5786
  const files = [];
5785
- // Check all relevant file types except HTML files
5786
- const extensions = ['.css', '.scss', '.sass', '.js', '.jsx', '.ts', '.tsx', '.vue', '.php', '.json', '.md', '.xml', '.jpg', '.jpeg', '.png', '.gif', '.svg', '.webp', '.ico', '.pdf', '.mp4', '.webm', '.mp3', '.wav'];
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'];
5787
5789
 
5788
5790
  const scan = async (dir) => {
5789
5791
  try {
@@ -5839,7 +5841,7 @@ class AccessibilityFixer {
5839
5841
  return referencedFiles;
5840
5842
  }
5841
5843
 
5842
- // Find all source files that could contain references
5844
+ // Find HTML and CSS/SCSS files to scan for references
5843
5845
  async findSourceFiles(directory) {
5844
5846
  const sourceFiles = [];
5845
5847
 
@@ -5856,10 +5858,9 @@ class AccessibilityFixer {
5856
5858
  await walk(filePath);
5857
5859
  }
5858
5860
  } else {
5859
- // Include files that could contain references
5861
+ // Include HTML (main entry) and CSS/SCSS (for background images)
5860
5862
  const ext = path.extname(file).toLowerCase();
5861
- if (['.html', '.htm', '.css', '.js', '.jsx', '.ts', '.tsx',
5862
- '.vue', '.php', '.json', '.md', '.xml', '.svg'].includes(ext)) {
5863
+ if (['.html', '.htm', '.css', '.scss', '.sass'].includes(ext)) {
5863
5864
  sourceFiles.push(filePath);
5864
5865
  }
5865
5866
  }
@@ -5873,59 +5874,47 @@ class AccessibilityFixer {
5873
5874
  return sourceFiles;
5874
5875
  }
5875
5876
 
5876
- // Enhanced reference extraction
5877
+ // Enhanced reference extraction from HTML and CSS files
5877
5878
  extractAllReferences(content, baseDir, sourceFile) {
5878
- const references = new Set();
5879
-
5880
- // Get file extension to determine extraction method
5879
+ const references = [];
5881
5880
  const ext = path.extname(sourceFile).toLowerCase();
5882
5881
 
5883
5882
  if (['.html', '.htm'].includes(ext)) {
5884
- // HTML references
5885
- const htmlRefs = this.extractFileReferences(content, baseDir);
5886
- htmlRefs.forEach(ref => references.add(ref));
5883
+ // Extract from HTML files - main entry points
5884
+ const htmlRefs = this.extractHtmlReferences(content, baseDir);
5885
+ references.push(...htmlRefs);
5887
5886
 
5888
- } else if (ext === '.css') {
5889
- // CSS references
5887
+ } else if (['.css', '.scss', '.sass'].includes(ext)) {
5888
+ // Extract from CSS/SCSS files - background images
5890
5889
  const cssRefs = this.extractCssReferences(content, baseDir);
5891
- cssRefs.forEach(ref => references.add(ref));
5892
-
5893
- } else if (['.js', '.jsx', '.ts', '.tsx'].includes(ext)) {
5894
- // JavaScript/TypeScript references
5895
- const jsRefs = this.extractJsReferences(content, baseDir);
5896
- jsRefs.forEach(ref => references.add(ref));
5897
-
5898
- // Also extract import statements
5899
- const importRefs = this.extractImportReferences(content, baseDir);
5900
- importRefs.forEach(ref => references.add(ref));
5901
-
5902
- } else if (ext === '.json') {
5903
- // JSON references (like package.json, config files)
5904
- const jsonRefs = this.extractJsonReferences(content, baseDir);
5905
- jsonRefs.forEach(ref => references.add(ref));
5906
-
5907
- } else {
5908
- // Generic file references (for .md, .xml, etc.)
5909
- const genericRefs = this.extractGenericReferences(content, baseDir);
5910
- genericRefs.forEach(ref => references.add(ref));
5890
+ references.push(...cssRefs);
5911
5891
  }
5912
5892
 
5913
- return Array.from(references);
5893
+ return references;
5914
5894
  }
5915
5895
 
5916
- extractFileReferences(content, baseDir) {
5896
+ extractHtmlReferences(content, baseDir) {
5917
5897
  const references = [];
5918
5898
 
5919
5899
  // HTML patterns for file references
5920
5900
  const patterns = [
5921
5901
  // Images
5922
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,
5923
5912
  // Links (CSS, other files)
5924
5913
  /<link[^>]*href\s*=\s*["']([^"']+)["']/gi,
5925
5914
  // Scripts
5926
5915
  /<script[^>]*src\s*=\s*["']([^"']+)["']/gi,
5927
- // Anchors
5928
- /<a[^>]*href\s*=\s*["']([^"']+)["']/gi,
5916
+ // Anchors to other HTML files
5917
+ /<a[^>]*href\s*=\s*["']([^"'#]+\.html?)["']/gi,
5929
5918
  // Video/Audio
5930
5919
  /<(?:video|audio)[^>]*src\s*=\s*["']([^"']+)["']/gi,
5931
5920
  // Object/Embed
@@ -5940,10 +5929,18 @@ class AccessibilityFixer {
5940
5929
  let match;
5941
5930
  while ((match = pattern.exec(content)) !== null) {
5942
5931
  const url = match[1];
5943
- if (this.isLocalFile(url)) {
5944
- const resolvedPath = this.resolveFilePath(url, baseDir);
5945
- if (resolvedPath) {
5946
- references.push(resolvedPath);
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);
5947
5944
  }
5948
5945
  }
5949
5946
  }
@@ -5952,15 +5949,29 @@ class AccessibilityFixer {
5952
5949
  return references;
5953
5950
  }
5954
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
+
5955
5964
  extractCssReferences(content, baseDir) {
5956
5965
  const references = [];
5957
5966
 
5958
- // CSS patterns for file references
5967
+ // CSS patterns for file references
5959
5968
  const patterns = [
5960
- // url() function
5969
+ // url() function - background images, fonts, etc.
5961
5970
  /url\s*\(\s*["']?([^"')]+)["']?\s*\)/gi,
5962
- // @import
5963
- /@import\s+["']([^"']+)["']/gi
5971
+ // @import CSS files
5972
+ /@import\s+["']([^"']+)["']/gi,
5973
+ // CSS custom properties with URLs
5974
+ /--[^:]+:\s*url\s*\(\s*["']?([^"')]+)["']?\s*\)/gi
5964
5975
  ];
5965
5976
 
5966
5977
  for (const pattern of patterns) {
@@ -5968,10 +5979,7 @@ class AccessibilityFixer {
5968
5979
  while ((match = pattern.exec(content)) !== null) {
5969
5980
  const url = match[1];
5970
5981
  if (this.isLocalFile(url)) {
5971
- const resolvedPath = this.resolveFilePath(url, baseDir);
5972
- if (resolvedPath) {
5973
- references.push(resolvedPath);
5974
- }
5982
+ this.addNormalizedUrl(references, url);
5975
5983
  }
5976
5984
  }
5977
5985
  }
@@ -5999,9 +6007,13 @@ class AccessibilityFixer {
5999
6007
  while ((match = pattern.exec(content)) !== null) {
6000
6008
  const url = match[1];
6001
6009
  if (this.isLocalFile(url)) {
6002
- const resolvedPath = this.resolveFilePath(url, baseDir);
6003
- if (resolvedPath) {
6004
- references.push(resolvedPath);
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 ./
6005
6017
  }
6006
6018
  }
6007
6019
  }
@@ -6074,10 +6086,20 @@ class AccessibilityFixer {
6074
6086
  const dirName = path.basename(path.dirname(filePath));
6075
6087
  const relativePath = path.relative(process.cwd(), filePath);
6076
6088
 
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
+
6077
6099
  // Skip certain file types and patterns - but only in root directory
6078
6100
  const skipPatterns = [
6079
6101
  // Common files that might not be directly referenced - only in root
6080
- /^(index|main|app)\.(html|js|css)$/i,
6102
+ /^(main|app)\.(html|js|css)$/i,
6081
6103
  /^(readme|license|changelog)/i,
6082
6104
  /^package\.json$/i,
6083
6105
  /^\.gitignore$/i,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gbu-accessibility-package",
3
- "version": "3.8.6",
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": [