738 lines
32 KiB
Python
738 lines
32 KiB
Python
# ANGULAR 18 FRONTEND DESIGNER SPECIALIST
|
|
# Expert-level Angular 18 architecture design with TypeScript, standalone components, and modern patterns
|
|
|
|
import json
|
|
from typing import Dict, Any, List
|
|
from loguru import logger
|
|
|
|
try:
|
|
import anthropic
|
|
CLAUDE_AVAILABLE = True
|
|
except ImportError:
|
|
CLAUDE_AVAILABLE = False
|
|
|
|
class Angular18Designer:
|
|
"""Expert Angular 18 Frontend Designer - Processes tagged rules from requirement-processor"""
|
|
|
|
def __init__(self):
|
|
self.framework = "Angular 18"
|
|
self.language = "TypeScript"
|
|
self.claude_client = None
|
|
|
|
if CLAUDE_AVAILABLE:
|
|
try:
|
|
self.claude_client = anthropic.Anthropic()
|
|
logger.info(f"✅ {self.framework} Designer initialized with Claude AI")
|
|
except Exception as e:
|
|
logger.warning(f"⚠️ Claude AI not available for {self.framework}: {e}")
|
|
else:
|
|
logger.warning(f"⚠️ Claude AI not available for {self.framework}")
|
|
|
|
async def design_frontend_architecture(
|
|
self,
|
|
functional_requirements: Dict[str, Any],
|
|
business_context: Dict[str, Any],
|
|
tech_stack: Any
|
|
) -> Dict[str, Any]:
|
|
"""Design comprehensive Angular 18 frontend architecture from tagged rules"""
|
|
|
|
logger.info(f"🎨 Designing {self.framework} frontend architecture...")
|
|
|
|
try:
|
|
# Extract all tagged rules from requirement-processor
|
|
tagged_rules = self._extract_tagged_rules(functional_requirements)
|
|
|
|
if not tagged_rules:
|
|
logger.warning("⚠️ No tagged rules found, using basic architecture")
|
|
return self._generate_basic_architecture(functional_requirements)
|
|
|
|
logger.info(f"📋 Processing {len(tagged_rules)} tagged rules for Angular 18 design")
|
|
|
|
if self.claude_client:
|
|
return await self._generate_ai_architecture(
|
|
tagged_rules, functional_requirements, business_context, tech_stack
|
|
)
|
|
else:
|
|
return self._generate_rule_based_architecture(
|
|
tagged_rules, functional_requirements, business_context, tech_stack
|
|
)
|
|
|
|
except Exception as e:
|
|
logger.error(f"❌ {self.framework} AI generation failed: {e}")
|
|
return self._generate_rule_based_architecture(
|
|
tagged_rules, functional_requirements, business_context, tech_stack
|
|
)
|
|
|
|
def _extract_tagged_rules(self, functional_requirements: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
"""Extract all tagged rules from requirement-processor output"""
|
|
|
|
all_rules = []
|
|
|
|
# Extract from detailed_requirements with tagged rules
|
|
detailed_requirements = functional_requirements.get('detailed_requirements', [])
|
|
for req in detailed_requirements:
|
|
requirement_name = req.get('requirement_name', 'Unknown')
|
|
feature_name = req.get('feature_name', 'Unknown')
|
|
rules = req.get('rules', [])
|
|
|
|
for rule in rules:
|
|
all_rules.append({
|
|
"rule_text": rule,
|
|
"requirement_name": requirement_name,
|
|
"feature_name": feature_name,
|
|
"source": "detailed_requirements"
|
|
})
|
|
|
|
# Extract from tagged_rules array (fallback)
|
|
tagged_rules = functional_requirements.get('tagged_rules', [])
|
|
for tagged_rule in tagged_rules:
|
|
all_rules.append({
|
|
"rule_text": tagged_rule.get('rule_text', ''),
|
|
"requirement_name": tagged_rule.get('requirement_name', 'Unknown'),
|
|
"feature_name": tagged_rule.get('feature_name', 'Unknown'),
|
|
"rule_id": tagged_rule.get('rule_id', ''),
|
|
"source": "tagged_rules"
|
|
})
|
|
|
|
# Extract from business_logic_rules (final fallback)
|
|
business_rules = functional_requirements.get('business_logic_rules', [])
|
|
for rule in business_rules:
|
|
all_rules.append({
|
|
"rule_text": rule,
|
|
"requirement_name": "General",
|
|
"feature_name": functional_requirements.get('feature_name', 'General'),
|
|
"source": "business_logic_rules"
|
|
})
|
|
|
|
logger.info(f"✅ Extracted {len(all_rules)} tagged rules for Angular 18 processing")
|
|
return all_rules
|
|
|
|
async def _generate_ai_architecture(
|
|
self,
|
|
tagged_rules: List[Dict[str, Any]],
|
|
functional_requirements: Dict[str, Any],
|
|
business_context: Dict[str, Any],
|
|
tech_stack: Any
|
|
) -> Dict[str, Any]:
|
|
"""Generate AI-powered Angular 18 architecture based on tagged rules"""
|
|
|
|
# Build comprehensive prompt with all tagged rules
|
|
rules_text = ""
|
|
for rule in tagged_rules:
|
|
rules_text += f"- {rule['feature_name']} → {rule['requirement_name']}: {rule['rule_text']}\n"
|
|
|
|
feature_name = functional_requirements.get('feature_name', 'Angular Application')
|
|
complexity = functional_requirements.get('complexity_level', 'medium')
|
|
|
|
prompt = f"""You are a senior Angular 18 architect. Design a complete, production-ready frontend architecture based on these specific tagged business rules.
|
|
|
|
PROJECT CONTEXT:
|
|
- Application: {feature_name}
|
|
- Complexity: {complexity}
|
|
- Framework: Angular 18 with TypeScript
|
|
- Backend: ASP.NET Core Web API 8
|
|
- Database: MS SQL Server 2022
|
|
|
|
TAGGED BUSINESS RULES TO IMPLEMENT:
|
|
{rules_text}
|
|
|
|
Design a comprehensive Angular 18 architecture that implements ALL these tagged rules with:
|
|
|
|
1. **PROJECT STRUCTURE** (Angular 18 specific)
|
|
- Standalone components architecture
|
|
- Feature-based module organization
|
|
- Lazy loading strategy
|
|
- Signal-based state management
|
|
|
|
2. **COMPONENTS FOR EACH RULE**
|
|
- Analyze each tagged rule and determine what Angular components are needed
|
|
- Use Angular 18 standalone components
|
|
- Implement new control flow syntax (@if, @for, @switch)
|
|
- Component communication patterns
|
|
|
|
3. **SERVICES & DATA MANAGEMENT**
|
|
- HTTP services for ASP.NET Core Web API integration
|
|
- State management with Signals or NgRx (based on complexity)
|
|
- Data models and interfaces matching backend DTOs
|
|
- Error handling and loading states
|
|
|
|
4. **ROUTING & NAVIGATION**
|
|
- Route configuration for each feature/requirement
|
|
- Route guards for authentication/authorization
|
|
- Lazy loading modules
|
|
- Navigation workflows based on business rules
|
|
|
|
5. **FORMS & VALIDATION**
|
|
- Reactive forms for data entry requirements
|
|
- Custom validators based on business rules
|
|
- Form state management
|
|
- Dynamic form generation if needed
|
|
|
|
6. **UI/UX IMPLEMENTATION**
|
|
- Angular Material 3 components
|
|
- Responsive design with Angular CDK
|
|
- Theme configuration
|
|
- Accessibility compliance
|
|
|
|
7. **TESTING STRATEGY**
|
|
- Unit tests with Jest/Jasmine
|
|
- Component testing
|
|
- Integration tests
|
|
- E2E tests with Cypress
|
|
|
|
Return detailed JSON with specific Angular 18 components, services, modules, and implementation details that cover ALL tagged rules.
|
|
|
|
CRITICAL:
|
|
- Each tagged rule should map to specific Angular components/services
|
|
- Use Angular 18 features (standalone components, signals, new control flow)
|
|
- Include exact file structure and component specifications
|
|
- Ensure 100% coverage of all tagged business rules
|
|
|
|
JSON Format:
|
|
{{
|
|
"framework_info": {{"name": "Angular 18", "version": "18.x", ...}},
|
|
"project_structure": {{"src/app/": {{"features/": "...", "shared/": "..."}}}},
|
|
"components": [{{
|
|
"name": "ComponentName",
|
|
"path": "src/app/features/...",
|
|
"purpose": "Implements rule: [specific rule text]",
|
|
"type": "standalone",
|
|
"dependencies": [...],
|
|
"inputs": [...],
|
|
"outputs": [...]
|
|
}}],
|
|
"services": [...],
|
|
"routing": {...},
|
|
"forms": [...],
|
|
"state_management": {...},
|
|
"ui_framework": {...},
|
|
"testing": {...},
|
|
"implementation_ready": true
|
|
}}"""
|
|
|
|
try:
|
|
message = self.claude_client.messages.create(
|
|
model="claude-3-5-sonnet-20241022",
|
|
max_tokens=8000,
|
|
temperature=0.1,
|
|
messages=[{"role": "user", "content": prompt}]
|
|
)
|
|
|
|
claude_response = message.content[0].text.strip()
|
|
|
|
try:
|
|
architecture = json.loads(claude_response)
|
|
logger.info(f"✅ {self.framework} AI architecture generated successfully")
|
|
|
|
# Add tagged rules coverage analysis
|
|
architecture["tagged_rules_coverage"] = self._analyze_rules_coverage(tagged_rules, architecture)
|
|
|
|
return architecture
|
|
except json.JSONDecodeError:
|
|
logger.warning(f"⚠️ {self.framework} AI response wasn't valid JSON, using fallback")
|
|
return self._generate_rule_based_architecture(tagged_rules, functional_requirements, business_context, tech_stack)
|
|
|
|
except Exception as e:
|
|
logger.error(f"❌ {self.framework} Claude API error: {e}")
|
|
raise e
|
|
|
|
def _generate_rule_based_architecture(
|
|
self,
|
|
tagged_rules: List[Dict[str, Any]],
|
|
functional_requirements: Dict[str, Any],
|
|
business_context: Dict[str, Any],
|
|
tech_stack: Any
|
|
) -> Dict[str, Any]:
|
|
"""Generate Angular 18 architecture based on tagged rules analysis (fallback without AI)"""
|
|
|
|
feature_name = functional_requirements.get('feature_name', 'Angular Application')
|
|
|
|
# Analyze tagged rules to generate components and services
|
|
components = self._generate_components_from_rules(tagged_rules)
|
|
services = self._generate_services_from_rules(tagged_rules)
|
|
routes = self._generate_routes_from_rules(tagged_rules)
|
|
forms = self._generate_forms_from_rules(tagged_rules)
|
|
|
|
return {
|
|
"framework_info": {
|
|
"name": "Angular 18",
|
|
"version": "18.x",
|
|
"language": "TypeScript",
|
|
"cli_version": "18.x",
|
|
"node_version": "18+ or 20+",
|
|
"standalone_components": True
|
|
},
|
|
|
|
"project_structure": {
|
|
"src/app/": {
|
|
"core/": "Singleton services, guards, interceptors",
|
|
"shared/": "Shared standalone components, pipes, directives",
|
|
"features/": "Feature-based standalone components with lazy loading",
|
|
"models/": "TypeScript interfaces and DTOs matching backend",
|
|
"services/": "HTTP services for API communication",
|
|
"guards/": "Route guards for authentication/authorization",
|
|
"interceptors/": "HTTP interceptors for auth/error handling",
|
|
"pipes/": "Custom pipes for data transformation",
|
|
"directives/": "Custom directives for DOM manipulation"
|
|
}
|
|
},
|
|
|
|
"components": components,
|
|
"services": services,
|
|
"routing": {
|
|
"strategy": "Lazy loading with standalone components",
|
|
"routes": routes,
|
|
"guards": ["AuthGuard", "RoleGuard", "CanDeactivateGuard"],
|
|
"resolvers": ["DataResolver for pre-loading data"]
|
|
},
|
|
|
|
"forms": forms,
|
|
|
|
"state_management": {
|
|
"approach": "Angular 18 Signals for reactive state",
|
|
"complex_state": "NgRx Store for complex business logic",
|
|
"http_state": "HTTP services with signal-based caching"
|
|
},
|
|
|
|
"http_communication": {
|
|
"base_service": "ApiService with HttpClient",
|
|
"interceptors": ["AuthInterceptor", "ErrorInterceptor", "LoadingInterceptor"],
|
|
"error_handling": "Global error handling with user notifications"
|
|
},
|
|
|
|
"ui_framework": {
|
|
"library": "Angular Material 3",
|
|
"theming": "Material 3 design tokens",
|
|
"responsive": "Angular CDK Layout for responsive design",
|
|
"accessibility": "CDK a11y for accessibility compliance"
|
|
},
|
|
|
|
"testing": {
|
|
"unit": "Jest or Jasmine/Karma with TestBed",
|
|
"integration": "Component integration tests",
|
|
"e2e": "Cypress or Playwright for end-to-end testing",
|
|
"coverage": "Istanbul for code coverage reporting"
|
|
},
|
|
|
|
"build_optimization": {
|
|
"standalone_components": "Tree-shakeable standalone architecture",
|
|
"lazy_loading": "Route-based code splitting",
|
|
"bundle_optimization": "Angular CLI build optimizations",
|
|
"pwa": "Service Worker for progressive web app features"
|
|
},
|
|
|
|
"tagged_rules_coverage": self._analyze_rules_coverage(tagged_rules, {}),
|
|
"implementation_ready": True,
|
|
"expert_level": True,
|
|
"angular_18_features": [
|
|
"Standalone components architecture",
|
|
"New control flow syntax (@if, @for, @switch)",
|
|
"Signals for reactive programming",
|
|
"Improved hydration for SSR",
|
|
"Material 3 design system integration"
|
|
]
|
|
}
|
|
|
|
def _generate_components_from_rules(self, tagged_rules: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
"""Generate Angular 18 components based on tagged business rules"""
|
|
|
|
components = [
|
|
{
|
|
"name": "AppComponent",
|
|
"path": "src/app/app.component.ts",
|
|
"type": "standalone",
|
|
"purpose": "Root application component with navigation shell",
|
|
"implements_rules": [],
|
|
"dependencies": ["CommonModule", "RouterOutlet", "MaterialModule"],
|
|
"template_features": ["Navigation", "Header", "Footer", "Router Outlet"]
|
|
}
|
|
]
|
|
|
|
# Analyze each tagged rule to generate specific components
|
|
for rule in tagged_rules:
|
|
rule_text = rule['rule_text'].lower()
|
|
feature_name = rule['feature_name']
|
|
requirement_name = rule['requirement_name']
|
|
|
|
# Generate components based on rule content
|
|
if any(word in rule_text for word in ['display', 'show', 'list', 'view']):
|
|
components.append({
|
|
"name": f"{feature_name.replace(' ', '')}ListComponent",
|
|
"path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}-list.component.ts",
|
|
"type": "standalone",
|
|
"purpose": f"Display list view for: {rule['rule_text']}",
|
|
"implements_rules": [rule['rule_text']],
|
|
"dependencies": ["CommonModule", "MaterialModule", "RouterModule"],
|
|
"inputs": ["data", "loading", "error"],
|
|
"outputs": ["itemSelected", "actionTriggered"],
|
|
"template_features": ["Data table", "Filtering", "Pagination", "Search"]
|
|
})
|
|
|
|
if any(word in rule_text for word in ['create', 'add', 'new', 'form', 'input']):
|
|
components.append({
|
|
"name": f"{feature_name.replace(' ', '')}FormComponent",
|
|
"path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}-form.component.ts",
|
|
"type": "standalone",
|
|
"purpose": f"Form component for: {rule['rule_text']}",
|
|
"implements_rules": [rule['rule_text']],
|
|
"dependencies": ["CommonModule", "ReactiveFormsModule", "MaterialModule"],
|
|
"inputs": ["initialData", "editMode"],
|
|
"outputs": ["formSubmit", "formCancel"],
|
|
"template_features": ["Reactive forms", "Validation", "Material form fields"]
|
|
})
|
|
|
|
if any(word in rule_text for word in ['edit', 'update', 'modify']):
|
|
components.append({
|
|
"name": f"{feature_name.replace(' ', '')}EditComponent",
|
|
"path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}-edit.component.ts",
|
|
"type": "standalone",
|
|
"purpose": f"Edit component for: {rule['rule_text']}",
|
|
"implements_rules": [rule['rule_text']],
|
|
"dependencies": ["CommonModule", "ReactiveFormsModule", "MaterialModule"],
|
|
"inputs": ["itemId", "item"],
|
|
"outputs": ["updateComplete", "editCancel"],
|
|
"template_features": ["Pre-populated forms", "Validation", "Save/Cancel actions"]
|
|
})
|
|
|
|
if any(word in rule_text for word in ['approve', 'workflow', 'status', 'process']):
|
|
components.append({
|
|
"name": f"{feature_name.replace(' ', '')}WorkflowComponent",
|
|
"path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}-workflow.component.ts",
|
|
"type": "standalone",
|
|
"purpose": f"Workflow management for: {rule['rule_text']}",
|
|
"implements_rules": [rule['rule_text']],
|
|
"dependencies": ["CommonModule", "MaterialModule", "CdkStepperModule"],
|
|
"inputs": ["workflowData", "currentStep"],
|
|
"outputs": ["stepComplete", "workflowFinish"],
|
|
"template_features": ["Stepper", "Status indicators", "Action buttons"]
|
|
})
|
|
|
|
if any(word in rule_text for word in ['calculate', 'total', 'amount', 'compute']):
|
|
components.append({
|
|
"name": f"{feature_name.replace(' ', '')}CalculatorComponent",
|
|
"path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}-calculator.component.ts",
|
|
"type": "standalone",
|
|
"purpose": f"Calculation component for: {rule['rule_text']}",
|
|
"implements_rules": [rule['rule_text']],
|
|
"dependencies": ["CommonModule", "ReactiveFormsModule", "MaterialModule"],
|
|
"inputs": ["calculationInputs"],
|
|
"outputs": ["calculationResult", "calculationError"],
|
|
"template_features": ["Calculation inputs", "Real-time results", "Formula display"]
|
|
})
|
|
|
|
return components
|
|
|
|
def _generate_services_from_rules(self, tagged_rules: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
"""Generate Angular 18 services based on tagged business rules"""
|
|
|
|
services = [
|
|
{
|
|
"name": "ApiService",
|
|
"path": "src/app/core/services/api.service.ts",
|
|
"purpose": "Base HTTP service for ASP.NET Core Web API communication",
|
|
"injectable": "root",
|
|
"dependencies": ["HttpClient"],
|
|
"methods": ["get", "post", "put", "delete", "patch"],
|
|
"implements_rules": []
|
|
},
|
|
{
|
|
"name": "AuthService",
|
|
"path": "src/app/core/services/auth.service.ts",
|
|
"purpose": "Authentication and authorization service",
|
|
"injectable": "root",
|
|
"dependencies": ["HttpClient", "Router"],
|
|
"methods": ["login", "logout", "isAuthenticated", "getToken", "refreshToken"],
|
|
"implements_rules": []
|
|
}
|
|
]
|
|
|
|
# Generate services based on tagged rules
|
|
processed_features = set()
|
|
|
|
for rule in tagged_rules:
|
|
rule_text = rule['rule_text'].lower()
|
|
feature_name = rule['feature_name']
|
|
requirement_name = rule['requirement_name']
|
|
|
|
# Avoid duplicate services for same feature
|
|
service_key = f"{feature_name}_{requirement_name}"
|
|
if service_key in processed_features:
|
|
continue
|
|
processed_features.add(service_key)
|
|
|
|
# Generate data service for each feature/requirement
|
|
services.append({
|
|
"name": f"{feature_name.replace(' ', '')}DataService",
|
|
"path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/services/{requirement_name.lower().replace(' ', '-')}.service.ts",
|
|
"purpose": f"Data service for {feature_name} - {requirement_name}",
|
|
"injectable": "root",
|
|
"dependencies": ["ApiService"],
|
|
"methods": self._generate_service_methods_from_rule(rule),
|
|
"implements_rules": [rule['rule_text']],
|
|
"api_endpoints": self._generate_api_endpoints_from_rule(rule, feature_name, requirement_name)
|
|
})
|
|
|
|
# Generate specific services based on rule content
|
|
if any(word in rule_text for word in ['validate', 'check', 'verify']):
|
|
services.append({
|
|
"name": f"{feature_name.replace(' ', '')}ValidationService",
|
|
"path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/services/{requirement_name.lower().replace(' ', '-')}-validation.service.ts",
|
|
"purpose": f"Validation service for: {rule['rule_text']}",
|
|
"injectable": "root",
|
|
"dependencies": [],
|
|
"methods": ["validate", "validateField", "getValidationErrors"],
|
|
"implements_rules": [rule['rule_text']]
|
|
})
|
|
|
|
if any(word in rule_text for word in ['calculate', 'compute', 'total']):
|
|
services.append({
|
|
"name": f"{feature_name.replace(' ', '')}CalculationService",
|
|
"path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/services/{requirement_name.lower().replace(' ', '-')}-calculation.service.ts",
|
|
"purpose": f"Calculation service for: {rule['rule_text']}",
|
|
"injectable": "root",
|
|
"dependencies": [],
|
|
"methods": ["calculate", "validateInputs", "formatResult"],
|
|
"implements_rules": [rule['rule_text']]
|
|
})
|
|
|
|
return services
|
|
|
|
def _generate_routes_from_rules(self, tagged_rules: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
"""Generate Angular routing configuration based on tagged rules"""
|
|
|
|
routes = [
|
|
{
|
|
"path": "",
|
|
"redirectTo": "/dashboard",
|
|
"pathMatch": "full"
|
|
},
|
|
{
|
|
"path": "dashboard",
|
|
"component": "DashboardComponent",
|
|
"title": "Dashboard"
|
|
}
|
|
]
|
|
|
|
# Generate routes for each feature/requirement
|
|
processed_routes = set()
|
|
|
|
for rule in tagged_rules:
|
|
feature_name = rule['feature_name']
|
|
requirement_name = rule['requirement_name']
|
|
|
|
# Create unique route path
|
|
route_path = f"{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}"
|
|
|
|
if route_path in processed_routes:
|
|
continue
|
|
processed_routes.add(route_path)
|
|
|
|
routes.append({
|
|
"path": route_path,
|
|
"loadComponent": f"() => import('./features/{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}.component').then(m => m.{feature_name.replace(' ', '')}{requirement_name.replace(' ', '')}Component)",
|
|
"title": f"{feature_name} - {requirement_name}",
|
|
"data": {
|
|
"breadcrumb": f"{feature_name} > {requirement_name}",
|
|
"implemented_rules": [rule['rule_text']]
|
|
}
|
|
})
|
|
|
|
return routes
|
|
|
|
def _generate_forms_from_rules(self, tagged_rules: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
"""Generate Angular reactive forms based on tagged rules"""
|
|
|
|
forms = []
|
|
|
|
for rule in tagged_rules:
|
|
rule_text = rule['rule_text'].lower()
|
|
feature_name = rule['feature_name']
|
|
requirement_name = rule['requirement_name']
|
|
|
|
if any(word in rule_text for word in ['create', 'add', 'input', 'form', 'enter']):
|
|
forms.append({
|
|
"name": f"{feature_name.replace(' ', '')}{requirement_name.replace(' ', '')}Form",
|
|
"purpose": f"Form for: {rule['rule_text']}",
|
|
"type": "reactive",
|
|
"fields": self._extract_form_fields_from_rule(rule),
|
|
"validators": self._extract_validators_from_rule(rule),
|
|
"implements_rules": [rule['rule_text']]
|
|
})
|
|
|
|
return forms
|
|
|
|
def _generate_service_methods_from_rule(self, rule: Dict[str, Any]) -> List[str]:
|
|
"""Generate service methods based on rule content"""
|
|
|
|
methods = []
|
|
rule_text = rule['rule_text'].lower()
|
|
|
|
if any(word in rule_text for word in ['get', 'retrieve', 'fetch', 'load']):
|
|
methods.extend(["getAll", "getById", "search"])
|
|
|
|
if any(word in rule_text for word in ['create', 'add', 'new']):
|
|
methods.append("create")
|
|
|
|
if any(word in rule_text for word in ['update', 'modify', 'edit']):
|
|
methods.append("update")
|
|
|
|
if any(word in rule_text for word in ['delete', 'remove']):
|
|
methods.append("delete")
|
|
|
|
if any(word in rule_text for word in ['validate', 'check']):
|
|
methods.append("validate")
|
|
|
|
return methods if methods else ["getAll", "getById", "create", "update", "delete"]
|
|
|
|
def _generate_api_endpoints_from_rule(self, rule: Dict[str, Any], feature_name: str, requirement_name: str) -> List[str]:
|
|
"""Generate API endpoint paths based on rule"""
|
|
|
|
base_path = f"/api/{feature_name.lower().replace(' ', '-')}"
|
|
endpoints = []
|
|
|
|
rule_text = rule['rule_text'].lower()
|
|
|
|
if any(word in rule_text for word in ['get', 'list', 'retrieve']):
|
|
endpoints.extend([f"GET {base_path}", f"GET {base_path}/{{id}}"])
|
|
|
|
if any(word in rule_text for word in ['create', 'add']):
|
|
endpoints.append(f"POST {base_path}")
|
|
|
|
if any(word in rule_text for word in ['update', 'edit']):
|
|
endpoints.append(f"PUT {base_path}/{{id}}")
|
|
|
|
if any(word in rule_text for word in ['delete', 'remove']):
|
|
endpoints.append(f"DELETE {base_path}/{{id}}")
|
|
|
|
return endpoints
|
|
|
|
def _extract_form_fields_from_rule(self, rule: Dict[str, Any]) -> List[Dict[str, str]]:
|
|
"""Extract form fields from rule content"""
|
|
|
|
fields = []
|
|
rule_text = rule['rule_text'].lower()
|
|
|
|
# Common fields based on rule content
|
|
if 'name' in rule_text:
|
|
fields.append({"name": "name", "type": "text", "required": True})
|
|
|
|
if 'description' in rule_text:
|
|
fields.append({"name": "description", "type": "textarea", "required": False})
|
|
|
|
if 'email' in rule_text:
|
|
fields.append({"name": "email", "type": "email", "required": True})
|
|
|
|
if 'amount' in rule_text or 'price' in rule_text:
|
|
fields.append({"name": "amount", "type": "number", "required": True})
|
|
|
|
if 'date' in rule_text:
|
|
fields.append({"name": "date", "type": "date", "required": True})
|
|
|
|
if 'status' in rule_text:
|
|
fields.append({"name": "status", "type": "select", "required": True})
|
|
|
|
return fields if fields else [{"name": "name", "type": "text", "required": True}]
|
|
|
|
def _extract_validators_from_rule(self, rule: Dict[str, Any]) -> List[str]:
|
|
"""Extract validation requirements from rule content"""
|
|
|
|
validators = []
|
|
rule_text = rule['rule_text'].lower()
|
|
|
|
if 'required' in rule_text or 'must' in rule_text:
|
|
validators.append("Validators.required")
|
|
|
|
if 'email' in rule_text:
|
|
validators.append("Validators.email")
|
|
|
|
if 'minimum' in rule_text or 'max' in rule_text:
|
|
validators.append("Validators.min")
|
|
|
|
if 'unique' in rule_text:
|
|
validators.append("CustomValidators.unique")
|
|
|
|
return validators
|
|
|
|
def _analyze_rules_coverage(self, tagged_rules: List[Dict[str, Any]], architecture: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
"""Analyze how well the architecture covers the tagged rules"""
|
|
|
|
coverage_analysis = []
|
|
|
|
for rule in tagged_rules:
|
|
rule_text = rule['rule_text']
|
|
|
|
coverage = {
|
|
"rule_text": rule_text,
|
|
"feature_name": rule['feature_name'],
|
|
"requirement_name": rule['requirement_name'],
|
|
"covered_by_components": [],
|
|
"covered_by_services": [],
|
|
"covered_by_routes": [],
|
|
"coverage_complete": False
|
|
}
|
|
|
|
# Check component coverage
|
|
components = architecture.get("components", [])
|
|
for component in components:
|
|
if rule_text in component.get("implements_rules", []):
|
|
coverage["covered_by_components"].append(component["name"])
|
|
|
|
# Check service coverage
|
|
services = architecture.get("services", [])
|
|
for service in services:
|
|
if rule_text in service.get("implements_rules", []):
|
|
coverage["covered_by_services"].append(service["name"])
|
|
|
|
# Determine if coverage is complete
|
|
coverage["coverage_complete"] = (
|
|
len(coverage["covered_by_components"]) > 0 or
|
|
len(coverage["covered_by_services"]) > 0
|
|
)
|
|
|
|
coverage_analysis.append(coverage)
|
|
|
|
return coverage_analysis
|
|
|
|
def _generate_basic_architecture(self, functional_requirements: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""Generate basic Angular 18 architecture when no tagged rules are available"""
|
|
|
|
feature_name = functional_requirements.get('feature_name', 'Angular Application')
|
|
|
|
return {
|
|
"framework_info": {
|
|
"name": "Angular 18",
|
|
"version": "18.x",
|
|
"language": "TypeScript",
|
|
"status": "basic_architecture_no_tagged_rules"
|
|
},
|
|
"components": [
|
|
{
|
|
"name": "AppComponent",
|
|
"path": "src/app/app.component.ts",
|
|
"type": "standalone",
|
|
"purpose": "Root application component"
|
|
},
|
|
{
|
|
"name": "DashboardComponent",
|
|
"path": "src/app/features/dashboard/dashboard.component.ts",
|
|
"type": "standalone",
|
|
"purpose": "Main dashboard view"
|
|
}
|
|
],
|
|
"services": [
|
|
{
|
|
"name": "ApiService",
|
|
"path": "src/app/core/services/api.service.ts",
|
|
"purpose": "HTTP communication service"
|
|
}
|
|
],
|
|
"routing": {
|
|
"routes": [
|
|
{"path": "", "redirectTo": "/dashboard", "pathMatch": "full"},
|
|
{"path": "dashboard", "component": "DashboardComponent"}
|
|
]
|
|
},
|
|
"implementation_ready": True,
|
|
"requires_tagged_rules": True,
|
|
"tagged_rules_coverage": []
|
|
} |