From 35c7d0bdc993971680dc5b6611850997b167f893 Mon Sep 17 00:00:00 2001 From: Ole-Morten Duesund Date: Mon, 18 Aug 2025 20:18:51 +0200 Subject: [PATCH] Fix manifest icon references and add file reference linter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- CLAUDE.md | 6 +- app/index.html | 6 +- app/manifest.json | 41 ++++++------- justfile | 10 ++- lint-references.py | 147 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 179 insertions(+), 31 deletions(-) create mode 100755 lint-references.py diff --git a/CLAUDE.md b/CLAUDE.md index 29eed55..b4029ed 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -68,6 +68,9 @@ bun run check # Check formatting without modifying # Python black server.py # Format Python code pylint server.py # Lint Python code + +# File References +just validate-references # Check HTML/manifest file references exist ``` ### Icon Generation @@ -164,10 +167,11 @@ node app/create-icons.js # Generate PNG icons - Print styles ### Code Quality -- ESLint: No errors, minimal warnings +- ESLint: No errors, no warnings - Prettier: All files formatted - Black: Python code formatted - Pylint: Score 10/10 +- File References: All HTML/manifest references exist ## Common Tasks diff --git a/app/index.html b/app/index.html index a32fd12..b4703c7 100644 --- a/app/index.html +++ b/app/index.html @@ -10,9 +10,9 @@ GlitchCraft - Artisanal Text Corruption - - - + + + diff --git a/app/manifest.json b/app/manifest.json index ab4102c..6e566fe 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -9,54 +9,47 @@ "orientation": "portrait-primary", "icons": [ { - "src": "icons/icon-72.png", + "src": "icons/icon-72.svg", "sizes": "72x72", - "type": "image/png" + "type": "image/svg+xml" }, { - "src": "icons/icon-96.png", + "src": "icons/icon-96.svg", "sizes": "96x96", - "type": "image/png" + "type": "image/svg+xml" }, { - "src": "icons/icon-128.png", + "src": "icons/icon-128.svg", "sizes": "128x128", - "type": "image/png" + "type": "image/svg+xml" }, { - "src": "icons/icon-144.png", + "src": "icons/icon-144.svg", "sizes": "144x144", - "type": "image/png" + "type": "image/svg+xml" }, { - "src": "icons/icon-152.png", + "src": "icons/icon-152.svg", "sizes": "152x152", - "type": "image/png" + "type": "image/svg+xml" }, { - "src": "icons/icon-192.png", + "src": "icons/icon-192.svg", "sizes": "192x192", - "type": "image/png", + "type": "image/svg+xml", "purpose": "any maskable" }, { - "src": "icons/icon-384.png", + "src": "icons/icon-384.svg", "sizes": "384x384", - "type": "image/png" + "type": "image/svg+xml" }, { - "src": "icons/icon-512.png", + "src": "icons/icon-512.svg", "sizes": "512x512", - "type": "image/png", + "type": "image/svg+xml", "purpose": "any maskable" } ], - "categories": ["utilities", "productivity"], - "screenshots": [ - { - "src": "screenshots/screenshot1.png", - "type": "image/png", - "sizes": "1280x720" - } - ] + "categories": ["utilities", "productivity"] } \ No newline at end of file diff --git a/justfile b/justfile index e463c0d..4f1acdd 100644 --- a/justfile +++ b/justfile @@ -55,8 +55,8 @@ lint-all: lint-js lint-python format-all: format-python format @echo "āœ“ All formatting completed" -# Check everything (linting + formatting) -check-all: lint-all check-format +# Check everything (linting + formatting + references) +check-all: lint-all check-format validate-references @echo "āœ“ All checks passed" # PWA icon generation @@ -97,8 +97,12 @@ validate-html: validate-manifest: python3 -m json.tool app/manifest.json > /dev/null && echo "āœ“ Manifest is valid JSON" +# Check file references (HTML, manifest) +validate-references: + python3 lint-references.py + # Run all validations -validate: validate-html validate-manifest check-all +validate: validate-html validate-manifest validate-references check-all @echo "āœ“ All validations passed" # Git helpers diff --git a/lint-references.py b/lint-references.py new file mode 100755 index 0000000..ff83722 --- /dev/null +++ b/lint-references.py @@ -0,0 +1,147 @@ +#!/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']+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']+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']+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()) \ No newline at end of file