diff --git a/Makefile b/Makefile
index 46b82626..f13ca6ce 100644
--- a/Makefile
+++ b/Makefile
@@ -83,6 +83,7 @@ help:
@echo " status - Show git status for repo and submodules"
@echo " clean - Clean build artifacts"
@echo " check-deps - Check dependency status"
+ @echo " validate-js - Validate JavaScript syntax in templates"
@echo ""
@echo "Documentation:"
@echo " update-digest - Update ProjectStatusDigest.md (requires Claude Code)"
@@ -1340,3 +1341,13 @@ cost-help:
@echo "š° Currency: Costs calculated in USD and EUR"
@echo "š¤ Model: Default claude-sonnet-4 pricing"
+# JavaScript validation for edit mode templates
+validate-js: $(VENV)/bin/activate
+ @echo "š Validating JavaScript syntax in templates..."
+ @if command -v node >/dev/null 2>&1; then \
+ $(PYTHON) tools/validate_js_syntax.py; \
+ else \
+ echo "ā ļø Node.js not available - skipping JavaScript validation"; \
+ echo " Install Node.js to enable JavaScript syntax checking"; \
+ fi
+
diff --git a/markitect/document_manager.py b/markitect/document_manager.py
index c847bdc5..40626078 100644
--- a/markitect/document_manager.py
+++ b/markitect/document_manager.py
@@ -659,18 +659,115 @@ class DocumentManager:
// Define editor class first (if in edit mode)
{editor_scripts if edit_mode else ''}
- // Error reporting utility
- function reportEditModeError(errorMsg, technicalDetails) {{
+ // Enhanced error reporting utility
+ function reportEditModeError(errorMsg, technicalDetails, errorType = 'error') {{
const statusDiv = document.getElementById('markitect-status');
const errorDiv = document.getElementById('error-details');
const errorText = document.getElementById('error-text');
const statusMsg = document.getElementById('status-message');
const browserInfo = document.getElementById('browser-info');
- if (statusMsg) statusMsg.textContent = 'Edit mode unavailable - content displayed in read-only mode';
+ // Log to console for debugging
+ console.error('[MarkiTect Edit Mode Error]', errorMsg, technicalDetails);
+
+ // Create error report object
+ const errorReport = {{
+ timestamp: new Date().toISOString(),
+ error: errorMsg,
+ details: technicalDetails,
+ type: errorType,
+ userAgent: navigator.userAgent,
+ url: window.location.href,
+ markdownContent: typeof markdownContent !== 'undefined' ? markdownContent.length + ' chars' : 'unavailable'
+ }};
+
+ // Store error for potential reporting
+ if (!window.markitectErrors) window.markitectErrors = [];
+ window.markitectErrors.push(errorReport);
+
+ // Update UI
+ if (statusMsg) {{
+ const statusText = errorType === 'warning'
+ ? 'Edit mode partially available - some features may not work'
+ : 'Edit mode unavailable - content displayed in read-only mode';
+ statusMsg.textContent = statusText;
+ }}
+
if (errorDiv) errorDiv.style.display = 'block';
- if (errorText) errorText.textContent = errorMsg + (technicalDetails ? ' (' + technicalDetails + ')' : '');
+ if (errorText) {{
+ const fullError = errorMsg + (technicalDetails ? ' (' + technicalDetails + ')' : '');
+ errorText.textContent = fullError;
+ }}
if (browserInfo) browserInfo.textContent = navigator.userAgent.split(' ').slice(-2).join(' ');
+
+ // Auto-hide warnings after 10 seconds
+ if (errorType === 'warning' && errorDiv) {{
+ setTimeout(() => {{
+ errorDiv.style.display = 'none';
+ }}, 10000);
+ }}
+ }}
+
+ // Enhanced error recovery utility
+ function attemptErrorRecovery(error, context) {{
+ console.warn('[MarkiTect] Attempting error recovery for:', context, error);
+
+ try {{
+ // Try to ensure content is still visible
+ const contentDiv = document.getElementById('markdown-content');
+ if (contentDiv && !contentDiv.innerHTML.trim()) {{
+ // Fallback content rendering
+ const fallbackHtml = markdownContent
+ .replace(/^# (.*$)/gim, '
$1
')
+ .replace(/^## (.*$)/gim, '$1
')
+ .replace(/\\n\\n/g, '
')
+ .replace(/\\n/g, '
');
+ contentDiv.innerHTML = '' + fallbackHtml + '
';
+
+ reportEditModeError('Recovered with fallback rendering', 'Edit features disabled', 'warning');
+ return true;
+ }}
+ }} catch (recoveryError) {{
+ console.error('[MarkiTect] Recovery failed:', recoveryError);
+ }}
+
+ return false;
+ }}
+
+ // Validation utility for edit mode state
+ function validateEditModeState() {{
+ const issues = [];
+
+ // Check required elements
+ if (!document.getElementById('markdown-content')) {{
+ issues.push('Missing markdown-content container');
+ }}
+
+ if (!document.getElementById('markitect-status')) {{
+ issues.push('Missing status display');
+ }}
+
+ // Check JavaScript dependencies
+ if (typeof marked === 'undefined') {{
+ issues.push('marked.js library not available');
+ }}
+
+ if (typeof MARKITECT_EDIT_MODE === 'undefined') {{
+ issues.push('Edit mode configuration missing');
+ }}
+
+ // Check for MarkitectEditor
+ if (typeof MarkitectEditor === 'undefined') {{
+ issues.push('MarkitectEditor class not defined');
+ }}
+
+ if (issues.length > 0) {{
+ console.warn('[MarkiTect] Edit mode validation issues:', issues);
+ reportEditModeError('Edit mode validation failed', issues.join(', '), 'warning');
+ return false;
+ }}
+
+ return true;
}}
// Status update utility
@@ -718,19 +815,44 @@ class DocumentManager:
}}
// Step 2: Try to enhance with edit capabilities (if in edit mode)
- {'''if (typeof MARKITECT_EDIT_MODE !== 'undefined' && MARKITECT_EDIT_MODE) {
+ {'''if (typeof MARKITECT_EDIT_MODE !== 'undefined' && MARKITECT_EDIT_MODE) {{
updateStatus("Initializing edit capabilities...");
- try {
+
+ // Validate edit mode prerequisites
+ if (!validateEditModeState()) {{
+ if (!attemptErrorRecovery('validation failed', 'edit mode prerequisites')) {{
+ return; // Stop here if recovery fails
+ }}
+ }}
+
+ try {{
updateStatus("Creating editor instance...");
markitectEditor = new MarkitectEditor();
updateStatus("ā Edit mode active - click any section to edit");
console.log("ā Edit mode initialized successfully");
- } catch (error) {
+
+ // Final validation check
+ setTimeout(() => {{
+ const sections = document.querySelectorAll('.markitect-section-editable');
+ if (sections.length === 0) {{
+ reportEditModeError('No editable sections found', 'Content may not be compatible with edit mode', 'warning');
+ }} else {{
+ console.log(`[MarkiTect] Found ${{sections.length}} editable sections`);
+ }}
+ }}, 1000);
+
+ }} catch (error) {{
updateStatus("Edit mode failed to initialize", true);
- reportEditModeError("Edit mode initialization failed", error.message);
console.error("Edit mode error:", error);
- }
- }''' if edit_mode else ''}
+
+ // Try error recovery
+ if (attemptErrorRecovery(error, 'editor initialization')) {{
+ reportEditModeError("Edit mode partially recovered", error.message, 'warning');
+ }} else {{
+ reportEditModeError("Edit mode initialization failed", error.message);
+ }}
+ }}
+ }}''' if edit_mode else ''}
}});
// Handle CDN loading errors
diff --git a/tests/test_issue_144_edit_mode_regression.py b/tests/test_issue_144_edit_mode_regression.py
new file mode 100644
index 00000000..d8757d9a
--- /dev/null
+++ b/tests/test_issue_144_edit_mode_regression.py
@@ -0,0 +1,348 @@
+"""
+Test suite for md-render --edit functionality to prevent regression.
+
+This test suite specifically targets the critical JavaScript syntax errors
+that were causing edit mode to fail completely, ensuring they never happen again.
+"""
+
+import tempfile
+import pytest
+from pathlib import Path
+import re
+import subprocess
+
+
+class TestEditModeRegression:
+ """Tests to prevent regression of the md-render --edit functionality."""
+
+ def test_edit_mode_generates_valid_javascript(self):
+ """Test that edit mode generates syntactically valid JavaScript."""
+ from markitect.document_manager import DocumentManager
+
+ doc_manager = DocumentManager()
+
+ # Test markdown content
+ test_content = "# Test Header\n\nThis is a test paragraph.\n\n## Section 2\n\nAnother paragraph."
+
+ # Generate HTML with edit mode
+ html_content = doc_manager._generate_html_template(
+ title="Test Document",
+ markdown_content=test_content,
+ edit_mode=True,
+ editor_theme='github',
+ keyboard_shortcuts=True
+ )
+
+ # Extract JavaScript from HTML
+ js_match = re.search(r'', html_content, re.DOTALL)
+ assert js_match, "No JavaScript found in edit mode HTML"
+
+ js_content = js_match.group(1)
+
+ # Write to temp file and validate syntax with Node.js
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.js', delete=False) as f:
+ f.write(js_content)
+ temp_js_path = f.name
+
+ try:
+ # Use Node.js to check JavaScript syntax
+ result = subprocess.run(
+ ['node', '-c', temp_js_path],
+ capture_output=True,
+ text=True
+ )
+
+ assert result.returncode == 0, f"JavaScript syntax error: {result.stderr}"
+
+ finally:
+ Path(temp_js_path).unlink()
+
+ def test_edit_mode_contains_required_functions(self):
+ """Test that edit mode HTML contains all required JavaScript functions."""
+ from markitect.document_manager import DocumentManager
+
+ doc_manager = DocumentManager()
+
+ html_content = doc_manager._generate_html_template(
+ title="Test",
+ markdown_content="# Test",
+ edit_mode=True
+ )
+
+ # Check for critical functions that must be present
+ required_functions = [
+ 'MarkitectEditor',
+ 'updateStatus',
+ 'reportEditModeError',
+ 'makeContentEditable',
+ 'handleSectionClick',
+ 'editSection'
+ ]
+
+ for func_name in required_functions:
+ assert func_name in html_content, f"Required function '{func_name}' not found in edit mode HTML"
+
+ def test_edit_mode_no_broken_string_literals(self):
+ """Test that there are no broken string literals in the generated JavaScript."""
+ from markitect.document_manager import DocumentManager
+
+ doc_manager = DocumentManager()
+
+ html_content = doc_manager._generate_html_template(
+ title="Test",
+ markdown_content="# Test",
+ edit_mode=True
+ )
+
+ # Extract JavaScript
+ js_match = re.search(r'', html_content, re.DOTALL)
+ js_content = js_match.group(1)
+
+ # Check for broken string patterns that caused the original bug
+ broken_patterns = [
+ r"'\s*\n\s*'", # Broken string literal across lines
+ r'"\s*\n\s*"', # Broken string literal across lines
+ r'reconstructed \+= .*\'\n', # Unescaped newline in string
+ ]
+
+ for pattern in broken_patterns:
+ matches = re.findall(pattern, js_content)
+ assert not matches, f"Found broken string pattern: {pattern} - matches: {matches}"
+
+ def test_edit_mode_proper_brace_escaping(self):
+ """Test that braces are properly escaped in f-string templates."""
+ from markitect.document_manager import DocumentManager
+
+ doc_manager = DocumentManager()
+
+ html_content = doc_manager._generate_html_template(
+ title="Test",
+ markdown_content="# Test",
+ edit_mode=True
+ )
+
+ # Extract JavaScript
+ js_match = re.search(r'', html_content, re.DOTALL)
+ js_content = js_match.group(1)
+
+ # Check for inconsistent brace patterns
+ inconsistent_patterns = [
+ r'} else if.*{{', # Mixed single and double braces
+ r'}} else if.*{[^{]', # Mixed double and single braces
+ ]
+
+ for pattern in inconsistent_patterns:
+ matches = re.findall(pattern, js_content)
+ assert not matches, f"Found inconsistent brace pattern: {pattern}"
+
+ def test_edit_mode_template_literal_syntax(self):
+ """Test that template literals are properly escaped."""
+ from markitect.document_manager import DocumentManager
+
+ doc_manager = DocumentManager()
+
+ html_content = doc_manager._generate_html_template(
+ title="Test",
+ markdown_content="# Test",
+ edit_mode=True
+ )
+
+ # Extract JavaScript
+ js_match = re.search(r'', html_content, re.DOTALL)
+ js_content = js_match.group(1)
+
+ # Check for problematic template literal patterns
+ # Should NOT find double-escaped template literals like ${{
+ problematic_patterns = [
+ r'\$\{\{.*?\}\}', # Double-escaped template literals
+ ]
+
+ for pattern in problematic_patterns:
+ matches = re.findall(pattern, js_content)
+ assert not matches, f"Found problematic template literal: {pattern}"
+
+ def test_edit_mode_contains_content_div(self):
+ """Test that edit mode HTML contains the markdown-content div."""
+ from markitect.document_manager import DocumentManager
+
+ doc_manager = DocumentManager()
+
+ html_content = doc_manager._generate_html_template(
+ title="Test",
+ markdown_content="# Test Content",
+ edit_mode=True
+ )
+
+ # Should contain the content container
+ assert 'id="markdown-content"' in html_content
+ assert 'MARKITECT_EDIT_MODE = true' in html_content
+ assert 'markitect-edit-mode' in html_content
+
+ def test_edit_mode_error_handling_elements(self):
+ """Test that edit mode includes proper error handling UI elements."""
+ from markitect.document_manager import DocumentManager
+
+ doc_manager = DocumentManager()
+
+ html_content = doc_manager._generate_html_template(
+ title="Test",
+ markdown_content="# Test",
+ edit_mode=True
+ )
+
+ # Should contain error handling elements
+ assert 'id="markitect-status"' in html_content
+ assert 'id="status-message"' in html_content
+ assert 'id="error-details"' in html_content
+ assert 'reportEditModeError' in html_content
+
+ def test_edit_mode_vs_normal_mode_differences(self):
+ """Test that edit mode and normal mode generate different output appropriately."""
+ from markitect.document_manager import DocumentManager
+
+ doc_manager = DocumentManager()
+ test_content = "# Test Header\n\nTest content."
+
+ # Generate both modes
+ normal_html = doc_manager._generate_html_template(
+ title="Test",
+ markdown_content=test_content,
+ edit_mode=False
+ )
+
+ edit_html = doc_manager._generate_html_template(
+ title="Test",
+ markdown_content=test_content,
+ edit_mode=True
+ )
+
+ # Edit mode should have additional elements
+ assert len(edit_html) > len(normal_html)
+ assert 'MarkitectEditor' in edit_html
+ assert 'MarkitectEditor' not in normal_html
+ assert 'markitect-edit-mode' in edit_html
+ assert 'markitect-edit-mode' not in normal_html
+
+ def test_edit_mode_javascript_execution_flow(self):
+ """Test the logical flow of JavaScript execution in edit mode."""
+ from markitect.document_manager import DocumentManager
+
+ doc_manager = DocumentManager()
+
+ html_content = doc_manager._generate_html_template(
+ title="Test",
+ markdown_content="# Test",
+ edit_mode=True
+ )
+
+ # Extract JavaScript
+ js_match = re.search(r'', html_content, re.DOTALL)
+ js_content = js_match.group(1)
+
+ # Check for proper execution flow elements
+ flow_elements = [
+ 'DOMContentLoaded', # Event listener setup
+ 'MARKITECT_EDIT_MODE', # Mode check
+ 'new MarkitectEditor', # Editor instantiation
+ 'makeContentEditable', # Content enhancement
+ 'handleSectionClick' # Interaction handler
+ ]
+
+ for element in flow_elements:
+ assert element in js_content, f"Missing execution flow element: {element}"
+
+ def test_newline_escaping_in_javascript_strings(self):
+ """Test that newlines in JavaScript strings are properly escaped."""
+ from markitect.document_manager import DocumentManager
+
+ doc_manager = DocumentManager()
+
+ html_content = doc_manager._generate_html_template(
+ title="Test",
+ markdown_content="# Test\n\nMultiple\nLines",
+ edit_mode=True
+ )
+
+ # Extract JavaScript
+ js_match = re.search(r'', html_content, re.DOTALL)
+ js_content = js_match.group(1)
+
+ # Look for the specific section that was broken
+ # Should find properly escaped newlines like '\\n\\n'
+ assert '\\\\n\\\\n' in js_content, "Newlines not properly escaped in JavaScript strings"
+
+ # Should NOT find unescaped newlines in string contexts
+ # This regex looks for string concatenation with actual newlines
+ broken_newline_pattern = r"'\s*\+\s*text\s*\+\s*'\s*\n"
+ matches = re.findall(broken_newline_pattern, js_content)
+ assert not matches, f"Found unescaped newlines in string concatenation: {matches}"
+
+
+class TestEditModeIntegration:
+ """Integration tests for the complete edit mode functionality."""
+
+ def test_md_render_edit_command_execution(self):
+ """Test that the md-render --edit command executes without errors."""
+ import tempfile
+ from markitect.plugins.builtin.markdown_commands import md_render_command
+ from click.testing import CliRunner
+
+ runner = CliRunner()
+
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False) as md_file:
+ md_file.write("# Test Document\n\nThis is a test paragraph.\n\n## Section 2\n\nAnother paragraph.")
+ md_file_path = md_file.name
+
+ with tempfile.NamedTemporaryFile(suffix='.html', delete=False) as html_file:
+ html_file_path = html_file.name
+
+ try:
+ # Test the command
+ result = runner.invoke(md_render_command, [
+ md_file_path,
+ '--edit',
+ '--output', html_file_path
+ ])
+
+ assert result.exit_code == 0, f"Command failed: {result.output}"
+
+ # Verify the output file exists and contains edit mode elements
+ html_content = Path(html_file_path).read_text()
+ assert 'MarkitectEditor' in html_content
+ assert 'markitect-edit-mode' in html_content
+
+ # Verify JavaScript syntax
+ js_match = re.search(r'', html_content, re.DOTALL)
+ assert js_match, "No JavaScript found in output"
+
+ finally:
+ Path(md_file_path).unlink(missing_ok=True)
+ Path(html_file_path).unlink(missing_ok=True)
+
+ def test_save_functionality_javascript_presence(self):
+ """Test that the save functionality JavaScript is properly included."""
+ from markitect.document_manager import DocumentManager
+
+ doc_manager = DocumentManager()
+
+ html_content = doc_manager._generate_html_template(
+ title="Test",
+ markdown_content="# Test Content",
+ edit_mode=True
+ )
+
+ # Check for save-related functionality
+ save_elements = [
+ 'Save & Download', # Button text
+ 'markitectEditor.save()', # Save function call
+ 'getMarkdownContent', # Content extraction
+ 'Blob', # File creation
+ 'download' # Download attribute
+ ]
+
+ for element in save_elements:
+ assert element in html_content, f"Save functionality element missing: {element}"
+
+
+if __name__ == "__main__":
+ pytest.main([__file__, "-v"])
\ No newline at end of file
diff --git a/tools/validate_js_syntax.py b/tools/validate_js_syntax.py
new file mode 100755
index 00000000..dbb996e8
--- /dev/null
+++ b/tools/validate_js_syntax.py
@@ -0,0 +1,283 @@
+#!/usr/bin/env python3
+"""
+JavaScript syntax validation tool for MarkiTect build process.
+
+This tool validates that all generated JavaScript in edit mode is syntactically correct,
+preventing the regression that caused edit mode to fail completely.
+"""
+
+import subprocess
+import tempfile
+import sys
+import re
+from pathlib import Path
+from typing import List, Tuple, Optional
+
+
+class JavaScriptValidator:
+ """Validates JavaScript syntax in MarkiTect templates."""
+
+ def __init__(self):
+ self.errors = []
+ self.warnings = []
+
+ def validate_document_manager_templates(self) -> bool:
+ """Validate JavaScript templates in DocumentManager."""
+ try:
+ # Import the template generation method directly to avoid database dependency
+ from markitect.document_manager import DocumentManager
+
+ # Create a mock DocumentManager to access the template method
+ class MockDatabaseManager:
+ pass
+
+ doc_manager = DocumentManager.__new__(DocumentManager)
+ doc_manager.database_manager = MockDatabaseManager()
+
+ # Test various configurations
+ test_cases = [
+ {
+ 'title': 'Basic Edit Mode',
+ 'markdown': '# Test\n\nBasic content.',
+ 'edit_mode': True,
+ 'theme': 'github'
+ },
+ {
+ 'title': 'Complex Content',
+ 'markdown': '''# Header 1
+
+## Header 2
+
+Paragraph with **bold** and *italic* text.
+
+- List item 1
+- List item 2
+
+1. Numbered item
+2. Another item
+
+> Blockquote text
+
+```python
+code block
+```
+
+Final paragraph.''',
+ 'edit_mode': True,
+ 'theme': 'dark'
+ },
+ {
+ 'title': 'Special Characters',
+ 'markdown': "# Test 'quotes' and \"double quotes\"\n\nContent with $pecial ch@racters & symbols!",
+ 'edit_mode': True,
+ 'theme': 'github'
+ }
+ ]
+
+ all_valid = True
+
+ for test_case in test_cases:
+ print(f"Validating: {test_case['title']}")
+
+ html_content = doc_manager._generate_html_template(
+ title=test_case['title'],
+ markdown_content=test_case['markdown'],
+ edit_mode=test_case['edit_mode'],
+ editor_theme=test_case.get('theme', 'github')
+ )
+
+ is_valid, errors = self._validate_html_javascript(html_content, test_case['title'])
+
+ if not is_valid:
+ all_valid = False
+ self.errors.extend(errors)
+ else:
+ print(f" ā
{test_case['title']} - JavaScript syntax valid")
+
+ return all_valid
+
+ except Exception as e:
+ self.errors.append(f"Failed to validate document manager templates: {e}")
+ return False
+
+ def _validate_html_javascript(self, html_content: str, context: str) -> Tuple[bool, List[str]]:
+ """Extract and validate JavaScript from HTML content."""
+ errors = []
+
+ # Extract all JavaScript blocks
+ js_blocks = re.findall(r'', html_content, re.DOTALL)
+
+ if not js_blocks:
+ errors.append(f"{context}: No JavaScript blocks found")
+ return False, errors
+
+ for i, js_content in enumerate(js_blocks):
+ # Skip empty blocks or blocks with only external src
+ if not js_content.strip() or 'src=' in js_content:
+ continue
+
+ is_valid, js_errors = self._validate_javascript_syntax(js_content, f"{context} block {i+1}")
+ if not is_valid:
+ errors.extend(js_errors)
+
+ return len(errors) == 0, errors
+
+ def _validate_javascript_syntax(self, js_content: str, context: str) -> Tuple[bool, List[str]]:
+ """Validate JavaScript syntax using Node.js."""
+ errors = []
+
+ try:
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.js', delete=False) as f:
+ f.write(js_content)
+ temp_js_path = f.name
+
+ # Use Node.js to check syntax
+ result = subprocess.run(
+ ['node', '-c', temp_js_path],
+ capture_output=True,
+ text=True,
+ timeout=10
+ )
+
+ if result.returncode != 0:
+ errors.append(f"{context}: JavaScript syntax error - {result.stderr.strip()}")
+
+ # Add helpful debugging info
+ lines = js_content.split('\n')
+ for line_num, line in enumerate(lines[:20], 1): # Show first 20 lines
+ if line.strip():
+ print(f" Line {line_num}: {line[:100]}") # First 100 chars
+
+ Path(temp_js_path).unlink(missing_ok=True)
+
+ except subprocess.TimeoutExpired:
+ errors.append(f"{context}: JavaScript validation timeout")
+ except FileNotFoundError:
+ errors.append(f"{context}: Node.js not available for validation")
+ except Exception as e:
+ errors.append(f"{context}: Validation error - {e}")
+
+ return len(errors) == 0, errors
+
+ def check_common_issues(self) -> bool:
+ """Check for common JavaScript issues that have caused problems."""
+ try:
+ from markitect.document_manager import DocumentManager
+
+ # Create a mock DocumentManager to access the template method
+ class MockDatabaseManager:
+ pass
+
+ doc_manager = DocumentManager.__new__(DocumentManager)
+ doc_manager.database_manager = MockDatabaseManager()
+
+ html_content = doc_manager._generate_html_template(
+ title="Issue Check",
+ markdown_content="# Test\n\nTest content.",
+ edit_mode=True
+ )
+
+ js_match = re.search(r'', html_content, re.DOTALL)
+ if not js_match:
+ self.errors.append("No JavaScript found for common issues check")
+ return False
+
+ js_content = js_match.group(1)
+ issues_found = False
+
+ # Check for specific issues that have caused problems
+ issue_patterns = [
+ (r"'\s*\n\s*'", "Broken string literal across lines"),
+ (r'"\s*\n\s*"', "Broken string literal across lines"),
+ (r'} else if.*{{.*}} else if.*{[^{]', "Inconsistent brace escaping"),
+ (r'\$\{\{.*?\}\}', "Double-escaped template literals"),
+ (r'reconstructed \+= .*\'\n', "Unescaped newline in string concatenation"),
+ ]
+
+ for pattern, description in issue_patterns:
+ matches = re.findall(pattern, js_content)
+ if matches:
+ self.errors.append(f"Found {description}: {matches[:3]}...") # Show first 3 matches
+ issues_found = True
+
+ # Check for required elements
+ required_elements = [
+ 'MarkitectEditor',
+ 'updateStatus',
+ 'makeContentEditable',
+ 'DOMContentLoaded'
+ ]
+
+ for element in required_elements:
+ if element not in js_content:
+ self.errors.append(f"Missing required element: {element}")
+ issues_found = True
+
+ return not issues_found
+
+ except Exception as e:
+ self.errors.append(f"Failed to check common issues: {e}")
+ return False
+
+ def validate_all(self) -> bool:
+ """Run all validation checks."""
+ print("š Validating JavaScript syntax in MarkiTect templates...")
+
+ all_checks_passed = True
+
+ # Run all validation checks
+ checks = [
+ ("Document Manager Templates", self.validate_document_manager_templates),
+ ("Common Issues", self.check_common_issues),
+ ]
+
+ for check_name, check_func in checks:
+ print(f"\nš Running {check_name} check...")
+ try:
+ if not check_func():
+ all_checks_passed = False
+ print(f" ā {check_name} check failed")
+ else:
+ print(f" ā
{check_name} check passed")
+ except Exception as e:
+ all_checks_passed = False
+ self.errors.append(f"{check_name} check failed with exception: {e}")
+ print(f" ā {check_name} check failed with exception")
+
+ return all_checks_passed
+
+ def report_results(self) -> None:
+ """Print validation results."""
+ print("\n" + "="*60)
+ print("JavaScript Validation Results")
+ print("="*60)
+
+ if self.errors:
+ print(f"\nā {len(self.errors)} Error(s) Found:")
+ for i, error in enumerate(self.errors, 1):
+ print(f" {i}. {error}")
+
+ if self.warnings:
+ print(f"\nā ļø {len(self.warnings)} Warning(s):")
+ for i, warning in enumerate(self.warnings, 1):
+ print(f" {i}. {warning}")
+
+ if not self.errors and not self.warnings:
+ print("\nā
All JavaScript validation checks passed!")
+
+ print("\n" + "="*60)
+
+
+def main():
+ """Main validation function."""
+ validator = JavaScriptValidator()
+
+ success = validator.validate_all()
+ validator.report_results()
+
+ return 0 if success else 1
+
+
+if __name__ == "__main__":
+ exit_code = main()
+ sys.exit(exit_code)
\ No newline at end of file