from __future__ import annotations import argparse import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] DEFAULT_PATH = ROOT / "plugins" / "1c" / "metadata" / "examples" / "metadata.example.json" VALID_KINDS = { "catalog", "document", "register", "common_module", "enum", "report", "processing", "other", } def validate_snapshot(data: object, path: Path) -> list[str]: errors: list[str] = [] if not isinstance(data, dict): return [f"{path}: snapshot must be a JSON object"] if data.get("schema_version") not in {1, 2}: errors.append(f"{path}: schema_version must be 1 or 2") source = data.get("source") if not isinstance(source, dict) or not source.get("name"): errors.append(f"{path}: source.name is required") if not data.get("created_at"): errors.append(f"{path}: created_at is required") objects = data.get("objects") if not isinstance(objects, list): errors.append(f"{path}: objects must be a list") return errors for index, obj in enumerate(objects): prefix = f"{path}: objects[{index}]" if not isinstance(obj, dict): errors.append(f"{prefix} must be an object") continue kind = obj.get("kind") name = obj.get("name") if kind not in VALID_KINDS: errors.append(f"{prefix}.kind must be one of {sorted(VALID_KINDS)}") if not name: errors.append(f"{prefix}.name is required") for attr_index, attr in enumerate(obj.get("attributes") or []): if not isinstance(attr, dict) or not attr.get("name"): errors.append(f"{prefix}.attributes[{attr_index}].name is required") for section_index, section in enumerate(obj.get("tabular_sections") or []): section_prefix = f"{prefix}.tabular_sections[{section_index}]" if not isinstance(section, dict) or not section.get("name"): errors.append(f"{section_prefix}.name is required") continue for attr_index, attr in enumerate(section.get("attributes") or []): if not isinstance(attr, dict) or not attr.get("name"): errors.append(f"{section_prefix}.attributes[{attr_index}].name is required") if data.get("schema_version") == 2: for module_index, module in enumerate(obj.get("modules") or []): if not isinstance(module, dict) or not module.get("module_id"): errors.append(f"{prefix}.modules[{module_index}].module_id is required") return errors def main() -> int: parser = argparse.ArgumentParser(description="Validate a 1C metadata snapshot.") parser.add_argument("path", nargs="?", type=Path, default=DEFAULT_PATH) args = parser.parse_args() with args.path.open("r", encoding="utf-8") as handle: data = json.load(handle) errors = validate_snapshot(data, args.path) if errors: print("1C metadata snapshot validation failed:", file=sys.stderr) for error in errors: print(f"- {error}", file=sys.stderr) return 1 print(f"Validated 1C metadata snapshot: {args.path}") return 0 if __name__ == "__main__": raise SystemExit(main())