- Add DocumentNavigator UI element for document navigation across viewing and editing modes - Implement lazy loading approach where control appears immediately but navigation content builds on-demand - Position controls on left side following UI convention for consistent navigation experience - Add scroll spy functionality for current section detection - Include responsive design with mobile auto-hide - Create comprehensive development guardrails to prevent JavaScript corruption - Add JavaScript validation tool for syntax error detection 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
161 lines
4.9 KiB
Python
Executable File
161 lines
4.9 KiB
Python
Executable File
#!/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 <script> blocks
|
|
script_pattern = r'<script[^>]*>(.*?)</script>'
|
|
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 <html_file>")
|
|
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() |