""" REACT FRONTEND HANDLER - FIXED JSON VERSION ===================== Expert-level React code generation with context preservation """ import json import re import asyncio from datetime import datetime from typing import Dict, Any, List, Optional from src.handlers.base_handler import TechnologyHandler, HandlerResult, ContextChunk import logging logger = logging.getLogger(__name__) class ReactHandler(TechnologyHandler): """Expert React frontend code generator""" def __init__(self, contract_registry, event_bus, claude_client=None): super().__init__(contract_registry, event_bus, claude_client) self.handler_type = "react_frontend" # React-specific configuration self.react_patterns = { "authentication": { "components": ["LoginForm", "AuthProvider", "ProtectedRoute"], "hooks": ["useAuth", "useAuthContext"], "services": ["authService", "tokenManager"] }, "user_management": { "components": ["UserList", "UserForm", "UserProfile"], "hooks": ["useUsers", "useUserForm"], "services": ["userService"] }, "real_time_chat": { "components": ["ChatRoom", "MessageList", "MessageInput"], "hooks": ["useSocket", "useMessages"], "services": ["socketService", "messageService"] } } # Quality validation patterns self.quality_patterns = { "error_handling": r"try\s*{|catch\s*\(|\.catch\(|error\s*&&", "loading_states": r"loading|isLoading|pending", "typescript_types": r"interface\s+\w+|type\s+\w+\s*=", "proper_hooks": r"useEffect|useState|useCallback|useMemo", "accessibility": r"aria-|role=|alt=", "security": r"sanitize|escape|validate" } async def _generate_with_chunked_context(self, features: List[str], context_chunks: List[ContextChunk], correlation_id: str) -> HandlerResult: """Generate React code using chunked context""" if not self.claude_client: raise Exception("Claude client not initialized") # Build expert React prompt prompt = self._build_expert_prompt(features, context_chunks) try: # Make Claude API call with retry logic response = await self._claude_request_with_retry(prompt, max_tokens=8000) response_text = response.content[0].text # Parse response into structured code parsed_code = self._parse_react_response(response_text) # Validate code quality quality_report = await self._validate_code_quality(parsed_code) # Extract contracts from generated code contracts = self._extract_react_contracts(parsed_code, features) return HandlerResult( success=True, handler_type=self.handler_type, features_implemented=features, code_files=parsed_code, contracts=contracts, quality_score=quality_report["overall_score"], tokens_used=response.usage.input_tokens + response.usage.output_tokens if hasattr(response, 'usage') else 0 ) except Exception as e: logger.error(f"❌ React generation failed: {e}") raise e def _build_expert_prompt(self, features: List[str], context_chunks: List[ContextChunk]) -> str: """Build expert-level React prompt with context""" # Combine context chunks context_content = "\n\n".join([ f"=== {chunk.chunk_type.upper()} ===\n{chunk.content}" for chunk in context_chunks ]) # Get existing contracts existing_contracts = "" for feature in features: contract = self.contracts.get_feature_contract(feature) if contract: endpoints = "\n".join([f" {ep.method} {ep.path}" for ep in contract.endpoints]) existing_contracts += f"\n{feature} API:\n{endpoints}\n" features_text = "\n".join([f"- {feature.replace('_', ' ').title()}" for feature in features]) prompt = f"""You are an EXPERT React developer with 10+ years of enterprise experience. Generate PRODUCTION-READY React components with PERFECT code quality. {context_content} EXISTING API CONTRACTS TO INTEGRATE: {existing_contracts} FEATURES TO IMPLEMENT: {features_text} REACT REQUIREMENTS: 1. **TypeScript**: Use proper interfaces and types 2. **Modern Hooks**: useState, useEffect, useCallback, useMemo appropriately 3. **Error Handling**: Try/catch blocks, error boundaries, loading states 4. **Accessibility**: ARIA labels, semantic HTML, keyboard navigation 5. **Performance**: React.memo, useMemo for expensive calculations 6. **Security**: Input validation, XSS prevention, sanitization 7. **State Management**: Redux Toolkit with RTK Query for API calls 8. **Styling**: Styled-components or CSS modules 9. **Testing**: Component structure ready for Jest/RTL ARCHITECTURE PATTERNS: - Feature-based folder structure - Custom hooks for business logic - Service layer for API calls - Context providers for global state - Higher-order components for reusability CRITICAL JSON RESPONSE REQUIREMENTS: - Your response MUST be ONLY valid JSON. No explanations, no markdown, no code blocks. - Start with {{ and end with }}. Nothing else. - Do NOT use ```json or ``` anywhere in your response. - Each file path maps to complete working code as a string. - Use \\n for line breaks in code strings. RESPONSE FORMAT - ONLY THIS JSON STRUCTURE: {{"src/components/LoginForm.tsx": "import React, {{ useState }} from 'react';\\n\\nconst LoginForm = () => {{\\n const [email, setEmail] = useState('');\\n const [password, setPassword] = useState('');\\n // COMPLETE WORKING CODE HERE\\n}};\\n\\nexport default LoginForm;", "src/components/SignupForm.tsx": "import React, {{ useState }} from 'react';\\n\\nconst SignupForm = () => {{\\n const [formData, setFormData] = useState({{}});\\n // COMPLETE WORKING CODE HERE\\n}};\\n\\nexport default SignupForm;"}} EXAMPLE CORRECT RESPONSE: {{"file1.tsx": "const code = 'here';", "file2.ts": "export const api = 'code';"}} EXAMPLE WRONG RESPONSE (DO NOT DO THIS): ```json {{"file": "code"}} ``` CRITICAL REQUIREMENTS: - COMPLETE, WORKING components (no placeholders) - Proper TypeScript interfaces - Comprehensive error handling - Loading and error states - Responsive design patterns - Accessibility compliance - Security best practices - Integration with existing API contracts Generate ONLY the JSON object. No other text. Implement ALL features with complete functionality.""" return prompt def _parse_react_response(self, response: str) -> Dict[str, str]: """Parse Claude's React response into structured code files""" try: # Try direct JSON parsing first response_clean = response.strip() # Find JSON boundaries start_idx = response_clean.find('{') end_idx = response_clean.rfind('}') + 1 if start_idx != -1 and end_idx > start_idx: json_content = response_clean[start_idx:end_idx] parsed = json.loads(json_content) # Validate structure if isinstance(parsed, dict) and all( isinstance(k, str) and isinstance(v, str) for k, v in parsed.items() ): return parsed # Fallback: Extract code blocks return self._extract_code_blocks_fallback(response) except json.JSONDecodeError as e: logger.warning(f"JSON parsing failed: {e}, using fallback extraction") return self._extract_code_blocks_fallback(response) def _extract_code_blocks_fallback(self, response: str) -> Dict[str, str]: """Fallback method to extract React code blocks""" code_files = {} # Pattern to match file paths and code blocks file_pattern = r'(?:```(?:typescript|tsx|ts|javascript|jsx)?\s*)?(?://\s*)?([^\n]*\.(?:tsx?|jsx?|ts))\s*\n(.*?)(?=\n\s*(?://|```|\w+/)|$)' matches = re.findall(file_pattern, response, re.DOTALL) for file_path, code_content in matches: file_path = file_path.strip().strip('"\'') code_content = code_content.strip() # Clean up code content if code_content.startswith('```'): code_content = '\n'.join(code_content.split('\n')[1:]) if code_content.endswith('```'): code_content = '\n'.join(code_content.split('\n')[:-1]) if file_path and code_content and len(code_content) > 50: code_files[file_path] = code_content # If still no files found, create basic structure if not code_files: logger.warning("No code files extracted, creating basic structure") code_files = { "src/components/App.tsx": self._generate_basic_app_component(), "src/index.tsx": self._generate_basic_index_file() } return code_files async def _validate_code_quality(self, code_files: Dict[str, str]) -> Dict[str, Any]: """Validate React code quality with detailed scoring""" total_score = 0 file_scores = {} issues = [] for file_path, content in code_files.items(): file_score = self._validate_single_file_quality(file_path, content) file_scores[file_path] = file_score total_score += file_score["score"] issues.extend(file_score["issues"]) overall_score = total_score / len(code_files) if code_files else 0 return { "overall_score": overall_score, "file_scores": file_scores, "issues": issues, "metrics": { "total_files": len(code_files), "average_score": overall_score, "files_above_8": sum(1 for score in file_scores.values() if score["score"] >= 8.0), "critical_issues": len([i for i in issues if i.startswith("CRITICAL")]) } } def _validate_single_file_quality(self, file_path: str, content: str) -> Dict[str, Any]: """Validate quality of a single React file""" score = 10.0 issues = [] # Check for TypeScript usage if file_path.endswith('.tsx') or file_path.endswith('.ts'): if not re.search(self.quality_patterns["typescript_types"], content): score -= 1.0 issues.append(f"Missing TypeScript types in {file_path}") # Check for proper hooks usage if 'component' in file_path.lower() or 'hook' in file_path.lower(): if not re.search(self.quality_patterns["proper_hooks"], content): score -= 1.0 issues.append(f"Missing proper hooks usage in {file_path}") # Check for error handling if not re.search(self.quality_patterns["error_handling"], content): score -= 1.5 issues.append(f"CRITICAL: No error handling in {file_path}") # Check for loading states if 'component' in file_path.lower(): if not re.search(self.quality_patterns["loading_states"], content): score -= 1.0 issues.append(f"Missing loading states in {file_path}") # Check for accessibility if 'component' in file_path.lower(): if not re.search(self.quality_patterns["accessibility"], content): score -= 0.5 issues.append(f"Missing accessibility features in {file_path}") # Check for security patterns if 'form' in file_path.lower() or 'input' in file_path.lower(): if not re.search(self.quality_patterns["security"], content): score -= 1.0 issues.append(f"Missing security validation in {file_path}") # Check for basic structure if len(content.strip()) < 100: score -= 3.0 issues.append(f"CRITICAL: File too short/incomplete {file_path}") # Check for syntax issues (basic) if content.count('{') != content.count('}'): score -= 2.0 issues.append(f"CRITICAL: Bracket mismatch in {file_path}") return { "score": max(0, score), "issues": issues, "file_path": file_path } def _extract_react_contracts(self, code_files: Dict[str, str], features: List[str]) -> Dict[str, Any]: """Extract API contracts from React code""" contracts = { "api_calls": [], "components_created": [], "hooks_created": [], "services_created": [] } for file_path, content in code_files.items(): # Extract API calls api_pattern = r'(?:fetch|axios|api)\s*\.\s*(?:get|post|put|delete)\s*\(\s*[\'"`]([^\'"`]+)[\'"`]' api_matches = re.findall(api_pattern, content, re.IGNORECASE) for endpoint in api_matches: contracts["api_calls"].append({ "endpoint": endpoint, "file": file_path, "method": "unknown" # Could be enhanced to detect method }) # Extract component exports if file_path.endswith('.tsx'): component_pattern = r'export\s+(?:default\s+)?(?:const|function)\s+(\w+)' component_matches = re.findall(component_pattern, content) for component in component_matches: contracts["components_created"].append({ "name": component, "file": file_path, "features": features }) # Extract custom hooks if 'hook' in file_path.lower() or re.search(r'export\s+(?:const|function)\s+use\w+', content): hook_pattern = r'export\s+(?:const|function)\s+(use\w+)' hook_matches = re.findall(hook_pattern, content) for hook in hook_matches: contracts["hooks_created"].append({ "name": hook, "file": file_path, "features": features }) return contracts async def _build_improvement_prompt(self, current_result: HandlerResult, quality_target: float) -> str: """Build improvement prompt for React code refinement""" issues_text = "\n".join([ f"- {issue}" for issue in current_result.contracts.get("quality_issues", []) ]) return f"""IMPROVE this React code to achieve {quality_target}/10 quality. CURRENT QUALITY: {current_result.quality_score}/10 TARGET QUALITY: {quality_target}/10 IDENTIFIED ISSUES: {issues_text} CURRENT CODE FILES: {json.dumps(current_result.code_files, indent=2)} IMPROVEMENT REQUIREMENTS: 1. Fix all critical issues (error handling, security, accessibility) 2. Enhance TypeScript types and interfaces 3. Improve component structure and reusability 4. Add comprehensive error boundaries 5. Implement proper loading states 6. Ensure accessibility compliance 7. Add input validation and sanitization 8. Optimize performance with React.memo, useMemo 9. Follow React best practices and patterns 10. Ensure all components are production-ready CRITICAL: Return ONLY valid JSON. No explanations, no markdown, no code blocks. Return ONLY the improved code in this JSON format: {{ "file_path": "improved_complete_code" }} Make every improvement necessary to reach the quality target.""" async def _apply_improvements(self, current_result: HandlerResult, improvement_prompt: str) -> HandlerResult: """Apply improvements to React code""" try: response = await self._claude_request_with_retry(improvement_prompt, max_tokens=8000) response_text = response.content[0].text # Parse improved code improved_code = self._parse_react_response(response_text) # Merge with existing code (keep files that weren't improved) final_code = current_result.code_files.copy() final_code.update(improved_code) # Re-validate quality quality_report = await self._validate_code_quality(final_code) # Update result improved_result = HandlerResult( success=True, handler_type=self.handler_type, features_implemented=current_result.features_implemented, code_files=final_code, contracts=self._extract_react_contracts(final_code, current_result.features_implemented), quality_score=quality_report["overall_score"], tokens_used=current_result.tokens_used + ( response.usage.input_tokens + response.usage.output_tokens if hasattr(response, 'usage') else 0 ), refinement_cycles=current_result.refinement_cycles ) return improved_result except Exception as e: logger.error(f"❌ React improvement failed: {e}") return current_result # Return original if improvement fails async def _claude_request_with_retry(self, prompt: str, max_tokens: int = 4000, max_retries: int = 3): """Make Claude API request with retry logic""" for attempt in range(max_retries): try: await asyncio.sleep(2 * attempt) # Progressive delay message = self.claude_client.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=max_tokens, temperature=0.1, messages=[{"role": "user", "content": prompt}] ) return message except Exception as e: if "overloaded" in str(e) or "rate_limit" in str(e): wait_time = 5 * (2 ** attempt) logger.warning(f"⚠️ API overloaded, waiting {wait_time}s (attempt {attempt+1})") await asyncio.sleep(wait_time) else: logger.error(f"❌ Claude API error: {e}") if attempt == max_retries - 1: raise e raise Exception("Max retries exceeded for Claude API") def _generate_basic_app_component(self) -> str: """Generate basic App component as fallback""" return '''import React from 'react'; import './App.css'; const App: React.FC = () => { return (
Your application components will be implemented here.