code-generation-system / src /validator.py
2008robocode-cryptoc
Publishing to public space for live url
d0fdbcd
Raw
History Blame Contribute Delete
11 kB
"""
Validation engine for detecting and reporting issues in generated schemas.
Checks for: invalid JSON, missing keys, type mismatches, cross-layer inconsistencies.
"""
import json
from typing import Any, Dict, List, Optional, Tuple
from schemas import ValidationResult, GeneratedConfig, DBTable, APIEndpoint, UIPage, Role, FieldType
class Validator:
"""Comprehensive validation for generated configurations."""
def __init__(self):
self.result = ValidationResult()
def validate_json(self, json_str: str) -> Tuple[bool, Optional[Dict[str, Any]]]:
"""Validate if string is valid JSON."""
try:
data = json.loads(json_str)
return True, data
except json.JSONDecodeError as e:
self.result.add_error(f"Invalid JSON: {str(e)}")
return False, None
def validate_required_fields(self, data: Dict[str, Any], required_fields: List[str]) -> bool:
"""Check if all required fields are present."""
missing = [f for f in required_fields if f not in data or data[f] is None]
if missing:
self.result.add_error(f"Missing required fields: {', '.join(missing)}")
return False
return True
def validate_generated_config_structure(self, config_dict: Dict[str, Any]) -> bool:
"""Validate top-level structure of GeneratedConfig."""
required_fields = [
"app_name", "app_description", "database_schema",
"api_schema", "ui_schema", "auth_config", "roles", "business_logic"
]
return self.validate_required_fields(config_dict, required_fields)
def validate_database_schema(self, db_schema: List[Dict[str, Any]]) -> bool:
"""Validate database schema integrity."""
if not isinstance(db_schema, list):
self.result.add_error("database_schema must be a list")
return False
table_names = set()
is_valid = True
for i, table in enumerate(db_schema):
if not isinstance(table, dict):
self.result.add_error(f"Table {i} is not a dict")
is_valid = False
continue
# Check required fields
if "name" not in table or "fields" not in table or "primary_key" not in table:
self.result.add_error(f"Table {i}: missing name, fields, or primary_key")
is_valid = False
continue
table_names.add(table["name"])
# Validate fields
if not isinstance(table["fields"], list):
self.result.add_error(f"Table '{table['name']}': fields must be a list")
is_valid = False
continue
# Validate field types
for field in table["fields"]:
if not self._validate_field(field, table["name"]):
is_valid = False
# Validate foreign key relations
for table in db_schema:
if "relations" in table and table["relations"]:
for field, related_table in table["relations"].items():
if related_table not in table_names:
self.result.add_warning(
f"Foreign key in {table['name']}.{field} references non-existent table: {related_table}"
)
return is_valid
def _validate_field(self, field: Dict[str, Any], table_name: str) -> bool:
"""Validate a single field."""
if not isinstance(field, dict):
self.result.add_error(f"Field in {table_name} is not a dict")
return False
required = ["name", "type"]
if not all(k in field for k in required):
self.result.add_error(f"Field in {table_name}: missing name or type")
return False
field_type = field["type"]
valid_types = [t.value for t in FieldType]
if field_type not in valid_types:
self.result.add_error(
f"Field '{field['name']}' in {table_name}: invalid type '{field_type}'"
)
return False
return True
def validate_api_schema(self, api_schema: List[Dict[str, Any]]) -> bool:
"""Validate API schema structure."""
if not isinstance(api_schema, list):
self.result.add_error("api_schema must be a list")
return False
valid_methods = ["GET", "POST", "PUT", "DELETE", "PATCH"]
is_valid = True
for i, endpoint in enumerate(api_schema):
if not isinstance(endpoint, dict):
self.result.add_error(f"Endpoint {i} is not a dict")
is_valid = False
continue
# Check required fields
if "path" not in endpoint or "method" not in endpoint:
self.result.add_error(f"Endpoint {i}: missing path or method")
is_valid = False
continue
# Validate method
if endpoint["method"] not in valid_methods:
self.result.add_error(
f"Endpoint {endpoint['path']}: invalid method '{endpoint['method']}'"
)
is_valid = False
return is_valid
def validate_ui_schema(self, ui_schema: List[Dict[str, Any]]) -> bool:
"""Validate UI schema structure."""
if not isinstance(ui_schema, list):
self.result.add_error("ui_schema must be a list")
return False
is_valid = True
for i, page in enumerate(ui_schema):
if not isinstance(page, dict):
self.result.add_error(f"Page {i} is not a dict")
is_valid = False
continue
required = ["path", "title", "components"]
if not all(k in page for k in required):
self.result.add_error(f"Page {i}: missing path, title, or components")
is_valid = False
continue
if not isinstance(page["components"], list):
self.result.add_error(f"Page {i}: components must be a list")
is_valid = False
return is_valid
def validate_cross_layer_consistency(self, config_dict: Dict[str, Any]) -> bool:
"""Validate consistency between API, DB, and UI layers."""
is_valid = True
# Extract API fields
api_fields = set()
for endpoint in config_dict.get("api_schema", []):
if endpoint.get("request_body"):
api_fields.update(endpoint["request_body"].keys())
if endpoint.get("response_body"):
api_fields.update(endpoint["response_body"].keys())
# Extract DB fields
db_fields = set()
for table in config_dict.get("database_schema", []):
for field in table.get("fields", []):
if isinstance(field, dict):
db_fields.add(field.get("name"))
elif hasattr(field, "name"):
db_fields.add(field.name)
# Extract UI fields
ui_fields = set()
for page in config_dict.get("ui_schema", []):
for component in page.get("components", []):
if isinstance(component, dict):
ui_fields.update(component.get("fields", {}).keys() if isinstance(component.get("fields"), dict) else [])
# Check consistency
if api_fields and db_fields:
# API fields should reference DB fields (not strict - API can have computed fields)
missing_db_fields = api_fields - db_fields
if missing_db_fields and len(missing_db_fields) > 3: # Allow some computed fields
self.result.add_warning(
f"API references fields not in DB: {missing_db_fields}"
)
return is_valid
def validate_roles_and_permissions(self, roles: List[Dict[str, Any]],
api_schema: List[Dict[str, Any]]) -> bool:
"""Validate roles match API requirements."""
is_valid = True
if not isinstance(roles, list):
self.result.add_error("roles must be a list")
return False
role_names = set()
for role in roles:
if not isinstance(role, dict) or "name" not in role:
self.result.add_error("Each role must be a dict with 'name'")
is_valid = False
continue
role_names.add(role["name"])
# Check if API endpoints reference existing roles
for endpoint in api_schema:
required_role = endpoint.get("required_role")
if required_role and required_role not in role_names:
self.result.add_warning(
f"API endpoint {endpoint.get('path')} requires role '{required_role}' which doesn't exist"
)
return is_valid
def validate_no_hallucinations(self, config_dict: Dict[str, Any]) -> bool:
"""Detect hallucinated or nonsensical fields."""
is_valid = True
# Check for common hallucination patterns
for key, value in config_dict.items():
if isinstance(value, str):
# Check for placeholder text
if any(p in value.lower() for p in ["todo", "placeholder", "tbd", "fix me"]):
self.result.add_warning(f"Potential placeholder in {key}: {value}")
# Check for values that don't match their keys semantically
if key == "business_logic" and not isinstance(value, dict):
self.result.add_error(f"{key} should be a dict, got {type(value)}")
is_valid = False
return is_valid
def validate_complete(self, config_dict: Dict[str, Any]) -> ValidationResult:
"""Run complete validation suite."""
self.result = ValidationResult()
# Structure validation
if not self.validate_generated_config_structure(config_dict):
return self.result
# Layer-specific validation
self.validate_database_schema(config_dict.get("database_schema", []))
self.validate_api_schema(config_dict.get("api_schema", []))
self.validate_ui_schema(config_dict.get("ui_schema", []))
# Cross-layer validation
self.validate_cross_layer_consistency(config_dict)
self.validate_roles_and_permissions(
config_dict.get("roles", []),
config_dict.get("api_schema", [])
)
# Hallucination detection
self.validate_no_hallucinations(config_dict)
return self.result