Manifest fixes: - Updated all icon references from .png to .svg files - Changed MIME types from image/png to image/svg+xml - Removed missing screenshots section - Fixed HTML favicon references to use SVG files New reference linter (lint-references.py): - Validates all file references in HTML and manifest files - Checks that referenced files actually exist - Prevents broken links and missing assets - Integrated into justfile as 'validate-references' - Added to check-all command for comprehensive validation Justfile enhancements: - Added validate-references command - Updated check-all to include reference validation - Enhanced validate command with reference checking Documentation updates: - Updated CLAUDE.md with reference validation info - Added file reference checking to code quality standards This prevents issues where manifest/HTML reference non-existent files, improving PWA reliability and catching asset mismatches early. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
147 lines
No EOL
4.1 KiB
Python
Executable file
147 lines
No EOL
4.1 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""
|
|
Reference validator for GlitchCraft
|
|
Checks that all file references in HTML and manifest actually exist
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def check_file_exists(file_path, base_dir):
|
|
"""Check if a file exists relative to base directory."""
|
|
full_path = base_dir / file_path
|
|
return full_path.exists()
|
|
|
|
|
|
def extract_html_references(html_content):
|
|
"""Extract file references from HTML content."""
|
|
references = []
|
|
|
|
# Link href attributes
|
|
for match in re.finditer(r'<link[^>]+href=["\']([^"\']+)["\']', html_content):
|
|
href = match.group(1)
|
|
if not href.startswith(('http://', 'https://', '//', 'data:', '#')):
|
|
references.append(href)
|
|
|
|
# Script src attributes
|
|
for match in re.finditer(r'<script[^>]+src=["\']([^"\']+)["\']', html_content):
|
|
src = match.group(1)
|
|
if not src.startswith(('http://', 'https://', '//', 'data:')):
|
|
references.append(src)
|
|
|
|
# Image src attributes
|
|
for match in re.finditer(r'<img[^>]+src=["\']([^"\']+)["\']', html_content):
|
|
src = match.group(1)
|
|
if not src.startswith(('http://', 'https://', '//', 'data:')):
|
|
references.append(src)
|
|
|
|
return references
|
|
|
|
|
|
def extract_manifest_references(manifest_data):
|
|
"""Extract file references from manifest JSON."""
|
|
references = []
|
|
|
|
# Icon sources
|
|
if 'icons' in manifest_data:
|
|
for icon in manifest_data['icons']:
|
|
if 'src' in icon:
|
|
references.append(icon['src'])
|
|
|
|
# Screenshot sources
|
|
if 'screenshots' in manifest_data:
|
|
for screenshot in manifest_data['screenshots']:
|
|
if 'src' in screenshot:
|
|
references.append(screenshot['src'])
|
|
|
|
return references
|
|
|
|
|
|
def check_html_file(file_path, base_dir):
|
|
"""Check all references in an HTML file."""
|
|
errors = []
|
|
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
|
|
references = extract_html_references(content)
|
|
|
|
for ref in references:
|
|
if not check_file_exists(ref, base_dir):
|
|
errors.append(f"Missing file: {ref}")
|
|
|
|
except Exception as e:
|
|
errors.append(f"Error reading {file_path}: {e}")
|
|
|
|
return errors
|
|
|
|
|
|
def check_manifest_file(file_path, base_dir):
|
|
"""Check all references in a manifest file."""
|
|
errors = []
|
|
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
manifest_data = json.load(f)
|
|
|
|
references = extract_manifest_references(manifest_data)
|
|
|
|
for ref in references:
|
|
if not check_file_exists(ref, base_dir):
|
|
errors.append(f"Missing file: {ref}")
|
|
|
|
except Exception as e:
|
|
errors.append(f"Error reading {file_path}: {e}")
|
|
|
|
return errors
|
|
|
|
|
|
def main():
|
|
"""Main function to check all references."""
|
|
script_dir = Path(__file__).parent
|
|
app_dir = script_dir / 'app'
|
|
|
|
print("🔍 Checking file references...")
|
|
|
|
total_errors = 0
|
|
|
|
# Check HTML files
|
|
html_files = list(app_dir.glob('*.html'))
|
|
for html_file in html_files:
|
|
errors = check_html_file(html_file, app_dir)
|
|
if errors:
|
|
print(f"\n❌ {html_file.name}:")
|
|
for error in errors:
|
|
print(f" • {error}")
|
|
total_errors += 1
|
|
else:
|
|
print(f"✅ {html_file.name}")
|
|
|
|
# Check manifest file
|
|
manifest_file = app_dir / 'manifest.json'
|
|
if manifest_file.exists():
|
|
errors = check_manifest_file(manifest_file, app_dir)
|
|
if errors:
|
|
print(f"\n❌ manifest.json:")
|
|
for error in errors:
|
|
print(f" • {error}")
|
|
total_errors += 1
|
|
else:
|
|
print("✅ manifest.json")
|
|
|
|
# Summary
|
|
if total_errors == 0:
|
|
print(f"\n🎉 All file references are valid!")
|
|
return 0
|
|
else:
|
|
print(f"\n💥 Found {total_errors} reference error(s)")
|
|
return 1
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main()) |