name: CI on: pull_request: branches: - main jobs: validate: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Validate HTML run: | # Check index.html exists and is valid-ish test -f index.html || { echo "ERROR: index.html missing"; exit 1; } # Check for unclosed tags (basic) python3 -c " import html.parser, sys class V(html.parser.HTMLParser): def __init__(self): super().__init__() self.errors = [] def handle_starttag(self, tag, attrs): pass def handle_endtag(self, tag): pass v = V() try: v.feed(open('index.html').read()) print('HTML: OK') except Exception as e: print(f'HTML: FAIL - {e}') sys.exit(1) " - name: Validate JavaScript run: | # Syntax check all JS files FAIL=0 for f in $(find . -name '*.js' -not -path './node_modules/*' -not -name 'sw.js'); do if ! node --check "$f" 2>/dev/null; then echo "FAIL: $f" FAIL=1 else echo "OK: $f" fi done exit $FAIL - name: Validate JSON run: | # Check all JSON files parse FAIL=0 for f in $(find . -name '*.json' -not -path './node_modules/*'); do if ! python3 -c "import json; json.load(open('$f'))"; then echo "FAIL: $f" FAIL=1 else echo "OK: $f" fi done exit $FAIL - name: Check file size budget run: | # Performance budget: no single JS file > 500KB FAIL=0 for f in $(find . -name '*.js' -not -path './node_modules/*'); do SIZE=$(wc -c < "$f") if [ "$SIZE" -gt 512000 ]; then echo "FAIL: $f is ${SIZE} bytes (budget: 512000)" FAIL=1 else echo "OK: $f (${SIZE} bytes)" fi done exit $FAIL