Source code for django_angular3.validation
from __future__ import annotations
from pathlib import Path
from typing import Any
from .config import ProjectConfig
from .documents import DocumentError, load_document
[docs]
class ValidationError(ValueError):
"""Raised when validation cannot continue."""
[docs]
def validate_openapi_document(document: Any) -> list[str]:
errors: list[str] = []
if not isinstance(document, dict):
return ["OpenAPI document must be a mapping."]
if not any(key in document for key in ("openapi", "swagger")):
errors.append("OpenAPI document must declare either 'openapi' or 'swagger'.")
paths = document.get("paths")
if not isinstance(paths, dict):
errors.append("OpenAPI document must contain a 'paths' mapping.")
return errors
if not paths:
errors.append("OpenAPI document must define at least one path.")
return errors
allowed_methods = {
"get",
"put",
"post",
"delete",
"options",
"head",
"patch",
"trace",
}
for path_name, path_item in paths.items():
if not isinstance(path_name, str) or not path_name.startswith("/"):
errors.append(f"OpenAPI path '{path_name}' must be a string starting with '/'.")
continue
if not isinstance(path_item, dict):
errors.append(f"OpenAPI path '{path_name}' must map to an object.")
continue
operations = [name for name in path_item if name in allowed_methods]
if not operations:
errors.append(f"OpenAPI path '{path_name}' must define at least one HTTP operation.")
continue
for operation_name in operations:
operation = path_item[operation_name]
if not isinstance(operation, dict):
errors.append(
f"Operation '{operation_name}' on path '{path_name}' must be an object."
)
return errors
[docs]
def validate_ui_document(document: Any) -> list[str]:
errors: list[str] = []
if not isinstance(document, dict):
return ["UI definition document must be a mapping."]
pages = document.get("pages", [])
forms = document.get("forms", [])
if not isinstance(pages, list):
errors.append("'pages' must be a list when provided.")
else:
for index, page in enumerate(pages):
if not isinstance(page, dict):
errors.append(f"pages[{index}] must be an object.")
continue
route = page.get("route")
kind = page.get("kind")
if not isinstance(route, str) or not route.startswith("/"):
errors.append(f"pages[{index}].route must be a string starting with '/'.")
if not isinstance(kind, str) or not kind.strip():
errors.append(f"pages[{index}].kind must be a non-empty string.")
if not isinstance(forms, list):
errors.append("'forms' must be a list when provided.")
else:
for index, form in enumerate(forms):
if not isinstance(form, dict):
errors.append(f"forms[{index}] must be an object.")
continue
form_id = form.get("id")
mode = form.get("mode")
submit = form.get("submit")
if not isinstance(form_id, str) or not form_id.strip():
errors.append(f"forms[{index}].id must be a non-empty string.")
if not isinstance(mode, str) or not mode.strip():
errors.append(f"forms[{index}].mode must be a non-empty string.")
if submit is not None:
if not isinstance(submit, dict):
errors.append(f"forms[{index}].submit must be an object when provided.")
else:
action = submit.get("action")
if not isinstance(action, str) or not action.strip():
errors.append(
f"forms[{index}].submit.action must be a non-empty string."
)
return errors
[docs]
def validate_openapi_file(path: str | Path) -> list[str]:
try:
document = load_document(path)
except DocumentError as exc:
return [str(exc)]
return validate_openapi_document(document)
[docs]
def validate_ui_file(path: str | Path) -> list[str]:
try:
document = load_document(path)
except DocumentError as exc:
return [str(exc)]
return validate_ui_document(document)
[docs]
def validate_project_config(config: ProjectConfig) -> list[str]:
errors: list[str] = []
if not config.openapi_source.exists():
errors.append(f"OpenAPI source does not exist: {config.openapi_source}")
else:
errors.extend(validate_openapi_file(config.openapi_source))
if not config.ui_source.exists():
errors.append(f"UI source does not exist: {config.ui_source}")
else:
errors.extend(validate_ui_file(config.ui_source))
if config.angular_output.exists() and not config.angular_output.is_dir():
errors.append(
"Angular output path must be a directory when it exists: "
f"{config.angular_output}"
)
if config.openapi_generator_config and not config.openapi_generator_config.exists():
errors.append(
"OpenAPI Generator config does not exist: "
f"{config.openapi_generator_config}"
)
if config.ng_openapi_gen_config and not config.ng_openapi_gen_config.exists():
errors.append(
"ng-openapi-gen config does not exist: "
f"{config.ng_openapi_gen_config}"
)
return errors