#!/usr/bin/env python3 """ JavaScript Validation Tool Extracts JavaScript from HTML files and validates syntax. Detects common issues like "Uncaught SyntaxError: unexpected token" """ import re import subprocess import sys import tempfile from pathlib import Path def extract_javascript_from_html(html_file): """Extract all JavaScript code from an HTML file.""" try: content = Path(html_file).read_text(encoding='utf-8') except Exception as e: print(f"❌ Failed to read {html_file}: {e}") return [] # Find all ' scripts = re.findall(script_pattern, content, re.DOTALL | re.IGNORECASE) # Filter out empty scripts and external script tags js_blocks = [] for script in scripts: script = script.strip() if script and not script.startswith('http'): # Skip external scripts js_blocks.append(script) return js_blocks def validate_javascript_syntax(js_code): """Validate JavaScript syntax using Node.js.""" try: # Create temporary JS file with tempfile.NamedTemporaryFile(mode='w', suffix='.js', delete=False) as f: f.write(js_code) temp_file = f.name # Try to parse with node --check result = subprocess.run( ['node', '--check', temp_file], capture_output=True, text=True ) # Clean up Path(temp_file).unlink() if result.returncode == 0: return True, "✓ Syntax OK" else: return False, f"❌ Syntax Error: {result.stderr.strip()}" except FileNotFoundError: # Fallback: Try to detect obvious syntax errors return validate_javascript_basic(js_code) except Exception as e: return False, f"❌ Validation failed: {e}" def validate_javascript_basic(js_code): """Basic JavaScript syntax validation without Node.js.""" errors = [] # Check for common syntax issues if js_code.count('{') != js_code.count('}'): errors.append("Mismatched curly braces") if js_code.count('(') != js_code.count(')'): errors.append("Mismatched parentheses") if js_code.count('[') != js_code.count(']'): errors.append("Mismatched square brackets") # Check for unescaped quotes in strings if re.search(r'["\']\s*["\']\s*["\']\s*["\']', js_code): errors.append("Possible quote escaping issue") # Check for Python-style string formatting leftover if '${' in js_code and '"}' in js_code: errors.append("Possible Python string template leftover") if errors: return False, f"❌ Potential issues: {', '.join(errors)}" else: return True, "✓ Basic validation passed (Node.js not available)" def validate_html_js(html_file): """Validate all JavaScript in an HTML file.""" print(f"🔍 Validating JavaScript in: {html_file}") js_blocks = extract_javascript_from_html(html_file) if not js_blocks: print("⚠️ No JavaScript found in HTML file") return True print(f"📝 Found {len(js_blocks)} JavaScript blocks") all_valid = True for i, js_block in enumerate(js_blocks, 1): print(f"\n--- Script Block {i} ({len(js_block)} chars) ---") # Show first few lines for context lines = js_block.split('\n')[:3] preview = '\n'.join(lines) if len(lines) < len(js_block.split('\n')): preview += "\n..." print(f"Preview:\n{preview}") is_valid, message = validate_javascript_syntax(js_block) print(message) if not is_valid: all_valid = False # Show more context around potential error if 'line' in message.lower(): try: line_num = re.search(r'line (\d+)', message, re.IGNORECASE) if line_num: line_no = int(line_num.group(1)) lines = js_block.split('\n') start = max(0, line_no - 3) end = min(len(lines), line_no + 2) print("\nContext around error:") for j in range(start, end): marker = ">>> " if j == line_no - 1 else " " print(f"{marker}{j+1:3}: {lines[j]}") except: pass print(f"\n{'✅' if all_valid else '❌'} Overall result: {'All JavaScript is valid' if all_valid else 'JavaScript validation failed'}") return all_valid def main(): if len(sys.argv) != 2: print("Usage: python validate_js.py ") print("Example: python validate_js.py /tmp/test-edit.html") sys.exit(1) html_file = sys.argv[1] if not Path(html_file).exists(): print(f"❌ File not found: {html_file}") sys.exit(1) success = validate_html_js(html_file) sys.exit(0 if success else 1) if __name__ == "__main__": main()