130 lines
4.0 KiB
Python
130 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Validate project manifest integrity."""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
|
|
def validate_structure(manifest: dict) -> list:
|
|
"""Validate manifest has required structure."""
|
|
errors = []
|
|
required_keys = ["project", "state", "entities", "dependencies"]
|
|
|
|
for key in required_keys:
|
|
if key not in manifest:
|
|
errors.append(f"Missing required key: {key}")
|
|
|
|
if "entities" in manifest:
|
|
entity_types = ["pages", "components", "api_endpoints", "database_tables"]
|
|
for etype in entity_types:
|
|
if etype not in manifest["entities"]:
|
|
errors.append(f"Missing entity type: {etype}")
|
|
|
|
return errors
|
|
|
|
|
|
def validate_pages(pages: list) -> list:
|
|
"""Validate page entities."""
|
|
errors = []
|
|
for page in pages:
|
|
if "id" not in page:
|
|
errors.append(f"Page missing id: {page}")
|
|
if "path" not in page:
|
|
errors.append(f"Page {page.get('id', 'unknown')} missing path")
|
|
if "file_path" not in page:
|
|
errors.append(f"Page {page.get('id', 'unknown')} missing file_path")
|
|
return errors
|
|
|
|
|
|
def validate_components(components: list) -> list:
|
|
"""Validate component entities."""
|
|
errors = []
|
|
for comp in components:
|
|
if "id" not in comp:
|
|
errors.append(f"Component missing id: {comp}")
|
|
if "name" not in comp:
|
|
errors.append(f"Component {comp.get('id', 'unknown')} missing name")
|
|
if "file_path" not in comp:
|
|
errors.append(f"Component {comp.get('id', 'unknown')} missing file_path")
|
|
return errors
|
|
|
|
|
|
def validate_apis(apis: list) -> list:
|
|
"""Validate API endpoint entities."""
|
|
errors = []
|
|
for api in apis:
|
|
if "id" not in api:
|
|
errors.append(f"API missing id: {api}")
|
|
if "method" not in api:
|
|
errors.append(f"API {api.get('id', 'unknown')} missing method")
|
|
if "path" not in api:
|
|
errors.append(f"API {api.get('id', 'unknown')} missing path")
|
|
return errors
|
|
|
|
|
|
def validate_tables(tables: list) -> list:
|
|
"""Validate database table entities."""
|
|
errors = []
|
|
for table in tables:
|
|
if "id" not in table:
|
|
errors.append(f"Table missing id: {table}")
|
|
if "name" not in table:
|
|
errors.append(f"Table {table.get('id', 'unknown')} missing name")
|
|
if "columns" not in table:
|
|
errors.append(f"Table {table.get('id', 'unknown')} missing columns")
|
|
return errors
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Validate project manifest")
|
|
parser.add_argument("--strict", action="store_true", help="Treat warnings as errors")
|
|
parser.add_argument("--manifest", default="project_manifest.json", help="Path to manifest")
|
|
args = parser.parse_args()
|
|
|
|
manifest_path = args.manifest
|
|
if not os.path.isabs(manifest_path):
|
|
manifest_path = os.path.join(os.getcwd(), manifest_path)
|
|
|
|
if not os.path.exists(manifest_path):
|
|
print(f"Error: Manifest not found at {manifest_path}")
|
|
return 1
|
|
|
|
with open(manifest_path) as f:
|
|
manifest = json.load(f)
|
|
|
|
errors = []
|
|
warnings = []
|
|
|
|
# Structure validation
|
|
errors.extend(validate_structure(manifest))
|
|
|
|
if "entities" in manifest:
|
|
errors.extend(validate_pages(manifest["entities"].get("pages", [])))
|
|
errors.extend(validate_components(manifest["entities"].get("components", [])))
|
|
errors.extend(validate_apis(manifest["entities"].get("api_endpoints", [])))
|
|
errors.extend(validate_tables(manifest["entities"].get("database_tables", [])))
|
|
|
|
# Report results
|
|
if errors:
|
|
print("VALIDATION FAILED")
|
|
for error in errors:
|
|
print(f" ERROR: {error}")
|
|
return 1
|
|
|
|
if warnings:
|
|
print("VALIDATION PASSED WITH WARNINGS")
|
|
for warning in warnings:
|
|
print(f" WARNING: {warning}")
|
|
if args.strict:
|
|
return 1
|
|
return 0
|
|
|
|
print("VALIDATION PASSED")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
exit(main())
|